USB總線是一種典型的熱插拔的總線標(biāo)準(zhǔn),由于其優(yōu)異的性能幾乎成為了當(dāng)下大小設(shè)備中的標(biāo)配。
USB的驅(qū)動可以分為3類:SoC的USB控制器的驅(qū)動,主機端USB設(shè)備的驅(qū)動,設(shè)備上的USB Gadget驅(qū)動,通常,對于USB這種標(biāo)準(zhǔn)化的設(shè)備,內(nèi)核已經(jīng)將主機控制器的驅(qū)動編寫好了,設(shè)備上的Gadget驅(qū)動通常只運行固件程序而不是基于Linux, 所以驅(qū)動工程師的主要工作就是編寫主機端的USB設(shè)備驅(qū)動。
USB子系統(tǒng)框架
下圖表示了Linux中USB子系統(tǒng)的框架結(jié)構(gòu),和i2c一樣,USB子系統(tǒng)也可分為三層:**設(shè)備驅(qū)動層--USB核心--控制器驅(qū)動層*
作為熱插拔總線, USB和非熱插拔總線最大的區(qū)別就是總線無法事前獲知設(shè)備的信息以及設(shè)備何時被插入或拔出,所以也就不能使用任意一種形式將設(shè)備信息事前寫入內(nèi)核。
為了解決由于熱插拔引起的設(shè)備識別問題,USB總線通過枚舉的方式來獲取一個接入總線的USB設(shè)備的設(shè)備信息——一個由device->config->interface->endpoint逐級描述的設(shè)備,基于分離的思想,USB子系統(tǒng)中設(shè)計了一組結(jié)構(gòu)來描述這幾個維度的設(shè)備信息,相比之下,i2c總線只要一個i2c_client即可描述一個設(shè)備.
USB總線上的所有通信都是由主機發(fā)起的,所以本質(zhì)上,USB都是采用輪詢的方式進(jìn)行的。USB總線會使用輪詢的方式不斷檢測總線上是否有設(shè)備接入,如果有設(shè)備接入相應(yīng)的D+D-就會有電平變化。然后總線就會按照USB規(guī)定的協(xié)議與設(shè)備進(jìn)行通信,設(shè)備將存儲在自身的設(shè)備信息依次交給主機,主機將這些信息按照4層模型組織起來。上報到內(nèi)核,內(nèi)核中的USB子系統(tǒng)再去匹配相應(yīng)的驅(qū)動,USB設(shè)備驅(qū)動是面向interface這一層次的信息的
作為一種高度標(biāo)準(zhǔn)化的設(shè)備, 雖然USB本身十分復(fù)雜, 但是內(nèi)核已經(jīng)為我們完成了相當(dāng)多的工作, 下述的常用設(shè)備驅(qū)動在內(nèi)核中已經(jīng)實現(xiàn)了。很多時候, 驅(qū)動的難度不是看設(shè)備的復(fù)雜程度, 而是看標(biāo)準(zhǔn)化程度
音頻設(shè)備類
通信設(shè)備類
HID設(shè)備類
顯示設(shè)備類
海量存儲設(shè)備類
電源設(shè)備類
打印設(shè)備類
集線器設(shè)備類
核心結(jié)構(gòu)和方法簡述
核心結(jié)構(gòu)
基于分離的思想,USB子系統(tǒng)也提供了描述一個USB設(shè)備的結(jié)構(gòu),只不過基于USB協(xié)議,完整描述一個USB設(shè)備信息需要9個結(jié)構(gòu),這些結(jié)構(gòu)中,前4個用來描述一個USB設(shè)備的硬件信息,即設(shè)備本身的信息,這些信息是寫入到設(shè)備的eeprom的,在任何USB主機中看到的都一樣,這些信息可以使用lsusb -v命令來查看; 后5個描述一個USB設(shè)備的軟件信息,即除了硬件信息之外,Linux為了管理一個USB設(shè)備還要封裝一些信息,是OS-specific的信息; USB設(shè)備硬件信息和軟件信息的關(guān)系類似于中斷子系統(tǒng)中的硬件中斷和內(nèi)核中斷,只不過更復(fù)雜一點。