Linux那些事儿之我是U盘(19)冬天来了,春天还会远吗?(三)

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

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

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

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

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

518526,这里调用了一个来自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里边.

至此,get_device_info这个函数就结束了他的使命.usb storage这部戏里,他将不再出场.但我想说,对于usb storage这整个模块来说,主角配角不重要,每个函数都是画布上的一抹色彩.就像我们每一个人,不也是别人人生中的配角,但总是自己人生的主角吗?

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值