USB Human Interface Devices: Difference between revisions
Jump to navigation
Jump to search
[unchecked revision] | [unchecked revision] |
Content deleted Content added
m →Parsing: Where'd that come from |
m →USB Report Protocol: Del section misplaced |
||
Line 228: | Line 228: | ||
'''Y movement:''' This is also a signed 8-bit integer that represents the Y movement. When this value is negative, the mouse is being moved up. When the value is positive, the mouse is being moved down (towards the user.) |
'''Y movement:''' This is also a signed 8-bit integer that represents the Y movement. When this value is negative, the mouse is being moved up. When the value is positive, the mouse is being moved down (towards the user.) |
||
== USB Report Protocol == |
|||
This is the complicated one supported by all HID class devices. Mouses, keyboards, joysticks... |
|||
The interface descriptor will contain an HID descriptor alongside the endpoint descriptors: |
|||
{| width="70%" border="1" |
|||
!Offset |
|||
!Field |
|||
!Size |
|||
!Type |
|||
!Description |
|||
|- valign="top" |
|||
|align="center" |0 |
|||
|bLength |
|||
|align="center" |1 |
|||
|align="center" |Number |
|||
|Size of this descriptor in bytes |
|||
|- valign="top" |
|||
|align="center" |1 |
|||
|bDescriptorType |
|||
|align="center" |1 |
|||
|align="center" |Constant |
|||
|HID Descriptor Type (0x22) |
|||
|- valign="top" |
|||
|align="center" |2 |
|||
|bcdHID |
|||
|align="center" |2 |
|||
|align="center" |BCD |
|||
|HID Class Specification Release Number in Binary-Coded Decimal (i.e, 1.10 is expressed as 110h). |
|||
|- valign="top" |
|||
|align="center" |4 |
|||
|bCountryCode |
|||
|align="center" |1 |
|||
|align="center" |ID |
|||
|Country code of localised hardware (0 if irrelevant. Mainly for keyboards). |
|||
|- valign="top" |
|||
|align="center" |5 |
|||
|bNumDescriptors |
|||
|align="center" |1 |
|||
|align="center" |Number |
|||
|Number of descriptors >= 1 |
|||
|- valign="top" |
|||
|align="center" |3i+6 |
|||
|bDescriptorType |
|||
|align="center" |1 |
|||
|align="center" |Number |
|||
|Type of HID descriptor |
|||
|- valign="top" |
|||
|align="center" |3i+7 |
|||
|wDescriptorLength |
|||
|align="center" |2 |
|||
|align="center" |Number |
|||
|Length of HID Descriptor |
|||
|} |
|||
There is always one descriptor, a Report Descriptor, followed by n Optional Descriptors. The types and lengths only are in an array at the end of the overarching HID Descriptor. |
|||
'''HID Descriptor Types''' |
|||
{| border="1" cellpadding="2" |
|||
!Value |
|||
!Description |
|||
|- |
|||
|align="center" |21h |
|||
|HID Descriptor |
|||
|- |
|||
|align="center" |22h |
|||
|Report Descriptor |
|||
|- |
|||
|align="center" |23h |
|||
|Physical Descriptor |
|||
|} |
|||
To get the details of these descriptors, use the standard USB [[USB#GET_DESCRIPTOR|GET_DESCRIPTOR]], but with an interface recipient. |
|||
{| align="center" border="1" cellpadding="5" |
|||
!bmRequestType |
|||
!bRequest |
|||
!colspan="2" |wValue |
|||
!wIndex |
|||
!wLength |
|||
|- align="center" |
|||
|10000001b |
|||
|GET_DESCRIPTOR<br />6 |
|||
|Descriptor Type |
|||
|Descriptor Index |
|||
|Interface Number |
|||
|Descriptor<br />Length |
|||
|} |
|||
Descriptor Index is 0 except for Physical Descriptors, where Index 0 will enumerate descriptor sets and their sizes. |
|||
===Country Codes=== |
|||
{| border="1" cellpadding="2" |
|||
!Value |
|||
!Country |
|||
!Value |
|||
!Country |
|||
!Value |
|||
!Country |
|||
!Value |
|||
!Country |
|||
!Value |
|||
!Country |
|||
|- |
|||
|align="center" |00h |
|||
|''Not Supported'' |
|||
|align="center" |08h |
|||
|French |
|||
|align="center" |10h |
|||
|Korean |
|||
|align="center" |18h |
|||
|Slovakia |
|||
|align="center" |20h |
|||
|UK |
|||
|- |
|||
|align="center" |01h |
|||
|Arabic |
|||
|align="center" |09h |
|||
|German |
|||
|align="center" |11h |
|||
|Latin American |
|||
|align="center" |19h |
|||
|Spanish |
|||
|align="center" |21h |
|||
|US |
|||
|- |
|||
|align="center" |02h |
|||
|Belgian |
|||
|align="center" |0Ah |
|||
|Greek |
|||
|align="center" |12h |
|||
|Netherlands |
|||
|align="center" |1Ah |
|||
|Swedish |
|||
|align="center" |22h |
|||
|Yugoslavia |
|||
|- |
|||
|align="center" |03h |
|||
|Canadian-Bilingual |
|||
|align="center" |0Bh |
|||
|Hebrew |
|||
|align="center" |13h |
|||
|Norwegian |
|||
|align="center" |1Bh |
|||
|Swiss/French |
|||
|align="center" |23h |
|||
|Turkish-F |
|||
|- |
|||
|align="center" |04h |
|||
|Canadian-French |
|||
|align="center" |0Ch |
|||
|Hungary |
|||
|align="center" |14h |
|||
|Persian |
|||
|align="center" |1Ch |
|||
|Swiss/German |
|||
|- |
|||
|align="center" |05h |
|||
|Czechia |
|||
|align="center" |0Dh |
|||
|International (ISO) |
|||
|align="center" |15h |
|||
|Poland |
|||
|align="center" |1Dh |
|||
|Switzerland |
|||
|- |
|||
|align="center" |06h |
|||
|Danish |
|||
|align="center" |0Eh |
|||
|Italian |
|||
|align="center" |16h |
|||
|Portuguese |
|||
|align="center" |1Eh |
|||
|Taiwan |
|||
|- |
|||
|align="center" |07h |
|||
|Finnish |
|||
|align="center" |0Fh |
|||
|Japan (Katakana) |
|||
|align="center" |17h |
|||
|Russia |
|||
|align="center" |1Fh |
|||
|Turkish-Q |
|||
|} |
|||
=== Report Descriptor === |
|||
This is not a value table, length and content vary as required. |
|||
It's a sequential list of items. Items come in two basic types, short and long. |
|||
==== Short Item==== |
|||
{| width="70%" border="1" |
|||
!Offset |
|||
!Field |
|||
!Size |
|||
!Type |
|||
!Description |
|||
|- valign="top" |
|||
|align="center" |0:0 |
|||
|bSize |
|||
|align="center" |2 bits |
|||
|align="center" |Enum |
|||
|Size of optional data in bytes |
|||
|- valign="top" |
|||
|align="center" |0:2 |
|||
|bType |
|||
|align="center" |2 bits |
|||
|align="center" |Enum |
|||
|Type of this descriptor |
|||
|- valign="top" |
|||
|align="center" |0:4 |
|||
|bTag |
|||
|align="center" |4 bits |
|||
|align="center" |Number |
|||
|Function of the item |
|||
|- valign="top" |
|||
|align="center" |1 |
|||
|Data |
|||
|align="center" |bSize |
|||
|align="center" |Data |
|||
|Item data |
|||
|} |
|||
Note that as a special case a bSize of 3 corresponds to 4 bytes. |
|||
'''bType''': |
|||
{| border="1" cellpadding="2" |
|||
!Value |
|||
!Description |
|||
|- |
|||
|align="center" |00h |
|||
|Main |
|||
|- |
|||
|align="center" |01h |
|||
|Global |
|||
|- |
|||
|align="center" |02h |
|||
|Local |
|||
|- |
|||
|align="center" |03h |
|||
|Reserved |
|||
|} |
|||
==== Long Item==== |
|||
{| width="70%" border="1" |
|||
!Offset |
|||
!Field |
|||
!Size |
|||
!Type |
|||
!Description |
|||
|- valign="top" |
|||
|align="center" |0:0 |
|||
|bSize |
|||
|align="center" |2 bits |
|||
|align="center" |Enum |
|||
|Size = 2 |
|||
|- valign="top" |
|||
|align="center" |0:2 |
|||
|bType |
|||
|align="center" |2 bits |
|||
|align="center" |Enum |
|||
|Type = 3 (Reserved) |
|||
|- valign="top" |
|||
|align="center" |0:4 |
|||
|bTag |
|||
|align="center" |4 bits |
|||
|align="center" |Number |
|||
|1111b - Long |
|||
|- valign="top" |
|||
|align="center" |1 |
|||
|bDataSize |
|||
|align="center" |1 |
|||
|align="center" |Number |
|||
|Byte count of data |
|||
|- valign="top" |
|||
|align="center" |2 |
|||
|bLongItemTag |
|||
|align="center" |1 |
|||
|align="center" |Number |
|||
|Long item tag |
|||
|- valign="top" |
|||
|align="center" |3 |
|||
|Data |
|||
|align="center" |bDataSize |
|||
|align="center" |Number |
|||
|Data |
|||
|} |
|||
=== Parsing === |
|||
The report descriptor's items are parsed in a sequential manner. The parser is a state machine. A complete report descriptor may look something like this: |
|||
<source lang="C"> |
|||
static const uint8_t hidReportDescriptor [] = |
|||
{ |
|||
0x05, 0x01, // UsagePage(Generic Desktop[1]) |
|||
0x09, 0x04, // UsageId(Joystick[4]) |
|||
0xA1, 0x01, // Collection(Application) |
|||
0x85, 0x01, // ReportId(1) |
|||
0x09, 0x01, // UsageId(Pointer[1]) |
|||
0xA1, 0x00, // Collection(Physical) |
|||
0x09, 0x30, // UsageId(X[48]) |
|||
0x09, 0x31, // UsageId(Y[49]) |
|||
0x15, 0x80, // LogicalMinimum(-128) |
|||
0x25, 0x7F, // LogicalMaximum(127) |
|||
0x95, 0x02, // ReportCount(2) |
|||
0x75, 0x08, // ReportSize(8) |
|||
0x81, 0x02, // Input(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, BitField) |
|||
0x05, 0x09, // UsagePage(Button[9]) |
|||
0x19, 0x01, // UsageIdMin(Button 1[1]) |
|||
0x29, 0x03, // UsageIdMax(Button 3[3]) |
|||
0x15, 0x00, // LogicalMinimum(0) |
|||
0x25, 0x01, // LogicalMaximum(1) |
|||
0x95, 0x03, // ReportCount(3) |
|||
0x75, 0x01, // ReportSize(1) |
|||
0x81, 0x02, // Input(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, BitField) |
|||
0xC0, // EndCollection() |
|||
0x05, 0x02, // UsagePage(Simulation Controls[2]) |
|||
0x09, 0xBB, // UsageId(Throttle[187]) |
|||
0x15, 0x80, // LogicalMinimum(-128) |
|||
0x25, 0x7F, // LogicalMaximum(127) |
|||
0x95, 0x01, // ReportCount(1) |
|||
0x75, 0x08, // ReportSize(8) |
|||
0x81, 0x02, // Input(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, BitField) |
|||
0x75, 0x05, // ReportSize(5) |
|||
0x81, 0x03, // Input(Constant, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, BitField) |
|||
0xC0, // EndCollection() |
|||
}; |
|||
</source> |
|||
Recall the descriptor types. |
|||
'''Main''' - This is added to the logical tree. There are 5 subtypes: |
|||
* ''Input'' |
|||
* ''Output'' |
|||
* ''Feature'' |
|||
* ''Collection'' |
|||
* ''End Collection'' |
|||
'''Global''' - Adjusts the global state machine. New main items will inherit this state. This is useful where multiple axes are similar, for instance. |
|||
* ''Usage Page'' |
|||
* ''Logical Minimum'' |
|||
* ''Logical Maximum'' |
|||
* ''Physical Minimum'' |
|||
* ''Physical Maximum'' |
|||
* ''Unit Exponent'' |
|||
* ''Unit'' |
|||
* ''Report Size'' |
|||
* ''Report ID'' |
|||
== USB mouse == |
== USB mouse == |