- 逻辑层次及描述符
逻辑上,usb包含设备(Device),配置(Configuration),接口(Interface)和端点(Endpoint)四个层次。设备通常有一个或多个配置,配置通常有一个或多个接口,接口有零个或多个端点(端点0应该是没有算进去)。有多个配置的设备,任意时刻只能有一个配置处于激活状态。在这四个层次之外,还有一个设置(setting),它与接口相关,一个接口可以有多个设置(setting)。有多个设置(setting)的接口,任意时刻也只能有一个设置(setting)生效。
这四个层次都有相应的描述符(另外一个常用的描述符是字符串描述符),它们都可以通过GET_DESCRIPTOR命令获取。GET_DESCRIPTOR命令需要指定描述符类型,描述符索引等参数。需要注意的是,只能指定设备,配置和字符串三种描述符类型,而不能指定接口和端点这两种描述符类型。这是因为在获取配置描述符时,会把它包含的所有接口和端点描述符一次性获取过来。因此,获取配置描述符时,得到的内容将是:配置描述符,接口0的描述符,接口0的端点描述符,接口1的描述符,接口1的端点描述符,直至接口n。另外,GET_DESCRIPTOR命令的描述符索引参数,只对配置描述符和字符串描述符有效,分别用于获取指定的配置描述符和字符串描述符,而对设备描述符无效(原因应该是一个设备只有一个设备描述符)。
获取设备描述符后,可以知道此设备支持几个配置。获取配置描述符后,可以得到此配置的编号(bConfigurationValue,应该不是从0开始编号),还可以知道此配置支持几个接口。解析接口描述符后,可以得到此接口的编号(bInterfaceNumber,从0开始编号,直至接口数目减1),还可以知道此接口支持几个端点。注意,接口描述符里,并没有说明此接口支持几个设置(setting)。获取配置描述符时,会一并获取它支持的接口描述符,如果获取到相同编号(bInterfaceNumber)的多个接口描述符,则是同一个接口的不同设置(setting),这些接口描述符的设置(setting)编号(bAlternateSetting,从0开始编号,直至设置(setting)数目减1)应该不同。
- 描述符详情
2.1 设备描述符
struct usb_device_descriptor {
__u8 bLength; // 18
__u8 bDescriptorType; // USB_DT_DEVICE,0x01
__le16 bcdUSB; // usb spec版本号,对应 sysfs 中的 version
__u8 bDeviceClass; // 见第3节,“类别(Class)和协议(Protocol)”
__u8 bDeviceSubClass;
__u8 bDeviceProtocol;
__u8 bMaxPacketSize0; // 端点0一次可以处理的最大字节数
__le16 idVendor; // 厂商id
__le16 idProduct; // 产品id
__le16 bcdDevice; // 设备版本号
__u8 iManufacturer; // 厂商对应的字符串描述符的索引值
__u8 iProduct; // 产品对应的字符串描述符的索引值
__u8 iSerialNumber; // 序列号对应的字符串描述符的索引值
__u8 bNumConfigurations; // 当前速度模式下的配置数目(不是设备支持的所有配置数目)。
} __attribute__ ((packed));
2.2 配置描述符
struct usb_config_descriptor {
__u8 bLength; // 9
__u8 bDescriptorType; // USB_DT_CONFIG, 0x02
__le16 wTotalLength; // GET_DESCRIPTOR 标准请求返回的总长度
__u8 bNumInterfaces; // 此配置包含的接口数目
__u8 bConfigurationValue; // 可以看做是此配置的编号
__u8 iConfiguration; // 此配置对应的字符串描述符的索引值
__u8 bmAttributes; // 此配置的特征。bit7必须为1,bit6:self powered. bit5:can wakeup. bit4:battery powered.
__u8 bMaxPower; // 表示此设备需要的最大电流,以2mA为单位
} __attribute__ ((packed));
在内核usb代码中,struct usb_device结构体的config成员表示设备支持的所有配置,actconfig成员表示当前激活的配置。在sysfs中,configuration(若不为空)就是当前激活的配置的名称(对应配置描述符中的iConfiguration)。而sysfs中的bConfigurationValue与配置描述符中的bConfigurationValue对应,读回就是当前激活的配置的编号,写入就是激活指定编号的配置。
2.3 接口描述符
struct usb_interface_descriptor {
__u8 bLength; // 9
__u8 bDescriptorType; // USB_DT_INTERFACE, 0x04
__u8 bInterfaceNumber; // 接口编号(zero-base)
__u8 bAlternateSetting; // 设置(setting)编号(zero-base)
__u8 bNumEndpoints; // 包含的端点数目(端点0不包含在内)
__u8 bInterfaceClass; // 见第3节,“类别(Class)和协议(Protocol)”
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
__u8 iInterface; // 此接口对应的字符串描述符的索引值
} __attribute__ ((packed));
有一种可能,配置中包含的接口的数目为1,但有多个接口描述符,应该就是一个接口的不同设置(setting),因此有相同的接口编号(bInterfaceNumber),不同的设置(setting)(bAlternateSetting)编号。
2.4 端点描述符
struct usb_endpoint_descriptor {
__u8 bLength; // 7,9
__u8 bDescriptorType; // USB_DT_ENDPOINT, 0x05
__u8 bEndpointAddress; // bit0~3表示端点编号,bit8表示端点方向
__u8 bmAttributes; // 端点属性
__le16 wMaxPacketSize; // 端点一次可以处理的最大字节数
__u8 bInterval; // 轮询时间间隔
__u8 bRefresh; // 音频相关
__u8 bSynchAddress; // 音频相关
} __attribute__ ((packed));
- 类别(Class)和协议(Protocol)
类别(Class)是针对设备和接口定义的,有一些类别(Class)仅针对设备,有一些类别(Class)仅针对接口,还有一些类别(Class)对设备和接口都有效。如下图所示:
class.jpg
而子类别(SubClass)和协议(Protocol)就根据类别(Class)的不同而不同了。
以常见的HID为例,它对应的子类别(SubClass)和协议(Protocol)如下图所示:
hid.jpg
而Mass Storage对应的则是:
mass.jpg
上述信息参考如下网址:
https://www.usb.org/defined-class-codes
https://www.usb.org/sites/default/files/hid1_11.pdf
https://www.usb.org/sites/default/files/Mass_Storage_Specification_Overview_v1.4_2-19-2010.pdf
更多信息,可以在下面的网址中搜索相关文档:
https://www.usb.org/documents?search=spec&items_per_page=50
网友评论