前面struct usb_interface里表示接口設置的struct usb_host_interface被有意的飄過了,咱們在這節主要講講這個結構體,同樣在include/linux/usb.h文件里定義。
/* host-side wrapper for one interface setting's parsed descriptors */
struct usb_host_interface {
struct usb_interface_descriptor desc;
/* array of desc.bNumEndpoint endpoints associated with this
* interface setting. these will be in no particular order.
*/
struct usb_host_endpoint *endpoint;
char *string; /* iInterface string, if present */
unsigned char *extra; /* Extra descriptors */
int extralen;
};
和前面分析一下,我們先略過usb_interface_descriptor結構體的分析,大餐總是喜歡最后吃。
endpoint,一個數組,表示這個設置所使用到端點。
string,用來保存從設備里取出來的字符串描述符信息的,既然字符串描述符可有可無,那這里的指針也有可能為空了。
xtra,extralen,關於額外的描述符。除了前面提到的四大描述符還有字符串描述符外,還有為一組設備也就是一類設備定義的描述符,和廠商為設備特別定義的描述符,extra指的就是它們,extralen表示它們的長度。
desc,接口的描述符。前面看了端點描述符,現在又有了接口描述符,那么什么叫描述符呢?實際上,usb的描述符是一個帶有預定義格式的數據結構,里面保存了usb設備的各種屬性還有相關信息,姓甚名誰啊,哪兒生產的啊等等,我們可以通過向設備請求獲得它們的內容來深刻的了解感知一個usb設備。主要有四種usb描述符,設備描述符,配置描述符,接口描述符和端點描述符,協議里規定一個usb設備是必須支持這四大描述符的,當然也有其它一些設備為了顯得個性些支持其特有描述符,但這四大描述符是一個都不能少的。
這些描述符放哪兒?當然是在設備里。usb設備里都會有一個叫EEPROM的東東,沒錯,就是放在它那兒,它就是用來存儲設備本身信息的,EEPROM就是電可擦寫的可編程ROM,它與Flash雖說都是要電擦除的,但它可以按字節擦除,Flash只能一次擦除一個block,所以如果要改動比較少的數據的話,使用它還是比較合適的,但是世界上沒有完美的東西,此物成本相對Flash比較高,所以一般來說usb設備里只拿它來存儲一些本身特有的信息,要想存儲數據,還是用Flash吧。
具體到接口描述符,它當然就是描述接口本身的信息的。一個接口可以有多個設置,使用不同的設置,描述接口的信息會有些不同,所以接口描述符並沒有放在struct usb_interface結構里,而是放在表示接口設置的struct usb_host_interface結構里。定義在include/linux/usb/ch9.h文件里:
/* 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));
再次強調一下,瀏覽ch9.h文件里的內容一定要同時對照協議規范去看。__attribute__意思就是告訴編譯器,這個結構的元素都是1字節對齊的,不要再添加填充位了。因為這個結構和spec里的Table 9.12是完全一致的,包括字段的長度,如果不給編譯器這么個暗示,編譯器就會依據你平台的類型在結構的每個元素之間添加一定的填充位,如果你拿這個添加了填充位的結構去向設備請求描述符,你想想會是什么結果。
bLength,描述符的字節長度。協議里規定,每個描述符必須以一個字節打頭來表明描述符的長度。接口描述符的bLength應該是9沒錯,ch9.h文件里緊挨着接口描述符的定義就定義了這個長度。
#define USB_DT_INTERFACE_SIZE 9
bDescriptorType,描述符的類型。各種描述符的類型都在ch9.h文件里有定義,對應spec Table 9.5。對於接口描述符來說,值為USB_DT_INTERFACE,也就是0x04。
#define USB_DT_INTERFACE 0x04
bInterfaceNumber,接口號。每個配置可以包含多個接口,這個值就是它們的索引值。
bAlternateSetting,接口使用的是哪個可選設置。協議里規定,接口默認使用的設置總為0號設置。
bNumEndpoints,接口擁有的端點數量。這里並不包括端點0,端點0是所有的設備都必須提供的,所以這里就沒必要多此一舉的包括它了。
bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol。這個世界上有許許多多的usb設備,它們各有各的特點,為了區分它們, usb協議規范把usb設備分成了很多類,然而每個類又分成子類。這很好理解,比如我們一個大學,先是分成很多個學院,然后每個學院又被分為很多個系,然后可能每個系下邊又分了各個專業。usb協議也是如此,首先每個Device或Interface屬於一個Class,然后Class下面又分了SubClass,完了SubClass下面又按各種設備所遵循的不同的通信協議繼續細分。usb協議里邊為每一種Class,每一種SubClass,每一種Protocol定義一個數值,比如mass storage 的Class就是0x08,hub的Class就是0x09。
iInterface,接口對應的字符串描述符的索引值。除了前面提到的四大描述符,還有字符串描述符,不過那四大描述符是每個設備必須支持的,這個字符串描述符卻是可有可無的。
現在總結下怎么分析描述符?一是對照usb協議規范第九章(非常重要,讀個十遍吧先),二是采用避重就輕(從小到大)順序慢慢分析源碼,當然你也可以先去看設備描述符,不過我第一次就是這么做的,后來發現很多看着看着就模糊了。所以,從小處着手,相信我們會有突破!!!
