Sys文件系統分析

還記得上篇講到的platform總線、設備、驅動的知識??這裏我們先來看一段documentation/filesystems/sysfs.txt裏關於sysfs文件系統的描述:

  sysfs is a ram-based filesystem initially based on ramfs.It provides a means to export kernel data structures,their attributes,and the linkages between them to userspace.

  sysfs 文件系統是基於ram文件系統的,

這裏注意:

ramdisk 文件系統基於磁盤模擬技術,實際文件系統是ex2 ex3等

sysfs是一種基於ram文件系統,和proc一樣。

Sysfs文件系統是一個類似於proc文件系統的特殊文件系統,用於將系統中的設備組織成層次結構,並向用戶模式程序提供詳細的內核數據結構信息。

其實,就是 在用戶態可以通過對sys文件系統的訪問,來看內核態的一些驅動或者設備等。

好了,下面直接去sys目錄看看吧!!!

localhost:/sys#ls

/sys/ block/ bus/ class/ devices/ firmware/ kernel/ module/ power/

Block目錄:包含所有的塊設備,進入到block目錄下,會發現下面全是link文件,link到sys/device/目錄下的一些設備。

Devices目錄:包含系統所有的設備,並根據設備掛接的總線類型組織成層次結構

Bus目錄:包含系統中所有的總線類型

Drivers目錄:包括內核中所有已註冊的設備驅動程序

Class目錄:系統中的設備類型(如網卡設備,聲卡設備等)。去class目錄中看一下,隨便進到一個文件夾下,會發現該文件夾下的文件其實是連接文件,link到/sys/device/.http://www.cnblogs.com/...下的一個設備文件。 可以說明,其實class目錄並不會新建什麼設備,只是將已經註冊的設備,在class目錄下重新歸類,放在一起。

 

但是,你可能根本沒有去關心過sysfs的掛載過程,她是這樣被掛載的。
mount -t sysfs sysfs /sys

 

但是sys文件是根據什麼依據來創建其內容呢?他的信息來源是什麼呢?

下面來分析sys的信息來源。

Linus設備底層模型

Kobject

應該說每個Kobject結構都對應一個 目錄。for example:/sys/bus/pci/drivers/serial/ 路徑, serial這個目錄就是由一個kobject 結構體 來表示的。由此可見,Kobject是用來表示 直接對應着一個 設備,或設備驅動  的目錄。Kobject包含了 這個目錄的一些信息,如:目錄名,父目錄,設備名稱等等一些信息。當然,如果Kobject用來表示一個目錄,那麼他所包含的信息是差不多了,但是Kobject表示的目錄是用來描述某一個設備/設備驅動 的。所以僅僅Kobject這個結構體還不能完全的描述這個設備/設備驅動,再所以,Kobject這個結構體不會單獨使用,一般都會包含在另一個結構體中,用網絡上的話說就是包含在一個容器中。這個容器可以是:device結構體,device_drive結構體。現在層次就很明顯了,device/device_drive來表示一個設備/設備驅動,當然包含了這個設備/設備驅動的信息,並且還包含了這個驅動所對應的目錄的信息,Kobject結構。

當然device/device_drive在另外一層的東西了,後面再分析。我們在這裏就先分析Kobject結構。

struct kobject {
    const char        *name;  //目錄的name
    struct list_head    entry;           //Kobject插入到某個鏈表的指針。
    struct kobject        *parent;  //父目錄,剛纔所述kobject所表示的是設備/設備驅動目錄,但爲什麼他的父目錄也用kobject來表示呢?後面講解。
    struct kset        *kset;    //kobject上上級目錄可能是Kset,這個表示。 這個變量和parent有些相似的地方。 可以從kset_register函數中看出些端倪。
    struct kobj_type    *ktype;
    struct sysfs_dirent    *sd;
    struct kref        kref;   //被引用的次數
    unsigned int state_initialized:1;
    unsigned int state_in_sysfs:1;
    unsigned int state_add_uevent_sent:1;
    unsigned int state_remove_uevent_sent:1;
    unsigned int uevent_suppress:1;
};


注意:在kenerl中,如kref,前面講到的 page_reference變量。 都用來表示被引用。 所以 以後看變量的時候要注意看 ref或reference,來表示被引用。

相關函數

void kobject_init(struct kobject * kobj);kobject初始化函數。

int kobject_set_name(struct kobject *kobj, const char *format, ...);設置指定kobject的名稱。

struct kobject *kobject_get(struct kobject *kobj);將kobj 對象的引用計數加1,同時返回該對象的指針。

void kobject_put(struct kobject * kobj); 將kobj對象的引用計數減1,如果引用計數降爲0,則調用kobject release()釋放該kobject對象。

int kobject_add(struct kobject * kobj);將kobj對象加入Linux設備層次。掛接該kobject對象到kset的list鏈中,增加父目錄各級kobject的引用計數,在其parent指向的目錄下創建文件節點,並啓動該類型內核對象的hotplug函數。

int kobject_register(struct kobject * kobj);kobject註冊函數。通過調用kobject init()初始化kobj,再調用kobject_add()完成該內核對象的註冊。

void kobject_del(struct kobject * kobj);從Linux設備層次(hierarchy)中刪除kobj對象。

void kobject_unregister(struct kobject * kobj);kobject註銷函數。與kobject register()相反,它首先調用kobject del從設備層次中刪除該對象,再調用kobject put()減少該對象的引用計數,如果引用計數降爲0,則釋放kobject對象。

 

kobject下的結構體描述:

struct kobj_type

{

 void (*release)(struct kobject *);

struct sysfs_ops * sysfs_ops;

struct attribute ** default_attrs;

 };

Kobj type數據結構包含三個域:一個release方法用於釋放kobject佔用的資源;一個sysfs ops指針指向sysfs操作表和一個sysfs文件系統缺省屬性列表。

Sysfs操作表包括兩個函數store()和show()。當用戶態讀取屬性時,show()函數被調用,該函數編碼指定屬性值存入buffer中返回給用戶態;而store()函數用於存儲用戶態傳入的屬性值。

attribute struct attribute

 {

char * name;

struct module * owner;

mode_t mode;

};

attribute屬性。它以文件的形式輸出到sysfs的目錄當中。在kobject對應的目錄下面。文件 名就是name。文件讀寫的方法對應於kobj type中的sysfs ops。

 

 

 

Kset

像剛纔所說,每個Kobject結構都對應一個 目錄。for example:/sys/bus/pci/drivers/serial/ 路徑, /serial/這個目錄由一個kobject 結構體 來表示的。但是/serial/的上一級目錄/drivers/如何表示呢?那麼就出現了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的目錄,所以使用一個list將他們全部link起來。  
  20.     spinlock_t list_lock;   //鎖機制  
  21.     struct kobject kobj;    //Kest本質上來說,也是個目錄,所以他也使用了Kobject,來表示他自己的這個目錄  
  22.     struct kset_uevent_ops *uevent_ops;    //由於Kset是將很多的有公共特性的Kobject集中到一起,所以這個變量操作,在他的目錄下的一些共性操作。  
  23. };  

 

subsystem

在以前的版本中,還有subsystem結構,但 是在現在的版本中都已經去掉了,用Kset來代替

 

1 struct subsystem {  
2 struct kset kset;  
3   
4 struct rw semaphore rwsem;   
5   
6 };  



由上面聲明可以看出,完全可以讓Kset來代替subsystem結構。

 

 

 

總結:

1,在sys下,表示一個目錄使用的結構體是 Kobject,但是在linux的內核中,有硬件的設備 和 軟件的驅動,在sys下都需要用一個目錄來表示。 單純的一個Kobject結構無法表示完全,增加了容器,來封裝Kobject。 即下面要將的:device和drive_device結構。

2, 最底層驅動目錄的上一層目錄,從sys角度上來說,他依然是個目錄,所以他也有Kobjec這個變量。但是從他的意義上講,他將 一些有公共特性Kobjec  的 device/driver_device結構組織到了一起,所以除了有Kobject這個變量外,他又添加了一些變量,組成了Kset這個結構來表示這一級的目錄。但是僅僅是用Kset來表示了這一級的目錄,和1,一樣,僅僅表示一個目錄是不夠的,在linux內核中,需要他在軟件上有個映射。所以,也將Kset進行了封裝,形成了  bus_type這個結構。

3, 從1 ,2,的解釋可以看出,應爲kobject在Kset的目錄下,那麼 device/device_driver 就在 bus_type結構下。所以,linux驅動模型中,驅動和設備都是掛在總線下面的。

4, 如上所述,Kset的意義:表示一個目錄(由結構體下的Kobject來完成),並且這個目錄下的所有目錄有共同的特性(所以說,Kset表示的目錄下,不一定非要是Kobject街頭的,也可以是Kset結構的。即:Kset嵌套Kset)。所以使用Kset來代替了以前的 subsystem結構。

貼兩張圖來形象瞭解一下:

1, Kset和Kobject的連接圖(from linux那些事之我是sys)

2,整個sys目錄的結構體表示圖:(from ULK--當然,在這裏subsystem結構要換成Kset了,但我個人認爲,以前的subsystem結構上會更清晰,不是嗎?)

(但這邊有個問題。。。Kobject通過下面的attribute來建立目錄下的文件,但我看到目錄下有好幾個文件,難道是根據一個attribute來建立好幾個文件?疑惑ing,好像attribute是個指針,還能當數組首地址?bus_add_attrs函數中如是說)

 

 

 

設備模型的上層容器

剛纔講了Kset和Kobject結構體,都是用來表示 sys下的目錄結構的。下面來講驅動中封裝這些結構的容器。

 

總線bus

bus_type結構: 剛纔上面已經將的夠多的了,閒話少說,直接上code。

 1 struct bus_type {
 2     const char        *name;       //總線的名稱,這個名字理論上並不是sys/bus/下的那些目錄的目錄名。那些目錄的目錄名應該是在下面變量  subsys_private p.sbusys的name變量中。但是往往那個name是由這個name賦值的,所以就一樣的。但這裏要明白的是(還是上面的老生常談),表示目錄是由Kset.Kobject這個東西來表示的。
 3     struct bus_attribute    *bus_attrs;  //根據後面的bus_add_attrs函數分析,這些個屬性可能是數組
 4     struct device_attribute    *dev_attrs;
 5     struct driver_attribute    *drv_attrs;  //bus device driver的屬性,一些操作導入導出的屬性,等後面再分析。
 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 (*resume)(struct device *dev);       //總線的操作
15 
16     const struct dev_pm_ops *pm;           //power manage 的operations
17 
18     struct subsys_private *p;  見下面:
19 };
 1 struct subsys_private {  //爲了保持和上面的代碼的連貫,我將這個結構體的註釋部分放到下面了。註釋還是比較清楚的,不解釋
 2  struct kset subsys;      
 3 &nbsp;struct kset *devices_kset;</p><p>&nbsp;struct kset *drivers_kset;
 4 &nbsp;struct klist klist_devices;
 5 &nbsp;struct klist klist_drivers;
 6 &nbsp;struct blocking_notifier_head bus_notifier;
 7 &nbsp;unsigned int drivers_autoprobe:1;
 8 &nbsp;struct bus_type *bus;</p><p>&nbsp;struct list_head class_interfaces;
 9 &nbsp;struct kset glue_dirs;
10 &nbsp;struct mutex class_mutex;
11 &nbsp;struct class *class;
12 };
13 &nbsp;* struct subsys_private - structure to hold the private to the driver core portions of the bus_type/class structure.
14 &nbsp;*
15 &nbsp;* @subsys - the struct kset that defines this subsystem
16 &nbsp;* @devices_kset - the list of devices associated
17 &nbsp;*
18 &nbsp;* @drivers_kset - the list of drivers associated
19 &nbsp;* @klist_devices - the klist to iterate over the @devices_kset
20 &nbsp;* @klist_drivers - the klist to iterate over the @drivers_kset
21 &nbsp;* @bus_notifier - the bus notifier list for anything that cares about things
22 &nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; on this bus.
23 &nbsp;* @bus - pointer back to the struct bus_type that this structure is associated
24 &nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; with.
25 &nbsp;*
26 &nbsp;* @class_interfaces - list of class_interfaces associated
27 &nbsp;* @glue_dirs - "glue" directory to put in-between the parent device to
28 &nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; avoid namespace conflicts
29 &nbsp;* @class_mutex - mutex to protect the children, devices, and interfaces lists.
30 &nbsp;* @class - pointer back to the struct class that this structure is associated
31 &nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; with.
32 &nbsp;*
33 &nbsp;* This structure is the one that is the actual kobject allowing struct
34 &nbsp;* bus_type/class to be statically allocated safely.&nbsp; Nothing outside of the
35 &nbsp;* driver core should ever touch these fields.
36 &nbsp;*/</p>

這個結構體用來描述比如:/sys/bus/pci pci總線,/sys/bus/platform platform總線等。

另外:從這個結構體分析下來,整個bus的目錄結構都很清楚了eg:

1,可以找到總線下的設備目錄: bus_type bus ---> subsys_private p---->Kest devices_kset

2,可以找到總線下的設備驅動目錄: bus_type bus ---> subsys_private p---->Kest driver_kset

另外,找到的也只是目錄,因爲找到的僅僅是Kset結構。


設備device

首先明白,device這個結構並不是直接掛在bus下的,可以到/sys/bus/platform/device下隨便看一下,發現裏面的都是link文件,link到/sys/device/下。所以真正的device結構體的在/sys/device下的。

 
  1. struct device {  
  2.     struct device       *parent;  //設備的父設備指針,那麼就是說device的目錄也是可以嵌套的?到/sys/device/platform/serial8250目錄下看看,竟然還存在着 tty/ 目錄,是不是這樣嵌套的呢??天知道。。。。。  
  3.   
  4.     struct device_private   *p;  
  5.   
  6.     struct kobject kobj;        //這個就是說了好久的 Kobject  
  7.     const char      *init_name; /* initial name of the device */  
  8.     struct device_type  *type;  
  9.   
  10.     struct mutex        mutex;  /* mutex 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        *platform_data; /* Platform specific data, device 
  18.                        core doesn't touch it */  
  19.     struct dev_pm_info  power;  
  20.     struct dev_power_domain *pwr_domain;  
  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.     struct device_node  *of_node; /* associated device tree node */  
  42.   
  43.     dev_t           devt;   /* dev_t, creates the sysfs "dev" */  
  44.   
  45.     spinlock_t      devres_lock;  
  46.     struct list_head    devres_head;  
  47.   
  48.     struct klist_node   knode_class;  
  49.     struct class        *class;  
  50.     const struct attribute_group **groups;  /* optional groups */  
  51.   
  52.     void    (*release)(struct device *dev);  
  53. };  


設備driver

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

 

 

設備模型的註冊等操作:

 

總線的操作:

用戶可以自己註冊一個總線,然後將自己喜歡的設備和驅動掛載到下面。但是linux 2.6中,有個默認的總線,platform總線。我們就分析一下這個總線。

小記:隨手在Source insight裏敲了個 platform_bus_init,結果的真的有這個函數,再看一下誰調用他了吧? 竟然是drive_init。啊。。終於找到組織了,在start_kernel的最後一步後調用這個drive_init了。

 
  1. int __init platform_bus_init(void)  
  2. {  
  3.     int error;  
  4.   
  5.     early_platform_cleanup();  //清除platform總線上的設備?不確定,,,好像就是將early_platform_device_list這個裏的內容清空。  
  6.   
  7.     error = device_register(&platform_bus);  //設備註冊。哦,linux將platform也當成了一個設備,他在/sys/device目錄下。當然,以後會在platform這個設備下再建立其他的設備,回顧剛纔介紹device結構體時候有個parent變量,應該就是用在這裏的。具體device_register這個函數,後面再介紹  
  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. }  

 

  1.  * bus_register - register a bus with the system. 
  2.  * @bus: bus. 
  3.  * 
  4.  * Once we have that, we registered the bus with the kobject 
  5.  * infrastructure, then register the children subsystems it has: 
  6.  * the devices and drivers that belong to the bus. 
  7.  */  
  8. int bus_register(struct bus_type *bus)  
  9. {  
  10.     int retval;  
  11.     struct subsys_private *priv;  
  12.   
  13.     priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);  
  14.     if (!priv)  
  15.         return -ENOMEM;  
  16.   
  17.     priv->bus = bus;  
  18.     bus->p = priv;  
  19.   
  20.     BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);       //bus_notifier就是個讀寫信號量,和RCU機制,這裏進行初始化  
  21.   
  22.     retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);  //設置name,這個name會顯示在sys/bus/下  
  23.     if (retval)  
  24.         goto out;  
  25.   
  26.     priv->subsys.kobj.kset = bus_kset;  
  27.     priv->subsys.kobj.ktype = &bus_ktype;  
  28.     priv->drivers_autoprobe = 1;  
  29.   
  30.     retval = kset_register(&priv->subsys);               //這個應該是註冊bus,但看函數名是ket_register,所以可能會根據剛纔對subsys.kobj.kset的賦值來判定是bus,並註冊。後面分析。  
  31.     if (retval)  
  32.         goto out;  
  33.   
  34.     retval = bus_create_file(bus, &bus_attr_uevent);       //在對應的bus目錄下,根據attribute來創建一個文件  
  35.     if (retval)  
  36.         goto bus_uevent_fail;  
  37.   
  38.     priv->devices_kset = kset_create_and_add("devices", NULL,                  //這就函數應該是創建目錄,所以在每個bus下會有 device和driver 兩個目錄。  
  39.                          &priv->subsys.kobj);  
  40.     if (!priv->devices_kset) {  
  41.         retval = -ENOMEM;  
  42.         goto bus_devices_fail;  
  43.     }  
  44.   
  45.     priv->drivers_kset = kset_create_and_add("drivers", NULL,  
  46.                          &priv->subsys.kobj);  
  47.     if (!priv->drivers_kset) {  
  48.         retval = -ENOMEM;  
  49.         goto bus_drivers_fail;  
  50.     }  
  51.   
  52.     klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);  
  53.     klist_init(&priv->klist_drivers, NULL, NULL);       //klist還是沒搞明白怎麼用,以後再說吧  
  54.   
  55.     retval = add_probe_files(bus);       //這個也是在對應的總線目錄下,建立bus_attr_drivers_probe 和 bus_attr_drivers_autoprobe文件。應該是probe的時候使用。  
  56.     if (retval)  
  57.         goto bus_probe_files_fail;  
  58.   
  59.     retval = bus_add_attrs(bus);  //循環將所有的bus的屬性都建立成一個文件。  
  60.     if (retval)  
  61.         goto bus_attrs_fail;  
  62.   
  63.     pr_debug("bus: '%s': registered\n", bus->name);  
  64.     return 0;  
  65.   
  66. bus_attrs_fail:  
  67.     remove_probe_files(bus);  
  68. bus_probe_files_fail:  
  69.     kset_unregister(bus->p->drivers_kset);  
  70. bus_drivers_fail:  
  71.     kset_unregister(bus->p->devices_kset);  
  72. bus_devices_fail:  
  73.     bus_remove_file(bus, &bus_attr_uevent);  
  74. bus_uevent_fail:  
  75.     kset_unregister(&bus->p->subsys);  
  76. out:  
  77.     kfree(bus->p);  
  78.     bus->p = NULL;  
  79.     return retval;  
  80. }  


  /** 

  kset_register - initialize and add a kset. 

  1.  * @k: kset. 
  2.  */  
  3. int kset_register(struct kset *k)  
  4. {  
  5.     int err;  
  6.   
  7.     if (!k)  
  8.         return -EINVAL;  
  9.   
  10.     kset_init(k);          //初始化,沒什麼東西  
  11.     err = kobject_add_internal(&k->kobj);  //下面分析  
  12.     if (err)  
  13.         return err;  
  14.     kobject_uevent(&k->kobj, KOBJ_ADD);    //通過這個函數的註釋可知,向usrspace發送信號。  
  15.     return 0;  
  16. }  
 
  1. static int kobject_add_internal(struct kobject *kobj)  
  2. {  
  3.  int error = 0;  
  4.  struct kobject *parent;</p><p> if (!kobj)  
  5.   return -ENOENT;</p><p> if (!kobj->name || !kobj->name[0]) {  
  6.   WARN(1, "kobject: (%p): attempted to be registered with empty "  
  7.     "name!\n", kobj);  
  8.   return -EINVAL;  
  9.  }
  10.  
  11. parent = kobject_get(kobj->parent);</p><p> /* join kset if set, use it as parent if we do not already have one */  
  12.  if (kobj->kset) {  
  13.   if (!parent)  
  14.    parent = kobject_get(&kobj->kset->kobj);   //get kobject->kset, 判斷與parent對比。        
  15. obj_kset_join(kobj);         //這個函數,是將kobject的entry這個變量 添加到 他的 上一級的kset結構的 list中。  
  16.   kobj->parent = parent;  
  17.  }
  18.  
  19.  
  20. pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",  
  21.    kobject_name(kobj), kobj, __func__,  
  22.    parent ? kobject_name(parent) : "<NULL>",  
  23.    kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");</p><p> error = create_dir(kobj);   //創建目錄。比如:/sys/bus 下的 platform, pci等目錄。  
  24.  if (error) {  
  25.   kobj_kset_leave(kobj);  
  26.   kobject_put(parent);  
  27.   kobj->parent = NULL;</p><p>  /* be noisy on error issues */  
  28.   if (error == -EEXIST)  
  29.    printk(KERN_ERR "%s failed for %s with "  
  30.           "-EEXIST, don't try to register things with "  
  31.           "the same name in the same directory.\n",  
  32.           __func__, kobject_name(kobj));  
  33.   else  
  34.    printk(KERN_ERR "%s failed for %s (%d)\n",  
  35.           __func__, kobject_name(kobj), error);  
  36.   dump_stack();  
  37.  } else  
  38.   kobj->state_in_sysfs = 1;</p><p> return error;  
  39. }</p>  

到此,bus_register解釋完成。

 

 
  1.  * device_register - register a device with the system. 
  2.  * @dev: pointer to the device structure 
  3.  * 
  4.  * This happens in two clean steps - initialize the device 
  5.  * and add it to the system. The two steps can be called 
  6.  * separately, but this is the easiest and most common. 
  7.  * I.e. you should only call the two helpers separately if 
  8.  * have a clearly defined need to use and refcount the device 
  9.  * before it is added to the hierarchy. 
  10.  * 
  11.  * NOTE: _Never_ directly free @dev after calling this function, even 
  12.  * if it returned an error! Always use put_device() to give up the 
  13.  * reference initialized in this function instead. 
  14.  */  
  15. int device_register(struct device *dev)  
  16. {  
  17.     device_initialize(dev);  
  18.     return device_add(dev);  
  19. }  
 
  1.  * device_initialize - init device structure. 
  2.  * @dev: device. 
  3.  * 
  4.  * This prepares the device for use by other layers by initializing 
  5.  * its fields. 
  6.  * It is the first half of device_register(), if called by 
  7.  * that function, though it can also be called separately, so one 
  8.  * may use @dev's fields. In particular, get_device()/put_device() 
  9.  * may be used for reference counting of @dev after calling this 
  10.  * function. 
  11.  * 
  12.  * NOTE: Use put_device() to give up your reference instead of freeing 
  13.  * @dev directly once you have called this function. 
  14.  */  
  15. void device_initialize(struct device *dev)  
  16. {  
  17.     dev->kobj.kset = devices_kset;  
  18.     kobject_init(&dev->kobj, &device_ktype);  
  19.     INIT_LIST_HEAD(&dev->dma_pools);  
  20.     mutex_init(&dev->mutex);  
  21.     lockdep_set_novalidate_class(&dev->mutex);  
  22.     spin_lock_init(&dev->devres_lock);  
  23.     INIT_LIST_HEAD(&dev->devres_head);  
  24.     device_pm_init(dev);  
  25.     set_dev_node(dev, -1);  
  26. }  


dev_initialize,不解釋。

這裏有個疑問:在bus_register的時候,有條語句:priv->subsys.kobj.kset = bus_kset;。在dev_initialize的時候也有條dev->kobj.kset = devices_kset;語句。 剛纔以爲是上級目錄的kset結構。但是如此看來好像不是很對,因爲dev的上級目錄是不定的,可能在/sys/device/platform下,也可能在其他。但是都賦值成devices_kset顯然不對。  那麼有可能在一個標誌。所有的bus的subsys.kobj.kset 這個變量都是bus_kset, 所有dev->kobj.kset的變量都是devices_kset。具體爲什麼?

天空中深沉的傳來一句話:1+1=幾?

我說:2

啪,一道雷劈死我了。答曰:你知道的太多了。  爲了留條命,就不解釋了。

 

  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.     if (!dev->p) {  
  27.         error = device_private_init(dev);  
  28.         if (error)  
  29.             goto done;  
  30.     }  
  31.   
  32.     /* 
  33.      * for statically allocated devices, which should all be converted 
  34.      * some day, we need to initialize the name. We prevent reading back 
  35.      * the name, and force the use of dev_name() 
  36.      */  
  37.     if (dev->init_name) {  
  38.         dev_set_name(dev, "%s", dev->init_name);  
  39.         dev->init_name = NULL;  
  40.     }  
  41.   
  42.     if (!dev_name(dev)) {  
  43.         error = -EINVAL;  
  44.         goto name_error;  
  45.     }  
  46.   
  47.     pr_debug("device: '%s': %s\n", dev_name(dev), __func__);  
  48.   
  49.     parent = get_device(dev->parent);  
  50.     setup_parent(dev, parent);  
  51.   
  52.     /* use parent numa_node */  
  53.     if (parent)  
  54.         set_dev_node(dev, dev_to_node(parent));  
  55.     //以上是對device進行初始化,包括name,private,parent……  
  56.     /* first, register with generic layer. */  
  57.     /* we require the name to be set before, and pass NULL */  
  58.     error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);   //device添加,根據他的parent等,當然還會根據他的attribute built一些文件。  
  59.     if (error)  
  60.         goto Error;  
  61.   
  62.     /* notify platform of device entry */  
  63.     if (platform_notify)  
  64.         platform_notify(dev);  
  65.   
  66.     error = device_create_file(dev, &uevent_attr);  //built attr file  
  67.     if (error)  
  68.         goto attrError;  
  69.   
  70.     if (MAJOR(dev->devt)) {  
  71.         error = device_create_file(dev, &devt_attr);  
  72.         if (error)  
  73.             goto ueventattrError;  
  74.   
  75.         error = device_create_sys_dev_entry(dev);  
  76.         if (error)  
  77.             goto devtattrError;  
  78.   
  79.         devtmpfs_create_node(dev);  
  80.     }  
  81.   
  82.     error = device_add_class_symlinks(dev);         //在其他文件夾 建立link文件,這就是爲什麼在class目錄下也能看到device的目錄和文件了  
  83.     if (error)  
  84.         goto SymlinkError;  
  85.     error = device_add_attrs(dev);  
  86.     if (error)  
  87.         goto AttrsError;  
  88.     error = bus_add_device(dev);      //在bus目錄下 建立link文件,所以在/sys/bus/platform/device下回看到n多個link文件。  
  89.     if (error)  
  90.         goto BusError;  
  91.     error = dpm_sysfs_add(dev);  
  92.     if (error)  
  93.         goto DPMError;  
  94.     device_pm_add(dev);  
  95.   
  96.     /* Notify clients of device addition.  This call must come 
  97.      * after dpm_sysf_add() and before kobject_uevent(). 
  98.      */  
  99.     if (dev->bus)  
  100.         blocking_notifier_call_chain(&dev->bus->p->bus_notifier,  
  101.                          BUS_NOTIFY_ADD_DEVICE, dev);  
  102.   
  103.     kobject_uevent(&dev->kobj, KOBJ_ADD);  
  104.     bus_probe_device(dev);         //進行probe,看有沒和device相對應的driver文件。  
  105.     if (parent)  
  106.         klist_add_tail(&dev->p->knode_parent,  
  107.                    &parent->p->klist_children);  
  108.   
  109.     if (dev->class) {  
  110.         mutex_lock(&dev->class->p->class_mutex);  
  111.         /* tie the class to the device */  
  112.         klist_add_tail(&dev->knode_class,  
  113.                    &dev->class->p->klist_devices);  
  114.   
  115.         /* notify any interfaces that the device is here */  
  116.         list_for_each_entry(class_intf,  
  117.                     &dev->class->p->class_interfaces, node)  
  118.             if (class_intf->add_dev)  
  119.                 class_intf->add_dev(dev, class_intf);  
  120.         mutex_unlock(&dev->class->p->class_mutex);  
  121.     }  
  122. done:  
  123.     put_device(dev);  
  124.     return error;  
  125.  DPMError:  
  126.     bus_remove_device(dev);  
  127.  BusError:  
  128.     device_remove_attrs(dev);  
  129.  AttrsError:  
  130.     device_remove_class_symlinks(dev);  
  131.  SymlinkError:  
  132.     if (MAJOR(dev->devt))  
  133.         devtmpfs_delete_node(dev);  
  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. }  



當然還有 drive_register的函數,其實和device_register差不多,另外,driver_register也會在最後進行probe,看有沒有相應的設備。driver_register會先check這個drvier所在的bus上有沒有probe函數,如果有就運行這個函數進行probe,如果沒有,就運行自己的probe進行probe,這就是我們在驅動中經常看到的probe函數。

所以,在驅動中,先運行drive_register和先運行device_register都是一樣的。

 

到這裏,我們看完了platform總線如何對底層的kobject的封裝機制了吧???親們是否明白了呢???呵呵,下面的驅動內容會介紹不同的封裝類型,請注意面向對象的思想。

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