前面分析了usb的四大描述符之端點描述符,接口描述符(每一個接口對應一個功能,與之配備相應驅動),下面是看配置描述符還是看設備描述符呢??我們知道,設備大於配置,配置大於接口,接口可以有多種設置。
我們還是按照從小到大的順序,繼續看配置結構體吧!
struct usb_host_config {
struct usb_config_descriptor desc;
char *string; /* iConfiguration string, if present */
/* the interfaces associated with this configuration,
* stored in no particular order */
struct usb_interface *interface[USB_MAXINTERFACES];
/* Interface information available even when this is not the
* active configuration */
struct usb_interface_cache *intf_cache[USB_MAXINTERFACES];
unsigned char *extra; /* Extra descriptors */
int extralen;
};
和前面分析一下,我們先略過usb_config_descriptor結構體的分析,大餐總是喜歡最后吃。
string,這個字符串保存了配置描述符iConfiguration字段對應的字符串描述符信息。
interface[USB_MAXINTERFACES],配置所包含的接口。注釋里說的很明確,這個數組的順序未必是按照配置里接口號的順序,所以你要想得到某個接口號對應的struct usb_interface結構對象,就必須使用drivers/usb/usb.c里定義的usb_ifnum_to_if函數。
struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev,
unsigned ifnum)
{
struct usb_host_config *config = dev->actconfig;
int i;
if (!config)
return NULL;
for (i = 0; i < config->desc.bNumInterfaces; i++)
if (config->interface[i]->altsetting[0]
.desc.bInterfaceNumber == ifnum)
return config->interface[i];
return NULL;
}
這個函數實現,就是用指定的接口號和當前配置的每一個接口可選設置0里的接口描述符的bInterfaceNumber字段做比較,相等了,那個接口就是你要尋找的。
如果你看了協議,可能會在9.6.5里看到,An interface descriptor is always returned as part of a configuration descriptor. Interface descriptors cannot be directly accessed with a GetDescriptor() or SetDescriptor() request…….請求配置描述符時,配置里的所有接口描述符是按照順序一個一個返回的。那為什么這里又明確說明,讓咱們不要期待它就會是接口號的順序那?其實很久很久以前這里並不是這么說地,它就說這個數組是按照0..desc.bNumInterfaces的順序,但同時又說需要通過usb_ifnum_to_if函數來獲得指定接口號的接口對象,為什么改?因為協議歸協議,廠商歸廠商,有些廠商就是有不遵守協議的癖好,它非要先返回接口1再返回接口0,你也沒轍,所以就不得不增加usb_ifnum_to_if函數。
intf_cache[USB_MAXINTERFACES],這是個struct usb_interface_cache對象的結構數組,usb_interface_cache就是usb接口的緩存。緩存些什么?看看include/linux/usb/usb.h里的定義。
struct usb_interface_cache {
unsigned num_altsetting; /* number of alternate settings */
struct kref ref; /* reference counter */
/* variable-length array of alternate settings for this interface,
* stored in no particular order */
struct usb_host_interface altsetting[0];
};
重點看一下成員altsetting[0],它是一個可變長數組,按需分配的那種,當對設備GET_DESCRIPTOR的時候,內核就根據返回的每個接口可選設置的數目(值num_altsetting)分配給intf_cache數組相應的空間。為什么要緩存這些東東?設備的配置會發生變化,為了在配置被取代之后仍然能夠獲取它的一些信息,就需要把一些信息放在intf_cache數組的struct usb_interface_cache對象里。那么誰會需要用到呢?你通過sysfs這個窗口只能看到設備當前配置的一些信息,即使是這個配置下面的接口,也只能看到接口正在使用的那個可選設置的信息,可是你希望能夠看到更多的,怎么辦?usbfs就是這個門,里面顯示有你的系統中所有usb設備的可選配置和端點信息,它就是利用intf_cache這個數組里緩存的東東實現的。
回到配置結構體usb_host_config 的剩下兩個成員extra和extralen,有關額外擴展的描述符的,和struct usb_host_interface里的差不多,只是這里的是針對配置的,如果你使用GET_DESCRIPTOR請求從設備里獲得配置描述符信息,它們會緊跟在標准的配置描述符后面返回給你。
還是老規矩,最后看一下usb_config_descriptor;
struct usb_config_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 wTotalLength;
__u8 bNumInterfaces;
__u8 bConfigurationValue;
__u8 iConfiguration;
__u8 bmAttributes;
__u8 bMaxPower;
} __attribute__ ((packed));
bLength,描述符的長度,值為#define USB_DT_CONFIG_SIZE 9
bDescriptorType,描述符的類型。還記得端點描述符和接口描述符類型是什么嗎??所以多想想就能記住了,記不住也沒關系,知道有這么個東東。這里為什么又要提一下?因為這里有一個轉折,配置描述符的值可以為USB_DT_CONFIG,0x02,也可以為#define USB_DT_OTHER_SPEED_CONFIG 0x07。這么說對不對?0x07描述符描述的是高速設備操作在低速或全速模式時的配置信息,和配置描述符的結構完全相同,區別只是描述符的類型不同,是只有名字不同的孿生兄弟。
wTotalLength,使用GET_DESCRIPTOR請求從設備里獲得配置描述符信息時,返回的數據長度,也就是說對包括配置描述符、接口描述符、端點描述符,class-或vendor-specific描述符在內的所有描述符算了個總帳。
bNumInterfaces,這個配置包含的接口數目。
bConfigurationValue,對於擁有多個配置的幸運設備來說,可以拿這個值為參數,使用SET_CONFIGURATION請求來改變正在被使用的 USB配置,bConfigurationValue就指明了將要激活哪個配置。咱們的設備雖然可以有多個配置,但同一時間卻也只能有一個配置被激活。SET_CONFIGURATION請求也是標准的設備請求之一,專門用來設置設備的配置。
iConfiguration,描述配置信息的字符串描述符的索引值。
bmAttributes,這個字段表征了配置的一些特點,比如bit 6為1表示self-powered,bit 5為1表示這個配置支持遠程喚醒。另外,它的bit 7必須為1,為什么?協議里就這么說的,我也不知道,這個世界上並不是什么事情都找得到原因的。ch9.h里有幾個相關的定義
/* from config descriptor bmAttributes */
#define USB_CONFIG_ATT_ONE (1 << 7) /* must be set */
#define USB_CONFIG_ATT_SELFPOWER (1 << 6) /* self powered */
#define USB_CONFIG_ATT_WAKEUP (1 << 5) /* can wakeup */
#define USB_CONFIG_ATT_BATTERY (1 << 4) /* battery powered */
bMaxPower,設備正常運轉時,從總線那里分得的最大電流值,以2mA為單位。設備可以使用這個字段向hub表明自己需要的的電流,但如果設備需求過於旺盛,請求的超出了hub所能給予的,hub就會直接拒絕,不會心軟。你去請求她給你多一點點愛,可她心系天下人,沒有多的分到你身上,於是怎么辦?拒絕你唄,不要說愛情是多么殘酷,這個世界就是很無奈。還記得struct usb_device結構里的bus_mA嗎?它就表示從總線上獲取到的當前值,也就是hub所能夠賦予給設備的值。
