1. 程式人生 > >linux2.6.32 platform驅動裝載過程跟蹤

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 函式是由我們在驅動程式中實現的,用來完成裝置的初始化工作。

這就又產生了一個新問題,就是總線上的裝置又是怎麼來的呢?下回分解。