- Linux那些事儿之我是USB
- 肖林甫 肖季东 任桥伟
- 1690字
- 2020-08-27 00:52:23
18.配置
还是接着看USB设备的配置吧,在include/linux/usb.h文件中定义:
244 struct usb_host_config { 245 struct usb_config_descriptor desc; 246 247 char *string; /* iConfiguration string, if present */ 248 /* the interfaces associated with this configuration, 249 * stored in no particular order */ 250 struct usb_interface *interface[USB_MAXINTERFACES]; 251 252 /* Interface information available even when this is not the 253 * active configuration */ 254 struct usb_interface_cache *intf_cache[USB_MAXINTERFACES]; 255 256 unsigned char *extra; /* Extra descriptors */ 257 int extralen; 258 };
245行,desc,四大描述符里最后的一个描述符终于出现了,同样是在include/linux/usb/ch9.h中定义。
258 struct usb_config_descriptor { 259 __u8 bLength; 260 __u8 bDescriptorType; 261 262 __le16 wTotalLength; 263 __u8 bNumInterfaces; 264 __u8 bConfigurationValue; 265 __u8 iConfiguration; 266 __u8 bmAttributes; 267 __u8 bMaxPower; 268 } __attribute__ ((packed)); 269 270 #define USB_DT_CONFIG_SIZE 9
259行,bLength,描述符的长度,值为USB_DT_CONFIG_SIZE。
260行,bDescriptorType,描述符的类型,值为USB_DT_CONFIG,0x02。按照前面接口描述符、端点描述符和设备描述符的习惯来说,这样说应该是没问题。但是,这里的值却并不仅仅可以为USB_DT_CONFIG,还可以为USB_DT_OTHER_SPEED_CONFIG,0x07。这里说的OTHER_SPEED_CONFIG描述符描述的是高速设备操作在低速或全速模式时的配置信息,和配置描述符的结构完全相同,区别只是描述符的类型不同,是只有名字不同的孪生兄弟。
262行,wTotalLength,是使用GET_DESCRIPTOR请求从设备中获得配置描述符信息时,返回的数据长度,也就是说对包括配置描述符、接口描述符、端点描述符,class-或vendor-specific描述符在内的所有描述符进行统计。
263行,bNumInterfaces,这个配置包含的接口数目。
263行,bConfigurationValue,对于拥有多个配置的幸运设备来说,可以用这个值为参数,使用SET_CONFIGURATION请求来改变正在被使用的USB配置,bConfigurationValue就指明了将要激活哪个配置。设备虽然可以有多个配置,但同一时间却也只能有一个配置被激活。SET_CONFIGURATION请求也是标准的设备请求之一,专门用来设置设备的配置。
265行,iConfiguration,描述配置信息的字符串描述符的索引值。
266行,bmAttributes,这个字段表示了配置的一些特点,比如bit 6为1表示self-powered,bit 5为1表示这个配置支持远程唤醒。另外,它的bit 7必须为1,ch9.h里有几个相关的定义:
272 /* from config descriptor bmAttributes */ 273 #define USB_CONFIG_ATT_ONE (1 << 7) /* must be set */ 274 #define USB_CONFIG_ATT_SELFPOWER (1 << 6) /* self powered */ 275 #define USB_CONFIG_ATT_WAKEUP (1 << 5) /* can wakeup */ 276 #define USB_CONFIG_ATT_BATTERY (1 << 4) /* battery powered */
267行,bMaxPower,设备正常运转时,从总线那里分得的最大电流值,以2mA为单位。设备可以使用这个字段向Hub表明自己需要的电流,但如果设备需求过于多,请求超出了Hub所能给予的,Hub就会直接拒绝。还记得struct usb_device结构中的bus_mA吗?它就表示Hub所能够给予的。Alan Stern告诉我们:
(c->desc.bMaxPower * 2) is what the device requests and udev->bus_mA is what the hub makes available.
到此为止,四大标准描述符已经全部登场亮相了,还是回到struct usb_host_config结构的247行,string,这个字符串保存了配置描述符iConfiguration字段对应的字符串描述符信息。
250行,interface[USB_MAXINTERFACES],配置所包含的接口。注释里说的很明确,这个数组的顺序未必是按照配置里接口号的顺序,所以你要想得到某个接口号对应的struct usb_interface结构对象,就必须使用drivers/usb/usb.c中定义的usb_ifnum_to_if函数。
84 struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev, 85 unsigned ifnum) 86 { 87 struct usb_host_config *config = dev->actconfig; 88 int i; 89 90 if (!config) 91 return NULL; 92 for (i = 0; i < config->desc.bNumInterfaces; i++) 93 if (config->interface[i]->altsetting[0] 94 .desc.bInterfaceNumber == ifnum) 95 return config->interface[i]; 96 97 return NULL; 98 }
这个函数的道理很简单,就是拿你指定的接口号,和当前配置的每一个接口可选设置0里接口描述符的bInterfaceNumber字段做比较,如果相等,那个接口就是你要寻找的,如果都不相等,不能满足你的要求,虽然它已经尽力了。
如果你看了协议,可能会在spec的9.6.5节里看到,请求配置描述符时,配置里的所有接口描述符是按照顺序一个一个返回的。那为什么这里又明确说明,不要期待它就会是接口号的顺序?其实以前这里并不是这么说的,这个数组是按照0..desc.bNumInterfaces的顺序,但同时又需要通过usb_ifnum_to_if函数来获得指定接口号的接口对象,Alan Stern质疑了这种有些矛盾的说法,于是David Brownell就把它改成现在这个样子了,为什么改?因为协议归协议,厂商归厂商,有些厂商就是不遵守协议,它非要先返回接口1再返回接口0,所以就不得不增加usb_ifnum_to_if函数。
USB_MAXINTERFACES是drivers/usb/usb.h中定义的一个宏,值为32,不要说不够用,谁见过有很多接口的设备?
/* this maximum is arbitrary */ #define USB_MAXINTERFACES 32
254行,intf_cache[USB_MAXINTERFACES],cache是缓存。这是一个struct usb_interface_cache对象的结构数组;usb_interface,USB接口;cache,缓存。所以usb_interface_cache就是USB接口的缓存。缓存些什么?在include/linux/usb/usb.h里查看其定义。
193 struct usb_interface_cache { 194 unsigned num_altsetting; /* number of alternate settings */ 195 struct kref ref; /* reference counter */ 196 197 /* variable-length array of alternate settings for this interface, 198 * stored in no particular order */ 199 struct usb_host_interface altsetting[0]; 200 };
199行的altsetting[0]是一个可变长数组,可以按需分配,你对设备说GET_DESCRIPTOR时,内核就根据返回的每个接口可选设置的数目分配给intf_cache数组相应的空间,有多少需要就分配多少空间。
为什么要缓存这些东西?为了在配置被取代之后仍然能够获取它的一些信息,就把日后可能会需要的一些东西放在了intf_cache数组的struct usb_interface_cache对象里。谁会需要?这么说吧,你通过sysfs这个窗口只能看到设备当前配置的一些信息,即使是这个配置下面的接口,也只能看到接口正在使用的可选设置的信息,可是你希望能够看到更多的信息,怎么办?usbfs里面显示有系统中所有USB设备的可选配置和端点信息,它就是利用intf_cache这个数组里缓存的东西实现的。
256行,extra;257行,extralen,有关额外扩展的描述符,和struct usb_host_interface里的差不多,只是这里的是针对配置的,如果你使用GET_DESCRIPTOR请求从设备中获得配置描述符信息,它们会紧跟在标准的配置描述符后面返回给你。