Linux設備模型——設備驅動模型和sysfs文件系統解讀

本文將對Linux系統中的sysfs進行簡單的分析,要分析sysfs就必須分析內核的driver-model(驅動模型),兩者是緊密聯繫的。在分析過程中,本文將以platform總線和spi主控制器的platform驅動爲例來進行講解。其實,platform機制是基於driver-model的,通過本文,也會對platform機制有個簡單的瞭解。

內核版本:2.6.30

1. What is sysfs?

  個人理解:sysfs向用戶空間展示了驅動設備的層次結構。我們都知道設備和對應的驅動都是由內核管理的,這些對於用戶空間是不可見的。現在通過sysfs,可以在用戶空間直觀的瞭解設備驅動的層次結構。

  我們來看看sysfs的文件結構:

[root@yj423 /sys]#ls
block     class     devices   fs        module
bus       dev       firmware  kernel    power

block:塊設備

bus:系統中的總線

class: 設備類型,比如輸入設備

dev:系統中已註冊的設備節點的視圖,有兩個子目錄char和block。

devices:系統中所有設備拓撲結構視圖

fireware:固件

fs:文件系統

kernel:內核配置選項和狀態信息

module:模塊

power:系統的電源管理數據

2. kobject ,kset和ktype

  要分析sysfs,首先就要分析kobject和kset,因爲驅動設備的層次結構的構成就是由這兩個東東來完成的。

2.1 kobject

  kobject是一個對象的抽象,它用於管理對象。每個kobject對應着sysfs中的一個目錄。

  kobject用struct kobject來描述。

  1. struct kobject {  
  2.     const char        *name;            /*在sysfs建立目錄的名字*/  
  3.     struct list_head    entry;        /*用於連接到所屬kset的鏈表中*/  
  4.     struct kobject        *parent;    /*父對象*/  
  5.     struct kset        *kset;            /*屬於哪個kset*/  
  6.     struct kobj_type    *ktype;        /*類型*/  
  7.     struct sysfs_dirent    *sd;        /*sysfs中與該對象對應的文件節點*/  
  8.     struct kref        kref;            /*對象的應用計數*/  
  9.     unsigned int state_initialized:1;  
  10.     unsigned int state_in_sysfs:1;  
  11.     unsigned int state_add_uevent_sent:1;  
  12.     unsigned int state_remove_uevent_sent:1;  
  13.     unsigned int uevent_suppress:1;  
  14. };  

2.2 kset

  kset是一些kobject的集合,這些kobject可以有相同的ktype,也可以不同。同時,kset自己也包含一個kobject。在sysfs中,kset也是對應這一個目錄,但是目錄下面包含着其他的kojbect。

  kset使用struct kset來描述。

  1. /** 
  2.  * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem. 
  3.  * 
  4.  * A kset defines a group of kobjects.  They can be individually 
  5.  * different "types" but overall these kobjects all want to be grouped 
  6.  * together and operated on in the same manner.  ksets are used to 
  7.  * define the attribute callbacks and other common events that happen to 
  8.  * a kobject. 
  9.  * 
  10.  * @list: the list of all kobjects for this kset 
  11.  * @list_lock: a lock for iterating over the kobjects 
  12.  * @kobj: the embedded kobject for this kset (recursion, isn't it fun...) 
  13.  * @uevent_ops: the set of uevent operations for this kset.  These are 
  14.  * called whenever a kobject has something happen to it so that the kset 
  15.  * can add new environment variables, or filter out the uevents if so 
  16.  * desired. 
  17.  */  
  18. struct kset {  
  19.     struct list_head list;      /*屬於該kset的kobject鏈表*/  
  20.     spinlock_t list_lock;     
  21.     struct kobject kobj;    /*該kset內嵌的kobj*/  
  22.   
  23.     struct kset_uevent_ops *uevent_ops;  
  24. };  

2.3 ktype

每個kobject對象都內嵌有一個ktype,該結構定義了kobject在創建和刪除時所採取的行爲

  1. struct kobj_type {  
  2.     void (*release)(struct kobject *kobj);  
  3.     struct sysfs_ops *sysfs_ops;  
  4.     struct attribute **default_attrs;  
  5. };  
  6.   
  7. struct sysfs_ops {  
  8.     ssize_t    (*show)(struct kobject *, struct attribute *,char *);  
  9.     ssize_t    (*store)(struct kobject *,struct attribute *,const char *, size_t);  
  10. };  
  11.   
  12. /* FIXME 
  13.  * The *owner field is no longer used. 
  14.  * x86 tree has been cleaned up. The owner 
  15.  * attribute is still left for other arches. 
  16.  */  
  17. struct attribute {  
  18.     const char        *name;  
  19.     struct module        *owner;  
  20.     mode_t            mode;  
  21. };  
當kobject的引用計數爲0時,通過release方法來釋放相關的資源。

attribute爲屬性,每個屬性在sysfs中都有對應的屬性文件。

sysfs_op的兩個方法用於實現讀取和寫入屬性文件時應該採取的行爲。

2.4 kobject與kset的關係

  下面這張圖非常經典。最下面的kobj都屬於一個kset,同時這些kobj的父對象就是kset內嵌的kobj。通過鏈表,kset可以獲取所有屬於它的kobj。

   從sysfs角度而言,kset代表一個文件夾,而下面的kobj就是這個文件夾裏面的內容,而內容有可能是文件也有可能是文件夾。



3.舉例

在上一節中,我們知道sys下有一個bus目錄,這一將分析如何通過kobject創建bus目錄。

下面代碼位於drivers/base/bus.c

  1. int __init buses_init(void)  
  2. {  
  3.     bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);  
  4.     if (!bus_kset)  
  5.         return -ENOMEM;  
  6.     return 0;  
  7. }  
  8.   
  9. static struct kset_uevent_ops bus_uevent_ops = {  
  10.     .filter = bus_uevent_filter,  
  11. };  
  12.   
  13. static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)  
  14. {  
  15.     struct kobj_type *ktype = get_ktype(kobj);  
  16.   
  17.     if (ktype == &bus_ktype)  
  18.         return 1;  
  19.     return 0;  
  20. }  
這裏直接調用kset_create_and_add,第一個參數爲要創建的目錄的名字,而第三個參數表示沒有父對象。

下面代碼位於drivers/base/kobject.c

  1. /** 
  2.  * kset_create_and_add - create a struct kset dynamically and add it to sysfs 
  3.  * 
  4.  * @name: the name for the kset 
  5.  * @uevent_ops: a struct kset_uevent_ops for the kset 
  6.  * @parent_kobj: the parent kobject of this kset, if any. 
  7.  * 
  8.  * This function creates a kset structure dynamically and registers it 
  9.  * with sysfs.  When you are finished with this structure, call 
  10.  * kset_unregister() and the structure will be dynamically freed when it 
  11.  * is no longer being used. 
  12.  * 
  13.  * If the kset was not able to be created, NULL will be returned. 
  14.  */  
  15. struct kset *kset_create_and_add(const char *name,  
  16.                  struct kset_uevent_ops *uevent_ops,  
  17.                  struct kobject *parent_kobj)  
  18. {  
  19.     struct kset *kset;  
  20.     int error;  
  21.   
  22.     kset = kset_create(name, uevent_ops, parent_kobj);  /*建立kset,設置某些字段*/  
  23.     if (!kset)  
  24.         return NULL;  
  25.     error = kset_register(kset);    /*添加kset到sysfs*/  
  26.     if (error) {  
  27.         kfree(kset);  
  28.         return NULL;  
  29.     }  
  30.     return kset;  
  31. }  

這裏主要調用了兩個函數,接下分別來看下。

3.1 kset_create函數

下面代碼位於drivers/base/kobject.c

  1. /** 
  2.  * kset_create - create a struct kset dynamically 
  3.  * 
  4.  * @name: the name for the kset 
  5.  * @uevent_ops: a struct kset_uevent_ops for the kset 
  6.  * @parent_kobj: the parent kobject of this kset, if any. 
  7.  * 
  8.  * This function creates a kset structure dynamically.  This structure can 
  9.  * then be registered with the system and show up in sysfs with a call to 
  10.  * kset_register().  When you are finished with this structure, if 
  11.  * kset_register() has been called, call kset_unregister() and the 
  12.  * structure will be dynamically freed when it is no longer being used. 
  13.  * 
  14.  * If the kset was not able to be created, NULL will be returned. 
  15.  */  
  16. static struct kset *kset_create(const char *name,  
  17.                 struct kset_uevent_ops *uevent_ops,  
  18.                 struct kobject *parent_kobj)  
  19. {  
  20.     struct kset *kset;  
  21.   
  22.     kset = kzalloc(sizeof(*kset), GFP_KERNEL);/*分配kset*/  
  23.     if (!kset)  
  24.         return NULL;  
  25.     kobject_set_name(&kset->kobj, name);/*設置kobj->name*/  
  26.     kset->uevent_ops = uevent_ops;  
  27.     kset->kobj.parent = parent_kobj; /*設置父對象*/  
  28.   
  29.     /* 
  30.      * The kobject of this kset will have a type of kset_ktype and belong to 
  31.      * no kset itself.  That way we can properly free it when it is 
  32.      * finished being used. 
  33.      */  
  34.     kset->kobj.ktype = &kset_ktype;  
  35.     kset->kobj.kset = NULL;          /*本keset不屬於任何kset*/  
  36.   
  37.     return kset;  
  38. }  

這個函數中,動態分配了kset結構,調用kobject_set_name設置kset->kobj->name爲bus,也就是我們要創建的目錄bus。同時這裏kset->kobj.parent爲NULL

也就是沒有父對象。因爲要創建的bus目錄是在sysfs所在的根目錄創建的,自然沒有父對象。

隨後簡要看下由kobject_set_name函數調用引發的一系列調用。

  1. /** 
  2.  * kobject_set_name - Set the name of a kobject 
  3.  * @kobj: struct kobject to set the name of 
  4.  * @fmt: format string used to build the name 
  5.  * 
  6.  * This sets the name of the kobject.  If you have already added the 
  7.  * kobject to the system, you must call kobject_rename() in order to 
  8.  * change the name of the kobject. 
  9.  */  
  10. int kobject_set_name(struct kobject *kobj, const char *fmt, ...)  
  11. {  
  12.     va_list vargs;  
  13.     int retval;  
  14.   
  15.     va_start(vargs, fmt);  
  16.     retval = kobject_set_name_vargs(kobj, fmt, vargs);  
  17.     va_end(vargs);  
  18.   
  19.     return retval;  
  20. }  
  21.   
  22. /** 
  23.  * kobject_set_name_vargs - Set the name of an kobject 
  24.  * @kobj: struct kobject to set the name of 
  25.  * @fmt: format string used to build the name 
  26.  * @vargs: vargs to format the string. 
  27.  */  
  28. int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,  
  29.                   va_list vargs)  
  30. {  
  31.     const char *old_name = kobj->name;  
  32.     char *s;  
  33.   
  34.     if (kobj->name && !fmt)  
  35.         return 0;  
  36.   
  37.     kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);  
  38.     if (!kobj->name)  
  39.         return -ENOMEM;  
  40.   
  41.     /* ewww... some of these buggers have '/' in the name ... */  
  42.     while ((s = strchr(kobj->name, '/')))  
  43.         s[0] = '!';  
  44.   
  45.     kfree(old_name);  
  46.     return 0;  
  47. }  
  48.   
  49. /* Simplified asprintf. */  
  50. char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)  
  51. {  
  52.     unsigned int len;  
  53.     char *p;  
  54.     va_list aq;  
  55.   
  56.     va_copy(aq, ap);  
  57.     len = vsnprintf(NULL, 0, fmt, aq);  
  58.     va_end(aq);  
  59.   
  60.     p = kmalloc(len+1, gfp);  
  61.     if (!p)  
  62.         return NULL;  
  63.   
  64.     vsnprintf(p, len+1, fmt, ap);  
  65.   
  66.     return p;  
  67. }  

3.2 kset_register

下面代碼位於drivers/base/kobject.c

  1. /** 
  2.  * kset_register - initialize and add a kset. 
  3.  * @k: kset. 
  4.  */  
  5. int kset_register(struct kset *k)  
  6. {  
  7.     int err;  
  8.   
  9.     if (!k)  
  10.         return -EINVAL;  
  11.   
  12.     kset_init(k);           /*初始化kset*/  
  13.     err = kobject_add_internal(&k->kobj);  /*在sysfs中建立目錄*/  
  14.     if (err)  
  15.         return err;  
  16.     kobject_uevent(&k->kobj, KOBJ_ADD);  
  17.     return 0;  
  18. }  

這裏面調用了3個函數。這裏先介紹前兩個函數。

3.2.1 kset_init

  該函數用於初始化kset。

  下面代碼位於drivers/base/kobject.c。

  1. /** 
  2.  * kset_init - initialize a kset for use 
  3.  * @k: kset 
  4.  */  
  5. void kset_init(struct kset *k)  
  6. {  
  7.     kobject_init_internal(&k->kobj);/*初始化kobject的某些字段*/  
  8.     INIT_LIST_HEAD(&k->list);    /*初始化鏈表頭*/  
  9.     spin_lock_init(&k->list_lock);   /*初始化自旋鎖*/  
  10. }  
  11.   
  12. static void kobject_init_internal(struct kobject *kobj)  
  13. {  
  14.     if (!kobj)  
  15.         return;  
  16.     kref_init(&kobj->kref);           /*初始化引用基計數*/  
  17.     INIT_LIST_HEAD(&kobj->entry);    /*初始化鏈表頭*/  
  18.     kobj->state_in_sysfs = 0;  
  19.     kobj->state_add_uevent_sent = 0;  
  20.     kobj->state_remove_uevent_sent = 0;  
  21.     kobj->state_initialized = 1;  
  22. }  

3.2.2 kobject_add_internal

  該函數將在sysfs中建立目錄。

 下面代碼位於drivers/base/kobject.c。

  1. static int kobject_add_internal(struct kobject *kobj)  
  2. {  
  3.     int error = 0;  
  4.     struct kobject *parent;  
  5.   
  6.     if (!kobj)  
  7.         return -ENOENT;  
  8.     /*檢查name字段是否存在*/  
  9.     if (!kobj->name || !kobj->name[0]) {  
  10.         WARN(1, "kobject: (%p): attempted to be registered with empty "  
  11.              "name!\n", kobj);  
  12.         return -EINVAL;  
  13.     }  
  14.   
  15.     parent = kobject_get(kobj->parent);  /*有父對象則增加父對象引用計數*/  
  16.   
  17.     /* join kset if set, use it as parent if we do not already have one */  
  18.     if (kobj->kset) {      
  19.         if (!parent)  
  20.             /*kobj屬於某個kset,但是該kobj沒有父對象,則以kset的kobj作爲父對象*/  
  21.             parent = kobject_get(&kobj->kset->kobj);  
  22.         kobj_kset_join(kobj);       /*將kojbect添加到kset結構中的鏈表當中*/  
  23.         kobj->parent = parent;  
  24.     }  
  25.   
  26.     pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",  
  27.          kobject_name(kobj), kobj, __func__,  
  28.          parent ? kobject_name(parent) : "<NULL>",  
  29.          kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");  
  30.   
  31.     error = create_dir(kobj);   /*根據kobj->name在sys中建立目錄*/  
  32.     if (error) {  
  33.         kobj_kset_leave(kobj);  /*刪除鏈表項*/  
  34.         kobject_put(parent);    /*減少引用計數*/  
  35.         kobj->parent = NULL;  
  36.   
  37.         /* be noisy on error issues */  
  38.         if (error == -EEXIST)  
  39.             printk(KERN_ERR "%s failed for %s with "  
  40.                    "-EEXIST, don't try to register things with "  
  41.                    "the same name in the same directory.\n",  
  42.                    __func__, kobject_name(kobj));  
  43.         else  
  44.             printk(KERN_ERR "%s failed for %s (%d)\n",  
  45.                    __func__, kobject_name(kobj), error);  
  46.         dump_stack();  
  47.     } else  
  48.         kobj->state_in_sysfs = 1;  
  49.   
  50.     return error;  
  51. }  

在上面的kset_create中有kset->kobj.kset = NULL,因此if (kobj->kset)條件不滿足。因此在這個函數中,對name進行了必要的檢查之後,調用了create_dir在sysfs中創建目錄。

在create_dir執行完成以後會在sysfs的根目錄(/sys/)建立文件夾bus。該函數的詳細分析將在後面給出。

至此,對bus目錄的建立有了簡單而直觀的瞭解。我們可以看出kset其實就是表示一個文件夾,而kset本身也含有一個kobject,而該kobject的name字段即爲該目錄的名字,本例中爲bus。

4. driver model

第2節所介紹的是最底層,最核心的內容。下面開始將描述較爲高層的內容。

Linux設備模型使用了三個數據結構分別來描述總線、設備和驅動。所有的設備和對應的驅動都必須掛載在某一個總線上,通過總線,可以綁定設備和驅動。

這個屬於分離的思想,將設備和驅動分開管理。

同時驅動程序可以瞭解到所有它所支持的設備,同樣的,設備也能知道它對應驅動程序。

4.1 bus

總線是處理器與一個設備或者多個設備之間的通道。在設備模型中,所有的設備都掛載在某一個總線上。總線使用struct bus_type來表述。

下列代碼位於include/linux/device.h。

  1. <strong><span style="font-family:System;font-size:12px;">struct bus_type {  
  2.     const char        *name;  
  3.     struct bus_attribute    *bus_attrs;  
  4.     struct device_attribute    *dev_attrs;  
  5.     struct driver_attribute    *drv_attrs;  
  6.   
  7.     int (*match)(struct device *dev, struct device_driver *drv);  
  8.     int (*uevent)(struct device *dev, struct kobj_uevent_env *env);  
  9.     int (*probe)(struct device *dev);  
  10.     int (*remove)(struct device *dev);  
  11.     void (*shutdown)(struct device *dev);  
  12.   
  13.     int (*suspend)(struct device *dev, pm_message_t state);  
  14.     int (*suspend_late)(struct device *dev, pm_message_t state);  
  15.     int (*resume_early)(struct device *dev);  
  16.     int (*resume)(struct device *dev);  
  17.   
  18.     struct dev_pm_ops *pm;  
  19.   
  20.     struct bus_type_private *p;  
  21. };  
  22.   
  23. /** 
  24.  * struct bus_type_private - structure to hold the private to the driver core portions of the bus_type structure. 
  25.  * 
  26.  * @subsys - the struct kset that defines this bus.  This is the main kobject 
  27.  * @drivers_kset - the list of drivers associated with this bus 
  28.  * @devices_kset - the list of devices associated with this bus 
  29.  * @klist_devices - the klist to iterate over the @devices_kset 
  30.  * @klist_drivers - the klist to iterate over the @drivers_kset 
  31.  * @bus_notifier - the bus notifier list for anything that cares about things 
  32.  * on this bus. 
  33.  * @bus - pointer back to the struct bus_type that this structure is associated 
  34.  * with. 
  35.  * 
  36.  * This structure is the one that is the actual kobject allowing struct 
  37.  * bus_type to be statically allocated safely.  Nothing outside of the driver 
  38.  * core should ever touch these fields. 
  39.  */  
  40. struct bus_type_private {  
  41.     struct kset subsys;  
  42.     struct kset *drivers_kset;  
  43.     struct kset *devices_kset;  
  44.     struct klist klist_devices;  
  45.     struct klist klist_drivers;  
  46.     struct blocking_notifier_head bus_notifier;  
  47.     unsigned int drivers_autoprobe:1;  
  48.     struct bus_type *bus;  
  49. };</span></strong>  
我們看到每個bus_type都包含一個kset對象subsys,該kset在/sys/bus/目錄下有着對應的一個目錄,目錄名即爲字段name。後面我們將看到platform總線的建立。

drivers_kset和devices_kset對應着兩個目錄,該兩個目錄下將包含該總線上的設備和相應的驅動程序。

同時總線上的設備和驅動將分別保存在兩個鏈表中:klist_devices和klist_drivers。

4.2 device

設備對象在driver-model中使用struct device來表示。

下列代碼位於include/linux/device.h。
  1. struct device {  
  2.     struct device       *parent;  
  3.   
  4.     struct device_private   *p;  
  5.   
  6.     struct kobject kobj;  
  7.     const char      *init_name; /* initial name of the device */  
  8.     struct device_type  *type;  
  9.   
  10.     struct semaphore    sem;    /* semaphore to synchronize calls to 
  11.                      * its driver. 
  12.                      */  
  13.   
  14.     struct bus_type *bus;       /* type of bus device is on */  
  15.     struct device_driver *driver;   /* which driver has allocated this 
  16.                        device */  
  17.     void        *driver_data;   /* data private to the driver */  
  18.     void        *platform_data; /* Platform specific data, device 
  19.                        core doesn't touch it */  
  20.     struct dev_pm_info  power;  
  21.   
  22. #ifdef CONFIG_NUMA  
  23.     int     numa_node;  /* NUMA node this device is close to */  
  24. #endif  
  25.     u64     *dma_mask;  /* dma mask (if dma'able device) */  
  26.     u64     coherent_dma_mask;/* Like dma_mask, but for 
  27.                          alloc_coherent mappings as 
  28.                          not all hardware supports 
  29.                          64 bit addresses for consistent 
  30.                          allocations such descriptors. */  
  31.   
  32.     struct device_dma_parameters *dma_parms;  
  33.   
  34.     struct list_head    dma_pools;  /* dma pools (if dma'ble) */  
  35.   
  36.     struct dma_coherent_mem *dma_mem; /* internal for coherent mem 
  37.                          override */  
  38.     /* arch specific additions */  
  39.     struct dev_archdata archdata;  
  40.   
  41.     dev_t           devt;   /* dev_t, creates the sysfs "dev" */  
  42.   
  43.     spinlock_t      devres_lock;  
  44.     struct list_head    devres_head;  
  45.   
  46.     struct klist_node   knode_class;  
  47.     struct class        *class;  
  48.     struct attribute_group  **groups;   /* optional groups */  
  49.   
  50.     void    (*release)(struct device *dev);  
  51. };  
  52.   
  53. /** 
  54.  * struct device_private - structure to hold the private to the driver core portions of the device structure. 
  55.  * 
  56.  * @klist_children - klist containing all children of this device 
  57.  * @knode_parent - node in sibling list 
  58.  * @knode_driver - node in driver list 
  59.  * @knode_bus - node in bus list 
  60.  * @device - pointer back to the struct class that this structure is 
  61.  * associated with. 
  62.  * 
  63.  * Nothing outside of the driver core should ever touch these fields. 
  64.  */  
  65. struct device_private {  
  66.     struct klist klist_children;  
  67.     struct klist_node knode_parent;  
  68.     struct klist_node knode_driver;  
  69.     struct klist_node knode_bus;  
  70.     struct device *device;  
  71. };  

device本身包含一個kobject,也就是說這個device在sysfs的某個地方有着一個對應的目錄。

該device所掛載的bus由knode_bus指定。

該device所對應的設備驅動由knode_driver指定。

4.3 driver

設備設備對象在driver-model中使用struct device_driver來表示。

下列代碼位於include/linux/device.h。

  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.     int (*probe) (struct device *dev);  
  9.     int (*remove) (struct device *dev);  
  10.     void (*shutdown) (struct device *dev);  
  11.     int (*suspend) (struct device *dev, pm_message_t state);  
  12.     int (*resume) (struct device *dev);  
  13.     struct attribute_group **groups;  
  14.   
  15.     struct dev_pm_ops *pm;  
  16.   
  17.     struct driver_private *p;  
  18. };  
  19.   
  20. struct driver_private {  
  21.     struct kobject kobj;  
  22.     struct klist klist_devices;  
  23.     struct klist_node knode_bus;  
  24.     struct module_kobject *mkobj;  
  25.     struct device_driver *driver;  
  26. };   
device_driver本身包含一個kobject,也就是說這個device_driver在sysfs的某個地方有着一個對應的目錄。

該設備驅動所支持的設備由klist_devices指定。

該設備驅動所掛載的總線由knode_bus制定。

5. Bus舉例

本節我們將以platform總線爲例,來看看,/sys/bus/platform是如何建立的。

platform總線的註冊是由platform_bus_init函數完成的。該函數在內核啓動階段被調用,我們來簡單看下調用過程:

start_kernel() -> rest_init() ->kernel_init() -> do_basic_setup() -> driver_init() -> platform_bus_init()。

注:kernel_init()是在rest_init函數中創建內核線程來執行的。


  1. int __init platform_bus_init(void)  
  2. {  
  3.     int error;  
  4.   
  5.     early_platform_cleanup();  
  6.   
  7.     error = device_register(&platform_bus);  
  8.     if (error)  
  9.         return error;  
  10.     error =  bus_register(&platform_bus_type);  
  11.     if (error)  
  12.         device_unregister(&platform_bus);  
  13.     return error;  
  14. }  
  15. struct bus_type platform_bus_type = {  
  16.     .name       = "platform",  
  17.     .dev_attrs  = platform_dev_attrs,  
  18.     .match      = platform_match,  
  19.     .uevent     = platform_uevent,  
  20.     .pm     = PLATFORM_PM_OPS_PTR,  
  21. };  
  22. EXPORT_SYMBOL_GPL(platform_bus_type);  
從bus_type,我們看到該總線的名字爲platform。

調用了兩個函數,我們只關注bus_register函數。

  1. /** 
  2.  * bus_register - register a bus with the system. 
  3.  * @bus: bus. 
  4.  * 
  5.  * Once we have that, we registered the bus with the kobject 
  6.  * infrastructure, then register the children subsystems it has: 
  7.  * the devices and drivers that belong to the bus. 
  8.  */  
  9. int bus_register(struct bus_type *bus)  
  10. {  
  11.     int retval;  
  12.     struct bus_type_private *priv;  
  13.   
  14.     priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);  
  15.     if (!priv)  
  16.         return -ENOMEM;  
  17.     /*互相保存*/  
  18.     priv->bus = bus;  
  19.     bus->p = priv;  
  20.   
  21.     BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);  
  22.     /*設定kobject->name*/  
  23.     retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);  
  24.     if (retval)  
  25.         goto out;  
  26.   
  27.     priv->subsys.kobj.kset = bus_kset;  
  28.     priv->subsys.kobj.ktype = &bus_ktype;  
  29.     priv->drivers_autoprobe = 1;  
  30.   
  31.     /*註冊kset,在bus/建立目錄XXX,XXX爲bus->name*/  
  32.     retval = kset_register(&priv->subsys);     
  33.     if (retval)  
  34.         goto out;  
  35.   
  36.     /*創建屬性,在bus/XXX/建立文件uevent*/  
  37.     retval = bus_create_file(bus, &bus_attr_uevent);  
  38.     if (retval)  
  39.         goto bus_uevent_fail;  
  40.   
  41.     /*創建kset,在bus/XXX/建立目錄devices*/  
  42.     priv->devices_kset = kset_create_and_add("devices", NULL,  
  43.                          &priv->subsys.kobj);  
  44.     if (!priv->devices_kset) {  
  45.         retval = -ENOMEM;  
  46.         goto bus_devices_fail;  
  47.     }  
  48.   
  49.     /*創建kset,在bus/XXX/建立目錄drivers*/  
  50.     priv->drivers_kset = kset_create_and_add("drivers", NULL,  
  51.                          &priv->subsys.kobj);  
  52.     if (!priv->drivers_kset) {  
  53.         retval = -ENOMEM;  
  54.         goto bus_drivers_fail;  
  55.     }  
  56.     /*初始化2個內核鏈表,*/  
  57.     klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);  
  58.     klist_init(&priv->klist_drivers, NULL, NULL);  
  59.   
  60.     /*創建屬性,在bus/XXX/建立文件drivers_autoprobe和drivers_probe*/  
  61.     retval = add_probe_files(bus);  
  62.     if (retval)  
  63.         goto bus_probe_files_fail;  
  64.     /*根據bus->bus_attribute創建屬性,在bus/XXX/下建立相應的文件d*/  
  65.     retval = bus_add_attrs(bus);  
  66.     if (retval)  
  67.         goto bus_attrs_fail;  
  68.   
  69.     pr_debug("bus: '%s': registered\n", bus->name);  
  70.     return 0;  
  71.   
  72. bus_attrs_fail:  
  73.     remove_probe_files(bus);  
  74. bus_probe_files_fail:  
  75.     kset_unregister(bus->p->drivers_kset);  
  76. bus_drivers_fail:  
  77.     kset_unregister(bus->p->devices_kset);  
  78. bus_devices_fail:  
  79.     bus_remove_file(bus, &bus_attr_uevent);  
  80. bus_uevent_fail:  
  81.     kset_unregister(&bus->p->subsys);  
  82.     kfree(bus->p);  
  83. out:  
  84.     bus->p = NULL;  
  85.     return retval;  
  86. }  
  87. EXPORT_SYMBOL_GPL(bus_register);  

函數中,首先調用kobject_set_name設置了bus對象的subsys.kobject->name 爲 platform,也就是說會建立一個名爲platform的目錄。kobject_set_name函數在3.1小節中已經給出。

在這裏還用到了bus_kset這個變量,這個變量就是在第3節buses_init函數中建立bus目錄所對應的kset對象。

接着,priv->subsys.kobj.kset = bus_kset,設置subsys的kobj在bus_kset對象包含的集合中,也就是說bus目錄下將包含subsys對象所對應的目錄,即platform。

緊接着調用了kset_register,參數爲&priv->subsys。該函數在3.2節中以給出。在該函數的調用過程中,將調用kobj_kset_join函數,該函數將kobject添加到kobject->kset的鏈表中。

  1. /* add the kobject to its kset's list */  
  2. static void kobj_kset_join(struct kobject *kobj)  
  3. {  
  4.     if (!kobj->kset)  
  5.         return;  
  6.   
  7.     kset_get(kobj->kset);    /*增加kset引用計數*/  
  8.     spin_lock(&kobj->kset->list_lock);  
  9.     list_add_tail(&kobj->entry, &kobj->kset->list);    /*將kojbect添加到kset結構中的鏈表當中*/  
  10.     spin_unlock(&kobj->kset->list_lock);  
  11. }  
kset_register函數執行完成後,將在/sys/bus/下建立目錄platform。此刻,我們先來看下kset和kobject之間的關係。


然後,調用了bus_create_file函數在/sys/bus/platform/下建立文件uevent。

  1. int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)  
  2. {  
  3.     int error;  
  4.     if (bus_get(bus)) {  
  5.         error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);  
  6.         bus_put(bus);  
  7.     } else  
  8.         error = -EINVAL;  
  9.     return error;  
  10. }  
  11. EXPORT_SYMBOL_GPL(bus_create_file);  
有關底層的sysfs將在後面敘述,這裏只要關注參數&bus->p->subsys.kobj,表示在該kset下建立文件,也就是platform下建立。

接着調用了2次kset_create_and_add,分別在/sys/bus/platform/下建立了文件夾devices和drivers。該函數位於第3節開始處。

這裏和第3節調用kset_create_and_add時的最主要一個區別就是:此時的parent參數不爲NULL,而是&priv->subsys.kobj。

也就是說,將要創建的kset的kobject->parent = &priv->subsys.kobj,也即新建的kset被包含在platform文件夾對應的kset中。

我們來看下關係圖:


隨後,調用了add_probe_files創建了屬性文件drivers_autoprobe和drivers_probe。

  1. static int add_probe_files(struct bus_type *bus)  
  2. {  
  3.     int retval;  
  4.   
  5.     retval = bus_create_file(bus, &bus_attr_drivers_probe);  
  6.     if (retval)  
  7.         goto out;  
  8.   
  9.     retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);  
  10.     if (retval)  
  11.         bus_remove_file(bus, &bus_attr_drivers_probe);  
  12. out:  
  13.     return retval;  
  14. }  
該函數只是簡單的調用了兩次bus_create_file,該函數已在前面敘述過。

最後調用bus_add_attrs創建總線相關的屬性文件。

  1. /** 
  2.  * bus_add_attrs - Add default attributes for this bus. 
  3.  * @bus: Bus that has just been registered. 
  4.  */  
  5.   
  6. static int bus_add_attrs(struct bus_type *bus)  
  7. {  
  8.     int error = 0;  
  9.     int i;  
  10.   
  11.     if (bus->bus_attrs) {  
  12.         for (i = 0; attr_name(bus->bus_attrs[i]); i++) {  
  13.             error = bus_create_file(bus, &bus->bus_attrs[i]);  
  14.             if (error)  
  15.                 goto err;  
  16.         }  
  17.     }  
  18. done:  
  19.     return error;  
  20. err:  
  21.     while (--i >= 0)  
  22.         bus_remove_file(bus, &bus->bus_attrs[i]);  
  23.     goto done;  
  24. }  
我們可以看到這個函數將根據bus_type->bus_arrts來創建屬性文件。不過,在本例中,bus_arrts從未給出定義,因此次函數不做任何工作。

好了,整個bus_register調用完成了,我們來看下sysfs中實際的情況。

[root@yj423 platform]#pwd
/sys/bus/platform
[root@yj423 platform]#ls
devices            drivers            drivers_autoprobe  drivers_probe      uevent

最後,我們對整個bus_register的過程進行一個小結。

6. device舉例

本節將首先講述如何在/sys/devices下建立虛擬的platform設備,然後再講述如何在/sys/devices/platform/下建立子設備。

6.1 虛擬的platform設備

之所以叫虛擬是因爲這個platform並不代表任何實際存在的設備,但是platform將是所有具體設備的父設備。

在第5節,platform_bus_init函數中還調用了device_register,現在對其做出分析。

  1. int __init platform_bus_init(void)  
  2. {  
  3.     int error;  
  4.   
  5.     early_platform_cleanup();  
  6.   
  7.     error = device_register(&platform_bus);  
  8.     if (error)  
  9.         return error;  
  10.     error =  bus_register(&platform_bus_type);  
  11.     if (error)  
  12.         device_unregister(&platform_bus);  
  13.     return error;  
  14. }  
  15.   
  16. struct device platform_bus = {  
  17.     .init_name    = "platform",  
  18. };  
  19. EXPORT_SYMBOL_GPL(platform_bus)  
下列函數位於drivers/base/core.c。
  1. /** 
  2.  * device_register - register a device with the system. 
  3.  * @dev: pointer to the device structure 
  4.  * 
  5.  * This happens in two clean steps - initialize the device 
  6.  * and add it to the system. The two steps can be called 
  7.  * separately, but this is the easiest and most common. 
  8.  * I.e. you should only call the two helpers separately if 
  9.  * have a clearly defined need to use and refcount the device 
  10.  * before it is added to the hierarchy. 
  11.  * 
  12.  * NOTE: _Never_ directly free @dev after calling this function, even 
  13.  * if it returned an error! Always use put_device() to give up the 
  14.  * reference initialized in this function instead. 
  15.  */  
  16. int device_register(struct device *dev)  
  17. {  
  18.     device_initialize(dev); /*初始化dev的某些字段*/  
  19.     return device_add(dev); /*將設備添加到系統中*/  
  20. }  

一個設備的註冊分成兩部,每步通過調用一個函數函數。首先先看第一步:

下列函數位於drivers/base/core.c。

  1. /** 
  2.  * device_initialize - init device structure. 
  3.  * @dev: device. 
  4.  * 
  5.  * This prepares the device for use by other layers by initializing 
  6.  * its fields. 
  7.  * It is the first half of device_register(), if called by 
  8.  * that function, though it can also be called separately, so one 
  9.  * may use @dev's fields. In particular, get_device()/put_device() 
  10.  * may be used for reference counting of @dev after calling this 
  11.  * function. 
  12.  * 
  13.  * NOTE: Use put_device() to give up your reference instead of freeing 
  14.  * @dev directly once you have called this function. 
  15.  */  
  16. void device_initialize(struct device *dev)  
  17. {  
  18.     dev->kobj.kset = devices_kset;        /*設置kobj屬於哪個kset,/sys/devices/*/  
  19.     kobject_init(&dev->kobj, &device_ktype);/*初始化dev->kobj*/  
  20.     INIT_LIST_HEAD(&dev->dma_pools);    /*初始化鏈表頭*/  
  21.     init_MUTEX(&dev->sem);                /*初始化互斥體*/  
  22.     spin_lock_init(&dev->devres_lock);    /*初始化自旋鎖*/  
  23.     INIT_LIST_HEAD(&dev->devres_head);    /*初始化鏈表頭*/  
  24.     device_init_wakeup(dev, 0);            /*設置該device不能喚醒*/  
  25.     device_pm_init(dev);                /*設置該device可操作*/  
  26.     set_dev_node(dev, -1);                /*設置NUMA節點*/  
  27. }  

6.1.1 有關devices_kset

首先其中用到了devices_kset對象,這個對象和第3節當中的bus_kset是同樣的性質,也就是說該對象表示一個目錄。

該對象的建立是在devices_init函數中完成的。

  1. int __init devices_init(void)  
  2. {  
  3.     devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);  
  4.     if (!devices_kset)  
  5.         return -ENOMEM;  
  6.     dev_kobj = kobject_create_and_add("dev", NULL);  
  7.     if (!dev_kobj)  
  8.         goto dev_kobj_err;  
  9.     sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);  
  10.     if (!sysfs_dev_block_kobj)  
  11.         goto block_kobj_err;  
  12.     sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);  
  13.     if (!sysfs_dev_char_kobj)  
  14.         goto char_kobj_err;  
  15.   
  16.     return 0;  
  17.   
  18.  char_kobj_err:  
  19.     kobject_put(sysfs_dev_block_kobj);  
  20.  block_kobj_err:  
  21.     kobject_put(dev_kobj);  
  22.  dev_kobj_err:  
  23.     kset_unregister(devices_kset);  
  24.     return -ENOMEM;  
  25. }  
由此可見,devices_kset對象表示的目錄爲/sys下的devices目錄。

6.1.2 kobject_init

下列函數位於lib/kojbect.c。

  1. /** 
  2.  * kobject_init - initialize a kobject structure 
  3.  * @kobj: pointer to the kobject to initialize 
  4.  * @ktype: pointer to the ktype for this kobject. 
  5.  * 
  6.  * This function will properly initialize a kobject such that it can then 
  7.  * be passed to the kobject_add() call. 
  8.  * 
  9.  * After this function is called, the kobject MUST be cleaned up by a call 
  10.  * to kobject_put(), not by a call to kfree directly to ensure that all of 
  11.  * the memory is cleaned up properly. 
  12.  */  
  13. void kobject_init(struct kobject *kobj, struct kobj_type *ktype)  
  14. {  
  15.     char *err_str;  
  16.   
  17.     if (!kobj) {  
  18.         err_str = "invalid kobject pointer!";  
  19.         goto error;  
  20.     }  
  21.     if (!ktype) {  
  22.         err_str = "must have a ktype to be initialized properly!\n";  
  23.         goto error;  
  24.     }  
  25.     if (kobj->state_initialized) {  
  26.         /* do not error out as sometimes we can recover */  
  27.         printk(KERN_ERR "kobject (%p): tried to init an initialized "  
  28.                "object, something is seriously wrong.\n", kobj);  
  29.         dump_stack();  
  30.     }  
  31.   
  32.     kobject_init_internal(kobj);  
  33.     kobj->ktype = ktype;  
  34.     return;  
  35.   
  36. error:  
  37.     printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);  
  38.     dump_stack();  
  39. }  
  40. EXPORT_SYMBOL(kobject_init);  
  41.   
  42. static void kobject_init_internal(struct kobject *kobj)  
  43. {  
  44.     if (!kobj)  
  45.         return;  
  46.     kref_init(&kobj->kref);            /*初始化引用基計數*/  
  47.     INIT_LIST_HEAD(&kobj->entry);    /*初始化鏈表頭*/  
  48.     kobj->state_in_sysfs = 0;  
  49.     kobj->state_add_uevent_sent = 0;  
  50.     kobj->state_remove_uevent_sent = 0;  
  51.     kobj->state_initialized = 1;  
  52. }  
該函數在做了一系列的必要檢查後,調用kobject_init_internal初始化了kobject的某些字段。

6.1.3 device_init_wakeup

參數val爲0,設置該device不能夠喚醒。

  1. #ifdef CONFIG_PM  
  2.   
  3. /* changes to device_may_wakeup take effect on the next pm state change. 
  4.  * by default, devices should wakeup if they can. 
  5.  */  
  6. static inline void device_init_wakeup(struct device *dev, int val)  
  7. {  
  8.     dev->power.can_wakeup = dev->power.should_wakeup = !!val;  
  9. }  
  10. 。。。。。。  
  11. #else /* !CONFIG_PM */  
  12.   
  13. /* For some reason the next two routines work even without CONFIG_PM */  
  14. static inline void device_init_wakeup(struct device *dev, int val)  
  15. {  
  16.     dev->power.can_wakeup = !!val;  
  17. }  
  18. 。。。。。。  
  19. #endif  

6.1.4 device_pm_init

設置電源的狀態。

  1. static inline void device_pm_init(struct device *dev)  
  2. {  
  3.     dev->power.status = DPM_ON;    /*該device被認爲可操作*/  
  4. }  

6.1.5 set_dev_node

如果使用NUMA,則設置NUMA節點。

  1. #ifdef CONFIG_NUMA  
  2. 。。。。。。  
  3. static inline void set_dev_node(struct device *dev, int node)  
  4. {  
  5.     dev->numa_node = node;  
  6. }  
  7. #else  
  8. 。。。。。。  
  9. static inline void set_dev_node(struct device *dev, int node)  
  10. {  
  11. }  
  12. #endif  

6.2 device_add

接下來是註冊的第二步:調用device_add。

  1. /** 
  2.  * device_add - add device to device hierarchy. 
  3.  * @dev: device. 
  4.  * 
  5.  * This is part 2 of device_register(), though may be called 
  6.  * separately _iff_ device_initialize() has been called separately. 
  7.  * 
  8.  * This adds @dev to the kobject hierarchy via kobject_add(), adds it 
  9.  * to the global and sibling lists for the device, then 
  10.  * adds it to the other relevant subsystems of the driver model. 
  11.  * 
  12.  * NOTE: _Never_ directly free @dev after calling this function, even 
  13.  * if it returned an error! Always use put_device() to give up your 
  14.  * reference instead. 
  15.  */  
  16. int device_add(struct device *dev)  
  17. {  
  18.     struct device *parent = NULL;  
  19.     struct class_interface *class_intf;  
  20.     int error = -EINVAL;  
  21.   
  22.     dev = get_device(dev);  /*增加引用計數*/  
  23.     if (!dev)  
  24.         goto done;  
  25.   
  26.     dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);    /*分配device_private結構*/  
  27.     if (!dev->p) {  
  28.         error = -ENOMEM;  
  29.         goto done;  
  30.     }  
  31.     dev->p->device = dev; /*保存dev*/  
  32.     klist_init(&dev->p->klist_children, klist_children_get,   /*初始化內核鏈表*/  
  33.            klist_children_put);  
  34.   
  35.     /* 
  36.      * for statically allocated devices, which should all be converted 
  37.      * some day, we need to initialize the name. We prevent reading back 
  38.      * the name, and force the use of dev_name() 
  39.      */  
  40.     if (dev->init_name) {  
  41.         dev_set_name(dev, dev->init_name);   /*dev->kobject->name = dev->init_name*/  
  42.         dev->init_name = NULL;  
  43.     }  
  44.   
  45.     if (!dev_name(dev)) /*檢查dev->kobject->name*/  
  46.         goto name_error;  
  47.   
  48.     pr_debug("device: '%s': %s\n", dev_name(dev), __func__);  
  49.   
  50.     parent = get_device(dev->parent);    /*增加父設備引用計數*/  
  51.     setup_parent(dev, parent);          /*設置dev->kobject->parent*/  
  52.   
  53.     /* use parent numa_node */  
  54.     if (parent)  
  55.         set_dev_node(dev, dev_to_node(parent));  
  56.   
  57.     /* first, register with generic layer. */  
  58.     /* we require the name to be set before, and pass NULL */  
  59.     /* 執行完以後,將在/sys/devices/下建立目錄XXX,目錄名XXX爲dev->kobj->name*/  
  60.     error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);    
  61.     if (error)  
  62.         goto Error;  
  63.   
  64.     /* notify platform of device entry */  
  65.     if (platform_notify)  
  66.         platform_notify(dev);  
  67.   
  68.     /*在XXX下建立文件uevent*/  
  69.     error = device_create_file(dev, &uevent_attr);  
  70.     if (error)  
  71.         goto attrError;  
  72.   
  73.     if (MAJOR(dev->devt)) {/*主設備號不爲0*/  
  74.         error = device_create_file(dev, &devt_attr);/*創建屬性文件dev*/  
  75.         if (error)  
  76.             goto ueventattrError;  
  77.   
  78.         /* 在sys/dev/char/下建立symlink,名字爲主設備號:次設備號,該鏈接指向XXX */  
  79.         error = device_create_sys_dev_entry(dev);   
  80.         if (error)  
  81.             goto devtattrError;  
  82.     }  
  83.   
  84.     error = device_add_class_symlinks(dev);  
  85.     if (error)  
  86.         goto SymlinkError;  
  87.     error = device_add_attrs(dev);  /*添加類設備屬型文件和屬性組*/  
  88.     if (error)  
  89.         goto AttrsError;  
  90.     error = bus_add_device(dev);    /*添加3個symlink*/  
  91.     if (error)  
  92.         goto BusError;  
  93.     error = dpm_sysfs_add(dev);     /*創建power子目錄,並在其下添加電源管理的屬性組文件*/  
  94.     if (error)  
  95.         goto DPMError;  
  96.     device_pm_add(dev);             /*將該device添加到電源管理鏈表中*/  
  97.   
  98.     /* Notify clients of device addition.  This call must come 
  99.      * after dpm_sysf_add() and before kobject_uevent(). 
  100.      */  
  101.     if (dev->bus)  
  102.         blocking_notifier_call_chain(&dev->bus->p->bus_notifier,  
  103.                          BUS_NOTIFY_ADD_DEVICE, dev);  
  104.   
  105.     kobject_uevent(&dev->kobj, KOBJ_ADD);    /*通知用戶層*/  
  106.     bus_attach_device(dev);                 /*將設備添加到總線的設備鏈表中,並嘗試獲取驅動*/  
  107.     if (parent)  
  108.         klist_add_tail(&dev->p->knode_parent, /*有父設備,則將該設備添加到父設備的兒子鏈表中*/  
  109.                    &parent->p->klist_children);  
  110.   
  111.     if (dev->class) {                        /*該設備屬於某個設備類*/  
  112.         mutex_lock(&dev->class->p->class_mutex);  
  113.         /* tie the class to the device */  
  114.         klist_add_tail(&dev->knode_class,    /*將device添加到class的類設備鏈表中*/  
  115.                    &dev->class->p->class_devices);  
  116.   
  117.         /* notify any interfaces that the device is here */  
  118.         list_for_each_entry(class_intf,  
  119.                     &dev->class->p->class_interfaces, node)  
  120.             if (class_intf->add_dev)  
  121.                 class_intf->add_dev(dev, class_intf);  
  122.         mutex_unlock(&dev->class->p->class_mutex);  
  123.     }  
  124. done:  
  125.     put_device(dev);  
  126.     return error;  
  127.  DPMError:  
  128.     bus_remove_device(dev);  
  129.  BusError:  
  130.     device_remove_attrs(dev);  
  131.  AttrsError:  
  132.     device_remove_class_symlinks(dev);  
  133.  SymlinkError:  
  134.     if (MAJOR(dev->devt))  
  135.         device_remove_sys_dev_entry(dev);  
  136.  devtattrError:  
  137.     if (MAJOR(dev->devt))  
  138.         device_remove_file(dev, &devt_attr);  
  139.  ueventattrError:  
  140.     device_remove_file(dev, &uevent_attr);  
  141.  attrError:  
  142.     kobject_uevent(&dev->kobj, KOBJ_REMOVE);  
  143.     kobject_del(&dev->kobj);  
  144.  Error:  
  145.     cleanup_device_parent(dev);  
  146.     if (parent)  
  147.         put_device(parent);  
  148. name_error:  
  149.     kfree(dev->p);  
  150.     dev->p = NULL;  
  151.     goto done;  
  152. }  

該函數調用了非常多的其他函數,接下來對主要的函數做出分析。

6.2.1 setup_parent函數

下列代碼位於drivers/base/core.c。

  1. static void setup_parent(struct device *dev, struct device *parent)  
  2. {  
  3.     struct kobject *kobj;  
  4.     kobj = get_device_parent(dev, parent);  
  5.     if (kobj)  
  6.         dev->kobj.parent = kobj;  
  7. }  
  8.   
  9. static struct kobject *get_device_parent(struct device *dev,  
  10.                      struct device *parent)  
  11. {  
  12.     /* class devices without a parent live in /sys/class/<classname>/ */  
  13.     if (dev->class && (!parent || parent->class != dev->class))  
  14.         return &dev->class->p->class_subsys.kobj;  
  15.     /* all other devices keep their parent */  
  16.     else if (parent)  
  17.         return &parent->kobj;  
  18.   
  19.     return NULL;  
  20. }  
該函數將設置dev對象的parent。在這裏實際傳入的parent爲NULL,同時dev->class也沒有定義過。因此這個函數什麼都沒有做。

6.2.2 kobject_add函數

下列代碼位於lib/kobject.c。

  1. /** 
  2.  * kobject_add - the main kobject add function 
  3.  * @kobj: the kobject to add 
  4.  * @parent: pointer to the parent of the kobject. 
  5.  * @fmt: format to name the kobject with. 
  6.  * 
  7.  * The kobject name is set and added to the kobject hierarchy in this 
  8.  * function. 
  9.  * 
  10.  * If @parent is set, then the parent of the @kobj will be set to it. 
  11.  * If @parent is NULL, then the parent of the @kobj will be set to the 
  12.  * kobject associted with the kset assigned to this kobject.  If no kset 
  13.  * is assigned to the kobject, then the kobject will be located in the 
  14.  * root of the sysfs tree. 
  15.  * 
  16.  * If this function returns an error, kobject_put() must be called to 
  17.  * properly clean up the memory associated with the object. 
  18.  * Under no instance should the kobject that is passed to this function 
  19.  * be directly freed with a call to kfree(), that can leak memory. 
  20.  * 
  21.  * Note, no "add" uevent will be created with this call, the caller should set 
  22.  * up all of the necessary sysfs files for the object and then call 
  23.  * kobject_uevent() with the UEVENT_ADD parameter to ensure that 
  24.  * userspace is properly notified of this kobject's creation. 
  25.  */  
  26. int kobject_add(struct kobject *kobj, struct kobject *parent,  
  27.         const char *fmt, ...)  
  28. {  
  29.     va_list args;  
  30.     int retval;  
  31.   
  32.     if (!kobj)  
  33.         return -EINVAL;  
  34.   
  35.     if (!kobj->state_initialized) {  
  36.         printk(KERN_ERR "kobject '%s' (%p): tried to add an "  
  37.                "uninitialized object, something is seriously wrong.\n",  
  38.                kobject_name(kobj), kobj);  
  39.         dump_stack();  
  40.         return -EINVAL;  
  41.     }  
  42.     va_start(args, fmt);  
  43.     retval = kobject_add_varg(kobj, parent, fmt, args);  
  44.     va_end(args);  
  45.   
  46.     return retval;  
  47. }  
  48. EXPORT_SYMBOL(kobject_add);  
  49.   
  50. static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,  
  51.                 const char *fmt, va_list vargs)  
  52. {  
  53.     int retval;  
  54.   
  55.     retval = kobject_set_name_vargs(kobj, fmt, vargs);  
  56.     if (retval) {  
  57.         printk(KERN_ERR "kobject: can not set name properly!\n");  
  58.         return retval;  
  59.     }  
  60.     kobj->parent = parent;  
  61.     return kobject_add_internal(kobj);  
  62. }  
  63.   
  64. static int kobject_add_internal(struct kobject *kobj)  
  65. {  
  66.     int error = 0;  
  67.     struct kobject *parent;  
  68.   
  69.     if (!kobj)  
  70.         return -ENOENT;  
  71.     /*檢查name字段是否存在*/  
  72.     if (!kobj->name || !kobj->name[0]) {  
  73.         WARN(1, "kobject: (%p): attempted to be registered with empty "  
  74.              "name!\n", kobj);  
  75.         return -EINVAL;  
  76.     }  
  77.   
  78.     parent = kobject_get(kobj->parent);    /*有父對象則增加父對象引用計數*/  
  79.   
  80.     /* join kset if set, use it as parent if we do not already have one */  
  81.     if (kobj->kset) {      
  82.         if (!parent)  
  83.             /*kobj屬於某個kset,但是該kobj沒有父對象,則以kset的kobj作爲父對象*/  
  84.             parent = kobject_get(&kobj->kset->kobj);  
  85.         kobj_kset_join(kobj);        /*將kojbect添加到kset結構中的鏈表當中*/  
  86.         kobj->parent = parent;  
  87.     }  
  88.   
  89.     pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",  
  90.          kobject_name(kobj), kobj, __func__,  
  91.          parent ? kobject_name(parent) : "<NULL>",  
  92.          kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");  
  93.   
  94.     error = create_dir(kobj);    /*根據kobj->name在sys中建立目錄*/  
  95.     if (error) {  
  96.         kobj_kset_leave(kobj);    /*刪除鏈表項*/  
  97.         kobject_put(parent);    /*減少引用計數*/  
  98.         kobj->parent = NULL;  
  99.   
  100.         /* be noisy on error issues */  
  101.         if (error == -EEXIST)  
  102.             printk(KERN_ERR "%s failed for %s with "  
  103.                    "-EEXIST, don't try to register things with "  
  104.                    "the same name in the same directory.\n",  
  105.                    __func__, kobject_name(kobj));  
  106.         else  
  107.             printk(KERN_ERR "%s failed for %s (%d)\n",  
  108.                    __func__, kobject_name(kobj), error);  
  109.         dump_stack();  
  110.     } else  
  111.         kobj->state_in_sysfs = 1;  
  112.   
  113.     return error;  
  114. }  
在調用時,參數parent爲NULL,且dev->kobj.kset在6.1節device_initialize函數中設置爲devices_kset。

而devices_kset對應着/sys/devices目錄,因此該函數調用完成後將在/sys/devices目錄下生成目錄platform。

但是這裏比較奇怪的是,爲什麼platform目錄沒有對應的kset對象???

6.2.3 device_create_sys_dev_entry函數

在調用該函數之前,會在/sys/devices/platform/下生成屬性文件。接着如果該device的設備號不爲0,則創建屬性文件dev,並調用本函數。

但是,在本例中設備號devt從未設置過,顯然爲0,那麼本函數實際並未執行。

下列代碼位於drivers/base/core.c。

  1. static int device_create_sys_dev_entry(struct device *dev)  
  2. {  
  3.     struct kobject *kobj = device_to_dev_kobj(dev);  
  4.     int error = 0;  
  5.     char devt_str[15];  
  6.   
  7.     if (kobj) {  
  8.         format_dev_t(devt_str, dev->devt);  
  9.         error = sysfs_create_link(kobj, &dev->kobj, devt_str);  
  10.     }  
  11.   
  12.     return error;  
  13. }  
  14. /** 
  15.  * device_to_dev_kobj - select a /sys/dev/ directory for the device 
  16.  * @dev: device 
  17.  * 
  18.  * By default we select char/ for new entries.  Setting class->dev_obj 
  19.  * to NULL prevents an entry from being created.  class->dev_kobj must 
  20.  * be set (or cleared) before any devices are registered to the class 
  21.  * otherwise device_create_sys_dev_entry() and 
  22.  * device_remove_sys_dev_entry() will disagree about the the presence 
  23.  * of the link. 
  24.  */  
  25. static struct kobject *device_to_dev_kobj(struct device *dev)  
  26. {  
  27.     struct kobject *kobj;  
  28.   
  29.     if (dev->class)  
  30.         kobj = dev->class->dev_kobj;  
  31.     else  
  32.         kobj = sysfs_dev_char_kobj;  
  33.   
  34.     return kobj;  
  35. }  

6.2.4 device_add_class_symlinks函數

由於dev->class爲NULL,本函數其實沒做任何工作。

下列代碼位於drivers/base/core.c。

  1. static int device_add_class_symlinks(struct device *dev)  
  2. {  
  3.     int error;  
  4.   
  5.     if (!dev->class)  
  6.         return 0;  
  7.   
  8.     error = sysfs_create_link(&dev->kobj,  
  9.                   &dev->class->p->class_subsys.kobj,  
  10.                   "subsystem");  
  11.     if (error)  
  12.         goto out;  
  13.   
  14. #ifdef CONFIG_SYSFS_DEPRECATED  
  15.     /* stacked class devices need a symlink in the class directory */  
  16.     if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&  
  17.         device_is_not_partition(dev)) {  
  18.         error = sysfs_create_link(&dev->class->p->class_subsys.kobj,  
  19.                       &dev->kobj, dev_name(dev));  
  20.         if (error)  
  21.             goto out_subsys;  
  22.     }  
  23.   
  24.     if (dev->parent && device_is_not_partition(dev)) {  
  25.         struct device *parent = dev->parent;  
  26.         char *class_name;  
  27.   
  28.         /* 
  29.          * stacked class devices have the 'device' link 
  30.          * pointing to the bus device instead of the parent 
  31.          */  
  32.         while (parent->class && !parent->bus && parent->parent)  
  33.             parent = parent->parent;  
  34.   
  35.         error = sysfs_create_link(&dev->kobj,  
  36.                       &parent->kobj,  
  37.                       "device");  
  38.         if (error)  
  39.             goto out_busid;  
  40.   
  41.         class_name = make_class_name(dev->class->name,  
  42.                         &dev->kobj);  
  43.         if (class_name)  
  44.             error = sysfs_create_link(&dev->parent->kobj,  
  45.                         &dev->kobj, class_name);  
  46.         kfree(class_name);  
  47.         if (error)  
  48.             goto out_device;  
  49.     }  
  50.     return 0;  
  51.   
  52. out_device:  
  53.     if (dev->parent && device_is_not_partition(dev))  
  54.         sysfs_remove_link(&dev->kobj, "device");  
  55. out_busid:  
  56.     if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&  
  57.         device_is_not_partition(dev))  
  58.         sysfs_remove_link(&dev->class->p->class_subsys.kobj,  
  59.                   dev_name(dev));  
  60. #else  
  61.     /* link in the class directory pointing to the device */  
  62.     error = sysfs_create_link(&dev->class->p->class_subsys.kobj,  
  63.                   &dev->kobj, dev_name(dev));  
  64.     if (error)  
  65.         goto out_subsys;  
  66.   
  67.     if (dev->parent && device_is_not_partition(dev)) {  
  68.         error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,  
  69.                       "device");  
  70.         if (error)  
  71.             goto out_busid;  
  72.     }  
  73.     return 0;  
  74.   
  75. out_busid:  
  76.     sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev_name(dev));  
  77. #endif  
  78.   
  79. out_subsys:  
  80.     sysfs_remove_link(&dev->kobj, "subsystem");  
  81. out:  
  82.     return error;  
  83. }  

6.2.5 device_add_attrs函數

同樣dev->class爲空,什麼都沒幹。

下列代碼位於drivers/base/core.c。

  1. static int device_add_attrs(struct device *dev)  
  2. {  
  3.     struct class *class = dev->class;  
  4.     struct device_type *type = dev->type;  
  5.     int error;  
  6.   
  7.     if (class) {  
  8.         error = device_add_attributes(dev, class->dev_attrs);  
  9.         if (error)  
  10.             return error;  
  11.     }  
  12.   
  13.     if (type) {  
  14.         error = device_add_groups(dev, type->groups);  
  15.         if (error)  
  16.             goto err_remove_class_attrs;  
  17.     }  
  18.   
  19.     error = device_add_groups(dev, dev->groups);  
  20.     if (error)  
  21.         goto err_remove_type_groups;  
  22.   
  23.     return 0;  
  24.   
  25.  err_remove_type_groups:  
  26.     if (type)  
  27.         device_remove_groups(dev, type->groups);  
  28.  err_remove_class_attrs:  
  29.     if (class)  
  30.         device_remove_attributes(dev, class->dev_attrs);  
  31.   
  32.     return error;  
  33. }  

6.2.6 bus_add_device函數

由於dev->bus未指定,因此這個函數什麼都沒幹。

該函數將創建三個symlink,在sysfs中建立總線和設備間的關係。

下列代碼位於drivers/base/bus.c。

  1. /** 
  2.  * bus_add_device - add device to bus 
  3.  * @dev: device being added 
  4.  * 
  5.  * - Add the device to its bus's list of devices. 
  6.  * - Create link to device's bus. 
  7.  */  
  8. int bus_add_device(struct device *dev)  
  9. {  
  10.     struct bus_type *bus = bus_get(dev->bus);  
  11.     int error = 0;  
  12.   
  13.     if (bus) {  
  14.         pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev));  
  15.         error = device_add_attrs(bus, dev);  
  16.         if (error)  
  17.             goto out_put;  
  18.           
  19.         /*在sys/bus/XXX/devices下建立symlink,名字爲設備名,該鏈接指向/sys/devices/下的某個目錄*/  
  20.         error = sysfs_create_link(&bus->p->devices_kset->kobj,  
  21.                         &dev->kobj, dev_name(dev));  
  22.         if (error)  
  23.             goto out_id;  
  24.           
  25.         /*在sys/devices/的某個目錄下建立symlink,名字爲subsystem,該鏈接指向/sys/bus/下的某個目錄*/  
  26.         error = sysfs_create_link(&dev->kobj,  
  27.                 &dev->bus->p->subsys.kobj, "subsystem");  
  28.         if (error)  
  29.             goto out_subsys;  
  30.           
  31.         /*在sys/devices/的某個目錄下建立symlink,名字爲bus,該鏈接指向/sys/bus/下的某個目錄*/  
  32.         error = make_deprecated_bus_links(dev);  
  33.         if (error)  
  34.             goto out_deprecated;  
  35.     }  
  36.     return 0;  
  37.   
  38. out_deprecated:  
  39.     sysfs_remove_link(&dev->kobj, "subsystem");  
  40. out_subsys:  
  41.     sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));  
  42. out_id:  
  43.     device_remove_attrs(bus, dev);  
  44. out_put:  
  45.     bus_put(dev->bus);  
  46.     return error;  
  47. }  

6.2.7 dpm_sysfs_add函數

下列代碼位於drivers/base/power/sysfs.c。

  1. int dpm_sysfs_add(struct device * dev)  
  2. {  
  3.     return sysfs_create_group(&dev->kobj, &pm_attr_group);  
  4. }  
  5.   
  6. static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);  
  7.   
  8.   
  9. static struct attribute * power_attrs[] = {  
  10.     &dev_attr_wakeup.attr,  
  11.     NULL,  
  12. };  
  13. static struct attribute_group pm_attr_group = {  
  14.     .name    = "power",  
  15.     .attrs    = power_attrs,  
  16. };  

該函數將在XXX目錄下建立power子目錄,並在該子目錄下建立屬性文件wakeup。

在本例中,將在/sys/bus/platform下建立子目錄power並在子目錄下建立wakeup文件。

6.2.8 device_pm_add函數

下列代碼位於drivers/base/power/main.c。

  1. /** 
  2.  *  device_pm_add - add a device to the list of active devices 
  3.  *  @dev:   Device to be added to the list 
  4.  */  
  5. void device_pm_add(struct device *dev)  
  6. {  
  7.     pr_debug("PM: Adding info for %s:%s\n",  
  8.          dev->bus ? dev->bus->name : "No Bus",  
  9.          kobject_name(&dev->kobj));  
  10.     mutex_lock(&dpm_list_mtx);  
  11.     if (dev->parent) {  
  12.         if (dev->parent->power.status >= DPM_SUSPENDING)  
  13.             dev_warn(dev, "parent %s should not be sleeping\n",  
  14.                  dev_name(dev->parent));  
  15.     } else if (transition_started) {  
  16.         /* 
  17.          * We refuse to register parentless devices while a PM 
  18.          * transition is in progress in order to avoid leaving them 
  19.          * unhandled down the road 
  20.          */  
  21.         dev_WARN(dev, "Parentless device registered during a PM transaction\n");  
  22.     }  
  23.   
  24.     list_add_tail(&dev->power.entry, &dpm_list); /*將該設備添加到鏈表中*/  
  25.     mutex_unlock(&dpm_list_mtx);  
  26. }  

該函數只是將設備添加到電源管理鏈表中。

6.2.9 bus_attach_device函數

在本例中,由於bus未指定,該函數實際不做任何工作。

下列代碼位於drivers/base/bus.c。

  1. /** 
  2.  * bus_attach_device - add device to bus 
  3.  * @dev: device tried to attach to a driver 
  4.  * 
  5.  * - Add device to bus's list of devices. 
  6.  * - Try to attach to driver. 
  7.  */  
  8. void bus_attach_device(struct device *dev)  
  9. {  
  10.     struct bus_type *bus = dev->bus;  
  11.     int ret = 0;  
  12.   
  13.     if (bus) {  
  14.         if (bus->p->drivers_autoprobe)  
  15.             ret = device_attach(dev);   /*嘗試獲取驅動*/  
  16.         WARN_ON(ret < 0);  
  17.         if (ret >= 0)        /*將設備掛在到總線中*/  
  18.             klist_add_tail(&dev->p->knode_bus,  
  19.                        &bus->p->klist_devices);  
  20.     }  
  21. }  
  22.   
  23. /** 
  24.  * device_attach - try to attach device to a driver. 
  25.  * @dev: device. 
  26.  * 
  27.  * Walk the list of drivers that the bus has and call 
  28.  * driver_probe_device() for each pair. If a compatible 
  29.  * pair is found, break out and return. 
  30.  * 
  31.  * Returns 1 if the device was bound to a driver; 
  32.  * 0 if no matching device was found; 
  33.  * -ENODEV if the device is not registered. 
  34.  * 
  35.  * When called for a USB interface, @dev->parent->sem must be held. 
  36.  */  
  37. int device_attach(struct device *dev)  
  38. {  
  39.     int ret = 0;  
  40.   
  41.     down(&dev->sem);  
  42.     if (dev->driver) {    /*如果已指定驅動,即已綁定*/  
  43.         ret = device_bind_driver(dev);    /*在sysfs中建立鏈接關係*/  
  44.         if (ret == 0)  
  45.             ret = 1;  
  46.         else {  
  47.             dev->driver = NULL;  
  48.             ret = 0;  
  49.         }  
  50.     } else {        /*尚未綁定,嘗試綁定,遍歷該總線上的所有驅動*/  
  51.         ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);  
  52.     }  
  53.     up(&dev->sem);  
  54.     return ret;  
  55. }  
  56. EXPORT_SYMBOL_GPL(device_attach);  


如果bus存在的話,將會調用device_attach函數進行綁定工作。該函數首先判斷dev->driver,如果非0,表示該設備已經綁定了驅動,只要在sysfs中建立鏈接關係即可。

爲0表示沒有綁定,接着調用bus_for_each_drv,注意作爲參數傳入的__device_attach,這是個函數,後面會調用它。

我們來看下bus_for_each_drv:

  1. /** 
  2.  * bus_for_each_drv - driver iterator 
  3.  * @bus: bus we're dealing with. 
  4.  * @start: driver to start iterating on. 
  5.  * @data: data to pass to the callback. 
  6.  * @fn: function to call for each driver. 
  7.  * 
  8.  * This is nearly identical to the device iterator above. 
  9.  * We iterate over each driver that belongs to @bus, and call 
  10.  * @fn for each. If @fn returns anything but 0, we break out 
  11.  * and return it. If @start is not NULL, we use it as the head 
  12.  * of the list. 
  13.  * 
  14.  * NOTE: we don't return the driver that returns a non-zero 
  15.  * value, nor do we leave the reference count incremented for that 
  16.  * driver. If the caller needs to know that info, it must set it 
  17.  * in the callback. It must also be sure to increment the refcount 
  18.  * so it doesn't disappear before returning to the caller. 
  19.  */  
  20. int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,  
  21.              void *data, int (*fn)(struct device_driver *, void *))  
  22. {  
  23.     struct klist_iter i;  
  24.     struct device_driver *drv;  
  25.     int error = 0;  
  26.   
  27.     if (!bus)  
  28.         return -EINVAL;  
  29.   
  30.     klist_iter_init_node(&bus->p->klist_drivers, &i,  
  31.                  start ? &start->p->knode_bus : NULL);  
  32.     while ((drv = next_driver(&i)) && !error)  
  33.         error = fn(drv, data);  
  34.     klist_iter_exit(&i);  
  35.     return error;  
  36. }  
  37. EXPORT_SYMBOL_GPL(bus_for_each_drv);  
該函數將遍歷總線的drivers目錄下的所有驅動,也就是/sys/bus/XXX/drivers/下的目錄,爲該driver調用fn函數,也就是__device_attach。我們來看下:

  1. static int __device_attach(struct device_driver *drv, void *data)  
  2. {  
  3.     struct device *dev = data;  
  4.   
  5.     if (!driver_match_device(drv, dev))   /*進行匹配工作*/  
  6.         return 0;  
  7.   
  8.     return driver_probe_device(drv, dev);  
  9. }  
  10.   
  11. static inline int driver_match_device(struct device_driver *drv,  
  12.                       struct device *dev)  
  13. {  
  14.     return drv->bus->match ? drv->bus->match(dev, drv) : 1;  
  15. }   
  16.   
  17. /** 
  18.  * driver_probe_device - attempt to bind device & driver together 
  19.  * @drv: driver to bind a device to 
  20.  * @dev: device to try to bind to the driver 
  21.  * 
  22.  * This function returns -ENODEV if the device is not registered, 
  23.  * 1 if the device is bound sucessfully and 0 otherwise. 
  24.  * 
  25.  * This function must be called with @dev->sem held.  When called for a 
  26.  * USB interface, @dev->parent->sem must be held as well. 
  27.  */  
  28. int driver_probe_device(struct device_driver *drv, struct device *dev)  
  29. {  
  30.     int ret = 0;  
  31.   
  32.     if (!device_is_registered(dev))    /*該device是否已在sysfs中*/  
  33.         return -ENODEV;  
  34.   
  35.     pr_debug("bus: '%s': %s: matched device %s with driver %s\n",  
  36.          drv->bus->name, __func__, dev_name(dev), drv->name);  
  37.   
  38.     ret = really_probe(dev, drv);/*device已在sysfs,調用really_probe*/      
  39.   
  40.     return ret;  
  41. }  

該函數首先調用driver_match_device函數,後者將會調用總線的match方法,如果有的話,來進行匹配工作。如果沒有該方法,則返回1,表示匹配成功。

我們這裏是針對platform總線,該總線的方法將在7.6.2節中看到。

隨後,又調用了driver_probe_device函數。該函數將首先判斷該device是否已在sysfs中,如果在則調用really_probe,否則返回出錯。

really_probe將會調用驅動的probe並完成綁定的工作。該函數將在7.6.2節中分析。

6.2.10 小結

在本例中,當device_register調用完成以後,將在/sys/devices/下建立目錄platform,並在platfrom下建立屬性文件uevent和子目錄power,最後在power子目錄下建立wakeup屬性文件。

最後以函數調用過程的總結來結束第6.2小結。



6.3 spi主控制器的平臺設備

本節對一個特定的platform設備進行講解,那就是spi主控制器的平臺設備。

在內核的啓動階段,platform設備將被註冊進內核。我們來看下。

下列代碼位於arch/arm/mach-s3c2440/mach-smdk2440.c

  1. static struct resource s3c_spi0_resource[] = {  
  2.     [0] = {  
  3.         .start = S3C24XX_PA_SPI,  
  4.         .end   = S3C24XX_PA_SPI + 0x1f,  
  5.         .flags = IORESOURCE_MEM,  
  6.     },  
  7.     [1] = {  
  8.         .start = IRQ_SPI0,  
  9.         .end   = IRQ_SPI0,  
  10.         .flags = IORESOURCE_IRQ,  
  11.     }  
  12.   
  13. };  
  14.   
  15. static u64 s3c_device_spi0_dmamask = 0xffffffffUL;  
  16.   
  17. struct platform_device s3c_device_spi0 = {  
  18.     .name          = "s3c2410-spi",  
  19.     .id          = 0,  
  20.     .num_resources      = ARRAY_SIZE(s3c_spi0_resource),  
  21.     .resource      = s3c_spi0_resource,  
  22.         .dev              = {  
  23.                 .dma_mask = &s3c_device_spi0_dmamask,  
  24.                 .coherent_dma_mask = 0xffffffffUL  
  25.         }  
  26. };  
  27.   
  28. static struct platform_device *smdk2440_devices[] __initdata = {  
  29.     &s3c_device_usb,  
  30.     &s3c_device_lcd,  
  31.     &s3c_device_wdt,  
  32.     &s3c_device_i2c0,  
  33.     &s3c_device_iis,  
  34.     &s3c_device_spi0,  
  35. };  
  36.   
  37.   
  38.   
  39. static void __init smdk2440_machine_init(void)  
  40. {  
  41.     s3c24xx_fb_set_platdata(&smdk2440_fb_info);  
  42.     s3c_i2c0_set_platdata(NULL);  
  43.   
  44.     platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));  
  45.     smdk_machine_init();  
  46. }  


在smdk2440_machine_init函數中,通過調用platform_add_devices將設備註冊到內核中。接着來看下該函數。

6.3.1 platform_add_devices

  1. /** 
  2.  * platform_add_devices - add a numbers of platform devices 
  3.  * @devs: array of platform devices to add 
  4.  * @num: number of platform devices in array 
  5.  */  
  6. int platform_add_devices(struct platform_device **devs, int num)  
  7. {  
  8.     int i, ret = 0;  
  9.   
  10.     for (i = 0; i < num; i++) {  
  11.         ret = platform_device_register(devs[i]);  
  12.         if (ret) {  
  13.             while (--i >= 0)  
  14.                 platform_device_unregister(devs[i]);  
  15.             break;  
  16.         }  
  17.     }  
  18.   
  19.     return ret;  
  20. }  
  21. EXPORT_SYMBOL_GPL(platform_add_devices);  
該函數將根據devs指針數組,調用platform_device_register將platform設備逐一註冊進內核。

6.3.2  platform_device_register

  1. /** 
  2.  * platform_device_register - add a platform-level device 
  3.  * @pdev: platform device we're adding 
  4.  */  
  5. int platform_device_register(struct platform_device *pdev)  
  6. {  
  7.     device_initialize(&pdev->dev);  
  8.     return platform_device_add(pdev);  
  9. }  
  10. EXPORT_SYMBOL_GPL(platform_device_register);  
調用了兩個函數,第一個函數在6.1節已經分析過。我們來看下第二個函數。

6.3.2  platform_device_register

  1. /** 
  2.  * platform_device_add - add a platform device to device hierarchy 
  3.  * @pdev: platform device we're adding 
  4.  * 
  5.  * This is part 2 of platform_device_register(), though may be called 
  6.  * separately _iff_ pdev was allocated by platform_device_alloc(). 
  7.  */  
  8. int platform_device_add(struct platform_device *pdev)  
  9. {  
  10.     int i, ret = 0;  
  11.   
  12.     if (!pdev)  
  13.         return -EINVAL;  
  14.   
  15.     if (!pdev->dev.parent)  
  16.         pdev->dev.parent = &platform_bus;    /*該設備的父設備是platform設備,/sys/devices/platform*/  
  17.   
  18.     pdev->dev.bus = &platform_bus_type;      /*設備掛載到platform總線上*/  
  19.   
  20.     if (pdev->id != -1)  
  21.         dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);  
  22.     else  
  23.         dev_set_name(&pdev->dev, pdev->name);/*pdev->dev->kobj->name = pdev->name*/  
  24.   
  25.     /*遍歷平臺設備的資源,並將資源添加到資源樹中*/  
  26.     for (i = 0; i < pdev->num_resources; i++) {  
  27.         struct resource *p, *r = &pdev->resource[i];  
  28.   
  29.         if (r->name == NULL)  
  30.             r->name = dev_name(&pdev->dev);   /*獲取dev->kobject->name*/  
  31.   
  32.         p = r->parent;  
  33.         if (!p) {   /*p空*/  
  34.             if (resource_type(r) == IORESOURCE_MEM)  
  35.                 p = &iomem_resource;  
  36.             else if (resource_type(r) == IORESOURCE_IO)  
  37.                 p = &ioport_resource;  
  38.         }  
  39.   
  40.         if (p && insert_resource(p, r)) {   /*將資源添加到資源樹中*/  
  41.             printk(KERN_ERR  
  42.                    "%s: failed to claim resource %d\n",  
  43.                    dev_name(&pdev->dev), i);  
  44.             ret = -EBUSY;  
  45.             goto failed;  
  46.         }  
  47.     }  
  48.   
  49.     pr_debug("Registering platform device '%s'. Parent at %s\n",  
  50.          dev_name(&pdev->dev), dev_name(pdev->dev.parent));  
  51.   
  52.     ret = device_add(&pdev->dev);    /*添加設備*/  
  53.     if (ret == 0)  
  54.         return ret;  
  55.   
  56.  failed:  
  57.     while (--i >= 0) {  
  58.         struct resource *r = &pdev->resource[i];  
  59.         unsigned long type = resource_type(r);  
  60.   
  61.         if (type == IORESOURCE_MEM || type == IORESOURCE_IO)  
  62.             release_resource(r);  
  63.     }  
  64.   
  65.     return ret;  
  66. }  
  67. EXPORT_SYMBOL_GPL(platform_device_add);  
在這個函數的最後赫然出現了device_add函數。我們回憶下在6.1節中device_register的註冊過程,該函數只調用了兩個函數,一個是device_initialize函數,另一個就是device_add。

本節的platform_device_register函數,首先也是調用了device_initialize,但是隨後他做了一些其他的工作,最後調用了device_add。

那麼這個"其他的工作"幹了些什麼呢?

首先,它將該SPI主控制對應的平臺設備的父設備設爲虛擬的platform設備(platform_bus),然後將該平臺設備掛在至platform總線(platform_bus_type)上,這兩步尤爲重要,後面我們將看到。

然後,調用了dev_set_name設置了pdev->dev-kobj.name,也就是該設備對象的名字,這裏的名字爲s3c2410-spi.0,這個名字將被用來建立一個目錄。

最後,將平臺的相關資源添加到資源樹中。這不是本篇文章討論的重點所在,所以不做過多說明。

在"其他的工作""幹完之後,調用了device_add函數。那麼後面的函數調用過程將和6.2小結的一致。

由於“其他的工作”的原因,實際執行的過程和結果將有所區別。我們來分析下。

6.3.3 不一樣device_add調用結果

首先,在device_add被調用之前,有若干個非常重要的條件已經被設置了。如下:

pdev->dev->kobj.kset = devices_kset

pdev->dev-.parent = &platform_bus

pdev->dev.bus = &platform_bus_type

set_up函數執行時,由於參數parent爲&platform_bus,因此最後將設置pdev->dev->kobj.parent = platform_bus.kobj。平臺設備對象的父對象爲虛擬的platform設備。

kobject_add函數執行時,由於參數parent的存在,將在parent對象所對應的目錄下創建另一個目錄。parent對象代表目錄/sys/devices/下的platform,因此將在/sys/devices/platform下建立目錄s3c2410-spi.0。

device_create_file建立屬性文件uevent。

bus_add_device函數執行時,由於dev.bus 爲&platform_bus_type,因此將建立三個symlink。

            /sys/devices/platform/s3c2410-spi.0下建立鏈接subsystem和bus,他們指向/sys/bus/platform。

           /sys/bus/platform/devices/下建立鏈接s3c2410-spi.0,指向/sys/devices/platform/s3c2410-spi.0。

dpm_sysfs_add函數在/sys/devices/platform/s3c2410-spi.0下建立子目錄power,並在該子目錄下建立屬性文件wakeup。

執行到這裏時,sysfs已將內核中新添加的SPI主控制器平臺設備呈現出來了,我們來驗證下。

[root@yj423 s3c2410-spi.0]#pwd/sys/devices/platform/s3c2410-spi.0[root@yj423 s3c2410-spi.0]#lllrwxrwxrwx    1 root     root             0 Jan  1 00:29 bus -> ../../../bus/platformlrwxrwxrwx    1 root     root             0 Jan  1 00:29 driver -> ../../../bus/platform/drivers/s3c2410-spi-r--r--r--    1 root     root          4096 Jan  1 00:29 modaliasdrwxr-xr-x    2 root     root             0 Jan  1 00:29 powerdrwxr-xr-x    3 root     root             0 Jan  1 00:00 spi0.0drwxr-xr-x    3 root     root             0 Jan  1 00:00 spi0.1lrwxrwxrwx    1 root     root             0 Jan  1 00:29 spi_master:spi0 -> ../../../class/spi_master/spi0lrwxrwxrwx    1 root     root             0 Jan  1 00:29 subsystem -> ../../../bus/platform-rw-r--r--    1 root     root          4096 Jan  1 00:29 uevent

[root@yj423 devices]#pwd/sys/bus/platform/devices[root@yj423 devices]#ll s3c2410-spi.0 lrwxrwxrwx    1 root     root             0 Jan  1 00:44 s3c2410-spi.0 -> ../../../devices/platform/s3c2410-spi.0

通過sysfs將設備驅動的模型層次呈現在用戶空間以後,將更新內核的設備模型之間的關係,這是通過修改鏈表的指向來完成的。

bus_attach_device函數執行時,將設備添加到總線的設備鏈表中,同時也會嘗試綁定驅動,不過會失敗。

接着,由於dev->parent的存在,將SPI主控制器設備添加到父設備platform虛擬設備的兒子鏈表中。

7. driver舉例

我們已經介紹過platform總線的註冊,也講述了SPI主控制器設備作爲平臺設備的註冊過程,在本節,將描述SPI主控制器的platform驅動是如何註冊的。

7.1 s3c24xx_spi_init

下列代碼位於drivers/spi/spi_s3c24xx.c。

  1. MODULE_ALIAS("platform:s3c2410-spi");  
  2. static struct platform_driver s3c24xx_spi_driver = {  
  3.     .remove        = __exit_p(s3c24xx_spi_remove),  
  4.     .suspend    = s3c24xx_spi_suspend,  
  5.     .resume        = s3c24xx_spi_resume,  
  6.     .driver        = {  
  7.         .name    = "s3c2410-spi",  
  8.         .owner    = THIS_MODULE,  
  9.     },  
  10. };  
  11.   
  12. static int __init s3c24xx_spi_init(void)  
  13. {  
  14.         return platform_driver_probe(&s3c24xx_spi_driver, s3c24xx_spi_probe);//設備不可熱插拔,所以使用該函數,而不是platform_driver_register  
  15. }  
驅動註冊通過調用platform_driver_probe來完成。

注意:driver.name字段使用來匹配設備的,該字段必須和6.3節一開始給出的pdev.name字段相同。

7.2  platform_driver_probe

下列代碼位於drivers/base/platform.c。

  1. /** 
  2.  * platform_driver_probe - register driver for non-hotpluggable device 
  3.  * @drv: platform driver structure 
  4.  * @probe: the driver probe routine, probably from an __init section 
  5.  * 
  6.  * Use this instead of platform_driver_register() when you know the device 
  7.  * is not hotpluggable and has already been registered, and you want to 
  8.  * remove its run-once probe() infrastructure from memory after the driver 
  9.  * has bound to the device. 
  10.  * 
  11.  * One typical use for this would be with drivers for controllers integrated 
  12.  * into system-on-chip processors, where the controller devices have been 
  13.  * configured as part of board setup. 
  14.  * 
  15.  * Returns zero if the driver registered and bound to a device, else returns 
  16.  * a negative error code and with the driver not registered. 
  17.  */  
  18. int __init_or_module platform_driver_probe(struct platform_driver *drv,  
  19.         int (*probe)(struct platform_device *))  
  20. {  
  21.     int retval, code;  
  22.   
  23.     /* temporary section violation during probe() */  
  24.     drv->probe = probe;  
  25.     retval = code = platform_driver_register(drv); /*註冊platform驅動*/  
  26.   
  27.     /* Fixup that section violation, being paranoid about code scanning 
  28.      * the list of drivers in order to probe new devices.  Check to see 
  29.      * if the probe was successful, and make sure any forced probes of 
  30.      * new devices fail. 
  31.      */  
  32.     spin_lock(&platform_bus_type.p->klist_drivers.k_lock);  
  33.     drv->probe = NULL;  
  34.     if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))  
  35.         retval = -ENODEV;  
  36.     drv->driver.probe = platform_drv_probe_fail;  
  37.     spin_unlock(&platform_bus_type.p->klist_drivers.k_lock);  
  38.   
  39.     if (code != retval)  
  40.         platform_driver_unregister(drv);  
  41.     return retval;  
  42. }  
  43. EXPORT_SYMBOL_GPL(platform_driver_probe);  
這裏的重點是platform_driver_register,由它來完成了platform驅動的註冊。

7.3 platform_driver_register

  1. /** 
  2.  * platform_driver_register 
  3.  * @drv: platform driver structure 
  4.  */  
  5. int platform_driver_register(struct platform_driver *drv)  
  6. {  
  7.     drv->driver.bus = &platform_bus_type;  
  8.     if (drv->probe)  
  9.         drv->driver.probe = platform_drv_probe;  
  10.     if (drv->remove)  
  11.         drv->driver.remove = platform_drv_remove;  
  12.     if (drv->shutdown)  
  13.         drv->driver.shutdown = platform_drv_shutdown;  
  14.     if (drv->suspend)  
  15.         drv->driver.suspend = platform_drv_suspend;  
  16.     if (drv->resume)  
  17.         drv->driver.resume = platform_drv_resume;  
  18.     return driver_register(&drv->driver); /*驅動註冊*/  
  19. }  
  20. EXPORT_SYMBOL_GPL(platform_driver_register);  
driver_register函數就是driver註冊的核心函數。需要注意的是,在調用函數之前,將該驅動所掛載的總線設置爲platform總線(platform_bus_type)。

7.4 driver_register

下列代碼位於drivers/base/driver.c。

  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 -EEXIST;  
  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. }  
  38. EXPORT_SYMBOL_GPL(driver_register);  
這裏主要調用兩個函數driver_find和bus_add_driver。前者將通過總線來搜索該驅動是否存在,後者將添加驅動到總線中。

接下來就分析這兩個函數。

7.5 driver_find

下列代碼位於drivers/base/driver.c。

  1. /** 
  2.  * driver_find - locate driver on a bus by its name. 
  3.  * @name: name of the driver. 
  4.  * @bus: bus to scan for the driver. 
  5.  * 
  6.  * Call kset_find_obj() to iterate over list of drivers on 
  7.  * a bus to find driver by name. Return driver if found. 
  8.  * 
  9.  * Note that kset_find_obj increments driver's reference count. 
  10.  */  
  11. struct device_driver *driver_find(const char *name, struct bus_type *bus)  
  12. {  
  13.     struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);  
  14.     struct driver_private *priv;  
  15.   
  16.     if (k) {  
  17.         priv = to_driver(k);  
  18.         return priv->driver;  
  19.     }  
  20.     return NULL;  
  21. }  
  22. EXPORT_SYMBOL_GPL(driver_find);  

  1. /** 
  2.  * kset_find_obj - search for object in kset. 
  3.  * @kset: kset we're looking in. 
  4.  * @name: object's name. 
  5.  * 
  6.  * Lock kset via @kset->subsys, and iterate over @kset->list, 
  7.  * looking for a matching kobject. If matching object is found 
  8.  * take a reference and return the object. 
  9.  */  
  10. struct kobject *kset_find_obj(struct kset *kset, const char *name)  
  11. {  
  12.     struct kobject *k;  
  13.     struct kobject *ret = NULL;  
  14.   
  15.     spin_lock(&kset->list_lock);  
  16.     list_for_each_entry(k, &kset->list, entry) {  
  17.         if (kobject_name(k) && !strcmp(kobject_name(k), name)) {  
  18.             ret = kobject_get(k);  
  19.             break;  
  20.         }  
  21.     }  
  22.     spin_unlock(&kset->list_lock);  
  23.     return ret;  
  24. }  


這裏調用了kset_find_obj函數,傳入的實參bus->p->drivers_kset,它對應的就是/sys/bus/platform/下的drivers目錄,然後通過鏈表,它將搜索該目錄下的所有文件,來尋找是否有名爲s3c2410-spi的文件。還記得嗎? kobject就是一個文件對象。如果沒有找到將返回NULL,接着將調用bus_add_driver把驅動註冊進內核。

7.6 bus_add_driver

下列代碼位於drivers/base/bus.c

  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); /*增加引用計數獲取bus_type*/  
  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);  /*分配driver_private結構體*/  
  18.     if (!priv) {  
  19.         error = -ENOMEM;  
  20.         goto out_put_bus;  
  21.     }  
  22.     /*初始化內核鏈表*/  
  23.     klist_init(&priv->klist_devices, NULL, NULL);  
  24.     /*相互保存*/  
  25.     priv->driver = drv;  
  26.     drv->p = priv;  
  27.     /*設置該kobj屬於那個kset*/  
  28.     priv->kobj.kset = bus->p->drivers_kset;  
  29.     error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,   /*parent=NULL*/  
  30.                      "%s", drv->name);   /*執行完以後,會在bus/總線名/drivers/下建立名爲drv->name的目錄*/  
  31.     if (error)  
  32.         goto out_unregister;  
  33.   
  34.     if (drv->bus->p->drivers_autoprobe) {  
  35.         error = driver_attach(drv); /*嘗試綁定驅動和設備*/  
  36.         if (error)  
  37.             goto out_unregister;  
  38.     }  
  39.     /*添加該驅動到bus的內核鏈表中*/  
  40.     klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);  
  41.     module_add_driver(drv->owner, drv);/*?????????*/  
  42.   
  43.     /*創建屬性,在bus/總線名/drivers/驅動名/下建立文件uevent*/  
  44.     error = driver_create_file(drv, &driver_attr_uevent);  
  45.     if (error) {  
  46.         printk(KERN_ERR "%s: uevent attr (%s) failed\n",  
  47.             __func__, drv->name);  
  48.     }  
  49.     /*利用bus->drv_attrs創建屬性,位於bus/總線名/drivers/驅動名/*/  
  50.     error = driver_add_attrs(bus, drv);  
  51.     if (error) {  
  52.         /* How the hell do we get out of this pickle? Give up */  
  53.         printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",  
  54.             __func__, drv->name);  
  55.     }  
  56.     /*創建屬性,在bus/總線名/drivers/驅動名/下建立文件bind和unbind*/  
  57.     error = add_bind_files(drv);  
  58.     if (error) {  
  59.         /* Ditto */  
  60.         printk(KERN_ERR "%s: add_bind_files(%s) failed\n",  
  61.             __func__, drv->name);  
  62.     }  
  63.     /*通知用戶空間???*/  
  64.     kobject_uevent(&priv->kobj, KOBJ_ADD);  
  65.     return 0;  
  66. out_unregister:  
  67.     kfree(drv->p);  
  68.     drv->p = NULL;  
  69.     kobject_put(&priv->kobj);  
  70. out_put_bus:  
  71.     bus_put(bus);  
  72.     return error;  
  73. }  
在設置driver的kobj.kset爲drivers目錄所對應的kset之後,調用了kobject_init_and_add,我們來看下。

7.6.1 kobject_init_and_add

下列代碼位於lib/kobject.c。

  1. /** 
  2.  * kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy 
  3.  * @kobj: pointer to the kobject to initialize 
  4.  * @ktype: pointer to the ktype for this kobject. 
  5.  * @parent: pointer to the parent of this kobject. 
  6.  * @fmt: the name of the kobject. 
  7.  * 
  8.  * This function combines the call to kobject_init() and 
  9.  * kobject_add().  The same type of error handling after a call to 
  10.  * kobject_add() and kobject lifetime rules are the same here. 
  11.  */  
  12. int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,  
  13.              struct kobject *parent, const char *fmt, ...)  
  14. {  
  15.     va_list args;  
  16.     int retval;  
  17.   
  18.     kobject_init(kobj, ktype);  
  19.   
  20.     va_start(args, fmt);  
  21.     retval = kobject_add_varg(kobj, parent, fmt, args);  
  22.     va_end(args);  
  23.   
  24.     return retval;  
  25. }  
  26. EXPORT_SYMBOL_GPL(kobject_init_and_add);  
該函數中調用了兩個函數,這兩個函數分別在6.1.2和6.2.2中講述過,這裏不再贅述。

調用該函數時由於parent爲NULL,但kobj.kset爲drivers目錄,所以將在/sys/bus/platform/drivers/下建立目錄,名爲s3c2410-spi。

我們來驗證下:

[root@yj423 s3c2410-spi]#pwd
/sys/bus/platform/drivers/s3c2410-spi

接着由於drivers_autoprobe在bus_register執行的時候已經置1,將調用driver_attach。

7.6.2 driver_attach

下列代碼位於drivers/base/dd.c。

  1. /** 
  2.  * driver_attach - try to bind driver to devices. 
  3.  * @drv: driver. 
  4.  * 
  5.  * Walk the list of devices that the bus has on it and try to 
  6.  * match the driver with each one.  If driver_probe_device() 
  7.  * returns 0 and the @dev->driver is set, we've found a 
  8.  * compatible pair. 
  9.  */  
  10. int driver_attach(struct device_driver *drv)  
  11. {  
  12.     return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);  
  13. }  
  14. EXPORT_SYMBOL_GPL(driver_attach);  
該函數將調用bus_for_each_dev來尋找總線上的每個設備,這裏的總線即爲platform總線,然後嘗試綁定設備。

這裏需要注意的是最後一個參數__driver_attach,這是一個函數名,後面將會調用它。

  1. /** 
  2.  * bus_for_each_dev - device iterator. 
  3.  * @bus: bus type. 
  4.  * @start: device to start iterating from. 
  5.  * @data: data for the callback. 
  6.  * @fn: function to be called for each device. 
  7.  * 
  8.  * Iterate over @bus's list of devices, and call @fn for each, 
  9.  * passing it @data. If @start is not NULL, we use that device to 
  10.  * begin iterating from. 
  11.  * 
  12.  * We check the return of @fn each time. If it returns anything 
  13.  * other than 0, we break out and return that value. 
  14.  * 
  15.  * NOTE: The device that returns a non-zero value is not retained 
  16.  * in any way, nor is its refcount incremented. If the caller needs 
  17.  * to retain this data, it should do, and increment the reference 
  18.  * count in the supplied callback. 
  19.  */  
  20. int bus_for_each_dev(struct bus_type *bus, struct device *start,  
  21.              void *data, int (*fn)(struct device *, void *))  
  22. {  
  23.     struct klist_iter i;  
  24.     struct device *dev;  
  25.     int error = 0;  
  26.   
  27.     if (!bus)  
  28.         return -EINVAL;  
  29.   
  30.     klist_iter_init_node(&bus->p->klist_devices, &i,  
  31.                  (start ? &start->p->knode_bus : NULL));  
  32.     while ((dev = next_device(&i)) && !error)  
  33.         error = fn(dev, data);  
  34.     klist_iter_exit(&i);  
  35.     return error;  
  36. }  
  37. EXPORT_SYMBOL_GPL(bus_for_each_dev);  
通過klist將遍歷該總線上的所有設備,併爲其調用__driver_attach函數。

  1. static int __driver_attach(struct device *dev, void *data)  
  2. {  
  3.     struct device_driver *drv = data;  
  4.   
  5.     /* 
  6.      * Lock device and try to bind to it. We drop the error 
  7.      * here and always return 0, because we need to keep trying 
  8.      * to bind to devices and some drivers will return an error 
  9.      * simply if it didn't support the device. 
  10.      * 
  11.      * driver_probe_device() will spit a warning if there 
  12.      * is an error. 
  13.      */  
  14.   
  15.     if (!driver_match_device(drv, dev))  
  16.         return 0;  
  17.   
  18.     if (dev->parent) /* Needed for USB */  
  19.         down(&dev->parent->sem);  
  20.     down(&dev->sem);  
  21.     if (!dev->driver)  
  22.         driver_probe_device(drv, dev);  
  23.     up(&dev->sem);  
  24.     if (dev->parent)  
  25.         up(&dev->parent->sem);  
  26.   
  27.     return 0;  
  28. }  
首先調用了driver_match_device函數,該函數進會進行匹配,如果匹配成功將返回1。我們看下這個函數:

  1. static inline int driver_match_device(struct device_driver *drv,  
  2.                       struct device *dev)  
  3. {  
  4.     return drv->bus->match ? drv->bus->match(dev, drv) : 1;  
  5. }  

這裏直接調用了platform總線的match方法,我們來看下這個方法。

  1. /** 
  2.  * platform_match - bind platform device to platform driver. 
  3.  * @dev: device. 
  4.  * @drv: driver. 
  5.  * 
  6.  * Platform device IDs are assumed to be encoded like this: 
  7.  * "<name><instance>", where <name> is a short description of the type of 
  8.  * device, like "pci" or "floppy", and <instance> is the enumerated 
  9.  * instance of the device, like '0' or '42'.  Driver IDs are simply 
  10.  * "<name>".  So, extract the <name> from the platform_device structure, 
  11.  * and compare it against the name of the driver. Return whether they match 
  12.  * or not. 
  13.  */  
  14. static int platform_match(struct device *dev, struct device_driver *drv)  
  15. {  
  16.     struct platform_device *pdev = to_platform_device(dev);  
  17.     struct platform_driver *pdrv = to_platform_driver(drv);  
  18.   
  19.     /* match against the id table first */  
  20.     if (pdrv->id_table)  
  21.         return platform_match_id(pdrv->id_table, pdev) != NULL;  
  22.   
  23.     /* fall-back to driver name match */  
  24.     return (strcmp(pdev->name, drv->name) == 0);  
  25. }  
該方法的核心其實就是使用stcmp進行字符匹配,判斷pdev->name和drv->name是否相等。

在本例中兩者同爲s3c2410-spi。因此匹配完成,返回1。

返回後,由於dev->driver爲NULL,將調用driver_probe_device函數。我們來看下:

  1. /** 
  2.  * driver_probe_device - attempt to bind device & driver together 
  3.  * @drv: driver to bind a device to 
  4.  * @dev: device to try to bind to the driver 
  5.  * 
  6.  * This function returns -ENODEV if the device is not registered, 
  7.  * 1 if the device is bound sucessfully and 0 otherwise. 
  8.  * 
  9.  * This function must be called with @dev->sem held.  When called for a 
  10.  * USB interface, @dev->parent->sem must be held as well. 
  11.  */  
  12. int driver_probe_device(struct device_driver *drv, struct device *dev)  
  13. {  
  14.     int ret = 0;  
  15.   
  16.     if (!device_is_registered(dev))  
  17.         return -ENODEV;  
  18.   
  19.     pr_debug("bus: '%s': %s: matched device %s with driver %s\n",  
  20.          drv->bus->name, __func__, dev_name(dev), drv->name);  
  21.   
  22.     ret = really_probe(dev, drv);  
  23.   
  24.     return ret;  
  25. }  
  26. static inline int device_is_registered(struct device *dev)  
  27. {  
  28.     return dev->kobj.state_in_sysfs;  
  29. }  
該函數將調用really_probe來綁定設備和它的驅動。
  1. static int really_probe(struct device *dev, struct device_driver *drv)  
  2. {  
  3.     int ret = 0;  
  4.   
  5.     atomic_inc(&probe_count);  
  6.     pr_debug("bus: '%s': %s: probing driver %s with device %s\n",  
  7.          drv->bus->name, __func__, drv->name, dev_name(dev));  
  8.     WARN_ON(!list_empty(&dev->devres_head));  
  9.   
  10.     dev->driver = drv;  
  11.     if (driver_sysfs_add(dev)) {    /*創建兩個symlink,更新sysfs*/  
  12.         printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",  
  13.             __func__, dev_name(dev));  
  14.         goto probe_failed;  
  15.     }  
  16.   
  17.     if (dev->bus->probe) {  
  18.         ret = dev->bus->probe(dev);/*調用總線的probe方法*/  
  19.         if (ret)  
  20.             goto probe_failed;  
  21.     } else if (drv->probe) {  
  22.         ret = drv->probe(dev);   /*調用驅動的probe方法*/  
  23.         if (ret)  
  24.             goto probe_failed;  
  25.     }  
  26.   
  27.     driver_bound(dev);              /*綁定設備和驅動*/  
  28.     ret = 1;  
  29.     pr_debug("bus: '%s': %s: bound device %s to driver %s\n",  
  30.          drv->bus->name, __func__, dev_name(dev), drv->name);  
  31.     goto done;  
  32.   
  33. probe_failed:  
  34.     devres_release_all(dev);  
  35.     driver_sysfs_remove(dev);  
  36.     dev->driver = NULL;  
  37.   
  38.     if (ret != -ENODEV && ret != -ENXIO) {  
  39.         /* driver matched but the probe failed */  
  40.         printk(KERN_WARNING  
  41.                "%s: probe of %s failed with error %d\n",  
  42.                drv->name, dev_name(dev), ret);  
  43.     }  
  44.     /* 
  45.      * Ignore errors returned by ->probe so that the next driver can try 
  46.      * its luck. 
  47.      */  
  48.     ret = 0;  
  49. done:  
  50.     atomic_dec(&probe_count);  
  51.     wake_up(&probe_waitqueue);  
  52.     return ret;  
  53. }  

在這個函數中調用4個函數。

第一個函數driver_sysfs_add將更新sysfs。

  1. static int driver_sysfs_add(struct device *dev)  
  2. {  
  3.     int ret;  
  4.     /* 在/sys/bus/XXX/drivers/XXX目錄下建立symlink,鏈接名爲kobj->name, 
  5.        鏈接指向/sys/devices/platform/XXX */  
  6.     ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,  
  7.               kobject_name(&dev->kobj));  
  8.     if (ret == 0) {  
  9.         /* 在/sys/devices/platform/XXX/下建立symlink,鏈接名爲driver, 
  10.           指向/sys/bus/xxx/drivers目錄下的某個目錄*/  
  11.         ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,  
  12.                     "driver");  
  13.         if (ret)  
  14.             sysfs_remove_link(&dev->driver->p->kobj,  
  15.                     kobject_name(&dev->kobj));  
  16.     }  
  17.     return ret;  
  18. }  

執行完以後,建立了兩個鏈接。

在/sys/bus/platform/drivers/s3c2410-spi下建立鏈接,指向/sys/devices/platform/s3c2410-spi.0

在/sys/devices/platform/s3c2410-spi.0下建立鏈接,指向/sys/devices/platform/s3c2410-spi.0。

這樣就在用戶空間呈現出驅動和設備的關係了。我們來驗證下。

[root@yj423 s3c2410-spi]#pwd
/sys/bus/platform/drivers/s3c2410-spi
[root@yj423 s3c2410-spi]#ll s3c2410-spi.0 
lrwxrwxrwx    1 root     root             0 Jan  1 02:28 s3c2410-spi.0 -> ../../../../devices/platform/s3c2410-spi.0

[root@yj423 s3c2410-spi.0]#pwd
/sys/devices/platform/s3c2410-spi.0
[root@yj423 s3c2410-spi.0]#ll driver
lrwxrwxrwx    1 root     root             0 Jan  1 02:26 driver -> ../../../bus/platform/drivers/s3c2410-spi

第2個函數執行總線的probe方法,由於platform總線沒有提供probe方法,因此不執行。

第3個函數執行驅動的probe方法,驅動提供了probe,因此調用它,該函數的細節超過了本文的討論內容,所以略過。

第4個函數執行driver_bound,用來綁定設備和驅動,來看下這個函數。

  1. static void driver_bound(struct device *dev)  
  2. {  
  3.     if (klist_node_attached(&dev->p->knode_driver)) {  
  4.         printk(KERN_WARNING "%s: device %s already bound\n",  
  5.             __func__, kobject_name(&dev->kobj));  
  6.         return;  
  7.     }  
  8.   
  9.     pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),  
  10.          __func__, dev->driver->name);  
  11.   
  12.     if (dev->bus)  
  13.         blocking_notifier_call_chain(&dev->bus->p->bus_notifier,  
  14.                          BUS_NOTIFY_BOUND_DRIVER, dev);  
  15.   
  16.     klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);  
  17. }  
其實,所謂的綁定,就是將設備的驅動節點添加到驅動支持的設備鏈表中。

至此,通過內核鏈表,這個platform device 和platform driver 已經綁定完成,將繼續遍歷內核鏈表嘗試匹配和綁定,直到鏈表結束。

在driver_attach執行完畢以後,bus_add_driver函數還有些剩餘工作要完成。

首先,將驅動添加到總線的驅動列表中。

接着,如果定義了驅動屬性文件,則創建。

最後,在/sys/bus/platform/drivers/s3c2410-spi/下建立屬性文件uevent,並在同一目錄下建立文件bind和unbind。

我們來驗證下:

[root@yj423 s3c2410-spi]#pwd
/sys/bus/platform/drivers/s3c2410-spi
[root@yj423 s3c2410-spi]#ls
bind           s3c2410-spi.0  uevent         unbind

7.7 小結

在本節中,我們看到了platform driver是如何註冊到內核中,在註冊過程中,通過更新了sysfs,向用戶空間展示總線,設備和驅動之間的關係。

同時,還更新了鏈表的指向,在內核中體現了同樣的關係。

最後以platform driver的註冊過程結束本章。



8. sysfs底層函數

下面講述的內容將基於VFS,有關VFS的基本內容超過本文的範圍,請參考<<深入理解Linux內核>>一書的第12章。

在前面講述的過程中,我們知道設備驅動模型是如何通過kobject將總線,設備和驅動間的層次關係在用戶空間呈現出來的。事實上,就是通過目錄,文件和symlink來呈現相互之間的關係。在前面的敘述中,我們並沒有對目錄,文件和symlink的創建進行 講解,本章就對這些底層函數進行講解。在講解這些函數之前,我們先來看下,sysfs文件系統是如何註冊的。

8.1 註冊sysfs文件系統

sysfs文件系統的註冊是調用sysfs_init函數來完成的,該函數在內核啓動階段被調用,我們來看下大致函數調用流程,這裏不作分析。

start_kernel( ) ->  vfs_caches_init( ) ->  mnt_init( ) ->  mnt_init( ) ->  sysfs_init( )。


  1. int __init sysfs_init(void)  
  2. {  
  3.     int err = -ENOMEM;  
  4.     /*建立cache,名字爲sysfs_dir_cache*/  
  5.     sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache",  
  6.                           sizeof(struct sysfs_dirent),  
  7.                           0, 0, NULL);  
  8.     if (!sysfs_dir_cachep)  
  9.         goto out;  
  10.   
  11.     err = sysfs_inode_init();  
  12.     if (err)  
  13.         goto out_err;  
  14.     /*註冊文件系統*/  
  15.     err = register_filesystem(&sysfs_fs_type);  
  16.     if (!err) {  
  17.         /*註冊成功,加載文件系統*/  
  18.         sysfs_mount = kern_mount(&sysfs_fs_type);  
  19.         if (IS_ERR(sysfs_mount)) {  
  20.             printk(KERN_ERR "sysfs: could not mount!\n");  
  21.             err = PTR_ERR(sysfs_mount);  
  22.             sysfs_mount = NULL;  
  23.             unregister_filesystem(&sysfs_fs_type);  
  24.             goto out_err;  
  25.         }  
  26.     } else  
  27.         goto out_err;  
  28. out:  
  29.     return err;  
  30. out_err:  
  31.     kmem_cache_destroy(sysfs_dir_cachep);  
  32.     sysfs_dir_cachep = NULL;  
  33.     goto out;  
  34. }  
  35.   
  36. static struct file_system_type sysfs_fs_type = {  
  37.     .name        = "sysfs",  
  38.     .get_sb        = sysfs_get_sb,  
  39.     .kill_sb    = kill_anon_super,  
  40. };  

8.1.1 register_filesystem

下列代碼位於fs/filesystems.c。

  1. /** 
  2.  *  register_filesystem - register a new filesystem 
  3.  *  @fs: the file system structure 
  4.  * 
  5.  *  Adds the file system passed to the list of file systems the kernel 
  6.  *  is aware of for mount and other syscalls. Returns 0 on success, 
  7.  *  or a negative errno code on an error. 
  8.  * 
  9.  *  The &struct file_system_type that is passed is linked into the kernel  
  10.  *  structures and must not be freed until the file system has been 
  11.  *  unregistered. 
  12.  */  
  13.    
  14. int register_filesystem(struct file_system_type * fs)  
  15. {  
  16.     int res = 0;  
  17.     struct file_system_type ** p;  
  18.   
  19.     BUG_ON(strchr(fs->name, '.'));  
  20.     if (fs->next)  
  21.         return -EBUSY;  
  22.     INIT_LIST_HEAD(&fs->fs_supers);  
  23.     write_lock(&file_systems_lock);  
  24.     p = find_filesystem(fs->name, strlen(fs->name));  /*查找要住的文件是同是否存在,返回位置*/  
  25.     if (*p)  
  26.         res = -EBUSY;   /*該文件系統已存在,返回error*/  
  27.     else  
  28.         *p = fs;        /*將新的文件系統加入到鏈表中*/  
  29.     write_unlock(&file_systems_lock);  
  30.     return res;  
  31. }  

  1. static struct file_system_type **find_filesystem(const char *name, unsigned len)  
  2. {  
  3.     struct file_system_type **p;  
  4.     for (p=&file_systems; *p; p=&(*p)->next)  
  5.         if (strlen((*p)->name) == len &&  
  6.             strncmp((*p)->name, name, len) == 0)  
  7.             break;  
  8.     return p;  
  9. }  


該函數將調用函數file_system_type,此函數根據name字段(sysfs)來查找要註冊的文件系統是否已經存在。

如果不存在,表示還未註冊,則將新的fs添加到鏈表中,鏈表的第一項爲全局變量file_systems

該全局變量爲單項鍊表,所有已註冊的文件系統都被插入到這個鏈表當中。

8.1.2 kern_mount函數

下列代碼位於include/linux/fs.h

  1. #define kern_mount(type) kern_mount_data(type, NULL)  
下列代碼位於fs/sysfs/mount.c
  1. struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)  
  2. {  
  3.     return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);  
  4. }  
  5.   
  6. EXPORT_SYMBOL_GPL(kern_mount_data);  

kern_mount實際上最後是調用了vfs_kern_mount函數。我們來看下:

  1. struct vfsmount *  
  2. vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)  
  3. {  
  4.     struct vfsmount *mnt;  
  5.     char *secdata = NULL;  
  6.     int error;  
  7.   
  8.     if (!type)  
  9.         return ERR_PTR(-ENODEV);  
  10.   
  11.     error = -ENOMEM;  
  12.     mnt = alloc_vfsmnt(name);   /*分配struct vfsmount*/  
  13.     if (!mnt)  
  14.         goto out;  
  15.   
  16.     if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {  
  17.         secdata = alloc_secdata();  
  18.         if (!secdata)  
  19.             goto out_mnt;  
  20.   
  21.         error = security_sb_copy_data(data, secdata);  
  22.         if (error)  
  23.             goto out_free_secdata;  
  24.     }  
  25.         /*get_sb方法,分配superblock對象,並初始化*/  
  26.     error = type->get_sb(type, flags, name, data, mnt);  
  27.     if (error < 0)  
  28.         goto out_free_secdata;  
  29.     BUG_ON(!mnt->mnt_sb);  
  30.   
  31.     error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);  
  32.     if (error)  
  33.         goto out_sb;  
  34.   
  35.     mnt->mnt_mountpoint = mnt->mnt_root;/*設置掛載點的dentry*/  
  36.     mnt->mnt_parent = mnt;           /*設置所掛載的fs爲自己本身*/  
  37.     up_write(&mnt->mnt_sb->s_umount);  
  38.     free_secdata(secdata);  
  39.     return mnt;  
  40. out_sb:  
  41.     dput(mnt->mnt_root);  
  42.     deactivate_locked_super(mnt->mnt_sb);  
  43. out_free_secdata:  
  44.     free_secdata(secdata);  
  45. out_mnt:  
  46.     free_vfsmnt(mnt);  
  47. out:  
  48.     return ERR_PTR(error);  
  49. }  

該函數在首先調用alloc_vfsmnt來分配struct vfsmount結構,並做了一些初試化工作。

下列函數位於fs/super.c

  1. struct vfsmount *alloc_vfsmnt(const char *name)  
  2. {  
  3.     struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);  
  4.     if (mnt) {  
  5.         int err;  
  6.   
  7.         err = mnt_alloc_id(mnt);    /*設置mnt->mnt_id*/  
  8.         if (err)  
  9.             goto out_free_cache;  
  10.   
  11.         if (name) {  
  12.             mnt->mnt_devname = kstrdup(name, GFP_KERNEL); /*拷貝name,並賦值*/  
  13.             if (!mnt->mnt_devname)  
  14.                 goto out_free_id;  
  15.         }  
  16.   
  17.         atomic_set(&mnt->mnt_count, 1);  
  18.         INIT_LIST_HEAD(&mnt->mnt_hash);  
  19.         INIT_LIST_HEAD(&mnt->mnt_child);  
  20.         INIT_LIST_HEAD(&mnt->mnt_mounts);  
  21.         INIT_LIST_HEAD(&mnt->mnt_list);  
  22.         INIT_LIST_HEAD(&mnt->mnt_expire);  
  23.         INIT_LIST_HEAD(&mnt->mnt_share);  
  24.         INIT_LIST_HEAD(&mnt->mnt_slave_list);  
  25.         INIT_LIST_HEAD(&mnt->mnt_slave);  
  26.         atomic_set(&mnt->__mnt_writers, 0);  
  27.     }  
  28.     return mnt;  
  29.   
  30. out_free_id:  
  31.     mnt_free_id(mnt);  
  32. out_free_cache:  
  33.     kmem_cache_free(mnt_cache, mnt);  
  34.     return NULL;  
  35. }  
分配好結構體以後,由於參數data爲NULL,將直接調用文件系統類型提供的get_sb方法,該方法就是函數sysfs_get_sb。我們來看下:

下列函數位於fs/sysfs/mount.c。

  1. static int sysfs_get_sb(struct file_system_type *fs_type,  
  2.     int flags, const char *dev_name, void *data, struct vfsmount *mnt)  
  3. {  
  4.     return get_sb_single(fs_type, flags, data, sysfs_fill_super, mnt);  
  5. }  
這裏直接調用了get_sb_single函數,注意這裏的第4個實參sysfs_fill_super,該參數是函數名,後面將會調用該函數。

該函數將分配sysfs文件系統的superblock,獲取文件系統根目錄的inode和dentry。

該函數的執行過程相當複雜,在下一節單獨講述。

8.2 get_sb_single函數

下列函數位於fs/sysfs/mount.c。

  1. int get_sb_single(struct file_system_type *fs_type,  
  2.     int flags, void *data,  
  3.     int (*fill_super)(struct super_block *, void *, int),  
  4.     struct vfsmount *mnt)  
  5. {  
  6.     struct super_block *s;  
  7.     int error;  
  8.     /*查找或者創建super_block*/  
  9.     s = sget(fs_type, compare_single, set_anon_super, NULL);  
  10.     if (IS_ERR(s))  
  11.         return PTR_ERR(s);  
  12.     if (!s->s_root) {        /*沒有根目錄dentry*/  
  13.         s->s_flags = flags;  
  14.         /*獲取root( / )的 inode和dentry*/  
  15.         error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);  
  16.         if (error) {  
  17.             deactivate_locked_super(s);  
  18.             return error;  
  19.         }  
  20.         s->s_flags |= MS_ACTIVE;  
  21.     }  
  22.     do_remount_sb(s, flags, data, 0);  
  23.     simple_set_mnt(mnt, s); /*設置vfsmount的superblock和根dentry*/  
  24.     return 0;  
  25. }  
  26.   
  27. EXPORT_SYMBOL(get_sb_single);  

8.2.1 sget函數

首先調用了sget函數來查找是否

下列函數位於fs/super.c。

  1. /** 
  2.  *  sget    -   find or create a superblock 
  3.  *  @type:  filesystem type superblock should belong to 
  4.  *  @test:  comparison callback 
  5.  *  @set:   setup callback 
  6.  *  @data:  argument to each of them 
  7.  */  
  8. struct super_block *sget(struct file_system_type *type,  
  9.             int (*test)(struct super_block *,void *),  
  10.             int (*set)(struct super_block *,void *),  
  11.             void *data)  
  12. {  
  13.     struct super_block *s = NULL;  
  14.     struct super_block *old;  
  15.     int err;  
  16.   
  17. retry:  
  18.     spin_lock(&sb_lock);  
  19.     if (test) {           
  20.         /*遍歷所有屬於該文件系統的super_block*/  
  21.         list_for_each_entry(old, &type->fs_supers, s_instances) {  
  22.             if (!test(old, data))  
  23.                 continue;  
  24.             if (!grab_super(old))  
  25.                 goto retry;  
  26.             if (s) {  
  27.                 up_write(&s->s_umount);  
  28.                 destroy_super(s);  
  29.             }  
  30.             return old;  
  31.         }  
  32.     }  
  33.     if (!s) {  
  34.         spin_unlock(&sb_lock);  
  35.         s = alloc_super(type);  /*創建新的super_block並初始化*/  
  36.         if (!s)  
  37.             return ERR_PTR(-ENOMEM);  
  38.         goto retry;  
  39.     }  
  40.           
  41.     err = set(s, data);     /*設置s->s_dev */  
  42.     if (err) {  
  43.         spin_unlock(&sb_lock);  
  44.         up_write(&s->s_umount);  
  45.         destroy_super(s);  
  46.         return ERR_PTR(err);  
  47.     }  
  48.     s->s_type = type;  
  49.     strlcpy(s->s_id, type->name, sizeof(s->s_id)); /*拷貝name*/  
  50.     list_add_tail(&s->s_list, &super_blocks);        /*將新的super_block添加到鏈表頭super_blocks中*/  
  51.     list_add(&s->s_instances, &type->fs_supers);  /*將新的super_block添加到相應的文件系統類型的鏈表中*/  
  52.     spin_unlock(&sb_lock);  
  53.     get_filesystem(type);  
  54.     return s;  
  55. }  
  56.   
  57. EXPORT_SYMBOL(sget);  
該函數將遍歷屬於sysfs文件系統的所有superblock,本例中由於之前沒有任何superblock創建,遍歷立即結束。

然後調用alloc_super函數來創建新的struct super_block。

下列函數位於fs/super.c。

  1. /** 
  2.  *  alloc_super -   create new superblock 
  3.  *  @type:  filesystem type superblock should belong to 
  4.  * 
  5.  *  Allocates and initializes a new &struct super_block.  alloc_super() 
  6.  *  returns a pointer new superblock or %NULL if allocation had failed. 
  7.  */  
  8. static struct super_block *alloc_super(struct file_system_type *type)  
  9. {  
  10.     struct super_block *s = kzalloc(sizeof(struct super_block),  GFP_USER);/*分配並清0super_block*/  
  11.     static struct super_operations default_op;  
  12.   
  13.     if (s) {  
  14.         if (security_sb_alloc(s)) {  
  15.             kfree(s);  
  16.             s = NULL;  
  17.             goto out;  
  18.         }  
  19.         INIT_LIST_HEAD(&s->s_dirty);  
  20.         INIT_LIST_HEAD(&s->s_io);  
  21.         INIT_LIST_HEAD(&s->s_more_io);  
  22.         INIT_LIST_HEAD(&s->s_files);  
  23.         INIT_LIST_HEAD(&s->s_instances);  
  24.         INIT_HLIST_HEAD(&s->s_anon);  
  25.         INIT_LIST_HEAD(&s->s_inodes);  
  26.         INIT_LIST_HEAD(&s->s_dentry_lru);  
  27.         INIT_LIST_HEAD(&s->s_async_list);  
  28.         init_rwsem(&s->s_umount);  
  29.         mutex_init(&s->s_lock);  
  30.         lockdep_set_class(&s->s_umount, &type->s_umount_key);  
  31.         /* 
  32.          * The locking rules for s_lock are up to the 
  33.          * filesystem. For example ext3fs has different 
  34.          * lock ordering than usbfs: 
  35.          */  
  36.         lockdep_set_class(&s->s_lock, &type->s_lock_key);  
  37.         /* 
  38.          * sget() can have s_umount recursion. 
  39.          * 
  40.          * When it cannot find a suitable sb, it allocates a new 
  41.          * one (this one), and tries again to find a suitable old 
  42.          * one. 
  43.          * 
  44.          * In case that succeeds, it will acquire the s_umount 
  45.          * lock of the old one. Since these are clearly distrinct 
  46.          * locks, and this object isn't exposed yet, there's no 
  47.          * risk of deadlocks. 
  48.          * 
  49.          * Annotate this by putting this lock in a different 
  50.          * subclass. 
  51.          */  
  52.         down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING);  
  53.         s->s_count = S_BIAS;  
  54.         atomic_set(&s->s_active, 1);  
  55.         mutex_init(&s->s_vfs_rename_mutex);  
  56.         mutex_init(&s->s_dquot.dqio_mutex);  
  57.         mutex_init(&s->s_dquot.dqonoff_mutex);  
  58.         init_rwsem(&s->s_dquot.dqptr_sem);  
  59.         init_waitqueue_head(&s->s_wait_unfrozen);  
  60.         s->s_maxbytes = MAX_NON_LFS;  
  61.         s->dq_op = sb_dquot_ops;  
  62.         s->s_qcop = sb_quotactl_ops;  
  63.         s->s_op = &default_op;  
  64.         s->s_time_gran = 1000000000;  
  65.     }  
  66. out:  
  67.     return s;  
  68. }  
分配完以後,調用作爲參數傳入的函數指針set,也就是set_anon_super函數,該函數用來設置s->s_dev。

下列函數位於fs/super.c。

  1. int set_anon_super(struct super_block *s, void *data)  
  2. {  
  3.     int dev;  
  4.     int error;  
  5.   
  6.  retry:  
  7.     if (ida_pre_get(&unnamed_dev_ida, GFP_ATOMIC) == 0)/*分配ID號*/  
  8.         return -ENOMEM;  
  9.     spin_lock(&unnamed_dev_lock);  
  10.     error = ida_get_new(&unnamed_dev_ida, &dev);/*獲取ID號,保存在dev中*/  
  11.     spin_unlock(&unnamed_dev_lock);  
  12.     if (error == -EAGAIN)  
  13.         /* We raced and lost with another CPU. */  
  14.         goto retry;  
  15.     else if (error)  
  16.         return -EAGAIN;  
  17.   
  18.     if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) {  
  19.         spin_lock(&unnamed_dev_lock);  
  20.         ida_remove(&unnamed_dev_ida, dev);  
  21.         spin_unlock(&unnamed_dev_lock);  
  22.         return -EMFILE;  
  23.     }  
  24.     s->s_dev = MKDEV(0, dev & MINORMASK);    /*構建設備號*/  
  25.     return 0;  
  26. }  

8.2.2  sysfs_fill_super函數

分配了super_block之後,將判斷該super_block是否有root dentry。本例中,顯然沒有。然後調用形參fill_super指向的函數,也就是sysfs_fill_super函數。

下列函數位於fs/sysfs/mount.c。

  1. struct super_block * sysfs_sb = NULL;  
  2.   
  3. static int sysfs_fill_super(struct super_block *sb, void *data, int silent)  
  4. {  
  5.     struct inode *inode;  
  6.     struct dentry *root;  
  7.   
  8.     sb->s_blocksize = PAGE_CACHE_SIZE;   /*4KB*/  
  9.     sb->s_blocksize_bits = PAGE_CACHE_SHIFT; /*4KB*/  
  10.     sb->s_magic = SYSFS_MAGIC;           /*0x62656572*/  
  11.     sb->s_op = &sysfs_ops;  
  12.     sb->s_time_gran = 1;  
  13.     sysfs_sb = sb;      /*sysfs_sb即爲sysfs的super_block*/  
  14.   
  15.     /* get root inode, initialize and unlock it */  
  16.     mutex_lock(&sysfs_mutex);  
  17.     inode = sysfs_get_inode(&sysfs_root); /*sysfs_root即爲sysfs所在的根目錄的dirent,,獲取inode*/         
  18.     mutex_unlock(&sysfs_mutex);  
  19.     if (!inode) {  
  20.         pr_debug("sysfs: could not get root inode\n");  
  21.         return -ENOMEM;  
  22.     }  
  23.   
  24.     /* instantiate and link root dentry */  
  25.     root = d_alloc_root(inode); /*爲獲得的根inode分配root(/) dentry*/  
  26.     if (!root) {  
  27.         pr_debug("%s: could not get root dentry!\n",__func__);  
  28.         iput(inode);  
  29.         return -ENOMEM;  
  30.     }  
  31.     root->d_fsdata = &sysfs_root;  
  32.     sb->s_root = root;   /*保存superblock的根dentry*/  
  33.     return 0;  
  34. }  
  35.   
  36. struct sysfs_dirent sysfs_root = {    /*sysfs_root即爲sysfs所在的根目錄的dirent*/  
  37.     .s_name        = "",  
  38.     .s_count    = ATOMIC_INIT(1),  
  39.     .s_flags    = SYSFS_DIR,  
  40.     .s_mode        = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,  
  41.     .s_ino        = 1,  
  42. };  

在設置了一些字段後,設置了sysfs_sb這個全局變量,該全局變量表示的就是sysfs的super_block。

隨後,調用了sysfs_get_inode函數,來獲取sysfs的根目錄的dirent。該函數的參數sysfs_root爲全局變量,表示sysfs的根目錄的sysfs_dirent。

我們看些這個sysfs_dirent數據結構:

  1. /* 
  2.  * sysfs_dirent - the building block of sysfs hierarchy.  Each and 
  3.  * every sysfs node is represented by single sysfs_dirent. 
  4.  * 
  5.  * As long as s_count reference is held, the sysfs_dirent itself is 
  6.  * accessible.  Dereferencing s_elem or any other outer entity 
  7.  * requires s_active reference. 
  8.  */  
  9. struct sysfs_dirent {  
  10.     atomic_t        s_count;  
  11.     atomic_t        s_active;  
  12.     struct sysfs_dirent *s_parent;  
  13.     struct sysfs_dirent *s_sibling;  
  14.     const char      *s_name;  
  15.   
  16.     union {  
  17.         struct sysfs_elem_dir       s_dir;  
  18.         struct sysfs_elem_symlink   s_symlink;  
  19.         struct sysfs_elem_attr      s_attr;  
  20.         struct sysfs_elem_bin_attr  s_bin_attr;  
  21.     };  
  22.   
  23.     unsigned int        s_flags;  
  24.     ino_t           s_ino;  
  25.     umode_t         s_mode;  
  26.     struct iattr        *s_iattr;  
  27. };  
其中比較關鍵的就是那個聯合體,針對不同的形式(目錄,symlink,屬性文件和可執行文件)將使用不同的數據結構。

另外,sysfs_dirent將最爲dentry的fs專有數據被保存下來,這一點會在下面中看到。

接着,在來看下sysfs_get_inode函數:

下列函數位於fs/sysfs/inode.c。

  1. /** 
  2.  *  sysfs_get_inode - get inode for sysfs_dirent 
  3.  *  @sd: sysfs_dirent to allocate inode for 
  4.  * 
  5.  *  Get inode for @sd.  If such inode doesn't exist, a new inode 
  6.  *  is allocated and basics are initialized.  New inode is 
  7.  *  returned locked. 
  8.  * 
  9.  *  LOCKING: 
  10.  *  Kernel thread context (may sleep). 
  11.  * 
  12.  *  RETURNS: 
  13.  *  Pointer to allocated inode on success, NULL on failure. 
  14.  */  
  15. struct inode * sysfs_get_inode(struct sysfs_dirent *sd)  
  16. {  
  17.     struct inode *inode;  
  18.   
  19.     inode = iget_locked(sysfs_sb, sd->s_ino);    /*在inode cache查找inode是否存在,不存在側創建一個*/  
  20.     if (inode && (inode->i_state & I_NEW))       /*如果是新創建的inode,則包含I_NEW*/  
  21.         sysfs_init_inode(sd, inode);  
  22.   
  23.     return inode;  
  24. }  
  25.   
  26. /** 
  27.  * iget_locked - obtain an inode from a mounted file system 
  28.  * @sb:        super block of file system 
  29.  * @ino:    inode number to get 
  30.  * 
  31.  * iget_locked() uses ifind_fast() to search for the inode specified by @ino in 
  32.  * the inode cache and if present it is returned with an increased reference 
  33.  * count. This is for file systems where the inode number is sufficient for 
  34.  * unique identification of an inode. 
  35.  * 
  36.  * If the inode is not in cache, get_new_inode_fast() is called to allocate a 
  37.  * new inode and this is returned locked, hashed, and with the I_NEW flag set. 
  38.  * The file system gets to fill it in before unlocking it via 
  39.  * unlock_new_inode(). 
  40.  */  
  41. struct inode *iget_locked(struct super_block *sb, unsigned long ino)  
  42. {  
  43.     struct hlist_head *head = inode_hashtable + hash(sb, ino);  
  44.     struct inode *inode;  
  45.   
  46.     inode = ifind_fast(sb, head, ino);/*在inode cache查找該inode*/  
  47.     if (inode)  
  48.         return inode;         /*找到了該inode*/  
  49.     /* 
  50.      * get_new_inode_fast() will do the right thing, re-trying the search 
  51.      * in case it had to block at any point. 
  52.      */  
  53.     return get_new_inode_fast(sb, head, ino);    /*分配一個新的inode*/  
  54. }  
  55. EXPORT_SYMBOL(iget_locked);  
  56.   
  57. static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)  
  58. {  
  59.     struct bin_attribute *bin_attr;  
  60.   
  61.     inode->i_private = sysfs_get(sd);  
  62.     inode->i_mapping->a_ops = &sysfs_aops;  
  63.     inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;  
  64.     inode->i_op = &sysfs_inode_operations;  
  65.     inode->i_ino = sd->s_ino;  
  66.     lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);  
  67.   
  68.     if (sd->s_iattr) {  
  69.         /* sysfs_dirent has non-default attributes 
  70.          * get them for the new inode from persistent copy 
  71.          * in sysfs_dirent 
  72.          */  
  73.         set_inode_attr(inode, sd->s_iattr);  
  74.     } else  
  75.         set_default_inode_attr(inode, sd->s_mode);/*設置inode屬性*/  
  76.   
  77.   
  78.     /* initialize inode according to type */  
  79.     switch (sysfs_type(sd)) {  
  80.     case SYSFS_DIR:  
  81.         inode->i_op = &sysfs_dir_inode_operations;  
  82.         inode->i_fop = &sysfs_dir_operations;  
  83.         inode->i_nlink = sysfs_count_nlink(sd);  
  84.         break;  
  85.     case SYSFS_KOBJ_ATTR:  
  86.         inode->i_size = PAGE_SIZE;  
  87.         inode->i_fop = &sysfs_file_operations;  
  88.         break;  
  89.     case SYSFS_KOBJ_BIN_ATTR:  
  90.         bin_attr = sd->s_bin_attr.bin_attr;  
  91.         inode->i_size = bin_attr->size;  
  92.         inode->i_fop = &bin_fops;  
  93.         break;  
  94.     case SYSFS_KOBJ_LINK:  
  95.         inode->i_op = &sysfs_symlink_inode_operations;  
  96.         break;  
  97.     default:  
  98.         BUG();  
  99.     }  
  100.   
  101.     unlock_new_inode(inode);  
  102. }  
該函數首先調用了,iget_locked來查找該inode是否已存在,如果不存在則創建。如果是新創建的inode,則對inode進行初始化。
再獲取了根目錄的inode和sysfs_dirent後,調用d_alloc_root來獲得dirent。

  1. /** 
  2.  * d_alloc_root - allocate root dentry 
  3.  * @root_inode: inode to allocate the root for 
  4.  * 
  5.  * Allocate a root ("/") dentry for the inode given. The inode is 
  6.  * instantiated and returned. %NULL is returned if there is insufficient 
  7.  * memory or the inode passed is %NULL. 
  8.  */  
  9.    
  10. struct dentry * d_alloc_root(struct inode * root_inode)  
  11. {  
  12.     struct dentry *res = NULL;  
  13.   
  14.     if (root_inode) {  
  15.         static const struct qstr name = { .name = "/", .len = 1 };  
  16.   
  17.         res = d_alloc(NULL, &name); /*分配struct dentry,沒有父dentry*/  
  18.         if (res) {  
  19.             res->d_sb = root_inode->i_sb;  
  20.             res->d_parent = res;   
  21.             d_instantiated_instantiate(res, root_inode); /*綁定inode和dentry之間的關係*/  
  22.         }  
  23.     }  
  24.     return res;  
  25. }  
  26.   
  27. /** 
  28.  * d_alloc    -    allocate a dcache entry 
  29.  * @parent: parent of entry to allocate 
  30.  * @name: qstr of the name 
  31.  * 
  32.  * Allocates a dentry. It returns %NULL if there is insufficient memory 
  33.  * available. On a success the dentry is returned. The name passed in is 
  34.  * copied and the copy passed in may be reused after this call. 
  35.  */  
  36.    
  37. struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)  
  38. {  
  39.     struct dentry *dentry;  
  40.     char *dname;  
  41.   
  42.     dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL);/*分配struct dentry*/  
  43.     if (!dentry)  
  44.         return NULL;  
  45.   
  46.     if (name->len > DNAME_INLINE_LEN-1) {  
  47.         dname = kmalloc(name->len + 1, GFP_KERNEL);  
  48.         if (!dname) {  
  49.             kmem_cache_free(dentry_cache, dentry);   
  50.             return NULL;  
  51.         }  
  52.     } else  {  
  53.         dname = dentry->d_iname;  
  54.     }      
  55.     dentry->d_name.name = dname;  
  56.   
  57.     dentry->d_name.len = name->len;  
  58.     dentry->d_name.hash = name->hash;  
  59.     memcpy(dname, name->name, name->len);  
  60.     dname[name->len] = 0;  
  61.   
  62.     atomic_set(&dentry->d_count, 1);  
  63.     dentry->d_flags = DCACHE_UNHASHED;  
  64.     spin_lock_init(&dentry->d_lock);  
  65.     dentry->d_inode = NULL;  
  66.     dentry->d_parent = NULL;  
  67.     dentry->d_sb = NULL;  
  68.     dentry->d_op = NULL;  
  69.     dentry->d_fsdata = NULL;  
  70.     dentry->d_mounted = 0;  
  71.     INIT_HLIST_NODE(&dentry->d_hash);  
  72.     INIT_LIST_HEAD(&dentry->d_lru);  
  73.     INIT_LIST_HEAD(&dentry->d_subdirs);  
  74.     INIT_LIST_HEAD(&dentry->d_alias);  
  75.   
  76.     if (parent) {    /*有父目錄,則設置指針來表示關係*/  
  77.         dentry->d_parent = dget(parent);  
  78.         dentry->d_sb = parent->d_sb;  /*根dentry的父對象爲自己*/  
  79.     } else {  
  80.         INIT_LIST_HEAD(&dentry->d_u.d_child);  
  81.     }  
  82.   
  83.     spin_lock(&dcache_lock);  
  84.     if (parent)        /*有父目錄,則添加到父目錄的兒子鏈表中*/  
  85.         list_add(&dentry->d_u.d_child, &parent->d_subdirs);  
  86.     dentry_stat.nr_dentry++;  
  87.     spin_unlock(&dcache_lock);  
  88.   
  89.     return dentry;  
  90. }   
  91.   
  92. /** 
  93.  * d_instantiate - fill in inode information for a dentry 
  94.  * @entry: dentry to complete 
  95.  * @inode: inode to attach to this dentry 
  96.  * 
  97.  * Fill in inode information in the entry. 
  98.  * 
  99.  * This turns negative dentries into productive full members 
  100.  * of society. 
  101.  * 
  102.  * NOTE! This assumes that the inode count has been incremented 
  103.  * (or otherwise set) by the caller to indicate that it is now 
  104.  * in use by the dcache. 
  105.  */  
  106.    
  107. void d_instantiate(struct dentry *entry, struct inode * inode)  
  108. {  
  109.     BUG_ON(!list_empty(&entry->d_alias));  
  110.     spin_lock(&dcache_lock);  
  111.     __d_instantiate(entry, inode);  
  112.     spin_unlock(&dcache_lock);  
  113.     security_d_instantiate(entry, inode);  
  114. }  
  115.   
  116. /* the caller must hold dcache_lock */  
  117. static void __d_instantiate(struct dentry *dentry, struct inode *inode)  
  118. {  
  119.     if (inode)  
  120.         list_add(&dentry->d_alias, &inode->i_dentry);/*將dentry添加到inode的鏈表中*/  
  121.     dentry->d_inode = inode;        /*保存dentry對應的inode*/  
  122.     fsnotify_d_instantiate(dentry, inode);  
  123. }  

該函數首先調用了d_alloc來創建struct dentry,參數parent爲NULL,既然是爲根( / )建立dentry,自然沒有父對象。

接着調用d_instantiate來綁定inode和dentry之間的關係。


在sysfs_fill_super函數執行的最後,將sysfs_root保存到了dentry->d_fsdata。

可見,在sysfs中用sysfs_dirent來表示目錄,但是對於VFS,還是要使用dentry來表示目錄。

8.2.3  do_remount_sb

下列代碼位於fs/super.c。

  1. /** 
  2.  *  do_remount_sb - asks filesystem to change mount options. 
  3.  *  @sb:    superblock in question 
  4.  *  @flags: numeric part of options 
  5.  *  @data:  the rest of options 
  6.  *      @force: whether or not to force the change 
  7.  * 
  8.  *  Alters the mount options of a mounted file system. 
  9.  */  
  10. int do_remount_sb(struct super_block *sb, int flags, void *data, int force)  
  11. {  
  12.     int retval;  
  13.     int remount_rw;  
  14.       
  15. #ifdef CONFIG_BLOCK  
  16.     if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev))  
  17.         return -EACCES;  
  18. #endif  
  19.     if (flags & MS_RDONLY)  
  20.         acct_auto_close(sb);  
  21.     shrink_dcache_sb(sb);  
  22.     fsync_super(sb);  
  23.   
  24.     /* If we are remounting RDONLY and current sb is read/write, 
  25.        make sure there are no rw files opened */  
  26.     if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) {  
  27.         if (force)  
  28.             mark_files_ro(sb);  
  29.         else if (!fs_may_remount_ro(sb))  
  30.             return -EBUSY;  
  31.         retval = vfs_dq_off(sb, 1);  
  32.         if (retval < 0 && retval != -ENOSYS)  
  33.             return -EBUSY;  
  34.     }  
  35.     remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY);  
  36.   
  37.     if (sb->s_op->remount_fs) {  
  38.         lock_super(sb);  
  39.         retval = sb->s_op->remount_fs(sb, &flags, data);  
  40.         unlock_super(sb);  
  41.         if (retval)  
  42.             return retval;  
  43.     }  
  44.     sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);  
  45.     if (remount_rw)  
  46.         vfs_dq_quota_on_remount(sb);  
  47.     return 0;  
  48. }  

這個函數用來修改掛在選項,這個函數就不分析了,不是重點。

8.2.4simple_set_mnt

下列函數位於fs/namespace.c。

  1. void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb)  
  2. {  
  3.     mnt->mnt_sb = sb;  
  4.     mnt->mnt_root = dget(sb->s_root);  
  5. }  
該函數設置了vfsmount的superblock和根dentry。

8.2.5 小結

這裏,對sysfs的註冊過程做一個總結。

sysfs_init函數調用過程示意圖如下:


在整個過程中,先後使用和創建了許多struct

第一,根據file_system_type表示的sysfs文件系統的類型註冊了sysfs。

第二,建立了vfsmount。

第三,創建了超級塊super_block。

第四,根據sysfs_dirent表示的根目錄,建立了inode。

最後,根據剛纔建立的inode創建了dentry。

除了sysfs_dirent,其他5個結構體都是VFS中基本的數據結構,而sysfs_dirent則是特定於sysfs文件系統的數據結構。

8.3 創建目錄

在前面的描述中,使用sysfs_create_dir在sysfs下建立一個目錄。我們來看下這個函數是如何來建立目錄的。

下列代碼位於fs/sysfs/dir.c。

  1. /** 
  2.  *  sysfs_create_dir - create a directory for an object. 
  3.  *  @kobj:      object we're creating directory for.  
  4.  */  
  5. int sysfs_create_dir(struct kobject * kobj)  
  6. {  
  7.     struct sysfs_dirent *parent_sd, *sd;  
  8.     int error = 0;  
  9.   
  10.     BUG_ON(!kobj);  
  11.   
  12.     if (kobj->parent)    /*如果有parent,獲取parent對應的sys目錄*/  
  13.         parent_sd = kobj->parent->sd;  
  14.     else                /*沒有則是在sys根目錄*/  
  15.         parent_sd = &sysfs_root;  
  16.   
  17.     error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);  
  18.     if (!error)  
  19.         kobj->sd = sd;  
  20.     return error;  
  21. }  

函數中,首先獲取待建目錄的父sysfs_dirent,然後將它作爲參數 來調用create_dir函數。

很明顯,就是要在父sysfs_dirent下建立新的sysfs_dirent,新建立的sysfs_dirent將保存到參數sd中。

下列代碼位於fs/sysfs/dir.c。

  1. static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,  
  2.               const char *name, struct sysfs_dirent **p_sd)  
  3. {  
  4.     umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;  
  5.     struct sysfs_addrm_cxt acxt;  
  6.     struct sysfs_dirent *sd;  
  7.     int rc;  
  8.   
  9.     /* allocate */  /*分配sysfs_dirent並初始化*/  
  10.     sd = sysfs_new_dirent(name, mode, SYSFS_DIR);  
  11.     if (!sd)  
  12.         return -ENOMEM;  
  13.     sd->s_dir.kobj = kobj;    /*保存kobject對象*/  
  14.   
  15.     /* link in */  
  16.     sysfs_addrm_start(&acxt, parent_sd);/*尋找父sysfs_dirent對應的inode*/  
  17.     rc = sysfs_add_one(&acxt, sd);  /*檢查父sysfs_dirent下是否已有有該sysfs_dirent,沒有則添加到父sysfs_dirent中*/  
  18.     sysfs_addrm_finish(&acxt);      /*收尾工作*/  
  19.   
  20.     if (rc == 0)        /*rc爲0表示創建成功*/  
  21.         *p_sd = sd;  
  22.     else  
  23.         sysfs_put(sd);  /*增加引用計數*/  
  24.   
  25.     return rc;  
  26. }  

這裏要注意一下mode變量,改變了使用了宏定義SYSFS_DIR,這個就表示要創建的是一個目錄。

mode還有幾個宏定義可以使用,如下:

  1. #define SYSFS_KOBJ_ATTR         0x0002  
  2. #define SYSFS_KOBJ_BIN_ATTR     0x0004  
  3. #define SYSFS_KOBJ_LINK         0x0008  
  4. #define SYSFS_COPY_NAME         (SYSFS_DIR | SYSFS_KOBJ_LINK)  

8.3.1 sysfs_new_dirent 

  在create_dir函數中,首先調用了sysfs_new_dirent來建立一個新的sysfs_dirent結構體。

下列代碼位於fs/sysfs/dir.c。

  1. struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)  
  2. {  
  3.     char *dup_name = NULL;  
  4.     struct sysfs_dirent *sd;  
  5.   
  6.     if (type & SYSFS_COPY_NAME) {  
  7.         name = dup_name = kstrdup(name, GFP_KERNEL);  
  8.         if (!name)  
  9.             return NULL;  
  10.     }  
  11.     /*分配sysfs_dirent並清0*/  
  12.     sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);  
  13.     if (!sd)  
  14.         goto err_out1;  
  15.   
  16.     if (sysfs_alloc_ino(&sd->s_ino)) /*分配ID號*/  
  17.         goto err_out2;  
  18.   
  19.     atomic_set(&sd->s_count, 1);  
  20.     atomic_set(&sd->s_active, 0);  
  21.   
  22.     sd->s_name = name;  
  23.     sd->s_mode = mode;  
  24.     sd->s_flags = type;  
  25.   
  26.     return sd;  
  27.   
  28.  err_out2:  
  29.     kmem_cache_free(sysfs_dir_cachep, sd);  
  30.  err_out1:  
  31.     kfree(dup_name);  
  32.     return NULL;  
  33. }  

8.3.2 有關sysfs_dirent中的聯合體

分配了sysfs_dirent後,設置了該結構中的聯合體數據。先來看下聯合體中的四個數據結構。

  1. /* type-specific structures for sysfs_dirent->s_* union members */  
  2. struct sysfs_elem_dir {  
  3.     struct kobject      *kobj;  
  4.     /* children list starts here and goes through sd->s_sibling */  
  5.     struct sysfs_dirent *children;  
  6. };  
  7.   
  8. struct sysfs_elem_symlink {  
  9.     struct sysfs_dirent    *target_sd;  
  10. };  
  11.   
  12. struct sysfs_elem_attr {  
  13.     struct attribute    *attr;  
  14.     struct sysfs_open_dirent *open;  
  15. };  
  16.   
  17. struct sysfs_elem_bin_attr {  
  18.     struct bin_attribute    *bin_attr;  
  19.     struct hlist_head    buffers;  
  20. };  
根據sysfs_dirent所代表的類型不同,也就是目錄,synlink,屬性文件和bin文件,將分別使用該聯合體中相應的struct。

在本例中要創建的是目錄,自然使用sysfs_elem_dir結構體,然後保存了kobject對象。

在8.4和8.5中我們將分別看到sysfs_elem_attr和sysfs_elem_symlink的使用。

8.3.3 sysfs_addrm_start

在獲取了父sysfs_dirent,調用sysfs_addrm_start來獲取與之對應的inode。

下列代碼位於fs/sysfs/dir.c。

  1. /** 
  2.  *  sysfs_addrm_start - prepare for sysfs_dirent add/remove 
  3.  *  @acxt: pointer to sysfs_addrm_cxt to be used 
  4.  *  @parent_sd: parent sysfs_dirent 
  5.  * 
  6.  *  This function is called when the caller is about to add or 
  7.  *  remove sysfs_dirent under @parent_sd.  This function acquires 
  8.  *  sysfs_mutex, grabs inode for @parent_sd if available and lock 
  9.  *  i_mutex of it.  @acxt is used to keep and pass context to 
  10.  *  other addrm functions. 
  11.  * 
  12.  *  LOCKING: 
  13.  *  Kernel thread context (may sleep).  sysfs_mutex is locked on 
  14.  *  return.  i_mutex of parent inode is locked on return if 
  15.  *  available. 
  16.  */  
  17. void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,  
  18.                struct sysfs_dirent *parent_sd)  
  19. {  
  20.     struct inode *inode;  
  21.   
  22.     memset(acxt, 0, sizeof(*acxt));  
  23.     acxt->parent_sd = parent_sd;  
  24.   
  25.     /* Lookup parent inode.  inode initialization is protected by 
  26.      * sysfs_mutex, so inode existence can be determined by 
  27.      * looking up inode while holding sysfs_mutex. 
  28.      */  
  29.     mutex_lock(&sysfs_mutex);  
  30.     /*根據parent_sd來尋找父inode*/  
  31.     inode = ilookup5(sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test,  
  32.              parent_sd);  
  33.     if (inode) {  
  34.         WARN_ON(inode->i_state & I_NEW);  
  35.   
  36.         /* parent inode available */  
  37.         acxt->parent_inode = inode;      /*保存找到的父inode*/  
  38.   
  39.         /* sysfs_mutex is below i_mutex in lock hierarchy. 
  40.          * First, trylock i_mutex.  If fails, unlock 
  41.          * sysfs_mutex and lock them in order. 
  42.          */  
  43.         if (!mutex_trylock(&inode->i_mutex)) {  
  44.             mutex_unlock(&sysfs_mutex);  
  45.             mutex_lock(&inode->i_mutex);  
  46.             mutex_lock(&sysfs_mutex);  
  47.         }  
  48.     }  
  49. }  
  50.   
  51. /* 
  52.  * Context structure to be used while adding/removing nodes. 
  53.  */  
  54. struct sysfs_addrm_cxt {  
  55.     struct sysfs_dirent    *parent_sd;  
  56.     struct inode        *parent_inode;  
  57.     struct sysfs_dirent    *removed;  
  58.     int            cnt;  
  59. };  
注意形參sysfs_addrm_cxt,該結構作用是臨時存放數據。

8.3.4 sysfs_add_one

下列代碼位於fs/sysfs/dir.c。

  1. /** 
  2.  *  sysfs_add_one - add sysfs_dirent to parent 
  3.  *  @acxt: addrm context to use 
  4.  *  @sd: sysfs_dirent to be added 
  5.  * 
  6.  *  Get @acxt->parent_sd and set sd->s_parent to it and increment 
  7.  *  nlink of parent inode if @sd is a directory and link into the 
  8.  *  children list of the parent. 
  9.  * 
  10.  *  This function should be called between calls to 
  11.  *  sysfs_addrm_start() and sysfs_addrm_finish() and should be 
  12.  *  passed the same @acxt as passed to sysfs_addrm_start(). 
  13.  * 
  14.  *  LOCKING: 
  15.  *  Determined by sysfs_addrm_start(). 
  16.  * 
  17.  *  RETURNS: 
  18.  *  0 on success, -EEXIST if entry with the given name already 
  19.  *  exists. 
  20.  */  
  21. int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)  
  22. {  
  23.     int ret;  
  24.   
  25.     ret = __sysfs_add_one(acxt, sd);  
  26.     if (ret == -EEXIST) {  
  27.         char *path = kzalloc(PATH_MAX, GFP_KERNEL);  
  28.         WARN(1, KERN_WARNING  
  29.              "sysfs: cannot create duplicate filename '%s'\n",  
  30.              (path == NULL) ? sd->s_name :  
  31.              strcat(strcat(sysfs_pathname(acxt->parent_sd, path), "/"),  
  32.                     sd->s_name));  
  33.         kfree(path);  
  34.     }  
  35.   
  36.     return ret;  
  37. }  
  38.   
  39. /** 
  40.  *    __sysfs_add_one - add sysfs_dirent to parent without warning 
  41.  *    @acxt: addrm context to use 
  42.  *    @sd: sysfs_dirent to be added 
  43.  * 
  44.  *    Get @acxt->parent_sd and set sd->s_parent to it and increment 
  45.  *    nlink of parent inode if @sd is a directory and link into the 
  46.  *    children list of the parent. 
  47.  * 
  48.  *    This function should be called between calls to 
  49.  *    sysfs_addrm_start() and sysfs_addrm_finish() and should be 
  50.  *    passed the same @acxt as passed to sysfs_addrm_start(). 
  51.  * 
  52.  *    LOCKING: 
  53.  *    Determined by sysfs_addrm_start(). 
  54.  * 
  55.  *    RETURNS: 
  56.  *    0 on success, -EEXIST if entry with the given name already 
  57.  *    exists. 
  58.  */  
  59. int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)  
  60. {  
  61.     /*查找該parent_sd下有無將要建立的sd,沒有返回NULL*/  
  62.     if (sysfs_find_dirent(acxt->parent_sd, sd->s_name))  
  63.         return -EEXIST;  
  64.   
  65.     sd->s_parent = sysfs_get(acxt->parent_sd);    /*設置父sysfs_dirent,增加父sysfs_dirent的引用計數*/  
  66.   
  67.     if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode)    /*如果要創建的是目錄或文件,並且有父inode*/  
  68.         inc_nlink(acxt->parent_inode);    /*inode->i_nlink加1*/  
  69.   
  70.     acxt->cnt++;  
  71.   
  72.     sysfs_link_sibling(sd);  
  73.   
  74.     return 0;  
  75. }  
  76.   
  77. /** 
  78.  *    sysfs_find_dirent - find sysfs_dirent with the given name 
  79.  *    @parent_sd: sysfs_dirent to search under 
  80.  *    @name: name to look for 
  81.  * 
  82.  *    Look for sysfs_dirent with name @name under @parent_sd. 
  83.  * 
  84.  *    LOCKING: 
  85.  *    mutex_lock(sysfs_mutex) 
  86.  * 
  87.  *    RETURNS: 
  88.  *    Pointer to sysfs_dirent if found, NULL if not. 
  89.  */  
  90. struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,  
  91.                        const unsigned char *name)  
  92. {  
  93.     struct sysfs_dirent *sd;  
  94.   
  95.     for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling)  
  96.         if (!strcmp(sd->s_name, name))  
  97.             return sd;  
  98.     return NULL;  
  99. }   
  100.   
  101. /** 
  102.  *    sysfs_link_sibling - link sysfs_dirent into sibling list 
  103.  *    @sd: sysfs_dirent of interest 
  104.  * 
  105.  *    Link @sd into its sibling list which starts from 
  106.  *    sd->s_parent->s_dir.children. 
  107.  * 
  108.  *    Locking: 
  109.  *    mutex_lock(sysfs_mutex) 
  110.  */  
  111. static void sysfs_link_sibling(struct sysfs_dirent *sd)  
  112. {  
  113.     struct sysfs_dirent *parent_sd = sd->s_parent;  
  114.     struct sysfs_dirent **pos;  
  115.   
  116.     BUG_ON(sd->s_sibling);  
  117.   
  118.     /* Store directory entries in order by ino.  This allows 
  119.      * readdir to properly restart without having to add a 
  120.      * cursor into the s_dir.children list. 
  121.      */  
  122.      /*children鏈表根據s_ino按升序排列,現在將sd插入到正確的兒子鏈表中*/  
  123.     for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) {  
  124.         if (sd->s_ino < (*pos)->s_ino)  
  125.             break;  
  126.     }  
  127.     /*插入鏈表*/  
  128.     sd->s_sibling = *pos;  
  129.     *pos = sd;   
  130. }  
該函數直接調用了__sysfs_add_one,後者先調用sysfs_find_dirent來查找該parent_sd下有無該的sysfs_dirent,如果沒有,則設置創建好的新的sysfs_dirent的s_parent字段。也就是將新的sysfs_dirent添加到父sys_dirent中。接着調用sysfs_link_sibling函數,將新建的sysfs_dirent添加到sd->s_parent->s_dir.children鏈表中。

8.3.5 sysfs_addrm_finish

下列代碼位於fs/sysfs/dir.c。

  1. /** 
  2.  *  sysfs_addrm_finish - finish up sysfs_dirent add/remove 
  3.  *  @acxt: addrm context to finish up 
  4.  * 
  5.  *  Finish up sysfs_dirent add/remove.  Resources acquired by 
  6.  *  sysfs_addrm_start() are released and removed sysfs_dirents are 
  7.  *  cleaned up.  Timestamps on the parent inode are updated. 
  8.  * 
  9.  *  LOCKING: 
  10.  *  All mutexes acquired by sysfs_addrm_start() are released. 
  11.  */  
  12. void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)  
  13. {  
  14.     /* release resources acquired by sysfs_addrm_start() */  
  15.     mutex_unlock(&sysfs_mutex);  
  16.     if (acxt->parent_inode) {  
  17.         struct inode *inode = acxt->parent_inode;  
  18.   
  19.         /* if added/removed, update timestamps on the parent */  
  20.         if (acxt->cnt)  
  21.             inode->i_ctime = inode->i_mtime = CURRENT_TIME;/*更新父inode的時間*/  
  22.   
  23.         mutex_unlock(&inode->i_mutex);  
  24.         iput(inode);  
  25.     }  
  26.   
  27.     /* kill removed sysfs_dirents */  
  28.     while (acxt->removed) {  
  29.         struct sysfs_dirent *sd = acxt->removed;  
  30.   
  31.         acxt->removed = sd->s_sibling;  
  32.         sd->s_sibling = NULL;  
  33.   
  34.         sysfs_drop_dentry(sd);  
  35.         sysfs_deactivate(sd);  
  36.         unmap_bin_file(sd);  
  37.         sysfs_put(sd);  
  38.     }  
  39. }  

該函數結束了添加sysfs_dirent的工作,這個就不多做說明了。


至此,添加一個目錄的工作已經完成了,添加目錄的工作其實就是創建了一個新的sysfs_dirent,並把它添加到父sysfs_dirent中。

下面我們看下如何添加屬性文件。

8.4 創建屬性文件

添加屬性文件使用sysfs_create_file函數。

下列函數位於fs/sysfs/file.c。

  1. /** 
  2.  *  sysfs_create_file - create an attribute file for an object. 
  3.  *  @kobj:  object we're creating for.  
  4.  *  @attr:  attribute descriptor. 
  5.  */  
  6.   
  7. int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)  
  8. {  
  9.     BUG_ON(!kobj || !kobj->sd || !attr);  
  10.   
  11.     return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR);  
  12.   
  13. }  
  14.   
  15. int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,  
  16.            int type)  
  17. {  
  18.     return sysfs_add_file_mode(dir_sd, attr, type, attr->mode);  
  19. }  
  20.   
  21. int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,  
  22.             const struct attribute *attr, int type, mode_t amode)  
  23. {  
  24.     umode_t mode = (amode & S_IALLUGO) | S_IFREG;  
  25.     struct sysfs_addrm_cxt acxt;  
  26.     struct sysfs_dirent *sd;  
  27.     int rc;  
  28.     /*分配sysfs_dirent並初始化*/  
  29.     sd = sysfs_new_dirent(attr->name, mode, type);  
  30.     if (!sd)  
  31.         return -ENOMEM;  
  32.     sd->s_attr.attr = (void *)attr;  
  33.   
  34.     sysfs_addrm_start(&acxt, dir_sd);    /*尋找父sysfs_dirent對應的inode*/  
  35.     rc = sysfs_add_one(&acxt, sd);        /*檢查父sysfs_dirent下是否已有有該sysfs_dirent,沒有則創建*/  
  36.     sysfs_addrm_finish(&acxt);            /*收尾工作*/  
  37.   
  38.     if (rc)            /*0表示創建成功*/   
  39.         sysfs_put(sd);  
  40.   
  41.     return rc;  
  42. }  

sysfs_create_file用參數SYSFS_KOBJ_ATTR(表示建立屬性文件)來調用了sysfs_add_file,後者又直接調用了sysfs_add_file_mode。

sysfs_add_file_mode函數的執行和8.3節的create_dir函數非常類似,只不過它並沒有保存kobject對象,也就是說該sysfs_dirent並沒有一個對應的kobject對象。

需要注意的是,這裏是建立屬性文件,因此使用了聯合體中的結構體s_attr。

8.5 創建symlink

最後,來看下symlink的建立。

  1. /** 
  2.  *  sysfs_create_link - create symlink between two objects. 
  3.  *  @kobj:  object whose directory we're creating the link in. 
  4.  *  @target:    object we're pointing to. 
  5.  *  @name:      name of the symlink. 
  6.  */  
  7. int sysfs_create_link(struct kobject *kobj, struct kobject *target,  
  8.               const char *name)  
  9. {  
  10.     return sysfs_do_create_link(kobj, target, name, 1);  
  11. }  
  12.   
  13. static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target,  
  14.                 const char *name, int warn)  
  15. {  
  16.     struct sysfs_dirent *parent_sd = NULL;  
  17.     struct sysfs_dirent *target_sd = NULL;  
  18.     struct sysfs_dirent *sd = NULL;  
  19.     struct sysfs_addrm_cxt acxt;  
  20.     int error;  
  21.   
  22.     BUG_ON(!name);  
  23.   
  24.     if (!kobj)    /*kobj爲空,表示在sysyfs跟目錄下建立symlink*/  
  25.         parent_sd = &sysfs_root;  
  26.     else        /*有父sysfs_dirent*/  
  27.         parent_sd = kobj->sd;  
  28.   
  29.     error = -EFAULT;  
  30.     if (!parent_sd)  
  31.         goto out_put;  
  32.   
  33.     /* target->sd can go away beneath us but is protected with 
  34.      * sysfs_assoc_lock.  Fetch target_sd from it. 
  35.      */  
  36.     spin_lock(&sysfs_assoc_lock);  
  37.     if (target->sd)  
  38.         target_sd = sysfs_get(target->sd);    、/*獲取目標對象的sysfs_dirent*/  
  39.     spin_unlock(&sysfs_assoc_lock);  
  40.   
  41.     error = -ENOENT;  
  42.     if (!target_sd)  
  43.         goto out_put;  
  44.   
  45.     error = -ENOMEM;  
  46.     /*分配sysfs_dirent並初始化*/  
  47.     sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK);  
  48.     if (!sd)  
  49.         goto out_put;  
  50.   
  51.     sd->s_symlink.target_sd = target_sd;/*保存目標sysfs_dirent*/  
  52.     target_sd = NULL;    /* reference is now owned by the symlink */  
  53.   
  54.     sysfs_addrm_start(&acxt, parent_sd);/*尋找父sysfs_dirent對應的inode*/  
  55.     if (warn)  
  56.         error = sysfs_add_one(&acxt, sd);/*檢查父sysfs_dirent下是否已有有該sysfs_dirent,沒有則創建*/  
  57.     else  
  58.         error = __sysfs_add_one(&acxt, sd);  
  59.     sysfs_addrm_finish(&acxt);            /*收尾工作*/  
  60.   
  61.     if (error)  
  62.         goto out_put;  
  63.   
  64.     return 0;  
  65.   
  66.  out_put:  
  67.     sysfs_put(target_sd);  
  68.     sysfs_put(sd);  
  69.     return error;  
  70. }  

這個函數的執行也和8.3節的create_dir函數非常類似。其次,symlink同樣沒有對應的kobject對象。

因爲sysfs_dirent表示的是symlink,這裏使用了聯合體中的s_symlink。同時設置了s_symlink.target_sd指向的目標sysfs_dirent爲參數targed_sd。

8.6 小結

本節首先對syfs這一特殊的文件系統的註冊過程進行了分析。接着對目錄,屬性文件和symlink的建立進行了分析。這三者的建立過程基本一致,但是目錄

有kobject對象,而剩餘兩個沒有。其次,這三者的每個sysfs_dirent中,都使用了自己的聯合體數據。

9 總結

本文首先對sysfs的核心數據kobject,kset等數據結構做出了分析,正是通過它們才能向用戶空間呈現出設備驅動模型。

接着,以/sys/bus目錄的建立爲例,來說明如何通過kobject和kset來建立該bus目錄。

隨後,介紹了驅動模型中表示總線,設備和驅動的三個數據結構。

然後,介紹了platform總線(bus/platform)的註冊,再介紹了虛擬的platform設備(devices/platform)的添加過程。

之後 ,以spi主控制器的platform設備爲例,介紹了該platform設備和相應的驅動的註冊過程。

最後,介紹了底層sysfs文件系統的註冊過程和如何建立目錄,屬性文件和symlink的過程。

 

更新說明:
2012.09.14 在6.2.9中,添加分析 bus_for_each_drv。

發佈了110 篇原創文章 · 獲贊 20 · 訪問量 32萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章