Linux设备模型之bus,device,driver分析

自己笔记使用.

内核的开发者将总线,设备,驱动这三者用软件思想抽象了出来,巧妙的建立了其间的关系,使之更形象化。结合前面所学的知识,总的来说其三者间的关系为bus有两条链表,分别用于挂接设备和驱动,指定了其自身bus的device或者driver最后都会分别连接到对应bus的这两条链表上,而总线又有其始端,为bus_kset,一个driver可以对应于几个设备,因此driver同样有其设备链表,用于挂接可以操作的设备,其自身也有bus挂接点,用于将自身挂接到对应bus(每个driver只属于一条总线),而对于device,一个设备只属于一条总线,只能有一个driver与其对应,因此对于device,都是单一的,一个driver挂接点,一个bus挂接点,device与bus相同的是都有始端,device为devices_kset,因此device的注册同时会出现在对应的bus目录和device总目录下。好了,下面就以源码为例分别分析一下bus,device,driver的注册过程。

Kernel 版本 4.15.0 (ubuntu 18.04,intel skylake)

一、bus的注册

最近想学习VGA驱动去了解 DDCCP / EDID 等协议,然后顺便了解下驱动是如何工作的.

      bus的注册比较简单,首先来看一下bus的结构:

1.  drivers/base/init.c –> driver_init() 这个函数比较重要,会创建驱动所需要的若干结构体,并且产生相应主目录

     

  •     比如 /sys/bus, /sys/devices, /sys/dev 等等目录.

[cpp]

  1. drivers/pci/pci-driver.c –>  postcore_initcall(pci_driver_init)  这里是个关键.
  1. struct bus_type {  
  2.     const char      *name;                //名字   
  3.     struct bus_attribute    *bus_attrs;           //bus属性集   
  4.     struct device_attribute *dev_attrs;           //device属性集   
  5.     struct driver_attribute *drv_attrs;           //driver属性集   
  6.     int (*match)(struct device *dev, struct device_driver *drv);  
  7.     int (*uevent)(struct device *dev, struct kobj_uevent_env *env);  
  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.     const struct dev_pm_ops *pm;  
  14.     struct bus_type_private *p;                   //bus的私有成员   
  15. };  
  16. //其中重点看一下私有成员结构体:   
  17. struct bus_type_private {  
  18.     struct kset subsys;                           //bus内嵌的kset,代表其自身   
  19.     struct kset *drivers_kset;                      
  20.     struct kset *devices_kset;  
  21.     struct klist klist_devices;                   //包含devices链表及其操作函数   
  22.     struct klist klist_drivers;                   //driver链表及其操作函数   
  23.     struct blocking_notifier_head bus_notifier;  
  24.     unsigned int drivers_autoprobe:1;              //匹配成功自动初始化标志   
  25.     struct bus_type *bus;                            
  26. };  

   PCI驱动所使用的结构体 struct pci_driver. struct device_driver.bus_type 都是引用 pci_driver_init 所初始化的

  无论是bus,driver,还是device其本身特征都放在私有成员里,其注册时,都会申请并填充这个结构体,下面具体分析一下bus的注册流程,从bus_register开始:

*   struct bus_type pci_bus_type,而 struct bus_type 引用的 kset 就是前面 1. 函数里面 buses_init 所创建*

     

   bus_register 里面有两动作是

[cpp]

  •    klist_init(&priv->klist_devices,klist_devices_get,klist_devices_put);
  •    klist_init(&priv->klist_drivers,NULL,NULL);
  • 从这里可以看出这里开始初始 bus->p->klist_devices,bus->p->klist_drivers
  1. int bus_register(struct bus_type *bus)  
  2. {  
  3.     int retval;  
  4.     struct bus_type_private *priv;  
  5.     priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);    //进入时bus_type->bus_type_private为NULL   
  6.     if (!priv)                                                      //该函数主要是对其的设置   
  7.         return -ENOMEM;  
  8.     priv->bus = bus;                                                //私有成员的bus回指该bus   
  9.     bus->p = priv;                                                  //初始化bus->p,即其私有属性   
  10.     BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);  
  11.     retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);  //设置该bus的名字,bus是kset的封装   
  12.     if (retval)  
  13.         goto out;  
  14.                                                       //bus_kset即为所有bus的总起始端点   
  15.                                                       //围绕bus内嵌的kset初始化,和kset的初始化时围绕   
  16.     priv->subsys.kobj.kset = bus_kset;                //kobj相似,没有parent时,就会用kset的kobj,此处即是   
  17.     priv->subsys.kobj.ktype = &bus_ktype;                    //属性操作级别统一为bus_ktype   
  18.     priv->drivers_autoprobe = 1;                                    //设置该标志,当有driver注册时,会自动匹配devices   
  19.                                                                     //上的设备并用probe初始化,   
  20.                                                                     //当有device注册时也同样找到  driver并会初始化   
  21.     retval = kset_register(&priv->subsys);                          //注册kset,创建目录结构,以及层次关系   
  22.     if (retval)  
  23.         goto out;  
  24.     retval = bus_create_file(bus, &bus_attr_uevent);                //当前bus目录下生成bus_attr_uevent属性文件   
  25.     if (retval)  
  26.         goto bus_uevent_fail;  
  27.     priv->devices_kset = kset_create_and_add("devices", NULL,       //初始化bus目录下的devices目录,里面级联了该bus下设备,   
  28.                          &priv->subsys.kobj);                    //仍然以kset为原型   
  29.     if (!priv->devices_kset) {  
  30.         retval = -ENOMEM;  
  31.         goto bus_devices_fail;  
  32.     }  
  33.     priv->drivers_kset = kset_create_and_add("drivers", NULL,       //初始化bus目录下的drivers目录,里面级联了该bus下设备的driver   
  34.                          &priv->subsys.kobj);  
  35.     if (!priv->drivers_kset) {  
  36.         retval = -ENOMEM;  
  37.         goto bus_drivers_fail;  
  38.     }  
  39.     klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);  //初始化klist_devices里的操作函数成员   
  40.     klist_init(&priv->klist_drivers, NULL, NULL);                            //klist_drivers里的操作函数置空   
  41.     retval = add_probe_files(bus);                                           //增加bus_attr_drivers_probe和bus_attr_drivers_autoprobe   
  42.     if (retval)                                                              //属性文件   
  43.         goto bus_probe_files_fail;  
  44.     retval = bus_add_attrs(bus);                                             //增加默认的属性文件   
  45.     if (retval)  
  46.         goto bus_attrs_fail;  
  47.     pr_debug("bus: '%s': registered/n", bus->name);  
  48.     return 0;  
  49. bus_attrs_fail:                                                               //以下为错误处理   
  50.     remove_probe_files(bus);  
  51. bus_probe_files_fail:  
  52.     kset_unregister(bus->p->drivers_kset);  
  53. bus_drivers_fail:  
  54.     kset_unregister(bus->p->devices_kset);  
  55. bus_devices_fail:  
  56.     bus_remove_file(bus, &bus_attr_uevent);  
  57. bus_uevent_fail:  
  58.     kset_unregister(&bus->p->subsys);  
  59. out:  
  60.     kfree(bus->p);  
  61.     bus->p = NULL;  
  62.     return retval;  
  63. }  
  1. drivers/gpu/drm/i915/i915_pci.c  -> module_init(i915_init) –>pci_register_driver(&i915_pci_driver)

   由此可见,bus又是kset的封装,bus_register主要完成了其私有成员bus_type_private的初始化,并初始化了其下的两个目录devices和drivers,及其属性文件,bus有个自己的根目录也就是bus有个起始端点,是bus_kset,经过此番的注册,bus目录下将会出现我们注册的bus,并且其下会有device和driver两个子目录,代表它下面的driver和device链表。

   static struct pci_driver i915_pci_driver{…} 这个是显卡驱动的结构体.

二、driver的注册

   上面调用最终会调用到 driver_register(struct device_driver *drv) ; //pci_driver.device_driver

  下面看一下driver是怎么和bus关联起来的,首先看下driver的结构:

本文由金沙官网线上发布于操作系统,转载请注明出处:Linux设备模型之bus,device,driver分析

您可能还会对下面的文章感兴趣: