Драйвер фильтр для устройства класса HID

Тема в разделе "WASM.NT.KERNEL", создана пользователем Jasper, 30 апр 2010.

  1. Jasper

    Jasper New Member

    Публикаций:
    0
    Регистрация:
    30 апр 2010
    Сообщения:
    10
    Доброго времени суток

    Требуется с помощью драйвера поменять функциональность устройства пользовательского интерфейса (HID), то есть грубо говоря, сделать так, чтобы в Windows XP можно было использовать геймпад вместо мышки.
    Собственно с этой целью думал написать драйвер-фильтр, который перехватывал бы запросы на чтение отчетов и дескрипторов и заменял их на аналогичные для мыши. И вот тут появляются вопросы:

    1) Будет ли вообще такая идея работать, или она изначально обречена на провал?)

    2) Написал на примере из WDK простейший фильтр, который просто перехватывает запросы, выдает сообщения о перехвате и пересылает их ниже по стеку. В inf-файле прописал установку драйвера в качестве нижнего фильтра и решил протестить его на USB-мышке. После установки он действительно виден как нижний фильтр устройства, но при этом он удаляет из стека драйверов все остальные, кроме hidusb.sys. При попытке нажатия на кнопку этой мыши или ее движении, положение курсора на экране не меняется и через секунду без всяких BSOD'ов комп просто перезагружается. Собственно в чем может быть проблема и каким образом ее можно исправить?)

    Заранее спасибо)
     
  2. deshiko

    deshiko New Member

    Публикаций:
    0
    Регистрация:
    10 фев 2009
    Сообщения:
    42
    Для анализа проблемы используйте windbg+vmware для отладки драйвера и определение причин перезагрузки.
    Каким образом вы устанавливаете драйвер-фильтр?
     
  3. JhanGhuangxi

    JhanGhuangxi New Member

    Публикаций:
    0
    Регистрация:
    15 апр 2010
    Сообщения:
    31
    Дык Jasper написал же, что через inf-файл
     
  4. Jasper

    Jasper New Member

    Публикаций:
    0
    Регистрация:
    30 апр 2010
    Сообщения:
    10
    устанавливаю через диспетчер устройств, обновляя драйвер для мыши
     
  5. Jasper

    Jasper New Member

    Публикаций:
    0
    Регистрация:
    30 апр 2010
    Сообщения:
    10
    дамп указывает что источником проблем является строка
    hDevice = WdfIoQueueGetDevice (Queue);
    из функции перехвата запросов IRP_MJ_INTERNAL_DEVICE_CONTROL
     
  6. jne100

    jne100 New Member

    Публикаций:
    0
    Регистрация:
    19 дек 2009
    Сообщения:
    13
    Я думал что комп не может сам перезагружаться, просто бсод быстро проходит изза того что дамп не пишется. Кстати про дамп, в последнем посте ты его упоминаешь, можешь приаттачить? (мини конечно)
     
  7. Jasper

    Jasper New Member

    Публикаций:
    0
    Регистрация:
    30 апр 2010
    Сообщения:
    10
    Да с BSOD'ом это я уже понял) А вот с дампом разобраться не очень получается, ибо сталкиваюсь впервые. Дамп, который у меня сейчас, весит порядка 90 метров. Если подскажете, как сделать его "мини", то с удовольствием приаттачу)

    И все-таки, если плясать от печки, сильно волнует вопрос с удаленными из стека устройства драйверами. Такое ощущение, что ставлю я его не так, как надо. Возможно inf-файл составил криво, хотя уже вроде все примеры из WDK по этому поводу прошерстил...
     
  8. jne100

    jne100 New Member

    Публикаций:
    0
    Регистрация:
    19 дек 2009
    Сообщения:
    13
    Что бы из дампа сделать минидамп надо этот дамп открыть в windbg и выполнить команду типа вот такой: .dump /m c:\minidump.dmp
     
  9. Jasper

    Jasper New Member

    Публикаций:
    0
    Регистрация:
    30 апр 2010
    Сообщения:
    10
    Ну вроде бы так.
     
  10. deshiko

    deshiko New Member

    Публикаций:
    0
    Регистрация:
    10 фев 2009
    Сообщения:
    42
    Теперь откройте windbg -> open crash dump указав ваш dump (лучше полный).
    Затем подгрузите символы (а главное filtr.pdb (созданный при компиляции драйвера) положите в c:\symbols)
    file->symbol file path srv*c:\Symbols*http://msdl.microsoft.com/download/symbols reload

    Затем !analyze -v
    и вы увидите что ошибка в вашей функуии
    f78ae8e0 f6330072 79ebbc30 79d5dc90 86027ef8 filtr+0x4154
    f78ae904 f6331432 79ebbc30 79d5dc90 86027ef8 wdf01000!FxIoQueueIoInternalDeviceControl::Invoke+0x30

    Причем немного меня смутило
    1: kd> u filtr+0x4154
    filtr+0x4154:
    f77cb154 ?? ???
    ^ Memory access error in 'u filtr+0x4154'

    Если все сделает правильно, то windbg, укажет точное место в вашем исходнике, где ошибка!
     
  11. Jasper

    Jasper New Member

    Публикаций:
    0
    Регистрация:
    30 апр 2010
    Сообщения:
    10
    Я уже писал, на какое место указывает WinDbg, а именно на hDevice = WdfIoQueueGetDevice (Queue);
    из функции перехвата запросов IRP_MJ_INTERNAL_DEVICE_CONTROL.
    Мне кажется, что дело все-таки в неправильной установке драйвера, ибо удаления из стека драйвера класса явно быть не должно! Возможен какой-либо другой способ установки нижнего фильтра устройства? Или необходимы какие-то дополнительные записи в inf-файле, кроме
    Код (Text):
    1. [filtr.NT.HW]
    2. AddReg = filtr.HW.AddReg
    3.  
    4. [filtr.HW.AddReg]
    5. HKR,,"LowerFilters", 0x00010000, "filtr"
     
  12. jne100

    jne100 New Member

    Публикаций:
    0
    Регистрация:
    19 дек 2009
    Сообщения:
    13
    Ну собственно вот что: случилось исключение и оно не было перехвачено (KERNEL_MODE_EXCEPTION_NOT_HANDLED_M), причем есть странный момент:

    Arg1: 80000003, The exception code that was not handled
    Arg2: 80501a3f, The address that the exception occurred at
    Arg3: f78ae4e0, Trap Frame
    Arg4: 00000000

    Здесь сказано что случившееся исключение 80000003 - а это ни много ни мало STATUS_BREAKPOINT, т.е. исключение вызвано сработавшим брекпоинтом (я так полагаю). Т.е. такой код получишь если напишешь в коде что то вроде

    __asm {
    int 3
    }

    или

    DebugBreak();

    Ничего такого в своем драйвере не писал?
     
  13. Jasper

    Jasper New Member

    Публикаций:
    0
    Регистрация:
    30 апр 2010
    Сообщения:
    10
    Да с этой проблемой разобрался. Что-то в этом роде какраз и написал, а именно PAGED_CODE(). На нем система и загибалась)

    Теперь появилась следующая проблема. Я то по глупости надеялся, что мой драйвер встанет где-то между HIDCLASS и HIDUSB, чтобы перехватывать запросы типа IOCTL_HID_GET_DEVICE_DESCRIPTOR и IOCTL_HID_READ_REPORT. А фильтр, судя по всему, встал после HIDUSB и перехватывает только IOCTL_INTERNAL_USB_SUBMIT_URB. Отсюда вопрос, возможно ли его "переставить" в нужное мне место в стеке, или надо вытаскивать данные, соответствующие дескрипторам и отчетам, получаемые в ответ на IOCTL_INTERNAL_USB_SUBMIT_URB? Или возможна какая-либо другая реализация для решения данной задачи?
     
  14. Jasper

    Jasper New Member

    Публикаций:
    0
    Регистрация:
    30 апр 2010
    Сообщения:
    10
    Доброго времени суток!

    Написал фильтр, перехватывающий URB, посылаемые геймпаду. Привязал к соответствующим запросам процедуры, вызываемые по факту их выполнения нижележащим драйвером. Сначала идут запросы типа URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE, из которых я получаю дескрипторы устройства, потом URB_FUNCTION_SELECT_CONFIGURATION, выбирающие конфигурацию устройства, потом URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE, возвращающий дескриптор отчета устройства и уже URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER собственно возвращающие сами отчеты геймпада.
    Собственно провожу анализ отчетов, вывожу в дебаггер сообщения о том, какие кнопки нажаты и т.д. В данном случае драйвер работает нормально.
    Но исходя из своей первоначальной цели, пытаюсь заставить систему видеть джойстик как мышку: добавляю соответствующий код, подменяющий дескрипторы и отчеты геймпада на оные для мыши, устанавливаю сей драйвер, модифицирую запись в реестре в каталоге ENUM->HID (меняю класс устройства (с HIDClass на Mouse) и соответствующие драйверы).
    Включаю устройство, без ошибок проходит весь этап считывания и подмены дескрипторов, а вместо первой же передачи отчета - BSOD:

    Код (Text):
    1. *******************************************************************************
    2. *                                                                             *
    3. *                        Bugcheck Analysis                                    *
    4. *                                                                             *
    5. *******************************************************************************
    6.  
    7. SYSTEM_THREAD_EXCEPTION_NOT_HANDLED (7e)
    8. This is a very common bugcheck.  Usually the exception address pinpoints
    9. the driver/function that caused the problem.  Always note this address
    10. as well as the link date of the driver/image that contains this address.
    11. Arguments:
    12. Arg1: c0000005, The exception code that was not handled
    13. Arg2: 80586219, The address that the exception occurred at
    14. Arg3: f895e93c, Exception Record Address
    15. Arg4: f895e638, Context Record Address
    16.  
    17. Debugging Details:
    18. ------------------
    19.  
    20. *** No owner thread found for resource 80551f60
    21. *** No owner thread found for resource 80551f60
    22. *** No owner thread found for resource 80551f60
    23. *** No owner thread found for resource 80551f60
    24.  
    25. EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - <Unable to get error code text>
    26.  
    27. FAULTING_IP:
    28. nt!PipCallDriverAddDevice+277
    29. 80586219 83780400        cmp     dword ptr [eax+4],0
    30.  
    31. EXCEPTION_RECORD:  f895e93c -- (.exr 0xfffffffff895e93c)
    32. ExceptionAddress: 80586219 (nt!PipCallDriverAddDevice+0x00000277)
    33.    ExceptionCode: c0000005 (Access violation)
    34.   ExceptionFlags: 00000000
    35. NumberParameters: 2
    36.    Parameter[0]: 00000000
    37.    Parameter[1]: 00000004
    38. Attempt to read from address 00000004
    39.  
    40. CONTEXT:  f895e638 -- (.cxr 0xfffffffff895e638)
    41. eax=00000000 ebx=40000000 ecx=45980003 edx=45970002 esi=8265fa98 edi=80584746
    42. eip=80586219 esp=f895ea04 ebp=f895eabc iopl=0         nv up ei pl zr na pe nc
    43. cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00210246
    44. nt!PipCallDriverAddDevice+0x277:
    45. 80586219 83780400        cmp     dword ptr [eax+4],0  ds:0023:00000004=????????
    46. Resetting default scope
    47.  
    48. PROCESS_NAME:  System
    49.  
    50. ERROR_CODE: (NTSTATUS) 0xc0000005 - <Unable to get error code text>
    51.  
    52. EXCEPTION_PARAMETER1:  00000000
    53.  
    54. EXCEPTION_PARAMETER2:  00000004
    55.  
    56. READ_ADDRESS:  00000004
    57.  
    58. FOLLOWUP_IP:
    59. nt!PipCallDriverAddDevice+277
    60. 80586219 83780400        cmp     dword ptr [eax+4],0
    61.  
    62. BUGCHECK_STR:  0x7E
    63.  
    64. DEFAULT_BUCKET_ID:  NULL_CLASS_PTR_DEREFERENCE
    65.  
    66. LOCK_ADDRESS:  80551fe0 -- (!locks 80551fe0)
    67.  
    68. Resource @ nt!IopDeviceTreeLock (0x80551fe0)    Shared 1 owning threads
    69.      Threads: 82a02020-01<*>
    70. 1 total locks, 1 locks currently held
    71.  
    72. PNP_TRIAGE:
    73.     Lock address  : 0x80551fe0
    74.     Thread Count  : 1
    75.     Thread address: 0x82a02020
    76.     Thread wait   : 0x1c57a
    77.  
    78. LAST_CONTROL_TRANSFER:  from 804f7b9d to 80527bdc
    79.  
    80. STACK_TEXT:  
    81. f895eabc 805876c0 00000000 00000001 f895ed54 nt!PipCallDriverAddDevice+0x277
    82. f895ed18 80587b76 825d4ca0 00000001 00000000 nt!PipProcessDevNodeTree+0x1a4
    83. f895ed4c 804f58b1 00000003 80552040 8055b0fc nt!PiProcessReenumeration+0x60
    84. f895ed74 80534c02 00000000 00000000 82a02020 nt!PipDeviceActionWorker+0x141
    85. f895edac 805c6160 00000000 00000000 00000000 nt!ExpWorkerThread+0x100
    86. f895eddc 80541dd2 80534b02 80000001 00000000 nt!PspSystemThreadStartup+0x34
    87. 00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16
    88.  
    89.  
    90. SYMBOL_STACK_INDEX:  0
    91.  
    92. SYMBOL_NAME:  nt!PipCallDriverAddDevice+277
    93.  
    94. FOLLOWUP_NAME:  MachineOwner
    95.  
    96. MODULE_NAME: nt
    97.  
    98. IMAGE_NAME:  ntkrnlpa.exe
    99.  
    100. DEBUG_FLR_IMAGE_TIMESTAMP:  4802516a
    101.  
    102. STACK_COMMAND:  .cxr 0xfffffffff895e638 ; kb
    103.  
    104. FAILURE_BUCKET_ID:  0x7E_VRF_nt!PipCallDriverAddDevice+277
    105.  
    106. BUCKET_ID:  0x7E_VRF_nt!PipCallDriverAddDevice+277
    107.  
    108. Followup: MachineOwner
    109. ---------
    Как я понимаю, указывает он на то, что ошибка произошла где-то в ядре.

    Отсюда собственно вопрос: Это обусловлено какими-либо моими неправильными действиями в области установки драйвера или модификации записи реестра, или же такой способ просто не подходит для решения данной задачи?

    Заранее спасибо)
     
  15. assasincore

    assasincore New Member

    Публикаций:
    0
    Регистрация:
    7 апр 2010
    Сообщения:
    55
    В какой версии WDK вы нашли Фильтер-драйвер на wdf framework?
    Судя со всего это у вам 7600.16385.0\src\usb\usbsamp\sys\
    Прочитайте сначало usbsamp.htm.
    В фильтрирующих драйверах не вызывают функции получения дескрипторов и выборку интерфейса для устройства.

    EXCEPTION_CODE: (NTSTATUS) 0xc0000005 == Думаю понятно

    Вообщем vmware(VirtualBox) + WinDbg (by pipe/com port )

    Не знаю почему, но в этом пример нету бряков...
    в файл private.h, Добавляете
    #if DBG
    # DBG_ALLOW_BREAKPOINT 1
    #endif

    #DBG_ALLOW_BREAKPOINT
    # MyDbgBreakpoint() __asm {int 3}
    #else
    # MyDbgBreakpoint() //nothing
    #endif

    После чего раставляете MyDbgBreakpoint().
    И в перет.
     
  16. Jasper

    Jasper New Member

    Публикаций:
    0
    Регистрация:
    30 апр 2010
    Сообщения:
    10
    драйвер писал на основе примеров
    \WinDDK\7600.16385.1\src\hid\hidusbfx2
    \WinDDK\7600.16385.1\src\input\moufiltr
    \WinDDK\7600.16385.1\src\general\toaster\kmdf\filter\

    Я не говорил, что вызываю эти функции, а только перехватвыю запросы URB, которые посылает минидрайвер и присваиваю им callback-процедуры, в которых читаю содержимое буфера ответного URB-пакета, откуда и получаю соответствующие дескрипторы. Сам фильтрующий драйвер не является источником никаких запросов, а только посредником в их передаче по стеку!

    И еще раз, эта проблема возникает только при попытке "подмены устройства". В противном случае драйвер работает нормально.

    Честно говоря, не очень то понятно. И чем мне тут может помочь расстановка брейкпоинтов?
     
  17. assasincore

    assasincore New Member

    Публикаций:
    0
    Регистрация:
    7 апр 2010
    Сообщения:
    55
    Вот и смотри в какой функции падает, а точнее после какой функции падает ...
    Вы уверены что устройство работает корректно? то и есть все дескрипторы и все такое?
     
  18. Jasper

    Jasper New Member

    Публикаций:
    0
    Регистрация:
    30 апр 2010
    Сообщения:
    10
    Если речь идет про сам геймпад, то десрипторы, которые я извлекаю из буфера пакета URB полностью совпадают. Если имеются в виду дескрипторы, которыми я заменяю реальные, то они взяты из спецификации HID USB, поэтому с ними проблем по идее быть не должно.
    В случае без замены дескрипторов, геймпад системой и приложениями определяется нормально, без косяков.
     
  19. assasincore

    assasincore New Member

    Публикаций:
    0
    Регистрация:
    7 апр 2010
    Сообщения:
    55
    Значит касяки в замене дескрипторов .... А дальше ... Ядро ? Не известно что происходит в соединение устройства и винды....
     
  20. Llirik

    Llirik Member

    Публикаций:
    0
    Регистрация:
    18 июл 2008
    Сообщения:
    468
    То есть удалить все PAGED_CODE? Дело в том, что у меня происходит точно такой же бсод "system_thread_exception_not_handled STATUS_BREAKPOINT ".
    Код моего FDO:
    Код (Text):
    1. #include "MKJoy.h"
    2.  
    3. NTSTATUS DriverEntry (PDRIVER_OBJECT, PUNICODE_STRING);
    4.  
    5. #ifdef ALLOC_PRAGMA
    6. #pragma alloc_text (INIT, DriverEntry)
    7. #pragma alloc_text (PAGE, MKJoy_AddDevice)
    8. #pragma alloc_text (PAGE, MKJoy_PnP)
    9. #pragma alloc_text (PAGE, MKJoy_Power)
    10. #pragma alloc_text (PAGE, MKJoy_Unload)
    11. #endif
    12.  
    13. NTSTATUS
    14. DriverEntry (
    15.   IN  PDRIVER_OBJECT  DriverObject,
    16.   IN  PUNICODE_STRING RegistryPath
    17.   )
    18. /*++
    19. Routine Description:
    20.  
    21.   Initialize the entry points of the driver.
    22.  
    23. --*/
    24. {
    25.  
    26.    HID_MINIDRIVER_REGISTRATION reg;
    27.   //
    28.   // Fill in all the dispatch entry points with the pass through function
    29.   // and the explicitly fill in the functions we are going to intercept
    30.   //
    31. //   DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = MKJoy_DispatchPassThrough;
    32.   DriverObject->MajorFunction [IRP_MJ_PNP] =  MKJoy_PnP;
    33.   DriverObject->MajorFunction [IRP_MJ_POWER] =  MKJoy_Power;
    34.   DriverObject->DriverExtension->AddDevice = MKJoy_AddDevice;
    35.  
    36.    RtlZeroMemory(&reg, sizeof(reg));
    37.    reg.Revision = HID_REVISION;
    38.    reg.DriverObject = DriverObject;
    39.    reg.RegistryPath = RegistryPath;
    40.    reg.DeviceExtensionSize = 0; //sizeof(DEVICE_EXTENSION) + GetSizeofGenericExtension();
    41.    reg.DevicesArePolled = FALSE;
    42.  
    43.    return HidRegisterMinidriver(&reg);
    44. }
    45.  
    46. NTSTATUS
    47. MKJoy_AddDevice(
    48.   IN PDRIVER_OBJECT  Driver,
    49.   IN PDEVICE_OBJECT  PDO
    50.   )
    51. {
    52.   PAGED_CODE();
    53.  
    54.   return STATUS_SUCCESS;
    55. }
    56.  
    57. NTSTATUS
    58. MKJoy_Complete(
    59.   IN PDEVICE_OBJECT  DeviceObject,
    60.   IN PIRP  Irp,
    61.   IN PVOID  Context
    62.   )
    63. /*++
    64. Routine Description:
    65.  
    66.   Generic completion routine that allows the driver to send the irp down the
    67.   stack, catch it on the way up, and do more processing at the original IRQL.
    68.    
    69. --*/
    70. {
    71.   PKEVENT  event;
    72.  
    73.   event = (PKEVENT) Context;
    74.  
    75.   //
    76.   // We could switch on the major and minor functions of the IRP to perform
    77.   // different functions, but we know that Context is an event that needs
    78.   // to be set.
    79.   //
    80.   KeSetEvent(event, 0, FALSE);
    81.  
    82.   //
    83.   // Allows the caller to use the IRP after it is completed
    84.   //
    85.   return STATUS_MORE_PROCESSING_REQUIRED;
    86. }
    87.  
    88. NTSTATUS
    89. MKJoy_DispatchPassThrough(
    90.   IN PDEVICE_OBJECT DeviceObject,
    91.   IN PIRP Irp
    92.   )
    93. /*++
    94. Routine Description:
    95.  
    96.   Passes a request on to the lower driver.
    97.    
    98. Considerations:
    99.    
    100.   If you are creating another device object (to communicate with user mode
    101.   via IOCTLs), then this function must act differently based on the intended
    102.   device object.  If the IRP is being sent to the solitary device object, then
    103.   this function should just complete the IRP (becuase there is no more stack
    104.   locations below it).  If the IRP is being sent to the PnP built stack, then
    105.   the IRP should be passed down the stack.
    106.    
    107.   These changes must also be propagated to all the other IRP_MJ dispatch
    108.   functions (such as create, close, cleanup, etc.) as well!
    109.  
    110. --*/
    111. {
    112.   PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
    113.  
    114.   //
    115.   // Pass the IRP to the target
    116.   //
    117.   IoSkipCurrentIrpStackLocation(Irp);
    118.   return IoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
    119. }  
    120. NTSTATUS
    121. MKJoy_PnP(
    122.   IN PDEVICE_OBJECT DeviceObject,
    123.   IN PIRP Irp
    124.   )
    125. /*++
    126.  
    127. Routine Description:
    128.  
    129.   This routine is the dispatch routine for plug and play irps
    130.  
    131. Arguments:
    132.  
    133.   DeviceObject - Pointer to the device object.
    134.  
    135.   Irp - Pointer to the request packet.
    136.  
    137. Return Value:
    138.  
    139.   Status is returned.
    140.  
    141. --*/
    142. {
    143.   PHID_DEVICE_EXTENSION  devExt;
    144.   PIO_STACK_LOCATION  irpStack;
    145.   NTSTATUS  status = STATUS_SUCCESS;
    146.   KIRQL  oldIrql;
    147.   KEVENT  event;  
    148.  
    149.   PAGED_CODE();
    150.  
    151.   devExt = (PHID_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
    152.   irpStack = IoGetCurrentIrpStackLocation(Irp);
    153.  
    154.   switch (irpStack->MinorFunction) {
    155.   case IRP_MN_START_DEVICE: {
    156.  
    157.   //
    158.   // The device is starting.
    159.   //
    160.   // We cannot touch the device (send it any non pnp irps) until a
    161.   // start device has been passed down to the lower drivers.
    162.   //
    163.   IoCopyCurrentIrpStackLocationToNext(Irp);
    164.   KeInitializeEvent(&event,
    165.   NotificationEvent,
    166.   FALSE
    167.   );
    168.  
    169.   IoSetCompletionRoutine(Irp,
    170.   (PIO_COMPLETION_ROUTINE) MKJoy_Complete,
    171.   &event,
    172.   TRUE,
    173.   TRUE,
    174.   TRUE); // No need for Cancel
    175.  
    176.   status = IoCallDriver(devExt->NextDeviceObject, Irp);
    177.  
    178.   if (STATUS_PENDING == status) {
    179.   KeWaitForSingleObject(
    180.   &event,
    181.   Executive, // Waiting for reason of a driver
    182.   KernelMode, // Waiting in kernel mode
    183.   FALSE, // No allert
    184.   NULL); // No timeout
    185.   }
    186.   Irp->IoStatus.Status = status;
    187.   Irp->IoStatus.Information = 0;
    188.   IoCompleteRequest(Irp, IO_NO_INCREMENT);
    189.  
    190.   break;
    191.   }
    192.   default:
    193.   //
    194.   // Here the filter driver might modify the behavior of these IRPS
    195.   // Please see PlugPlay documentation for use of these IRPs.
    196.   //
    197.   IoSkipCurrentIrpStackLocation(Irp);
    198.   status = IoCallDriver(devExt->NextDeviceObject, Irp);
    199.   break;
    200.   }
    201.  
    202.   return status;
    203. }
    204.  
    205. NTSTATUS
    206. MKJoy_Power(
    207.   IN PDEVICE_OBJECT  DeviceObject,
    208.   IN PIRP  Irp
    209.   )
    210. /*++
    211.  
    212. Routine Description:
    213.  
    214.   This routine is the dispatch routine for power irps  Does nothing except
    215.   record the state of the device.
    216.  
    217. Arguments:
    218.  
    219.   DeviceObject - Pointer to the device object.
    220.  
    221.   Irp - Pointer to the request packet.
    222.  
    223. Return Value:
    224.  
    225.   Status is returned.
    226.  
    227. --*/
    228. {
    229.   PHID_DEVICE_EXTENSION  devExt;
    230.  
    231.   PAGED_CODE();
    232.  
    233.   devExt = (PHID_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
    234.   PoStartNextPowerIrp(Irp);
    235.   IoSkipCurrentIrpStackLocation(Irp);
    236.   return PoCallDriver(devExt->NextDeviceObject, Irp);
    237. }