內核的開發者將總線,設備,驅動這三者用軟件思想抽象了出來,巧妙的建立了其間的關系,使之更形象化。結合前面所學的知識,總的來說其三者間的關系為bus有兩條鏈表,分別用於掛接設備和驅動,指定了其自身bus的device或者driver最後都會分別連接到對應bus的這兩條鏈表上,而總線又有其始端,為bus_kset,一個driver可以對應於幾個設備,因此driver同樣有其設備鏈表,用於掛接可以操作的設備,其自身也有bus掛接點,用於將自身掛接到對應bus(每個driver只屬於一條總線),而對於device,一個設備只屬於一條總線,只能有一個driver與其對應,因此對於device,都是單一的,一個driver掛接點,一個bus掛接點,device與bus相同的是都有始端,device為devices_kset,因此device的注冊同時會出現在對應的bus目錄和device總目錄下。好了,下面就以源碼為例分別分析一下bus,device,driver的注冊過程。
一、bus的注冊
bus的注冊比較簡單,首先來看一下bus的結構:
[cpp]
- struct bus_type {
- const char *name; //名字
- struct bus_attribute *bus_attrs; //bus屬性集
- struct device_attribute *dev_attrs; //device屬性集
- struct driver_attribute *drv_attrs; //driver屬性集
- 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 bus_type_private *p; //bus的私有成員
- };
- //其中重點看一下私有成員結構體:
- struct bus_type_private {
- struct kset subsys; //bus內嵌的kset,代表其自身
- struct kset *drivers_kset;
- struct kset *devices_kset;
- struct klist klist_devices; //包含devices鏈表及其操作函數
- struct klist klist_drivers; //driver鏈表及其操作函數
- struct blocking_notifier_head bus_notifier;
- unsigned int drivers_autoprobe:1; //匹配成功自動初始化標志
- struct bus_type *bus;
- };
無論是bus,driver,還是device其本身特征都放在私有成員裡,其注冊時,都會申請並填充這個結構體,下面具體分析一下bus的注冊流程,從bus_register開始:
[cpp]
- int bus_register(struct bus_type *bus)
- {
- int retval;
- struct bus_type_private *priv;
- priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL); //進入時bus_type->bus_type_private為NULL
- if (!priv) //該函數主要是對其的設置
- return -ENOMEM;
- priv->bus = bus; //私有成員的bus回指該bus
- bus->p = priv; //初始化bus->p,即其私有屬性
- BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
- retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name); //設置該bus的名字,bus是kset的封裝
- if (retval)
- goto out;
- //bus_kset即為所有bus的總起始端點
- //圍繞bus內嵌的kset初始化,和kset的初始化時圍繞
- priv->subsys.kobj.kset = bus_kset; //kobj相似,沒有parent時,就會用kset的kobj,此處即是
- priv->subsys.kobj.ktype = &bus_ktype; //屬性操作級別統一為bus_ktype
- priv->drivers_autoprobe = 1; //設置該標志,當有driver注冊時,會自動匹配devices
- //上的設備並用probe初始化,
- //當有device注冊時也同樣找到 driver並會初始化
- retval = kset_register(&priv->subsys); //注冊kset,創建目錄結構,以及層次關系
- if (retval)
- goto out;
- retval = bus_create_file(bus, &bus_attr_uevent); //當前bus目錄下生成bus_attr_uevent屬性文件
- if (retval)
- goto bus_uevent_fail;
- priv->devices_kset = kset_create_and_add("devices", NULL, //初始化bus目錄下的devices目錄,裡面級聯了該bus下設備,
- &priv->subsys.kobj); //仍然以kset為原型
- if (!priv->devices_kset) {
- retval = -ENOMEM;
- goto bus_devices_fail;
- }
- priv->drivers_kset = kset_create_and_add("drivers", NULL, //初始化bus目錄下的drivers目錄,裡面級聯了該bus下設備的driver
- &priv->subsys.kobj);
- if (!priv->drivers_kset) {
- retval = -ENOMEM;
- goto bus_drivers_fail;
- }
- klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); //初始化klist_devices裡的操作函數成員
- klist_init(&priv->klist_drivers, NULL, NULL); //klist_drivers裡的操作函數置空
- retval = add_probe_files(bus); //增加bus_attr_drivers_probe和bus_attr_drivers_autoprobe
- if (retval) //屬性文件
- goto bus_probe_files_fail;
- retval = bus_add_attrs(bus); //增加默認的屬性文件
- if (retval)
- goto bus_attrs_fail;
- pr_debug("bus: '%s': registered/n", bus->name);
- return 0;
- bus_attrs_fail: //以下為錯誤處理
- remove_probe_files(bus);
- bus_probe_files_fail:
- kset_unregister(bus->p->drivers_kset);
- bus_drivers_fail:
- kset_unregister(bus->p->devices_kset);
- bus_devices_fail:
- bus_remove_file(bus, &bus_attr_uevent);
- bus_uevent_fail:
- kset_unregister(&bus->p->subsys);
- out:
- kfree(bus->p);
- bus->p = NULL;
- return retval;
- }
由此可見,bus又是kset的封裝,bus_register主要完成了其私有成員bus_type_private的初始化,並初始化了其下的兩個目錄devices和drivers,及其屬性文件,bus有個自己的根目錄也就是bus有個起始端點,是bus_kset,經過此番的注冊,bus目錄下將會出現我們注冊的bus,並且其下會有device和driver兩個子目錄,代表它下面的driver和device鏈表。
二、driver的注冊
下面看一下driver是怎麼和bus關聯起來的,首先看下driver的結構:
[cpp]
- struct device_driver {
- const char *name; //名字
- struct bus_type *bus; //其所在的bus
- struct module *owner;
- const char *mod_name; /* used for built-in modules */
- bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
- #if defined(CONFIG_OF)
- const struct of_device_id *of_match_table;
- #endif
- 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; //私有成員,表示driver
- };
- //重點看下driver的私有成員
- struct driver_private {
- struct kobject kobj; //代表driver自身
- struct klist klist_devices; //可以操控的設備鏈表
- struct klist_node knode_bus; //掛接到bus的節點
- struct module_kobject *mkobj; //模塊相關
- struct device_driver *driver; //回指該driver
- };
如同bus一樣,重點的仍是可以代表其自身的私有屬性,下面具體看一下driver的注冊過程,從driver_register開始:
[cpp]
- int driver_register(struct device_driver *drv)
- {
- int ret;
- struct device_driver *other;
- BUG_ON(!drv->bus->p);
- if ((drv->bus->probe && drv->probe) || //driver和bus的同名操作函數如果同時存在,會出現警告
- (drv->bus->remove && drv->remove) || //並且會優先選用bus的
- (drv->bus->shutdown && drv->shutdown))
- printk(KERN_WARNING "Driver '%s' needs updating - please use "
- "bus_type methods/n", drv->name);
- other = driver_find(drv->name, drv->bus); //進入bus的driver鏈表,確認該driver是否已經注冊
- if (other) {
- put_driver(other); //找到了再減少引用計數,並且報錯退出
- printk(KERN_ERR "Error: Driver '%s' is already registered, "
- "aborting.../n", drv->name);
- return -EBUSY;
- }
- ret = bus_add_driver(drv); //如果沒有注冊,那麼把該driver加入所在bus
- if (ret)
- return ret;
- ret = driver_add_groups(drv, drv->groups);
- if (ret)
- bus_remove_driver(drv);
- return ret;
- }
- /****************************************************
- × 跟蹤一下driver_find(drv->name, drv->bus)
- ****************************************************/
- struct device_driver *driver_find(const char *name, struct bus_type *bus)
- {
- struct kobject *k = kset_find_obj(bus->p->drivers_kset, name); //bus->p->drivers_kset代表bus下
- struct driver_private *priv; //的driver目錄,此處會遍歷bus的
- //driver鏈表,通過driver內嵌的
- if (k) { //kobj名字比較
- priv = to_driver(k);
- return priv->driver; //如果找到同名的kobj那麼返回該driver
- }
- return NULL;
- }
- //看一下kset_find_obj吧:
- struct kobject *kset_find_obj(struct kset *kset, const char *name)
- {
- struct kobject *k;
- struct kobject *ret = NULL;
- spin_lock(&kset->list_lock);
- list_for_each_entry(k, &kset->list, entry) { //遍歷bus下的driver鏈表,如果
- if (kobject_name(k) && !strcmp(kobject_name(k), name)) { //找到那麼返回找到的kobj,並且把
- ret = kobject_get(k); //該driver的kobj引用計數+1
- break;
- }
- }
- spin_unlock(&kset->list_lock);
- return ret;
- }
- /************************************************
- × 再來跟蹤一下driver_register裡面的另外一個函數
- × bus_add_driver(drv)
- ************************************************/
- int bus_add_driver(struct device_driver *drv)
- {
- struct bus_type *bus;
- struct driver_private *priv;
- int error = 0;
- bus = bus_get(drv->bus); //取得其所在bus的指針
- if (!bus)
- return -EINVAL;
- pr_debug("bus: '%s': add driver %s/n", bus->name, drv->name); //開始初始化這個driver的私有成員,
- //和bus類似
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- error = -ENOMEM;
- goto out_put_bus;
- }
- klist_init(&priv->klist_devices, NULL, NULL); //設備操作函數清空,設備鏈表初始化
- priv->driver = drv;
- drv->p = priv;
- priv->kobj.kset = bus->p->drivers_kset; //kset指定到bus下面
- error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, //建立層次結構和屬性文件
- "%s", drv->name);
- if (error)
- goto out_unregister;
- if (drv->bus->p->drivers_autoprobe) { //bus的自動匹配如果設置為真,
- error = driver_attach(drv); //那麼到bus的devices上去匹配設備
- if (error)
- goto out_unregister;
- }
- klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); //把driver掛接到bus的driver鏈表
- module_add_driver(drv->owner, drv);
- error = driver_create_file(drv, &driver_attr_uevent); //以下添加該driver相關屬性文件
- if (error) {
- printk(KERN_ERR "%s: uevent attr (%s) failed/n",
- __func__, drv->name);
- }
- error = driver_add_attrs(bus, drv);
- if (error) {
- /* How the hell do we get out of this pickle? Give up */
- printk(KERN_ERR "%s: driver_add_attrs(%s) failed/n",
- __func__, drv->name);
- }
- if (!drv->suppress_bind_attrs) {
- error = add_bind_files(drv);
- if (error) {
- /* Ditto */
- printk(KERN_ERR "%s: add_bind_files(%s) failed/n",
- __func__, drv->name);
- }
- }
- kobject_uevent(&priv->kobj, KOBJ_ADD);
- return 0;
- out_unregister:
- kobject_put(&priv->kobj);
- kfree(drv->p);
- drv->p = NULL;
- out_put_bus:
- bus_put(bus);
- return error;
- }
- /****************************************************************
- × 接下來就剩下最終要的匹配函數driver_attach(drv)了,我們來看一下:
- ****************************************************************/
- int driver_attach(struct device_driver *drv) //遍歷bus的設備鏈表找到
- { //合適的設備就調用__driver_attach,
- return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); //NULL表示從頭開始遍歷
- }
- //============
- int bus_for_each_dev(struct bus_type *bus, struct device *start,
- void *data, int (*fn)(struct device *, void *))
- {
- struct klist_iter i;
- struct device *dev;
- int error = 0;
- if (!bus)
- return -EINVAL;
- klist_iter_init_node(&bus->p->klist_devices, &i, //進入bus的devices鏈表
- (start ? &start->p->knode_bus : NULL));
- while ((dev = next_device(&i)) && !error) //設備存在則調用fn即__driver_attach
- error = fn(dev, data); //進行匹配
- klist_iter_exit(&i);
- return error;
- }
- /*********************************************
- × 接著看一下__driver_attach這個函數
- *********************************************/
- 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
- driver_probe_device(drv, dev); //那麼需要初始化匹配到的這個設備
- device_unlock(dev);
- if (dev->parent)
- device_unlock(dev->parent);
- return 0;
- }
- /*********************************************
- × 又遇到兩個分支,囧,先看一下driver_match_device
- *********************************************/
- static inline int driver_match_device(struct device_driver *drv, //bus的match存在就用bus的
- struct device *dev) //,否則就直接匹配成功...
- { //match通常實現為首先掃描
- return drv->bus->match ? drv->bus->match(dev, drv) : 1; //driver支持的id設備表,如果
- } //為NULL就用名字進行匹配
- /************************************
- × 再來看一下driver_probe_device這個函數
- ************************************/
- int driver_probe_device(struct device_driver *drv, struct device *dev)
- {
- int ret = 0;
- if (!device_is_registered(dev)) //判斷該設備是否已經注冊
- return -ENODEV;
- pr_debug("bus: '%s': %s: matched device %s with driver %s/n",
- drv->bus->name, __func__, dev_name(dev), drv->name);
- pm_runtime_get_noresume(dev);
- pm_runtime_barrier(dev);
- ret = really_probe(dev, drv); //調用really_probe
- pm_runtime_put_sync(dev);
- return ret;
- }
- /************************************
- × 看一下device_is_registered
- ************************************/
- static inline int device_is_registered(struct device *dev)
- {
- return dev->kobj.state_in_sysfs; //在sysfs中表示已經注冊
- }
- /************************************
- × 再看really_probe
- ************************************/
- static int really_probe(struct device *dev, struct device_driver *drv)
- {
- int ret = 0;
- atomic_inc(&probe_count);
- pr_debug("bus: '%s': %s: probing driver %s with device %s/n",
- drv->bus->name, __func__, drv->name, dev_name(dev));
- WARN_ON(!list_empty(&dev->devres_head));
- dev->driver = drv; //device的driver初始化成該driver
- if (driver_sysfs_add(dev)) {
- printk(KERN_ERR "%s: driver_sysfs_add(%s) failed/n",
- __func__, dev_name(dev));
- goto probe_failed;
- }
- //利用probe初始化設備
- if (dev->bus->probe) { //如果bus的probe存在就用bus的,
- ret = dev->bus->probe(dev); //如果bus的不存在driver的存在
- if (ret) //再用driver的
- goto probe_failed;
- } else if (drv->probe) {
- ret = drv->probe(dev);
- if (ret)
- goto probe_failed;
- }
- driver_bound(dev); //調用driver_bound進行綁定
- ret = 1;
- pr_debug("bus: '%s': %s: bound device %s to driver %s/n",
- drv->bus->name, __func__, dev_name(dev), drv->name);
- goto done;
- probe_failed:
- devres_release_all(dev);
- driver_sysfs_remove(dev);
- dev->driver = NULL;
- if (ret != -ENODEV && ret != -ENXIO) {
- /* driver matched but the probe failed */
- printk(KERN_WARNING
- "%s: probe of %s failed with error %d/n",
- drv->name, dev_name(dev), ret);
- }
- /*
- * Ignore errors returned by ->probe so that the next driver can try
- * its luck.
- */
- ret = 0;
- done:
- atomic_dec(&probe_count);
- wake_up(&probe_waitqueue);
- return ret;
- }
- /**********************************
- * 最後跟一下driver_bound(dev)這個函數
- **********************************/
- static void driver_bound(struct device *dev)
- {
- if (klist_node_attached(&dev->p->knode_driver)) { //判斷是否已經綁定
- printk(KERN_WARNING "%s: device %s already bound/n",
- __func__, kobject_name(&dev->kobj));
- return;
- }
- pr_debug("driver: '%s': %s: bound to device '%s'/n", dev_name(dev),
- __func__, dev->driver->name);
- klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices); //將設備添加
- //到driver的鏈表
- if (dev->bus)
- blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
- BUS_NOTIFY_BOUND_DRIVER, dev);
- }
- //all end
總結一下,driver的注冊,主要涉及將自身掛接到bus的driver鏈表,並將匹配到的設備加入自己的device鏈表,並且將匹配到的device的driver成員初始化為該driver,私有屬性的driver節點也掛到driver的設備鏈表下,其中匹配函數是利用利用bus的match函數,該函數通常判斷如果driver有id表,就查表匹配,如果沒有就用driver和device名字匹配。當匹配成功後如果自動初始化標志允許則調用初始化函數probe,bus的probe優先級始終高於driver的。另外注意一點driver是沒有總的起始端點的,driver不是可具體描述的事物。
由於篇幅比較長,device的分析放到下一篇《linux設備模型之bus,device,driver分析<二>》 ^_^!