| 
 從協(xié)議中來,到協(xié)議中去(上) 在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); 我們來看其中的參數(shù),structusb_device_id這個(gè)不用說了,剛才已經(jīng)介紹過,那么struct usb_interface從何而來?還是讓我們先從struct usb_device說起。 我們知道每一個(gè)設(shè)備對(duì)應(yīng)一個(gè)struct device結(jié)構(gòu)體變量,但是設(shè)備不可能是萬能的,生命是多樣性的,就像我們可以用“人”來統(tǒng)稱全人類,但是分得細(xì)一點(diǎn),又有男人和女人的區(qū)別。那么設(shè)備也一樣,由于有各種各樣的設(shè)備,于是又出來了更多的詞匯(數(shù)據(jù)結(jié)構(gòu)),比如針對(duì)USB設(shè)備,開發(fā)人員們?cè)O(shè)計(jì)了一個(gè)叫做struct usb_device的結(jié)構(gòu)體。它定義于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) 看起來很復(fù)雜的一個(gè)數(shù)據(jù)結(jié)構(gòu),不過我們目前不需要去理解她的每一個(gè)成員,不過我們可以看到,其中有一個(gè)成員struct device dev,這就是前面說的那個(gè)屬于每個(gè)設(shè)備的struct device結(jié)構(gòu)體變量。 實(shí)際上,U盤驅(qū)動(dòng)里邊并不會(huì)直接去處理這個(gè)結(jié)構(gòu)體,因?yàn)閷?duì)于一個(gè)U盤來說,它就是對(duì)應(yīng)這么一個(gè)struct usb_device的變量,這個(gè)變量由USB Core負(fù)責(zé)申請(qǐng)和賦值。但是我們需要記住這個(gè)結(jié)構(gòu)體變量,因?yàn)槿蘸笪覀冋{(diào)用USBCore提供的函數(shù)時(shí),會(huì)把這個(gè)變量作為參數(shù)傳遞上去。因?yàn)楹芎?jiǎn)單,要和USB Core交流,總得讓人家知道我們是誰(shuí)吧。比如后來要調(diào)用的一個(gè)函數(shù),usb_buffer_alloc,它就需要這個(gè)參數(shù)。 而對(duì)U盤設(shè)備驅(qū)動(dòng)來說,比這個(gè)struct usb_device更重要的數(shù)據(jù)結(jié)構(gòu)是,struct usb_interface。走到這一步,我們不得不去了解一些USB設(shè)備的規(guī)范了,或者專業(yè)一點(diǎn)說,USB協(xié)議。因?yàn)槲覀冎辽僖朗裁词荱SB接口(Interface)。 從協(xié)議中來,到協(xié)議中去(中) 任何事物都有其要遵守的規(guī)矩。USB設(shè)備要遵循的就是USB協(xié)議。 不管是軟件還是硬件,在設(shè)計(jì)的開始,總是要參考USB協(xié)議。怎么設(shè)計(jì)硬件?如何編寫軟件?不看USB協(xié)議,誰(shuí)也不可能憑空想象出來。 USB協(xié)議規(guī)定了,每個(gè)USB設(shè)備都得有一些基本的元素,稱為描述符。有四類描述符是任何一種USB設(shè)備都得有的,它們是,設(shè)備描述符(Device Descriptor),配置描述符(ConfigurationDescriptor),接口描述符(Interface Descriptor),端點(diǎn)描述符(Endpoint Descriptor)。描述符里的東西是一個(gè)設(shè)備出廠時(shí)就被廠家給固化在設(shè)備中了。這種東西不管怎樣也改變不了,比如我有一個(gè)Intel的U盤,里面的固有的信息肯定是在Intel出廠時(shí)就被烙在里邊了,廠家早已把它的一切,烙上Intel印。所以當(dāng)我插入U(xiǎn)盤,用cat /proc/scsi/scsi命令看一下的話,“Vendor”一項(xiàng)顯示的肯定是Intel。 關(guān)于這幾種描述符,USB Core在總線掃描就會(huì)去讀取,獲得里邊的信息,其中,設(shè)備描述符描述的是整個(gè)設(shè)備。注意了,這個(gè)設(shè)備和咱們一直講的設(shè)備驅(qū)動(dòng)那里的設(shè)備是不一樣的。因?yàn)橐粋€(gè)USB設(shè)備實(shí)際上指的是一種宏觀上的概念,它可以是一種多功能的設(shè)備,改革開放之后,多功能的東西越來越多了,比如外企常見的多功能一體機(jī),就是集打印機(jī)、復(fù)印機(jī)、掃描儀、傳真機(jī)于一體的設(shè)備。當(dāng)然,這不屬于USB設(shè)備,但是USB設(shè)備當(dāng)然也有這種情況,比如電臺(tái)DJ可能會(huì)用到的,一個(gè)鍵盤,上邊帶一個(gè)揚(yáng)聲器,它們用兩個(gè)USB接口接到USB Hub上去,而設(shè)備描述符描述的就是這整個(gè)設(shè)備的特點(diǎn)。 那么配置描述符呢?老實(shí)說,對(duì)我們了解U盤驅(qū)動(dòng)真是沒有什么意義,但是作為一個(gè)有責(zé)任的人,此刻,我必須為它多說幾句,一個(gè)設(shè)備可以有一種或者幾種配置。沒見過具體的USB設(shè)備?那么好,手機(jī)見過吧,每個(gè)手機(jī)都會(huì)有多種配置,或者說“設(shè)定”,比如,我的這款,Nokia 6300。手機(jī)語(yǔ)言可以設(shè)定為English、繁體中文或簡(jiǎn)體中文。一旦選擇了其中一種,那么手機(jī)里面所顯示的所有的信息都是該種語(yǔ)言/字體。還有最簡(jiǎn)單的例子,操作模式也有好幾種,標(biāo)準(zhǔn)、無聲、會(huì)議等。基本上如果我設(shè)為“會(huì)議”,那么就是只振動(dòng)不發(fā)聲;要是設(shè)為無聲,那么就什么動(dòng)靜也不會(huì)有,只能憑感覺了。那么USB設(shè)備的配置也是如此,不同的USB設(shè)備當(dāng)然有不同的配置了,或者說需要配置哪些東西也會(huì)不一樣。好了,關(guān)于配置,就說這么多。 對(duì)于USB設(shè)備驅(qū)動(dòng)程序編寫者來說,更為關(guān)鍵的是下面的接口和端點(diǎn)。先說接口。第一句,一個(gè)接口對(duì)應(yīng)一個(gè)USB設(shè)備驅(qū)動(dòng)程序。沒錯(cuò),還舉前邊那個(gè)例子。一個(gè)USB設(shè)備,兩種功能,一個(gè)鍵盤,上面帶一個(gè)揚(yáng)聲器,兩個(gè)接口,那肯定得要兩個(gè)驅(qū)動(dòng)程序,一個(gè)是鍵盤驅(qū)動(dòng)程序,一個(gè)是音頻流驅(qū)動(dòng)程序。“道上”的兄弟喜歡把這樣兩個(gè)整合在一起的東西叫做一個(gè)設(shè)備,我門用接口來區(qū)分這兩者。于是有了我們前面提到的那個(gè)數(shù)據(jù)結(jié)構(gòu),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) 這個(gè)結(jié)構(gòu)體是一個(gè)貫穿整個(gè)U盤驅(qū)動(dòng)程序的,所以雖然我們不用去深入了解,但是需要記住,整個(gè)U盤驅(qū)動(dòng)程序在后面任何一處提到的struct usb_interface都是同一個(gè)變量,這個(gè)變量是在USB Core總線掃描時(shí)就申請(qǐng)好了的。我們只需要直接用就是了,比如前面說過的storage_probe(struct usb_interface *intf,const struct usb_device_id*id),storage_disconnect(structusb_interface *intf)這兩個(gè)函數(shù)中的參數(shù)intf。 而這里130行的宏interface_to_usbdev,也會(huì)用得著的,顧名思義,就是從一個(gè)structusb_interface轉(zhuǎn)換成一個(gè)structusb_device,我們說過了,有些函數(shù)需要的參數(shù)就是struct usb_device,而不是usb_interface,所以這種轉(zhuǎn)換是經(jīng)常會(huì)用到的,而這個(gè)宏,USB Core的設(shè)計(jì)者們也為我們準(zhǔn)備好了,除了感激,我們還能說什么呢? 
 從協(xié)議中來,到協(xié)議中去(下) 如果你是急性子,那這時(shí)候你一定很想開始看storage_probe函數(shù)了,因?yàn)檎麄€(gè)U盤的工作就是從這里開始的。 前面我們已經(jīng)了解了設(shè)備、配置和接口,還剩最后一個(gè)就是端點(diǎn)。USB通信的最基本的形式就是通過端點(diǎn),一個(gè)接口有一個(gè)或多個(gè)端點(diǎn),而作為像U盤這樣的存儲(chǔ)設(shè)備,它至少有一個(gè)控制端點(diǎn),兩個(gè)批量端點(diǎn)。這些端點(diǎn)都是干什么用的?說來話長(zhǎng),真是一言難盡啊。 USB協(xié)議中規(guī)定了,USB設(shè)備有四種通信方式,分別是控制傳輸、中斷傳輸、批量傳輸、等時(shí)傳輸。其中,等時(shí)傳輸顯然是用于音頻和視頻一類的設(shè)備,這類設(shè)備期望能夠有一個(gè)比較穩(wěn)定的數(shù)據(jù)流,比如你在網(wǎng)上QQ視頻聊天,肯定希望每分鐘傳輸?shù)膱D像/聲音速率是比較穩(wěn)定的。usb-storage里邊肯定不會(huì)用到等時(shí)傳輸。因?yàn)槲覀冎还軓?fù)制一個(gè)文件,管它第一秒和第二秒的傳輸有什么區(qū)別,只要幾十秒內(nèi)傳完了就行了。 相比之下,等時(shí)傳輸是四種傳輸中最麻煩的,所以,U盤用不著。不過我要說,中斷傳輸也用不著,對(duì)于U盤來說,的確用不著,雖然說USBMass Storage的協(xié)議中邊有一個(gè)叫做CBI的傳輸協(xié)議,CBI就是Control/Bulk/Interrupt,即控制/批量/中斷,這三種傳輸都會(huì)用到,但這種傳輸協(xié)議并不適用于U盤,U盤使用的是叫做Bulk-Only的傳輸協(xié)議。使用這種協(xié)議的設(shè)備只有兩種傳輸方式,一種是批量傳輸,另一種是控制傳輸,控制傳輸是任何一種USB設(shè)備都必須支持的,它專門用于傳輸一些控制信息。比如我想查詢一下關(guān)于這個(gè)接口的一些信息,那么就用控制傳輸。而批量傳輸,它就是U盤的主要工作了,讀寫數(shù)據(jù),這種情況就得用批量傳輸。具體的傳輸我們后面再講。 好了,知道了傳輸方式,就可以來認(rèn)識(shí)端點(diǎn)了。和端點(diǎn)齊名的有一個(gè)叫做管道,或者有文化的人管這個(gè)叫Pipe。端點(diǎn)就是通信的發(fā)送點(diǎn)或者接收點(diǎn),要發(fā)送數(shù)據(jù),那你只要把數(shù)據(jù)發(fā)送到正確的端點(diǎn)那里就可以了。之所以U盤有兩個(gè)批量端點(diǎn),是因?yàn)槎它c(diǎn)也是有方向的,一個(gè)叫做Bulk 
IN,一個(gè)叫做Bulk 
OUT。從USB主機(jī)到設(shè)備稱為OUT,從設(shè)備到主機(jī)稱為IN。而管道實(shí)際上只是為了讓我們能夠找到端點(diǎn),就相當(dāng)于我們?nèi)粘Uf的郵編地址,比如一個(gè)國(guó)家,為了通信,我們必須給各個(gè)地方取名,給各條大大小小的路取名,比如要從某偏僻的小縣城出發(fā),要到北京,那你的這個(gè)端點(diǎn)就是北京,而你得知道你來北京的路線,那這個(gè)從你們縣城到北京的路線就算一條管道。有人好奇地問了,管道應(yīng)該有兩個(gè)端點(diǎn)吧,一個(gè)端點(diǎn)是北京,那另一個(gè)端點(diǎn)呢?答案是,這條管道有些特殊,我們只需要知道一端的目的地是北京,而另一端是哪里無所謂,因?yàn)椴还苣阍谀睦锬愣嫉玫奖本?/p>嚴(yán)格來說,管道的另一端應(yīng)該是USB主機(jī),USB協(xié)議中邊也是這么規(guī)定的,協(xié)議中管道代表著一種能力。怎樣一種能力呢?在主機(jī)和設(shè)備上的端點(diǎn)之間移動(dòng)數(shù)據(jù),聽上去挺玄的。因?yàn)槭聦?shí)上,USB里邊所有的數(shù)據(jù)傳輸都是由主機(jī)發(fā)起的。一切都是以主機(jī)為核心,各種設(shè)備緊緊圍繞在主機(jī)周圍。所以USB 
Core里邊很多函數(shù)就是為了讓USB主機(jī)能夠正確地完成數(shù)據(jù)傳輸或者說傳輸調(diào)度,就得告訴主機(jī)這個(gè)管道,換而言之,它得知道自己這次調(diào)度的數(shù)據(jù)是傳送給誰(shuí),或者從誰(shuí)那里傳輸過來。不過有人又要問了,比如說要從U盤里讀一個(gè)文件,那告訴USB主機(jī)某個(gè)端點(diǎn)能有用嗎?那個(gè)文件又不是存放在一個(gè)端點(diǎn)里邊,它不是存放在U盤里面嗎?這個(gè)就只能在后面的代碼里去知道了。 | 
|  |