> Linux教程 > linux基础 >

linux文件系统的系统分析--(十一)sysfs和设备模型--Bus

 在分析设备模型的bus之前,我们看一下初始化的过程,很有意思:

     start_kernel-->rest_init-->kernel_init-->do_basic_setup

     在do_basic_setup中有个usermodehelper_init有意思,凭感觉,这个函数与kobject_uevent有联系,kobject_uevent做什么的,就是内核空间来通知用户空间的,比如udev就是利用这个来在/dev创建设备文件的,再比如在嵌入式中,插拔个硬盘或者USB,gui总会提示插入或者拨出之类的提示,这个一般是内核中驱动模型根据kobject的uevent来告诉用户态的,如果通信的,是通过netlink这种特殊的socket来像用户空间广播的,这样gui中可以用socket来接受信息,并解析,然后显示出来。先提到这里,usermodehelper_init是不是这么回事,还需要更多的时间去研究。

      好,继续看do_basic_setup中的其它函数:driver_init

      

[cpp] view plain copy
 
  1. /** 
  2.  * driver_init - initialize driver model. 
  3.  * 
  4.  * Call the driver model init functions to initialize their 
  5.  * subsystems. Called early from init/main.c. 
  6.  */  
  7. void __init driver_init(void)  
  8. {  
  9.     /* These are the core pieces */  
  10.     devtmpfs_init();  
  11.     devices_init();  
  12.     buses_init();  
  13.     classes_init();  
  14.     firmware_init();  
  15.     hypervisor_init();  
  16.   
  17.     /* These are also core pieces, but must come after the 
  18.      * core core pieces. 
  19.      */  
  20.     platform_bus_init();  
  21.     system_bus_init();  
  22.     cpu_dev_init();  
  23.     memory_dev_init();  
  24. }  
      看下这个函数的注释,就清楚它就是接下来要分析的设备模型 的初始化。

 

      devtmpfs_init是什么?是在/dev下面挂载的一个内存文件系统,具体可以看《linux设备模型之字符设备》一文,与驱动是有一定联系,应该是2.6.32之后加入的。

      今天我们只分析core core pieces中的buses_init:

 

[cpp] view plain copy
 
  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. }  
       很简单,新增一个kset,在/sys下有了bus目录。

 

       我们的重心在后面,如何在bus目录下添加总线类型:

       描述总线的结构体:bus_type

 

[cpp] view plain copy
 
  1. 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 (*resume)(struct device *dev);   //总线的电源管理操作  
  15.   
  16.     const struct dev_pm_ops *pm;  
  17.   
  18.     struct bus_type_private *p;    //总线的私有变量指针  
  19. };  
         与bus_type紧密相关的结构体:struct bus_type_private

 

 

[cpp] view plain copy
 
  1. struct bus_type_private {  
  2.     struct kset subsys;   //具体总线的kset  
  3.     struct kset *drivers_kset;  //总线上所有驱动的集合  
  4.     struct kset *devices_kset; //总线上所有设备的集合  
  5.     struct klist klist_devices;  //链表,上面是总线上的设备  
  6.     struct klist klist_drivers;   //链表,上面是总线上的驱动  
  7.     struct blocking_notifier_head bus_notifier;  
  8.     unsigned int drivers_autoprobe:1;  
  9.     struct bus_type *bus;    //指向总线类型结构体  
  10. };  
        总线的注册:bus_register

 

        

[cpp] view plain copy
 
  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;      //bus_type和bus_type_private紧密联系起来  
  20.   
  21.     BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);  
  22.   
  23.     retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);   //设置具体总线kset内嵌kobject的名称  
  24.     if (retval)  
  25.         goto out;  
  26.   
  27.     priv->subsys.kobj.kset = bus_kset;        //总线kset内嵌kobject的kset指向bus_kset,也就是说上级目录是/sys/bus  
  28.     priv->subsys.kobj.ktype = &bus_ktype;  
  29.     priv->drivers_autoprobe = 1;  
  30.   
  31.     retval = kset_register(&priv->subsys);    //注册总线的kset,生成/sys/bus/xxbus 目录  
  32.     if (retval)  
  33.         goto out;  
  34.   
  35.     retval = bus_create_file(bus, &bus_attr_uevent);    //创建uevent目录,只写的文件,写文件会调用kobject_uevent函数  
  36.     if (retval)  
  37.         goto bus_uevent_fail;  
  38.   
  39.     priv->devices_kset = kset_create_and_add("devices", NULL,      //在xxbus目录下建立devices目录  
  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,      //在xxbus目录下建立drivers目录  
  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);   //初始化klist_devices链表  
  54.     klist_init(&priv->klist_drivers, NULL, NULL);                             //初始化klist_drivers链表  
  55.   
  56.     retval = add_probe_files(bus);                                //在xxbus目录下建立drivers_probe和drivers_autoprobe文件  
  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.     kfree(bus->p);  
  78. out:  
  79.     bus->p = NULL;  
  80.     return retval;  
  81. }  
        总线的注册方法就是上面这么多,比如platform总线的注册,就是在/sys/bus目录下多了个platform目录,而在platform目录下:

 

        devices  drivers  drivers_autoprobe  drivers_probe  uevent

        总线远没有目前看到的这么简单,因为它的方法我们还没用到。在分析完设备和驱动后,我们再分析一个完整的过程。

(责任编辑:IT)