免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: projl

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

论坛徽章:
0
发表于 2008-06-06 13:54 |显示全部楼层
170

vendor_name, product_name, use_protocol, use_transport,
\
171

init_function, Flags) \
172 { \
173 .vendorName = vendor_name, \
174 .productName = product_name, \
175 .useProtocol = use_protocol, \
176 .useTransport = use_transport, \
177 .initFunction = init_function, \
178 .flags = Flags, \
179 }
180
181 static struct us_unusual_dev us_unusual_dev_list[] = {
182 # include "unusual_devs.h"
183 # undef UNUSUAL_DEV
184 /* Control/Bulk transport for all SubClass values */
185 { .useProtocol = US_SC_RBC,
186 .useTransport = US_PR_CB},
187 { .useProtocol = US_SC_8020,
188 .useTransport = US_PR_CB},
189 { .useProtocol = US_SC_QIC,
190 .useTransport = US_PR_CB},
191 { .useProtocol = US_SC_UFI,
192 .useTransport = US_PR_CB},
193 { .useProtocol = US_SC_8070,
194 .useTransport = US_PR_CB},
195 { .useProtocol = US_SC_SCSI,
196 .useTransport = US_PR_CB},
197
198 /* Control/Bulk/Interrupt transport for all SubClass values */
199 { .useProtocol = US_SC_RBC,
200 .useTransport = US_PR_CBI},
201 { .useProtocol = US_SC_8020,
202 .useTransport = US_PR_CBI},
203 { .useProtocol = US_SC_QIC,
204 .useTransport = US_PR_CBI},
205

{ .useProtocol = US_SC_UFI,
206


.useTransport = US_PR_CBI}
,
207


{ .useProtocol = US_SC_8070,
208


.useTransport = US_PR_CBI}
,
209


{ .useProtocol = US_SC_SCSI,
210


.useTransport = US_PR_CBI}
,
211
212


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

论坛徽章:
0
发表于 2008-06-06 13:55 |显示全部楼层
213

{ .useProtocol = US_SC_RBC,
214


.useTransport = US_PR_BULK}
,
215


{ .useProtocol = US_SC_8020,
216


.useTransport = US_PR_BULK}
,
217


{ .useProtocol = US_SC_QIC,
218


.useTransport = US_PR_BULK}
,
219


{ .useProtocol = US_SC_UFI,
220


.useTransport = US_PR_BULK}
,
221


{ .useProtocol = US_SC_8070,
222 .useTransport = US_PR_BULK}
,
223 #if !defined(CONFIG_BLK_DEV_UB)


&& !defined(CONFIG_BLK_DEV_UB_MODULE)
224 { .useProtocol = US_SC_SCSI,
225 .useTransport = US_PR_BULK},
226 #endif
227
228 /* Terminating entry */
229 { NULL }
230 };

无可奈何花落去,似曾相识燕归来.这个数组看上去特别面熟对不对?可曾记得当初我们见过的那个
storage_usb_ids, 仔细对比一下会发现,这两个数组的元素个数完全一样,只不过,一个由是struct
usb_device_id 结构体构成的,另一个则是struct us_unusual_dev 结构体构成的,其实这两个表格是一
一对应的,它们也都定义于同一个文件中. 细心一点会注意到,UNUSUAL_DEV 这个宏在这个文件里被定
义了两次,这是干嘛用的?听仔细了,我们曾经提过unusual_devs.h 这个文件,这个文件的作用是什么?假
设没有这个文件,那么storage_usb_ids 这张表就是用USB_INTERFACE_INFO 这个宏定义了几种常规
的usb mass storage 的设备,比如,

{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_CB) },

这一行就是定义一个设备的bInterfaceClass,bInterfaceSubClass,bInterfaceProtocol, 也就是说
一个usb interface 只要其这三个项特点与这张表里定义的任何一行匹配,那么就可以把这个设备和这个驱
动绑定,但是这三个条件毕竟只是规定了一些主流的或者说常规的设备的特点,这个世界上usb mass
storage 设备有许多种,林子大了,什么鸟都有.如果你的设备不符合这三个条件但是你仍然要用这个驱动怎
么办?或者说你的设备不一般,在正式工作之前需要进行一些初始化的操作,你想自己提供一个初始化函数,
那怎么办?伟大的Linux 内核开发者们为你准备了一个文件,它就是让诸多usb mass storage 设备厂家欢
欣鼓舞的unusual_devs.h, 有了它,厂家们不用再为自己的设备不被Linux 内核支持而烦恼了.虽然我们的
U 盘基本上不属于这些另类设备,但作为一个有责任心的社会主义新青年,我们有必要为这个文件说两句.

冬天来了,春天还会远吗?(二)

我们打开unusual_devs.h 吧,随便看一下,发现里边就是很多一个个UNUSUAL_DEV宏,每一行就是这么
一个宏,毫无疑问它对应一种设备,我们从其中挑一个来看,比如挑一个三星的吧,过去在Intel 的时候,前辈
们会说,若不是当初我们对自己太自信了,这个世界上又怎么有三星的生存空间.说的是上世纪末,Intel 决定
提高flash 产品的价格,而Nokia 这个大客户不干了,它想找别人,一个叫三星的小公司鬼魅般的出现了,没

论坛徽章:
0
发表于 2008-06-06 13:56 |显示全部楼层
有人相信这样一个小公司能够满足Nokia, 可是,韩国人,韩国人的韧劲不仅仅是体现在足球场上.于是,世界
上有了三星,Nokia 养活了三星,而Intel, 在flash 这一领域失去了一个重要的客户,副CEO 也为此引咎辞职
了.而下面这个设备,正是来自三星的一个flash 产品.

711 /* Submitted by Hartmut Wahl <hwahl@hwahl.de>*/

712 UNUSUAL_DEV( 0x0839, 0x000a, 0x0001, 0x0001,

713 "Samsung",

714

"Digimax 410"
,
715


US_SC_DEVICE, US_PR_DEVICE, NULL,
716 US_FL_FIX_INQUIRY)
,


Digimax 410, 熟悉数码相机的哥们儿大概对三星的这款410 万像素3 倍光学变焦的产品不会陌生,
不过数码相机更新得很快,这款2002 年推出的相机如今当然也算是很一般了,市场上卖的话也就1500 以
下,不过当时刚推出的时候也是3000 到4000 元的.ok,我们来看这一行是什么意思.

UNUSUAL_DEV 这个宏被定义过两次,当然,#define 了之后再下一次#define 之前有一个#undef,
否则就重复定义了.在storage_usb_ids 之前,它的定义是

116 #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax,
\
117 vendorName, productName,useProtocol, useTransport,
\
118 initFunction, flags)
\
119 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax)
}


USB_DEVICE_VER 的定义在include/linux/usb.h 中,

448 /**

449 * USB_DEVICE_VER - macro used to describe a specific usb device with a
version range

450 * @vend: the 16 bit USB Vendor ID

451 * @prod: the 16 bit USB Product ID

452 * @lo: the bcdDevice_lo value

453 * @hi: the bcdDevice_hi value

454 *

455 * This macro is used to create a struct usb_device_id that matches a

456 * specific device, with a version range.

457 */

458 #define USB_DEVICE_VER(vend,prod,lo,hi) \

459 .match_flags =
USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, .idVendor = (vend), .idProduct =
(prod), .bcdDevice_lo = (lo), .bcdDevice_hi = (hi)

所以这行最终出现在storage_usb_ids 中的意思就是令match_flags 为
USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,idVendor 为0x0839,idProduct 为
0x000a,bcdDevice_lo 为0x0001,bcdDevice_hi 为0x0001.

论坛徽章:
0
发表于 2008-06-06 13:56 |显示全部楼层
而在us_unusal_dev_list 这张表之前,UNUSUAL_DEV 又被定义为:

168 #undef UNUSUAL_DEV
169 #define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax,
\
170 vendor_name, product_name, use_protocol, use_transport,


\
171

init_function, Flags)
\
172 {
\
173 .vendorName = vendor_name,
\
174 .productName = product_name,
\
175 .useProtocol = use_protocol,
\
176 .useTransport = use_transport,
\
177 .initFunction = init_function,
\
178 .flags = Flags,
\
179
}


Ok.这样这个宏的意思又是令vendorName 为"Samsung",令productName 为"Digimax 410",
而useProtocol 为US_SC_DEVICE, useTransport 为US_PR_DEVICE,initFunction 为NULL,flag
为US_FL_FIX_INQUIRY.

看明白了吗?首先不去管各项的具体含义,至少我们看出来,针对同一个文件,我们使用两次定义
UNUSUAL_DEV 这个宏的方法,两次利用了它的不同元素,换言之,UNUSUAL_DEV 这个宏本来可以设定
10 个参数,而storage_usb_ids 中需要使用其中的前4 个参数,同时us_unusual_dev_list 中需要使用
其中的后6 个参数,所以在unusual_devs.h 中定义的一行起了两个作用.我们注意到不管是
storage_usb_ids 数组还是us_unusual_dev_list, 其中都通过这么一行把unusual_devs.h 文件给包
含了进来.storage_usb_ids 中:

121 static struct usb_device_id storage_usb_ids [] =
{
122
123 # include "unusual_devs.h"
124 #undef UNUSUAL_DEV


us_unusual_dev_list 中:

181 static struct us_unusual_dev us_unusual_dev_list[] =
{
182 # include "unusual_devs.h"
183 # undef UNUSUAL_DEV


而我们之所以使用两个数组的原因是,storage_usb_ids 是提供给usb core 的,它需要比较driver 和
device 从而确定设备是被这个driver 所支持的,我们只需要比较四项就可以了,因为这四项已经足以确定
一个设备了,厂商,产品,序列号.比较这些就够了,而us_unusual_dev_list 这个数组中的元素是我们接下
来的代码要用的,比如它用什么协议,它有什么初始化函数,所以我们使用了两个数组.而我们需要注意的是,
这两个数组中元素的顺序是一样的,所以我们从storage_usb_ids 中得到的id_index 用于
us_unusual_dev_list 也是可以的,表示的还是同一个设备.而这也就是我们刚才在get_device_info 中
看到的.

论坛徽章:
0
发表于 2008-06-06 13:57 |显示全部楼层
472 struct us_unusual_dev *unusual_dev = &us_unusual_dev_list[id_index];
473 struct usb_device_id *id = &storage_usb_ids[id_index];

这样,unusual_dev 和id 就各取所需了.下面我们将会用到这两个指针.暂且不表.

总结陈词,最后具体解释一下这行为三星这款数码相机写的语句,

1. 关于match_flags,它的值是USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, 这
是一个宏,它就告诉usb core, 要比较这样几个方面,idVendor,idProduct,bcdDevice_lo,bcdDevice_hi,
其中idVendor 和下面的vendorName 是对应的,而idProduct 和下面的productName 是对应的,业内
为每家公司编一个号,这样便于管理,比如三星的编号就是0x0839, 那么三星的产品中就会在其设备描述符
中idVendor 的烙上0x0839. 而三星自己的每种产品也会有个编号,和Digimax 410 对应的编号就是
0x000a,而bcdDevice_lo 和bcdDevice_hi 共同组成一个具体设备的编号(device release
number),bcd 就意味着这个编号是二进制的格式.
2. vendorName 和productName 不用再说了, "Samsung" 和"Digimax 410".
3. useProtocol 为US_SC_DEVICE, useTransport 为US_PR_DEVICE, 这种情况就说明对
于这种设备,它属于什么subclass, 它使用什么通信协议,得从设备描述符里边去读取,它都写在那里边了.
一会我们会看到我们的代码中会如何判断这个的.
4. initFunction 等于NULL,这个很有意义的,这个函数就是设备的初始化函数,一般的设备都不
需要这个函数,但是有些设备它偏要标新立异,它就告诉你,要用我的设备你必须先做一些初始化,于是它提
供了一个函数,initFunction 当然是一个函数指针,这里如果不为NULL 的话,到时候就会被调用,以后我们
会看到代码中对这个指针进行了判断.如果为空不理睬,否则就会执行.比如我们看下面两处,惠普的两个设
备,它就提供了一个叫做init_8200e 的初始化函数,
63 UNUSUAL_DEV( 0x03f0, 0x0207, 0x0001, 0x0001,
64 "HP",
65 "CD-Writer+ 8200e",
66 US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0),
67
68 UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x0001,
69 "HP",
70 "CD-Writer+ CD-4e",
71 US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0),

5. flag 等于US_FL_FIX_INQUIRY, 这个flag 可以设为很多值,这个flag 的存在本身就表示这
个设备有些与众不同,因为一般的设备是不用这个flag 的,有这个flag 就表明这个设备可能在某些地方需要
进行特殊的处理,所以今后在代码中我们会看到突然跳出一句,判断us->flag 等于某个咚咚不,如果等于,就
执行一些代码,如果不等于,那就不做任何事情.这个flag 的存在也使得我们可以方便处理一些设备的bug,
比如正常的设备你问它吃了吗?它就回答吃了.可是不正常的设备可能就会根本不回答,或者回答北京房价
真贵!于是对于这种设备,可能我们就需要一些专门的代码来对付.具体到这个US_FL_FIX_INQUIRY, 这
个flag 这么一设置,就表明这个设备在接受到INQUIRY 命令的时候会有一些异常的特征,所以以后我们会

论坛徽章:
0
发表于 2008-06-06 13:57 |显示全部楼层
在代码里看到我们是如何处理它的.设置了这个flag 的当然不只是三星的这款相机,别的设备也有可能设置
的.

6. 既然明白了unusual_devs.h 的作用,那么很显然的一个事情,如果一个厂家推出了一个新的
设备,它有一些新的特征,而目前的设备驱动不足以完全支持它,那么厂家首先需要做的事情就是在
unusual_devs.h 中添加一个UNUSUAL_DEV 来定义自己的设备,然后再看是否需要给内核打补丁以及
如何打.因此这几年unusual_devs.h 这个文件的长度也是慢慢在增长.
冬天来了,春天还会远吗?(三)

从两张表得到了我们需要的冬冬,然后下面的代码就是围绕着这两个指针来展开了.(unusual_dev 和id)

476 行,把unusual_dev 给记录在us 里边,反正us 里边也有这么一个成员.这样记录下来日后要用起来就
方便了,因为us 是贯穿整个故事的,所以访问他的成员很方便,随时都可以,但是us_unusual_dev_list 以
及storage_usb_ids 这两张表这次之后就不会再用了.因为我们已经得到了我们想要的,所以我们就不用
再去骚扰这两个数组了.

477 至483 行,给us 的另外三个成员赋值,subclass,protocol,flags. 比如我们的U 盘,它属于主流设备,
在us_unusual_dev_list 列表中能找到它,其subclass 是US_SC_SCSI, 而protocol 是Bulk-only, 即
这里用宏US_PR_BULK 所代表的.(224 行和225 行.)关于US_SC_DEVICE 和US_PR_DEVICE 我们
之前讲那个三星的数码相机的时候已经看到了,它就表示subclass 和protocol 得从设备的描述符里边读出
来.这样做看起来很滑稽,因为三星完全可以把subclass 和protocol 在UNUSUAL_DEV 中写清楚,何必让
我们再去读设备描述符呢.然而,我们可以想象,它这样的好处是定义一个UNUSUAL_DEV 可以代表几种设
备,即它可以让几个不同subclass 的设备共用这么一个宏,或者几个不同protocol 的设备共用这么一个宏.
能省一点就省一点吧,这里体现了开源社区人们勤俭节约的高尚品德. 需要特别指出的是us->flags, 对于
U 盘来说,它当然没有什么flags 需要设定,但是unusual_devs.h 中的很多设备都设置了各种flags,稍后
在代码中我们会看到,时不时我们就得判断一下是否某个flag 设置了,通常是如果设置了,就要多执行某段
代码,以满足某种要求.

490 至515 行,这是一段纯粹的调试代码,对我们理解usb 没有任何意义的.这段代码检查
unusual_devs.h, 看是否这个文件定义了一行没有意义的句子.什么叫没有意义?我们刚才看见了,如果这
个设备设了US_SC_DEVICE, 那么其subclass 将从描述符中读出来,如果不然,则让
subclass=unusual_dev->useProtocol, 但是如果后者又真的和描述符里读出来的一样,那么这个设备
就没有必要把自己的useProtocol 定义在unusual_devs.h 中了,因为反正也可以从描述符里读出来.还不
如和大众一样设为US_SC_DEVICE 得了.就比如我们来看下面这行代表一个Sony 的Memory Stick 产
品的代码:

371 UNUSUAL_DEV( 0x054c, 0x0069, 0x0000, 0x9999,

372 "Sony",

373

"Memorystick MSC-U03"
,
374


US_SC_UFI, US_PR_CB, NULL,
375


US_FL_SINGLE_LUN ),

论坛徽章:
0
发表于 2008-06-06 13:58 |显示全部楼层
我们看到其useProtocol 这一栏里写了US_SC_UFI,这表明它自称是属于UFI 这个subclass 的,但是如
果我们从它的描述符里边读出来也是这个,那就没有必要注明在这里了,这里直接写成US_SC_DEVICE 好
了.当然,总的来说这段代码有些傻.写代码的是希望能够更好的管理unusual_devs.h, 希望它不要不断的
增加,他总希望能够从这个文件里删除一些行,并且即使不能删除一行,也希望每一行都看上去整齐一点,让
这个文件看上去更加小巧玲珑,更加精致.而不是无休的增加,不息的扩充.于是我们也只能对其良苦用心多
一份理解吧.

518 至526 行,这里调用了一个来自usb core 的函数,usb_string, 这个函数的作用是获得一个设备的字
符串描述符.咦?怎么跳出来一个叫做字符串描述符的冬冬?之前不是只讲了四种描述符吗?没错,设备描述
符,配置描述符,接口描述符,端点描述符,这是每个设备都有的,而还有些描述符是可有可无的,字符串描述
符就是这么一种情况,有的设备有,有的设备没有.又比如,hub, 它就有一个hub 描述符,这当然是一般的设
备没有的.那么字符串描述符是干嘛的呢?有些东西模糊一些也未偿不是一件好事,看得太透彻了才知道很
残酷.如果你一定要知道的话,举个例子,我的机器里很多usb 设备,有一个和lspci 类似的命令,可以查看一
下,这个命令就是lsusb. 你也可以试一下,安装一个软件包usbutils, 然后就可以使用这个命令.我们看:

localhost:~/test # lsusb
Bus 004 Device 003: ID 0ea0:1001 Ours Technology, Inc.
Bus 004 Device 002: ID 04b4:6560 Cypress Semiconductor Corp. CY7C65640 USB-2.0
"TetraHub"
Bus 004 Device 001: ID 0000:0000
Bus 003 Device 001: ID 0000:0000
Bus 002 Device 002: ID 0624:0294 Avocent Corp.
Bus 002 Device 001: ID 0000:0000
Bus 001 Device 001: ID 0000:0000

看这个第二行, Cypress Semiconductor Corp., 这么一长串的东西,你说哪来的?是不是应该从设备里来?
设备的那几个标准描述符,整个描述符的大小也不一定放得下这么一长串,所以,一些设备专门准备了一些字
符串描述符(string descriptor). 就用来记这些长串的东西,我们结合刚才的518 行开始讲,如果设备描述
符里边iManufacturer 不为0,那么调用usb_string, 这句话具体做了什么?就是根据iManufactuer 的值
得到公司名字,而iManufactuer 的第一个字母i,就表示index, 它记录的是真正的公司名字保存在哪一个字
符串描述符中,因为字符串描述符可以有多个,那么必然就有个号码来区分,接下来几行,iProduct 记录了产
品名在第几个字符串描述符中,iSerialNumber 记录了产品序列号在第几个字符串描述中,然后调用
usb_string 这个函数,就把真正的字符串描述符里的冬冬给记录了下来.我们看到,我们三次调用的时候分
别传递了us->vendor,us->product,us->serial. 这样函数调用结束之后,这三个里面就记录了必要的信
息,于是以后我们就可以用了.

得到了us->vendor,us->product,us->serial, 那么下面528 直到547 行就不需要多讲了,就是说如果
得到的东西是空的,(得到的是空可以有两种可能,一个是设备根本就没提供这些字符串描述符,另一种情况
是usb_string 函数没能成功,但是这个函数不成功也无所谓,没影响.)那也没关系,毕竟这些信息我们可有
可无,无非是打印出来给客户看看.如果unusual_dev 里边有的话,那就拷贝过来,如果也没有,那没办法,设
为Unknown.而序列号这个就索性置为None 好了,最后US_DEBUGP 把这些信息给打印出来,如果你打
开了debug 开关,那么你会在日志文件里看到这么一句话,在/var/log/messages 里边.

论坛徽章:
0
发表于 2008-06-06 13:59 |显示全部楼层
至此,get_device_info 这个函数就结束了他的使命.在usb storage 这部戏里,他将不再出场.但我想说,
对于usb storage 这整个模块来说,主角配角不重要,每个函数都是画布上的一抹色彩.就像我们每一个人,
不也是别人人生中的配角,但总是自己人生的主角吗?

冬天来了,春天还会远吗(四)

结束了get_device_info, 我们继续沿着storage_probe 一步一步走下去.为了保持原汁原味,我们贴代码
的原则是一个函数的每一行都贴出来.get_device_info 是962 行,我们已经贴过,所以下面从963 行开始
了.

963
964 #ifdef CONFIG_USB_STORAGE_SDDR09
965 if (us->protocol == US_PR_EUSB_SDDR09 |
|
966 us->protocol == US_PR_DPCM_USB)
{
967 /* set the configuration -- STALL is an acceptable response here *
/
968 if (us->pusb_dev->actconfig->desc.bConfigurationValue != 1)
{
969 US_DEBUGP("active config #%d != 1 ??\n", us->pusb_dev
970 ->actconfig->desc.bConfigurationValue)
;
971 goto BadDevice;
972
}
973 result = usb_reset_configuration(us->pusb_dev)
;
974
975 US_DEBUGP("Result of usb_reset_configuration is %d\n", result)
;
976 if (result == -EPIPE)
{
977 US_DEBUGP("-- stall on control interface\n")
;
978 } else if (result != 0)
{
979 /* it's not a stall, but another error -- time to bail *
/
980 US_DEBUGP("-- Unknown error. Rejecting device\n")
;
981 goto BadDevice;
982
}
983
}
984 #endif


看到这段代码,我笑了.因为#ifdef CONFIG_USB_STORAGE_SDDR09 说明这段代码跟我们无关.关于
这些编译选项我们前面已然提过,第六感告诉我们这个选项是针对某种特殊产品的,对于这种特殊的产品,它
在某些方面有它自己的要求,所以它会有它特殊的代码.具体到这个选项,我们看一下
drivers/usb/storage/Kconfig 文件,这个文件里边介绍了该目录下每一个编译选项的作用.

99 config USB_STORAGE_SDDR09
100 bool "SanDisk SDDR-09 (and other SmartMedia) support (EXPERIMENTAL)"
101

depends on USB_STORAGE && EXPERIMENTAL
102 help
103


Say Y here to include additional code to support the Sandisk SDDR-09
104

SmartMedia reader in the USB Mass Storage driver.

论坛徽章:
0
发表于 2008-06-06 13:59 |显示全部楼层
105

Also works for the Microtech Zio! SmartMedia reader.

可以看到,如果要支持Sandisk SDDR-09 SmartMedia 的读卡器,那你就打开这个编译选项吧.Sandisk
是公司名,玩数码的人对这家公司不会陌生,中文名叫晟碟,这是一家全球最大的闪存数据存储产品供应商.
而SmartMedia( 简称SM) 卡通常用于数码相机中,也曾一度被用于MP3 中,它也是一种flash memory
存储卡.不过如今市面上很少有SM 卡了,因为其兼容性不好.眼下用得比较多的应该是CF 卡(Compact
Flash) 了.而读卡器就是用来把卡里边的数据读出来,使用USB 接口,从原理上来看和U 盘也是差不多.( 顺
便介绍一下,U 盘和存储卡的区别吧,我们所讲的U 盘,就是可以直接读写的存储器,而存储卡需要外部设备
才能进行访问,如手机的闪存卡,数码相机的闪存卡等就只是一张卡,电脑不能直接对其进行访问,这就需要
一种叫"读卡器"的外部设备进行识别,存储卡有多种,如XD、CF、SD、SM 等等,有些读卡器具有"多合一"
的功能,可以对不同的闪存卡进行读写.而我们这段代码里以及接下来的代码中每一个条件编译开关显然对
应的是一种读卡器.她们属于不同的厂商的不同的产品.)

继续,这就是我们前面提到过的三个函数.get_transport,get_protocol,get_pipes. 一旦结束了这三个函
数,我们就将进入本故事的高潮部分.而在这之前,我们只能一个一个来看.好在这几个函数虽然不短,但是真
正有用的信息只有一点点,所以可以很快的看完.

985

986 /* Get the transport, protocol, and pipe settings */

987 result = get_transport(us);

988 if (result)

989 goto BadDevice;

990 result = get_protocol(us);

991 if (result)

992 goto BadDevice;

993 result = get_pipes(us);

994 if (result)

995 goto BadDevice;

第一个,get_transport(us),

549 /* Get the transport settings */

550 static int get_transport(struct us_data *us)

551 {

552 switch (us->protocol) {

553 case US_PR_CB:

554

us->transport_name = "Control/Bulk"
;
555


us->transport = usb_stor_CB_transport;
556


us->transport_reset = usb_stor_CB_reset;
557


us->max_lun = 7;
558 break;
559
560


case US_PR_CBI:
561


us->transport_name = "Control/Bulk/Interrupt"
;
562


us->transport = usb_stor_CBI_transport;

论坛徽章:
0
发表于 2008-06-06 14:00 |显示全部楼层
563 us->transport_reset = usb_stor_CB_reset;
564 us->max_lun = 7;
565 break;
566
567 case US_PR_BULK:
568 us->transport_name = "Bulk"
;
569 us->transport = usb_stor_Bulk_transport;
570 us->transport_reset = usb_stor_Bulk_reset;
571 break;
572
573 #ifdef CONFIG_USB_STORAGE_HP8200e
574 case US_PR_SCM_ATAPI:
575 us->transport_name = "SCM/ATAPI"
;
576 us->transport = hp8200e_transport;
577 us->transport_reset = usb_stor_CB_reset;
578 us->max_lun = 1;
579 break;
580 #endif
581
582 #ifdef CONFIG_USB_STORAGE_SDDR09
583 case US_PR_EUSB_SDDR09:
584 us->transport_name = "EUSB/SDDR09"
;
585 us->transport = sddr09_transport;
586 us->transport_reset = usb_stor_CB_reset;
587 us->max_lun = 0;
588 break;
589 #endif
590
591 #ifdef CONFIG_USB_STORAGE_SDDR55
592 case US_PR_SDDR55:
593 us->transport_name = "SDDR55"
;
594 us->transport = sddr55_transport;
595 us->transport_reset = sddr55_reset;
596 us->max_lun = 0;
597 break;
598 #endif
599
600 #ifdef CONFIG_USB_STORAGE_DPCM
601 case US_PR_DPCM_USB:
602 us->transport_name = "Control/Bulk-EUSB/SDDR09"
;
603 us->transport = dpcm_transport;
604 us->transport_reset = usb_stor_CB_reset;
605 us->max_lun = 1;
606 break;
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP