小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

《Linux那些事兒之我是USB》我是U盤(11)從協(xié)議中來到協(xié)議中去

 orion360doc 2011-07-27

《Linux那些事兒之我是USB》我是U盤(11)從協(xié)議中來到協(xié)議中去

分類: 《Linux那些事兒之我是USB》 660人閱讀 評(píng)論(2) 收藏 舉報(bào)

 

從協(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è)就只能在后面的代碼里去知道了。

分享到:

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多