《Linux那些事兒之我是USB》我是U盤(15)冬天來了,春天還會遠嗎?(一)

在整個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內核支持而煩惱了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章