Linux裝置和驅動的匹配過程
阿新 • • 發佈:2019-01-11
一、bus_type結構體及涉及的函式: (1)bus_type結構體 struct bus_type { const char *name; const char *dev_name; struct device *dev_root; struct bus_attribute *bus_attrs; struct device_attribute *dev_attrs; struct driver_attribute *drv_attrs; int (*match)(struct device *dev, struct device_driver *drv);//匯流排用來匹配裝置和驅動的函式 int (*uevent)(struct device *dev, struct kobj_uevent_env *env); 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 dev_pm_ops *pm; struct iommu_ops *iommu_ops; struct subsys_private *p; struct lock_class_key lock_key; }; (2)涉及的函式 kernel/linux-3.10/drivers/base/core.c: device_create()、device_register()、device_add() kernel/linux-3.10/drivers/base/driver.c: driver_register() kernel/linux-3.10/drivers/base/busc: bus_add_driver()、bus_add_device()、bus_probe_device() kernel/linux-3.10/drivers/base/dd.c: device_attach()、__device_attach()、driver_attach()、__driver_attach() kernel/linux-3.10/drivers/base/base.h: driver_match_device()、driver_probe_device() 二、註冊過程: Linux裝置驅動註冊過程如下所示: xxxx_driver_register()/xxxx_register_driver()--->driver_register()---> bus_add_driver()--->driver_attach()--->__driver_attach() 如:platform_driver_register()、spi_register_driver()、i2c_register_driver() Linux裝置新增過程如下所示: device_create()/xxxx_device_register()/xxxx_new_device()--->device_register()/xxxx_device_add()/xxxx_add_device() --->device_add()--->bus_add_device()--->bus_probe_device()---> device_attach()---> __device_attach() (1)可以直接使用device_create()建立裝置,其最終會呼叫device_register()函式建立裝置。 (2)platform_device_register()--->platform_device_add()。 (3)spi_new_device()--->spi_add_device()。 (4)i2c_new_device()--->device_register()。 從裝置和驅動的註冊過程可以看到兩者處理的過程是非常類似,下面分別從最後的函式展開進行深入探索。 三、驅動匹配裝置過程 static int __driver_attach(struct device *dev, void *data) { struct device_driver *drv = data; if (!driver_match_device(drv, dev)) return 0; if (dev->parent) /* Needed for USB */ device_lock(dev->parent); device_lock(dev); if (!dev->driver) driver_probe_device(drv, dev); device_unlock(dev); if (dev->parent) device_unlock(dev->parent); return 0; } 從上述函式可以看到在driver註冊時呼叫函式driver_match_device進行driver和device的匹配,在匹配之後執行driver的probe函式進行初始化等操作。我們主要看一下driver和device的匹配過程,不再詳細研究probe過程。 static inline int driver_match_device(struct device_driver *drv, struct device *dev) { return drv->bus->match ?drv->bus->match(dev, drv) : 1; } 可以看到,會呼叫相應匯流排的match函式來匹配driver和device。一般匯流排的呼叫過程如下所示,具體可參考每個匯流排的match函式。 static int xxxx_match(struct device *dev,struct device_driver *drv) { struct xxxx_device *xxxdev = to_xxxx_device(dev); struct xxxx_driver *xxxdrv =to_xxxx_driver(drv); /* Attempt an OF style match first */ if((of_driver_match_device(dev, drv)) return 1; /* Then ACPI style match */ if((acpi_driver_match_device(dev, drv)) return 1; /* Then try to match against the id table*/ if((xxxdrv->id_table) return xxxx_match_id(xxxdrv->id_table,xxxdev) != NULL; /* fall-back to driver name match */ return (strcmp([xxxdev/dev]->[name/modalias], drv->name)== 0); } 可以看到基本上有四種方式,第一種是呼叫of_driver_match_device()函式;第二種方式是是ACPI系統專用的;第三種通過driver的id_table;第四種比較簡單,是通過裝置的名稱或別名和驅動的名稱進行匹配的。 下面詳細看一下前第一種和第三種匹配方式: (1)、of_driver_match_device() 該函式的呼叫過程如下: static inline int of_driver_match_device(struct device *dev, const structdevice_driver *drv) { returnof_match_device(drv->of_match_table, dev) != NULL; } const struct of_device_id *of_match_device(const struct of_device_id *matches, conststruct device *dev) { if ((!matches) || (!dev->of_node)) return NULL; return of_match_node(matches, dev->of_node); } const struct of_device_id *of_match_node(const struct of_device_id *matches, conststruct device_node *node) { const struct of_device_id *match; unsigned long flags; raw_spin_lock_irqsave(&devtree_lock,flags); match = __of_match_node(matches, node); raw_spin_unlock_irqrestore(&devtree_lock,flags); return match; } static const struct of_device_id *__of_match_node(const struct of_device_id *matches,const struct device_node *node) { if (!matches) return NULL; while (matches->name[0] ||matches->type[0] || matches->compatible[0]) { int match = 1; if (matches->name[0]) match &= node->name &&!strcmp(matches->name, node->name); if (matches->type[0]) match &= node->type &&!strcmp(matches->type, node->type); if (matches->compatible[0]) match &= __of_device_is_compatible(node,matches->compatible); if (match) return matches; matches++; } return NULL; } 可以發現最終匹配會呼叫__of_match_node,該函式通過of_device_id的名稱、型別和相容性和裝置節點的名稱、型別和相容性進行匹配,其中相容性具有最高優先順序,如果相容性不匹配,即使前兩者匹配,最終結果還是不匹配。另外,of_device_id中一般只有相容性一項。 在進行相容性匹配時會呼叫__of_device_is_compatible(),該函式最終會呼叫strcasecmp函式,比較相容性字串是否一致,一致則匹配。呼叫過程如下: static int__of_device_is_compatible(const struct device_node *device, const char *compat) { const char* cp; int cplen, l; cp = __of_get_property(device,"compatible", &cplen); if (cp == NULL) return0; while (cplen > 0) { if (of_compat_cmp(cp, compat,strlen(compat)) == 0) return 1; l = strlen(cp) + 1; cp += l; cplen -= l; } return 0; } #defineof_compat_cmp(s1, s2, l) strcasecmp((s1), (s2)) (2)、id_table 一般是呼叫xxxx_match_id函式比較id_table的名稱和裝置相關屬性的名稱來進行匹配。xxxx_match_id的一般形式如下,具體可以參考各個匯流排的函式。 static const struct xxxx_device_id *xxxx_match_id(const struct xxxx_device_id *id,const struct _xxxx *xxxx) { while (id->name[0]) { if (strcmp(xxxx->name, id->name) == 0) return id; id++; } return NULL; } 我們可以看一下i2c匯流排和SPI匯流排的xxxx_match_id函式,如下所示: static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, conststruct i2c_client *client) { while (id->name[0]) { if (strcmp(client->name, id->name) == 0) return id; id++; } return NULL; } 可以看到I2C匯流排使用i2c_client的名稱和id_table的名稱來進行匹配。 static const struct spi_device_id *spi_match_id(const struct spi_device_id *id, conststruct spi_device *sdev) { while (id->name[0]) { if (!strcmp(sdev->modalias, id->name)) return id; id++; } return NULL; } 可以看到SPI匯流排使用SPI裝置的別名和id_table的名稱來進行匹配。其它匯流排的匹配方式請自行檢視,再此不再贅述。 四、裝置匹配驅動過程 static int__device_attach(struct device_driver *drv, void *data) { struct device *dev = data; if (!driver_match_device(drv, dev)) return 0; return driver_probe_device(drv, dev); } staticinline int driver_match_device(struct device_driver *drv, struct device *dev) { return drv->bus->match ?drv->bus->match(dev, drv) : 1; } 從上述函式可以看到device註冊時也是呼叫函式driver_match_device來進行driver和device的匹配,在匹配之後執行driver的probe函式進行初始化等操作。 由此可見無論是裝置還是驅動註冊,都是呼叫匯流排的match函式進行匹配。在裝置和驅動匹配之後,會呼叫driver_probe_device()函式,呼叫驅動的probe函式進行初始化工作。 五、常見匯流排的match函式: (1)platform_bus: static int platform_match(struct device *dev, struct device_driver *drv) { struct platform_device *pdev = to_platform_device(dev); struct platform_driver *pdrv = to_platform_driver(drv); /* Attempt an OF style match first */ if (of_driver_match_device(dev, drv)) return 1; /* Then try ACPI style match */ if (acpi_driver_match_device(dev, drv)) return 1; /* Then try to match against the id table */ if (pdrv->id_table) return platform_match_id(pdrv->id_table, pdev) != NULL; /* fall-back to driver name match */ return (strcmp(pdev->name, drv->name) == 0);//比較平臺裝置的名稱和驅動名稱進行匹配 } (2)spi_bus: static int spi_match_device(struct device *dev, struct device_driver *drv) { const struct spi_device *spi = to_spi_device(dev); const struct spi_driver *sdrv = to_spi_driver(drv); /* Attempt an OF style match */ if (of_driver_match_device(dev, drv)) return 1; /* Then try ACPI */ if (acpi_driver_match_device(dev, drv)) return 1; if (sdrv->id_table) return !!spi_match_id(sdrv->id_table, spi); return strcmp(spi->modalias, drv->name) == 0;//通過比較spi_device的別名和驅動的名稱進行匹配 } (3)i2c_bus: static int i2c_device_match(struct device *dev, struct device_driver *drv) { struct i2c_client *client = i2c_verify_client(dev); struct i2c_driver *driver; if (!client) return 0; /* Attempt an OF style match */ if (of_driver_match_device(dev, drv)) return 1; /* Then ACPI style match */ if (acpi_driver_match_device(dev, drv)) return 1; driver = to_i2c_driver(drv); /* match on an id table if there is one */ if (driver->id_table) return i2c_match_id(driver->id_table, client) != NULL; return 0; }