天天看點

Linux Platform驅動模型(二) _驅動方法【轉】

如何填充platform_driver對象?

如何将驅動方法對象注冊到平台總線中?

寫驅動也有一段時間了,可以發現,其實驅動本質上隻做了兩件事:向上提供接口,向下控制硬體,當然,這裡的向上并不是直接提供接口到應用層,而是提供接口給核心再由核心間接的将我們的接口提供給應用層。而寫驅動也是有一些套路可尋的,拿到一個硬體,我們大體可以按照下面的流程寫一個驅動:

确定驅動架構:根據硬體連接配接方式結合分層/分離思想設計驅動的基本結構

确定驅動對象:核心中的一個驅動/裝置就是一個對象,1.定義,2.初始化,3.注冊,4.登出

向上提供接口:根據業務需要确定提供cdev/proc/sysfs哪種接口

向下控制硬體:1.檢視原理圖确定引腳和控制邏輯,2.檢視晶片手冊确定寄存器配置方式,3.進行記憶體映射,4.實作控制邏輯

核心用platform_driver結構來表示一個驅動方法對象

在這個結構中,我們主要關心以下幾個成員

struct platform_driver --174-->探測函數,如果驅動比對到了目标裝置,總線會自動回調probe函數,必須實作,下面詳細讨論。 --175-->釋放函數,如果比對到的裝置從總線移除了,總線會自動回調remove函數,必須實作 --179-->platform_driver的父類,我們接下來讨論 --180-->用于C語言寫的裝置資訊,下面詳細讨論。

platform_driver裡面有些内容需要在父類driver中實作,

下面是我們關心的幾個成員

struct device_driver --229-->驅動名,如果這個驅動隻比對一個C語言的裝置,那麼可以通過name相同來比對 --230-->總線類型,這個成員由核心填充 --232-->owner,通常就寫THIS_MODULE --237-->of_device_id顧名思義就是用來比對用裝置樹寫的裝置資訊,下面詳細讨論 --249-->私有資料

裝置資訊有三種表達方式,而一個驅動是可以比對多個裝置的,平台總線中的驅動要具有三種比對資訊的能力,基于這種需求,platform_driver中使用不同的成員來進行相應的比對。

對于使用裝置樹編碼的裝置資訊,我們使用其父類device_driver中的of_match_table就是用來比對

struct of_device_id --225-->name[32]裝置名 --226-->type[32]裝置類型 --227-->重點!compatible[128]用于與裝置樹compatible屬性值比對的字元串 --228-->data驅動私有資料

對于一個驅動比對多個裝置的情況,我們使用struct of_device_id tbl[]來表示。

對于使用C語言編碼的裝置資訊,我們用platform_driver對象中的id_table就是用來比對。我們使用struct platform_device_id ids[]來實作一個驅動比對多個C語言編碼的裝置資訊。

struct platform_device_id --486-->name就是裝置名

下面這個例子就是用一個驅動來比對兩個分别叫"demo0"和"demo1"的裝置,注意,數組最後的{}是一定要的,這個是核心判斷數組已經結束的标志。

如果platform_driver和C語言編碼的platform_device是一一比對的,我們還可以使用device_driver中的name來進行比對

填充完platform_driver結構之後,我們應該将其中用到的裝置表注冊到核心,雖然不注冊也可以工作,但是注冊可以将我們表加入到相關檔案中,便于核心管理裝置。

細心的讀者可能會發現,這麼多方式都寫在一個對象中,那如果我同時注冊了三種比對結構核心該用哪種呢?此時就需要我們搬出平台總線的比對方式:

從中不難看出,這幾中形式的比對是有優先級的:of_match_table>id_table>name,了解到這點,我們甚至可以構造出同時适應兩種裝置資訊的平台驅動:

此外,如果你追一下of_driver_match_device(),就會發現平台總線的最終的比對是compatible,name,type三個成員,其中一個為NULL或""時表示任意,是以我們使用平台總線時總是使用compatile比對裝置樹,而不是節點路徑或節點名。

probe即探測函數,如果驅動比對到了目标裝置,總線會自動回調probe函數,下面詳細讨論。并把比對到的裝置資訊封裝策劃嗯platform_device對象傳入,裡面主要完成下面三個工作

申請資源

初始化

提供接口(cdev/sysfs/proc)

顯然,remove主要完成與probe相反的操作,這兩個接口都是我們必須實作的。

在probe的工作中,最常見的就是提取裝置資訊,雖然總線會将裝置資訊封裝成一個platform_device對象并傳入probe函數,我們可以很容易的得到關于這個裝置的所有資訊,但是更好的方法就是直接使用核心API中相關的函數

注意,通過核心API(eg,上下這兩個API)擷取的resource如果是中斷,那麼隻能是軟中斷号,而不是晶片手冊/C語言裝置資訊/裝置樹裝置資訊中的硬中斷号,但是此時擷取的resource的flag是可以正确的反映該中斷的觸發方式的,隻需要<code>flag &amp; IRQF_TRIGGER_MASK</code>即可擷取該中斷的觸發方式。

核心提供了兩個API來注冊/登出platform_driver對象到核心

在動态編譯的情況下,我們往往在子產品初始化函數中注冊一個驅動方法對象,而在子產品解除安裝函數中登出一個驅動方法對象,是以我們可以使用核心中如下的宏來提高代碼複用

這個執行個體同時使用了裝置資訊子產品和裝置樹兩種裝置資訊來源,不過最終使用的是裝置樹,需要注意的是,當我們用裝置樹的裝置資訊時,有一個成員platform_device.device.of_node來表示裝置的節點,這樣就允許我們使用豐富的裝置樹操作API來操作。

繼續閱讀