USB学习笔记一之描述符

2021-07-03  本文已影响0人  浙南旧事
  1. 逻辑层次及描述符

逻辑上,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)应该不同。

  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));
  1. 类别(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

上一篇 下一篇

猜你喜欢

热点阅读