linux驱动注册过程分析--driver_register(一)
来源:互联网 发布:snmptrap协议端口号 编辑:程序博客网 时间:2024/05/18 05:55
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源代码:
- /**
- * platform_driver_register - register a driver for platform-level devices
- * @drv: platform driver structure
- */
- int platform_driver_register(struct platform_driver *drv)
- {
- drv->driver.bus = &platform_bus_type;
- if (drv->probe)
- drv->driver.probe = platform_drv_probe;
- if (drv->remove)
- drv->driver.remove = platform_drv_remove;
- if (drv->shutdown)
- drv->driver.shutdown = platform_drv_shutdown;
- return driver_register(&drv->driver);
- }
- EXPORT_SYMBOL_GPL(platform_driver_register);
这里我们需要注意,driver的总线类型(bus_type)被初始化为platform_bus_type
- drv->driver.bus = &platform_bus_type;
- struct bus_type platform_bus_type = {
- .name = "platform",
- .dev_attrs = platform_dev_attrs,
- .match = platform_match,
- .uevent = platform_uevent,
- .pm = &platform_dev_pm_ops,
- };
其实也类似,例如在./drivers/i2c/i2c-core.c中有I2C注册函数i2c_register_driver源码(省略部分无关代码)
- int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
- {
- ……
- driver->driver.owner = owner;
- driver->driver.bus = &i2c_bus_type;
- ……
- }
- struct bus_type i2c_bus_type = {
- .name = "i2c",
- .match = i2c_device_match,
- .probe = i2c_device_probe,
- .remove = i2c_device_remove,
- .shutdown = i2c_device_shutdown,
- .pm = &i2c_device_pm_ops,
- };
当总线类型和probe、remove、shutdown等函数注册后,就开始调用driver_register注册对应的驱动了。
driver_register源代码在文件./drivers/base/driver.c中
- /**
- * driver_register - register driver with bus
- * @drv: driver to register
- *
- * We pass off most of the work to the bus_add_driver() call,
- * since most of the things we have to do deal with the bus
- * structures.
- */
- int driver_register(struct device_driver *drv)
- {
- int ret;
- struct device_driver *other;
- BUG_ON(!drv->bus->p);
- if ((drv->bus->probe && drv->probe) ||
- (drv->bus->remove && drv->remove) ||
- (drv->bus->shutdown && drv->shutdown))
- printk(KERN_WARNING "Driver '%s' needs updating - please use "
- "bus_type methods\n", drv->name);
- other = driver_find(drv->name, drv->bus);
- if (other) {
- printk(KERN_ERR "Error: Driver '%s' is already registered, "
- "aborting...\n", drv->name);
- return -EBUSY;
- }
- ret = bus_add_driver(drv);
- if (ret)
- return ret;
- ret = driver_add_groups(drv, drv->groups);
- if (ret) {
- bus_remove_driver(drv);
- return ret;
- }
- kobject_uevent(&drv->p->kobj, KOBJ_ADD);
- return ret;
- }
- EXPORT_SYMBOL_GPL(driver_register);
- int driver_register(struct device_driver *drv)
- |
- |--> driver_find //查找驱动是否已经装载
- |--> bus_add_driver//根据总线类型添加驱动
- |--> driver_add_groups//将驱动添加到对应组中
- |--> kobject_uevent//注册uevent事件
2. driver_find分析
在driver_register中调用driver_find,driver_find名字很通俗易懂,可以简单理解为找“驱动”。由于从linux 2.6版本,内核采用设备驱动模型,所以所谓的“找驱动“还是了解一点设备驱动模型的知识比较好。
在文件./drivers/base/driver.c中有driver_find源码
- /**
- * driver_find - locate driver on a bus by its name.
- * @name: name of the driver.
- * @bus: bus to scan for the driver.
- *
- * Call kset_find_obj() to iterate over list of drivers on
- * a bus to find driver by name. Return driver if found.
- *
- * This routine provides no locking to prevent the driver it returns
- * from being unregistered or unloaded while the caller is using it.
- * The caller is responsible for preventing this.
- */
- struct device_driver *driver_find(const char *name, struct bus_type *bus)
- {
- struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);
- struct driver_private *priv;
- if (k) {
- /* Drop reference added by kset_find_obj() */
- kobject_put(k);
- priv = to_driver(k);
- return priv->driver;
- }
- return NULL;
- }
- 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中定义
- /**
- * struct device_driver - The basic device driver structure
- * @name: Name of the device driver.
- * @bus: The bus which the device of this driver belongs to.
- * @owner: The module owner.
- * @mod_name: Used for built-in modules.
- * @suppress_bind_attrs: Disables bind/unbind via sysfs.
- * @of_match_table: The open firmware table.
- * @acpi_match_table: The ACPI match table.
- * @probe: Called to query the existence of a specific device,
- * whether this driver can work with it, and bind the driver
- * to a specific device.
- * @remove: Called when the device is removed from the system to
- * unbind a device from this driver.
- * @shutdown: Called at shut-down time to quiesce the device.
- * @suspend: Called to put the device to sleep mode. Usually to a
- * low power state.
- * @resume: Called to bring a device from sleep mode.
- * @groups: Default attributes that get created by the driver core
- * automatically.
- * @pm: Power management operations of the device which matched
- * this driver.
- * @p: Driver core's private data, no one other than the driver
- * core can touch this.
- *
- * The device driver-model tracks all of the drivers known to the system.
- * The main reason for this tracking is to enable the driver core to match
- * up drivers with new devices. Once drivers are known objects within the
- * system, however, a number of other things become possible. Device drivers
- * can export information and configuration variables that are independent
- * of any specific device.
- */
- struct device_driver {
- const char *name;
- struct bus_type *bus;
- struct module *owner;
- const char *mod_name; /* used for built-in modules */
- bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
- const struct of_device_id *of_match_table;
- const struct acpi_device_id *acpi_match_table;
- int (*probe) (struct device *dev);
- int (*remove) (struct device *dev);
- void (*shutdown) (struct device *dev);
- int (*suspend) (struct device *dev, pm_message_t state);
- int (*resume) (struct device *dev);
- const struct attribute_group **groups;
- const struct dev_pm_ops *pm;
- struct driver_private *p;
- };
/*******************************************************************************************************************************
下面涉及到设备驱动,这里只是简单提一下,一时看不懂很正常。如果有时间还想把设备驱动专门写几篇博文
*******************************************************************************************************************************/
那么问题来了,driver_find到底是如何通过name在bus中寻找驱动呢。其实就是通过下面的代码实现的
- struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);
所以实现了基本的面向对象管理机制,是构成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函数的源码
- * kset_find_obj - search for object in kset.
- * @kset: kset we're looking in.
- * @name: object's name.
- *
- * Lock kset via @kset->subsys, and iterate over @kset->list,
- * looking for a matching kobject. If matching object is found
- * take a reference and return the object.
- */
- struct kobject *kset_find_obj(struct kset *kset, const char *name)
- {
- struct kobject *k;
- struct kobject *ret = NULL;
- spin_lock(&kset->list_lock);
- list_for_each_entry(k, &kset->list, entry) {
- if (kobject_name(k) && !strcmp(kobject_name(k), name)) {
- ret = kobject_get_unless_zero(k);
- break;
- }
- }
- spin_unlock(&kset->list_lock);
- return ret;
- }
总结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的作用,
- other = driver_find(drv->name, drv->bus);
- if (other) {
- printk(KERN_ERR "Error: Driver '%s' is already registered, "
- "aborting...\n", drv->name);
- return -EBUSY;
- }
所以driver_register调用driver_find是为了检验驱动是否已经被注册,防止重复注册。
- linux驱动注册过程分析--driver_register(一)
- linux驱动篇之 driver_register 过程分析(一)
- linux驱动篇之 driver_register 过程分析(一)
- linux驱动篇之 driver_register 过程分析(一)
- linux驱动篇之 driver_register 过程分析(二)bus_add_driver
- linux驱动篇之 driver_register 过程分析(二)bus_add_driver
- linux驱动篇之 driver_register 过程分析(二)bus_add_driver
- linux I2C 驱动之----i2c驱动的注册过程(i2c_register_driver->driver_register(&driver->driver)->driver_find)
- linux I2C 驱动之----i2c驱动的注册过程(i2c_register_driver->driver_register(&driver->driver)->driver_find)
- linux I2C 驱动之----i2c驱动的注册过程(i2c_register_driver->driver_register(&driver->driver)->driver_find)
- linux I2C 驱动之----i2c驱动的注册过程(i2c_register_driver->driver_register(&driver->driver)->driver_find)
- 浅析linux 2.6.23驱动注册函数driver_register()
- 浅析linux 2.6.23驱动注册函数driver_register()
- 浅析linux 2.6.23驱动注册函数driver_register()
- 浅析linux 2.6.23驱动注册函数driver_register()
- 浅析linux 2.6.23驱动注册函数driver_register()
- Linux 驱动注册(driver_register)流程probe方法的选择
- linux IDE驱动分析之Ide_driver的注册(一)
- mybatis错误: Invalid bound statement (not found) 怎么解决
- 工具类【Http请求】
- JavaScript从url中获取参数 / js get url parameter
- python学习4——元组
- python元组,集合
- linux驱动注册过程分析--driver_register(一)
- Linux命令一:sudo
- H5 中监听页面滚动事件,判断滚动方向的方法
- Memcached使用
- request对象JSP学习
- 看代码说出文本“Sausage”的输出颜色
- 关于angular路由传值(一个或多个)问题
- [Object-c]_[初级]_[数组NSArray过滤NSPredicate的简单介绍]
- opencv-python 应用滑动条改变canny边缘检测的阈值