linux usb枚举分析1----(枚举过程及数据分析)

1.枚举过程简述

        USB Host带有Root Hub,第一个USB设备是一个根集线器(Root_hub)它控制连接到其上的整个USB总线。

        当USB设备的速度类型确定之后,USB通信双方将会工作在相同的速度模式下,随后USB枚举才会开始。USB枚举的本质就是USB主机获取USB设备的参数信息并且对于可配置参数进行配置的过程。当枚举结束时,USB设备将会使用在枚举过程中USB主机所配置的参数进行工作,从而确保通信双方使用相同的参数。

       枚举完成之前,USB设备要经历一系列的状态变化,才能最终完成枚举。这些状态是连接状态(attach)、供电状态(powered)、默认状态(default)、地址状态(addressed)、配置状态(configured)、挂起状态(suspended)。当设备状态变为配置状态时,即可认为USB设备与USB主机间的枚举完成。

  1. 连接了设备的HUB在HOST查询其状态改变端点时返回对应的bitmap,告知HOST某个PORT状态发生了改变。
  2. 主机向HUB查询该PORT的状态,得知有设备连接,并知道了该设备的基本特性。
  3. 主机等待(至少100ms)设备上电稳定,然后向HUB发送请求,复位并使能该PORT。
  4. HUB执行PORT复位操作,复位完成后该PORT就使能了。现在设备进入到default状态,可以从vbus获取不超过100mA的电流。主机可通过0地址与其通讯。
  5. 主机通过0地址向该设备发送get_device_descriptor标准请求,获取设备的描述符。
  6. 主机再向HUB发送请求,复位该PORT。
  7. 主机通过标准请求set_address给设备分配地址。
  8. 主机通过新地址向设备发送get_device_descriptor标准请求,获取设备的描述符。
  9. 主机通过新地址向设备发送get_configuration请求,获取设备的配置描述符。
  10. 根据配置信息,主机选择合适的配置,通过set_configuration请求对设备进行配置,这时设备可以正常使用了。

2. USB 2.0握手过程

第一阶段:设备接入后,将D+信号线拉高,host或者更精确点说roothub/hub,会上报一个端口connect信号

第二阶段:host发送reset信号,并拉低D+D-进入SE0状态,此SE0状态持续时间t > 2.5us

第三阶段:device检测到SE0超过2.5us之后,向总线发送Chrip K信号(1ms < t < 7ms)

第四阶段:Chrip K结束后,如果host支持HS,在 < 100us的时间内,响应一连串的Chrip K/J信号对,每个Chrip K/J信号宽度 40us < d < 60us,每个Chrip K和J之间间隔 < 2.5us

第五阶段:Device在检测到3对Chrip K/J信号后,在 < 500us的时间内断开D+的上拉电阻,并将D+D-接地,进入高速传输模式,枚举完成。

        传输数据时,枚举的第一步是请求获取设备描述符。对于高速设备和低速设备,用于控制传输的端点0支持的紧大包长度是确定的,分别是64字节和8字节。但是对于全速设备,端点0支持的最大包长度可能是8字节、16字节、32字节或64字节,在USB主机获取USB设备的设备描述符之前,USB主机不能确定USB设备端点0的最大包长度,这样USB主机获取USB设备描述符的请求就可能不能正常工作。

        在USB主机和USB设备通信前,USB主机必须要指定端点0上的最大包长度,以便正确检测控制传输中数据阶段的结束。假设USB主机端默认USB端点0的最大包长度为64字节,而实际USB设备端点0的最大包长度为8字节。由于USB的设备描述符长度为固定的18字节,USB主机发送的第一个GetDescriptor(Device type)请求将会要求USB设备端发送18字节的数据。USB设备收到该请求后,准备发送18字节的数据,由于其最大包长度为8字节,所以18字节的数据将会分成3个事务完成,分别发送8字节、8字节和2字节。但是由于USB 主机端认为设备端最大包长度为64字节,当USB主机接收到第一个8字节的事务时,就认为数据阶段已经完成(因为8字节的包长度小于USB主机端指定的最大包长度),而USB设备端此时还在准备发送第二个8字节的事务,导致这个控制传输由于通信双方的状态不同步而无法正常完成。

        在不同的主机系统上,使用了不同的解决方案。下面以Windows7操作系统和Linux Ubuntu系统为例介绍其解决方案。

        在win7上,主机要求设备返回64字节的设备描述符并默认USB设备端点0的最大包长度为64字节。如果设备端点0的最大包长度不小于标准设备描述符的长度(18字节),设备就可以一次性将18字节的设备描述符发送给主机,通信双方状态保持同步;如果设备的端点0最大包长度小于设备描述符的长度,那么此时设备要使用多个事务向主机发送一个完整的设备描述符,前述的不同步问题会出现。对此,Windows7系统在第一次获取设备描述符后,直接进行复位(Reset),将设备状态重置为初始状态。而由于设备端所支持的最小的最大包长度为8,此时主机一定能获取到设备描述符的前8个字节;而设备描述符的第8个字节就是设备端点0所支持的最大包长度。主机可以在后续的控制传输中使用这个设备端的最大包长度来保证双方正常通信。上图中枚举总流程就是如此。

        在ubuntu中,主机第一次获取设备描述符时只获取其前8字节。此时,不管USB设备端点的最大包长度是多少,USB设备只能发送8字节的数据,同时通信双方同步结束数据阶段。之后USB主机读取 USB设备描述符的第8个字节,得到设备端点0的最大包长度,并用于后续的控制传输。这个解决方案的关键点就是第一次获取设备描述符时只获取其前8字节。

        这两种解决方案都能解决实际的问题,但是解决问题的思路有所不同,Windows7的解决方案是一种异常处理的方式,而Linux Ubuntu的解决方案则体现了一种精细控制、避免出错的思想。

二、usb关键数据结构

1.设备描述符

总共18 byte

struct usb_device_descriptor {

    __u8  bLength; ///长度

    __u8  bDescriptorType; ///描述符类型

    __le16 bcdUSB; //USB spec的版本号,一个设备如果能够进行高速传输,那么它设备描述符里的bcdUSB这一项就应该为0200H。

    __u8  bDeviceClass;///设备类型

    __u8  bDeviceSubClass;///设备子类型

    __u8  bDeviceProtocol;///协议

    __u8  bMaxPacketSize0;///第8个byte,最大传输大小,设备端数据包的最大值。

    __le16 idVendor;///厂商 ID

    __le16 idProduct;///设备 ID

    __le16 bcdDevice;/// 设备版本号

    __u8  iManufacturer; //描述厂商字符串的索引

    __u8  iProduct; //描述产品字符串的索引

    __u8  iSerialNumber;///序列号

    __u8  bNumConfigurations;/// 设备当前速度模式下支持的配置数量。有的设备可以在多个速度模式下操作,这里包括的只是当前速度模式下的配置数目,不是总的配置数目

}

2.配置描述符

       配置描述符用于说明USB设备中各个配置的特性,如配置所含接口的个数等。USB设备的每一个配置都必须有一个配置描述符,总共9 byte。

struct usb_config_descriptor {

__u8  bLength;                //描述符长度

__u8  bDescriptorType;        //这里的值并不仅仅可以为USB_DT_CONFIG,还可以为USB_DT_OTHER_SPEED_CONFIG

__le16 wTotalLength;         //使用GET_DESCRIPTOR请求从设备里获得配置描述符信息时,返回的数据长度

    __u8  bNumInterfaces;       //这个配置包含的接口数量

    __u8  bConfigurationValue;    //对于拥有多个配置的幸运设备来说,可以拿这个值为参数,使用SET_CONFIGURATION请求来改变正在被使用的USB配置,bConfigurationValue就指明了将要激活哪个配置。咱们的设备虽然可以有多个配置,但同一时间却也只能有一个配置被激活。SET_CONFIGURATION请求也是标准的设备请求之一,专门用来设置设备的配置。

    __u8  iConfiguration;      //描述配置信息的字符串描述符的索引值

    __u8  bmAttributes;         //这个字段表征了配置的一些特点,比如bit 6为1表示self-powered,bit 5为1表示这个配置支持远程唤醒。另外,它的bit 7必须为1

    __u8  bMaxPower;          //设备正常运转时,从总线那里分得的最大电流值,以2mA为单位。设备可以使用这个字段向hub表明自己需要的的电流,但如果设备需求过于旺盛,请求的超出了hub所能给予的,hub就会直接拒绝。

3.接口描述符

一个配置可以包含一个或多个接口,接口描述符用于说明设备中各个接口的特性,如接口所属的设备类及其子类等。USB设备的每个接口都必须有一个接口描述符

struct usb_interface_descriptor  

{

     __u8  bLength;//接口描述符长度 

    __u8 bDescriptorType;//接口描述符类型 

    __u8 bInterfaceNumber;//接口号。每个配置可以包含多个接口,这个值就是它们的索引值。 

    __u8 bAlternateSetting;//接口使用的是哪个可选设置。协议里规定,接口默认使用的设置总为0号设置。 

    __u8 bNumEndpoints;//接口拥有的端点数量。这里并不包括端点0,因为端点0是控制传输,是所有的设备都必须提供的,所以这里就没必要多此一举的包括它了。对于hub,因为它的传输是中断传输,所以此值为1(不包括端点0)

    __u8 bInterfaceClass;  //接口类型

    __u8 bInterfaceSubClass;//接口子类型。对于hub,这个值是零 

    __u8 bInterfaceProtocol;  //接口所遵循的协议

    __u8 iInterface;  //描述该接口的字符串索引值

}

4.端点描述符

端点是USB设备中的实际物理单元,USB数据传输就是在主机和USB设备各个端点之间进行的。USB设备中的每一个端点都有唯一的端点号,每个端点所支持的数据传输方向一般而言也是确定的:或是输入(IN),或是输出(OUT)。

     利用设备地址、端点号和传输方向就可以指定一个端点,并与它进行通信。端点的传输特性还决定了其与主机通信是所采用的传输类型,例如控制端点只能使用控制传输。根据端点的不同用途,可将端点分为两类:0号端点和非0号端点。

      0号端点比较特殊,它有数据输入IN和数据输出OUT两个物理单元,且只能支持控制传输。所有的USB设备都必须含有一个0号端点,用作默认控制管道。USB系统软件就是使用该管道与USB逻辑设备进行配置通信的。0号端点在USB设备上可以直接使用,而非0号端点必须要在配置以后才可以使用。

     根据具体应用的需要,USB设备还可以含有多个除0号端点以外的其他端点。对于低速设备,其附加的端点数最多为2个;对于全速/高速设备,其附加的端点数最多为15个。

struct usb_endpoint_descriptor {   ///USB 端点描述符(每个USB设备最多有16个端点)

__u8  bLength;             ///描述符的字节长度

    __u8  bDescriptorType;        ///描述符类型,对于端点就是USB_DT_ENDPOIN

    __u8  bEndpointAddress;    ///bit0~3表示端点地址,bit8 表示方向,输入(1)还是输出(0)

    __u8  bmAttributes;        ///属性(bit0、bit1构成传输类型,00--控制,01--等时,10--批量,11--中断)

    __le16 wMaxPacketSize;        ///端点一次可以处理的最大字节数

    __u8  bInterval;            ///希望主机轮询自己的时间间隔

     /* NOTE:  these two are _only_ in audio endpoints. */

      /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */

    __u8  bRefresh;  //对于批量传送的端点以及控制传送的端点,此域忽略

    __u8  bSynchAddress; //对于同步传送的端点,此域必须为1

}

5.字符串描述符

      在USB设备中通常还含有字符串描述符,以说明一些专用信息,如制造商的名称、设备的序列号等。它的内容以UNICODE的形式给出,且可以被客户软件所读取。对USB设备来说,字符串描述符是可选的。

struct usb_string_descriptor

{

    __u8 bLength; //描述符长度

    __u8 bDescriptorType; //描述符类型

    __le16 wData[1];

}

三、通过bus hound分析USB鼠标的枚举过程

       打开bus hound后,将device选项上所有的设备都不选中,在左下角auto select hot plugged devices前面打勾,这样在capture中选中运行,这样当有USB设备插入后,bus hound会自动选中我们新插入的设备,并对其进行抓包。

插入一个小米的无线USB鼠标后,有如下数据包,主要是设备枚举:

  1. 获取设备描述符

Host发送CTL传输请求:

CTL    80 06 00 01  00 00 12 00

80  bmRequestType:数据方向从设备端到主机端;标准的请求;USB设备接收

06 bRequest :请求为 GET_DESCRIPTOR

00 01 wValue:设备描述符

00 00 wIndex:从偏移地址0开始读取设备描述符

12 00 wLength:下一阶段数据的长度为18个字节(小端格式,实际为0x0012,即18)

device返回数据:

IN     12 01 10 01  00 00 00 08  17 27 16 50  02 01 01 02  00 01

12 bLength长度为18

01 bDescriptorType:表示设备描述符

10 01 bcdUSB:转换后为0x0110,表示USB协议版本1.10 (注:USB协议版本使用bcd表示)

00 bDeviceClass设备类型(USB分配)

00 bDeviceSubClass:设备子类

00 bDeviceProtocol:协议码

08 bMaxPacketSize0端点0的最大包为8(注:仅有8、16、32、64这几个值)

17 27 idVendorVID,转换后为0x2717

16 50 idProductPID,转换后为0x5016

02 01 bcdDevice设备版本号

01 iManufacturer厂商字符串的索引

02 iproduct: 产品字符串的索引

00 iSerialNumber:序列号

01 bNumConfigurations:当前速度模式下的配置数量

  1. 获取配置描述符

配置描述符主要记录的信息有:配置所包含的接口数、配置的编号、供电方式、是否支持远程唤醒、电流需求量等。

Host发送CTL传输请求:

CTL    80 06 00 02  00 00 09 00

80 bmRequestType:数据方向从设备端到主机端;标准的请求;USB设备接收

06 bRequest:请求为 GET_DESCRIPTOR

00 02 wValue:Index为0的CONFIGURATION

00 00 wIndex:从偏移地址0开始读取设备描述符

09 00 wLength:下一阶段数据的长度为9个字节(小端格式,实际为0x0009,即9)

该条指令的意思是:要求设备返回一个长度为9字节的Index为0的配置描述符。

Device返回数据:

       IN     09 02 3b 00  02 01 00 a0  32

09 bLength:本描述符数据长度

02 bDescriptorType:类型,表示配置描述符

3b 00 wTotalLength:即003b,表示此次数据长度。包括其它描述符(配置、接口、端点和HID)的总长度

02 bNumInterface:本配置支持的接口数量为2

01 bConfigurationValue:设置配置命令(Set Configuration)的参数值

00 iConfiguration字符串描述符索引值,0表示没有

a0 bmAttributes:电源和唤醒方式 a0表示总线供电(Bus Powered),远程唤醒(Remote Wakeup)

32 bMaxPower:耗电电流,单位为2mA,此值表示32h就是50d,即50*2=100mA

      

       Host按照配置描述符的标准长度9byte来向设备申请数据,故设备只返回了一个完整的配置描述符。下面host会根据配置描述符中的配置+接口+端点+HID的总长部003b来向device申请数据。

  1. 获取接口描述符、端点描述符、HID描述符

如上所述,host会再次向device发起获取配置描述符的请求,但获取数据的长充不再是9字节,而是3bH(56)个字节。

Host向device发送请求:

CTL    80 06 00 02  00 00 3b 00

Device向host返回:

IN     09 02 3b 00  02 01 00 a0  32 09 04 00  00 01 03 01  01 00 09 21  10 01 00 01  22 41 00 07  05 81 03 08  00 0a 09 04  01 00 01 03  01 02 00 09  21 10 01 00  01 22 d6 00  07 05 82 03  08 00 02

       绿色的配置描述符不再分析。

       配置描述符中指明了有两个接口,第一个接口棕色数据段为第一个接口描述符:

09 bLength:本描述符长度

04 bDescriptorType:类型值,表示接口描述符

00 bInterfaceNumber:接口编号为0

00 bAlternateSetting:备用的接口描述符编号

01 bNumEndpoint:接口端点数量为1

03 bInterfaceClass:接口类型值,3表示HID(由USB分配)

01 bInterfaceSubClass:子类型

01 bInterfaceProtocol:协议码,1表示键盘,2为鼠标,0为无

00 iInterface:本接口字符串描述符索引

       后面跟着HID描述符:

09 blength: 本描述符长度

21 bDescriptorType: 类别,21为HID描述符

11 01 bcdHID:转换后为0111,表示USB协议版本为1.11(bcd码)

00 bCountryCode: 国家码

01 bNumDescritors: HID描述符数量为1

22 bDescriptorType: 描述符类型,0x22为报告描述符,0x21为HID描述符,0x23为物理描述符

41 00 wDescriptorLength: 描述符长度,此处为0x0041

       再后面跟着端点描述符:

07 bLength:本描述符长度

05 bDescriptor:类别,5表示端点描述符

81 bEndpointAddress:端点地址,Bit7表示方向,1为输入,0为输出,低4比特为端点号。81为输入的1号,82为输入的2号

03 bmAttributes:端口属性,00表示控制,01为同步,02为批量,03为中断

08 00 bMaxPacketSize:转换后为0x0008,表示最大包长度为8

0a bInterval:轮询时间间隔,单位ms

       第二个棕色的接口描述符:

09 bLength:本描述符长度

04 bDescriptorType:类型值,表示接口描述符

01 bInterfaceNumber::接口编号为1

00 bAlternateSetting:备用的接口描述符编号

01 bNumEndpoint:接口端点数量为1

03 bInterfaceClass:接口类型值,3表示HID(由USB分配)

01 bInterfaceSubClass:子类型

02 bInterfaceProtocol:协议码,1表示键盘,2为鼠标,0为无

00 iInterface:本接口字符串描述符索引

  1. Set_configuration来配置device

Host向device发送set_config命令:

CTL    00 09 01 00  00 00 00 00

00 bmRequestType : direction:Host to Device,Type:standard Recipient:device

09 bRequest:SET_CONFIGURATION

01 00 wValue:选择1号configuration

00 00 wIndex:0x00 0x00

00 00 wLength:0x00 0x00

  1. 获取字符串描述符

Host向device发送控制请求:

CTL    80 06 02 03  09 04 04 00

80 bmRequestType: Dir: D2H, Type: Standard, Recipient: Device

06, bRequest (Get Descriptor)

02, wValue[0:7]  Desc Index: 2

03, wValue[8:15] Desc Type: (String)

09 04,wIndex Language ID: 0x0409

04 00, wLength = 4

      

       Device向host返回4个字节:

IN     2e 03 4d 00

bLength:0x04,描述符长度4 bytes

bDescriptorType:0x03,STRING type descriptor

首字节为长度,然后重新获取字符串描述符,长度变为00 2e:

CTL    80 06 02 03  09 04 2e 00

       设备返回:

IN     2e 03 4d 00  69 00 20 00  57 00 69 00  72 00 65 00  6c 00 65 00  73 00 73 00  20 00 4d 00  6f 00 75 00  73 00 65 00  20 00 4c 00  69 00 74 00  65 00

表示..M.i. .W.i.r.e.l.e.s.s. .M.o.u.s.e. .L.i.t.e.

  1. 多次枚举分析

在脑插入一个USB鼠标时,通常会有两个接口被枚举出来。一个接口是鼠标的接口,另一个接口是键盘的接口。这是因为许多USB鼠标都具有内置的媒体控制按钮,例如音量控制和播放/暂停按钮,这些按钮可以被操作系统识别为键盘按键。因此,当您插入USB鼠标时,操作系统会枚举出两个接口,一个用于鼠标,另一个用于键盘。

第一次获取描述符时,在配置里有两个接口,两个接口分别指明了两个HID设备,一个是键盘一个是鼠标,每个HID设备都分别跟着一个HID描述符。接下来需要分别读取键盘和鼠标的报告描述符,分别重新走枚举流程,以获取键盘和鼠标的HID报告描述符。

第二次

Host向device申请报告描述符:

CTL    21 0a 00 00  00 00 00 00 (SET IDLE)

CTL    81 06 00 22  00 00 81 00 (GET DESCRIPTOR)

IN     05 01 09 06  a1 01 05 07  19 e0 29 e7  15 00 25 01  75 01 95 08  81 02 75 08  95 01 81 01  75 01 95 03  05 08 19 01  29 03 91 02  75 01 95 05  91 01 75 08  95 06 15 00  26 ff 00 05  07 19 00 2a  ff 00 81 00

其中SET_IDLE命令用于设置设备的空闲率。空闲率是设备在报告的数据没有变化时向主机发送报告的速率。通过设置空闲率,主机可以通过减少轮询设备的频率来节省电源。

GET DESCRIPTOR,其中0x06和0x22表示host想获取device的描述符,类型是HID报告描述符:

0x81, bmRequestType: Dir: D2H, Type: Standard, Recipient: Interface

0x06, bRequest (Get Descriptor)

0x00, wValue[0:7]  Desc Index: 0

0x22, wValue[8:15] Desc Type: (HID Report)

0x00, 0x00, wIndex Language ID: 0x00

0x81, 0x00, wLength = 129

       报告描述符解析,第一次获得了一个键盘的报告描述符:

0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)

0x09, 0x06,        // Usage (Keyboard)

0xA1, 0x01,        // Collection (Application)

0x05, 0x07,        //   Usage Page (Kbrd/Keypad)

0x19, 0xE0,        //   Usage Minimum (0xE0)

0x29, 0xE7,        //   Usage Maximum (0xE7)

0x15, 0x00,        //   Logical Minimum (0)

0x25, 0x01,        //   Logical Maximum (1)

0x75, 0x01,        //   Report Size (1)

0x95, 0x08,        //   Report Count (8)

0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)

0x75, 0x08,        //   Report Size (8)

0x95, 0x01,        //   Report Count (1)

0x81, 0x01,        //   Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)

0x75, 0x01,        //   Report Size (1)

0x95, 0x03,        //   Report Count (3)

0x05, 0x08,        //   Usage Page (LEDs)

0x19, 0x01,        //   Usage Minimum (Num Lock)

0x29, 0x03,        //   Usage Maximum (Scroll Lock)

0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)

0x75, 0x01,        //   Report Size (1)

0x95, 0x05,        //   Report Count (5)

0x91, 0x01,        //   Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)

0x75, 0x08,        //   Report Size (8)

0x95, 0x06,        //   Report Count (6)

0x15, 0x00,        //   Logical Minimum (0)

0x26, 0xFF, 0x00,  //   Logical Maximum (255)

0x05, 0x07,        //   Usage Page (Kbrd/Keypad)

0x19, 0x00,        //   Usage Minimum (0x00)

0x2A, 0xFF, 0x00,  //   Usage Maximum (0xFF)

0x81, 0x00,        //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)

// 64 bytes

第三次

Host向device申请HID报告描述符:

CTL    81 06 00 22  01 00 16 01

IN     05 01 09 02  a1 01 85 01  09 01 a1 00  05 09 19 01  29 05 15 00  25 01 75 01  95 05 81 02  75 03 95 01  81 01 05 01  09 30 09 31  16 01 f8 26  ff 07 75 0c  95 02 81 06  09 38 15 81  25 7f 75 08  95 01 81 06  c0 05 0c 15  81 25 7f 75  08 95 01 0a  38 02 81 06  c0 05 0c 09  01 a1 01 85  03 19 00 2a  80 03 15 00  26 80 03 75  10 95 01 81  00 c0 05 01  09 80 a1 01  85 04 19 81  29 83 25 01  75 01 95 03  81 02 95 05  81 01 c0 06  01 ff 09 00  a1 01 85 02  09 00 15 00  26 ff 00 75  08 95 07 81  02 c0 06 f2  f1 0a f2 f1  a1 01 85 05  09 00 95 06  75 08 15 00  26 ff 00 91  02 09 00 95  05 75 08 15  00 26 ff 00  81 02 c0 06  02 ff 09 02  a1 01 85 06  09 02 15 00  26 ff 00 75  08 95 07 b1  02 c0

        解析HID报告描述符,是一个鼠标的描述符:

0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)

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 (0x01)

0x29, 0x05,        //     Usage Maximum (0x05)

0x15, 0x00,        //     Logical Minimum (0)

0x25, 0x01,        //     Logical Maximum (1)

0x75, 0x01,        //     Report Size (1)

0x95, 0x05,        //     Report Count (5)

0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)

0x75, 0x03,        //     Report Size (3)

0x95, 0x01,        //     Report Count (1)

0x81, 0x01,        //     Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)

0x05, 0x01,        //     Usage Page (Generic Desktop Ctrls)

0x09, 0x30,        //     Usage (X)

0x09, 0x31,        //     Usage (Y)

0x16, 0x01, 0xF8,  //     Logical Minimum (-2047)

0x26, 0xFF, 0x07,  //     Logical Maximum (2047)

0x75, 0x0C,        //     Report Size (12)

0x95, 0x02,        //     Report Count (2)

0x81, 0x06,        //     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)

0x09, 0x38,        //     Usage (Wheel)

0x15, 0x81,        //     Logical Minimum (-127)

0x25, 0x7F,        //     Logical Maximum (127)

0x75, 0x08,        //     Report Size (8)

0x95, 0x01,        //     Report Count (1)

0x81, 0x06,        //     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)

0xC0,              //   End Collection

0x05, 0x0C,        //   Usage Page (Consumer)

0x15, 0x81,        //   Logical Minimum (-127)

0x25, 0x7F,        //   Logical Maximum (127)

0x75, 0x08,        //   Report Size (8)

0x95, 0x01,        //   Report Count (1)

0x0A, 0x38, 0x02,  //   Usage (AC Pan)

0x81, 0x06,        //   Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)

0xC0,              // End Collection

0x05, 0x0C,        // Usage Page (Consumer)

0x09, 0x01,        // Usage (Consumer Control)

0xA1, 0x01,        // Collection (Application)

0x85, 0x03,        //   Report ID (3)

0x19, 0x00,        //   Usage Minimum (Unassigned)

0x2A, 0x80, 0x03,  //   Usage Maximum (0x0380)

0x15, 0x00,        //   Logical Minimum (0)

0x26, 0x80, 0x03,  //   Logical Maximum (896)

0x75, 0x10,        //   Report Size (16)

0x95, 0x01,        //   Report Count (1)

0x81, 0x00,        //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)

0xC0,              // End Collection

0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)

0x09, 0x80,        // Usage (Sys Control)

0xA1, 0x01,        // Collection (Application)

0x85, 0x04,        //   Report ID (4)

0x19, 0x81,        //   Usage Minimum (Sys Power Down)

0x29, 0x83,        //   Usage Maximum (Sys Wake Up)

0x25, 0x01,        //   Logical Maximum (1)

0x75, 0x01,        //   Report Size (1)

0x95, 0x03,        //   Report Count (3)

0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)

0x95, 0x05,        //   Report Count (5)

0x81, 0x01,        //   Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)

0xC0,              // End Collection

0x06, 0x01, 0xFF,  // Usage Page (Vendor Defined 0xFF01)

0x09, 0x00,        // Usage (0x00)

0xA1, 0x01,        // Collection (Application)

0x85, 0x02,        //   Report ID (2)

0x09, 0x00,        //   Usage (0x00)

0x15, 0x00,        //   Logical Minimum (0)

0x26, 0xFF, 0x00,  //   Logical Maximum (255)

0x75, 0x08,        //   Report Size (8)

0x95, 0x07,        //   Report Count (7)

0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)

0xC0,              // End Collection

0x06, 0xF2, 0xF1,  // Usage Page (Reserved 0xF1F2)

0x0A, 0xF2, 0xF1,  // Usage (0xF1F2)

0xA1, 0x01,        // Collection (Application)

0x85, 0x05,        //   Report ID (5)

0x09, 0x00,        //   Usage (0x00)

0x95, 0x06,        //   Report Count (6)

0x75, 0x08,        //   Report Size (8)

0x15, 0x00,        //   Logical Minimum (0)

0x26, 0xFF, 0x00,  //   Logical Maximum (255)

0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)

0x09, 0x00,        //   Usage (0x00)

0x95, 0x05,        //   Report Count (5)

0x75, 0x08,        //   Report Size (8)

0x15, 0x00,        //   Logical Minimum (0)

0x26, 0xFF, 0x00,  //   Logical Maximum (255)

0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)

0xC0,              // End Collection

0x06, 0x02, 0xFF,  // Usage Page (Vendor Defined 0xFF02)

0x09, 0x02,        // Usage (0x02)

0xA1, 0x01,        // Collection (Application)

0x85, 0x06,        //   Report ID (6)

0x09, 0x02,        //   Usage (0x02)

0x15, 0x00,        //   Logical Minimum (0)

0x26, 0xFF, 0x00,  //   Logical Maximum (255)

0x75, 0x08,        //   Report Size (8)

0x95, 0x07,        //   Report Count (7)

0xB1, 0x02,        //   Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)

0xC0,              // End Collection

// 214 bytes

   下面将分析一下linux USB host和device的代码流程。

  • 35
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
USB(Universal Serial Bus)是一种用于连接电脑和外部设备的标准接口,它有自己的通信协议。USB枚举是指在插入USB设备时,计算机系统自动检测并识别该设备过程。 首先,当我们将USB设备插入计算机的USB端口时,计算机会发送一个复位信号给USB设备,以便设备知道计算机已经察觉到它的存在。USB设备在接收到复位信号后会执行一些初始化操作,并返回一个握手信号给计算机。 接下来,计算机会发送一个叫作Get Descriptor的命令给USB设备,这个命令的作用是要求USB设备返回一些描述该设备的信息,比如设备的厂商ID、产品ID、设备类别等。USB设备收到这个命令后会返回这些信息给计算机。 然后,计算机会发送一个Set Configuration的命令给USB设备,这个命令的目的是告诉USB设备要使用哪种配置,因为有些USB设备可以有多种不同的配置。USB设备在接收到Set Configuration命令后会根据配置来进行初始化,并返回一个确认信号给计算机。 最后,计算机会发送一些其他的命令给USB设备,比如读取和写入数据的命令,以及其他特定的设备命令,这些命令的具体内容取决于USB设备的功能和应用。 通过上述的过程USB设备和计算机建立起了通信链接,USB设备可以向计算机提供相应的功能和服务。USB枚举过程中的各个步骤确保了设备和计算机之间的正常通信和数据传输。 总结来说,USB枚举过程是计算机通过一系列的命令向USB设备发出请求,USB设备根据这些请求进行相应的操作,并返回相应的结果给计算机,以实现设备和计算机之间的通信和数据传输。这个过程USB协议中非常重要的一部分,保证了USB设备的插拔即用的特性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值