sys文件系统

来源:互联网 发布:java 数组转化成json 编辑:程序博客网 时间:2024/05/17 03:04

http://blog.csdn.net/mihouge/article/details/7044679

linux混混之牢骚:

 同事小李要移民到美国,领导问他:“你对你的工资不满意吗?”

 小李说:“满意。”

“对你的住房不满意?”

“满意”

“那是上网环境不满意?”

“也满意”

“对医疗,孩子上学都不满意?”

“都满意!”

“既然你都满意为什么还要移民?”

“因为那里允许有不满意!”

 

 

linux version:2.6.39

什么是sys文件系统:

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/.../../...下的一个设备文件。 可以说明,其实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结构。

[cpp] view plaincopyprint?
  1. struct kobject {  
  2.     const char      *name;  //目录的name  
  3.     struct list_head    entry;           //Kobject插入到某个链表的指针。  
  4.     struct kobject      *parent;  //父目录,刚才所述kobject所表示的是设备/设备驱动目录,但为什么他的父目录也用kobject来表示呢?后面讲解。  
  5.     struct kset     *kset;    //kobject上上级目录可能是Kset,这个表示。 这个变量和parent有些相似的地方。 可以从kset_register函数中看出些端倪。  
  6.     struct kobj_type    *ktype;  
  7.     struct sysfs_dirent *sd;  
  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. };  

注意:在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这个结构体。

[cpp] view plaincopyprint?
  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来代替

[cpp] view plaincopyprint?
  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。

[cpp] view plaincopyprint?
  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. };  
[cpp] view plaincopyprint?
  1. <p>struct subsys_private {  //为了保持和上面的代码的连贯,我将这个结构体的注释部分放到下面了。注释还是比较清楚的,不解释  
  2.  struct kset subsys;        
  3.  struct kset *devices_kset;</p><p> struct kset *drivers_kset;  
  4.  struct klist klist_devices;  
  5.  struct klist klist_drivers;  
  6.  struct blocking_notifier_head bus_notifier;  
  7.  unsigned int drivers_autoprobe:1;  
  8.  struct bus_type *bus;</p><p> struct list_head class_interfaces;  
  9.  struct kset glue_dirs;  
  10.  struct mutex class_mutex;  
  11.  struct class *class;  
  12. };</p><p>/** 
  13.  * struct subsys_private - structure to hold the private to the driver core portions of the bus_type/class structure. 
  14.  * 
  15.  * @subsys - the struct kset that defines this subsystem 
  16.  * @devices_kset - the list of devices associated 
  17.  * 
  18.  * @drivers_kset - the list of drivers associated 
  19.  * @klist_devices - the klist to iterate over the @devices_kset 
  20.  * @klist_drivers - the klist to iterate over the @drivers_kset 
  21.  * @bus_notifier - the bus notifier list for anything that cares about things 
  22.  *                 on this bus. 
  23.  * @bus - pointer back to the struct bus_type that this structure is associated 
  24.  *        with. 
  25.  * 
  26.  * @class_interfaces - list of class_interfaces associated 
  27.  * @glue_dirs - "glue" directory to put in-between the parent device to 
  28.  *              avoid namespace conflicts 
  29.  * @class_mutex - mutex to protect the children, devices, and interfaces lists. 
  30.  * @class - pointer back to the struct class that this structure is associated 
  31.  *          with. 
  32.  * 
  33.  * This structure is the one that is the actual kobject allowing struct 
  34.  * bus_type/class to be statically allocated safely.  Nothing outside of the 
  35.  * driver core should ever touch these fields. 
  36.  */</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结构。

于此看来,这个subsys_private p这个变量挺有用的。 哥预言,此子日后必成大器。当然,条件是 日后!!哥邪恶的笑了。。。。。

 

 

设备device

首先明白,device这个结构并不是直接挂在bus下的,可以到/sys/bus/platform/device下随便看一下,发现里面的都是link文件,link到/sys/device/下。所以真正的device结构体的在/sys/device下的。

[cpp] view plaincopyprint?
  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

[cpp] view plaincopyprint?
  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了。

[cpp] view plaincopyprint?
  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. }  


 

[cpp] view plaincopyprint?
  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 subsys_private *priv;  
  13.   
  14.     priv = kzalloc(sizeof(struct subsys_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);       //bus_notifier就是个读写信号量,和RCU机制,这里进行初始化  
  22.   
  23.     retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);  //设置name,这个name会显示在sys/bus/下  
  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.     retval = kset_register(&priv->subsys);               //这个应该是注册bus,但看函数名是ket_register,所以可能会根据刚才对subsys.kobj.kset的赋值来判定是bus,并注册。后面分析。  
  32.     if (retval)  
  33.         goto out;  
  34.   
  35.     retval = bus_create_file(bus, &bus_attr_uevent);       //在对应的bus目录下,根据attribute来创建一个文件  
  36.     if (retval)  
  37.         goto bus_uevent_fail;  
  38.   
  39.     priv->devices_kset = kset_create_and_add("devices", NULL,                  //这就函数应该是创建目录,所以在每个bus下会有 device和driver 两个目录。  
  40.                          &priv->subsys.kobj);  
  41.     if (!priv->devices_kset) {  
  42.         retval = -ENOMEM;  
  43.         goto bus_devices_fail;  
  44.     }  
  45.   
  46.     priv->drivers_kset = kset_create_and_add("drivers", NULL,  
  47.                          &priv->subsys.kobj);  
  48.     if (!priv->drivers_kset) {  
  49.         retval = -ENOMEM;  
  50.         goto bus_drivers_fail;  
  51.     }  
  52.   
  53.     klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);  
  54.     klist_init(&priv->klist_drivers, NULL, NULL);       //klist还是没搞明白怎么用,以后再说吧  
  55.   
  56.     retval = add_probe_files(bus);       //这个也是在对应的总线目录下,建立bus_attr_drivers_probe 和 bus_attr_drivers_autoprobe文件。应该是probe的时候使用。  
  57.     if (retval)  
  58.         goto bus_probe_files_fail;  
  59.   
  60.     retval = bus_add_attrs(bus);  //循环将所有的bus的属性都建立成一个文件。  
  61.     if (retval)  
  62.         goto bus_attrs_fail;  
  63.   
  64.     pr_debug("bus: '%s': registered\n", bus->name);  
  65.     return 0;  
  66.   
  67. bus_attrs_fail:  
  68.     remove_probe_files(bus);  
  69. bus_probe_files_fail:  
  70.     kset_unregister(bus->p->drivers_kset);  
  71. bus_drivers_fail:  
  72.     kset_unregister(bus->p->devices_kset);  
  73. bus_devices_fail:  
  74.     bus_remove_file(bus, &bus_attr_uevent);  
  75. bus_uevent_fail:  
  76.     kset_unregister(&bus->p->subsys);  
  77. out:  
  78.     kfree(bus->p);  
  79.     bus->p = NULL;  
  80.     return retval;  
  81. }  


 

bus_register-->kset_register

[cpp] view plaincopyprint?
  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);          //初始化,没什么东西  
  13.     err = kobject_add_internal(&k->kobj);  //下面分析  
  14.     if (err)  
  15.         return err;  
  16.     kobject_uevent(&k->kobj, KOBJ_ADD);    //通过这个函数的注释可知,向usrspace发送信号。  
  17.     return 0;  
  18. }  
[cpp] view plaincopyprint?
  1. <p>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.  }</p><p> parent = kobject_get(kobj->parent);</p><p> /* join kset if set, use it as parent if we do not already have one */  
  10.  if (kobj->kset) {  
  11.   if (!parent)  
  12.    parent = kobject_get(&kobj->kset->kobj);   //get kobject->kset, 判断与parent对比。        
  13. obj_kset_join(kobj);         //这个函数,是将kobject的entry这个变量 添加到 他的 上一级的kset结构的 list中。  
  14.   kobj->parent = parent;  
  15.  }</p><p> pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",  
  16.    kobject_name(kobj), kobj, __func__,  
  17.    parent ? kobject_name(parent) : "<NULL>",  
  18.    kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");</p><p> error = create_dir(kobj);   //创建目录。比如:/sys/bus 下的 platform, pci等目录。  
  19.  if (error) {  
  20.   kobj_kset_leave(kobj);  
  21.   kobject_put(parent);  
  22.   kobj->parent = NULL;</p><p>  /* be noisy on error issues */  
  23.   if (error == -EEXIST)  
  24.    printk(KERN_ERR "%s failed for %s with "  
  25.           "-EEXIST, don't try to register things with "  
  26.           "the same name in the same directory.\n",  
  27.           __func__, kobject_name(kobj));  
  28.   else  
  29.    printk(KERN_ERR "%s failed for %s (%d)\n",  
  30.           __func__, kobject_name(kobj), error);  
  31.   dump_stack();  
  32.  } else  
  33.   kobj->state_in_sysfs = 1;</p><p> return error;  
  34. }</p>  

到此,bus_register解释完成。

 

[cpp] view plaincopyprint?
  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);  
  19.     return device_add(dev);  
  20. }  
[cpp] view plaincopyprint?
  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;  
  19.     kobject_init(&dev->kobj, &device_ktype);  
  20.     INIT_LIST_HEAD(&dev->dma_pools);  
  21.     mutex_init(&dev->mutex);  
  22.     lockdep_set_novalidate_class(&dev->mutex);  
  23.     spin_lock_init(&dev->devres_lock);  
  24.     INIT_LIST_HEAD(&dev->devres_head);  
  25.     device_pm_init(dev);  
  26.     set_dev_node(dev, -1);  
  27. }  


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

啪,一道雷劈死我了。答曰:你知道的太多了。  为了留条命,就不解释了。

 

[cpp] view plaincopyprint?
  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都是一样的。



实际的在操作系统中,很少有像教科书中那样的驱动。 建立一个 字符设备,初始化,注册, 然后就齐活了。这样的写法很少的。当然,如果仅仅像教科书中,使用alloc_chrdev(),add_chrdev()等函数的话,好像不会和sys文件系统产生什么关系。仅仅在添加了一个字符驱动,要再运行mknod 来建立设备文件进行操作。

 

但是,在实际中,最底层的驱动,并不是直接与用户进行交互的。 例如:nand,nor上面会有mtd层,serial上面有tty层等。。。。真正开放给用户的是mtd和tty。所以在上文中的讨论的函数(bus,device,drive,bus_register,device_register....)都是最最底层的驱动。nand,Nor,serial这样的底层驱动用的。

 

而到mtd,tty层的时候,可能就不会使用(bus,device,drive)等这些结构和函数了。mtd,tty这些层一般会使用最底层驱动提供的接口(读,写),再对其进行一次封装,使其更标准更易用。然后同过class_creat等函数,对/sys/class进行操作,所以/sys/class下的那些文件,才是最后面向用户提供的。

 

系统boot成功后,udev会check /sys/class还有/sys/block下的每个文件,然后在/dev目录下建立设备文件。

 

所以说,/sys/device /sys/bus目录都是面向很底层很底层的驱动的。当然哭在用户态通过 观察对/sys/bus下的目录结构来了解很底层的设备,如usb的数量,什么样的flash等。/sys/class 是面向用户的,可以通过/sys/class 查看到鼠标设备,网络等。那么由此可以看出,如果编写很底层的设备的话,那么要做的事,1,调用drive_register,device_register等函数注册,实现probe函数,2,实现对上层子系统的接口。 只需要这两步就可以了,什么主次设备号,什么其他的东西都不用。

当然,如上面例子中,也可以直接编写Nand,Nor的驱动,跳过MTD层,直接让flash的驱动接口开放给用户。那么的话,就需要在flash的驱动中,添加 字符驱动的注册,或者块设备的注册函数等。同时,drive_register,device_register等函数就可以省略了。因为这些函数都是向他上层的子系统来传达信息的。





0 0