最近看到一款与我们同类型的USB Audio Chip的SPEC: CM108AH(http://www.hardwaresecrets.com/datasheets/CM108AH.pdf), 其中通过HID协议对芯片内部寄存器进行读写操作的feature觉得很有意思。 考虑到客户应用场景下通过USB进行寄存器调整的简便性,觉得增加这个功能还是很有必要。
由于之前已经使用USB HID来进行音量的控制,所以相对修改就小的多,基本上只需要进行描述符的改动即可。
HID接口描述符
0x09, /* bLength: Interface Descriptor size */
0x04, /* bDescriptorType: Interface descriptor type */
0x03, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x02, /* bNumEndpoints */
0x03, /* bInterfaceClass: HID */
0x00, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
0x00, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
0x00, /* iInterface: Index of string descriptor */
端点描述符
0x07, /* bLength: Endpoint Descriptor size */
0x05, /* bDescriptorType: */
0x81, /* bEndpointAddress: Endpoint Address (IN) */
0x03, /* bmAttributes: Interrupt endpoint */
0x08, 0x00, /* wMaxPacketSize: 8 Bytes max */
0x20, /* bInterval: Polling Interval (32 ms) */
0x07, /* bLength: Endpoint Descriptor size */
0x05, /* bDescriptorType: */
0x09, /* bEndpointAddress: Endpoint Address (OUT) */
0x03, /* bmAttributes: Interrupt endpoint */
0x08, 0x00, /* wMaxPacketSize: 8 Bytes max */
0x20, /* bInterval: Polling Interval (32 ms) */
这里使用了2个端点,IN端点1作为媒体控制信息和私有数据的输入端点,OUT端点作为私有数据的输出端点。
由于IN端点1里面承载的2种不同用途的payload,就必须要用report id区分下。
HID 描述符
0x05, 0x0c, // USAGE_PAGE (Consumer Devices)
0x09, 0x01, // USAGE (Consumer Control)
0xa1, 0x01, // COLLECTION (Application)
0x85, 0x01, // Report ID1
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x09, 0xe9, // USAGE (Volume Up)
0x09, 0xea, // USAGE (Volume Down)
0x09, 0xe2, // USAGE (Mute)
0x09, 0xCD, // USAGE (Play/Pause)
0x09, 0xb5, // USAGE (Scan Next Track)
0x09, 0xb6, // USAGE (Scan Previous Track)
0x09, 0xb3, // USAGE (Fast Forward)
0x09, 0xb7, // USAGE (Stop)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x08, // REPORT_COUNT (8)
0x81, 0x42, // INPUT (Data,Var,Abs,Null)
0x85, 0x02, // Report ID2 Data Input(2 bytes)
0x26, 0xFF, 0x00,
0x09, 0x00,
0x75, 0x08,
0x95, 0x02,
0x81, 0x02,
0x85, 0x03, // Report ID3 Data Output (2 bytes)
0x26, 0xFF, 0x00,
0x09, 0x00,
0x75, 0x08,
0x95, 0x02,
0x91, 0x02,
0xc0, // END_COLLECTION
注意在进行数据传输时,需要先发送report id,然后再加上playload。
按上面的描述信息,report ID1的payload是1个字节,所以传输数据格式应该为: 0x01,,0x**,其他对应的格式如下:
我是通过Linux下对/dev/hidrawX这个设备节点进行read、write操作来进行功能的验证。
USB分析仪抓包数据如下:
可以看到帧号45096是report1的输入数据,帧号45105是report3的输出数据。
BTW:
- 大家可以观察下,HID采用USB中断传输类型,其本质也是轮询方式,如果过多使用的话也会很占用USB带宽(从超多的NAK就可以看出来)。
- 我本人是在vmware虚拟机里装ubuntu进行对hidrawX节点的操作,结果问题很多hidapi(http://www.signal11.us/oss/hidapi/)也用不起来。如果只能在虚拟机下测试,最好每次测试完后拔插下USB设备。
- 关于OUT端点9可以不用,这样的话HID默认采用端点0进行传输。