文章要提供新知,創造價值。Andy 老師這篇關於 U-boot 驅動模型的文章就符合這個特點。
量大且密度大,邏輯性強。這是底層軟體開發人員的必備素質了。
容易理解,我希望分享的都是大家只要墊起腳尖就能學到的新知識,如何你覺得哪篇文章太難,請在後臺告訴我。
永遠有效的兩個字——真誠。真誠不是寫作技巧,但也是最好的寫作技巧。
最近公眾號某篇文章被投訴「濫用原創」了,我承認那篇文章確實是不應該標註原創。我當時只想著真誠地分享幾本書給大家,並且以我認為的合理且客觀的描述去推薦那幾本書。
這引起了我的思考:
我分享的東西都是我的讀書筆記 + 自己的理解和思考,並且毫無保留地分享給大家。我只是想做專心學習認真分享這件事,如果這些東西都不能標註原創的話,那我會考慮不標註原創,我享受的是記錄和分享知識這件事。公眾號是一個很好的寫作平臺,但是在公眾號上寫文章是有風險的,最大的風險就是封號。如果到了那一天,封就封吧,我不喜歡被束縛的感覺,沒了我這麼一個積極健康向上的芝麻小號主,是微信公眾號平臺的一大損失~到時大家可以去 知乎或者我的個人網站 (www.es-hacker.com) 找到我,歡迎收藏。
目錄
一、U-Boot DM 三要素
1. udevice
2. uclass
3. driver
二、設備驅動的使用最近拿了一塊 Firefly 的開發板,主控是 RK3308,發現上面用的 U-Boot 是 2017 年的,於是想移植一個最新的版本上去,調試驅動的時候,總結了這些經驗。
一、U-Boot DM 三要素DM 是 U-Boot 中的驅動框架,全稱 Driver Mode。像 Linux Kernel 中的驅動三要素 device 、bus 、driver 一樣,DM 也有自己的三要素:udevice、uclass、driver。
uclass 是同一類設備的抽象,提供管理同一類設備的抽象接口。1. udevice通過三種途徑生成:
主動調用 device_bind_xxx 系列 API
根據當前 U-Boot 的編程哲學,基本大部分設備都是通過 dts 來描述,還有少部分設備因為特殊原因,可以通過 U_BOOT_DEVICE(_name) 宏申明。
在 UBoot DM 初始化階段(initfdm 和 initrdm),通過調用 dm_init_and_scan(boolpre_reloc_only) 根據名稱 (UBOOT_DEVICE 中和 driver 的 name,或者 dts 和 driver 的 compatible) 匹配到對應的 driver,然後調用 device_bind_common 函數生成 udevice,udevice 會和 driver 綁定,並根據 driver 中的uclass id 找到對應的 uclass driver,並生成相應的 uclass, 並把該設備掛到 uclass 的設備節點之下。最後調用 driver 的 bind 函數。
還有部分特殊的驅動,他們並不存在實際意義上的設備,比如 MMC 子系統中的 mmcblk 驅動,該驅動主要是把所有的 mmc 設備註冊到更上一層的 blk 子系統中,向 blk 層提供操作 mmc 設備的 blkops,向下通過mmc uclass 提供的統一接口控制 mmc 設備。
顯然,這個驅動位於抽象層,它不和具體的硬體設備直接交互,並不適合用一個 dts(dts 是用來描述具體的硬體信息的) 節點或者 UBOOTDEVICE(_name) 宏來為這個驅動顯示的申明設備。這種情形下一般通過主動調用 device_bind_xxx 系列 API 來完成驅動和設備已經更上一層 uclass 之間的 bind。
C:把設備掛到 uclass 的dev_head 鍊表下。
2. uclass
這裡主要的成員是 uclassdriver 和 devhead 鍊表。
dev_head 是一個鍊表頭, 用來連結該類下的所有設備。可以通過 uclass_foreach_dev(dev,uc) 遍歷該class 下的所有設備。
uclass_driver 是針對某一類設備提供的通用操作接口,然後通過 udevice->driver->ops 操作到具體的硬體設備。
uclass_driver 通過 UCLASSDRIVER(name) 宏申明, 在 device_bind_common 中根據設備對應的驅動 driver 中的 uclass id 找到 uclass_driver,並生成相應的 uclass, 並把設備掛到該 uclass 的設備節點 dev_head 下。
通過 UBOOTDRIVER 的 id 可以看出,該設備(pwm backlight)驅動屬於 UCLASSPANELBACKLIGHT 類。
這裡定義了 backlight 的 UCLASS_DRIVER。該 uclass driver 提供了 backlight_enable(structudevicedev) 和 backlight_set_brightness(structudevicedev,intpercent) 兩個通用的 API 供應用調用,可以看到他們都需要傳遞對應設備的 udevice ,然後通過 backlight_get_ops(dev) 拿到對該設備的操作接口。
3. driver
通過 UBOOTDRIVER(__name) 宏聲明。
如果 driver 實現了 bind 接口,該bind 將在 device_bind_common 中 device 和 driver 匹配上後被調用, 而且在 device_bind_common 中會完成 udevice 和 driver 的綁定。
driver 一般都有對應的 probe 接口,通過 device_probe(structudevice*dev) 調用,需要注意的是driver 的 bind 接口調用的比 probe 接口早, 大部分在 dm_init_and_scan 中就被調用了。
driver 一般會提供 ops 操作接口,供上一層調用
需要說明的是,driver 一般都不需要把自己註冊到 uclass 中,而是在 device_bind _common 階段實現driver 、uclass、device 三者的對接,然後 uclass 層通過 udevice->driver->ops 獲取對應 driver 的操作接口
二、設備驅動的使用一般應用層的代碼要使用某個設備的時候,首先需要通過 uclass_get_device_xxx 系列 API 拿到該設備的 udevice, 然後通過該設備的 uclass 提供的 API 操作該設備。uclass_get_device_xxx 拿到該設備的 udevice 後會調用該設備的 probe 接口。
以前面提到的 pwm backlight 為例:
/**
* drivers/video/simple_panel.c
*/
struct
udevice *bldev;
uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
"backlight"
, &bldev);
backlight_enable(bldev);
backlight_set_brightness(bldev, percent);
三、歡迎加入我的微信群你和我各有一個蘋果,如果我們交換蘋果的話,我們還是只有一個蘋果。但當你和我各有一個想法,我們交換想法的話,我們就都有兩個想法了。如果你也對 嵌入式系統和開源軟體 感興趣,並且想和更多人互相交流學習的話,請關注我的公眾號:嵌入式Hacker,一起來學習吧,無論是 關注或轉發 , 還是賞賜,都是對作者莫大的支持,感謝 各位的大拇指 ,祝工作順利,家庭和睦~