《Linux那些事儿之我是USB》我是U盘(17)冬天来了,春天还会远吗?(三)
从两张表得到了我们需要的东西,然后下面的代码就是围绕着这两个指针来展开了。(unusual_dev和id)继续看get_device_info()。
497行,把unusual_dev给记录在us里面,反正us里面也有这么一个成员。这样记录下来以后使用起来就方便了,因为us是贯穿整个故事的,所以访问它的成员很方便,随时都可以,但是us_unusual_dev_list以及storage_usb_ids这两张表这次之后就不会再用了。因为我们已经得到了我们想要的,所以就不用再去骚扰这两个数组了。
498行至504行,给us的另外三个成员赋值,subclass、protocol和flags。比如我们的U盘,它属于主流设备,在us_unusual_dev_list列表中能找到它,其subclass是US_SC_SCSI,而protocol是Bulk-only,即这里用宏US_PR_BULK代表。
关于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设置了,通常是如果设置了,就要多执行某段代码,以满足某种要求。
523行到551行,这是一段纯粹的调试代码,对我们理解USB没有任何意义的。这段代码检查unusual_devs.h,看是否这个文件定义了一行没有意义的句子。什么叫没有意义?我们刚才看见了,如果这个设备设了US_SC_DEVICE,那么其subclass将从描述符中读出来,如果不然,则让subclass=unusual_dev->useProtocol,但是如果后者又真的和描述符里读出来的一样,那么这个设备就没有必要把自己的useProtocol定义在unusual_devs.h中了,因为反正也可以从描述符里读出来。还不如和大众一样设为US_SC_DEVICE得了。就比如我们来看下面这行代表一个Sony的Memory Stick产品的代码:
629 UNUSUAL_DEV( 0x054c, 0x0069, 0x0000, 0x9999,
630 "Sony",
631 "Memorystick MSC-U03",
632 US_SC_UFI, US_PR_CB, NULL,
633 US_FL_SINGLE_LUN ),
我们看到其useProtocol这一栏里写了US_SC_UFI,这表明它自称是属于UFI这个SubClass的,但是如果我们从它的描述符里面读出来也是这个,那就没有必要注明在这里了,这里直接写成US_SC_DEVICE好了。当然,总的来说这段代码有一些傻。写代码的是希望能够更好地管理unusual_devs.h,希望它不要不断增加,它总希望能够从这个文件中删除一些行,并且即使不能删除一行,也希望每一行都看上去整齐一点,让这个文件看上去更加小巧玲珑,更加精致。而不是无休地增加,不息地扩充。
至此,get_device_info这个函数就结束了它的使命。在USB Storage这部戏里,它将不再出场。但我想说,对于USB Storage这整个模块来说,主角配角不重要,每个函数都是画布上的一抹色彩。就像我们每一个人,不也是别人人生中的配角,但总是自己人生的主角吗?