usb標(biāo)準(zhǔn)描述符之技巧
USB是個(gè)通用的總線,端口都是統(tǒng)一的。但是USB設(shè)備卻各種各樣,例如USB鼠標(biāo),USB鍵盤,U盤等等,那么USB主機(jī)是如何識(shí)別出不同的設(shè)備的呢?這就要依賴于描述符了。
??? USB的描述符主要有設(shè)備描述符,配置描述符,接口描述符,端點(diǎn)描述符,字符串描述符,HID描述符,報(bào)告描述符等等。
??? 一個(gè)USB設(shè)備有一個(gè)設(shè)備描述符,設(shè)備描述符里面決定了該設(shè)備有多少種配置,每種配置描述符對(duì)應(yīng)著配置描述符;而在配置描述符中又定義了該配置里面有多少個(gè)接口,每個(gè)接口有對(duì)應(yīng)的接口描述符;在接口描述符里面又定義了該接口有多少個(gè)端點(diǎn),每個(gè)端點(diǎn)對(duì)應(yīng)一個(gè)端點(diǎn)描述符;端點(diǎn)描述符定義了端點(diǎn)的大小,類型等等。由此我們可以看出,USB的描述符之間的關(guān)系是一層一層的,最上一層是設(shè)備描述符,下面是配置描述符,再下面是接口描述符,再下面是端點(diǎn)描述符。在獲取描述符時(shí),先獲取設(shè)備描述符,然后再獲取配置描述符,根據(jù)配置描述符中的配置集合長(zhǎng)度,一次將配置描述符、接口描述符、端點(diǎn)描述符一起一次讀回。其中可能還會(huì)有獲取設(shè)備序列號(hào),廠商字符串,產(chǎn)品字符串等。
???
???? 每種描述符都有自己獨(dú)立的編號(hào),如下:
#define DEVICE_DESCRIPTOR?????????????? 0x01? //設(shè)備描述符
#define CONFIGURATION_DESCRIPTOR??????? 0x02? //配置描述符
#define STRING_DESCRIPTOR?????????????? 0x03? //字符串描述符
#define INTERFACE_DESCRIPTOR??????????? 0x04? //接口描述符
#define ENDPOINT_DESCRIPTOR???????????? 0x05? //端點(diǎn)描述符
???
下面分別詳細(xì)介紹一下各描述符。
1.設(shè)備描述符
//定義標(biāo)準(zhǔn)的設(shè)備描述符結(jié)構(gòu)
typedef struct _DEVICE_DCESCRIPTOR_STRUCT
{
?BYTE blength;?????????????????????????????? //設(shè)備描述符的字節(jié)數(shù)大小
?BYTE bDescriptorType;????????????????????? //設(shè)備描述符類型編號(hào)
?WORD bcdUSB;??????????????????????????????? //USB版本號(hào)
?BYTE bDeviceClass;????????????????????????? //USB分配的設(shè)備類代碼
?BYTE bDeviceSubClass;?????????????????????? //USB分配的子類代碼
?BYTE bDeviceProtocol;?????????????????????? //USB分配的設(shè)備協(xié)議代碼
?BYTE bMaxPacketSize0;?????????????????????? //端點(diǎn)0的最大包大小
?WORD idVendor;????????????????????????????? //廠商編號(hào)
?WORD idProduct;???????????????????????????? //產(chǎn)品編號(hào)
?WORD bcdDevice;???????????????????????????? //設(shè)備出廠編號(hào)
?BYTE iManufacturer;???????????????????????? //設(shè)備廠商字符串的索引
?BYTE iProduct;????????????????????????????? //描述產(chǎn)品字符串的索引
?BYTE iSerialNumber;???????????????????????? //描述設(shè)備序列號(hào)字符串的索引
?BYTE bNumConfigurations;??????????????????? //可能的配置數(shù)量
}
DEVICE_DESCRIPTOR_STRUCT, * pDEVICE_DESCRIPTOR_STRUCT;
//實(shí)際的設(shè)備描述符示例
code DEVICE_DESCRIPTOR_STRUCT device_descriptor=?? //設(shè)備描述符
{
?sizeof(DEVICE_DESCRIPTOR_STRUCT),?????????????????? //設(shè)備描述符的字節(jié)數(shù)大小,這里是18字節(jié)
?DEVICE_DESCRIPTOR,????????????????????????????? //設(shè)備描述符類型編號(hào),設(shè)備描述符是01
?0x1001,?? //USB版本號(hào),這里是USB01.10,即USB1.1。由于51是大端模式,所以高低字節(jié)交換
?0x00,???????????????????????????????? //USB分配的設(shè)備類代碼,0表示類型在接口描述符中定義
?0x00,???????????????????????????????? //USB分配的子類代碼,上面一項(xiàng)為0時(shí),本項(xiàng)也要設(shè)置為0
?0x00,??????????????????????????????? //USB分配的設(shè)備協(xié)議代碼,上面一項(xiàng)為0時(shí),本項(xiàng)也要設(shè)置為0
?0x10,??????????????????????????????? //端點(diǎn)0的最大包大小,這里為16字節(jié)
?0x7104,???????????????????????????? //廠商編號(hào),這個(gè)是需要跟USB組織申請(qǐng)的ID號(hào),表示廠商代號(hào)。
?0xf0ff,??????? //該產(chǎn)品的編號(hào),跟廠商編號(hào)一起配合使用,讓主機(jī)注冊(cè)該設(shè)備并加載相應(yīng)的驅(qū)動(dòng)程序
?0x0100,?????? //設(shè)備出廠編號(hào)
?0x01,??????? //設(shè)備廠商字符串的索引,在獲取字符串描述符時(shí),使用該索引號(hào)來(lái)識(shí)別不同的字符串
?0x02,??????? //描述產(chǎn)品字符串的索引,同上
?0x03,???????? //描述設(shè)備序列號(hào)字符串的索引,同上
?0x01??????????????????????? //可能的配置數(shù)為1,即該設(shè)備只有一個(gè)配置
};
2.配置描述符
//定義標(biāo)準(zhǔn)的配置描述符結(jié)構(gòu)
typedef struct _CONFIGURATION_DESCRIPTOR_STRUCT
{
?BYTE bLength;?????????????????????????????? //配置描述符的字節(jié)數(shù)大小
?BYTE bDescriptorType;?????????????????????? //配置描述符類型編號(hào)
?WORD wTotalLength;????????????????????????? //此配置返回的所有數(shù)據(jù)大小
?BYTE bNumInterfaces;??????????????????????? //此配置所支持的接口數(shù)量
?BYTE bConfigurationValue;?????????????????? //Set_Configuration命令所需要的參數(shù)值
?BYTE iConfiguration;??????????????????????? //描述該配置的字符串的索引值
?BYTE bmAttributes;????????????????????????? //供電模式的選擇
?BYTE MaxPower;????????????????????????????? //設(shè)備從總線提取的最大電流
}
CONFIGURATION_DESCRIPTOR_STRUCT, * pCONFIGURATION_DESCRIPTOR_STRUCT;
2.接口描述符
//定義標(biāo)準(zhǔn)的接口描述符結(jié)構(gòu)
typedef struct _INTERFACE_DESCRIPTOR_STRUCT
{
?BYTE bLength;?????????????????????????????? //接口描述符的字節(jié)數(shù)大小
?BYTE bDescriptorType;?????????????????????? //接口描述符的類型編號(hào)
?BYTE bInterfaceNumber;????????????????????? //該接口的編號(hào)
?BYTE bAlternateSetting;???????????????????? //備用的接口描述符編號(hào)
?BYTE bNumEndpoints;???????????????????????? //該接口使用的端點(diǎn)數(shù),不包括端點(diǎn)0
?BYTE bInterfaceClass;?????????????????????? //接口類型
?BYTE bInterfaceSubClass;??????????????????? //接口子類型
?BYTE bInterfaceProtocol;??????????????????? //接口遵循的協(xié)議
?BYTE iInterface;??????????????????????????? //描述該接口的字符串索引值
}
INTERFACE_DESCRIPTOR_STRUCT, * pINTERFACE_DESCRIPTOR_STRUCT;
4.端點(diǎn)描述符
//定義標(biāo)準(zhǔn)的端點(diǎn)描述符結(jié)構(gòu)
typedef struct _ENDPOINT_DESCRIPTOR_STRUCT
{
?BYTE bLegth;??????????????????????????????? //端點(diǎn)描述符字節(jié)數(shù)大小
?BYTE bDescriptorType;?????????????????????? //端點(diǎn)描述符類型編號(hào)
?BYTE bEndpointAddress;????????????????????? //端點(diǎn)地址及輸入輸出屬性
?BYTE bmAttributes;????????????????????????? //端點(diǎn)的傳輸類型屬性
?WORD wMaxPacketSize;??????????????????????? //端點(diǎn)收、發(fā)的最大包大小
?BYTE bInterval;???????????????????????????? //主機(jī)查詢端點(diǎn)的時(shí)間間隔
}
ENDPOINT_DESCRIPTOR_STRUCT, * pENDPOINT_DESCRIPTOR_STRUCT;
下面是一個(gè)配置描述符集合的定義
typedef struct _CON_INT_ENDP_DESCRIPTOR_STRUCT
{
?CONFIGURATION_DESCRIPTOR_STRUCT configuration_descriptor;
?INTERFACE_DESCRIPTOR_STRUCT? interface_descritor;
?ENDPOINT_DESCRIPTOR_STRUCT? endpoint_descriptor[ENDPOINT_NUMBER];
}CON_INT_ENDP_DESCRIPTOR_STRUCT;
配置描述符集合的示例
code CON_INT_ENDP_DESCRIPTOR_STRUCT con_int_endp_descriptor=? //配置描述符集合
{
//configuration_descriptor???????????????????? //配置描述符
{
?sizeof(CONFIGURATION_DESCRIPTOR_STRUCT),????? //配置描述符的字節(jié)數(shù)大小,這里為9
?CONFIGURATION_DESCRIPTOR,???????????????????? //配置描述符類型編號(hào),配置描述符為2
?(sizeof(CONFIGURATION_DESCRIPTOR_STRUCT)+
?sizeof(INTERFACE_DESCRIPTOR_STRUCT)+
?sizeof(ENDPOINT_DESCRIPTOR_STRUCT)*ENDPOINT_NUMBER)*256+
?(sizeof(CONFIGURATION_DESCRIPTOR_STRUCT)+
?sizeof(INTERFACE_DESCRIPTOR_STRUCT)+
?sizeof(ENDPOINT_DESCRIPTOR_STRUCT)*ENDPOINT_NUMBER)/256,?? //配置描述符集合的總大小
?0x01,????????????????????????????????? //只包含一個(gè)接口
?0x01,????????????????????????????????? //該配置的編號(hào)
?0x00,????????????????????????????????? //iConfiguration字段
?0x80,????????????????????????????????? //采用總線供電,不支持遠(yuǎn)程喚醒
?0xC8?????????????????????????????????? //從總線獲取最大電流400mA
},
//interface_descritor?????????????????? //接口描述符
{
?sizeof(INTERFACE_DESCRIPTOR_STRUCT),?? //接口描述符的字節(jié)數(shù)大小,這里為9
?INTERFACE_DESCRIPTOR,????????????????? //接口描述符類型編號(hào),接口描述符為3
?0x00,????????????????????????????????? //接口編號(hào)為4
?0x00,????????????????????????????????? //該接口描述符的編號(hào)為0
?ENDPOINT_NUMBER,?????????????????????? //非0端點(diǎn)數(shù)量為2,只使用端點(diǎn)主端點(diǎn)輸入和輸出
?0x08,????????????????????????????????? //定義為USB大容量存儲(chǔ)設(shè)備
?0x06,????????????????????????????????? //使用的子類,為簡(jiǎn)化塊命令
?0x50,????????????????????????????????? //使用的協(xié)議,這里使用單批量傳輸協(xié)議
?0x00?????????????????????????????????? //接口描述符字符串索引,為0,表示沒有字符串
},
//endpoint_descriptor[]
{
?{???????????????????????????????????? //主端點(diǎn)輸入描述
? sizeof(ENDPOINT_DESCRIPTOR_STRUCT),? //端點(diǎn)描述符的字節(jié)數(shù)大小,這里為7
? ENDPOINT_DESCRIPTOR,???????????????? //端點(diǎn)描述符類型編號(hào),端點(diǎn)描述符為5
? MAIN_POINT_IN,?????????????????????? //端點(diǎn)號(hào),主輸入端點(diǎn)
? ENDPOINT_TYPE_BULK,????????????????? //使用的傳輸類型,批量傳輸
? 0x4000,????????????????????????????? //該端點(diǎn)支持的最大包尺寸,64字節(jié)
? 0x00???????????????????????????????? //中斷掃描時(shí)間,對(duì)批量傳輸無(wú)效
?},
?
?{???????????????????????????????????? //主端點(diǎn)輸出描述
? sizeof(ENDPOINT_DESCRIPTOR_STRUCT),? //端點(diǎn)描述符的字節(jié)數(shù)大小,這里為7
? ENDPOINT_DESCRIPTOR,???????????????? //端點(diǎn)描述符類型編號(hào),端點(diǎn)描述符為5
? MAIN_POINT_OUT,????????????????????? //端點(diǎn)號(hào),主輸出端點(diǎn)
? ENDPOINT_TYPE_BULK,????????????????? //使用的傳輸類型,批量傳輸
? 0x4000,????????????????????????????? //該端點(diǎn)支持的最大包尺寸,64字節(jié)
? 0x00???????????????????????????????? //中斷掃描時(shí)間,對(duì)批量傳輸無(wú)效
?}
}
};
其中關(guān)于端點(diǎn)的類型定義如下
//定義的端點(diǎn)類型
#define ENDPOINT_TYPE_CONTROL?????????? 0x00? //控制傳輸
#define ENDPOINT_TYPE_ISOCHRONOUS?????? 0x01? //同步傳輸
#define ENDPOINT_TYPE_BULK????????????? 0x02? //批量傳輸
#define ENDPOINT_TYPE_INTERRUPT???????? 0x03? //中斷傳輸
端點(diǎn)號(hào)的定義如下
#define MAIN_POINT_OUT?????????? 0x02?? //2號(hào)輸出端點(diǎn)
#define MAIN_POINT_IN??????????? 0x82?? //2號(hào)輸入端點(diǎn)