Linux设备驱动-platform虚拟总线dya01
參考連接:https://www.cnblogs.com/deng-tao/p/6026373.html
參考書:<Linux設(shè)備驅(qū)動開發(fā)詳解>宋寶華
根據(jù)參考資料和同事討論總結(jié).
摘要: platform的原理及相關(guān)結(jié)構(gòu)體
1、什么是platform(平臺)總線?
相對于USB、PCI、I2C、SPI等物理總線來說,platform總線是一種虛擬、抽象出來的總線,實際中并不存在這樣的總線。
那為什么需要platform總線呢?
其實是Linux設(shè)備驅(qū)動模型為了保持設(shè)備驅(qū)動的統(tǒng)一性而虛擬出來的總線。因為對于usb設(shè)備、i2c設(shè)備、pci設(shè)備、spi設(shè)備等等,他們與cpu的通信都是直接掛在相應(yīng)的總線下面與我們的cpu進行數(shù)據(jù)交互的,但是在我們的嵌入式系統(tǒng)當中,并不是所有的設(shè)備都能夠歸屬于這些常見的總線,在嵌入式系統(tǒng)里面,SoC系統(tǒng)中集成的獨立的外設(shè)控制器、掛接在SoC內(nèi)存空間的外設(shè)卻不依附與此類總線。所以Linux驅(qū)動模型為了保持完整性,將這些設(shè)備掛在一條虛擬的總線上(platform總線),而不至于使得有些設(shè)備掛在總線上,另一些設(shè)備沒有掛在總線上。
platform總線相關(guān)代碼:driver\base\platform.c 文件
相關(guān)結(jié)構(gòu)體定義:include\linux\platform_device.h 文件中
2.通俗理解
Platform虛擬總線
總線兩邊分別掛接設(shè)備和驅(qū)動,設(shè)備和驅(qū)動互相探測,一旦探測成功(基于設(shè)備樹風格的匹配,基于ID表,基于設(shè)備名和驅(qū)動名)就可以對設(shè)備進行操作了.
設(shè)備驅(qū)動的開發(fā),我們可以總結(jié)為以下順序:
定義platform_device
注冊platform_device
定義platform_driver
注冊platform_driver
單片機是直接拿寄存器控制硬件.
而嵌入式設(shè)備因為有操作系統(tǒng),必須通過驅(qū)動來控制硬件設(shè)備.
3.platform平臺總線工作原理
平臺總線體系的工作流程
(1)第一步:系統(tǒng)啟動時在bus系統(tǒng)中注冊platform
(2)第二步:內(nèi)核移植的人負責提供platform_device
(3)第三步:寫驅(qū)動的人負責提供platform_driver
(4)第四步:platform的match函數(shù)發(fā)現(xiàn)driver和device匹配后,調(diào)用driver的probe函數(shù)來完成驅(qū)動的初始化和安裝,然后設(shè)備就工作起來了
4.platform總線管理下的2員大將
兩個結(jié)構(gòu)體platform_device和platform_driver
對于任何一種Linux設(shè)備驅(qū)動模型下的總線都由兩個部分組成:
描述設(shè)備相關(guān)的結(jié)構(gòu)體和描述驅(qū)動相關(guān)的結(jié)構(gòu)體
在platform總線下就是platform_device和platform_driver
(1)platform_device結(jié)構(gòu)體:(include\linux\platform_device.h)
struct platform_device { // platform總線設(shè)備const char * name; // 平臺設(shè)備的名字int id; // ID 是用來區(qū)分如果設(shè)備名字相同的時候(通過在后面添加一個數(shù)字來代表不同的設(shè)備,因為有時候有這種需求)struct device dev; // 內(nèi)置的device結(jié)構(gòu)體u32 num_resources; // 資源結(jié)構(gòu)體數(shù)量struct resource * resource; // 指向一個資源結(jié)構(gòu)體數(shù)組const struct platform_device_id *id_entry; // 用來進行與設(shè)備驅(qū)動匹配用的id_table表/* arch specific additions */struct pdev_archdata archdata; // 自留地 添加自己的東西};platform_device結(jié)構(gòu)體中的struct resource結(jié)構(gòu)體分析:
struct resource { // 資源結(jié)構(gòu)體resource_size_t start; // 資源的起始值,如果是地址,那么是物理地址,不是虛擬地址resource_size_t end; // 資源的結(jié)束值,如果是地址,那么是物理地址,不是虛擬地址const char *name; // 資源名unsigned long flags; // 資源的標示,用來識別不同的資源struct resource *parent, *sibling, *child; // 資源指針,可以構(gòu)成鏈表};(2)platform_driver結(jié)構(gòu)體
struct platform_driver(){ int (*probe) (struct platform_device *); int (*remove) (struct platform_device *); void (*shutdown) (struct platform_device *); int (*suspend) (struct platform_device *,pm_message_t state); int (*resume) (struct platform_device *); struct device_driver driver; const struct platform_device_id *id_table; bool prevent_deferred_probe; };其中,device_driver結(jié)構(gòu)體定義如下:
struct device_driver {const char *name;struct bus_type *bus;struct module *owner;const char *mod_name; /*used for built-in modules*/bool suppress_bind_attrs; /*disables bind/unbind via sysfs*/const struct of_device_id *of_match_table;const struct acpi_device_id *acpi_match_table;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);const struct attribute_group **groups;const struct dev_pm_ops *pm;struct driver_private *p; };與platform_driver地位對等的i2c_driver,spi_driver,usb_driver等都包含device_driver結(jié)構(gòu)體實例成員,他其實描述了xxx_driver(xxx是總線名)在驅(qū)動意義上的一些共性.
在Linux4.0以后,內(nèi)核直接使用設(shè)備樹來管理設(shè)備信息.設(shè)備樹中包含寄存器地址,中斷號等信息,直接寫成一個文本文檔,bootloader會將"這棵樹"傳給內(nèi)核,內(nèi)核解析其中的內(nèi)容,進而展開內(nèi)核中的platform_device,i2c_client,spi_device等設(shè)備. 驅(qū)動程序直接從設(shè)備樹的name進行匹配, 匹配到就可以通過platform_get_resource函數(shù)得到設(shè)備信息和寄存器信息等,進而控制硬件設(shè)備.
總結(jié)
以上是生活随笔為你收集整理的Linux设备驱动-platform虚拟总线dya01的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 完美解决EclipseTab占位符问题
- 下一篇: linux 其他常用命令