Linux內核部件分析 設備驅動模型之driver ---mark 詳細

Linux內核部件分析

設備驅動模型之driver

上節我們分析設備驅動模型中的device,主要是drivers/base/core.c,可以說是代碼量最大的一個文件。本節要分析的驅動driver,就要相對簡單很多。原因也很簡單,對於driver,我們能定義的公共部分實在不多,能再sysfs中表達的也很少。本節的分析將圍繞drivers/base/driver.c,但頭文件仍然是include/linux/device.h和drivers/base/base.h。

先讓我們來看看driver的結構。

  1. struct device_driver {  
  2.     const char      *name;  
  3.     struct bus_type     *bus;  
  4.   
  5.     struct module       *owner;  
  6.     const char      *mod_name;  /* used for built-in modules */  
  7.   
  8.     bool suppress_bind_attrs;   /* disables bind/unbind via sysfs */  
  9.   
  10.     int (*probe) (struct device *dev);  
  11.     int (*remove) (struct device *dev);  
  12.     void (*shutdown) (struct device *dev);  
  13.     int (*suspend) (struct device *dev, pm_message_t state);  
  14.     int (*resume) (struct device *dev);  
  15.     const struct attribute_group **groups;  
  16.   
  17.     const struct dev_pm_ops *pm;  
  18.   
  19.     struct driver_private *p;  
  20. };  

struct device_driver就是模型定義的通用驅動結構。name是驅動名稱,但這個name也只是在靜態定義的初始名稱,實際使用的名稱還是由kobject中保管的。bus執行驅動所在的總線,owner是驅動所在的模塊,還有一個所在模塊名稱mod_name,suppress_bind_attrs定義是否允許驅動通過sysfs決定掛載還是卸載設備。下面是一系列函數指針,probe是在驅動剛與設備掛接時調用的,remove是在設備卸載時調用的,shutdown是在設備關閉時調用的(說實話我現在還不知道remove和shutdown的區別),suspend是設備休眠時調用的,resume是設備恢復時調用的。group是屬性集合,pm是電源管理的函數集合,p是指向driver_private的指針。

  1. struct driver_private {  
  2.     struct kobject kobj;  
  3.     struct klist klist_devices;  
  4.     struct klist_node knode_bus;  
  5.     struct module_kobject *mkobj;  
  6.     struct device_driver *driver;  
  7. };  
  8. #define to_driver(obj) container_of(obj, struct driver_private, kobj)  

與device類似,device_driver把與其它組件聯繫的大部分結構變量移到struct driver_private中來。首先是kobj,在sysfs中代表driver目錄本身。klist_devices是驅動下的設備鏈表,knode_bus是要掛載在總線的驅動鏈表上的節點。mkobj是driver與相關module的聯繫,之前在device_driver結構中已經有指向module的指針,但這還不夠,在/sys下你能發現一個module目錄,所以驅動所屬的模塊在sysfs中也有顯示,具體留到代碼中再看。driver指針自然是從driver_private指回struct device_driver的。

  1. struct driver_attribute {  
  2.     struct attribute attr;  
  3.     ssize_t (*show)(struct device_driver *driver, char *buf);  
  4.     ssize_t (*store)(struct device_driver *driver, const char *buf,  
  5.              size_t count);  
  6. };  
  7.   
  8. #define DRIVER_ATTR(_name, _mode, _show, _store)    \   
  9. struct driver_attribute driver_attr_##_name =       \  
  10.     __ATTR(_name, _mode, _show, _store)  

除了以上兩個結構,還有struct driver_attribute。driver_attribute是driver對struct attribute的封裝,添加了兩個特用於device_driver的讀寫函數。這種封裝看似簡單重複,工作量很小,但在使用時卻會造成巨大的便利。 

好,結構介紹完畢,下面看driver.c中的實現。

  1. static struct device *next_device(struct klist_iter *i)  
  2. {  
  3.     struct klist_node *n = klist_next(i);  
  4.     struct device *dev = NULL;  
  5.     struct device_private *dev_prv;  
  6.   
  7.     if (n) {  
  8.         dev_prv = to_device_private_driver(n);  
  9.         dev = dev_prv->device;  
  10.     }  
  11.     return dev;  
  12. }  
  13.   
  14. int driver_for_each_device(struct device_driver *drv, struct device *start,  
  15.                void *data, int (*fn)(struct device *, void *))  
  16. {  
  17.     struct klist_iter i;  
  18.     struct device *dev;  
  19.     int error = 0;  
  20.   
  21.     if (!drv)  
  22.         return -EINVAL;  
  23.   
  24.     klist_iter_init_node(&drv->p->klist_devices, &i,  
  25.                  start ? &start->p->knode_driver : NULL);  
  26.     while ((dev = next_device(&i)) && !error)  
  27.         error = fn(dev, data);  
  28.     klist_iter_exit(&i);  
  29.     return error;  
  30. }  
  31. struct device *driver_find_device(struct device_driver *drv,  
  32.                   struct device *start, void *data,  
  33.                   int (*match)(struct device *dev, void *data))  
  34. {  
  35.     struct klist_iter i;  
  36.     struct device *dev;  
  37.   
  38.     if (!drv)  
  39.         return NULL;  
  40.   
  41.     klist_iter_init_node(&drv->p->klist_devices, &i,  
  42.                  (start ? &start->p->knode_driver : NULL));  
  43.     while ((dev = next_device(&i)))  
  44.         if (match(dev, data) && get_device(dev))  
  45.             break;  
  46.     klist_iter_exit(&i);  
  47.     return dev;  
  48. }  

driver_for_each_device()是對drv的設備鏈表中的每個設備調用一次指定函數。

driver_find_device()是在drv的設備鏈表中尋找一個設備,尋找使用指定的匹配函數。

這兩個函數都不陌生,在之前分析device的core.c中已經見到與它們很類似的函數,只不過那裏是遍歷設備的子設備鏈表,這裏是遍歷驅動的設備鏈表。next_device()同樣是輔助用的內部函數。

  1. int driver_create_file(struct device_driver *drv,  
  2.                struct driver_attribute *attr)  
  3. {  
  4.     int error;  
  5.     if (drv)  
  6.         error = sysfs_create_file(&drv->p->kobj, &attr->attr);  
  7.     else  
  8.         error = -EINVAL;  
  9.     return error;  
  10. }  
  11.   
  12. void driver_remove_file(struct device_driver *drv,  
  13.             struct driver_attribute *attr)  
  14. {  
  15.     if (drv)  
  16.         sysfs_remove_file(&drv->p->kobj, &attr->attr);  
  17. }  

driver_create_file()創建drv下的屬性文件,調用sysfs_create_file()實現。

driver_remove_file()刪除drv下的屬性文件,調用sysfs_remove_file()實現。

  1. static int driver_add_groups(struct device_driver *drv,  
  2.                  const struct attribute_group **groups)  
  3. {  
  4.     int error = 0;  
  5.     int i;  
  6.   
  7.     if (groups) {  
  8.         for (i = 0; groups[i]; i++) {  
  9.             error = sysfs_create_group(&drv->p->kobj, groups[i]);  
  10.             if (error) {  
  11.                 while (--i >= 0)  
  12.                     sysfs_remove_group(&drv->p->kobj,  
  13.                                groups[i]);  
  14.                 break;  
  15.             }  
  16.         }  
  17.     }  
  18.     return error;  
  19. }  
  20.   
  21. static void driver_remove_groups(struct device_driver *drv,  
  22.                  const struct attribute_group **groups)  
  23. {  
  24.     int i;  
  25.   
  26.     if (groups)  
  27.         for (i = 0; groups[i]; i++)  
  28.             sysfs_remove_group(&drv->p->kobj, groups[i]);  
  29. }  

driver_add_groups()在drv目錄下添加屬性集合,調用sysfs_create_groups()實現。

driver_remove_groups()在drv目錄下刪除屬性集合,調用sysfs_remove_groups()實現。

 

發現兩點問題:第一,是不是覺得driver_add_groups()不太合適,最好改爲driver_create_groups()才搭調。但不只是driver用driver_add_groups(),device也使用device_add_groups(),不知一處這樣做。第二,有沒有發現driver_create_file()是外部���數,driver_add_groups()就是內部函數,也就是說driver只對外提供添加屬性的接口,卻不提供添加屬性集合的接口。理由嗎?在struct device_driver()已經專門定義了一個groups變量來添加屬性集合,後面就不易再重複提供接口,而且創建屬性集合需要的操作遠比創建屬性費時。在device中也是這樣做的。

另外,driver中只提供管理屬性文件的方法,卻不提供管理二進制屬性文件的方法,這是因爲驅動本身沒有這種需求,只有部分設備纔要求二進制文件表示。

  1. struct device_driver *get_driver(struct device_driver *drv)  
  2. {  
  3.     if (drv) {  
  4.         struct driver_private *priv;  
  5.         struct kobject *kobj;  
  6.   
  7.         kobj = kobject_get(&drv->p->kobj);  
  8.         priv = to_driver(kobj);  
  9.         return priv->driver;  
  10.     }  
  11.     return NULL;  
  12. }  
  13.   
  14. void put_driver(struct device_driver *drv)  
  15. {  
  16.     kobject_put(&drv->p->kobj);  
  17. }  

get_driver()增加drv的引用計數,put_driver()減少drv的引用計數。這都是通過drv->p->kobj來做的。

  1. struct device_driver *driver_find(const char *name, struct bus_type *bus)  
  2. {  
  3.     struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);  
  4.     struct driver_private *priv;  
  5.   
  6.     if (k) {  
  7.         priv = to_driver(k);  
  8.         return priv->driver;  
  9.     }  
  10.     return NULL;  
  11. }  

driver_find()從bus的驅動鏈表中尋找特定名稱的driver。

  1. /** 
  2.  * driver_register - register driver with bus 
  3.  * @drv: driver to register 
  4.  * 
  5.  * We pass off most of the work to the bus_add_driver() call, 
  6.  * since most of the things we have to do deal with the bus 
  7.  * structures. 
  8.  */  
  9. int driver_register(struct device_driver *drv)  
  10. {  
  11.     int ret;  
  12.     struct device_driver *other;  
  13.   
  14.     BUG_ON(!drv->bus->p);  
  15.   
  16.     if ((drv->bus->probe && drv->probe) ||  
  17.         (drv->bus->remove && drv->remove) ||  
  18.         (drv->bus->shutdown && drv->shutdown))  
  19.         printk(KERN_WARNING "Driver '%s' needs updating - please use "  
  20.             "bus_type methods\n", drv->name);  
  21.   
  22.     other = driver_find(drv->name, drv->bus);  
  23.     if (other) {  
  24.         put_driver(other);  
  25.         printk(KERN_ERR "Error: Driver '%s' is already registered, "  
  26.             "aborting...\n", drv->name);  
  27.         return -EBUSY;  
  28.     }  
  29.   
  30.     ret = bus_add_driver(drv);  
  31.     if (ret)  
  32.         return ret;  
  33.     ret = driver_add_groups(drv, drv->groups);  
  34.     if (ret)  
  35.         bus_remove_driver(drv);  
  36.     return ret;  
  37. }  

driver_register()將drv註冊到系統中。它真是做得難以預料地簡單,所有的工作幾乎完全是由bus_add_driver()代爲完成的。但你要注意,在調用driver_register()前,drv->bus一定要預先設置。device可以不綁定bus,但driver一定要綁定到bus上。

  1. void driver_unregister(struct device_driver *drv)  
  2. {  
  3.     if (!drv || !drv->p) {  
  4.         WARN(1, "Unexpected driver unregister!\n");  
  5.         return;  
  6.     }  
  7.     driver_remove_groups(drv, drv->groups);  
  8.     bus_remove_driver(drv);  
  9. }  

driver_unregister()將drv從系統中撤銷。大部分工作是調用bus_remove_driver()完成的。可以看出bus_add_driver()與bus_remove_driver()相對。driver和bus的聯繫如此緊密,以至於driver的註冊和撤銷工作都可以由bus代勞了。我們需要更進一步的分析。 

經過調查,我們發現很有一部分driver的代碼被移動到了bus.c中。我們本節是以driver爲主,所以接下來會盡量在不驚動bus的情況下,分析存在於bus.c中的driver代碼。 

  1. static ssize_t drv_attr_show(struct kobject *kobj, struct attribute *attr,  
  2.                  char *buf)  
  3. {  
  4.     struct driver_attribute *drv_attr = to_drv_attr(attr);  
  5.     struct driver_private *drv_priv = to_driver(kobj);  
  6.     ssize_t ret = -EIO;  
  7.   
  8.     if (drv_attr->show)  
  9.         ret = drv_attr->show(drv_priv->driver, buf);  
  10.     return ret;  
  11. }  
  12.   
  13. static ssize_t drv_attr_store(struct kobject *kobj, struct attribute *attr,  
  14.                   const char *buf, size_t count)  
  15. {  
  16.     struct driver_attribute *drv_attr = to_drv_attr(attr);  
  17.     struct driver_private *drv_priv = to_driver(kobj);  
  18.     ssize_t ret = -EIO;  
  19.   
  20.     if (drv_attr->store)  
  21.         ret = drv_attr->store(drv_priv->driver, buf, count);  
  22.     return ret;  
  23. }  
  24.   
  25. static struct sysfs_ops driver_sysfs_ops = {  
  26.     .show   = drv_attr_show,  
  27.     .store  = drv_attr_store,  
  28. };  

看到這裏,你終於覺得driver開始正常了,它還要定義sysfs讀寫時操作的函數。

  1. static void driver_release(struct kobject *kobj)  
  2. {  
  3.     struct driver_private *drv_priv = to_driver(kobj);  
  4.   
  5.     pr_debug("driver: '%s': %s\n", kobject_name(kobj), __func__);  
  6.     kfree(drv_priv);  
  7. }  
  8.   
  9. static struct kobj_type driver_ktype = {  
  10.     .sysfs_ops  = &driver_sysfs_ops,  
  11.     .release    = driver_release,  
  12. };  

與device的釋放函數device_release不同,driver_release沒有提供外界代碼運行的機會,只是簡單地釋放drv_priv函數。

  1. /* Manually detach a device from its associated driver. */  
  2. static ssize_t driver_unbind(struct device_driver *drv,  
  3.                  const char *buf, size_t count)  
  4. {  
  5.     struct bus_type *bus = bus_get(drv->bus);  
  6.     struct device *dev;  
  7.     int err = -ENODEV;  
  8.   
  9.     dev = bus_find_device_by_name(bus, NULL, buf);  
  10.     if (dev && dev->driver == drv) {  
  11.         if (dev->parent) /* Needed for USB */  
  12.             down(&dev->parent->sem);  
  13.         device_release_driver(dev);  
  14.         if (dev->parent)  
  15.             up(&dev->parent->sem);  
  16.         err = count;  
  17.     }  
  18.     put_device(dev);  
  19.     bus_put(bus);  
  20.     return err;  
  21. }  
  22. static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);  
  23.   
  24. /* 
  25.  * Manually attach a device to a driver. 
  26.  * Note: the driver must want to bind to the device, 
  27.  * it is not possible to override the driver's id table. 
  28.  */  
  29. static ssize_t driver_bind(struct device_driver *drv,  
  30.                const char *buf, size_t count)  
  31. {  
  32.     struct bus_type *bus = bus_get(drv->bus);  
  33.     struct device *dev;  
  34.     int err = -ENODEV;  
  35.   
  36.     dev = bus_find_device_by_name(bus, NULL, buf);  
  37.     if (dev && dev->driver == NULL && driver_match_device(drv, dev)) {  
  38.         if (dev->parent) /* Needed for USB */  
  39.             down(&dev->parent->sem);  
  40.         down(&dev->sem);  
  41.         err = driver_probe_device(drv, dev);  
  42.         up(&dev->sem);  
  43.         if (dev->parent)  
  44.             up(&dev->parent->sem);  
  45.   
  46.         if (err > 0) {  
  47.             /* success */  
  48.             err = count;  
  49.         } else if (err == 0) {  
  50.             /* driver didn't accept device */  
  51.             err = -ENODEV;  
  52.         }  
  53.     }  
  54.     put_device(dev);  
  55.     bus_put(bus);  
  56.     return err;  
  57. }  
  58. static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);  

上面描述了driver下兩個只寫的屬性文件,unbind和bind。應該是提供用戶空間命令是否將設備與驅動掛接的接口。

  1. static int driver_add_attrs(struct bus_type *bus, struct device_driver *drv)  
  2. {  
  3.     int error = 0;  
  4.     int i;  
  5.   
  6.     if (bus->drv_attrs) {  
  7.         for (i = 0; attr_name(bus->drv_attrs[i]); i++) {  
  8.             error = driver_create_file(drv, &bus->drv_attrs[i]);  
  9.             if (error)  
  10.                 goto err;  
  11.         }  
  12.     }  
  13. done:  
  14.     return error;  
  15. err:  
  16.     while (--i >= 0)  
  17.         driver_remove_file(drv, &bus->drv_attrs[i]);  
  18.     goto done;  
  19. }  
  20.   
  21. static void driver_remove_attrs(struct bus_type *bus,  
  22.                 struct device_driver *drv)  
  23. {  
  24.     int i;  
  25.   
  26.     if (bus->drv_attrs) {  
  27.         for (i = 0; attr_name(bus->drv_attrs[i]); i++)  
  28.             driver_remove_file(drv, &bus->drv_attrs[i]);  
  29.     }  
  30. }  

driver_add_attrs()向drv目錄下添加屬性,只是這些屬性都是在bus中定義的drv_attrs[]。

driver_remove_attrs()從drv目錄中刪除相應的bus->drv_attrs[]。

  1. static int __must_check add_bind_files(struct device_driver *drv)  
  2. {  
  3.     int ret;  
  4.   
  5.     ret = driver_create_file(drv, &driver_attr_unbind);  
  6.     if (ret == 0) {  
  7.         ret = driver_create_file(drv, &driver_attr_bind);  
  8.         if (ret)  
  9.             driver_remove_file(drv, &driver_attr_unbind);  
  10.     }  
  11.     return ret;  
  12. }  
  13.   
  14. static void remove_bind_files(struct device_driver *drv)  
  15. {  
  16.     driver_remove_file(drv, &driver_attr_bind);  
  17.     driver_remove_file(drv, &driver_attr_unbind);  
  18. }  

add_bind_files()在drv目錄下增加bind和unbind屬性。

remove_bind_files()從drv目錄下刪除bind和unbind屬性。

  1. static ssize_t driver_uevent_store(struct device_driver *drv,  
  2.                    const char *buf, size_t count)  
  3. {  
  4.     enum kobject_action action;  
  5.   
  6.     if (kobject_action_type(buf, count, &action) == 0)  
  7.         kobject_uevent(&drv->p->kobj, action);  
  8.     return count;  
  9. }  
  10. static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);  

這是drv目錄下地uevent屬性文件,提供了從drv發送uevent的方法。

  1. /** 
  2.  * bus_add_driver - Add a driver to the bus. 
  3.  * @drv: driver. 
  4.  */  
  5. int bus_add_driver(struct device_driver *drv)  
  6. {  
  7.     struct bus_type *bus;  
  8.     struct driver_private *priv;  
  9.     int error = 0;  
  10.   
  11.     bus = bus_get(drv->bus);  
  12.     if (!bus)  
  13.         return -EINVAL;  
  14.   
  15.     pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);  
  16.   
  17.     priv = kzalloc(sizeof(*priv), GFP_KERNEL);  
  18.     if (!priv) {  
  19.         error = -ENOMEM;  
  20.         goto out_put_bus;  
  21.     }  
  22.     klist_init(&priv->klist_devices, NULL, NULL);  
  23.     priv->driver = drv;  
  24.     drv->p = priv;  
  25.     priv->kobj.kset = bus->p->drivers_kset;  
  26.     error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,  
  27.                      "%s", drv->name);  
  28.     if (error)  
  29.         goto out_unregister;  
  30.   
  31.     if (drv->bus->p->drivers_autoprobe) {  
  32.         error = driver_attach(drv);  
  33.         if (error)  
  34.             goto out_unregister;  
  35.     }  
  36.     klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);  
  37.     module_add_driver(drv->owner, drv);  
  38.   
  39.     error = driver_create_file(drv, &driver_attr_uevent);  
  40.     if (error) {  
  41.         printk(KERN_ERR "%s: uevent attr (%s) failed\n",  
  42.             __func__, drv->name);  
  43.     }  
  44.     error = driver_add_attrs(bus, drv);  
  45.     if (error) {  
  46.         /* How the hell do we get out of this pickle? Give up */  
  47.         printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",  
  48.             __func__, drv->name);  
  49.     }  
  50.   
  51.     if (!drv->suppress_bind_attrs) {  
  52.         error = add_bind_files(drv);  
  53.         if (error) {  
  54.             /* Ditto */  
  55.             printk(KERN_ERR "%s: add_bind_files(%s) failed\n",  
  56.                 __func__, drv->name);  
  57.         }  
  58.     }  
  59.   
  60.     kobject_uevent(&priv->kobj, KOBJ_ADD);  
  61.     return 0;  
  62.   
  63. out_unregister:  
  64.     kfree(drv->p);  
  65.     drv->p = NULL;  
  66.     kobject_put(&priv->kobj);  
  67. out_put_bus:  
  68.     bus_put(bus);  
  69.     return error;  
  70. }  

bus_add_driver()看似是把drv與bus聯繫起來,其實是完成driver加入系統的大部分操作。

首先調用bus_get(drv->bus)增加對bus的引用。

分配並初始化drv->p,即driver_private結構。

調用kobject_init_and_add()將drv加入sysfs,之前只是設置了priv->obj.kset爲bus->p->drivers_kset,所以drv目錄會出現在bus目錄的drivers子目錄中。如果總線允許自動probe,就會調用driver_attach()將驅動和總線上的設備進行匹配,這個過程先略過。

然後調用klist_add_tail()將drv掛入總線的驅動鏈表。

調用module_add_driver()創建driver相關的模塊在sysfs中的表示。後面專門描述。

調用driver_create_file()在drv目錄下創建uevent屬性文件。

調用driver_add_attrs()在drv目錄下添加bus->driver_attrs[]中定義的屬性。

如果drv->suppress_bind_attrs爲零,即允許用戶空間決定驅動何時鏈接和卸載設備,則調用add_bind_files()添加bind和unbind屬性文件。

調用kobject_uevent()向用戶空間發佈KOBJ_ADD消息。 

從bus_add_driver()的處理過程來看,driver只在bus的drivers目錄下出現,沒什麼軟鏈接,需要的屬性也不多。

  1. /** 
  2.  * bus_remove_driver - delete driver from bus's knowledge. 
  3.  * @drv: driver. 
  4.  * 
  5.  * Detach the driver from the devices it controls, and remove 
  6.  * it from its bus's list of drivers. Finally, we drop the reference 
  7.  * to the bus we took in bus_add_driver(). 
  8.  */  
  9. void bus_remove_driver(struct device_driver *drv)  
  10. {  
  11.     if (!drv->bus)  
  12.         return;  
  13.   
  14.     if (!drv->suppress_bind_attrs)  
  15.         remove_bind_files(drv);  
  16.     driver_remove_attrs(drv->bus, drv);  
  17.     driver_remove_file(drv, &driver_attr_uevent);  
  18.     klist_remove(&drv->p->knode_bus);  
  19.     pr_debug("bus: '%s': remove driver %s\n", drv->bus->name, drv->name);  
  20.     driver_detach(drv);  
  21.     module_remove_driver(drv);  
  22.     kobject_put(&drv->p->kobj);  
  23.     bus_put(drv->bus);  
  24. }  

bus_remove_driver()將drv從系統中撤銷,與bus_add_driver()相對應。

driver真正精彩的地方在於probe函數,對設備的操作,對用戶空間提供的接口,可惜這些都是特定的。這裏只能將driver與bus聯繫起來,並在以後與device聯繫起來。

 

不過不必失望,下面我們分析下drivers/base/module.c,它顯示了與驅動有關的module,在sysfs中的表現情況。

首先介紹使用到的結構。應該說module.c的代碼實現很簡單,但使用到的結構不簡單。

  1. struct module_attribute {  
  2.         struct attribute attr;  
  3.         ssize_t (*show)(struct module_attribute *, struct module *, char *);  
  4.         ssize_t (*store)(struct module_attribute *, struct module *,  
  5.              const char *, size_t count);  
  6.     void (*setup)(struct module *, const char *);  
  7.     int (*test)(struct module *);  
  8.     void (*free)(struct module *);  
  9. };  
  10.   
  11. struct param_attribute  
  12. {  
  13.     struct module_attribute mattr;  
  14.     struct kernel_param *param;  
  15. };  
  16.   
  17. struct module_param_attrs  
  18. {  
  19.     unsigned int num;  
  20.     struct attribute_group grp;  
  21.     struct param_attribute attrs[0];  
  22. };  
  23.   
  24. struct module_kobject  
  25. {  
  26.     struct kobject kobj;  
  27.     struct module *mod;  
  28.     struct kobject *drivers_dir;  
  29.     struct module_param_attrs *mp;  
  30. };  

可以看到module_attribute結構除了包含struct attribute,還多增加了好幾條函數指針。而這只是最簡單的,struct param_attribute除了包含module_attribute,還有一個指向kernel_param的指針param。這個kernel_param就太複雜了,是外界向module提供參數用的窗口,這裏忽略。後面還有struct module_param_attrs和struct module_kobject。

  1. static char *make_driver_name(struct device_driver *drv)  
  2. {  
  3.     char *driver_name;  
  4.   
  5.     driver_name = kmalloc(strlen(drv->name) + strlen(drv->bus->name) + 2,  
  6.                   GFP_KERNEL);  
  7.     if (!driver_name)  
  8.         return NULL;  
  9.   
  10.     sprintf(driver_name, "%s:%s", drv->bus->name, drv->name);  
  11.     return driver_name;  
  12. }  

make_driver_name()將drv的名字和drv->bus的名字合起來,不過這是一個內部函數,具體使用還要看後面。

  1. static void module_create_drivers_dir(struct module_kobject *mk)  
  2. {  
  3.     if (!mk || mk->drivers_dir)  
  4.         return;  
  5.   
  6.     mk->drivers_dir = kobject_create_and_add("drivers", &mk->kobj);  
  7. }  

module_create_drivers_dir()在mk所在的目錄下創建一個drivers的目錄。不過因爲是使用kobject_create_and_add(),所以這個kobject使用默認的dynamic_kobj_ktype。

  1. void module_add_driver(struct module *mod, struct device_driver *drv)  
  2. {  
  3.     char *driver_name;  
  4.     int no_warn;  
  5.     struct module_kobject *mk = NULL;  
  6.   
  7.     if (!drv)  
  8.         return;  
  9.   
  10.     if (mod)  
  11.         mk = &mod->mkobj;  
  12.     else if (drv->mod_name) {  
  13.         struct kobject *mkobj;  
  14.   
  15.         /* Lookup built-in module entry in /sys/modules */  
  16.         mkobj = kset_find_obj(module_kset, drv->mod_name);  
  17.         if (mkobj) {  
  18.             mk = container_of(mkobj, struct module_kobject, kobj);  
  19.             /* remember our module structure */  
  20.             drv->p->mkobj = mk;  
  21.             /* kset_find_obj took a reference */  
  22.             kobject_put(mkobj);  
  23.         }  
  24.     }  
  25.   
  26.     if (!mk)  
  27.         return;  
  28.   
  29.     /* Don't check return codes; these calls are idempotent */  
  30.     no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module");  
  31.     driver_name = make_driver_name(drv);  
  32.     if (driver_name) {  
  33.         module_create_drivers_dir(mk);  
  34.         no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj,  
  35.                         driver_name);  
  36.         kfree(driver_name);  
  37.     }  
  38. }  

module_add_drivers()在module下添加與driver的聯繫。

開始調用kset_find_obj()從module_kset下尋找drv所屬的module對應的kobj。說明每個module在加載時都會在/sys/module中創建一個kobject目錄。這裏找到後只是將其賦給drv->p->kmobj,並調用kobject_put()釋放找到時加上的引用計數。至於爲什麼driver不保留對module的引用計數,或許是不需要,或許是已經存在了。

接下來調用sysfs_create_link()在驅動目錄中添加指向module目錄的軟鏈接,名稱就是module。

調用module_create_drivers_dir()在module目錄下建立drivers子目錄。

調用sysfs_create_link()在drivers子目錄下建立指向驅動目錄的軟鏈接,名稱使用make_driver_name()的返回結果。

  1. void module_remove_driver(struct device_driver *drv)  
  2. {  
  3.     struct module_kobject *mk = NULL;  
  4.     char *driver_name;  
  5.   
  6.     if (!drv)  
  7.         return;  
  8.   
  9.     sysfs_remove_link(&drv->p->kobj, "module");  
  10.   
  11.     if (drv->owner)  
  12.         mk = &drv->owner->mkobj;  
  13.     else if (drv->p->mkobj)  
  14.         mk = drv->p->mkobj;  
  15.     if (mk && mk->drivers_dir) {  
  16.         driver_name = make_driver_name(drv);  
  17.         if (driver_name) {  
  18.             sysfs_remove_link(mk->drivers_dir, driver_name);  
  19.             kfree(driver_name);  
  20.         }  
  21.     }  
  22. }  

module_remove_driver()消除driver與相應module之間的軟鏈接關係。

對於module,應該是另一個議題了,這裏只是簡單涉及,下節我們將涉及到總線bus,並深入分析device和driver的關係。

linux
 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章