Input report 0: 00 00 00 00 00 00 00 00 A released

     Usages set: (Break: 04) (Make: )

     Input report 0: 00 00 05 00 00 00 00 00 B pressed

     Usages set: 07:05 (Break: ) (Make: 05)

     Input report 0: 00 00 00 00 00 00 00 00 B released

     Usages set: (Break: 05) (Make: )

     Input report 0: 00 00 06 00 00 00 00 00 C pressed

     Usages set: 07:06 (Break: ) (Make: 06)

     Input report 0: 00 00 00 00 00 00 00 00 C released

     Usages set: (Break: 06) (Make: )

     Input report 0: 00 00 29 00 00 00 00 00 Esc pressed

     Usages set: 07:29 (Break: ) (Make: 29)

Test 3

     Output report: 00

     Wrote output report OK

     Output report: 04

     Wrote output report OK

     Output report: 02

     Wrote output report OK

     Output report: 01

     Wrote output report OK

     Output report: 06

     Wrote output report OK

     Output report: 05

     Wrote output report OK

     Output report: 03

     Wrote output report OK

     Output report: 07

     Wrote output report OK

     Output report: 00

     Wrote output report OK

Test 4

     CloseHandle worked

Kernel Mode HID Clients

A device driver can talk to a HID device using the HID class driver. As mentioned previously, it is far easier to write a user mode application to control a HID device. However, you may find that it is necessary to write a HID client driver (e.g., if you need to implement an existing device API). A kernel client should be more efficient than a user mode client, though speed ought not to be a problem for most human input devices.

Client Types

A kernel mode HID client can take one of two main forms, depending on how it relates to devices. An 'AddDevice' HID client uses installation files (as usual) to layer itself above the HID class driver for each device. Alternatively, 'Plug and Play Notification' HID client driver is not initially associated with any one device. Instead, it receives notifications when a HID device arrives or disappears. A PnP Notification HID client makes its own device objects if a HID device of interest arrives.

As I have not examined Plug and Play Notification before, this chapter's example driver, HidKbd, uses this technique.

'AddDevice' HID Clients

An 'AddDevice' HID client will look like all the previous WDM device drivers. The driver is loaded using installation INF files in the normal way. The driver's AddDevice routine is called when a suitable device is loaded. The driver must handle Plug and Play IRPs in the same way as usual.

An 'AddDevice' HID client makes calls to the HID class driver by calling the NextStackDevice as usual. The HID class driver responds to read and write requests as well as various IOCTL IRPs.

As is usual for WDM drivers, your driver's upper edge may be completely different. For example, the kbdhid.sys system keyboard driver has an upper edge that reports 8042 equivalent key presses. However, kbdhid.sys makes HID requests on its lower edge to find the HID keyboard data.

Things can now get complicated. Note that user mode clients will still be able to find the HID device. If they try to send HID requests to the HID device, these requests will be routed to your driver first. If your driver implements some other upper edge, it will not recognize these requests. Or, if you are being very clever, you could recognize when HID operations have been requested and route them straight through to the HID class driver. If you do this job, you are acting as a HID filter driver.

All in all, it is probably easier if you do not use the 'AddDevice' device technique when writing a HID client driver. Therefore, I shall take a close look at how to write a Plug and Play Notification client. However, kernel mode PnP Notification does not seem to work in Windows 98, so you will have to write an 'AddDevice' client.

'PnP Notification' HID Clients

A PnP Notification HID client is usually an NT style driver. Therefore, it is not loaded as a result of a device being plugged in. As an NT style driver, it is usually loaded when the system boots up. Installation INF files are not used. Instead, you must write a custom installation program, as described in Chapter 11.

The DriverEntry routine calls the IoRegisterPlugPlayNotification function to ask to receive any device interface change events for a particular device interface GUID. The driver AbcUnload routine calls IoUnregisterPlugPlayNotification to indicate that it no longer wants to receive such notifications.

In this case, the device interface change callback is informed whenever any HID device is plugged into the system. The HidKbd code then interrogates the device to see if it is a HID keyboard. If it is, it creates a HidKbd device.

Just to complicate matters, HidKbd now has two options. First, it can layer itself over the HID device so that is becomes part of the device stack for this device. However, this suffers from the same drawbacks as the 'AddDevice' technique, that user mode requests to the HID device would be routed to HidKbd.

The HidKbd driver takes the second option. HidKbd stores a pointer to the HID device object, but does not layer itself above the HID device. Both HidKbd and a user mode application can therefore call the HID class driver safely.

Plug and Play Notifications

Kernel mode drivers can register to receive three different types of notification events. As far as I can tell, none of these notifications work in Windows 98, as calling IoRegisterPlugPlayNotification seems to hang the system. Therefore, ail the subsequent discussion here applies to Windows 2000 only. The Beta 2 version of W2000 let the HidKbd driver access the HID keyboard. Later versions do not, so most of the code in HidKbd will now not run.

Table 23.2 shows how to call IoRegisterPlugPlayNotification. The EventCategory parameter specifies what type of event you want to receive. HidKbd only asks for device interface change events, EventCategoryDeviceInterfaceChange, and so passes the relevant GUID as the EventCategoryData parameter. It also specifies the PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES flag as the EventCategoryFlags parameter. This means that it receives notifications straightaway for any existing devices that support the given interface.

If you register to receive EventCategoryHardwareProfileChange events, you are supposed to receive hardware profile change events. The callback is told whether a Query Change, Change Complete, or Change Cancelled event occurred.

Registering for EventCategoryTargetDeviceChange events asks for notifications when a target device is removed. You must pass a PFILE_OBJECT as the EventCategoryFlags. The callback is told whether a Query Remove, Remove Complete, or Remove Cancelled event occurred. In my mind, there is a fundamental flaw to this notification. You must pass a file object to IoRegisterPlugPlayNotification. To have a file object pointer, you must have opened a file. If a file is open on a device, Windows 2000 automatically stops any PnP remove request for the device. When I tried it, my target device callback received a Query Remove event followed straightaway by a Remove Cancelled event. It seems as though registering for target device notifications automatically stops any remove requests from completing.

Table 23.2 IoRegisterPlugPlayNotification function

NTSTATUS IoRegisterPlugPlayNotification (IRQL==PASSIVE_LEVEL)
Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату