從協議中來,到協議中去(上)
在structusb_driver中,.probe和.disconnect的原型如下:
836 int(*probe) (struct usb_interface *intf,
837 const struct usb_device_id *id);
838
839 void(*disconnect) (struct usb_interface *intf);
我們來看其中的參數,structusb_device_id這個不用說了,剛纔已經介紹過,那麼struct usb_interface從何而來?還是讓我們先從struct usb_device說起。
我們知道每一個設備對應一個struct device結構體變量,但是設備不可能是萬能的,生命是多樣性的,就像我們可以用“人”來統稱全人類,但是分得細一點,又有男人和女人的區別。那麼設備也一樣,由於有各種各樣的設備,於是又出來了更多的詞彙(數據結構),比如針對USB設備,開發人員們設計了一個叫做struct usb_device的結構體。它定義於include/linux/usb.h:
336 struct usb_device {
337 int devnum; /* Address on USBbus */
338 char devpath [16]; /* Use in messages: /port/port/... */
339 enumusb_device_state state;/*configured, not attached, etc */
340 enum usb_device_speed speed; /* high/full/low (or error) */
341
342 structusb_tt *tt; /* low/full speed dev, highspeed hub */
343 int ttport; /* device port onthat tt hub */
344
345 unsigned inttoggle[2]; /* one bit foreach endpoint
346 * ([0] = IN, [1] = OUT) */
347
348 structusb_device *parent; /* ourhub, unless we're the root */
349 structusb_bus *bus; /* Bus we're part of */
350 structusb_host_endpoint ep0;
351
352 structdevice dev; /* Generic device interface */
353
354 structusb_device_descriptor descriptor;/* Descriptor */
355 struct usb_host_config *config; /*All of the configs */
356
357 structusb_host_config *actconfig;/* the active configuration */
358 structusb_host_endpoint *ep_in[16];
359 structusb_host_endpoint *ep_out[16];
360
361 char**rawdescriptors; /* Raw descriptors for eachconfig */
362
363 unsignedshort bus_mA; /* Current available from thebus */
364 u8portnum; /* Parent port number (origin 1) */
365 u8level; /* Number of USB hub ancestors */
366
367 unsigneddiscon_suspended:1; /* Disconnected while suspended */
368 unsignedhave_langid:1; /* whether string_langid is valid */
369 intstring_langid; /* language ID for strings */
370
371 /* staticstrings from the device */
372 char*product; /* iProduct string, if present */
373 char*manufacturer; /* iManufacturer string, if present */
374 char*serial; /* iSerialNumber string, if present */
375
376 structlist_head filelist;
377 #ifdef CONFIG_USB_DEVICE_CLASS
378 structdevice *usb_classdev;
379 #endif
380 #ifdef CONFIG_USB_DEVICEFS
381 structdentry *usbfs_dentry;/*usbfs dentry entry for the device*/
382 #endif
383 /*
384 * Child devices - these can be eithernew devices
385 * (if this is a hub device), ordifferent instances
386 * of this same device.
387 *
388 * Each instance needs its own set ofdata structures.
389 */
390
391 intmaxchild; /* Number of ports if hub */
392 structusb_device *children[USB_MAXCHILDREN];
393
394 intpm_usage_cnt; /* usage counter for autosuspend */
395 u32quirks; /* quirks of the whole device */
396
397 #ifdef CONFIG_PM
398 structdelayed_work autosuspend; /* for delayed autosuspends */
399 struct mutex pm_mutex; /* protectsPM operations */
400
401 unsignedlong last_busy; /* time of last use */
402 intautosuspend_delay; /* injiffies */
403
404 unsignedauto_pm:1; /*autosuspend/resume in progress */
405 unsigneddo_remote_wakeup:1;/* remote wakeup should be enabled */
406 unsignedautosuspend_disabled:1; /* autosuspend and autoresume */
407 unsignedautoresume_disabled:1; /* disabled by the user */
408 #endif
409 };
410 #define to_usb_device(d) container_of(d,struct usb_device, dev)
看起來很複雜的一個數據結構,不過我們目前不需要去理解她的每一個成員,不過我們可以看到,其中有一個成員struct device dev,這就是前面說的那個屬於每個設備的struct device結構體變量。
實際上,U盤驅動裏邊並不會直接去處理這個結構體,因爲對於一個U盤來說,它就是對應這麼一個struct usb_device的變量,這個變量由USB Core負責申請和賦值。但是我們需要記住這個結構體變量,因爲日後我們調用USBCore提供的函數時,會把這個變量作爲參數傳遞上去。因爲很簡單,要和USB Core交流,總得讓人家知道我們是誰吧。比如後來要調用的一個函數,usb_buffer_alloc,它就需要這個參數。
而對U盤設備驅動來說,比這個struct usb_device更重要的數據結構是,struct usb_interface。走到這一步,我們不得不去了解一些USB設備的規範了,或者專業一點說,USB協議。因爲我們至少要知道什麼是USB接口(Interface)。
從協議中來,到協議中去(中)
任何事物都有其要遵守的規矩。USB設備要遵循的就是USB協議。 不管是軟件還是硬件,在設計的開始,總是要參考USB協議。怎麼設計硬件?如何編寫軟件?不看USB協議,誰也不可能憑空想象出來。
USB協議規定了,每個USB設備都得有一些基本的元素,稱爲描述符。有四類描述符是任何一種USB設備都得有的,它們是,設備描述符(Device Descriptor),配置描述符(ConfigurationDescriptor),接口描述符(Interface Descriptor),端點描述符(Endpoint Descriptor)。描述符裏的東西是一個設備出廠時就被廠家給固化在設備中了。這種東西不管怎樣也改變不了,比如我有一個Intel的U盤,裏面的固有的信息肯定是在Intel出廠時就被烙在裏邊了,廠家早已把它的一切,烙上Intel印。所以當我插入U盤,用cat /proc/scsi/scsi命令看一下的話,“Vendor”一項顯示的肯定是Intel。
關於這幾種描述符,USB Core在總線掃描就會去讀取,獲得裏邊的信息,其中,設備描述符描述的是整個設備。注意了,這個設備和咱們一直講的設備驅動那裏的設備是不一樣的。因爲一個USB設備實際上指的是一種宏觀上的概念,它可以是一種多功能的設備,改革開放之後,多功能的東西越來越多了,比如外企常見的多功能一體機,就是集打印機、複印機、掃描儀、傳真機於一體的設備。當然,這不屬於USB設備,但是USB設備當然也有這種情況,比如電臺DJ可能會用到的,一個鍵盤,上邊帶一個揚聲器,它們用兩個USB接口接到USB Hub上去,而設備描述符描述的就是這整個設備的特點。
那麼配置描述符呢?老實說,對我們瞭解U盤驅動真是沒有什麼意義,但是作爲一個有責任的人,此刻,我必須爲它多說幾句,一個設備可以有一種或者幾種配置。沒見過具體的USB設備?那麼好,手機見過吧,每個手機都會有多種配置,或者說“設定”,比如,我的這款,Nokia 6300。手機語言可以設定爲English、繁體中文或簡體中文。一旦選擇了其中一種,那麼手機裏面所顯示的所有的信息都是該種語言/字體。還有最簡單的例子,操作模式也有好幾種,標準、無聲、會議等。基本上如果我設爲“會議”,那麼就是隻振動不發聲;要是設爲無聲,那麼就什麼動靜也不會有,只能憑感覺了。那麼USB設備的配置也是如此,不同的USB設備當然有不同的配置了,或者說需要配置哪些東西也會不一樣。好了,關於配置,就說這麼多。
對於USB設備驅動程序編寫者來說,更爲關鍵的是下面的接口和端點。先說接口。第一句,一個接口對應一個USB設備驅動程序。沒錯,還舉前邊那個例子。一個USB設備,兩種功能,一個鍵盤,上面帶一個揚聲器,兩個接口,那肯定得要兩個驅動程序,一個是鍵盤驅動程序,一個是音頻流驅動程序。“道上”的兄弟喜歡把這樣兩個整合在一起的東西叫做一個設備,我門用接口來區分這兩者。於是有了我們前面提到的那個數據結構,struct usb_interface,它定義於include/linux/usb.h:
140 struct usb_interface {
141 /* array of alternate settings forthis interface,
142 * stored in no particular order */
143 struct usb_host_interface *altsetting;
144
145 struct usb_host_interface*cur_altsetting; /* the currently
146 * active alternate setting */
147 unsignednum_altsetting; /* number of alternatesettings */
148
149 int minor; /* minor number this interface is
150 * bound to */
151 enumusb_interface_condition condition; /* state of binding */
152 unsignedis_active:1; /* the interfaceis not suspended */
153 unsignedneeds_remote_wakeup:1; /*driver requires remote wakeup*/
154
155 structdevice dev; /* interface specific device info */
156 struct device *usb_dev;/* pointer to the usbclass's device, if any*/
157 int pm_usage_cnt; /* usage counter for autosuspend */
158 };
159 #defineto_usb_interface(d) container_of(d, struct usb_interface, dev)
160 #define interface_to_usbdev(intf) \
161 container_of(intf->dev.parent, struct usb_device, dev)
這個結構體是一個貫穿整個U盤驅動程序的,所以雖然我們不用去深入瞭解,但是需要記住,整個U盤驅動程序在後面任何一處提到的struct usb_interface都是同一個變量,這個變量是在USB Core總線掃描時就申請好了的。我們只需要直接用就是了,比如前面說過的storage_probe(struct usb_interface *intf,const struct usb_device_id*id),storage_disconnect(structusb_interface *intf)這兩個函數中的參數intf。
而這裏130行的宏interface_to_usbdev,也會用得着的,顧名思義,就是從一個structusb_interface轉換成一個structusb_device,我們說過了,有些函數需要的參數就是struct usb_device,而不是usb_interface,所以這種轉換是經常會用到的,而這個宏,USB Core的設計者們也爲我們準備好了,除了感激,我們還能說什麼呢?
從協議中來,到協議中去(下)
如果你是急性子,那這時候你一定很想開始看storage_probe函數了,因爲整個U盤的工作就是從這裏開始的。
前面我們已經瞭解了設備、配置和接口,還剩最後一個就是端點。USB通信的最基本的形式就是通過端點,一個接口有一個或多個端點,而作爲像U盤這樣的存儲設備,它至少有一個控制端點,兩個批量端點。這些端點都是幹什麼用的?說來話長,真是一言難盡啊。
USB協議中規定了,USB設備有四種通信方式,分別是控制傳輸、中斷傳輸、批量傳輸、等時傳輸。其中,等時傳輸顯然是用於音頻和視頻一類的設備,這類設備期望能夠有一個比較穩定的數據流,比如你在網上QQ視頻聊天,肯定希望每分鐘傳輸的圖像/聲音速率是比較穩定的。usb-storage裏邊肯定不會用到等時傳輸。因爲我們只管複製一個文件,管它第一秒和第二秒的傳輸有什麼區別,只要幾十秒內傳完了就行了。
相比之下,等時傳輸是四種傳輸中最麻煩的,所以,U盤用不着。不過我要說,中斷傳輸也用不着,對於U盤來說,的確用不着,雖然說USBMass Storage的協議中邊有一個叫做CBI的傳輸協議,CBI就是Control/Bulk/Interrupt,即控制/批量/中斷,這三種傳輸都會用到,但這種傳輸協議並不適用於U盤,U盤使用的是叫做Bulk-Only的傳輸協議。使用這種協議的設備只有兩種傳輸方式,一種是批量傳輸,另一種是控制傳輸,控制傳輸是任何一種USB設備都必須支持的,它專門用於傳輸一些控制信息。比如我想查詢一下關於這個接口的一些信息,那麼就用控制傳輸。而批量傳輸,它就是U盤的主要工作了,讀寫數據,這種情況就得用批量傳輸。具體的傳輸我們後面再講。
好了,知道了傳輸方式,就可以來認識端點了。和端點齊名的有一個叫做管道,或者有文化的人管這個叫Pipe。端點就是通信的發送點或者接收點,要發送數據,那你只要把數據發送到正確的端點那裏就可以了。之所以U盤有兩個批量端點,是因爲端點也是有方向的,一個叫做Bulk IN,一個叫做Bulk OUT。從USB主機到設備稱爲OUT,從設備到主機稱爲IN。而管道實際上只是爲了讓我們能夠找到端點,就相當於我們日常說的郵編地址,比如一個國家,爲了通信,我們必須給各個地方取名,給各條大大小小的路取名,比如要從某偏僻的小縣城出發,要到北京,那你的這個端點就是北京,而你得知道你來北京的路線,那這個從你們縣城到北京的路線就算一條管道。有人好奇地問了,管道應該有兩個端點吧,一個端點是北京,那另一個端點呢?答案是,這條管道有些特殊,我們只需要知道一端的目的地是北京,而另一端是哪裏無所謂,因爲不管你在哪裏你都得到北京。
嚴格來說,管道的另一端應該是USB主機,USB協議中邊也是這麼規定的,協議中管道代表着一種能力。怎樣一種能力呢?在主機和設備上的端點之間移動數據,聽上去挺玄的。因爲事實上,USB裏邊所有的數據傳輸都是由主機發起的。一切都是以主機爲核心,各種設備緊緊圍繞在主機周圍。所以USB Core裏邊很多函數就是爲了讓USB主機能夠正確地完成數據傳輸或者說傳輸調度,就得告訴主機這個管道,換而言之,它得知道自己這次調度的數據是傳送給誰,或者從誰那裏傳輸過來。不過有人又要問了,比如說要從U盤裏讀一個文件,那告訴USB主機某個端點能有用嗎?那個文件又不是存放在一個端點裏邊,它不是存放在U盤裏面嗎?這個就只能在後面的代碼裏去知道了。