免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: projl
打印 上一主题 下一主题

《Linux 那些事儿之我是U盘》 [复制链接]

论坛徽章:
0
21 [报告]
发表于 2008-06-06 13:43 |只看该作者
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协议,
谁也不可能凭空想象出来.毕竟不是写小说,有几人能像海岩那样,光凭想象就能写出便衣警察,永不瞑目,玉
观音这些经典的爱情加案情的作品来呢.

论坛徽章:
0
22 [报告]
发表于 2008-06-06 13:44 |只看该作者
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

论坛徽章:
0
23 [报告]
发表于 2008-06-06 13:44 |只看该作者
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)

论坛徽章:
0
24 [报告]
发表于 2008-06-06 13:45 |只看该作者
嗬,贴这么长一段,怎么又是注释为主啊?知足吧,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. 而管道,实际
上只是为了让我们能够找到端点,就相当于我们日常说的邮编地址,比如一个国家,为了通信,我们
必须给各个地方取名,完了给各条大大小小的路取名,比如你要揭发你们那里的官员腐败,你要去

论坛徽章:
0
25 [报告]
发表于 2008-06-06 13:45 |只看该作者
上访,你从某偏僻的小县城出发,要到北京来上访,那你的这个端点(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);

论坛徽章:
0
26 [报告]
发表于 2008-06-06 13:46 |只看该作者
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 *
/

论坛徽章:
0
27 [报告]
发表于 2008-06-06 13:47 |只看该作者
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 那么就是失败了,那么别再浪费表情了,整部戏就这么提前夭

论坛徽章:
0
28 [报告]
发表于 2008-06-06 13:47 |只看该作者
折了.在这里需要强调的是,整个内核代码中,像这种判断内存申请是否成功的语句是无处不在,每
次有内存申请的语句,其后边一定会跟随一句判断申请成功与否的语句.写过代码的人都该知道,
这样做是很有必要的,因为你没有申请到内存,那么继续下去就是没有意义的,除了可能让人见识
计算机是如何崩溃之外,没有别的好处.而内存申请不管申请了多大,都有可能失败,写代码的人这
样做无非是想告诫我们,我们的计算机并不总像人民币那般坚挺,她很脆弱.当你真正用计算机写
代码的时候你就会发现计算机多么的脆弱和无力。

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, 差别不大,只是形式上略
有不同罢了.

需要注意的是,这些调试信息得是我们打开了编译选项CONFIG_USB_STORAGE_DEBUG 才
有意义的,这里也看出来了,如果这个选项为0,那么这几个宏就什么也不干,因为它们被赋为空了.
关于US_DEBUG 系列的这几个宏,就讲这么多,之后再碰上,将直接过滤掉,不予多说.

关于prink 和kmalloc, 这两个函数也没有太多需要说的,对大多数人来讲,就把printk 当成
printf,把kmalloc 当成malloc 即可,只不过是这两个函数是专门用于内核代码中的.一个是打印
一些东西,一个是申请内存空间.

931 行呢?id_index 干嘛用的?让我们在下节不见不散吧.Be there or be square!-孙楠如是
说.

设备花名册

storage_probe 这个函数挺有意思的,总长度不足100 行,但是干了许多事情,这就像足球场上的后腰,比如
切尔西的马克莱莱,在场上并不起眼,但是却为整个团队做出了卓越的贡献.也有很多评论家说银河战舰皇家
马德里这几年的衰落正是从赶走这个不起眼的马克莱莱开始的.

在讲id_index 之前,我们继续贴storage_probe 的代码:

论坛徽章:
0
29 [报告]
发表于 2008-06-06 13:48 |只看该作者
943 init_MUTEX(&(us->dev_semaphore));

944 init_MUTEX_LOCKED(&(us->sema));

945 init_completion(&(us->notify));

946 init_waitqueue_head(&us->dev_reset_wait);

947 init_waitqueue_head(&us->scsi_scan_wait);

948 init_completion(&us->scsi_scan_done);

949

950 /* Associate the us_data structure with the USB device */

951 result = associate_dev(us, intf);

952 if (result)

953 goto BadDevice;

954

955 /*

956 * Get the unusual_devs entries and the descriptors

957 *

958 * id_index is calculated in the declaration to be the index number

959 * of the match from the usb_device_id table, so we can find the

960 * corresponding entry in the private table.

961 */

962 get_device_info(us, id_index);

storage_probe 这个函数之所以短小,是因为它调用了大量的函数.所以,看起来短短一段代码,实际上却要
花费我们读代码的人好几个小时,想想真是觉得不划算,难怪朱自清先生看到这个storage_probe 函数的
时候,不禁感慨,燕子去了,有再来的时候,杨柳枯了,有再青的时候,桃花谢了,有再开的时候,但是,聪明的你
告诉我,我们读这段不足100 行的函数花掉的时间为何一去不复返呢?

其实我们不知道id_index 也不影响对后面问题的理解,甚至某种意义上来说,花太多笔墨去讲这个
id_index 有一点喧宾夺主的感觉,但是,有时候,有些事情,你明知它是无奈的事,无奈的心情,却还要无奈的
面对,无奈的去选择,有时想无奈的逃避都不可能,因为我们都被无奈禁锢了.比如这里,注意到962 行出现了
一个get_device_info 的函数,它的一个参数就是id_index, 所以,我们别无选择,只能看看这个id_index
究竟是干嘛的.

上节我们注意到id_index=id-storage_usb_ids,id 我们知道,storage_probe 函数的两个形参之一,而
storage_usb_ids, 不是别人,正是我们曾经赋给usb_storage_driver 的成员id_table 的值.忘记了
id_table 的可以回去看.它实际上就是一张表格,告诉全世界我这个driver 支持怎样的一些设
备.storage_usb_ids 同样来自drivers/usb/storage/usb.c 中,

111 /* The entries in this table, except for final ones here

112 * (USB_MASS_STORAGE_CLASS and the empty entry), correspond,

113 * line for line with the entries of us_unsuaul_dev_list[].

114 */

115

116 #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \

117 vendorName, productName,useProtocol, useTransport, \

118

initFunction, flags) \

论坛徽章:
0
30 [报告]
发表于 2008-06-06 13:48 |只看该作者
119 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax) }

120

121 static struct usb_device_id storage_usb_ids [] = {

122

123 # include "unusual_devs.h"

124 #undef UNUSUAL_DEV

125 /* Control/Bulk transport for all SubClass values */

126 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC,
US_PR_CB) },

127 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020,
US_PR_CB) },

128 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC,
US_PR_CB) },

129 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI,
US_PR_CB) },

130 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070,
US_PR_CB) },

131 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI,
US_PR_CB) },

132

133 /* Control/Bulk/Interrupt transport for all SubClass values */

134 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC,
US_PR_CBI) },

135 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020,
US_PR_CBI) },

136 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC,
US_PR_CBI) },

137 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI,
US_PR_CBI) },

138 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070,
US_PR_CBI) },

139 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI,
US_PR_CBI) },

140

141 /* Bulk-only transport for all SubClass values */

142 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC,
US_PR_BULK) },

143 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020,
US_PR_BULK) },

144 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC,
US_PR_BULK) },

145 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI,
US_PR_BULK) },

146 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070,
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP