usb驱动分析一:http://wenku.baidu.com/view/fbce5512a2161479171128f5.html
USB驱动分析(二)
probe,disconnect,id_table,这三个咚咚中首先要登场亮相的是id_table,它是干嘛用的呢?
我们说过,一个device只能绑定一个driver,但driver并非只能支持一种设备,道理很简单,比如我有两块U盘,那么我可以一起都插入,但是我只需要加载一个模块,usb-storage,没听说过插入两块U盘就得加载两次驱动程序的,除非这两块U盘本身就得使用不同的驱动程序.也正是因为一个模块可以被多个设备共用,才会有模块计数这么一个说法.
ok,既然一个driver可以支持多个device,那么当发现一个device的时候,如何知道哪个driver才是她的Mr.Right呢?这就是id_table的用处,让每一个struct usb_driver准备一张表,里边注明该driver支持哪些设备,这总可以了吧.如果你这个设备属于这张表里的,那么ok,绑定吧,如果不属于这张表里的,那么不好意思,您请便.哪凉快上哪去.
来自struct usb_driver中的id_table,
const struct usb_device_id *id_table;
实际上是一个指针,一个struct usb_device_id结构体的指针,当然赋了值以后就是代表一个数组名了,正如我们在定义struct usb_driver usb_storage_driver中所赋的值那样,.id_table=storage_usb_ids,那好,我们来看一下usb_device_id这究竟是怎样一个结构体.
struct usb_device_id来自include/linux/mod_devicetable.h,
40 /*
41 * Device table entry for "new style" table-driven USB drivers.
42 * User mode code can read these tables to choose which modules to load.
43 * Declare the table as a MODULE_DEVICE_TABLE.
44 *
45 * A probe() parameter will point to a matching entry from this table.
46 * Use the driver_info field for each match to hold information tied
47 * to that match: device quirks, etc.
48 *
49 * Terminate the driver's table with an all-zeroes entry.
50 * Use the flag values to control which fields are compared.
51 */
52
53 /**
54 * struct usb_device_id - identifies USB devices for probing and hotplugging
55 * @match_flags: Bit mask controlling of the other fields are used to match
56 * against new devices. Any field except for driver_info may be used,
57 * although some only make sense in conjunction with other fields.
58 * This is usually set by a USB_DEVICE_*() macro, which sets all
59 * other fields in this structure except for driver_info.
60 * @idVendor: USB vendor ID for a device; numbers are assigned
61 * by the USB forum to its members.
62 * @idProduct: Vendor-assigned product ID.
63 * @bcdDevice_lo: Low end of range of vendor-assigned product version numbers.
64 * This is also used to identify individual product versions, for
65 * a range consisting of a single device.
66 * @bcdDevice_hi: High end of version number range. The range of product
67 * versions is inclusive.
68 * @bDeviceClass: Class of device; numbers are assigned
69 * by the USB forum. Products may choose to implement classes,
70 * or be vendor-specific. Device classes specify behavior of all
71 * the interfaces on a devices.
72 * @bDeviceSubClass: Subclass of device; associated with bDeviceClass.
73 * @bDeviceProtocol: Protocol of device; associated with bDeviceClass.
74 * @bInterfaceClass: Class of interface; numbers are assigned
75 * by the USB forum. Products may choose to implement classes,
76 * or be vendor-specific. Interface classes specify behavior only
77 * of a given interface; other interfaces may support other classes.
78 * @bInterfaceSubClass: Subclass of interface; associated with bInterfaceClass.
79 * @bInterfaceProtocol: Protocol of interface; associated with bInterfaceClass.
80 * @driver_info: Holds information used by the driver. Usually it holds
81 * a pointer to a descriptor understood by the driver, or perhaps
82 * device flags.
83 *
84 * In most cases, drivers will create a table of device IDs by using
85 * USB_DEVICE(), or similar macros designed for that purpose.
86 * They will then export it to userspace using MODULE_DEVICE_TABLE(),
87 * and provide it to the USB core through their usb_driver structure.
88 *
89 * See the usb_match_id() function for information about how matches are
90 * performed. Briefly, you will normally use one of several macros to help
91 * construct these entries. Each entry you provide will either identify
92 * one or more specific products, or will identify a class of products
93 * which have agreed to behave the same. You should put the more specific
94 * matches towards the beginning of your table, so that driver_info can
95 * record quirks of specific products.
96 */
97 struct usb_device_id {
98 /* which fields to match against? */
99 __u16 match_flags;
100
101 /* Used for product specific matches; range is inclusive */
102 __u16 idVendor;
103 __u16 idProduct;
104 __u16 bcdDevice_lo;
105 __u16 bcdDevice_hi;
106
107 /* Used for device class matches */
108 __u8 bDeviceClass;
109 __u8 bDeviceSubClass;
110 __u8 bDeviceProtocol;
111
112 /* Used for interface class matches */
113 __u8 bInterfaceClass;
114 __u8 bInterfaceSubClass;
115 __u8 bInterfaceProtocol;
116
117 /* not matched against */
118 kernel_ulong_t driver_info;
119 };
实际上这个结构体对每一个usb设备来说,就相当于是她的身份证,记录了她的一些基本信息,通常我们的身份证上会记录我们的姓名,性别,出生年月,户口地址等等,而usb设备她也有她需要记录的信息,以区分她和别的usb设备,比如Vendor-厂家,Product-产品,以及其他一些比如产品编号,产品的类别,遵循的协议,这些都会在usb的规范里边找到对应的冬冬.暂且先不细说.
于是我们知道,一个usb_driver会把它的这张id表去和每一个usb设备的实际情况进行比较,如果该设备的实际情况和这张表里的某一个id相同,准确地说,只有这许多特征都吻合,才能够把一个usb device和这个usb driver进行绑定,这些特征哪怕差一点也不行.就像我们每个人都是一道弧,都在不停寻找能让彼此嵌成完整的圆的另一道弧,事实却是,每个人对∏(PI)的理解不尽相同,而圆心能否重合,或许只有痛过才知道.差之毫厘,失之交臂.
那么usb设备的实际情况是什么时候建立起来的?嗯,在介绍.probe指针之前有必要先谈一谈另一个数据结构了,她就是struct usb_device.
在struct usb_driver中,.probe和.disconnect的原型如下:
int (*probe) (struct usb_interface *intf,const struct usb_device_id *id);
void (*disconnect) (struct usb_interface *intf);
我们来看其中的参数,struct usb_device_id这个不用说了,刚才已经介绍过,那么struct usb_interface从何而来?还是让我们先从struct usb_device说起.
我们知道每一个device对应一个struct device结构体变量,但是device不可能是万能的,生命是多样性的,就像我们可以用"人"来统称全人类,但是分的细一点,又有男人和女人的区别,那么device也一样,由于有各种各样的设备,于是又出来了更多的词汇(数据结构),比如针对usb设备,开发者们设计了一个叫做struct usb_device的结构体.她定义于include/linux/usb.h,
294 /*
295 * struct usb_device - kernel's representation of a USB device
296 *
297 * FIXME: Write the kerneldoc!
298 *
299 * Usbcore drivers should not set usbdev->state directly. Instead use
300 * usb_set_device_state().
301 */
302 struct usb_device {
303 int devnum; /* Address on USB bus */
304 char devpath [16]; /* Use in messages: /port/port/... */
305 enum usb_device_state state; /* configured, not attached, etc */
306 enum usb_device_speed speed; /* high/full/low (or error) */
307
308 struct usb_tt *tt; /* low/full speed dev, highspeed hub */
309 int ttport; /* device port on that tt hub */
310
311 struct semaphore serialize;
312
313 unsigned int toggle[2]; /* one bit for each endpoint ([0] = IN, [1] = OUT) */
314 int epmaxpacketin[16]; /* INput endpoint specific maximums */
315 int epmaxpacketout[16]; /* OUTput endpoint specific maximums */
316
317 struct usb_device *parent; /* our hub, unless we're the root */
318 struct usb_bus *bus; /* Bus we're part of */
319
320 struct device dev; /* Generic device interface */
321
322 struct usb_device_descriptor descriptor;/* Descriptor */
323 struct usb_host_config *config; /* All of the configs */
324 struct usb_host_config *actconfig;/* the active configuration */
325
326 char **rawdescriptors; /* Raw descriptors for each config */
327
328 int have_langid; /* whether string_langid is valid yet */
329 int string_langid; /* language ID for strings */
330
331 void *hcpriv; /* Host Controller private data */
332
333 struct list_head filelist;
334 struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */
335
336 /*
337 * Child devices - these can be either new devices
338 * (if this is a hub device), or different instances
339 * of this same device.
340 *
341 * Each instance needs its own set of data structures.
342 */
343
344 int maxchild; /* Number of ports if hub */
345 struct usb_device *children[USB_MAXCHILDREN];
346 };
347 #define to_usb_device(d) container_of(d, struct usb_device, dev)
看起来很复杂的一个数据结构,不过我们目前不需要去理解她的每一个成员,不过我们可以看到,其中有一个成员struct device dev,没错,这就是前面说的那个属于每个设备的struct device结构体变量.
实际上,U盘驱动里边并不会直接去处理这个结构体,因为对于一个U盘来说,她就是对应这么一个struct usb_device的变量,这个变量由usb core负责申请和赋值.但是我们需要记住这个结构体变量,因为日后我们调用usb core提供的函数的时候,会把这个变量作为参数传递上去,因为很简单,要和usb core交流,总得让人家知道我们是谁吧,比如后来要调用的一个函数,usb_buffer_alloc,它就需要这个参数.
而对U盘设备驱动来说,比这个struct usb_device更重要的数据结构是,struct usb_interface.走到这一步,我们不得不去了解一点usb设备的规范了,或者专业一点说,usb协议.因为我们至少要知道什么是usb interface.
星爷说,人有人他妈,妖有妖他妈.说的就是任何事物都有其要遵守的规矩.usb设备要遵循的就是usb协议. 不管是软件还是硬件,在设计的伊始,总是要参考usb协议.怎么设计硬件,如何编写软件,不看usb协议,谁也不可能凭空想象出来.毕竟不是写小说,有几人能像海岩那样,光凭想象就能写出便衣警察,永不瞑目,玉观音这些经典的爱情加案情的作品来呢.
usb协议规定了,每个usb设备都得有些基本的元素,称为描述符,有四类描述符是任何一种usb设备都得有的.他们是,device descriptor,configuration descriptor,interface descriptor,endpoint descriptor.描述符里的冬冬是一个设备出厂的时候就被厂家给固化在设备里了.这种东西不管怎样也改变不了,比如我有个Intel的U盘,那里边的固有的信息肯定是在Intel出厂的时候就被烙在里边了,厂家早已把它的一切,烙上Intel印.所以当我插入U盘,用cat /proc/scsi/scsi命令看一下的话,"Vendor"那一项显示的肯定是Intel. 关于这几种描述符,usb core在总线扫描那会就会去读取,会去获得里边的信息,其中,device描述符描述的是整个device,注意了,这个device和咱们一直讲的device和driver那里的device是不一样的.因为一个usb device实际上指的是一种宏观上的概念,它可以是一种多功能的设备,改革开放之后,多功能的东西越来越多了,比如外企常见的多功能一体机,就是集打印机,复印机,扫描仪,传真机于一体的设备, 当然,这不属于usb设备,但是usb设备当然也有这种情况,比如电台DJ可能会用到的,一个键盘,上边带一个扬声器,它们用两个usb接口接到usb hub上去,而device描述符描述的就是这整个设备的特点.那么configuration描述符呢,老实说,对我们了解U盘驱动真是没有什么意义,但是作为一个有责任心的男人,此刻,我必须为它多说几句,虽然只是很简单的说几句.一个设备可以有一种或者几种配置,这能理解吧?没见过具体的usb设备?那么好,手机见过吧,每个手机都会有多种配置,或者说"设定",比如,我的这款,Nokia6300,手机语言,可以设定为English,繁体中文,简体中文,一旦选择了其中一种,那么手机里边所显示的所有的信息都是该种语言/字体.还有最简单的例子,操作模式也有好几种,标准,无声,会议,etc.基本上如果我设为"会议",那么就是只振动不发声,要是设为无声,那么就啥动静也不会有,只能凭感觉了,以前去公司面试的话通常就是设为无声,因为觉得振动也不好,让人家面试官听到了还是不合适.那么usb设备的配置也是如此,不同的usb设备当然有不同的配置了,或者说需要配置哪些东西也会不一样.好了,关于配置,就说这么多,更多的我们暂时也不需要了解了.
对于usb设备驱动程序编写者来说,更为关键的是下面两个,interface和endpoint.先说,interface.第一句,一个interface对应一个usb设备驱动程序.没错,还说前边那个例子,一个usb设备,两种功能,一个键盘,上面带一个扬声器,两个接口,那这样肯定得要两个驱动程序,一个是键盘驱动程序,一个是音频流驱动程序.道上的兄弟喜欢把这样两个整合在一起的东西叫做一个设备,那好,让他们去叫吧,我门用interface来区分这两者行了吧.于是有了我们前面提到的那个数据结构,struct usb_interface.它定义于include/linux/usb.h:
71 /**
72 * struct usb_interface - what usb device drivers talk to
73 * @altsetting: array of interface structures, one for each alternate
74 * setting that may be selected. Each one includes a set of
75 * endpoint configurations. They will be in no particular order.
76 * @num_altsetting: number of altsettings defined.
77 * @cur_altsetting: the current altsetting.
78 * @driver: the USB driver that is bound to this interface.
79 * @minor: the minor number assigned to this interface, if this
80 * interface is bound to a driver that uses the USB major number.
81 * If this interface does not use the USB major, this field should
82 * be unused. The driver should set this value in the probe()
83 * function of the driver, after it has been assigned a minor
84 * number from the USB core by calling usb_register_dev().
85 * @condition: binding state of the interface: not bound, binding
86 * (in probe()), bound to a driver, or unbinding (in disconnect())
87 * @dev: driver model's view of this device
88 * @class_dev: driver model's class view of this device.
89 *
90 * USB device drivers attach to interfaces on a physical device. Each
91 * interface encapsulates a single high level function, such as feeding
92 * an audio stream to a speaker or reporting a change in a volume control.
93 * Many USB devices only have one interface. The protocol used to talk to
94 * an interface's endpoints can be defined in a usb "class" specification,
95 * or by a product's vendor. The (default) control endpoint is part of
96 * every interface, but is never listed among the interface's descriptors.
97 *
98 * The driver that is bound to the interface can use standard driver model
99 * calls such as dev_get_drvdata() on the dev member of this structure.
100 *
101 * Each interface may have alternate settings. The initial configuration
102 * of a device sets altsetting 0, but the device driver can change
103 * that setting using usb_set_interface(). Alternate settings are often
104 * used to control the the use of periodic endpoints, such as by having
105 * different endpoints use different amounts of reserved USB bandwidth.
106 * All standards-conformant USB devices that use isochronous endpoints
107 * will use them in non-default settings.
108 *
109 * The USB specification says that alternate setting numbers must run from
110 * 0 to one less than the total number of alternate settings. But some
111 * devices manage to mess this up, and the structures aren't necessarily
112 * stored in numerical order anyhow. Use usb_altnum_to_altsetting() to
113 * look up an alternate setting in the altsetting array based on its number.
114 */
115 struct usb_interface {
116 /* array of alternate settings for this interface,
117 * stored in no particular order */
118 struct usb_host_interface *altsetting;
119
120 struct usb_host_interface *cur_altsetting; /* the currently
121 * active alternate setting */
122 unsigned num_altsetting; /* number of alternate settings */
123
124 int minor; /* minor number this interface is bound to */
125 enum usb_interface_condition condition; /* state of binding */
126 struct device dev; /* interface specific device info */
127 struct class_device *class_dev;
128 };
129 #define to_usb_interface(d) container_of(d, struct usb_interface, dev)
130 #define interface_to_usbdev(intf) \
131 container_of(intf->dev.parent, struct usb_device, dev)
嗬,贴这么长一段,怎么又是注释为主啊?知足吧,Linux代码中注释实在是太少了,等你真的需要认真看某一个模块的时候你就会嫌注释少了.这个结构体是一个贯穿整个U盘驱动程序的,所以虽然我们不用去深入了解,但是需要记住,整个U盘驱动程序在后面任何一处提到的struct usb_interface都是同一个变量,这个变量是在usb core总线扫描的时候就申请好了的.我们只需贯彻鲁迅先生的拿来主义即可,直接用就是了.比如前面说过的storage_probe(struct usb_interface *intf,const struct usb_device_id *id),storage_disconnect(struct usb_interface *intf)这两个函数中的那个参数intf.
而这里130行这个宏-interface_to_usbdev,也会用得着的,顾名思义,就是从一个struct usb_interface转换成一个struct usb_device,我们说过了,有些函数需要的参数就是struct usb_device,而不是usb_interface,所以这种转换是经常会用到的,而这个宏,usb core的设计者们也为我们准备好了,除了感激,我们还能说什么呢?
如果你是急性子,那这时候你一定很想开始看storage_probe函数了,因为整个U盘的工作就是从这里开始的.不过,莎士比亚说过,磨刀不误砍柴功.不妨继续花点时间,至少把四大关键词中最后一个给弄明白了,
前面我们已经了解了device,configuration,interface,还剩最后一个endpoint.USB通信的最基本的形式就是通过endpoint,道上的兄弟管这个叫做端点,一个接口有一个或多个端点,而作为像U盘这样的存储设备吧,它至少有一个控制端点,两个bulk端点.这些端点都是干嘛的?说来话长,真是一言难尽哪.
usb协议里规定了,usb设备有四种通信方式,分别是控制传输,中断传输,批量传输,等时传输.其中,等时传输显然是用于音频和视频一类的设备,这类设备期望能够有个比较稳定的数据流,比如你在网上QQ视频聊天,肯定希望每分钟传输的图像/声音速率是比较稳定的,不能说这一分钟对方看到你在向她向你深情表白,可是下一分钟却看见画面停滞在那里,只能看到你那傻样一动不动,你说这不浪费感情嘛.所以,每一个有良知的男人都应该知道,usb-storage里边肯定不会用到等时传输.因为我们只管copy一个文件,管它第一秒和第二秒的传输有什么区别,只要几十秒内传完了就ok.
相比之下,等时传输是四种传输中最麻烦的,所以,U盘里边用不着,那您就偷着乐去吧.不过我要说,中断传输也用不着,对于U盘来说,的确用不着,虽然说usb mass storage的协议里边有一个叫做CBI的传输协议,CBI就是Control/Bulk/Interrupt,即控制/批量/中断,这三种传输都会用到,但这种传输协议并不适用于U盘,U盘使用的是一个叫做Bulk-Only的传输协议.使用这种协议的设备只有两种传输方式,一种是批量传输,另一种是控制传输,控制传输是任何一种usb设备都必须支持的,它专门用于传输一些控制信息.比如我想查询一下关于这个interface的一些信息,那么就用控制传输,而bulk传输,它就是U盘的主要工作了,读写数据,这种情况就得用bulk传输.具体的传输我们后面再讲.
好了,知道了传输方式,就可以来认识endpoint了.和endpoint齐名的有一个叫做管道,或者有文化的人管这个叫pipe.endpoint就是通信的发送或者接收点,你要发送数据,那你只要把数据发送到正确的端点那里就可以了.之所以U盘有两个bulk端点,是因为端点也是有方向的,一个叫做Bulk in,一个叫做Bulk out,从usb主机到设备称为out,从设备到主机称为in.而管道,实际上只是为了让我们能够找到端点,就相当于我们日常说的邮编地址,比如一个国家,为了通信,我们必须给各个地方取名,完了给各条大大小小的路取名,比如你要揭发你们那里的官员腐败,你要去上访,你从某偏僻的小县城出发,要到北京来上访,那你的这个端点(endpoint)就是北京,而你得知道你来北京的路线,那这个从你们县城到北京的路线就算一条管道.有人好奇的问了,管道应该有两端吧,一个端点是北京,那另一个端点呢?答案是,这条管道有些特殊,就比如上访,我们只需要知道一端是北京,而另一端是哪里无所谓,因为不管你在哪里你都得到北京来上访.没听说过你在山西你可以上访,你要在宁夏还不能上访了,没这事对吧.
严格来说,管道的另一端应该是usb主机,即前面说的那个host,usb协议里边也是这么说的,协议里边说pipes代表着一种能力,怎样一种能力呢,在主机和设备上的端点之间移动数据,听上去挺玄的.因为事实上,usb里边所有的数据传输都是有主机发起的.一切都是以主机为核心,各种设备紧紧围绕在主机周围.所以呢,usb core里边很多函数就是,为了让usb host能够正确的完成数据传输或者说传输调度,就得告诉host这么一个pipe,换言之,它得知道自己这次调度的数据是传送给谁或者从谁那里传输过来.不过有人又要问了,比如说我要从U盘里读一个文件,那我告诉usb host某个端点能有用吗?那个文件又不是存放在一个端点里边,它不该是存放在U盘里边吗?这个就只能在后面的代码里去知道了.实际上端点这东西是一个很虚的东西,它的身上充分体现了我国军事思想中的声东击西的想法,即数据本身并不是在端点里,但是看上去却觉得仿佛在端点里.这一切的谜团,让我们在storage_probe()函数里去慢慢解开吧.
对于整个usb-storage模块,usb_stor_init()是它的开始,然而,对于U盘驱动程序来说,它真正驱使U盘工作却是始于storage_probe().
两条平行线只要相交,就注定开始纠缠一生,不管中间是否短暂分离. usbcore为设备找到了适合她的驱动程序,或者为驱动程序找到了他所支持的设备,但这只是表明双方的第一印象还可以,但彼此是否真的适合对方还需要进一步的了解.毋庸置疑,了解对方的第一步是,知道她有哪些爱好,她的生日,她的星座,喜欢吃什么,而U盘driver则会调用函数storage_probe()去认识对方,她是个什么样的设备,她的生活习惯是?她的联系方式是?这里调用了四个函数get_device_info,get_protocol,get_transport,get_pipes.当然还有一些别人并不了解的冬冬你也会知道,比如她的三围,这里对应的就是usb_stor_Bulk_man_lun().
整个U盘驱动这部大戏,由storage_probe开始,由storage_disconnect结束.其中,storage_probe这个函数占了相当大的篇幅.我们一段一段来看.这两个函数都来自drivers/usb/storage/usb.c中:
926 /* Probe to see if we can drive a newly-connected USB device */
927 static int storage_probe(struct usb_interface *intf,
928 const struct usb_device_id *id)
929 {
930 struct us_data *us;
931 const int id_index = id - storage_usb_ids;
932 int result;
933
934 US_DEBUGP("USB Mass Storage device detected\n");
935
936 /* Allocate the us_data structure and initialize the mutexes */
937 us = (struct us_data *) kmalloc(sizeof(*us), GFP_KERNEL);
938 if (!us) {
939 printk(KERN_WARNING USB_STORAGE "Out of memory\n");
940 return -ENOMEM;
941 }
942 memset(us, 0, sizeof(struct us_data));
首先先贴出这么几行,两个参数不用多说了,struct usb_interface和struct usb_device_id的这两个指针都是前面介绍过的,来自usb core那一层,我们整个故事里用到的就是这么一个,不是说一会指向你,一会指向他,这两个指针的指向是定下来的.
930行,最重要的一个数据结构终于在这种神不知鬼不觉的地方惊艳亮相了.整个usb-storage模块里边自己定义的数据结构不多,但是us_data算一个.这个数据结构是跟随我们的代码一直走下去的,如影随形,几乎处处都可以看见她的身影.先把它的代码贴出来,来自drivers/usb/storage/usb.h:
105 /* we allocate one of these for every device that we remember */
106 struct us_data {
107 /* The device we're working with
108 * It's important to note:
109 * (o) you must hold dev_semaphore to change pusb_dev
110 */
111 struct semaphore dev_semaphore; /* protect pusb_dev */
112 struct usb_device *pusb_dev; /* this usb_device */
113 struct usb_interface *pusb_intf; /* this interface */
114 struct us_unusual_dev *unusual_dev; /* device-filter entry */
115 unsigned long flags; /* from filter initially */
116 unsigned int send_bulk_pipe; /* cached pipe values */
117 unsigned int recv_bulk_pipe;
118 unsigned int send_ctrl_pipe;
119 unsigned int recv_ctrl_pipe;
120 unsigned int recv_intr_pipe;
121
122 /* information about the device */
123 char vendor[USB_STOR_STRING_LEN];
124 char product[USB_STOR_STRING_LEN];
125 char serial[USB_STOR_STRING_LEN];
126 char *transport_name;
127 char *protocol_name;
128 u8 subclass;
129 u8 protocol;
130 u8 max_lun;
131
132 u8 ifnum; /* interface number */
133 u8 ep_bInterval; /* interrupt interval */
134
135 /* function pointers for this device */
136 trans_cmnd transport; /* transport function */
137 trans_reset transport_reset; /* transport device reset */
138 proto_cmnd proto_handler; /* protocol handler */
139
140 /* SCSI interfaces */
141 struct Scsi_Host *host; /* our dummy host data */
142 struct scsi_cmnd *srb; /* current srb */
143
144 /* thread information */
145 int pid; /* control thread */
146
147 /* control and bulk communications data */
148 struct urb *current_urb; /* USB requests */
149 struct usb_ctrlrequest *cr; /* control requests */
150 struct usb_sg_request current_sg; /* scatter-gather req. */
151 unsigned char *iobuf; /* I/O buffer */
152 dma_addr_t cr_dma; /* buffer DMA addresses */
153 dma_addr_t iobuf_dma;
154
155 /* mutual exclusion and synchronization structures */
156 struct semaphore sema; /* to sleep thread on */
157 struct completion notify; /* thread begin/end */
158 wait_queue_head_t dev_reset_wait; /* wait during reset */
159 wait_queue_head_t scsi_scan_wait; /* wait before scanning */
160 struct completion scsi_scan_done; /* scan thread end */
161
162 /* subdriver information */
163 void *extra; /* Any extra data */
164 extra_data_destructor extra_destructor;/* extra data destructor */
165 };
不难发现,Linux内核中每一个重要的数据结构都很复杂,这体现了内核代码编写者们的一种清高,仿佛不用点复杂的数据结构不足以体现他们是个腕儿.这可就苦了我们这些读代码的了,尤其是中国的学生,毕竟谭浩强的书里边翻多少遍也翻不出这么一变态的数据结构吧.所以,此刻,每一个有志青年都应该倍感责任重大,只有我们国家强大了,我们才能把谭浩强的书籍向全世界推广,从而告诉那些写内核代码的家伙,不要写那么复杂的冬冬,要按照谭浩强的书里的规矩来设计数据结构,来编写代码.这才是造福全人类的做法.不是吗?
先不说这些了,总之,这个令人头疼的数据结构是每一个device都有的,换句话说,我们会为每一个device申请一个us_data,因为这个结构里边的冬冬我们之后一直会用得着的.至于怎么用,每个成员什么意思,以后用上了再细说.930行,struct us_data *us,于是,日后我们会非常频繁的看到us的.另,us什么意思?尼采说:us者,usb storage是也.
937行,就是为us申请内存空间,而938行就是判断内存空间是否申请成功,成功的话us就不会为0,或者说为NULL,如果为NULL那么就是失败了,那么别再浪费表情了,整部戏就这么提前夭折了.在这里需要强调的是,整个内核代码中,像这种判断内存申请是否成功的语句是无处不在,每次有内存申请的语句,其后边一定会跟随一句判断申请成功与否的语句.写过代码的人都该知道,这样做是很有必要的,因为你没有申请到内存,那么继续下去就是没有意义的,除了可能让人见识计算机是如何崩溃之外,没有别的好处.而内存申请不管申请了多大,都有可能失败,写代码的人这样做无非是想告诫我们,我们的计算机并不总像人民币那般坚挺,她很脆弱.当你真正用计算机写代码的时候你就会发现计算机多么的脆弱和无力。
942行,给us初始化为全0.
934行这个US_DEBUGP,是一个宏,来自drivers/usb/storage/debug.h,接下来很多代码中我们也会看到这个宏,她无非就是打印一些调试信息.debug.h中有这么一段,
54 #ifdef CONFIG_USB_STORAGE_DEBUG
55 void usb_stor_show_command(struct scsi_cmnd *srb);
56 void usb_stor_show_sense( unsigned char key,
57 unsigned char asc, unsigned char ascq );
58 #define US_DEBUGP(x...) printk( KERN_DEBUG USB_STORAGE x )
59 #define US_DEBUGPX(x...) printk( x )
60 #define US_DEBUG(x) x
61 #else
62 #define US_DEBUGP(x...)
63 #define US_DEBUGPX(x...)
64 #define US_DEBUG(x)
65 #endif
66
67 #endif
这里一共定义了几个宏,US_DEBUGP,US_DEBUGPX,US_DEBUG,差别不大,只是形式上略有不同罢了.
USB驱动分析(三) | |
| |
来源: ChinaUnix博客 日期:2008.06.05 21:26 (共有条评论) 我要评论 | |
需要注意的是,这些调试信息得是我们打开了编译选项CONFIG_USB_STORAGE_DEBUG才有意义的,这里也看出来了,如果这个选项为0,那么这几个宏就什么也不干,因为它们被赋为空了.关于US_DEBUG系列的这几个宏,就讲这么多,之后再碰上,将直接过滤掉,不予多说. 下面我们分析下USB鼠标驱动,鼠标输入HID类型,其数据传输采用中断URB,鼠标端点类型为IN。好了,我们先看看这个驱动的模块加载部分。 static int __init usb_mouse_init(void) { int retval = usb_register(&usb_mouse_driver); if (retval == 0) printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" DRIVER_DESC "\n"); return retval; } 模块加载部分仍然是调用usb_register注册USB驱动,我们跟踪看看被注册的usb_mouse_driver static struct usb_driver usb_mouse_driver = { .name = "usbmouse", //驱动名 .probe = usb_mouse_probe, //探测 .disconnect = usb_mouse_disconnect, .id_table = usb_mouse_id_table, //支持项 }; 关于设备支持项我们前面已经讨论过了 static struct usb_device_id usb_mouse_id_table [] = { {USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, USB_INTERFACE_PROTOCOL_MOUSE) }, { } }; 再细细看看USB_INTERFACE_INFO宏的定义 #define USB_INTERFACE_INFO(cl, sc, pr) \ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, \ .bInterfaceClass = (cl), \ .bInterfaceSubClass = (sc), \ .bInterfaceProtocol = (pr) 根据宏,我们知道,我们设置的支持项包括接口类,接口子类,接口协议三个匹配项。 好了,我们主要看看usb_driver中定义的probe函数 static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(intf); //由接口获取usb_device struct usb_host_interface *interface; //设置 struct usb_endpoint_descriptor *endpoint; //端点描述符 struct usb_mouse *mouse //本驱动私有结构体 struct input_dev *input_dev; //输入结构体 int pipe, maxp; int error = -ENOMEM; interface = intf->cur_altsetting; //获取设置 if (interface->desc.bNumEndpoints != 1) //鼠标端点只有1个 return -ENODEV; endpoint = &interface->endpoint[0].desc; //获得端点描述符 if (!usb_endpoint_is_int_in(endpoint)) //检查该端点是否是中断输入端点 return -ENODEV; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); //建立中断输入端点 //返回端点能传输的最大的数据包,鼠标的返回的最大数据包为4个字节 maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL); //分配mouse结构体 input_dev = input_allocate_device(); //分配input设备空间 if (!mouse || !input_dev) goto fail1; mouse->data = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &mouse->data_dma); //分配缓冲区 if (!mouse->data) goto fail1; mouse->irq = usb_alloc_urb(0, GFP_KERNEL); //分配urb if (!mouse->irq) goto fail2; mouse->usbdev = dev; //填充mouse的usb_device结构体 mouse->dev = input_dev; //填充mouse的 input结构体 if (dev->manufacturer) //拷贝厂商ID strlcpy(mouse->name, dev->manufacturer, sizeof(mouse->name)); if (dev->product) { //拷贝产品ID if (dev->manufacturer) strlcat(mouse->name, " ", sizeof(mouse->name)); strlcat(mouse->name, dev->product, sizeof(mouse->name)); } if (!strlen(mouse->name)) //拷贝产品ID snprintf(mouse->name, sizeof(mouse->name), "USB HIDBP Mouse %04x:%04x", le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct)); usb_make_path(dev, mouse->phys, sizeof(mouse->phys)); strlcat(mouse->phys, "/input0", sizeof(mouse->phys)); input_dev->name = mouse->name; //将鼠标名赋给内嵌input结构体 input_dev->phys = mouse->phys; //将鼠标设备节点名赋给内嵌input结构体 usb_to_input_id(dev, &input_dev->id); //将usb_driver的支持项拷贝给input input_dev->dev.parent = &intf->dev; //evbit表明支持按键事件(EV_KEY)和相对坐标事件(EV_REL) input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); //keybit表明按键值包括左键、右键和中键 input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE); //relbit表明相对坐标事件值包括X坐标和Y坐标 input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); //keybit表明除了左键、右键和中键,还支持其他按键 input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA); //relbit表明除了X坐标和Y坐标,还支持中键滚轮的滚动值 input_dev->relbit[0] |= BIT_MASK(REL_WHEEL); input_set_drvdata(input_dev, mouse); //将mouse设置为input的私有数据 input_dev->open = usb_mouse_open; //input设备的open input_dev->close = usb_mouse_close; usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data, (maxp > 8 ? 8 : maxp), usb_mouse_irq, mouse, endpoint->bInterval); //填充urb mouse->irq->transfer_dma = mouse->data_dma; mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; //使用transfer_dma error = input_register_device(mouse->dev); //注册input设备 if (error) goto fail3; usb_set_intfdata(intf, mouse); return 0; fail3: usb_free_urb(mouse->irq); fail2: usb_buffer_free(dev, 8, mouse->data, mouse->data_dma); fail1: input_free_device(input_dev); kfree(mouse); return error; } 其实上面这个probe主要是初始化usb设备和input设备,终极目标是为了完成urb的提交和input设备的注册。由于注册为input设备类型,那么当用户层open打开设备时候,最终会调用input中的open实现打开,我们看看input中open的实现 static int usb_mouse_open(struct input_dev *dev) { struct usb_mouse *mouse = input_get_drvdata(dev); //获取私有数据 mouse->irq->dev = mouse->usbdev; //获取urb指针 if (usb_submit_urb(mouse->irq, GFP_KERNEL)) //提交urb return -EIO; return 0; } 好了,当用户层open打开这个USB鼠标后,我们就已经将urb提交给了USB核心,那么根据USB数据处理流程知道,当处理完毕后,USB核心会通知USB设备驱动程序,这里我们是响应中断服务程序,这就相当于该URB的回调函数。我们在提交urb时候定义了中断服务程序usb_mouse_irq,我们跟踪看看 static void usb_mouse_irq(struct urb *urb) { struct usb_mouse *mouse = urb->context; signed char *data = mouse->data; struct input_dev *dev = mouse->dev; int status; switch (urb->status) { case 0: //成功 break; case -ECONNRESET: //未连接 case -ENOENT: case -ESHUTDOWN: return; default: goto resubmit; //数据处理没成功,重新提交urb } input_report_key(dev, BTN_LEFT, data[0] & 0x01); //鼠标左键 input_report_key(dev, BTN_RIGHT, data[0] & 0x02); //鼠标右键 input_report_key(dev, BTN_MIDDLE, data[0] & 0x04); //鼠标中键 input_report_key(dev, BTN_SIDE, data[0] & 0x08); //鼠标SIDE input_report_key(dev, BTN_EXTRA, data[0] & 0x10); //鼠标EXTRA input_report_rel(dev, REL_X, data[1]); //鼠标的水平位移 input_report_rel(dev, REL_Y, data[2]); //鼠标的垂直位移 input_report_rel(dev, REL_WHEEL, data[3]); //鼠标的滚轮滚动值 input_sync(dev); resubmit: status = usb_submit_urb (urb, GFP_ATOMIC); //再次提交urb,等待下次响应 if (status) err ("can't resubmit intr, %s-%s/input0, status %d", mouse->usbdev->bus->bus_name, mouse->usbdev->devpath, status); } 根据上面的中断服务程序,我们应该知道,系统是周期性地获取鼠标的事件信息,因此在URB回调函数的末尾再次提交URB请求块,这样又会调用新的回调函数,周而复始。在回调函数中提交URB只能是GFP_ATOMIC优先级,因为URB回调函数运行于中断上下文中禁止导致睡眠的行为。而在提交URB过程中可能会需要申请内存、保持信号量,这些操作或许会导致USB内核睡眠。 最后我们再看看这个驱动的私有数据mouse的定义 struct usb_mouse { char name[128]; //名字 char phys[64]; //设备节点 struct usb_device *usbdev; //内嵌usb_device设备 struct input_dev *dev; //内嵌input_dev设备 struct urb *irq; //urb结构体 signed char *data; //transfer_buffer缓冲区 dma_addr_t data_dma; // transfer _dma缓冲区 }; 在上面这个结构体中,每一个成员的作用都应该很清楚了,尤其最后两个的使用区别和作用,前面也已经说过。 如果最终需要测试这个USB鼠标驱动,需要在内核中配置USB支持、对HID接口的支持、对OHCI HCD驱动的支持。另外,将驱动移植到开发板之后,由于采用的是input设备模型,所以还需要开发板带LCD屏才能测试。
3.USB键盘驱动usbkbd.c 跟USB鼠标类型,USB键盘也属于HID类型,代码在/dirver/hid/usbhid/usbkbd.c下。USB键盘除了提交中断URB外,还需要提交控制URB。不多话,我们看代码 static int __init usb_kbd_init(void) { int result = usb_register(&usb_kbd_driver); //注册USB驱动 if (result == 0) printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" DRIVER_DESC "\n"); return result; } static struct usb_driver usb_kbd_driver = { .name = "usbkbd", .probe = usb_kbd_probe, .disconnect = usb_kbd_disconnect, .id_table = usb_kbd_id_table, }; 大家都懂,下面跟踪usb_driver中的probe static int usb_kbd_probe(struct usb_interface *iface, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(iface); //由接口获得设备 struct usb_host_interface *interface; //设置 struct usb_endpoint_descriptor *endpoint; //端点描述符 struct usb_kbd *kbd; //私有数据 struct input_dev *input_dev; //input设备 int i, pipe, maxp; int error = -ENOMEM; interface = iface->cur_altsetting; //获得设置 if (interface->desc.bNumEndpoints != 1) //只有一个端点 return -ENODEV; endpoint = &interface->endpoint[0].desc; //获取端点描述符 if (!usb_endpoint_is_int_in(endpoint)) //端点必须是中断输入端点 return -ENODEV; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); //建立中断输入端点 maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); //获取返回字节大小 kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL); //分配私有数据空间 input_dev = input_allocate_device(); //分配input设备空间 if (!kbd || !input_dev) goto fail1; if (usb_kbd_alloc_mem(dev, kbd)) //分配urb空间和其他缓冲空间 goto fail2; kbd->usbdev = dev; //给内嵌结构体赋值 kbd->dev = input_dev; //给内嵌结构体赋值 if (dev->manufacturer) strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name)); if (dev->product) { if (dev->manufacturer) strlcat(kbd->name, " ", sizeof(kbd->name)); strlcat(kbd->name, dev->product, sizeof(kbd->name)); } if (!strlen(kbd->name)) snprintf(kbd->name, sizeof(kbd->name), "USB HIDBP Keyboard %04x:%04x", le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct)); usb_make_path(dev, kbd->phys, sizeof(kbd->phys)); strlcpy(kbd->phys, "/input0", sizeof(kbd->phys)); input_dev->name = kbd->name; input_dev->phys = kbd->phys; usb_to_input_id(dev, &input_dev->id); //复制usb_driver的支持项给input的支持项 input_dev->dev.parent = &iface->dev; input_set_drvdata(input_dev, kbd); //将kbd设置为input的私有数据 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) | BIT_MASK(EV_REP); input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) | BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_COMPOSE) | BIT_MASK(LED_KANA); for (i = 0; i < 255; i++) set_bit(usb_kbd_keycode[i], input_dev->keybit); clear_bit(0, input_dev->keybit); input_dev->event = usb_kbd_event; //定义event函数 input_dev->open = usb_kbd_open; input_dev->close = usb_kbd_close; usb_fill_int_urb(kbd->irq, dev, pipe,kbd->new, (maxp > 8 ? 8 : maxp), usb_kbd_irq, kbd, endpoint->bInterval); //填充中断urb kbd->irq->transfer_dma = kbd->new_dma; kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; //dma方式传输 kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE; kbd->cr->bRequest = 0x09; //设置控制请求的格式 kbd->cr->wValue = cpu_to_le16(0x200); kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber); kbd->cr->wLength = cpu_to_le16(1); usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0), (void *) kbd->cr, kbd->leds, 1, usb_kbd_led, kbd); //填充控制urb kbd->led->setup_dma = kbd->cr_dma; kbd->led->transfer_dma = kbd->leds_dma; kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); //设置dma和setup_dma有效 error = input_register_device(kbd->dev); //注册input设备 if (error) goto fail2; usb_set_intfdata(iface, kbd); return 0; fail2: usb_kbd_free_mem(dev, kbd); fail1: input_free_device(input_dev); kfree(kbd); return error; } 在上面的probe中,我们主要是初始化一些结构体,然后提交中断urb和控制urb,并注册input设备。其中有几个地方需要细看下,其一,usb_kbd_alloc_mem的实现。其二,设置控制请求的格式。 先来看看usb_kbd_alloc_mem的实现 static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd) { if (!(kbd->irq = usb_alloc_urb(0, GFP_KERNEL))) //分配中断urb return -1; if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL))) //分配控制urb return -1; if (!(kbd->new = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &kbd->new_dma))) return -1; if (!(kbd->cr = usb_buffer_alloc(dev, sizeof(struct usb_ctrlrequest), GFP_ATOMIC, &kbd->cr_dma))) //分配控制urb使用的控制请求描述符 return -1; if (!(kbd->leds = usb_buffer_alloc(dev, 1, GFP_ATOMIC, &kbd->leds_dma))) return -1; //分配中断urb使用的缓冲区 return 0; } 这里我们需要明白中断urb和控制urb需要分配不同的urb结构体,同时在提交urb之前,需要填充的内容也不同,中断urb填充的是缓冲区和中断处理函数,控制urb填充的是控制请求描述符合回调函数。 好了,接着我们解决第二个问题,设置控制请求的格式。cr是struct usb_ctrlrequest结构的指针,USB协议中规定一个控制请求的格式为一个8个字节的数据包,其定义如下 struct usb_ctrlrequest { __u8 bRequestType; //设定传输方向、请求类型等 __u8 bRequest; //指定哪个请求,可以是规定的标准值也可以是厂家定义的值 __le16 wValue; //即将写到寄存器的数据 __le16 wIndex; //接口数量,也就是寄存器的偏移地址 __le16 wLength; //数据传输阶段传输多少个字节 } __attribute__ ((packed)); USB协议中规定,所有的USB设备都会响应主机的一些请求,这些请求来自USB主机控制器,主机控制器通过设备的默认控制管道发出这些请求。默认的管道为0号端口对应的那个管道。 同样这个input设备首先由用户层调用open函数,所以先看看input中定义的open static int usb_kbd_open(struct input_dev *dev) { struct usb_kbd *kbd = input_get_drvdata(dev); kbd->irq->dev = kbd->usbdev; if (usb_submit_urb(kbd->irq, GFP_KERNEL)) //提交中断urb return -EIO; return 0; } 因为这个驱动里面有一个中断urb一个控制urb,我们先看中断urb的处理流程。中断urb在input的open中被提交后,当USB核心处理完毕,会通知这个USB设备驱动,然后执行回调函数,也就是中断处理函数usb_kbd_irq static void usb_kbd_irq(struct urb *urb) { struct usb_kbd *kbd = urb->context; int i; switch (urb->status) { case 0: //成功 break; case -ECONNRESET: //未连接 case -ENOENT: case -ESHUTDOWN: return; default: goto resubmit; //出错就再次提交中断urb } for (i = 0; i < 8; i++) //向input子系统报告 input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1); for (i = 2; i < 8; i++) { if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) { if (usb_kbd_keycode[kbd->old[i]]) input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0); else dev_info(&urb->dev->dev, "Unknown key (scancode %#x) released.\n", kbd->old[i]); } if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) { if (usb_kbd_keycode[kbd->new[i]]) input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1); else dev_info(&urb->dev->dev, "Unknown key (scancode %#x) released.\n", kbd->new[i]); } } input_sync(kbd->dev); memcpy(kbd->old, kbd->new, 8); resubmit: i = usb_submit_urb (urb, GFP_ATOMIC); //再次提交中断urb if (i) err_hid ("can't resubmit intr, %s-%s/input0, status %d", kbd->usbdev->bus->bus_name, kbd->usbdev->devpath, i); } 这个就是中断urb的处理流程,跟前面讲的的USB鼠标中断处理流程类似。好了,我们再来看看剩下的控制urb处理流程吧。 我们有个疑问,我们知道在probe中,我们填充了中断urb和控制urb,但是在input的open中,我们只提交了中断urb,那么控制urb什么时候提交呢? 我们知道对于input子系统,如果有事件被响应,我们会调用事件处理层的event函数,而该函数最终调用的是input下的event。所以,对于input设备,我们在USB键盘驱动中只设置了支持LED选项,也就是ledbit项,这是怎么回事呢?刚才我们分析的那个中断urb其实跟这个input基本没啥关系,中断urb并不是像讲键盘input实现的那样属于input下的中断。我们在USB键盘驱动中的input子系统中只设计了LED选项,那么当input子系统有按键选项的时候必然会使得内核调用调用事件处理层的event函数,最终调用input下的event。好了,那我们来看看input下的event干了些什么。 static int usb_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct usb_kbd *kbd = input_get_drvdata(dev); if (type != EV_LED) //不是LED事件就返回 return -1; //将当前的LED值保存在kbd->newleds中 kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) | (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) |(!!test_bit(LED_NUML, dev->led)); if (kbd->led->status == -EINPROGRESS) return 0; if (*(kbd->leds) == kbd->newleds) return 0; *(kbd->leds) = kbd->newleds; kbd->led->dev = kbd->usbdev; if (usb_submit_urb(kbd->led, GFP_ATOMIC)) //提交控制urb err_hid("usb_submit_urb(leds) failed"); return 0; } 当在input的event里提交了控制urb后,经过URB处理流程,最后返回给USB设备驱动的回调函数,也就是在probe中定义的usb_kbd_led static void usb_kbd_led(struct urb *urb) { struct usb_kbd *kbd = urb->context; if (urb->status) //提交失败显示 dev_warn(&urb->dev->dev, "led urb status %d received\n", urb->status); //比较kbd->leds和kbd->newleds,如果发生变化,则更新kbd->leds if (*(kbd->leds) == kbd->newleds) return; *(kbd->leds) = kbd->newleds; kbd->led->dev = kbd->usbdev; if (usb_submit_urb(kbd->led, GFP_ATOMIC)) //再次提交控制urb err_hid("usb_submit_urb(leds) failed"); } 总结下,我们的控制urb走的是先由input的event提交,触发后由控制urb的回调函数再次提交。好了,通过USB鼠标,我们已经知道了控制urb和中断urb的设计和处理流程。 USB Mass Storage是一类USB存储设备,这些设备包括USB磁盘、USB硬盘、USB磁带机、USB光驱、U盘、记忆棒、智能卡和一些USB摄像头等,这类设备由USB协议支持。 首先我想去看看/driver/usb/storage/Makefile EXTRA_CFLAGS := -Idrivers/scsi obj-$(CONFIG_USB_STORAGE) += usb-storage.o usb-storage-obj-$(CONFIG_USB_STORAGE_DEBUG) += debug.o usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \ initializers.o sierra_ms.o option_ms.o $(usb-storage-obj-y) 这是Makefile中前几行代码,在此我进行一个说明。第一行,-I选项表示需要编译的目录。当本Makefile文件被编译器读取时,会先判断/driver/scsi目录下的文件是否已经被编译,如果没有被编译,则先编译该目录下的文件后,再转到该Makefile文件中。第二行就是USB Mass Storage选项,是总指挥。第三行是调试部分。第四行说明了这个文件夹也就是usb-storage模块必须包含的文件,这些文件将是主要分析的对象,目前我们分析USB驱动,所以重点去分析这些文件中的usb.c 同样,我们先看看usb.c中的模块加载部分 static int __init usb_stor_init(void) { int retval; printk(KERN_INFO "Initializing USB Mass Storage driver...\n"); retval = usb_register(&usb_storage_driver); //注册usb_driver驱动 if (retval == 0) { printk(KERN_INFO "USB Mass Storage support registered.\n"); usb_usual_set_present(USB_US_TYPE_STOR); } return retval; } static struct usb_driver usb_storage_driver = { .name = "usb-storage", .probe = storage_probe, .disconnect = usb_stor_disconnect, .suspend = usb_stor_suspend, .resume = usb_stor_resume, .reset_resume = usb_stor_reset_resume, .pre_reset = usb_stor_pre_reset, .post_reset = usb_stor_post_reset, .id_table = usb_storage_usb_ids, .soft_unbind = 1, }; 下面重点我们来看看这个probe函数 static int storage_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct us_data *us; int result; //检测匹配 if (usb_usual_check_type(id, USB_US_TYPE_STOR) ||usb_usual_ignore_device(intf)) return -ENXIO; //探测的第一部分 result = usb_stor_probe1(&us, intf, id,(id - usb_storage_usb_ids) + us_unusual_dev_list); if (result) return result; result = usb_stor_probe2(us); //探测的第二部分 return result; } 我们发现U盘驱动的探测分为两个部分,我们先来看看第一个部分usb_stor_probe1 int usb_stor_probe1(struct us_data **pus,struct usb_interface *intf, const struct usb_device_id *id,struct us_unusual_dev *unusual_dev) { struct Scsi_Host *host; struct us_data *us; int result; US_DEBUGP("USB Mass Storage device detected\n"); host = scsi_host_alloc(&usb_stor_host_template, sizeof(*us)); //分配Scsi_Host结构体 if (!host) { printk(KERN_WARNING USB_STORAGE "Unable to allocate the scsi host\n"); return -ENOMEM; } host->max_cmd_len = 16; *pus = us = host_to_us(host); //从host结构体中提取出us_data结构体 memset(us, 0, sizeof(struct us_data)); mutex_init(&(us->dev_mutex)); init_completion(&us->cmnd_ready); //初始化完成量 init_completion(&(us->notify)); init_waitqueue_head(&us->delay_wait); //初始化等待队列头 init_completion(&us->scanning_done); //初始化完成量 result = associate_dev(us, intf); //将us_data与USB设备相关联 if (result) goto BadDevice; result = get_device_info(us, id, unusual_dev); //获取设备信息 if (result) goto BadDevice; get_transport(us); //获取传输方式 get_protocol(us); //获取传输协议 return 0; BadDevice: US_DEBUGP("storage_probe() failed\n"); release_everything(us); return result; } 我们再看看U盘驱动的探测的第二部分usb_stor_probe2 int usb_stor_probe2(struct us_data *us) { struct task_struct *th; int result; if (!us->transport || !us->proto_handler) { result = -ENXIO; goto BadDevice; } US_DEBUGP("Transport: %s\n", us->transport_name); US_DEBUGP("Protocol: %s\n", us->protocol_name); if (us->fflags & US_FL_SINGLE_LUN) us->max_lun = 0; result = get_pipes(us); //获得管道 if (result) goto BadDevice; result = usb_stor_acquire_resources(us); //获取资源 if (result) goto BadDevice; result = scsi_add_host(us_to_host(us), &us->pusb_intf->dev); //添加scsi if (result) { printk(KERN_WARNING USB_STORAGE "Unable to add the scsi host\n"); goto BadDevice; } th = kthread_create(usb_stor_scan_thread, us, "usb-stor-scan"); //创建线程 if (IS_ERR(th)) { printk(KERN_WARNING USB_STORAGE "Unable to start the device-scanning thread\n"); complete(&us->scanning_done); quiesce_and_remove_host(us); result = PTR_ERR(th); goto BadDevice; } wake_up_process(th); //唤醒usb_stor_scan_thread线程 return 0; BadDevice: US_DEBUGP("storage_probe() failed\n"); release_everything(us); return result; } 好了,我们已经把probe大致阅读了一下,主要通过assocaite_dev(),get_device_info(),get_transport(),get_protocol(),get_pipes()五个函数来为us结构体赋值,然后调用usb_stor_acquire_resources()来得到设备需要的动态资源。最后创建扫描线程usb_stor_scan_thread,让用户能通过cat /proc/scsi/scsi看到U盘设备。现在我们一个个分析下这里提到了每个函数。 首先我们看看来为us结构体赋值的设备关联函数associate_dev的实现 static int associate_dev(struct us_data *us, struct usb_interface *intf) { US_DEBUGP("-- %s\n", __func__); us->pusb_dev = interface_to_usbdev(intf); //由接口获取设备 us->pusb_intf = intf; //接口赋值 us->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; //接口数量 US_DEBUGP("Vendor: 0x%04x, Product: 0x%04x, Revision: 0x%04x\n", le16_to_cpu(us->pusb_dev->descriptor.idVendor), le16_to_cpu(us->pusb_dev->descriptor.idProduct), le16_to_cpu(us->pusb_dev->descriptor.bcdDevice)); US_DEBUGP("Interface Subclass: 0x%02x, Protocol: 0x%02x\n", intf->cur_altsetting->desc.bInterfaceSubClass, intf->cur_altsetting->desc.bInterfaceProtocol); usb_set_intfdata(intf, us); //把us设置为接口的私有数据 //分配控制urb的控制字符空间 us->cr = usb_buffer_alloc(us->pusb_dev, sizeof(*us->cr),GFP_KERNEL, &us->cr_dma); if (!us->cr) { US_DEBUGP("usb_ctrlrequest allocation failed\n"); return -ENOMEM; } us->iobuf = usb_buffer_alloc(us->pusb_dev, US_IOBUF_SIZE, GFP_KERNEL, &us->iobuf_dma); //分配urb的缓冲区 if (!us->iobuf) { US_DEBUGP("I/O buffer allocation failed\n"); return -ENOMEM; } return 0; } 然后我们继续看获得设备信息函数get_device_info的实现 static int get_device_info(struct us_data *us, const struct usb_device_id *id, struct us_unusual_dev *unusual_dev) { struct usb_device *dev = us->pusb_dev; struct usb_interface_descriptor *idesc =&us->pusb_intf->cur_altsetting->desc; us->unusual_dev = unusual_dev; //不常用的设备 //找到USB设备支持的子类和协议 us->subclass = (unusual_dev->useProtocol == US_SC_DEVICE) ? idesc->bInterfaceSubClass :unusual_dev->useProtocol; us->protocol = (unusual_dev->useTransport == US_PR_DEVICE) ? idesc->bInterfaceProtocol :unusual_dev->useTransport; us->fflags = USB_US_ORIG_FLAGS(id->driver_info); adjust_quirks(us); if (us->fflags & US_FL_IGNORE_DEVICE) {//USB设备不能被系统识别则退出 printk(KERN_INFO USB_STORAGE "device ignored\n"); return -ENODEV; } if (dev->speed != USB_SPEED_HIGH) //USB设备不支持高速则改为低速 us->fflags &= ~US_FL_GO_SLOW; //根据生产厂商和产品号来设置协议、传输类型等参数 if (id->idVendor || id->idProduct) { static const char *msgs[3] = { "an unneeded SubClass entry", "an unneeded Protocol entry", "unneeded SubClass and Protocol entries"}; struct usb_device_descriptor *ddesc = &dev->descriptor; int msg = -1; if (unusual_dev->useProtocol != US_SC_DEVICE && us->subclass == idesc->bInterfaceSubClass) msg += 1; if (unusual_dev->useTransport != US_PR_DEVICE && us->protocol == idesc->bInterfaceProtocol) msg += 2; if (msg >= 0 && !(us->fflags & US_FL_NEED_OVERRIDE)) printk(KERN_NOTICE USB_STORAGE "This device " "(%04x,%04x,%04x S %02x P %02x)" " has %s in unusual_devs.h (kernel" " %s)\n" " Please send a copy of this message to " "<linux-usb@vger.kernel.org> and " "<usb-storage@lists.one-eyed-alien.net>\n", le16_to_cpu(ddesc->idVendor), le16_to_cpu(ddesc->idProduct), le16_to_cpu(ddesc->bcdDevice), idesc->bInterfaceSubClass, idesc->bInterfaceProtocol, msgs[msg], utsname()->release); } return 0; } 我们继续看得到传输协议函数get_transport,这个函数主要获得USB设备支持的通信协议,并设置USB驱动的传输类型。对于U盘,USB协议规定它属于Bulk-only的传输方式,也就是它的us->protocot为US_PR_BULK static void get_transport(struct us_data *us) { switch (us->protocol) { case US_PR_CB: us->transport_name = "Control/Bulk"; us->transport = usb_stor_CB_transport; us->transport_reset = usb_stor_CB_reset; us->max_lun = 7; break; case US_PR_CBI: us->transport_name = "Control/Bulk/Interrupt"; us->transport = usb_stor_CB_transport; us->transport_reset = usb_stor_CB_reset; us->max_lun = 7; break; case US_PR_BULK: us->transport_name = "Bulk"; us->transport = usb_stor_Bulk_transport; //传输函数 us->transport_reset = usb_stor_Bulk_reset; break; } } 好了,接着我们看获得协议信息的get_protocol函数,该函数根据不同的协议,用来设置协议的传输函数。对于U盘,USB协议规定us->subclass为US_SC_SCSI static void get_protocol(struct us_data *us) { switch (us->subclass) { case US_SC_RBC: us->protocol_name = "Reduced Block Commands (RBC)"; us->proto_handler = usb_stor_transparent_scsi_command; break; case US_SC_8020: us->protocol_name = "8020i"; us->proto_handler = usb_stor_pad12_command; us->max_lun = 0; break; case US_SC_QIC: us->protocol_name = "QIC-157"; us->proto_handler = usb_stor_pad12_command; us->max_lun = 0; break; case US_SC_8070: us->protocol_name = "8070i"; us->proto_handler = usb_stor_pad12_command; us->max_lun = 0; break; case US_SC_SCSI: us->protocol_name = "Transparent SCSI"; us->proto_handler = usb_stor_transparent_scsi_command; //协议处理函数 break; case US_SC_UFI: us->protocol_name = "Uniform Floppy Interface (UFI)"; us->proto_handler = usb_stor_ufi_command; break; } } 最后一个初始化us的函数是获得管道信息的get_pipes函数。 static int get_pipes(struct us_data *us) { struct usb_host_interface *altsetting =us->pusb_intf->cur_altsetting; //获取设置 int i; struct usb_endpoint_descriptor *ep; //定义端点描述符 struct usb_endpoint_descriptor *ep_in = NULL; //定义输入端点描述符 struct usb_endpoint_descriptor *ep_out = NULL; //定义输出端点描述符 struct usb_endpoint_descriptor *ep_int = NULL; //定义中断端点描述符 for (i = 0; i < altsetting->desc.bNumEndpoints; i++) { ep = &altsetting->endpoint[i].desc; //获取端点描述符 if (usb_endpoint_xfer_bulk(ep)) { //是否是批量传输端点 if (usb_endpoint_dir_in(ep)) { //是否是输入端点 if (!ep_in) ep_in = ep; //设置为批量传输输入端点 } else { if (!ep_out) ep_out = ep; //设置为批量传输输出端点 } } else if (usb_endpoint_is_int_in(ep)) { //是否是中断端点 if (!ep_int) ep_int = ep; //设置为中断端点 } } if (!ep_in || !ep_out || (us->protocol == US_PR_CBI && !ep_int)) { US_DEBUGP("Endpoint sanity check failed! Rejecting dev.\n"); return -EIO; } us->send_ctrl_pipe = usb_sndctrlpipe(us->pusb_dev, 0); //建立输出控制端点 us->recv_ctrl_pipe = usb_rcvctrlpipe(us->pusb_dev, 0); //建立输入控制端点 //建立输出批量传输端点 us->send_bulk_pipe = usb_sndbulkpipe(us->pusb_dev, usb_endpoint_num(ep_out)); //建立输入批量传输端点 us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev, usb_endpoint_num(ep_in)); if (ep_int) { //建立中断传输端点 us->recv_intr_pipe = usb_rcvintpipe(us->pusb_dev,usb_endpoint_num(ep_int)); us->ep_bInterval = ep_int->bInterval; //设置中断间隔时间 } return 0; } 分析完上面get_pipes的代码,需要补充说明的是,在我们的U盘中只有输入批量传输和输出批量传输两个端点,不存在控制端点,如果出现控制端点,那么设备支持CBI协议,即Control/Bulk/Interrupt协议,另外U盘也没有中断端点。 分析完上面五个对cr初始化的函数后,我们接着需要看usb_stor_acquire_resources了,这个函数主要功能是初始化设备,并创建数据传输的控制线程。 static int usb_stor_acquire_resources(struct us_data *us) { int p; struct task_struct *th; us->current_urb = usb_alloc_urb(0, GFP_KERNEL); //申请urb if (!us->current_urb) { US_DEBUGP("URB allocation failed\n"); return -ENOMEM; } if (us->unusual_dev->initFunction) { //特殊设备的初始化函数 p = us->unusual_dev->initFunction(us); if (p) return p; } th = kthread_run(usb_stor_control_thread, us, "usb-storage"); //创建并执行控制线程 if (IS_ERR(th)) { printk(KERN_WARNING USB_STORAGE "Unable to start control thread\n"); return PTR_ERR(th); } us->ctl_thread = th; //保存线程号 return 0; } 在上面这个usb_stor_acquire_resources函数中,我们创建并执行了usb_stor_control_thread这个内核线程,这个控制线程用来完成数据的接收和发送,它会一直运行,直到驱动程序退出。 我们来看看这个控制线程。 static int usb_stor_control_thread(void * __us) { struct us_data *us = (struct us_data *)__us; struct Scsi_Host *host = us_to_host(us); for(;;) { US_DEBUGP("*** thread sleeping.\n"); if (wait_for_completion_interruptible(&us->cmnd_ready)) //等待用户层SISI命令唤醒 break; US_DEBUGP("*** thread awakened.\n"); mutex_lock(&(us->dev_mutex)); scsi_lock(host); if (us->srb == NULL) { //为循环中超时后的退出 scsi_unlock(host); mutex_unlock(&us->dev_mutex); US_DEBUGP("-- exiting\n"); break; } if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { //直接跳到超时判断去 us->srb->result = DID_ABORT << 16; goto SkipForAbort; } scsi_unlock(host); if (us->srb->sc_data_direction == DMA_BIDIRECTIONAL) { //方向 US_DEBUGP("UNKNOWN data direction\n"); us->srb->result = DID_ERROR << 16; } else if (us->srb->device->id && !(us->fflags & US_FL_SCM_MULT_TARG)) { US_DEBUGP("Bad target number (%d:%d)\n", us->srb->device->id, us->srb->device->lun); us->srb->result = DID_BAD_TARGET << 16; } else if (us->srb->device->lun > us->max_lun) {US_DEBUGP("Bad LUN (%d:%d)\n", us->srb->device->id, us->srb->device->lun); us->srb->result = DID_BAD_TARGET << 16; } else if ((us->srb->cmnd[0] == INQUIRY) && (us->fflags & US_FL_FIX_INQUIRY)) { //如果SCSI是请求命令的处理 unsigned char data_ptr[36] = { 0x00, 0x80, 0x02, 0x02, 0x1F, 0x00, 0x00, 0x00}; US_DEBUGP("Faking INQUIRY command\n"); fill_inquiry_response(us, data_ptr, 36); //填充一个请求命令 us->srb->result = SAM_STAT_GOOD; } else { US_DEBUG(usb_stor_show_command(us->srb)); us->proto_handler(us->srb, us); //数据传输 } scsi_lock(host); if (us->srb->result != DID_ABORT << 16) { US_DEBUGP("scsi cmd done, result=0x%x\n", us->srb->result); us->srb->scsi_done(us->srb); } else { SkipForAbort: US_DEBUGP("scsi command aborted\n"); } if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { //超时处理 complete(&(us->notify)); clear_bit(US_FLIDX_ABORTING, &us->dflags); clear_bit(US_FLIDX_TIMED_OUT, &us->dflags); } us->srb = NULL; scsi_unlock(host); mutex_unlock(&us->dev_mutex); } for (;;) { set_current_state(TASK_INTERRUPTIBLE); if (kthread_should_stop()) break; schedule(); } __set_current_state(TASK_RUNNING); return 0; } 对于上面这个控制线程,首先该函数执行了一个for(;;),这是一个死循环,也就是这个函数作为一些线程用可以不停息的运行。同时,根据刚开始wait_for_completion_interruptible代码,我们知道开始就进入睡眠状态了,只有唤醒us->cmnd_ready这个控制线程才能继续执行下去,那我们要知道什么时候释放这把锁来唤醒下面的程序呢? 其实有两个地方,一个是模块卸载的时候,另一个就是有SCSI命令发过来。每一次应用层发过来SCSI命令了,比如你去读写/dev/sda,最终SCSI核心层就会调用该与该主机对应的queuecommand函数,这个函数是scsi_host_template结构体成员,在probe中scsi_host_alloc时候注册的。下面是queuecommand函数的实现。 static int queuecommand(struct scsi_cmnd *srb, void (*done)(struct scsi_cmnd *)) { struct us_data *us = host_to_us(srb->device->host); US_DEBUGP("%s called\n", __func__); if (us->srb != NULL) { printk(KERN_ERR USB_STORAGE "Error in %s: us->srb = %p\n", __func__, us->srb); return SCSI_MLQUEUE_HOST_BUSY; } if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) { US_DEBUGP("Fail command during disconnect\n"); srb->result = DID_NO_CONNECT << 16; done(srb); return 0; } srb->scsi_done = done; us->srb = srb; complete(&us->cmnd_ready); //释放锁,唤醒控制线程 return 0; } 好了,用户层有了SCSI命令,就会执行我们驱动中这个控制线程。这个死循环首先会做一些判断,然后一直进行数据通信。那么这个死循环也是会退出的,什么时候呢?当执行这个死循环的最后一个if语句,会进行超时处理,如果超时会将us->srb=NULL,而我们在这个控制线程的死循环中发现,当获取us->cmnd_ready锁后,第一个执行的代码就是判断us->srb是否为NULL,如果us->srb=NULL就会执行break语句,从而跳出第一个死循环。接下来进入第二个死循环,这个死循环首先判断是否真的该结束了,如果真的结束了,那么就break,彻底退出这个控制线程,如果不是应该彻底结束,那进行schedule重新调度控制子线程。
到目前为止,我们的控制线程就已经分析完了,不过我们发现,这个控制线程是在usb_stor_acquire_resources中定义的,在usb_stor_acquire_resources之后,我们还创建了usb_stor_scan_thread线程,这是一个扫描线程。 static int usb_stor_scan_thread(void * __us) { struct us_data *us = (struct us_data *)__us; printk(KERN_DEBUG "usb-storage: device found at %d\n", us->pusb_dev->devnum); set_freezable(); //设备在一定时间内没有响应,会挂起 if (delay_use > 0) { // delay_use秒后如果U盘没拔出则继续执行,否则执行disconnect printk(KERN_DEBUG "usb-storage: waiting for device " "to settle before scanning\n"); wait_event_freezable_timeout(us->delay_wait,test_bit(US_FLIDX_DONT_SCAN, &us->dflags), delay_use * HZ); } if (!test_bit(US_FLIDX_DONT_SCAN, &us->dflags)) { if (us->protocol == US_PR_BULK && !(us->fflags & US_FL_SINGLE_LUN)) { mutex_lock(&us->dev_mutex); us->max_lun = usb_stor_Bulk_max_lun(us); //询问设备支持多少个LUN mutex_unlock(&us->dev_mutex); } scsi_scan_host(us_to_host(us)); printk(KERN_DEBUG "usb-storage: device scan complete\n"); } complete_and_exit(&us->scanning_done, 0); //本进程结束,唤醒disconnect中的进程 } 对于上面这个扫描线程,里面的usb_stor_Bulk_max_lun函数完成了主机控制器与设备之间的第一次通信。USB驱动程序首先发送一个命令,然后设备根据命令返回一些信息,这里显示的是一个表示LUN个数的数字,usb_stor_Bulk_max_lun完成的是一次控制传输。 int usb_stor_Bulk_max_lun(struct us_data *us) { int result; us->iobuf[0] = 0; //默认只有0个LUN result = usb_stor_control_msg(us, us->recv_ctrl_pipe, US_BULK_GET_MAX_LUN, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, us->iobuf, 1, 10*HZ); //向设备发送一个命令 US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", result, us->iobuf[0]); if (result > 0) return us->iobuf[0]; return 0; } 我们看看里面usb_stor_control_msg的实现 int usb_stor_control_msg(struct us_data *us, unsigned int pipe, u8 request, u8 requesttype, u16 value, u16 index, void *data, u16 size, int timeout) { int status; US_DEBUGP("%s: rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n", __func__, request, requesttype, value, index, size); us->cr->bRequestType = requesttype; //初始化us->cr us->cr->bRequest = request; us->cr->wValue = cpu_to_le16(value); us->cr->wIndex = cpu_to_le16(index); us->cr->wLength = cpu_to_le16(size); usb_fill_control_urb(us->current_urb, us->pusb_dev, pipe, (unsigned char*) us->cr, data, size, usb_stor_blocking_completion, NULL); //填充控制urb status = usb_stor_msg_common(us, timeout); //继续填充控制urb并提交 if (status == 0) status = us->current_urb->actual_length; return status; } 继续往下看usb_stor_msg_common的实现 static int usb_stor_msg_common(struct us_data *us, int timeout) { struct completion urb_done; long timeleft; int status; if (test_bit(US_FLIDX_ABORTING, &us->dflags)) //设备处于放弃状态则结束 return -EIO; init_completion(&urb_done); //初始化完成量 us->current_urb->context = &urb_done; us->current_urb->actual_length = 0; us->current_urb->error_count = 0; us->current_urb->status = 0; us->current_urb->transfer_flags = URB_NO_SETUP_DMA_MAP; if (us->current_urb->transfer_buffer == us->iobuf) us->current_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; us->current_urb->transfer_dma = us->iobuf_dma; us->current_urb->setup_dma = us->cr_dma; status = usb_submit_urb(us->current_urb, GFP_NOIO); //提交控制urb if (status) { return status; } set_bit(US_FLIDX_URB_ACTIVE, &us->dflags); //当前还没取消urb时,取消urb请求 if (test_bit(US_FLIDX_ABORTING, &us->dflags)) { if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) { US_DEBUGP("-- cancelling URB\n"); usb_unlink_urb(us->current_urb); } } //等待直到urb完成,如果1秒时间到进程没有被信号唤醒,则自动唤醒 timeleft = wait_for_completion_interruptible_timeout( &urb_done, timeout ? : MAX_SCHEDULE_TIMEOUT); clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags); if (timeleft <= 0) { US_DEBUGP("%s -- cancelling URB\n", timeleft == 0 ? "Timeout" : "Signal"); usb_kill_urb(us->current_urb); } return us->current_urb->status; } 通过对上面这个usb_stor_msg_common函数的分析,我们现在已经把控制urb提交给USB内核了,当处理完,就会通知USB设备驱动,调用其回调函数,该回调函数在填充控制urb时已经说明,也就是usb_stor_blocking_completion函数 static void usb_stor_blocking_completion(struct urb *urb) { struct completion *urb_done_ptr = urb->context; complete(urb_done_ptr); } 当一次通信完成,执行了回调函数后,就会释放锁,这样stor_msg_common函数中的wait_for_completion_interruptible_timeout处就会被唤醒,至此一次通信完毕。 最后需要补充说明一个问题,在上面提交控制urb时,flag标志使用的是GFP_NOIO。GFP_NOIO标志的意思是不能在申请内存的时候进行I/O操作,原因是usb_submit_urb()提交之后,会读取磁盘或者U盘中的数据,这种情况下,由于虚拟内存的原因,,申请内存的函数还需要读取磁盘。所以不允许在usb_submit_urb()提交urb时进行I/O操作。
总结下,USB设备驱动主要围绕URB请求块,也就是控制URB、中断URB、批量URB、等时URB。USB骨骼框架是批量URB的例子。USB鼠标是一个中断URB和input子系统结合的例子。USB键盘是一个控制URB和中断URB结合input子系统的例子。USB的U盘是批量URB和控制URB结合的例子。不幸的是,等时URB没有填充函数,因此等时URB在被提交给USB核心之前,需要手动进行初始化。
三. U盘驱动测试 本Mini2440开发板具有两种USB接口,一个是USB Host,它和普通PC的USB接口是一样的,可以接USB摄像头、USB 键盘、USB鼠标、优盘等常见的USB外设,另外一种是USB Slave,我们一般使用它来下载程序到目标板。对于U盘的测试,要配置内核后才能进行测试。
实验环境:内核linux2.6.32.2,arm-linux-gcc交叉编译器,mini2440开发板。 内核配置:(1)因为优盘用到了 SCSI命令,所以我们先增加SCSI 支持。在 Device Drivers菜单里面,选择SCSI device support。(2)选择 USB support,按回车进入USB support菜单,找到并选中USB Mass Storage support。(3)另外,现在的优盘等移动存储器使用的大都是FAT/FAT32格式的,因此我们还需要添加FAT32 文件系统的支持,在内核配置主菜单下进入FAT32文件系统配置子菜单,为了支持中英文的编码,在File systems菜单下选择Native language support。
接上面的步骤,在内核源代码根目录下执行:make zImage,把生成的新内核烧写到开发板中,先不要插入优盘(这样做是为了看插入时的打印信息),等系统启动后,进入命令行控制台,此时优盘,可以看到其厂家ID和产品ID,以及存储设备uba1信息。 (1) 执行cat /proc/partitions查看磁盘分区信息 (2) 挂载U盘,在mnt目录下建立usb目录 执行mkdir /mnt/usb ;mount /dev/uba1 /mnt/usb/ (3) 查看U盘信息 ls /mnt/usb –l (4) 查看挂载后的分区信息 df –h
1. usb-storage 驱动注册过程. module_init(usb_stor_init);
2. storage_probe 函数的处理过程.
在 usb-stroage 驱动程序注册的过程中, 由于 bus_usb_type 没有定义 probe 函数,所以会执行代码 usb_storage_driver 中定义的 probe 函数.
3. usb_stor_host_template 数据结构.
4. usb_storage_driver 数据结构.
usb-storage 驱动的核心结构.
5. USB 读写.
(1) 当用户需要访问 USB 设备时, scsi-core 会调用 scsi_dispatch_cmd(), 而 scsi_dispatch_cmd()
会进一步调用 scsi_host_template 中的 queuecommand, 也就是 usb_stor_host_template 中的 queuecommand() 函数.
(2) usb_stor_control_thread 线程的处理过程.
(3) usb_stor_transparent_scsi_command() 函数的处理过程. <drivers/usb/storage/protocol.c> USB 的数据传输分为三个过程: 命令传输, 数据传输, 状态传输.
6. 移除 USB 设备. usb_stor_disconnect() 函数的处理过程. 基本都是释放资源, 释放锁.
http://www.linuxidc.com/Linux/2012-12/76197p17.htm
|