Hi,
Just a few notes, if I may.
Any and all Endpoint Descriptors are contained within the Interface Descriptor which is contained within the Config Descriptor. However, please note that there can be multiple Interface Descriptors *and* multiple Config Descriptors, as well as Alternate Interface Descriptors containing multiple Interface Descriptors all grouped together. Try enumerating a camera device with multiple resolution capabilities and you will see.
foliagecanine wrote:Protocol 3 for a USB keyboard? I would think it would be protocol 1. Also, the USB mouse returns these same values.
Edit: A bug in my code caused the class to be displayed for all 3 values. This is fixed. However, the other problems still remain
Even with USB, backward compatibility comes into play. Most HID mice and keyboards will allow you to set the protocol used. This protocol usually defaults to the Boot Protocol returning a known and set Report Descriptor. For example, the Boot Protocol for the Mouse might be
Code: Select all
byte 0: Buttons
byte 1: X displacement
byte 2: Y displacement
This is so a Legacy BIOS or other firmware can enumerate and use most any mouse before a vendor specific driver is installed. Once this driver is installed, it can query the mouse for other report formats and then choose one of these formats, which might be the same or could be completely different.
This is where the HID comes into play. Using the "Get Report Descriptor Request", you can retrieve the HID values that will describe the report returned. Here is an example from page 15-9 of
my book:
Code: Select all
0x00000000 05 01 09 02 A1 01 09 01-A1 00 05 09 19 01 29 03
0x00000010 15 00 25 01 75 01 95 03-81 02 75 05 95 01 81 01
0x00000020 05 01 09 30 09 31 09 38-15 81 25 7F 75 08 95 03
0x00000030 81 06 C0 09 3C 05 FF 09-01 15 00 25 01 75 01 95
0x00000040 02 B1 22 75 06 95 01 B1-01 C0
It should describe the following (or similar) report:
Code: Select all
byte 0: Buttons
Bits 7-3 = reserved
Bit 2 = Button 3
Bit 1 = Button 2
Bit 0 = Button 1
byte 1: X displacement
Range of -127 to +127
byte 2: Y displacement
Range of -127 to +127
byte 3: Z displacement
Range of -127 to +127
If you use the
HIDParser utility included with the source code of my book, you can see how this works. For example, here is part of a Report Descriptor from another mouse:
Code: Select all
05 01 Usage Page (Generic Desktop)
09 02 Usage (Mouse)
A1 01 Collection (Application)
09 01 Usage (Pointer) (Inherits the Usage Page)
A1 00 Collection (Physical)
05 01 Usage Page (Generic Desktop)
09 30 Usage (X)
09 31 Usage (Y)
09 38 Usage (Wheel)
15 81 Logical Min (-127)
25 7F Logical Max (127)
75 08 report size (8)
95 03 report count (3)
81 06 Input (Data,Var,Rel,NoW,Lin,PState,NoNull,Bit)
Notice that the report describes three (3) usage items (X, Y, Wheel), describes that they all use a range of -127 to +127, the report size is 8 bits per, and there are three (3) items. This gives the format of the X, Y, and Z parts of the report.
Since the buttons are of a different size (1 instead of 8), and a different Logical Min and Max, (0 to 1, instead of -127 to +127), a new set of parameters are given and another "action" line is used. Here is a section that might describe these buttons:
Code: Select all
15 00 Logical Min (0)
25 01 Logical Max (1)
75 01 report size (1)
95 02 report count (2)
B1 22 Feature (Data,Var,Abs,NoW,Lin,NoPre,NoNull,Bit)
75 06 report size (6)
95 01 report count (1)
B1 01 Feature (Cons,Array,Abs,NoW,Lin,PState,NoNull,Bit)
Notice now that the Logical Min and Max, the Size, and the Count have changed. Also notice that there are six (6) reserved bits after these buttons and before the next item. Imagine if these six (6) bits were not given--the X, Y, and Z values would be unaligned. (A small tidbit would be that the manufacturer could have used a reserved field of six 1-bit fields compared to one 6-bit field).
Another thing to know about periodic driven devices, such as mice, is you have to tell the device how often to report this information. A Mouse might report it so often that all of your USB Stack Bandwidth is used up on Movement Reports, almost all of these reports being the exact same thing. Therefore, it is a good idea to send the "Set Idle" request to the mouse to tell it to only report a change in a report, rather than constantly reporting the same report. However, with this in mind you have to handle Stalls and Request Errors. Not all mice support the "Set Idle" request.
Back to the Set Protocol Request. Once you know what type of mouse you have and its capabilities, now you can tell the mouse what HID report to return. Imagine a gaming mouse with all three axis and multiple buttons as well as two or three wheels. All perfectly legal and acceptable as long as you parse the HID report correctly and then know what to do with the results.
Chapter 15 of my book explains in detail what you should expect from a typical mouse, how to set it up, and then the reports it might return. Chapter 16 does this for HID keyboards. Chapter 25 along with the source code mentioned above, describes how to parse an HID Report.
Just for fun, HID devices are practically unlimited on what can be done. For example, have you ever played one of those modern Game Consoles and the handheld controller vibrates on occasion? This may simply be an HID report sent to the controller to "turn on" vibration, and then another sent again to "turn it off". These controllers also have motion controls that may simply be an axis value via an HID report descriptor.
Did you know that a keyboard accepts an HID report from the host? A keyboard usually only sends reports to the host when a key is pressed or released. However, the keyboard might accept a report from the host to turn on or off the Status LEDs. If the interface includes an INTERRUPT OUT endpoint, it might have an HID report identifying the format to use. If the interface doesn't contain an INTERRUPT OUT endpoint, sending the "Set Report" request can be used. One thing to remember, turning on or off one of the LEDs does not change the status of the keyboard's state. The LEDs are simply an indicator and your driver must keep it in sync with the state of the keyboard, also noting that the keyboard itself does not keep a Caps-Lock (or other) state. It is simply a key to tell the host to set an internal state.
What an interesting hobby we have, huh?
Hope this helps,
Ben