Linux那些事儿之我是USB
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人
 17.设备

17.设备

struct usb_device结构冗长而又杂乱,但还是得说。

336 struct usb_device {
337    int     devnum;        /* Address on USB bus */
338    char    devpath [16];  /* Use in messages: /port/port/... */
339    enum usb_device_state state;/* configured, not attached, etc */
340    enum usb_device_speed speed; /* high/full/low (or error) */
341
342    struct usb_tt *tt;   /* low/full speed dev, highspeed hub */
343    int     ttport;      /* device port on that tt hub */
344
345    unsigned int toggle[2];  /* one bit for each endpoint
346                                * ([0] = IN, [1] = OUT) */
347
348    struct usb_device *parent; /* our hub, unless we're the root */
349    struct usb_bus *bus;       /* Bus we're part of */
350    struct usb_host_endpoint ep0;
351
352    struct device dev;         /* Generic device interface */
353
354    struct usb_device_descriptor descriptor;/* Descriptor */
355    struct usb_host_config *config; /* All of the configs */
356
357    struct usb_host_config *actconfig;/* the active configuration */
358    struct usb_host_endpoint *ep_in[16];
359    struct usb_host_endpoint *ep_out[16];
360
361    char **rawdescriptors;   /* Raw descriptors for each config */
362
363    unsigned short bus_mA;   /* Current available from the bus */
364    u8 portnum;       /* Parent port number (origin 1) */
365    u8 level;        /* Number of USB hub ancestors */
366
367    unsigned discon_suspended:1;  /* Disconnected while suspended */
368    unsigned have_langid:1;    /* whether string_langid is valid */
369    int string_langid;         /* language ID for strings */
370
371    /* static strings from the device */
372    char *product;            /* iProduct string, if present */
373    char *manufacturer;    /* iManufacturer string, if present */
374    char *serial;          /* iSerialNumber string, if present */
375
376    struct list_head filelist;
377 #ifdef CONFIG_USB_DEVICE_CLASS
378    struct device *usb_classdev;
379 #endif
380 #ifdef CONFIG_USB_DEVICEFS
381    struct dentry *usbfs_dentry;/*usbfs dentry entry for the device*/
382 #endif
383    /*
384     * Child devices - these can be either new devices
385     * (if this is a hub device), or different instances
386     * of this same device.
387     *
388     * Each instance needs its own set of data structures.
389     */
390
391    int maxchild;       /* Number of ports if hub */
392    struct usb_device *children[USB_MAXCHILDREN];
393
394    int pm_usage_cnt;     /* usage counter for autosuspend */
395    u32 quirks;       /* quirks of the whole device */
396
397 #ifdef CONFIG_PM
398    struct delayed_work autosuspend; /* for delayed autosuspends */
399    struct mutex pm_mutex;    /* protects PM operations */
400
401    unsigned long last_busy;   /* time of last use */
402    int autosuspend_delay;    /* in jiffies */
403
404    unsigned auto_pm:1;    /* autosuspend/resume in progress */
405    unsigned do_remote_wakeup:1;/* remote wakeup should be enabled */
406    unsigned autosuspend_disabled:1; /* autosuspend and autoresume */
407    unsigned autoresume_disabled:1; /* disabled by the user */
408 #endif
409 };

337行,devnum,设备的地址。此地与写程序时通常说的地址不一样。devnum只是USB设备在一条USB总线上的编号。你的USB设备插到Hub上时,Hub观察到这个变化,会在一个漫长而又曲折的处理过程中调用一个名叫choose_address的函数,为你的设备选择一个地址。

有人说我没有用Hub,我的USB设备直接插到主机的USB接口上了。不管是一般的Hub还是Root Hub,你的USB设备总要通过一个Hub才能在USB的世界里生活。

现在来认识USB子系统里面关于地址的游戏规则。在USB世界里,一条总线就是大树一棵,一个设备就是一片叶子。为了记录这棵树上的每一个叶子节点,每条总线设有一个地址映射表,即struct usb_bus结构体里有一个成员struct usb_devmap devmap。

268  /* USB device number allocation bitmap */
269  struct usb_devmap {
270      unsigned long devicemap[128 / (8*sizeof(unsigned long))];
271 };

什么是usb_bus?前面不是已经有一个struct bus_type类型的usb_bus_type了吗?没错,在USB子系统的初始化函数usb_init里已经注册了usb_bus_type,不过那是让系统知道有这么一个类型的总线。而一个总线类型和一条总线是两码事儿。从硬件上来讲,一个主机控制器就会连出一条USB总线;而从软件上来讲,不管你有多少个主机控制器,或者说有多少条总线,它们通通属于usb_bus_type这个类型,只是每一条总线对应一个struct usb_bus结构体变量,这个变量在主机控制器的驱动程序中申请。

上面的devmap地址映射表就表示了一条总线上设备连接的情况,假设unsigned long为4Bytes,那么unsigned long devicemap[128/(8*sizeof(unsigned long)]]就等价于unsigned long devicemap[128/(8*4)],进而等价于unsigned long devicemap[4],而4Bytes就是32 bits,因此这个数组最终表示的就是128 bits。而这也对应于一条总线可以连接128个USB设备。之所以这里使用sizeof(unsigned long),就是为了跨平台应用,不管unsigned long到底是几,总之这个devicemap数组最终可以表示128位,也就是说每条总线上最多可以连上128个设备。

338行,devpath [16],它显然是用来记录一个字符串的,这个字符串是什么意思?如下所示。

localhost:~ # ls /sys/bus/usb/devices/
1-0:1.0 2-1       2-1:1.1   4-0:1.0  4-5:1.0  usb2  usb4
2-0:1.0 2-1:1.0   3-0:1.0   4-5      usb1     usb3

在sysfs文件系统下,我们可以看到这些乱七八糟的东西,它们都是什么?usb1、usb2、usb3、usb4表示计算机上接了4条USB总线,即4个USB主机控制器,事物多了自然就要编号,就跟我们在中学或大学里的学号一样,用于区分多个个体。

而4-0:1.0表示什么?4表示是4号总线,或者说4号Root Hub;0就是这里我们说的devpath,1表示配置为1号,0表示接口号为0。也就是说,4号总线的0号端口的设备,使用的是1号配置,接口号为0。

那么devpath是否就是端口号呢?显然不是,这里我列出来的这个例子是只有Root Hub没有级联Hub的情况,如果在Root Hub上又接了别的Hub,然后一级一级连下去,那么如何在sysfs里面来表示这整个大家族呢?这就是devpath的作用,顶级设备的devpath就是其连在Root Hub上的端口号,而次级的设备就是其父hub的devpath后面加上其端口号,即如果4-0:1.0如果是一个Hub,那么它下面的1号端口的设备就可以是4-0.1:1.0;2号端口的设备就可以是4-0.2:1.0;3号端口就可以是4-0.3:1.0。总的来说,就是端口号一级一级地往下加。

339行,state,设备的状态,这是一个枚举类型。

557 enum usb_device_state {
558     /* NOTATTACHED isn't in the USB spec, and this state acts
559      * the same as ATTACHED ... but it's clearer this way.
560      */
561     USB_STATE_NOTATTACHED = 0,
562
563     /* chapter 9 and authentication (wireless) device states */
564     USB_STATE_ATTACHED,
565     USB_STATE_POWERED,             /* wired */
566     USB_STATE_UNAUTHENTICATED,     /* auth */
567     USB_STATE_RECONNECTING,        /* auth */
568     USB_STATE_DEFAULT,             /* limited function */
569     USB_STATE_ADDRESS,
570     USB_STATE_CONFIGURED,          /* most functions */
571
572     USB_STATE_SUSPENDED
573
574     /* NOTE: there are actually four different SUSPENDED
575      * states, returning to POWERED, DEFAULT, ADDRESS, or
576      * CONFIGURED respectively when SOF tokens flow again.
577      */
578 };

上面定义了9种状态,spec里只定义了6种状态,Attached,Powered,Default,Address,Configured,Suspended,对应于spec中的Table 9.1。

● Attached表示设备已经连接到USB接口上了,是Hub检测到设备时的初始状态。那么这里所谓的USB_STATE_NOTATTACHED就是表示设备并没有Attached。

● Powered是加电状态。USB设备的电源可以来自外部电源,协议中叫做self-powered,也可以来自Hub,称为bus-powered。尽管self-powered的USB设备可能在连接上USB接口以前已经上电,但它们直到连上USB接口后才能被看做是“Powered”的。

● Default默认状态,在Powered之后,设备必须在收到一个复位(reset)信号并成功复位后,才能使用默认地址回应主机发过来的设备和配置描述符的请求。

● Address状态表示主机分配了一个唯一的地址给设备,此时设备可以使用默认管道响应主机的请求。

● Configured状态表示设备已经被主机配置过了,也就是协议中说的处理一个带有非0值的SetConfiguration()请求,此时主机可以使用设备提供的所有功能。

● Suspended挂起状态,为了省电,设备在指定的时间内(大约3ms吧)如果没有发生总线传输,就要进入挂起状态。此时,USB设备要自己维护包括地址、配置在内的信息。

USB设备从生到死都要按照这么几个状态,遵循这么一个过程。

340行,speed,设备的速度,这也是一个枚举变量。

550 enum usb_device_speed {
551    USB_SPEED_UNKNOWN = 0,        /* enumerating */
552    USB_SPEED_LOW, USB_SPEED_FULL,    /* usb 1.1 */
553    USB_SPEED_HIGH,               /* usb 2.0 */
554    USB_SPEED_VARIABLE,           /* wireless (usb 2.5) */
555 };

在USB 3.0以前,设备有三种速度:低速、全速、高速。USB 1.1在那时只有低速和全速,后来才出现了高速,就是所谓的480MB/s。这里还有一个USB_SPEED_VARIABLE,是无线USB,号称USB 2.5。USB_SPEED_UNKNOWN只是表示现阶段还不知道这个设备究竟什么速度。

342行,tt;343行,ttport。tt全称为transaction translator。你可以把它想像成一块特殊的电路,是Hub里面的电路,确切地说是高速Hub中的电路,我们知道USB设备有三种速度,分别是Low Speed,Full Speed和High Speed,即所谓的低速、全速及高速。以前主机控制器,只有两种接口的,OHCI/UHCI,这都是在USB spec 1.0时,2.0时代推出了EHCI,高速设备应运而生。

Hub也有高速的Hub和低速的Hub,但是这里就产生一个兼容性问题了,高速的Hub是否能够支持低速/全速的设备呢?一般来说是不支持的,于是有了一个叫做TT的电路,它就负责高速和低速/全速的数据转换。于是,如果一个高速设备中有这么一个TT,那么就可以连接低速/全速设备,要不然,低速/全速设备就没法用,只能连接到OHCI/UHCI那边出来的Hub口里。

345行,toggle[2],这个数组只有两个元素,分别对应IN端点和OUT端点,每一个端点占一位。似乎这么说仍是在雾中看花,黑格尔告诉我们:“存在就是有价值的。”那么这个数组存在的价值是什么?

前面说,你要想和你的USB通信,创建一个urb,为它赋值,交给USB Core就可以了。这个urb是站在我们的角度,实际上在USB cable里流淌的根本就不是那么回事儿,我们提交的是urb,USB cable里流淌的是一个一个的数据包(packet)。

所有packets都从一个SYNC同步字段开始,SYNC是一个8位长的二进制串,只是用来同步的,它的最后两位标志了SYNC的结束和PID(Packet Identifer)的开始。

PID也是一个8位的二进制串,前四位用来区分不同的packet类型,后面四位只是前四位的反码,是校验用的。正如spec的Table 8-1里描述的那样,共有四大类的packet,分别是Token、Data、Handshake和Special,每个大类又包含了几个子类。

主机和设备通过PID来判断送过来的packet是不是自己所需要的。

PID之后紧跟着的是地址字段,每个packet都需要知道自己要往哪里去,它们是一个一个目的明确的精灵,行走在USB cable里。这个地址实际上包括两部分:7位表示了总线上连接的设备或接口的地址,4位表示端点的地址,这就是为什么前面说每条USB总线最多只能有128个设备的原因,即使是高速设备,除了0号端点也最多只能有15个in端点和15个out端点。

地址字段再往后是11位的帧号(frame number),值达到7FFH时归零。这个帧号并不是每一个packet都会有,它只在每帧或微帧(Mircoframe)开始的SOF Token包中发送。帧是相对于低速和全速模式来说的,一帧就是1ms,对于高速模式的称呼是微帧,一个微帧为125ms,每帧或微帧当然不会只能传一个packet。

帧号再往后就是千呼万唤始出来的Data字段了,它可以有0到1024个字节不等。最后还有CRC校验字段来做扫尾工作。

我们开始学习packet,但这里只看一看Data类型的packet。有四种类型的Data包:DATA0,DATA1,DATA2和MDATA。存在就是有价值的,这里数据包分成4种自然有其道理,其中DATA0和DATA1就可以用来实现data toggle同步,看到toggle,好像有点接近不久之前留下的疑问了。

对于批量传输、控制传输和中断传输来说,数据包最开始都是被初始化为DATA0的,然后为了传输的正确性,就传一次DATA0,再传一次DATA1。一旦哪次打破了这种规律,主机就可以认为传输出错了。对于等时传输来说,data toggle并不被支持。USB就是在使用这种简单的哲学来判断对与错。

我们的struct usb_device中的数组unsigned int toggle[2]就是为了支持这种简单的哲学而生的,它里面的每一位元素表示的就是每个端点当前发送或接收的数据包是DATA0还是DATA1。

348行的parent,struct usb_device结构体的parent自然也是一个struct usb_device指针。对于Root Hub,前面说过,它是和Host Controller是绑定在一起的。它的parent指针在Host Controller的驱动程序中就已经赋了值,这个值就是NULL。换句话说,对于Root Hub,它不需要再有父指针了,这个父指针就是给从Root Hub连出来的节点用的。USB设备是从Root Hub开始,一个一个往外面连。比如Root Hub有4个接口,每个接口连一个USB设备,比如其中有一个是Hub,那么这个Hub有可以继续有多个接口,于是一级一级地往下连,最终连成了一棵树。

349行,bus,设备所在的那条总线。

350行,ep0,端点0的特殊地位决定了它必将受到特殊的待遇,在struct usb_device对象产生时它就要初始化。

352行,dev,嵌入到struct usb_device结构中的struct device结构。

354行,desc,设备描述符,作为四大描述符的第三个姗姗而来。它在include/linux/usb/ch9.h中定义。

203 /* USB_DT_DEVICE: Device descriptor */
204 struct usb_device_descriptor {
205    __u8 bLength;
206    __u8 bDescriptorType;
207
208    __le16 bcdUSB;
209    __u8 bDeviceClass;
210    __u8 bDeviceSubClass;
211    __u8 bDeviceProtocol;
212    __u8 bMaxPacketSize0;
213    __le16 idVendor;
214    __le16 idProduct;
215    __le16 bcdDevice;
216     __u8 iManufacturer;
217    __u8 iProduct;
218    __u8 iSerialNumber;
219    __u8 bNumConfigurations;
220 } __attribute__ ((packed));
221
222 #define USB_DT_DEVICE_SIZE     18

205行,bLength,描述符的长度,可以自己数一数,或者看紧接着的定义USB_DT_DEVICE_SIZE。

206行,bDescriptorType,这里对于设备描述符应该是USB_DT_DEVICE,0x01。

208行,bcdUSB,USB spec的版本号,一个设备如果能够进行高速传输,那么它的设备描述符里的bcdUSB这一项就应该为0200H。

209行,bDeviceClass;210行,bDeviceSubClass;211行,bDeviceProtocol,和接口描述符的意义差不多。

212行,bMaxPacketSize0,端点0一次可以处理的最大字节数,端点0的属性却放到设备描述符里去了,更加彰显了它突出的地位。

前面说端点时说了端点0并没有一个专门的端点描述符,因为不需要,基本上它所有的特性都在spec里规定好了的。然而,别忘了这里说的是“基本上”,有一个特性则是不一样的,这叫做maximum packet size,每个端点都有个特性,即告诉你该端点能够发送或者接收的包的最大值。对于通常的端点来说,这个值被保存在该端点描述符中的wMaxPacketSize这个field,而对于端点0就不一样了,由于它自己没有一个描述符,而每个设备又都有这么一个端点,所以这个信息被保存在了设备描述符里,所以我们在设备描述符里可以看到,bMaxPacketSize0。而且spec还规定了,这个值只能是8,16,32或者64这四者之一,如果一个设备工作在高速模式,这个值还只能是64,如果是工作在低速模式,则只能是8,取别的值都不行。

213行,idVendor;214行,idProduct,分别是厂商和产品的ID号。

215行,bcdDevice,设备的版本号。

216行,iManufacturer;217行,iProduct;218行,iSerialNumber,分别是厂商,产品和序列号对应的字符串描述符的索引值。

219行,bNumConfigurations:设备当前速度模式下支持的配置数量。有的设备可以在多个速度模式下操作,这里包括的只是当前速度模式下的配置数目,不是总的配置数目。

这就是设备描述符,它和spec中的Table 9-8是一一对应的。回到struct usb_device的355行,config;357行,actconfig,分别表示设备拥有的所有配置和当前激活的,也就是正在使用的配置。USB设备的配置用struct usb_host_config结构来表示,下节再说。

358行,ep_in[16];359行,ep_out[16],除了端点0,一个设备即使在高速模式下也最多只能再有15个IN端点和15个OUT端点,端点0太特殊了,对应的管道是message管道,又能进又能出,所以这里的ep_in和ep_out数组都有16个值。

361行,rawdescriptors,这是一个字符指针数组,数组里的每一项都指向一个使用GET_DESCRIPTOR请求去获得配置描述符时所得到的结果。考虑为什么我只说得到的结果,而不直接说得到的配置描述符?不是请求的就是配置描述符吗?这是因为当你使用GET_DESCRIPTOR去请求配置描述符时,设备返回给你的不仅仅只有配置描述符,它把该配置所包括的所有接口的接口描述符,还有接口里端点的端点描述符一股脑儿地都塞给你了。第一个接口的接口描述符紧跟着这个配置描述符,然后是这个接口下面端点的端点描述符,如果有还有其他接口,它们的接口描述符和端点描述符也跟在后面,这里面专门为一类设备定义的描述符和厂商定义的描述符跟在它们对应的标准描述符后面。

这里提到了GET_DESCRIPTOR请求,就顺便简单提提USB的设备请求(device request)。协议中说了,所有的设备通过默认的控制管道来响应主机的请求,既然使用的是控制管道,那当然就是控制传输了,这些请求的底层packet属于Setup类型。协议中同时也定义了一些标准的设备请求,并规定所有的设备必须响应它们,即使它们还处于Default或Address状态。在这些标准的设备请求里,GET_DESCRIPTOR就赫然在列。

363行,bus_mA,这个值是在主机控制器的驱动程序中设置的,通常来讲,计算机的USB端口可以提供500mA的电流。

364行,portnum,不管是Root Hub还是一般的Hub,你的USB设备总归要插在一个Hub的端口上才能用,portnum就是那个端口号。当然,对于Root Hub这个USB设备来说,它本身没有portnum这个概念,因为它不插在别的Hub的任何一个口上。所以对于Root Hub来说,它的portnum在主机控制器的驱动程序里给设置成了0。

365行,level,层次,也可以说是级别,表示USB设备树的级连关系。Root Hub的level当然就是0,其下面一层就是level 1,再下面一层就是level 2,依此类推。

366行,discon_suspended,Disconnected while suspended。

368行,have_langid;369行,string_langid,USB设备中的字符串描述符使用的是UNICODE编码,可以支持多种语言,string_langid就是用来指定使用哪种语言的,have_langid用来判断string_langid是否有效。

372行,product;373行,manufacturer;374行,serial,分别用来保存产品、厂商和序列号对应的字符串描述符信息。

376行到382行,与usbfs相关的代码。

391行,maxchild,Hub的端口数,注意可不包括上行端口。

392行,children[USB_MAXCHILDREN],USB_MAXCHILDREN是include/linux/usb.h中定义的一个宏,值为31。

324 #define USB_MAXCHILDREN   (31)

其实Hub可以一共接255个端口,不过实际上遇到的Hub最多的也就是支持10个端口的,所以31端口基本上够用了。

394行,pm_usage_cnt,struct usb_interface结构中也有。

396行,quirks,简单说就是 “毛病”。

397行,看到#ifdef CONFIG_PM这个标志,我们就知道从这里直到最后的那个#endif都是关于电源管理的代码。