从零开始学USB(十、USB的描述符)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_16777851/article/details/85222030

USB设备使用描述符报告其属性。描述符是具有定义格式的数据结构。每个描述符都以字节宽度字段开头,该字段包含描述符中的总字节数,后跟一个标识描述符类型的字节宽度字段。

使用描述符允许简单地存储各个配置的属性,因为每个配置可以重用具有相同特征的其他配置的描述符或描述符的部分。以这种方式,描述符类似于关系数据库中的各个数据记录。

适当时,描述符包含对字符串描述符的引用,这些字符串描述符提供以可读形式描述描述符的可显示信息。包含字符串描述符是可选的。但是,描述符中的引用字段是必需的。如果设备不支持字符串描述符,则必须将字符串引用字段重置为零,以指示没有可用的字符串描述符。

如果描述符返回的长度字段中的值小于此规范定义的值,则描述符无效,应由主机拒绝。如果描述符返回的长度字段中的值大于此规范定义的值,则主机将忽略额外的字节,但使用返回的长度而不是预期的长度来定位下一个描述符。

设备可以通过两种方式返回特定于类或特定于供应商的描述符:

  • 如果类或供应商特定描述符使用与标准描述符相同的格式(例如,以长度字节开头并后跟类型字节),则必须在GetDescriptor返回的配置信息中将它们与标准描述符交错返回(配置)请求。在这种情况下,类或特定于供应商的描述符必须遵循它们修改或扩展的相关标准描述符。
  • 如果类或供应商特定描述符独立于配置信息或使用非标准格式,则可以使用指定类或供应商特定描述符类型和索引的GetDescriptor()请求来从设备检索描述符。类或供应商规范将定义检索这些描述符的适当方法。

下图是USB2.0规范中规定的8种描述符。

在USB3.0中在2.0的基础上又增加了6种描述符

一、设备描述符(device)

设备描述符描述有关USB设备的一般信息。它包括信息全局适用于设备和所有设备的配置。 USB设备只有一个设备描述符。
具有SuperSpeed功能的设备的DEVICE描述符的版本号为3.0(0300H)。

bcdUSB字段包含BCD版本号。 bcdUSB字段的值为0xJJMN版本JJ.M.N(JJ  - 主要版本号,M  - 次要版本号,N  - 次要版本
例如,版本2.1.3用值0x0213表示,版本3.0用a表示值0x0300。

bNumConfigurations字段指示当前操作速度下的配置数。其他运行速度的配置不包括在计数中。如果设备具有特定速度的特定配置,则bNumConfigurations字段仅反映单个速度的配置数,而不是两个速度的配置总数。

如果设备高速运行,则bMaxPacketSize0字段必须为64,表示64字节最大包。高速操作不允许控制的其他最大数据包大小端点(端点0)。

所有USB设备都有一个默认控制管道。 设备描述符中描述了设备的默认控制管道的最大数据包大小。 配置描述符中描述了特定于配置及其接口的端点。 配置及其接口不包括默认控制管道的端点描述符。 除最大数据包大小外,默认控制管道的特性由本规范定义,并且对于所有USB设备都是相同的。
bNumConfigurations字段标识设备支持的配置数。 表9-8显示标准设备描述符。

在linux系统中对设备描述符的表示如下。

/* USB_DT_DEVICE: Device descriptor */
struct usb_device_descriptor {
	__u8  bLength;
	__u8  bDescriptorType;

	__le16 bcdUSB;
	__u8  bDeviceClass;
	__u8  bDeviceSubClass;
	__u8  bDeviceProtocol;
	__u8  bMaxPacketSize0;
	__le16 idVendor;
	__le16 idProduct;
	__le16 bcdDevice;
	__u8  iManufacturer;
	__u8  iProduct;
	__u8  iSerialNumber;
	__u8  bNumConfigurations;
} __attribute__ ((packed));

可以看到,linux系统中对USB设备描述符的表示和协议完全一致。(包括命名)

二、配置描述符(configuration)

配置描述符描述有关特定设备配置的信息。该描述符包含bConfigurationValue字段,该字段的值在用作SetConfiguration()请求的参数时,使设备采用所描述的配置。

描述符描述了配置提供的接口数量。每个接口可以独立运行。例如,ISDN设备可能配置有两个接口,每个接口提供64 Kb / s双向信道,在主机上具有单独的数据源或接收器。另一种配置可能将ISDN设备作为单个接口,将两个信道绑定到一个128 Kb / s双向信道。

当主机请求配置描述符时,将返回所有相关的接口和端点描述符。

USB设备具有一个或多个配置描述符。 每个配置都有一个或多个接口,每个接口都有零个或多个端点。 除非端点由同一接口的备用设置使用,否则端点不会在单个配置中的接口之间共享。 端点可以在不受此限制的不同配置的一部分的接口之间共享。

配置完成后,设备可能会对配置进行有限的调整。 如果特定接口有备用设置,可在配置后选择备用。

表9-10显示了该标准配置描述符。


/* USB_DT_CONFIG: Configuration descriptor information.
 *
 * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the
 * descriptor type is different.  Highspeed-capable devices can look
 * different depending on what speed they're currently running.  Only
 * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG
 * descriptors.
 */
struct usb_config_descriptor {
	__u8  bLength;
	__u8  bDescriptorType;

	__le16 wTotalLength;
	__u8  bNumInterfaces;
	__u8  bConfigurationValue;
	__u8  iConfiguration;
	__u8  bmAttributes;
	__u8  bMaxPower;
} __attribute__ ((packed));

三、字符串描述符(string)

字符串描述符是可选的。如果设备不支持字符串描述符,则必须将对设备,配置和接口描述符中的字符串描述符的所有引用重置为零。

字符串描述符使用由Unicode标准,全球字符编码,版本3.0,Unicode联盟,Addison-Wesley Publishing Company,Reading,Massachusetts(URL:http://www.unicode.com)定义的UNICODE编码。 USB设备中的字符串可能支持多种语言。请求字符串描述符时,请求者使用USB-IF定义的16位语言ID(LANGID)指定所需的语言。可以在http://www.usb.org/developers/docs.html上找到当前定义的USB LANGID列表。所有语言的字符串索引零都返回一个字符串描述符,该描述符包含设备支持的双字节LANGID代码数组。表9-15显示了LANGID代码数组。 USB设备可以省略所有字符串描述符。省略所有字符串描述符的USB设备不得返回LANGID代码数组。
LANGID代码数组不以NULL结尾。通过从描述符的第一个字节的值中减去两个来计算数组的大小(以字节为单位)。

UNICODE字符串描述符(如表9-16所示)不以NULL结尾。 字符串长度是通过从描述符的第一个字节的值中减去2来计算。

/* USB_DT_STRING: String descriptor */
struct usb_string_descriptor {
	__u8  bLength;
	__u8  bDescriptorType;

	__le16 wData[1];		/* UTF-16LE encoded */
} __attribute__ ((packed));

/* note that "string" zero is special, it holds language codes that
 * the device supports, not Unicode characters.
 */

四、接口描述符(interface)

接口描述符描述配置中的特定接口。 配置提供一个或多个接口,每个接口具有零个或多个端点描述符,用于描述配置中的唯一端点集。 当配置支持多个接口时,特定接口的端点描述符遵循GetConfiguration()请求返回的数据中的接口描述符。接口描述符始终作为配置描述符的一部分返回。 无法使用GetDescriptor()或SetDescriptor()请求直接访问接口描述符。

接口可以包括备用设置,其允许在配置设备之后改变端点和/或它们的特性。接口的默认设置始终为备用设置零.SetInterface()请求用于选择备用设置或返回默认设置。 GetInterface()请求返回选定的备用设置。

备用设置允许改变设备配置的一部分,而其他接口保持运行。如果配置具有其一个或多个接口的备用设置,则每个设置都包含单独的接口描述符及其关联的端点。

如果设备配置支持具有两个备用设置的单个接口,则配置描述符后面将是一个接口描述符,其中bInterfaceNumber和bAlternateSetting字段设置为零,然后是该设置的端点描述符,后跟另一个接口描述符及其关联的端点描述。 第二个接口描述符的bInterfaceNumber字段也将设置为零,但第二个接口描述符的bAlternateSetting字段将设置为1。

如果接口仅使用端点0,则端口描述符不会跟随接口描述符。 在这种情况下,bNumEndpoints字段必须设置为零。
接口描述符永远不包括端点数量中的端点零。

表9-12显示了标准接口描述符。

/* USB_DT_INTERFACE: Interface descriptor */
struct usb_interface_descriptor {
	__u8  bLength;
	__u8  bDescriptorType;

	__u8  bInterfaceNumber;
	__u8  bAlternateSetting;
	__u8  bNumEndpoints;
	__u8  bInterfaceClass;
	__u8  bInterfaceSubClass;
	__u8  bInterfaceProtocol;
	__u8  iInterface;
} __attribute__ ((packed));

五、端点描述符(endpoint)

用于接口的每个端点都有自己的描述符。 此描述符包含主机确定每个端点的带宽要求所需的信息。 始终返回端点描述符作为GetDescriptor(配置)请求返回的配置信息的一部分。 无法使用GetDescriptor()或SetDescriptor()请求直接访问端点描述符。 端点零永远不会有端点描述符。

表9-13显示了标准端点描述。

/* USB_DT_ENDPOINT: Endpoint descriptor */
struct usb_endpoint_descriptor {
	__u8  bLength;
	__u8  bDescriptorType;

	__u8  bEndpointAddress;
	__u8  bmAttributes;
	__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;
} __attribute__ ((packed));

六、设备限定描述符

device_qualifier描述符描述了有关高速设备的信息,如果设备以其他速度运行,该设备将发生变化。 例如,如果设备当前正以全速运行,则device_qualifier将返回有关其如何以高速运行的信息。反之亦然。

表9-9显示了device_qualifier描述符的字段。

标准设备描述符的供应商,产品,设备,制造商,产品和序列号字段不包含在此描述符中,因为该信息对于所有支持的速度的设备是恒定的。 此描述符的版本号必须至少为2.0(0200H)。
主机使用GetDescriptor()请求访问此描述符。 GetDescriptor()请求中的描述符类型设置为device_qualifier(参见表9-5)。
如果仅全速设备(设备描述符版本号等于0200H)收到对device_qualifier的GetDescriptor()请求,则它必须响应请求错误。 除非首先成功检索device_qualifier描述符,否则主机不得请求other_speed_configuration描述符。


/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */
struct usb_qualifier_descriptor {
	__u8  bLength;
	__u8  bDescriptorType;

	__le16 bcdUSB;
	__u8  bDeviceClass;
	__u8  bDeviceSubClass;
	__u8  bDeviceProtocol;
	__u8  bMaxPacketSize0;
	__u8  bNumConfigurations;
	__u8  bRESERVED;
} __attribute__ ((packed));

 

下面的几个都是USB3.0规范定义的描述符。

 

七、二进制设备对象描述符(BOS)

本节定义了一个灵活且可扩展的框架,用于描述和添加USB标准规范集的设备级功能。如上所述,存在设备描述符,但是使用以下框架定义所有设备级功能扩展。
BOS描述符定义了与配置描述符类似的根描述符,并且是用于访问相关描述符族的基本描述符。主机可以读取BOS描述符并wTotalLength字段学习设备级描述符集的整个大小,或者它可以读取整个BOS描述符集的设备功能。主机使用GetDescriptor()请求访问此描述符。 GetDescriptor()请求中的描述符类型设置为BOS。主机无法读取单个设备功能描述符。只能通过使用GetDescriptor()请求读取BOS描述符并使用wTotalLength字段中报告的长度来访问整个集合。


/* USB_DT_BOS:  group of device-level capabilities */
struct usb_bos_descriptor {
	__u8  bLength;
	__u8  bDescriptorType;

	__le16 wTotalLength;
	__u8  bNumDeviceCaps;
} __attribute__((packed));

八、设备能力描述符(capability)

通过设备功能描述符报告各个技术特定或通用设备级功能。 Device Capability描述符的格式在表9-11中定义。Device Capability描述符有一个通用头,带有一个子类型字段(bDevCapabilityType),用于定义描述符其余部分的布局。 bDevCapabilityType的代码在表9-12中定义。

/* USB_DT_DEVICE_CAPABILITY:  grouped with BOS */
struct usb_dev_cap_header {
	__u8  bLength;
	__u8  bDescriptorType;
	__u8  bDevCapabilityType;
} __attribute__((packed));

设备功能描述符始终作为GetDescriptor(BOS)请求返回的BOS信息的一部分返回。 无法直接访问设备功能GetDescriptor()或SetDescriptor()请求。

目前支持三种,无线USB、USB2.0扩展和USB3.0。


#define	USB_CAP_TYPE_WIRELESS_USB	1

struct usb_wireless_cap_descriptor {	/* Ultra Wide Band */
	__u8  bLength;
	__u8  bDescriptorType;
	__u8  bDevCapabilityType;

	__u8  bmAttributes;
#define	USB_WIRELESS_P2P_DRD		(1 << 1)
#define	USB_WIRELESS_BEACON_MASK	(3 << 2)
#define	USB_WIRELESS_BEACON_SELF	(1 << 2)
#define	USB_WIRELESS_BEACON_DIRECTED	(2 << 2)
#define	USB_WIRELESS_BEACON_NONE	(3 << 2)
	__le16 wPHYRates;	/* bit rates, Mbps */
#define	USB_WIRELESS_PHY_53		(1 << 0)	/* always set */
#define	USB_WIRELESS_PHY_80		(1 << 1)
#define	USB_WIRELESS_PHY_107		(1 << 2)	/* always set */
#define	USB_WIRELESS_PHY_160		(1 << 3)
#define	USB_WIRELESS_PHY_200		(1 << 4)	/* always set */
#define	USB_WIRELESS_PHY_320		(1 << 5)
#define	USB_WIRELESS_PHY_400		(1 << 6)
#define	USB_WIRELESS_PHY_480		(1 << 7)
	__u8  bmTFITXPowerInfo;	/* TFI power levels */
	__u8  bmFFITXPowerInfo;	/* FFI power levels */
	__le16 bmBandGroup;
	__u8  bReserved;
} __attribute__((packed));

#define USB_DT_USB_WIRELESS_CAP_SIZE	11

SuperSpeed设备应包含USB 2.0扩展描述符,并在何时支持LPM(Link Power Management)在USB 2.0高速模式下运行。

/* USB 2.0 Extension descriptor */
#define	USB_CAP_TYPE_EXT		2

struct usb_ext_cap_descriptor {		/* Link Power Management */
	__u8  bLength;
	__u8  bDescriptorType;
	__u8  bDevCapabilityType;
	__le32 bmAttributes;
#define USB_LPM_SUPPORT			(1 << 1)	/* supports LPM */
#define USB_BESL_SUPPORT		(1 << 2)	/* supports BESL */
#define USB_BESL_BASELINE_VALID		(1 << 3)	/* Baseline BESL valid*/
#define USB_BESL_DEEP_VALID		(1 << 4)	/* Deep BESL valid */
#define USB_GET_BESL_BASELINE(p)	(((p) & (0xf << 8)) >> 8)
#define USB_GET_BESL_DEEP(p)		(((p) & (0xf << 12)) >> 12)
} __attribute__((packed));

#define USB_DT_USB_EXT_CAP_SIZE	7

设备功能描述符始终作为GetDescriptor(BOS)请求返回的BOS信息的一部分返回。 无法直接访问设备功能GetDescriptor()或SetDescriptor()请求。

/*
 * SuperSpeed USB Capability descriptor: Defines the set of SuperSpeed USB
 * specific device level capabilities
 */
#define		USB_SS_CAP_TYPE		3
struct usb_ss_cap_descriptor {		/* Link Power Management */
	__u8  bLength;
	__u8  bDescriptorType;
	__u8  bDevCapabilityType;
	__u8  bmAttributes;
#define USB_LTM_SUPPORT			(1 << 1) /* supports LTM */
	__le16 wSpeedSupported;
#define USB_LOW_SPEED_OPERATION		(1)	 /* Low speed operation */
#define USB_FULL_SPEED_OPERATION	(1 << 1) /* Full speed operation */
#define USB_HIGH_SPEED_OPERATION	(1 << 2) /* High speed operation */
#define USB_5GBPS_OPERATION		(1 << 3) /* Operation at 5Gbps */
	__u8  bFunctionalitySupport;
	__u8  bU1devExitLat;
	__le16 bU2DevExitLat;
} __attribute__((packed));

#define USB_DT_USB_SS_CAP_SIZE	10

九、接口关联描述符(interface asssociation)

接口关联描述符用于描述两个或多个接口与同一功能相关联。 “关联”包括两个或多个接口及其所有备用设置接口。设备必须为需要多个接口的每个设备功能使用接口关联描述符。始终返回接口关联描述符作为GetDescriptor(配置)请求返回的配置信息的一部分。无法使用GetDescriptor()或SetDescriptor()请求直接访问接口关联描述符。接口关联描述符必须位于它关联的接口的接口描述符集(包括所有备用设置)之前。相关接口集中的所有接口号必须是连续的。表9-15显示了标准接口关联描述符。接口关联描述符包括函数类,子类和协议字段。这些字段中的值可以与任何一个关联接口的接口类,子类和协议值相同。对于现有设备类,首选实现是使用列表中第一个接口的接口类,子类和协议字段值相关接口。

注意:由于此特定功能未包含在早期版本的USB规范中,因此现有USB OS实现将如何支持使用此描述符的设备存在问题。 强烈建议使用接口关联描述符的设备实现使用设备描述符中的多接口函数类代码。 这允许简单且容易地识别这些设备,并允许在某些操作系统上安装可以解析和枚举包括接口关联描述符的配置的升级驱动程序。 多接口函数类代码记录在http://www.usb.org/developers/docs

十、超速端点联合描述符(SuperSpeed Endpoint Companion)

接口中描述的每个SuperSpeed端点后跟一个SuperSpeed Endpoint Companion描述符。 此描述符包含仅为SuperSpeed端点定义的其他端点特征。 此描述符始终作为GetDescriptor(配置)请求返回的配置信息的一部分返回,并且无法使用GetDescriptor()或SetDescriptor()请求直接访问。 默认控制管道没有Endpoint Companion描述符。 Endpoint Companion描述符应紧跟在配置信息中与其关联的端点描述符之后。

/* USB_DT_SS_ENDPOINT_COMP: SuperSpeed Endpoint Companion descriptor */
struct usb_ss_ep_comp_descriptor {
	__u8  bLength;
	__u8  bDescriptorType;

	__u8  bMaxBurst;
	__u8  bmAttributes;
	__le16 wBytesPerInterval;
} __attribute__ ((packed));

以上内容都是在USB2.0或USB3.0协议的第九章。

在linux中这些描述符的定义文件也描述为ch9.h

include/uapi/linux/usb/ch9.h

猜你喜欢

转载自blog.csdn.net/qq_16777851/article/details/85222030
今日推荐