设备与驱动的匹配
来源:互联网 发布:淘宝里抢的红包怎么用 编辑:程序博客网 时间:2024/05/24 15:37
看了许久,今天终于是了解了驱动及设备的注册及彼此的绑定过程,详细内容请见下文,如有不对地方请指正,多谢了!
一、
先看一下这个
- int __init devices_init(void)
- {
- devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
- if (!devices_kset)
- return -ENOMEM;
- dev_kobj = kobject_create_and_add("dev", NULL);
- if (!dev_kobj)
- goto dev_kobj_err;
- sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
- if (!sysfs_dev_block_kobj)
- goto block_kobj_err;
- sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
- if (!sysfs_dev_char_kobj)
- goto char_kobj_err;
- return 0;
- char_kobj_err:
- kobject_put(sysfs_dev_block_kobj);
- block_kobj_err:
- kobject_put(dev_kobj);
- dev_kobj_err:
- kset_unregister(devices_kset);
- return -ENOMEM;
- }
再看
int device_register(struct device *dev)
{
device_initialize(dev);
return device_add(dev);
}
- void device_initialize(struct device *dev)
- {
- dev->kobj.kset = devices_kset;
- kobject_init(&dev->kobj, &device_ktype);
- INIT_LIST_HEAD(&dev->dma_pools);
- init_MUTEX(&dev->sem);
- spin_lock_init(&dev->devres_lock);
- INIT_LIST_HEAD(&dev->devres_head);
- device_init_wakeup(dev, 0);
- device_pm_init(dev);
- set_dev_node(dev, -1);
- }
- int device_add(struct device *dev)
- {
- struct device *parent = NULL;
- struct class_interface *class_intf;
- int error = -EINVAL;
- dev = get_device(dev);
- if (!dev)
- goto done;
- if (!dev->p) {
- error = device_private_init(dev);
- if (error)
- goto done;
- }
- /*
- * for statically allocated devices, which should all be converted
- * some day, we need to initialize the name. We prevent reading back
- * the name, and force the use of dev_name()
- */
- if (dev->init_name) {
- dev_set_name(dev, "%s", dev->init_name);
- dev->init_name = NULL;
- }
- if (!dev_name(dev))
- goto name_error;
- pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
- parent = get_device(dev->parent);
- setup_parent(dev, parent);
- /* use parent numa_node */
- if (parent)
- set_dev_node(dev, dev_to_node(parent));
- /* first, register with generic layer. */
- /* we require the name to be set before, and pass NULL */
- error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
- if (error)
- goto Error;
- /* notify platform of device entry */
- if (platform_notify)
- platform_notify(dev);
- error = device_create_file(dev, &uevent_attr);
- if (error)
- goto attrError;
- if (MAJOR(dev->devt)) {
- error = device_create_file(dev, &devt_attr);
- if (error)
- goto ueventattrError;
- error = device_create_sys_dev_entry(dev);
- if (error)
- goto devtattrError;
- devtmpfs_create_node(dev);
- }
- error = device_add_class_symlinks(dev);
- if (error)
- goto SymlinkError;
- error = device_add_attrs(dev);
- if (error)
- goto AttrsError;
- error = bus_add_device(dev);
- if (error)
- goto BusError;
- error = dpm_sysfs_add(dev);
- if (error)
- goto DPMError;
- device_pm_add(dev);
- /* Notify clients of device addition. This call must come
- * after dpm_sysf_add() and before kobject_uevent().
- */
- if (dev->bus)
- blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
- BUS_NOTIFY_ADD_DEVICE, dev);
- kobject_uevent(&dev->kobj, KOBJ_ADD);
- bus_probe_device(dev); //设备与驱动的探测绑定再次完成
- if (parent)
- klist_add_tail(&dev->p->knode_parent,
- &parent->p->klist_children);
- if (dev->class) {
- mutex_lock(&dev->class->p->class_mutex);
- /* tie the class to the device */
- klist_add_tail(&dev->knode_class,
- &dev->class->p->class_devices);
- /* notify any interfaces that the device is here */
- list_for_each_entry(class_intf,
- &dev->class->p->class_interfaces, node)
- if (class_intf->add_dev)
- class_intf->add_dev(dev, class_intf);
- mutex_unlock(&dev->class->p->class_mutex);
- }
- done:
- put_device(dev);
- return error;
- DPMError:
- bus_remove_device(dev);
- BusError:
- device_remove_attrs(dev);
- AttrsError:
- device_remove_class_symlinks(dev);
- SymlinkError:
- if (MAJOR(dev->devt))
- device_remove_sys_dev_entry(dev);
- devtattrError:
- if (MAJOR(dev->devt))
- device_remove_file(dev, &devt_attr);
- ueventattrError:
- device_remove_file(dev, &uevent_attr);
- attrError:
- kobject_uevent(&dev->kobj, KOBJ_REMOVE);
- kobject_del(&dev->kobj);
- Error:
- cleanup_device_parent(dev);
- if (parent)
- put_device(parent);
- name_error:
- kfree(dev->p);
- dev->p = NULL;
- goto done;
- }
- 此函数的具体功能就不详细说了,主要看bus_probe_device(dev);
- void bus_probe_device(struct device *dev)
- {
- struct bus_type *bus = dev->bus;
- int ret;
- if (bus && bus->p->drivers_autoprobe) {
- ret = device_attach(dev);
- WARN_ON(ret < 0);
- }
- }
这里如果设备的总线存在,且驱动为自动探测的话调用device_attach(dev);
- int device_attach(struct device *dev)
- {
- int ret = 0;
- down(&dev->sem);
- if (dev->driver) { //这里如果设备的驱动定义的话,直接绑定设备的驱动节点到驱动的设备链表上,
- ret = device_bind_driver(dev); //此函数源码就不贴了
- if (ret == 0)
- ret = 1;
- else {
- dev->driver = NULL;
- ret = 0;
- }
- } else { //这里如果设备没有驱动的话,到遍历总线上的驱动,最后调用__device_attach
- pm_runtime_get_noresume(dev);
- ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); //这里忘了一点,如果此时还总线上还没有驱动的话,就不去变量总线,完成匹配了,带在驱动里完成设备和驱动的匹配工作
- pm_runtime_put_sync(dev);
- }
- up(&dev->sem);
- return ret;
- }
__device_attach功能见下分分析
- static int __device_attach(struct device_driver *drv, void *data)
- {
- struct device *dev = data;
- if (!driver_match_device(drv, dev)) //这里首先进行match,这里的match调用的是bus里的match
- return 0;
- return driver_probe_device(drv, dev);
- }
接下来再看driver_probe_device(drv, dev);
- int driver_probe_device(struct device_driver *drv, struct device *dev)
- {
- int ret = 0;
- if (!device_is_registered(dev))
- return -ENODEV;
- pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
- drv->bus->name, __func__, dev_name(dev), drv->name);
- pm_runtime_get_noresume(dev);
- pm_runtime_barrier(dev);
- ret = really_probe(dev, drv);
- pm_runtime_put_sync(dev);
- return ret;
- }
- static int really_probe(struct device *dev, struct device_driver *drv)
- {
- int ret = 0;
- atomic_inc(&probe_count);
- pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
- drv->bus->name, __func__, drv->name, dev_name(dev));
- WARN_ON(!list_empty(&dev->devres_head));
- dev->driver = drv;
- if (driver_sysfs_add(dev)) {
- printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
- __func__, dev_name(dev));
- goto probe_failed;
- }
- if (dev->bus->probe) { //此处大家应该很重视吧,总线里的probe一般都为空,所以此处没用到,就此跳过
- ret = dev->bus->probe(dev);
- if (ret)
- goto probe_failed;
- } else if (drv->probe) { //这里就是你写的驱动里的probe了,在这里才开始执行,呵呵,看到此处有何感慨!
- ret = drv->probe(dev);
- if (ret)
- goto probe_failed;
- }
- driver_bound(dev); //这里完成设备的驱动节点绑定到驱动的设备链表上,至此完成了设备和驱动的绑定,同时也完成了设备驱动里的东东,注意在加载驱动的时候
- bus_add_drver()实现的功能基本和这里的一样,下篇文章将分析
- ret = 1;
- pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
- drv->bus->name, __func__, dev_name(dev), drv->name);
- goto done;
- probe_failed:
- devres_release_all(dev);
- driver_sysfs_remove(dev);
- dev->driver = NULL;
- if (ret != -ENODEV && ret != -ENXIO) {
- /* driver matched but the probe failed */
- printk(KERN_WARNING
- "%s: probe of %s failed with error %d\n",
- drv->name, dev_name(dev), ret);
- }
- /*
- * Ignore errors returned by ->probe so that the next driver can try
- * its luck.
- */
- ret = 0;
- done:
- atomic_dec(&probe_count);
- wake_up(&probe_waitqueue);
- return ret;
- }
相信大家看到此处,定会万分惊喜终于找的了probe函数在何处执行,也知道了设备如何和驱动配对,绑定的,哦,不对,还没贴出绑定的函数了,如下
- static void driver_bound(struct device *dev)
- {
- if (klist_node_attached(&dev->p->knode_driver)) {
- printk(KERN_WARNING "%s: device %s already bound\n",
- __func__, kobject_name(&dev->kobj));
- return;
- }
- pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),
- __func__, dev->driver->name);
- if (dev->bus)
- blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
- BUS_NOTIFY_BOUND_DRIVER, dev);
- klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
- }
- 设备与驱动的匹配
- 驱动与设备的匹配
- 驱动与设备的匹配
- 设备与驱动的匹配
- linux platform 设备与驱动的匹配
- i2c设备与驱动匹配过程
- i2c设备与驱动匹配过程
- i2c设备与驱动匹配过程
- 浅谈设备、驱动的加载和匹配
- 浅谈设备、驱动的加载和匹配
- 浅谈设备、驱动的加载和匹配
- 设备驱动--中断开关执行的匹配
- 设备驱动--中断开关执行的匹配
- Linux设备和驱动的匹配过程
- Linux SPI 子系统驱动笔记之Linux spi设备驱动与SPI控制器驱动的匹配问题
- 设备与驱动的关系以及设备号、设备文件
- 设备与驱动的关系以及设备号、设备文件
- 浅谈设备、驱动的加载和匹配【转】
- grep与egrep使用
- mx.controls::AdvancedDataGrid/findHeaderRenderer()......AdvancedDataGrid.as:5861
- oracle简单学习总结(一)——sql
- 模板测试
- SVN插件在Aptana Studio3上的安装
- 设备与驱动的匹配
- hdu 1695
- 程序员的艺术:排序算法舞蹈
- hdu 4046(树状数组)2011年预选网络赛
- vbo3
- android activity初步
- 获取本机号码及sim卡信息
- MYSQL常用命令
- ant打包编译部署笔记2