免费注册 查看新帖 |

Chinaunix

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

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

论坛徽章:
0
31 [报告]
发表于 2008-06-06 13:49 |只看该作者
US_PR_BULK) },

147 #if !defined(CONFIG_BLK_DEV_UB) && !defined(CONFIG_BLK_DEV_UB_MODULE)

148 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI,
US_PR_BULK) },

149 #endif

150

151 /* Terminating entry */

152 { }

153 };
注意到这是一个struct usb_device_id 结构体的数组,所以即使我们用下半身思考也能知道,其中每一项
必然是一个struct usb_device_id 的结构体变量.我们先来看USB_INTERFACE_INFO 这个咚咚,很显
然这是一个宏,来自include/linux/usb.h,

473 /**

474 * USB_INTERFACE_INFO - macro used to describe a class of usb interfaces

475 * @cl: bInterfaceClass value

476 * @sc: bInterfaceSubClass value

477 * @pr: bInterfaceProtocol value

478 *

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

480 * specific class of interfaces.

481 */

482 #define USB_INTERFACE_INFO(cl,sc,pr) \

483 .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass =
(cl), .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)
每一个USB_INTERFACE_INFO 就是构造一个struct usb_device_id 的结构体变量,回顾一下我们之前
给出的struct usb_device_id 的定义,这里实际上就是为其中的四个元素赋了值,它们是
match_flags,bInterfaceClass,bInterfaceSubClass,bInterfaceProtocol. 这里不得不说的是,这个世
界上有许许多多的usb 设备,它们各有各的特点,为了区分它们,usb 规范,或者说usb 协议,把usb 设备分
成了很多类,然而每个类又分成子类,这很好理解,我们一个大学也是如此,先是分成很多个学院,比如我们复
旦大学,信息学院,经济学院,管理学院,外文学院,等等.然后每个学院又被分为很多个系,比如信息学院,下面
分了电子工程系,微电子系,计算机系,通信工程系,然后可能每个系下边又分了各个专业,usb 协议也是这样
干的,首先每个Interface 属于一个Class,( 为什么是把Interface 分类,而不把Device 分类?前面讲过了,
在usb 设备驱动中,不用再提Device, 因为每个设备驱动对应的是一种Interface,而不是一种Device), 然
后Class 下面又分了SubClass, 完了SubClass 下面又按各种设备所遵循的不同的通信协议继续细分.usb
协议里边为每一种Class, 每一种SubClass, 每一种Protocol 定义一个数值,比如mass storage 的Class
就是0x08,而这里USB_CLASS_MASS_STORAGE 这个宏在include/linux/usb_ch9.h 中定义,其值正
是8.

我们拿第126 行来举例,
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_CB) },

把这个宏展开,就是说定义了这么一个usb_device_id 结构体变量,其
match_flags=USB_DEVICE_ID_MATCH_INT_INFO, 而

论坛徽章:
0
32 [报告]
发表于 2008-06-06 13:49 |只看该作者
bInterfaceClass=USB_CLASS_MASS_STORAGE,bInterfaceSubClass=US_SC_RBC, 而
bInterfaceProtocol=US_PR_CB.

USB_CLASS_MASS_STORAGE 就不用再说了,咱们这个驱动程序所支持的每一种设备都是属于这个类,
或者说这个Class. 但是这个Class 里边包含不同的SubClass, 比如subclass 02 为CD-ROM 设备,04 为
软盘驱动器,06 为通用SCSI 类设备.而通信协议则主要有CBI 协议和Bulk-Only 协议.

像US_SC_RBC 这些关于sub class 的宏的定义是在文件drivers/usb/storage/protocol.h 中:

47 /* Sub Classes */

48

49 #define US_SC_RBC 0x01 /* Typically, flash devices */

50 #define US_SC_8020 0x02 /* CD-ROM */

51 #define US_SC_QIC 0x03 /* QIC-157 Tapes */

52 #define US_SC_UFI 0x04 /* Floppy */

53 #define US_SC_8070 0x05 /* Removable media */

54 #define US_SC_SCSI 0x06 /* Transparent */

55 #define US_SC_ISD200 0x07 /* ISD200 ATA */
而像US_PR_CB 这些关于传输协议的宏则在另一个文件中,drivers/usb/storage/transport.h

/* Protocols */

#define US_PR_CBI 0x00 /* Control/Bulk/Interrupt *
/
#define US_PR_CB 0x01 /* Control/Bulk w/o interrupt *
/
#define US_PR_BULK 0x50 /* bulk only *
/
这个文件中还定义了更多的协议,不过我们暂时只需要知道这三种,因为其她协议都是专门针对一些特殊

备的,在storage_usb_ids 数组中使用宏USB_INTERFACE_INFO 定义的usb_device_id 都只是用

这三种协议.(US_PR_CBI 和US_PR_CB 这两种协议在usb 协议中都唤作CBI,不过之间有点差别.)而

于一些特殊的设备,则还在unusual_devs.h 文件中有专门的一些变量定义,我们暂且不去关注它们
.


说了这许多,U 盘属于其中的哪一种呢?usb 协议中规定,U 盘的Subclass 是属于US_SC_SCSI 的.而其通
信协议使用的是Bulk-Only 的.显然这些东西我们后来都会用得上.

那么这里还有一个match_flag,它又是表示什么意思?USB_INTERFACE_INFO 这个宏貌似把所有的设
备的match_flag 都给设成了USB_DEVICE_ID_MATCH_INT_INFO, 这是为啥?这个宏来自
include/linux/usb.h,

435 #define USB_DEVICE_ID_MATCH_INT_INFO \

436 (USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS | USB_DEVICE_ID_MATCH_INT_PROTOCOL)
match_flag 这个咚咚是给usb core 去用的,usb core 负责给设备寻找适合她的driver, 负责给driver
寻找适合他的device, 它所比较的就是struct usb_device_id 的变量,而struct usb_device_id 结构体
中有许多成员,那么是不是一定要把每一个成员都给比较一下呢,其实没有必要那么细,差不多就行了,比如
咱们这里,就是告诉usb core,你只要比较bInterfaceClass,bInterfaceSubClass,bInterfaceProtocol
即可.include/linux/mod_devicetable.h 中针对struct usb_device_id 中的每一个要比较的项定义了
一个宏:

论坛徽章:
0
33 [报告]
发表于 2008-06-06 13:51 |只看该作者
先看associate_dev(), 定义于drivers/usb/storage/usb.c,

429 /* Associate our private data with the USB device */

430 static int associate_dev(struct us_data *us, struct usb_interface *intf)

431 {

432 US_DEBUGP("-- %s\n", __FUNCTION__);

433

434 /* Fill in the device-related fields */

435 us->pusb_dev = interface_to_usbdev(intf);

436 us->pusb_intf = intf;

437 us->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;

438 US_DEBUGP("Vendor: 0x%04x, Product: 0x%04x, Revision: 0x%04x\n",

439 us->pusb_dev->descriptor.idVendor,

440 us->pusb_dev->descriptor.idProduct,

441 us->pusb_dev->descriptor.bcdDevice);

442 US_DEBUGP("Interface Subclass: 0x%02x, Protocol: 0x%02x\n",

443 intf->cur_altsetting->desc.bInterfaceSubClass,

444 intf->cur_altsetting->desc.bInterfaceProtocol);

445

446 /* Store our private data in the interface */

447 usb_set_intfdata(intf, us);

448

449 /* Allocate the device-related DMA-mapped buffers */

450 us->cr = usb_buffer_alloc(us->pusb_dev, sizeof(*us->cr),

451 GFP_KERNEL, &us->cr_dma);

452 if (!us->cr) {

453 US_DEBUGP("usb_ctrlrequest allocation failed\n");

454 return -ENOMEM;

455 }

456

457 us->iobuf = usb_buffer_alloc(us->pusb_dev, US_IOBUF_SIZE,

458 GFP_KERNEL, &us->iobuf_dma);

459 if (!us->iobuf) {

460 US_DEBUGP("I/O buffer allocation failed\n");

461 return -ENOMEM;

462 }

463 return 0;

464 }

我们首先来关注函数associate_dev 的参数, struct us_data *us, 传递给它的是us,这个不用多说了
吧,此前刚刚为它申请了内存,并且初始化各成员为0. 这个us将一直陪伴我们走下去,直到我们的故事结束.
所以其重要性不言而喻. struct usb_interface *intf, 这个也不用说,storage_probe()函数传进来的两个
参数之一.总之,此处郑重申明一次,struct us_data 的结构体指针us,struct usb_interface 结构体的指
针intf, 以及struct usb_device 结构体和struct usb_device_id 结构体在整个U 盘驱动的故事中是唯
一的,每次提到都是那个. 而以后我们会遇上的几个重要的数据结构,struct urb urb,struct scsi_cmnd

论坛徽章:
0
34 [报告]
发表于 2008-06-06 13:51 |只看该作者
srb 这也非常重要,但是它们并不唯一,也许每次遇上都不一样,就像演戏一样.前边这几个数据结构的变量
就像那些主角,而之后遇见的urb 啊,srb 啊,虽然频繁露面,但是只是群众演员,只不过这次是路人甲,下次是
路人乙. 所以,以后我们将只说us,不再说struct us_data *us,struct usb_interface * intf 也将只用
intf 来代替.

us 之所以重要,是因为接下来很多函数都要用到它以及它的各个成员.实际上目前这个函
数,associate_dev 所做的事情就是为us 的各成员赋值,毕竟此刻us 和我们之前提到的那些struct
usb_device 啊,struct usb_interface 啊,还没有一点关系.因而,这个函数,以及这之后的好几个函数都是
为了给us 的各成员赋上适当的值,之所以如此兴师动众去为它赋值,主要就是因为后面要利用它.所谓天下
没有免费的午餐.

432 行,本来无须多讲,因为只是一个debug 语句,不过提一下__FUNCTION__ 这个"宏",gcc 2.95 以
后的版本支持这么一个冬冬,这个"宏"在编译的时候会被转换为函数名(字符串),这里自然就是
"associate_dev" 这么一个字符串,于是函数执行到这里就会打印一句话告诉世人我们执行到这个函数来
了,这种做法显然会有利于咱们调试程序.不过这个冬冬实际上不是宏,因为预处理器对她一无所知.她的心
只有编译器才懂.

435 行,pusb_dev, 就是point of usb device 的意思.struct us_data 中的一个成员,按照我们刚才
约定的规矩,此刻我将说us 的一个成员,us->pusb_dev= interface_to_usbdev(intf),
interface_to_usbdev 我们前面已经讲过,其含义正如字面表示的那样,把一个struct interface 结构体的
指针转换成一个struct usb_device 的结构体指针.前面我们说过,struct usb_device 对我们没有什么用,
但是usb core 层的一些函数要求使用这个参数,所以我们不得已而为止,正所谓人在江湖身不由己.

436 行,把intf 赋给us 的pusb_intf.

437 行,us 的ifnum, 先看intf 的cur_altsetting, 这个容易令外行混淆.usb 设备有一个
configuration 的概念,这个我们前面讲协议的时候说了,而这里又有一个setting, 咋一看有些奇怪,这两个
词不是一回事吗.这时候,就体现出外语水平了,上过新东方没上过新东方,背没背过俞敏洪的GRE 红宝书,
在这时候就体现出差距了.还是拿我们最熟悉的手机来打比方,configuration 不说了,setting, 一个手机可
能各种配置都确定了,是振动还是铃声已经确定了,各种功能都确定了,但是声音的大小还可以变吧,通常手
机的音量是一格一格的变动,大概也就5,6 格,那么这个可以算一个setting 吧.这里cur_altsetting 就是表
示的当前的这个setting, 或者说设置.cur_altsetting 是一个struct usb_host_interface 的指针,这个结
构体定义于include/linux/usb.h:

51 /* host-side wrapper for one interface setting's parsed descriptors */
52 struct usb_host_interface {

53 struct usb_interface_descriptor desc;
54
55 /* array of desc.bNumEndpoint endpoints associated with this
56 * interface setting. these will be in no particular order.
57 */
58 struct usb_host_endpoint *endpoint;
59
60 unsigned char *extra; /* Extra descriptors */
61 int extralen;

论坛徽章:
0
35 [报告]
发表于 2008-06-06 13:52 |只看该作者
62 };
它的成员desc 是一个struct usb_interface_descriptor 结构体变量,这个结构体的定义是和usb 协议直
接对应的,定义于include/linux/usb_ch9.h.( 这里取名为"ch9"是因为这个文件很多东西对应于usb
spec 2.0 中的第九章,chapter 9.):

242 /* USB_DT_INTERFACE: Interface descriptor *
/
243 struct usb_interface_descriptor
{
244 __u8 bLength;
245 __u8 bDescriptorType;
246
247 __u8 bInterfaceNumber;
248 __u8 bAlternateSetting;
249 __u8 bNumEndpoints;
250 __u8 bInterfaceClass;
251 __u8 bInterfaceSubClass;
252 __u8 bInterfaceProtocol;
253 __u8 iInterface;
254 } __attribute__ ((packed))
;


而其中我们这里提到的是bInterfaceNumber, 一个设备可以有多个Interface, 于是每一个Interface 当
然就得用个编号了,要不然咋区分啊?所有这些描述符里的冬冬都是出厂的时候就固化在设备里边的,而我
们这里之所以可以用bInterfaceNumber 来赋值,是因为usbcore 在为设备初始化的时候就已经做足了这
些功课.否则的话,我们真是寸步难行.

总之,us->ifnum 就是这样,最终就是等于咱们眼下这个interface 的编号.

438 到444 行就是两句调试语句,打印更多一些描述符信息,包括device 描述符和interface 描述符.

447 行, usb_set_intfdata(), 这其实是一个内联函数,她就一行代码,也是定义于
include/linux/usb.h 中:

138 static inline void usb_set_intfdata (struct usb_interface *intf, void *data)

139 {

140 dev_set_drvdata(&intf->dev, data);

141 }

有趣的是,dev_set_drvdata 这个函数也是内联函数,也只有一行代码,她定义于
include/linux/device.h 中:

302 static inline void

303 dev_set_drvdata (struct device *dev, void *data)

304 {

305 dev->driver_data = data;

306 }

所以,结合来看,最终做的事情就是让&intf->dev->driver_data=data, 即
&intf->dev->driver_data=us.

论坛徽章:
0
36 [报告]
发表于 2008-06-06 13:52 |只看该作者
再往下走,就是申请内存了,us->cr 和us->iobuf 都是指针,这里让它们指向两段内存空间,下面会用得
到.需要注意的是usb_buffer_alloc(), 这个函数是usbcore 提供的,我们只管调用即可.从名字上就能知道
它是用来申请内存的,第一个参数就是struct usb_device 结构体的指针,所以我们要传递一个pusb_dev,
第三个参数,GFP_KERNEL,是一个内存申请的flag,通常内存申请都用这个flag,除非是中断上下文,不能
睡眠,那就得用GPF_ATOMIC, 这里没那么多要求.第二个参数申请的buffer 的大小,对于cr, 传递的是
sizeof(*us->cr), 而对于iobuf, 传递的是US_IOBUF_SIZE, 这是一个宏,大小是64,是我们自己定义的,
来自drivers/usb/storage/usb.h:

91 /
*
92 * We provide a DMA-mapped I/O buffer for use with small USB transfers.
93 * It turns out that CB[I] needs a 12-byte buffer and Bulk-only needs
a


94 * 31-byte buffer. But Freecom needs a 64-byte buffer, so that's the

95 * size we'll allocate.

96 */

97

98 #define US_IOBUF_SIZE 64 /* Size of the DMA-mapped I/O buffer
*/

而usb_buffer_alloc() 的第四个参数有些意思了,第一次我们传递的是&us->cr_dma,第二次传递的是
&us->iobuf_dma, 这涉及到dma 传输.这两个咚咚此前我们都没有赋过值,相反它们是在这个函数调用之
后被赋上值的.cr_dma 和iobuf_dma 都是dma_addr_t 类型的变量,这个数据类型是Linux 内核中专门
为dma 传输而准备的.为了支持dma 传输,usb_buffer_alloc 不仅仅是申请了地址,并且建立了dma 映
射,cr_dma 和iobuf_dma 就是记录着cr 和iobuf 的dma 地址.关于什么是cr,关于这些dma 地址究竟
有什么用,我们稍候就会遇到,那时候再讲也不迟.现在需要知道的就是usb_buffer_alloc 申请的空间分别
返回给了cr 和iobuf. 顺便提一下,用usb_buffer_alloc 申请的内存空间需要用它的搭档
usb_buffer_free()来释放.

452 行和459 行,每一次申请完内存就要检查成功与否,这是惯例.驱动程序能否驱动设备,关键就是看能否
申请到内存空间,任何一处内存空间申请失败,整个驱动程序就没法正常工作.这就像如今找对象,谈婚姻,总
是要看有没有房子.没有房子的话,那么基本上爱情也就没戏.然而现实中要拥有房子比计算机里分配内存却
要难上许多,许多.可怜的我们这一代人,当我们不能挣钱的时候,房子是分配的,当我们能挣钱的时候,却发
现房子已经买不起了.哭…

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

整个usb-storage 模块的代码中,其最灵魂的部分在一个叫做usb_stor_control_thread() 的函数中,而
那也自然是我们整个故事的高潮.这个函数的调用有些特殊,我们是从usb_stor_acquire_resources() 函
数进入的,而后者我们即将遇到,它在整部戏中只出现过一次,即storage_probe 中,行号为998 的地方.然
而在此之前,有四个函数挡在我们面前,它们就是

论坛徽章:
0
37 [报告]
发表于 2008-06-06 13:53 |只看该作者
get_device_info,get_transport,get_protocol,get_pipes. 如我前面所说,两个人要走到一起,首先要
了解彼此,这四个函数就是让driver 去认识device 的.这一点我们从名字上也能看出来.driver 需要知道
device 姓甚名谁,所以有了get_device_info,driver 需要知道device 喜欢用什么方式沟通,是用QQ 还
是用msn 还是只用手机短信,如果是某一种,那么账号是多少,或者手机号是多少,写代码的人把这些工作分
配给了get_transport,get_protocol,get_pipes.

实际上,这四个函数,加上之前刚说过的那个associate_dev(), 是整个故事中最平淡最枯燥的部分,第一次
读这部分代码总让人困惑,怎么没看见一点usb 数据通信啊?完全没有看到usb host 和usb device 是如
何在交流的,这是usb 吗?这一刻,这颗浮躁的心,在这个城市,迷失了.但是,我们知道,爱情,并非都与风花雪
月有关,友情,并非总与疯斗打闹有关.这几个函数应该说是给后面做铺垫,红花总要有绿叶配,没有这段代码
的铺垫,到了后面usb 设备恐怕也无法正常工作吧.不过,一个利好消息是,这几个函数我们只会遇见这一次,
它们在整个故事中就这么一次露脸的机会,像我们每个人的青春,只有一次,无法回头.和我们每个人的青春
一样,都是绝版的.所以,让我们享受这段平淡无奇的代码吧.

get_device_info, 这个函数定义于drivers/usb/storage/usb.c 中:

466 /* Get the unusual_devs entries and the string descriptors */

467 static void get_device_info(struct us_data *us, int id_index)

468 {

469 struct usb_device *dev = us->pusb_dev;

470 struct usb_interface_descriptor *idesc =

471 &us->pusb_intf->cur_altsetting->desc;

472 struct us_unusual_dev *unusual_dev = &us_unusual_dev_list[id_index];

473 struct usb_device_id *id = &storage_usb_ids[id_index];

474

475 /* Store the entries */

476 us->unusual_dev = unusual_dev;

477 us->subclass = (unusual_dev->useProtocol == US_SC_DEVICE) ?

478 idesc->bInterfaceSubClass :

479 unusual_dev->useProtocol;

480 us->protocol = (unusual_dev->useTransport == US_PR_DEVICE) ?

481 idesc->bInterfaceProtocol :

482 unusual_dev->useTransport;

483 us->flags = unusual_dev->flags;

484

485 /* Log a message if a non-generic unusual_dev entry contains an

486 * unnecessary subclass or protocol override. This may stimulate

487 * reports from users that will help us remove unneeded entries

488 * from the unusual_devs.h table.

489 */

490 if (id->idVendor || id->idProduct) {

491

static char *msgs[3] =
{
492


"an unneeded SubClass entry"
,
493


"an unneeded Protocol entry"
,
494


"unneeded SubClass and Protocol entries"};

论坛徽章:
0
38 [报告]
发表于 2008-06-06 13:53 |只看该作者
495 struct usb_device_descriptor *ddesc = &dev->descriptor;
496 int msg = -1;
497
498 if (unusual_dev->useProtocol != US_SC_DEVICE &
&
499 us->subclass == idesc->bInterfaceSubClass)
500 msg += 1;
501 if (unusual_dev->useTransport != US_PR_DEVICE &
&
502 us->protocol == idesc->bInterfaceProtocol)
503 msg += 2;
504 if (msg >= 0 && !(unusual_dev->flags & US_FL_NEED_OVERRIDE)
)
505 printk(KERN_NOTICE USB_STORAGE "This device
"
506 "(%04x,%04x,%04x S %02x P %02x)
"
507 " has %s in unusual_devs.h\n"
508 " Please send a copy of this message to
"
509 "<linux-usb-devel@lists.sourceforge.net>\n"
,
510 ddesc->idVendor, ddesc->idProduct,
511 ddesc->bcdDevice,
512 idesc->bInterfaceSubClass,
513 idesc->bInterfaceProtocol,
514 msgs[msg])
;
515
}
516
517 /* Read the device's string descriptors *
/
518 if (dev->descriptor.iManufacturer)
519 usb_string(dev, dev->descriptor.iManufacturer,
520 us->vendor, sizeof(us->vendor))
;
521 if (dev->descriptor.iProduct)
522 usb_string(dev, dev->descriptor.iProduct,
523 us->product, sizeof(us->product))
;
524 if (dev->descriptor.iSerialNumber)
525 usb_string(dev, dev->descriptor.iSerialNumber,
526 us->serial, sizeof(us->serial))
;
527
528 /* Use the unusual_dev strings if the device didn't provide them *
/
529 if (strlen(us->vendor) == 0)
{
530 if (unusual_dev->vendorName)
531 strlcpy(us->vendor, unusual_dev->vendorName,
532 sizeof(us->vendor))
;
533 else
534 strcpy(us->vendor, "Unknown")
;
535
}
536 if (strlen(us->product) == 0)
{
537 if (unusual_dev->productName)
538 strlcpy(us->product, unusual_dev->productName,

论坛徽章:
0
39 [报告]
发表于 2008-06-06 13:54 |只看该作者
539

sizeof(us->product))
;
540 else
541


strcpy(us->product, "Unknown")
;
542
}
543 if (strlen(us->serial) == 0)
544


strcpy(us->serial, "None");
545
546 US_DEBUGP("Vendor: %s, Product: %s\n", us->vendor, us->product);
547 }

469 行,不多说,dev 还是那个dev.

470 行,struct usb_interface_descriptor *idesc, 这个也无须再说,之前那个associate_dev 函数里
已经介绍过这个结构体,而且整个故事就是针对一个interface 的,一个interface 就对应一个interface 描
述符.所以不管在哪里看到,她总还是她.

472 行, struct us_unusual_dev, 这个结构体是第一次出现,她定义于drivers/usb/storage/usb.h 中,

55 /
*
56 * Unusual device list definitions
57 *
/
58
59 struct us_unusual_dev
{
60 const char* vendorName;
61 const char* productName;
62 __u8 useProtocol;
63 __u8 useTransport;
64 int (*initFunction)(struct us_data *)
;
65 unsigned int flags;
66 }
;


而等号右边的us_unusal_dev_list 是一个数组,定义于drivers/usb/storage/usb.c:

157 /* This is the list of devices we recognize, along with their flag data */
158
159 /* The vendor name should be kept at eight characters or less, and
160 * the product name should be kept at 16 characters or less. If a device
161 * has the US_FL_FIX_INQUIRY flag, then the vendor and product names
162 * normally generated by a device thorugh the INQUIRY response will be
163 * taken from this list, and this is the reason for the above size
164 * restriction. However, if the flag is not present, then you
165 * are free to use as many characters as you like.
166 */
167
168 #undef UNUSUAL_DEV
169 #define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \

论坛徽章:
0
40 [报告]
发表于 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 */
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP