在整個usb-storage模塊的代碼中,其最靈魂的部分在一個叫做usb_stor_control_thread()的函數中,而那也自然是我們整個故事的高潮。這個函數的調用有一些特殊,是從usb_stor_acquire_resources()函數進入的,而後者我們即將遇到,它在整部戲中只出現過一次,即storage_probe中,行號爲1005的地方。
然而在此之前,有四個函數擋在我們面前,它們就是get_device_info,get_transport,get_protocol,get_pipes。如我前面所說,兩個人要走到一起,首先要了解彼此,這四個函數就是讓驅動去認識設備的。這一點我們從名字上也能看出來。驅動需要知道設備的名字,所以有了get_device_info,驅動需要知道設備是哪一種類型,寫代碼的人把這些工作分配給了get_transport,get_protocol和get_pipes。
實際上,這四個函數,加上之前剛說過的associate_dev()函數,是整個故事中最平淡最枯燥的部分,第一次讀這部分代碼總讓人困惑,怎麼沒看見一點USB數據通信?完全沒有看到USB主機和USB設備是如何在交流的,這是USB嗎?這幾個函數應該說是給後面做鋪墊,紅花總要有綠葉配,沒有這段代碼的鋪墊,到了後面USB設備恐怕也無法正常工作吧。不過,一個好消息是,這幾個函數我們只會遇見這一次,它們在整個故事中就這麼一次露臉的機會,像我們每個人的青春,只有一次,無法回頭。所以,讓我們享受這段平淡無奇的代碼吧。
get_device_info,這個函數定義於drivers/usb/storage/usb.c中:
488 /* Get the unusual_devs entries and the stringdescriptors */
489 static int get_device_info(struct us_data *us,const struct usb_device_id *id)
490 {
491 struct usb_device *dev =us->pusb_dev;
492 structusb_interface_descriptor *idesc =
493 &us->pusb_intf->cur_altsetting->desc;
494 struct us_unusual_dev *unusual_dev= find_unusual(id);
495
496 /*Store the entries */
497 us->unusual_dev= unusual_dev;
498 us->subclass= (unusual_dev->useProtocol == US_SC_DEVICE) ?
499 idesc->bInterfaceSubClass:
500 unusual_dev->useProtocol;
501 us->protocol= (unusual_dev->useTransport == US_PR_DEVICE) ?
502 idesc->bInterfaceProtocol :
503 unusual_dev->useTransport;
504 us->flags =USB_US_ORIG_FLAGS(id->driver_info);
505
506 if(us->flags & US_FL_IGNORE_DEVICE) {
507 printk(KERN_INFO USB_STORAGE "deviceignored\n");
508 return -ENODEV;
509 }
510
511 /*
512 * This flag is onlyneeded when we're in high-speed, so let's
513 * disable it if we're in full-speed
514 */
515 if(dev->speed != USB_SPEED_HIGH)
516 us->flags&= ~US_FL_GO_SLOW;
517
518 /* Log a message if a non-genericunusual_dev entry contains an
519 * unnecessary subclass or protocol override. This may stimulate
520 * reports from users that will help usremove unneeded entries
521 * from the unusual_devs.h table.
522 */
523 if(id->idVendor || id->idProduct) {
524 static const char * msgs[3] = {
525 "an unneeded SubClass entry",
526 "an unneeded Protocol entry",
527 "unneeded SubClass and Protocol entries"};
528 struct usb_device_descriptor *ddesc =&dev->descriptor;
529 int msg = -1;
530
531 if (unusual_dev->useProtocol != US_SC_DEVICE &&
532 us->subclass == idesc->bInterfaceSubClass)
533 msg += 1;
534 if(unusual_dev->useTransport != US_PR_DEVICE &&
535 us->protocol == idesc->bInterfaceProtocol)
536 msg += 2;
537 if ( msg >= 0 && !(us->flags& US_FL_NEED_OVERRIDE))
538 printk(KERN_NOTICE USB_STORAGE"This device "
539 "(%04x,%04x,%04x S %02x P%02x)"
540 " has %s in unusual_devs.h(kernel"
541 " %s)\n"
542 " Please send a copy of this message to "
543 "<[email protected]>\n",
544 le16_to_cpu(ddesc->idVendor),
545 le16_to_cpu(ddesc->idProduct),
546 le16_to_cpu(ddesc->bcdDevice),
547 idesc->bInterfaceSubClass,
548 idesc->bInterfaceProtocol,
549 msgs[ msg],
550 utsname()->release);
551 }
552
553 return0;
554 }
492行,struct usb_interface_descriptor *idesc,這個也無需再說,在之前的associate_dev函數中已經介紹過這個結構體,而且整個故事就是針對一個接口的,一個接口就對應一個接口描述符。
494行,struct us_unusual_dev,這個結構體是第一次出現,它定義於drivers/usb/storage/usb.h中:
61 struct us_unusual_dev {
62 constchar* vendorName;
63 const char*productName;
64 __u8 useProtocol;
65 __u8 useTransport;
66 int(*initFunction)(struct us_data *);
67 };
而“=”右邊的find_unusual()函數定義於drivers/usb/storage/usb.c中:
482 static struct us_unusual_dev*find_unusual(const struct usb_device_id *id)
483 {
484 const int id_index = id - storage_usb_ids;
485 return&us_unusual_dev_list[id_index];
486 }
us_unusual_dev_list是一個數組,定義於drivers/usb/storage/usb.c:
178 static struct us_unusual_devus_unusual_dev_list[] = {
179 # include "unusual_devs.h"
180 # undef UNUSUAL_DEV
181 # undef USUAL_DEV
182
183 /* Terminating entry */
184 {NULL }
185 };
Linux代碼中有很多奇怪的地方,可是像us_unusual_dev_list這個數組這麼奇怪還真沒見過。爲了瞭解這個數組以及find_unusual()函數,我們先來看一看這個storage_usb_ids。它不是別人,正是我們曾經賦給usb_storage_driver的成員id_table的值。忘記了id_table的可以回去看。它實際上就是一張表格,告訴全世界driver支持怎樣的一些設備。storage_usb_ids同樣來自drivers/usb/storage/usb.c中:
138 static struct usb_device_id storage_usb_ids []= {
139
140 # include"unusual_devs.h"
141 #undef UNUSUAL_DEV
142 #undef USUAL_DEV
143 /*Terminating entry */
144 { }
145 };
這麼一看,us_unusual_dev_list和storage_usb_ids儼然是雙胞胎啊!唯一的區別只是前者多了一個NULL。這裏最莫名其妙的就是包含了一個文件,於是讓我們先來查看這個unusual_devs.h文件到底是幹什麼的?先看一下這個文件最下面的一些行:
1476 /* Control/Bulk transport for all SubClassvalues */
1477 USUAL_DEV(US_SC_RBC, US_PR_CB,USB_US_TYPE_STOR),
1478 USUAL_DEV(US_SC_8020, US_PR_CB,USB_US_TYPE_STOR),
1479 USUAL_DEV(US_SC_QIC, US_PR_CB,USB_US_TYPE_STOR),
1480 USUAL_DEV(US_SC_UFI, US_PR_CB,USB_US_TYPE_STOR),
1481 USUAL_DEV(US_SC_8070, US_PR_CB, USB_US_TYPE_STOR),
1482 USUAL_DEV(US_SC_SCSI, US_PR_CB,USB_US_TYPE_STOR),
1483
1484 /* Control/Bulk/Interrupt transport for allSubClass values */
1485 USUAL_DEV(US_SC_RBC, US_PR_CBI,USB_US_TYPE_STOR),
1486 USUAL_DEV(US_SC_8020, US_PR_CBI,USB_US_TYPE_STOR),
1487 USUAL_DEV(US_SC_QIC, US_PR_CBI,USB_US_TYPE_STOR),
1488 USUAL_DEV(US_SC_UFI, US_PR_CBI,USB_US_TYPE_STOR),
1489 USUAL_DEV(US_SC_8070, US_PR_CBI,USB_US_TYPE_STOR),
1490 USUAL_DEV(US_SC_SCSI, US_PR_CBI,USB_US_TYPE_STOR),
1491
1492 /* Bulk-only transport for all SubClassvalues */
1493 USUAL_DEV(US_SC_RBC, US_PR_BULK,USB_US_TYPE_STOR),
1494 USUAL_DEV(US_SC_8020, US_PR_BULK,USB_US_TYPE_STOR),
1495 USUAL_DEV(US_SC_QIC, US_PR_BULK,USB_US_TYPE_STOR),
1496 USUAL_DEV(US_SC_UFI, US_PR_BULK,USB_US_TYPE_STOR),
1497 USUAL_DEV(US_SC_8070, US_PR_BULK,USB_US_TYPE_STOR),
1498 USUAL_DEV(US_SC_SCSI, US_PR_BULK, 0),
USUAL_DEV以及UNUSUAL_DEV均定義於drivers/usb/storage/usb.c中:
128 #define UNUSUAL_DEV(id_vendor, id_product,bcdDeviceMin, bcdDeviceMax, \
129 vendorName, productName,useProtocol, useTransport, \
130 initFunction, flags) \
131 { USB_DEVICE_VER(id_vendor, id_product,bcdDeviceMin,bcdDeviceMax), \
132 .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
133
134 #define USUAL_DEV(useProto, useTrans, useType)\
135 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE,useProto, useTrans), \
136 .driver_info = (USB_US_TYPE_STOR<<24) }
注意到我們看的是structusb_device_id結構體的數組,其中每一項必然是一個struct usb_device_id的結構體變量。我們先來看USB_DEVICE_VER和USB_INTERFACE_INFO,很顯然這兩個都是宏,來自include/linux/usb.h:
715 /**
716 *USB_DEVICE_VER - macro used to describe a specific usb device with a
717 * version range
718 *@vend: the 16 bit USB Vendor ID
719 *@prod: the 16 bit USB Product ID
720 *@lo: the bcdDevice_lo value
721 *@hi: the bcdDevice_hi value
722 *
723 *This macro is used to create a struct usb_device_id that matches a
724 *specific device, with a version range.
725 */
726 #define USB_DEVICE_VER(vend,prod,lo,hi) \
727 .match_flags =USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, \
728 .idVendor = (vend), .idProduct =(prod), \
729 .bcdDevice_lo = (lo),.bcdDevice_hi = (hi)
744 /**
745 *USB_INTERFACE_INFO - macro used to describe a class of usb interfaces
746 *@cl: bInterfaceClass value
747 *@sc: bInterfaceSubClass value
748 *@pr: bInterfaceProtocol value
749 *
750 *This macro is used to create a struct usb_device_id that matches a
751 *specific class of interfaces.
752 */
753 #define USB_INTERFACE_INFO(cl,sc,pr) \
754 .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass = (cl),\
755 .bInterfaceSubClass = (sc), .bInterfaceProtocol= (pr)
756
每一個USB_DEVICE_VER或者USB_INTERFACE_INFO就是構造一個struct usb_device_id的結構體變量,回顧一下struct usb_device_id的定義,這裏實際上就是爲其中的四個元素賦了值,它們是match_flags、bInterfaceClass、bInterfaceSubClass和bInterfaceProtocol。
這裏不得不說的是,這個世界上有許許多多的USB設備,它們各有各的特點,爲了區分它們,USB規範或者說USB協議,把USB設備分成了很多類,然而每個類又分成子類。這很好理解,我們的大學也是如此,先是分成很多個學院,然後每個學院又被分爲很多個系,比如信息學院,下面分了電子工程系、微電子系、計算機系、通信工程系,然後可能每個系下邊又分了各個專業。USB協議也是,首先每個接口屬於一個Class,(爲什麼是把接口分類,而不把設備分類?前面講過了,在USB設備驅動中,不用再提設備,因爲每個設備驅動對應的是一種接口,而不是一種設備),然後Class下面分了SubClass,接着SubClass下面又按各種設備所遵循的不同的通信協議繼續細分。
USB協議中爲每一種Class、每一種SubClass和每一種Protocol定義一個數值,比如Mass Storage的Class就是0x08,而這裏USB_CLASS_MASS_STORAGE這個宏在include/linux/usb/ch9.h中定義,其值正是8。
我們拿第1477行來舉例。
1477 USUAL_DEV(US_SC_RBC, US_PR_CB,USB_US_TYPE_STOR),
把這個宏展開,就是說定義了這麼一個usb_device_id結構體變量,其match_flags=USB_DEVICE_ID_MATCH_INT_INFO,而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這些關於SubClass的宏的定義是在文件include/linux/usb_usual.h中:
74 #define US_SC_RBC 0x01 /* Typically, flash devices */
75 #define US_SC_8020 0x02 /* CD-ROM */
76 #define US_SC_QIC 0x03 /* QIC-157 Tapes */
77 #define US_SC_UFI 0x04 /* Floppy */
78 #define US_SC_8070 0x05 /* Removable media */
79 #define US_SC_SCSI 0x06 /* Transparent */
80 #define US_SC_ISD200 0x07 /* ISD200 ATA */
81 #define US_SC_MIN US_SC_RBC
82 #define US_SC_MAX US_SC_ISD200
83
84 #define US_SC_DEVICE 0xff /* Use device's value */
而像US_PR_CB這些關於傳輸協議的宏也定義於同一個文件中:
88 #define US_PR_CBI 0x00 /* Control/Bulk/Interrupt */
89 #define US_PR_CB 0x01 /* Control/Bulk w/o interrupt */
90 #define US_PR_BULK 0x50 /* bulk only */
91 #ifdef CONFIG_USB_STORAGE_USBAT
92 #define US_PR_USBAT 0x80 /* SCM-ATAPI bridge */
93 #endif
94 #ifdef CONFIG_USB_STORAGE_SDDR09
95 #define US_PR_EUSB_SDDR09 0x81 /* SCM-SCSI bridge for SDDR-09 */
96 #endif
97 #ifdef CONFIG_USB_STORAGE_SDDR55
98 #define US_PR_SDDR55 0x82 /* SDDR-55 (made up) */
99 #endif
100 #define US_PR_DPCM_USB 0xf0 /* Combination CB/SDDR09 */
101 #ifdef CONFIG_USB_STORAGE_FREECOM
102 #define US_PR_FREECOM 0xf1 /* Freecom */
103 #endif
104 #ifdef CONFIG_USB_STORAGE_DATAFAB
105 #define US_PR_DATAFAB 0xf2 /* Datafab chipsets */
106 #endif
107 #ifdef CONFIG_USB_STORAGE_JUMPSHOT
108 #define US_PR_JUMPSHOT 0xf3 /* Lexar Jumpshot */
109 #endif
110 #ifdef CONFIG_USB_STORAGE_ALAUDA
111 #define US_PR_ALAUDA 0xf4 /* Alauda chipsets */
112 #endif
113 #ifdef CONFIG_USB_STORAGE_KARMA
114 #define US_PR_KARMA 0xf5 /* Rio Karma */
115 #endif
116
117 #define US_PR_DEVICE 0xff /* Use device's value */
說了這麼多,U盤屬於其中的哪一種呢?USB協議中規定,U盤的SubClass是屬於US_SC_SCSI的,而其通信協議使用的是Bulk-Only的,即這裏看到的US_PR_BULK。顯然這些東西我們後來都會用得上。
那麼這裏還有一個match_flag,它又是表示什麼意思?USB_INTERFACE_INFO這個宏好像把所有的設備的match_flag都給設成了USB_DEVICE_ID_MATCH_INT_INFO,這是爲什麼?這個宏來自include/linux/usb.h:
699 #define USB_DEVICE_ID_MATCH_INT_INFO \
700 (USB_DEVICE_ID_MATCH_INT_CLASS | \
701 USB_DEVICE_ID_MATCH_INT_SUBCLASS | \
702 USB_DEVICE_ID_MATCH_INT_PROTOCOL)
match_flag這個東西是給USB Core去用的,USB Core負責給設備尋找適合它的驅動,負責給驅動尋找適合它的設備,它所比較的就是struct usb_device_id的變量,而struct usb_device_id結構體中有許多成員,那麼是不是一定要把每一個成員都給比較一下呢?其實就是告訴USB Core,你只要比較bInterfaceClass,bInterfaceSubClass和bInterfaceProtocol即可。include/linux/mod_devicetable.h中針對struct usb_device_id中的每一個要比較的項定義了一個宏:
122 /* Some useful macros to use to create structusb_device_id */
123 #define USB_DEVICE_ID_MATCH_VENDOR 0x0001
124 #define USB_DEVICE_ID_MATCH_PRODUCT 0x0002
125 #define USB_DEVICE_ID_MATCH_DEV_LO 0x0004
126 #define USB_DEVICE_ID_MATCH_DEV_HI 0x0008
127 #define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010
128 #define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020
129 #define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040
130 #define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080
131 #define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100
132 #define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200
回去對比一下structusb_device_id就知道這些宏是什麼意思了。
但是你一定有一個疑問,那就是爲什麼會有一個USUAL_DEV和一個UNUSUAL_DEV這樣兩個宏的存在,它們之間有什麼區別呢?顧名思義,有些設備屬於普通設備,而有些設備卻並不是普通設備,它們或者是有一些別的設備不具備的特性,或者是他們遵循的通信協議有些與衆不同,比如,它既不是Bulk-Only也不是CBI,像這些不按常理出牌的設備,寫代碼的人把它們單獨給列了出來。當然,從大的分類來看,它們依然是屬於USB Mass Storage這個類別的,否則也沒必要放在這個目錄下面了。
爲了包容這些另類的設備,偉大的Linux內核開發人員們爲它們準備了一個文件,它就是讓諸多USB Mass Storage設備廠家歡欣鼓舞的unusual_devs.h,有了它,廠家們不用再爲自己的設備不被Linux內核支持而煩惱了。