2012年5月23日 星期三

HID Descriptor

HID(Human Interface Device) class 裝置與 HID class 驅動程式間的資料描述是透過 HID descriptor. 以下是 HID descriptor 於 USB device descriptor 中的位置:
device descriptor
  + configuration descriptor
  |   + interface descriptor
  |   |   + endpoint descriptor
  |   |   + (more) endpoint descriptor
  |   |   + hid descriptor
  |   |       + physical descriptor
  |   |       + report descriptor
  |   + (more) interface descriptor
  + (more) configuration descriptor

驅動程式取得 descriptor 的順序為:
  1. device descriptor
  2. configuration descriptor #1 (+ interface descriptor #1 + endpoint descriptor (#1~#N) + hid descriptor (不包括 physical descriptor 及 report descriptor)interface descriptor #2 + endpoint descriptor (#1~#N) + hid descriptor (不包括 physical descriptor 及 report descriptor) + ... + interface descriptor #N ... )
  3. 各別 interface descriptor 中的 HID report descriptor.
  4. 讀取 configuration descriptor #2~N (重複 2~3 步驟)
Report descriptor 在 HID descriptor 之下, 用以描述 HID 裝置的應用及資料, 使得作業系統能掛載相關的驅動程式, 並能讓裝置與驅動程式間能依照標準的資料定義解釋收到的資料. Report descriptor 由許多 item 組成, 而 item 包括 tag, type, size, 及 data, 以下為一個 report descriptor 的例子:
      +--- bit field: 7654   32   10
      |                tag type size
      |                 |    |    |
      |                 |    |    +--- 0, 1, 2, 4 bytes
      |                 |    +--- main item, global item, local item
      |                 +--- item
      |
      |     +--- data byte 1 (LSB)
      |     |
      |     |     +--- data byte 2 (data byte 為 32 bits, 因此 byte 2~4 沒指定的話, 都為 0)
      |     |     |
      |     |     |
    0x05, 0x01,        // USAGE_PAGE (Generic Desktop)
    0x09, 0x02,        // USAGE (Mouse)
    0xa1, 0x01,        // COLLECTION (Application)
    0x85, 0x01,        //   REPORT_ID (1)
    0x09, 0x01,        //   USAGE (Pointer)
    0xa1, 0x00,        //   COLLECTION (Physical)
    0x05, 0x09,        //     USAGE_PAGE (Button)
    0x19, 0x01,        //     USAGE_MINIMUM (Button 1)
    0x29, 0x03,        //     USAGE_MAXIMUM (Button 3)
    0x15, 0x00,        //     LOGICAL_MINIMUM (0)
    0x25, 0x01,        //     LOGICAL_MAXIMUM (1)
    0x75, 0x01,        //     REPORT_SIZE (1)
    0x95, 0x03,        //     REPORT_COUNT (3)
    0x81, 0x02,        //     INPUT (Data,Var,Abs) Input 是單向的(host 接收)
    0x75, 0x05,        //     REPORT_SIZE (5)
    0x95, 0x01,        //     REPORT_COUNT (1)
    0x81, 0x01,        //     INPUT (Cnst,Ary,Abs)
    0x05, 0x01,        //     USAGE_PAGE (Generic Desktop)
    0x09, 0x30,        //     USAGE (X)
    0x09, 0x31,        //     USAGE (Y)
    0x09, 0x38,        //     USAGE (Wheel)
    0x15, 0x81,        //     LOGICAL_MINIMUM (-127)
    0x25, 0x7f,        //     LOGICAL_MAXIMUM (127)
    0x75, 0x08,        //     REPORT_SIZE (8)
    0x95, 0x03,        //     REPORT_COUNT (3)
    0x81, 0x06,        //     INPUT (Data,Var,Rel)
    0xc0,              //   END_COLLECTION
    0xc0,              // END_COLLECTION
    0x06, 0x00, 0xff,  // USAGE_PAGE (Vendor Defined Page)
    0x0A, 0x01, 0x88,  // USAGE (Vendor Usage)
    0xa1, 0x01,        // COLLECTION (Application)
    0x85, 0x04,        //   REPORT_ID (4)
    0x15, 0x00,        //   LOGICAL_MINIMUM (0)
    0x25, 0xff,        //   LOGICAL_MAXIMUM (255)
    0x09, 0x00,        //   USAGE (Undefined)
    0x75, 0x08,        //   REPORT_SIZE (8)
    0x95, 0x10,        //   REPORT_COUNT (16)
    0x81, 0x02,        //   INPUT (Data,Var,Abs)
    0x09, 0x00,        //   USAGE (Undefined)
    0x95, 0x08,        //   REPORT_COUNT (8)
    0xb1, 0x02,        //   FEATURE (Data,Var,Abs) Feature 是雙向的
    0xc0               // END_COLLECTION

在以上 report descriptor 中, 每一行都是一個 item, 從 item type 及 item tag 就可以區分出所有的 item 了:
  • Main item: Input, Output, Feature, Collection, End Collection.
  • Global item: Usage Page, Logical Minimum, Logical Maximum, Physical Minimum, Physical Maximum, Unit Exponent, Unit Report Size, Report ID, Report Count, Push, Pop.
  • Local item: Usage, Usage Minimum, Usage Maximum, Designator Index, Designator Minimum, Designator Maximum, String Index, String Minimum, String Maximum, Delimiter.
Report 中最重要的 item 就是 main item, 它表示的是一筆資料欄位或是資料欄位的集合, 而 global item 及 local item 則用以描述資料屬性, 兩者不同之處, 在於 global item 的屬性可跨越 main item, 而 local item 則不行.

一個 HID 裝置可以有多種應用, 譬如一個觸控板裝置的應用為滑鼠, 但也有可能附加其它應用, 如鍵盤(以在判斷出手勢時, 送出按鍵). 每一個應用, 在 report descriptor 中是以 COLLECTION (Application) item 為開端, 舉前文中 report descriptor 為例, 在作業系統中會由 HID class 驅動程式列舉出兩個裝置: 滑鼠及特殊應用裝置(廠商自定義), 另外, 特別要注意的是 Report ID, 如果 report descriptor 中有多種應用集合, 則在應用集合中要指定不同的 Report ID.

HID 裝置上電後是以 report protocol 傳送資料, 即所送出的資料是完全依照 report descriptor 中之描述, 此外, HID 裝置還可以支援 boot protocol, 以固定格式傳送資料(且不含 Report ID), 如此一來, 可於 BIOS 或是空間有限的嵌入式系統中省下解譯 report descriptor 的程式碼. 目前 boot protocol 所支援的 HID 裝置有鍵盤及滑鼠.


更多資訊:
USB in a NutShell - USB Descriptors
USB Protocol
USnooBie's USB HID Report Descriptor Tutorial 1
USB DIY -- 自學計畫
USB 官方網頁 - HID Information
Wiki - Human Interface Device (boot protocol)

應用程式開發:
The HID Page
READING INPUT REPORTS FROM A HID DEVICE

1 則留言: