推薦閱讀
講的很好
☆ platform匯流排簡介
==>匯流排的產生的意義是讓裝置(硬體被抽象成乙個結構體來代表乙個裝置)和驅動分離
==>linux核心中常見的的匯流排有i2c匯流排,pci匯流排,串列埠匯流排,spi匯流排,pci匯流排,can匯流排,單匯流排等,所以有些裝置和驅動就可以掛在這些匯流排上,然後通過匯流排上的match進行裝置和驅動的匹配。但是有的裝置並不屬於這些常見匯流排,所以我們引入了一種虛擬匯流排,也就是platform匯流排的概念,對應的裝置叫做platform裝置,對應的驅動叫做platform驅動
☆ platform匯流排分析
==>先從使用方法入手分析,我們的驅動**如果想用platform匯流排,主要分兩個步驟:
① 抽象硬體為乙個裝置結構體,struct platform_device ,填充後呼叫 platform_device_register 將裝置註冊到匯流排上去
② 驅動部分定義乙個結構體 struct platform_driver,填充後呼叫 platform_driver_register 將驅動註冊到匯流排上去
注 : 比較常用的幾個元素是:
platform_device 結構體的 name 用於去適配驅動
platform_device 結構體的 dev.platform_data 包含裝置所使用的資源(io口 中斷號等)
platform_driver 結構體的 driver.name 和 platform_device_id 用於去適配裝置
platform_driver 結構體的 probe函式 是裝置和驅動適配成功後去執行的函式
==>x210的呼叫邏輯分析舉例
① 在mach-x210.c 檔案中定義了platform_device *smdkc110_devices結構體陣列,
包含了板級移植著給封裝的各類裝置(以後我們新增新裝置的時候也推薦在這裡新增)
這個陣列被 smdkc110_machine_init(前面部落格已分析如何被start_kernel呼叫)中的
platform_add_devices函式呼叫,將陣列中的裝置依次呼叫platform_device_register 新增到platform匯流排上去
② 我們隨便分析乙個驅動,以dm9000網絡卡驅動程式為例
module_init(dm9000_init);
platform_driver_register(&dm9000_driver);
當網絡卡裝置和網絡卡驅動的名字一致的時候就會呼叫 dm9000_driver 結構體的 .probe 函式;
☆ 是怎麼樣能夠執行.probe函式的
platform匯流排的設計思想實現裝置和驅動分離,驅動和裝置分開之後就會有先後載入的順序,所以platform匯流排實現了
無論是先載入裝置還是先載入驅動,都會對比name,合適後呼叫.probe 函式,下面來分析這個過程
==> 其實這個過程就是分析 platform_bus_init , platform_device_register 和 platform_driver_register 函式的實現
==>platform_bus_init 是核心啟動後被呼叫的 被呼叫的流程是
start_kernel
rest_init();
do_basic_setup();
driver_init()
platform_bus_init();
先定義了兩個結構體
struct device platform_bus = ;
struct bus_type platform_bus_type = ;
然後分析platform_bus_init()函式
platform_bus_init()
device_register(&platform_bus);
改函式把裝置名為platform 的裝置platform_bus註冊到系統中,其他的platform的裝置都會以它為parent(後面會看到)。
它在sysfs中目錄下.即 /sys/devices/platform。
bus_register(&platform_bus_type);
註冊了platform_bus_type匯流排,(如果裝置要註冊到platform匯流排上,要把裝置device結構體的bus賦值為platform_bus_type,
然後呼叫device_add後,系統就會知道這個裝置要掛到platform匯流排上)
這樣platform裝置的父裝置有了,platform bus匯流排也有了,後面其他裝置和驅動就可以掛在platform bus匯流排上了
==>分析platform_device_register(pdev) 一般是移植人員提供platform_device結構體,然後在板級檔案中這個函式被呼叫,(新版本核心用了驅動樹,這裡會不一樣)
device_initialize(&pdev->dev) 初始化platform_device 的device 結構體關鍵內容
platform_device_add(pdev)
pdev->dev.parent = &platform_bus; 這個就是前面說的,把platform_bus作為父節點
個人理解之所以用父節點這個東西,方便sys虛擬檔案系統下生成樹狀的檔案結構
pdev->dev.bus = &platform_bus_type; 這個就是告訴核心,我們要把這個裝置去掛載到platform匯流排上面
device_add(&pdev->dev); 這個就是真正的掛載裝置(猜測裡面肯定依據bus到掛載不同的裝置匯流排上)
..................
一系列的其他操作
bus_probe_device(dev)
device_attach
裝置去挨個匹配驅動
bus_for_each_drv(dev->bus, null, dev, __device_attach);
引數__device_attach
driver_match_device(drv, dev) 如果沒匹配成功則return
drv->bus->match(dev, drv) 這裡真正呼叫的就是platform_bus_type中的.match(也就是platform_match)函式
driver_probe_device(drv, dev) 呼叫到這裡說明匹配成功了
really_probe(dev, drv);
drv->probe(dev) 這裡呼叫就是驅動提供的probe函式
==>分析platform_driver_register(drv) 一般是由驅動開發者提供platform_driver結構體然後呼叫的,
drv->driver.bus = &platform_bus_type;
這個就是告訴核心,我們要把這個驅動去掛載到platform匯流排上面
..................... 然後給probe remove 和 shutdown 函式賦預設值(如果沒有提供函式)
driver_register(&drv->driver); 這個就是真正的掛載驅動
bus_add_driver add a driver to the bus.
driver_attach
驅動去挨個匹配裝置
bus_for_each_dev(drv->bus, null, drv, __driver_attach);
引數__driver_attach
driver_match_device
如果沒匹配成功則return
drv->bus->match(dev, drv) 這裡真正呼叫的就是platform_bus_type中的.match(也就是platform_match)函式
driver_probe_device
呼叫到這裡說明匹配成功了
really_probe(dev, drv);
drv->probe(dev) 這裡呼叫就是驅動提供的probe函式
注:關於really_probe的**實現裡有個細節
if (dev->bus->probe) else if (drv->probe)
也就是如果platform_bus_type結構體如果定義了probe函式 則使用它的probe函式,沒有定義的情況下才使用驅動開發者提供的probe函式
platform匯流排 學習
一直想要寫些部落格,記錄學習的過程,算是自己的乙個複習,也是鍛鍊一下自己的總結能力,但是一直到今天才開始。今天,學習的 platform匯流排。總的來說,platform匯流排是基於linux2.6核心的匯流排裝置驅動模型所自己定義出來的一條匯流排,具體為什麼要有這麼一條匯流排還沒有深入研究,目前覺...
Platform匯流排註冊驅動
linux核心中常見的的匯流排有i2c匯流排,pci匯流排,串列埠匯流排,spi匯流排,pci匯流排,can匯流排,單匯流排等,所以有些裝置和驅動就可以掛在這些匯流排上,然後通過匯流排上的match進行裝置和驅動的匹配。但是有的裝置並不屬於這些常見匯流排,所以我們引入了一種虛擬匯流排,也就是plat...
linux驅動之platform匯流排
第一部分 裝置驅動模型 1 匯流排 bus type結構體,關鍵函式是match函式和uevent函式 匯流排將裝置和驅動繫結,在系統每註冊乙個裝置的時候,會尋找與之匹配的驅動,相反,在系統每註冊乙個驅動的時候,會尋找與之匹配的裝置,而匹配由匯流排完成。2 裝置 struct device結構體,硬...