Linux driver編寫思考
linux 下面對 driver 的定義:
struct device_driver {
const char * name;
struct bus_type * bus;
struct completion unloaded;
struct kobject kobj;
struct klist klist_devices;
struct klist_node knode_bus;
struct module * owner;
const char * mod_name; /* used for built-in modules */
struct module_kobject * mkobj;
int (*probe) (struct device * dev);
int (*remove) (struct device * dev);
void (*shutdown) (struct device * dev);
int (*suspend) (struct device * dev, pm_message_t state);
int (*resume) (struct device * dev);
unsigned int multithread_probe:1;
};
我們一個個來看,
Name :就是這個 driver 的名字;
Bus :就是這個 driver 是掛在上面 bus 上面的;
Unloaded :這個以后再討論;
Kobj :這個可以理解為 driver 結構的父親,如果從面向對象的角度來看的話;
Klist_devices: 這個就是由此 driver 驅動的設備列表;
Knode_bus: 這個就是用來掛在它說屬的 bus 鏈表上的節點,順著這個鏈表就可以找到所有的掛在這個 bus 上的所有的 driver ;
Owner :這個 driver 所屬的模塊;
Mod_name: 模塊名字;
mkobj: 模塊的頂層描述;
probe :這個是很關鍵的函數,用來初始化此 driver 驅動的硬件,還有其它能夠正常為應用層提供服務說需要提前做的事都需要在這里做;
remove :這個就是移除的時候做的事情;
suspend :這個應該是睡眠的時候做的事情,也就是說上層通過這個函數實現對硬件的電源策略控制;
resume :這個就是從睡眠中醒來需要對硬件所做的事都需要在這里做;
multithread_probe :是否啟用多線程 probe ;
分析完了 driver 的結構,我們看看為什么需要這樣的設計,也就是說,如果我們自己需要實現一套架構用來實現同樣的功能,我們需要做什么呢?
Driver 應該提供的功能
driver 應該提供哪些功能呢?
1, 為應用層使用 driver 提供接口;
這個應該是很好理解的,不可能讓每個上層軟件的作者自己寫驅動來訪問硬件;所以必須要抽象出一套接口,但是需要哪些接口呢?
Linux 的 driver 實現很有意思,把任何東西都抽象成文件,包括硬件,這樣對硬件的操作也就只需提供 vfs 所需的一套接口,當然其實這些接口的類型在很大程度上劃分了 driver 的類型,而這些接口也可以提供其它的形式,比如網卡就不提供這些接口;
Open :打開,也就是打開這個設備,這只是抽象的概念,很多硬件設備不存在這樣的物理動作,比如門,我們才說打開,當然如果理解所謂“打開心扉”也就很好理解這里的 driver 所抽象出的打開了;先前所說硬件的初始化可以在 probe 函數里面做,當然我想有些動作放在 open 里面做也可以的,但是必須要考慮的是, open 是可能出現許多個進程來訪問的,或者你自己要上鎖或者你就要考慮可重入性,也就是說如果一些動作只能做一次,那么顯然放在 open 里面來做就不合適了。
Close :這個和 open 相反的動作,但是這個 close 是上層才有的一個概念,在驅動里面用來一個叫 release 的接口實現,至于 close 到 release 之間的轉換就需要去看看文件系統這層的實現了。
#p#Read :這就是讀取數據了,沒什么好說,比如串口,比如 touch panel ;
Write :這就是寫了,也就是往設備里面寫數據;
其它的一些對上的接口 …. 就不討論了;
而 driver 還必須要提供其它的接口:那就是做為 linux driver 本身說必須要提供的接口,這些接口通常是內核自身所調用的;
那就是
Probe :這個函數很關鍵,它作為一個橋梁連接設備和 driver ,并且必須要對硬件進行初始化,以便在以后的用戶接口調用的時候設備能正常工作;從軟件的角度說,許多空間的分配等都在這里做,通過 dev_set_drvdata 和 dev_get_drvdata 設置和獲取相應的數據;
Remove :這個函數和上面這個函數是相反的,也就是負責清理掃尾的工作,負責釋放數據結構,停止硬件等;
Suspend :這個是在睡眠的時候調用的,在這里就必須要進行功耗控制;
Resume :這個就是喚醒的時候調用的,它需要執行相應的恢復動作,以便硬件能正常工作;
2, 實現對硬件設備的訪問控制;
只提供接口不負責實現,就是所謂的“銀樣蠟槍頭 ” ,所以驅動最復雜的地方在于如何控制硬件實現我們想實現的功能;而這些具體的實現通常就包含在給上層提供的接口中;而另外一方面一個驅動要實現某項功能很多時候不是自己獨立實現的,而是依賴于其它的模塊,比如 WIFI 驅動,在我們的平臺上,是通過 sdio 口連接的,而 sdio 口是 mmc controller 提供的,而 mmc 本身又是通過 gpio 口實現的,換句話說,如果要 wifi 能正常工作,就必須要 mmc 這一套能正常工作;那么就需要先配置 gpio 口,再移植 mmc 驅動,***才是 wifi 驅動,而 wifi 芯片本身說不定還需要其它的動作才能正常,比如上電等等;
Driver 和設備之間的連接
如果說 driver 就是由 struct device_driver 來描述,而設備也是有 struct device 來描述的話,那么如何描述 driver 和 driver 所驅動的設備這種關系呢?也就是說如果是父子,或夫妻關系的話,他們是如何相認的,又是如何維持這種紐帶的?一個設備通常由一個 driver 驅動,而一個 driver 有時候可以驅動多個設備(這也許是在美好的一夫多妻制時代)
1, 家族的概念
每個人都誕生于一個家庭,而由一系列有血緣關系的家庭又組成家族,我想 bus 的概念有點類似家族;
2, 設備的誕生
當一個設備通過 device_add 的方式調用的話,對它所屬的家族來說意味著一個新的小孩誕生了;如果這時候它的配偶已經由上帝指定的話,意味著它的配偶已經住進了它們的家族(掛在了 bus 上),那么上帝就會把它的配偶 driver 指向這個 device 完成婚姻,通常這時候就會調用 driver 提供的 probe 函數進行一系列的初始化操作,這就像丈夫對妻子進行思想教育一樣;
3, driver 的誕生
當一個 driver 調用 driver_register 的時候,也就宣布著新的孩子誕生了,如果它的配偶已經住進他們的家族,也就是說如果驅動的設備已經掛在了總線上,那么就可以結婚了(估計他們是屬于一出生就比較成熟的類型),同樣這時候就要調用 driver 的 probe 函數進行初始化工作了;
4, 人口登記
不管是男孩還是女孩,對政府來說都是 kobject ,所以一旦有孩子誕生不管是男是女都會調用 kobject_add 登記在案,這樣政府就可以完全掌控所有的信息;
5, 配偶的尋找
如果是先有 device ,那么匹配就是通過遍歷 bus 上的 driver 來進行的,反之就是通過遍歷 bus 上的設備進行的,而匹配的前提就是設備已經注冊,并且符合這個家族的族規,而族規通常是由 bus 的 match 函數來控制,而很多時候都是比較設備的名字和 driver 的名字是否相同(這個比結婚要比的東西簡樸許多啊,現在結婚比的是 money )當然還有其它許多的匹配方式,如果通過這個測試就可以調用 driver 提供的 probe 函數進行初始化了;
這樣的話,設備和 driver 就可以連接起來了,有了這樣的人口登記和家族聯系,就可以實現諸如睡眠喚醒這樣的功能了。
【編輯推薦】