linux2.6.32 platform驅動裝載過程跟蹤
本文基於linux 2.6.32核心程式碼,分析了platform驅動的狀態過程,跟蹤了從模組init函式到 執行probe的過程。其他匯流排的驅動也是類似的。
module_init(xxx_init); 那麼在模組裝載時 將 呼叫 xxx_init()函式
在xxx_init()中 僅呼叫
int platform_driver_register(struct platform_driver *drv)
在 platform_driver_register() 中呼叫
int driver_register(struct device_driver *drv)
在 driver_register() 中呼叫
int bus_add_driver(struct device_driver *drv)
在 bus_add_driver() 中呼叫
int driver_attach(struct device_driver *drv)
在driver_attach() 中 就一句話:
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, int (*fn)(struct device *, void *))
這個函式實際上是在做一個遍歷工作,從start開始, 遍歷 bus 上的每一個裝置 dev, 對每一個dev,執行 fn 操作,可以看到fn有兩個輸入引數,分別是 dev 和 data;
在這裡,bus 是 drv->bus 即 驅動掛載的匯流排, start是NULL 即從頭開始,data 是 drv 即驅動結構體,fn 是 __driver_attach
__driver_attach是一個函式,這個函式有兩個輸入引數 dev 和 drv, 即裝置和驅動,函式中會去呼叫
if (!driver_match_device(drv, dev))
return 0;
driver_match_device 這個函式之後細說,總之是用於判斷 驅動 和 裝置 是否匹配,不匹配的就直接返回,
如果匹配,且dev結構還沒有繫結驅動(即if (!dev->driver)為真),就去呼叫 driver_probe_device(drv, dev),這個函式我們也待會兒細說。
這樣我們就知道了 driver_attach() 這個函式在做這件事情: 將驅動 drv 掛載的總線上的所有裝置分別去和 drv判斷兩者是否匹配,至於怎麼判斷,就是呼叫這個函式:
static inline int driver_match_device(struct device_driver *drv, struct device *dev)
而匹配了之後做什麼,就是呼叫這個函式:
int driver_probe_device(struct device_driver *drv, struct device *dev)
接下來我們就來看看這兩個函式。
driver_match_device() 非常簡單, 也就一句話
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
實際上就是呼叫 匯流排的 match 函式,如果該驅動掛載的匯流排沒有 match 函式,那就始終返回1,認為始終是匹配的。
那我們就看下 platform 匯流排的匹配函式
static int platform_match(struct device *dev, struct device_driver *drv)
在 platform_match() 函式中,如果 驅動drv 有 id_table, 就通過 id_table 匹配,
否則就直接判斷名字是否一樣: return (strcmp(pdev->name, drv->name) == 0);
接著再看確認匹配後,且裝置還沒有繫結驅動時所呼叫的
int driver_probe_device(struct device_driver *drv, struct device *dev)
在 driver_probe_device() 函式中 呼叫了 really_probe(dev, drv)
在really_probe() 函式中, 首先做了裝置和驅動的繫結:
dev->driver = drv;
driver_sysfs_add(dev);
接著:
if (dev->bus->probe) {
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) {
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}
如果匯流排有probe函式, 就呼叫匯流排的 probe 函式,否則如果有驅動的probe函式,就呼叫驅動的probe函式。
platform匯流排並沒有probe函式:
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
那麼就直接呼叫驅動的probe函式,至此,終於又回到了我們寫的驅動程式中來,我們就可以在probe函式中進行初始化的操作了。
總結一下:
在編寫platform總線上的驅動時,init函式中只需呼叫platform_driver_register(…),之後,系統會遍歷platform上的所有裝置,若找到了與驅動匹配的裝置 device,那麼就會呼叫 probe函式,而probe 函式是由我們在驅動程式中實現的,用來完成裝置的初始化工作。
這就又產生了一個新問題,就是總線上的裝置又是怎麼來的呢?下回分解。