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 ==