前言
平時寫驅動或者看一份驅動代碼的時候,經常被各種註冊接口函數搞暈,到底什麼時候用哪一個呢?這個問題必須要在理解了Linux的設備模型後纔能有個清晰的概念,本文只是在閱讀了網上一些大神的博客後的一些小小的總結。不過本文暫時不會對Linux的設備模型有過多的深入,只是在自己的理解上,理清一下注冊接口之間的關係。
正文
先來看一下我們在驅動開發過程中,最常接觸到的兩個結構體。
1、device和device_driver
這兩個結構體是驅動開發的基礎,顧名思義,device就是設備的抽象,device_driver就是驅動的抽象。結構體都比較複雜,但是好在註釋比較清晰,具體可以參考:include\linux\device.h。驅動開發中接觸最多的就是怎麼使用這些接口,所以我們先看一下這些使用步驟。
下面以hid總線(bus)、uhid設備(device)、hid-generic驅動(device_driver)爲例子,講述一下流程,代碼目錄爲:drivers\hid\。
1.1、bus
因爲這一小節重點講device和device_driver,所以bus的概念我們先放一邊。註冊hid總線的代碼在:drivers\hid\hid-core.c
1.2、device
分配一個struct device類型的變量,填充必要的信息後,把它註冊到內核中。
代碼目錄:
drivers\hid\uhid.c
函數調用關係:
uhid_char_open //分配了uhid_device結構體,其中就包含了struct device
->uhid_device_add_worker
->hid_add_device
->device_add //這個函數就是將分配到的device註冊到內核中,並在這個過程中匹配合適的device_driver
->bus_probe_device //註冊進總線
->device_attach
->__device_attach
->driver_match_device //最終會調用driver的match函數
1.3、device_driver
分配一個struct device_driver類型的變量,填充必要的信息後,把它註冊到內核中
代碼目錄:
drivers\hid\hid-generic.c
函數調用關係:
module_hid_driver //分配的struct hid_driver就包含了struct device_driver
->__hid_register_driver
->driver_register
->bus_add_driver //將driver加到bus上
->driver_attach //匹配對應的device
1.4、小結
所以我們可以看到,註冊device用的device_add接口(或者device_register、device_create_vargs和device_create,不過它們最終都是調用device_add);註冊device_driver用的driver_register接口。不過實際開發中,除了直接用device和device_driver,也會用,在這兩個結構體封裝上的其他結構體,比如下一小節要講的內容。
2、platform_device和platform_driver
系統中,每個設備都需要連接到一個bus上,這個bus可以是一個實際存在的內部bus、虛擬的bus或者是platform bus。這一小節我們主要關注platform bus。
那麼連接到platform bus的platform device又有哪些呢?kernel在platform.txt中有相關的定義,總的來說就是,platform device包括:基於端口的設備(已不推薦使用,保留下來只爲兼容舊設備,legacy);連接物理總線的橋設備;集成在SOC上的各種控制器;連接在其他bus上的設備等等。
platform bus基於底層的bus模塊,抽象出來的一個虛擬的platform bus,用於platform設備的連接;platform device基於底層的device模塊,用於表示platform設備;platform driver基於底層的driver模塊,用於驅動platform設備。
其實從platform device和platform driver兩個結構體的定義就可以看出,他們是和struct device和struct device_driver有着千絲萬縷的關係。具體的定義可以參考:include\linux\platform_device.h。下面我們只是看一下怎麼用系統提供的API。
2.1、struct platform_device
代碼路徑:
drivers\base\platform.c
函數調用關係:
platform_device_register
->platform_device_add
->device_add
從函數調用關係來看,最終還是走到了device_add,也進一步說明platform_device是在device上的一層封裝而已。還有其它的註冊接口可以參考include\linux\platform_device.h
2.2、struct platform_driver
代碼路徑:
linux\platform_device.h
函數調用關係:
platform_driver_register
->__platform_driver_register
->driver_register //類似於platform_device,最終也是調用到註冊device_driver的函數
2.3、platform bus
想註冊device和driver,當然需要有對應的bus,而platform bus的註冊在drivers\base\platform.c的platform_bus_init實現。細節就不過多說了,有興趣的同學可以自行查閱代碼。
2.4、小結
上面只是提到了一些API,具體的驅動代碼例子可以參考我以前寫的文章:設備、驅動、總線模型簡介。