Êíèãà: Writing Windows WDM Device Drivers
Sending Output Reports
Ðàçäåëû íà ýòîé ñòðàíèöå:
Sending Output Reports
You send HID output reports using the Win32 WriteFile function. While you can build the output buffer by hand, it is safer to use the HID parsing routines to fill in the buffer.
The SetLEDs function shown in Listing 23.5 shows how a single output report is sent to set the state of the HID keyboard LEDs. It has three optional parameters, which must contain the individual LED usages that you want set on. This line in the HidUsbUser main routine shows how to turn the ScrollLock LED on and turn the other LEDs off.
SetLEDs(hHidKbd, OutputReportLen, HidPreparsedData, HID_USAGE_LED_SCROLL_LOCK);
A keyboard output report consists of just one byte. However, as before, the output buffer must have an extra byte at the beginning for the report ID. This is set to zero in this case, as keyboards do not use report IDs. SetLEDs allocates an output buffer and zeroes it.
SetLEDs must now build an array of USAGEs, filled with any of its optional parameters that are non-zero. This array and its length are passed to HidP_SetButtons. HidP_SetButtons builds the output buffer in the correct format. SetLEDs then simply calls WriteFile to send off the output report.
You can call HidP_SetButtons more than once for a single output report. Indeed, you may also want to call one of the set value functions, if the output report must contain values. Set values into an output report using the HidP_SetUsageValue, HidP_SetScaledUsageValue, and HidP_SetUsageValueArray functions.
Be careful if you are using a HID device that has more than one output report. HidP_SetButtons can only build one output report at a time. HidP_SetButtons sets the report ID, if appropriate. If a second call to HidP_SetButtons tries to set a usage that is not in the first report, it fails with a suitable error code. However, if you start afresh with a new output report and repeat the second call to HidP_SetButtons, it should work this time. This whole process makes it particularly laborious to set output usages in a way that is truly independent of the device that is attached.
Listing 23.5 Setting keyboard LEDs using an output HID report
void SetLEDs(HANDLE hHidKbd, USHORT OutputReportLen, PHIDP_PREPARSED_DATA HidPreparsedData,
USAGE Usage1/*=0*/, USAGE Usage2/*=0*/, USAGE Usage3/*=0*/) {
// Build Output report from given usage(s)
char* OutputReport = new char[OutputReportLen];
assert(OutputReport!=NULL);
memset(OutputReport, 0, OutputReportLen);
USAGE UsageList[3];
UsageList[0] = Usage1;
UsageList[1] = Usage2;
UsageList[2] = Usage3;
ULONG UsageLength = 0;
if (Usage1!=0) {
UsageLength++;
if (Usage2!=0) {
UsageLength++;
if (Usage3!=0) {
UsageLength++;
}
}
}
// Convert usages into an output report
NTSTATUS status = HidP_SetButtons(HidP_Output, HID_USAGE_PAGE_LED, 0, UsageList, &UsageLength, HidPreparsedData, OutputReport, OutputReportLen);
if (status!=HIDP_STATUS_SUCCESS) {
delete OutputReport;
return;
}
printf(" Output report: ");
for (ULONG i=1; i<OutputReportLen; i++) printf(" %02X", OutputReport[i]);
printf("n");
// Send off output report
DWORD TxdBytes;
if (!WriteFile(hHidKbd, OutputReport, OutputReportLen, &TxdBytes, NULL))
printf("XXX Could not write value %dn", GetLastError());
else if (TxdBytes==OutputReportLen) printf(" Wrote output report 0Kn");
else printf("XXX Wrong number of bytes written: %dn",TxdBytes);
delete OutputReport;
}
Other User Mode HID Client Functions
User mode HID clients can send and receive HID feature reports. Use HidD_GetFeature to get a feature report. The first byte of the buffer must be set to the report ID that you want to receive. The received feature report can be analyzed using HidP_GetButtonsEx, etc., as usual. Use HidD_SetFeature to send a feature report. Beforehand, use HidP_SetButtons, etc., to build up the feature report in the correct format, as usual.
HidD_FlushQueue deletes all pending information from the input queue for this HID device.
The functions HidD_GetNumInputBuffers and HidD_SetNumInputBuffers may be available in the future to let you get or set the ring buffer size used by the HID class driver for this device[58].
Running HidKbdUser
If you have a HID keyboard, you can run HidKbdUser yourself. For the benefit of those who do not, Listing 23.6 shows some example output. As mentioned earlier, HidKbdUser will not run in W2000 as the HID keyboard device cannot be shared.
There is only one HID device in the system. It is opened and HidKbdUser finds that it is a HID keyboard, as the top-level usage page and usage are the correct values. HidKbdUser then prints out the capabilities of the device.
Test 2 reads any input reports from the HID keyboard. In this example, I pressed Ctrl+Alt+Del followed by A, B, C, and Esc. You can see how an input report is produced every time a key is pressed or released. The actual input report is in exactly the same format as the raw USB interrupt transfer shown in Table 21.9.
If you remember from Chapter 21, the USB example driver, UsbKbd, kept on receiving input interrupt data even if no state changes had occurred. The HID class driver sensibly filters out these redundant input reports and only returns data when a key is pressed or released.
Test 3 sends several output reports to flash the LEDs on the keyboard. HidKbdUser calls the SetLEDs function several times for different LED combinations with a short delay between each call.
Listing 23.6 Example HidKbdUser output
Test 1
Symbolic link is .00000000000000b#{4d1e55b2-f16f-11cf-88cb-001111000030}
Found HID device
HID attributes: VendorID=046A, ProductID=0001, VersionNumber=0305
Top level Usage page 1 usage 6
Found HID keyboard
InputReportByteLength 9
OutputReportByteLength 2
FeatureReportByteLength 0
NumberLinkCollectionNodes 1
NumberInputButtonCaps 2
NumberInputValueCaps 0
NumberOutputButtonCaps 1
NumberOutputValueCaps 0
NumberFeatureButtonCaps 0
NumberFeatureValueCaps 0
Input button capabilities
ButtonCaps[0].UsagePage 7
.Usages 224..231
ButtonCaps[1].UsagePage 7
.Usages 0..101
Output button capabilities
ButtonCaps[0].UsagePage 8
.Usages 1..3
Opened OK
Test 2
Input report 0: 01 00 00 00 00 00 00 00 Left Ctrl pressed
Usages set: 07:E0 (Break: ) (Make: E0)
Input report 0: 05 00 00 00 00 00 00 00 Left Alt pressed
Usages set: 07:E0 07:E2 (Break: ) (Make: E2)
Input report 0: 05 00 63 00 00 00 00 00 Del pressed
Usages set: 07:E0 07:E2 07:63 (Break: ) (Make: 63)
Input report 0: 05 00 00 00 00 00 00 00 Del released
Usages set: 07:E0 07:E2 (Break: 63) (Make: )
Input report 0: 00 00 00 00 00 00 00 00 Left Ctrl & Alt released
Usages set: (Break: E0 E2) (Make: )
Input report 0: 00 00 04 00 00 00 00 00 A pressed
Usages set: 07:04 (Break: ) (Make: 04)
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
- Data sending and control session
- OUTPUT chain
- 8.4.2. Sending and Receiving Messages
- Compressing, Encrypting, and Sending tar Streams
- Paging Through Output with less
- Using the Backtick to Replace a String with Output
- 14.5.1. Early Serial Debug Output
- 3.2 PIC Microcontroller Input-Output Port Programming
- 1.3.9 Serial Input-Output
- PROJECT 8.1 — USB-Based Microcontroller Output Port
- PROJECT 10.3 — Voltmeter with RS232 Serial Output
- 7.6.2 Sending and Receiving Messages