1. 程式人生 > >從零開始學USB(十、USB的描述符)

從零開始學USB(十、USB的描述符)

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