linux驱动篇之 driver_register 过程分析(一)

来源:互联网 发布:提现接口网站 php 编辑:程序博客网 时间:2024/06/05 03:10

linux驱动注册过程分析--driver_register(一)

个人笔记,欢迎转载,请注明出处,共同分享 共同进步 

http://blog.csdn.net/richard_liujh/article/details/45825333

kernel版本3.10.14

driver_register顾名思义,是驱动程序的注册。但是很少是由我们写的驱动直接调用的,例如framebuffer中调用platform_driver_register,i2c中调用i2c_add_driver等等函数注册对应的驱动程序。虽然我们并没有直接调用driver_register,但是最终都是通过driver_register帮我们完成了驱动程序的注册。所以,了解driver_register的注册过程,对我们理解linux的设备驱动有很到的帮助。


我们借助常用的platform_driver_register开始分析driver_register的调用过程。

1.初始化总线类型(bus_type),注册probe等相关函数

在文件./drivers/base/platform.c中有platform_driver_register源代码:

[cpp] view plain copy
 print?
  1. /** 
  2.  * platform_driver_register - register a driver for platform-level devices 
  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.   
  15.     return driver_register(&drv->driver);  
  16. }  
  17. EXPORT_SYMBOL_GPL(platform_driver_register);  
上面注册了相应的probe remove shutdown 等函数后,开始调用driver_register

这里我们需要注意,driver的总线类型(bus_type)被初始化为platform_bus_type

[cpp] view plain copy
 print?
  1. drv->driver.bus = &platform_bus_type;  
其中platform_bus_type也在文件./drivers/base/platform.c中有具体定义
[cpp] view plain copy
 print?
  1. struct bus_type platform_bus_type = {  
  2.     .name       = "platform",  
  3.     .dev_attrs  = platform_dev_attrs,  
  4.     .match      = platform_match,  
  5.     .uevent     = platform_uevent,  
  6.     .pm     = &platform_dev_pm_ops,  
  7. };  
我们是已platform为例讲解,所以注册驱动的总线类型是platform的。如果是I2C总线呢?

其实也类似,例如在./drivers/i2c/i2c-core.c中有I2C注册函数i2c_register_driver源码(省略部分无关代码)

[cpp] view plain copy
 print?
  1. int i2c_register_driver(struct module *owner, struct i2c_driver *driver)  
  2. {  
  3.     ……  
  4.     driver->driver.owner = owner;  
  5.     driver->driver.bus = &i2c_bus_type;  
  6.      ……  
  7. }  
res = driver_register(&driver->driver);……return 0;}EXPORT_SYMBOL(i2c_register_driver);

所以,如果注册的是i2c驱动,那么总线类型初始化为i2c_bus_type,也可以在文件./drivers/i2c/i2c-core.c中看到其定义

[cpp] view plain copy
 print?
  1. struct bus_type i2c_bus_type = {  
  2.     .name       = "i2c",  
  3.     .match      = i2c_device_match,  
  4.     .probe      = i2c_device_probe,  
  5.     .remove     = i2c_device_remove,  
  6.     .shutdown   = i2c_device_shutdown,  
  7.     .pm     = &i2c_device_pm_ops,  
  8. };  

当总线类型和probe、remove、shutdown等函数注册后,就开始调用driver_register注册对应的驱动了。

driver_register源代码在文件./drivers/base/driver.c

[cpp] view plain copy
 print?
  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.         printk(KERN_ERR "Error: Driver '%s' is already registered, "  
  25.             "aborting...\n", drv->name);  
  26.         return -EBUSY;  
  27.     }  
  28.   
  29.     ret = bus_add_driver(drv);  
  30.     if (ret)  
  31.         return ret;  
  32.     ret = driver_add_groups(drv, drv->groups);  
  33.     if (ret) {  
  34.         bus_remove_driver(drv);  
  35.         return ret;  
  36.     }  
  37.     kobject_uevent(&drv->p->kobj, KOBJ_ADD);  
  38.   
  39.     return ret;  
  40. }  
  41. EXPORT_SYMBOL_GPL(driver_register);  
为了更好阅读上面的代码,我将其化简如下

[cpp] view plain copy
 print?
  1. int driver_register(struct device_driver *drv)  
  2.     |  
  3.     |--> driver_find //查找驱动是否已经装载  
  4.     |--> bus_add_driver//根据总线类型添加驱动  
  5.     |--> driver_add_groups//将驱动添加到对应组中  
  6.     |--> kobject_uevent//注册uevent事件  


2. driver_find分析

在driver_register中调用driver_find,driver_find名字很通俗易懂,可以简单理解为找“驱动”。由于从linux 2.6版本,内核采用设备驱动模型,所以所谓的“找驱动“还是了解一点设备驱动模型的知识比较好。

在文件./drivers/base/driver.c中有driver_find源码

[cpp] view plain copy
 print?
  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.  * This routine provides no locking to prevent the driver it returns 
  10.  * from being unregistered or unloaded while the caller is using it. 
  11.  * The caller is responsible for preventing this. 
  12.  */  
  13. struct device_driver *driver_find(const char *name, struct bus_type *bus)  
  14. {  
  15.     struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);  
  16.     struct driver_private *priv;  
  17.   
  18.     if (k) {  
  19.         /* Drop reference added by kset_find_obj() */  
  20.         kobject_put(k);  
  21.         priv = to_driver(k);  
  22.         return priv->driver;  
  23.     }  
  24.     return NULL;  
  25. }  
  26. EXPORT_SYMBOL_GPL(driver_find);  

我们注意通过注释和代码知道,driver_find 通过我们给定的name在某bus中寻找驱动。这个比较好理解,就像上学的时候,老师XX知道某个学生的名字(name),然后去他所在的班级(bus)找这个学生。如果找到过(一般没好事TT),就把学生叫出来好好教育一番....。那么driver_find找了所谓的驱动会怎样呢?我们观察driver_find的返回值,你会发现,这里返回的是指针,也就是说driver_find是一个指针函数喽。指针的类型是struct device_driver类型的。

struct device_driver 在文件 include/linux/device.h中定义

[cpp] view plain copy
 print?
  1. /** 
  2.  * struct device_driver - The basic device driver structure 
  3.  * @name:   Name of the device driver. 
  4.  * @bus:    The bus which the device of this driver belongs to. 
  5.  * @owner:  The module owner. 
  6.  * @mod_name:   Used for built-in modules. 
  7.  * @suppress_bind_attrs: Disables bind/unbind via sysfs. 
  8.  * @of_match_table: The open firmware table. 
  9.  * @acpi_match_table: The ACPI match table. 
  10.  * @probe:  Called to query the existence of a specific device, 
  11.  *      whether this driver can work with it, and bind the driver 
  12.  *      to a specific device. 
  13.  * @remove: Called when the device is removed from the system to 
  14.  *      unbind a device from this driver. 
  15.  * @shutdown:   Called at shut-down time to quiesce the device. 
  16.  * @suspend:    Called to put the device to sleep mode. Usually to a 
  17.  *      low power state. 
  18.  * @resume: Called to bring a device from sleep mode. 
  19.  * @groups: Default attributes that get created by the driver core 
  20.  *      automatically. 
  21.  * @pm:     Power management operations of the device which matched 
  22.  *      this driver. 
  23.  * @p:      Driver core's private data, no one other than the driver 
  24.  *      core can touch this. 
  25.  * 
  26.  * The device driver-model tracks all of the drivers known to the system. 
  27.  * The main reason for this tracking is to enable the driver core to match 
  28.  * up drivers with new devices. Once drivers are known objects within the 
  29.  * system, however, a number of other things become possible. Device drivers 
  30.  * can export information and configuration variables that are independent 
  31.  * of any specific device. 
  32.  */  
  33. struct device_driver {  
  34.     const char      *name;  
  35.     struct bus_type     *bus;  
  36.   
  37.     struct module       *owner;  
  38.     const char      *mod_name;  /* used for built-in modules */  
  39.   
  40.     bool suppress_bind_attrs;   /* disables bind/unbind via sysfs */  
  41.   
  42.     const struct of_device_id   *of_match_table;  
  43.     const struct acpi_device_id *acpi_match_table;  
  44.   
  45.     int (*probe) (struct device *dev);  
  46.     int (*remove) (struct device *dev);  
  47.     void (*shutdown) (struct device *dev);  
  48.     int (*suspend) (struct device *dev, pm_message_t state);  
  49.     int (*resume) (struct device *dev);  
  50.     const struct attribute_group **groups;  
  51.   
  52.     const struct dev_pm_ops *pm;  
  53.   
  54.     struct driver_private *p;  
  55. };  
这个结构体里面包含了设备驱动的重要信息,例如名字(name)、总线类型(bus)、所述模块(owner)和一些用于回调的函数指针(probe,remove,suspend...)。总而言之,得到此指针就像得到了驱动,就像得民心者得天下闭嘴....

/*******************************************************************************************************************************

下面涉及到设备驱动,这里只是简单提一下,一时看不懂很正常。如果有时间还想把设备驱动专门写几篇博文

*******************************************************************************************************************************/

那么问题来了,driver_find到底是如何通过name在bus中寻找驱动呢。其实就是通过下面的代码实现的

[cpp] view plain copy
 print?
  1. struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);  
其中kset_find_obj貌似很高端的样子,这又得谈到linux的设备模型了。linux2.6为了更好的管理,加入了一系列”面向对象“概念,说简单点就是更好的管理资源。例如一些资源占用了内存空间,但是却没有人去使用,这种资源其实是可以从内存中被释放的。

所以实现了基本的面向对象管理机制,是构成Linux2.6设备模型的核心结构。它与sysfs文件系统紧密相连,在内核中注册的每个kobject对象对应sysfs文件系统中的一个目录。类似于C++中的基类,Kobject常被嵌入于其他类型(即:容器)中。如bus,devices,drivers都是典型的容器。这些容器通过kobject连接起来,形成了一个树状结构。Bus:在内核中注册的每条总线在该目录下对应一个子目录,如: i2c platform spi ide pci scsi等等 其中每个总线目录内又包含两个子目录:devices和drivers ,devices目录包含了在整个系统中发现的属于该总线类型的设备,drivers目录包含了注册到该总线。其实说这么多,就是想让读者了解一点,我们的driver和bus类型、Kobject,kset等有莫大的关联。至于具体的原理,大家可以自己找一些设备驱动的资料看看。这里就不详细说明了。

 在文件./lib/kobject.c  文件中有kset_find_obj函数的源码

[cpp] view plain copy
 print?
  1.  * kset_find_obj - search for object in kset.  
  2.  * @kset: kset we're looking in.  
  3.  * @name: object's name.  
  4.  *  
  5.  * Lock kset via @kset->subsys, and iterate over @kset->list,  
  6.  * looking for a matching kobject. If matching object is found  
  7.  * take a reference and return the object.  
  8.  */  
  9. struct kobject *kset_find_obj(struct kset *kset, const char *name)  
  10. {  
  11.     struct kobject *k;  
  12.     struct kobject *ret = NULL;  
  13.   
  14.     spin_lock(&kset->list_lock);  
  15.   
  16.     list_for_each_entry(k, &kset->list, entry) {  
  17.         if (kobject_name(k) && !strcmp(kobject_name(k), name)) {  
  18.             ret = kobject_get_unless_zero(k);  
  19.             break;  
  20.         }  
  21.     }  
  22.   
  23.     spin_unlock(&kset->list_lock);  
  24.     return ret;  
  25. }  
这里面涉及到了一个很常用很的宏函数list_for_each_entry,不知道的童鞋可以点击这里。kset_find_obj通过循环操作,,根据我们给的名字name在指定的bus中循环对比,查看是否有相同的名字name(这个name存放在kobj中)。其实这就是一个循环链表的遍历过程,kset和kobj里面都有链表指针next和prev。kset是a set of kobjects,kobj是kernel object,所以kset是一系列的kobj的组合。其中kset,内核中的解释是struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.那么这里有个重要的belonging to啦,也就是现在分词做定语尴尬。哈哈,belonging to a specific subsystem说的是kset(一系列kobjs)属于特定的子系统。所以,初学者我们可以这么思考,一个kobj应该是属于某个kset(或者说kobj在kset循环链表中),kset又是属于某个subsystem的。所以,我们要通过name去寻找驱动,就必须要知道bustype,然后得到kset,最后得到kobj才能去对比name是否相同。这时我们回头看看调用driver_find(drv->name, drv->bus);时,不就给了drv->bus,然后通过bus->p->drivers_kset得到了kset。

总结driver_find过程如下:

1. driver_find,拿到了drv->name和drv->bus开始找驱动

2. kset_find_obj 通过driver_find传递的bus->p->drivers_kset,利用list_for_each_entry遍历kset循环链表。(kset结构体中有循环链表指针next和prev)

3. 遍历循环链表中每一个kobj中的成员变量name

4. 通过strcmp(kobject_name(k), name)比较drv->name 和kobj中的name,如果有相同则表示查找成功

5. return :如果找到,则返回device_driver的指针,如果没有找到则返回了NULL。

为了能更好的说明driver_find,我用下面的图示意一下。



通过下面driver_register的代码可以看出调用driver_find的作用,

[cpp] view plain copy
 print?
  1. other = driver_find(drv->name, drv->bus);  
  2. if (other) {  
  3.     printk(KERN_ERR "Error: Driver '%s' is already registered, "  
  4.         "aborting...\n", drv->name);  
  5.     return -EBUSY;  
  6. }  
通过判断driver_find的返回值other,如果if(other)条件成立,说明other不是NULL,也就是说driver_find查找成功。但driver_register是注册驱动程序,如果驱动已经注册过,就不需要再次注册了。如果已经注册,那么直接return -EBUSY;后面的操作就不需要进行了。

所以driver_register调用driver_find是为了检验驱动是否已经被注册,防止重复注册。

阅读全文
0 0
原创粉丝点击