驱动加载到I2C总线,如何运行到probe
来源:互联网 发布:新网域名转出申请书 编辑:程序博客网 时间:2024/06/06 07:47
为了简短文章长度,一些检查和调试信息被删除
1. 在xxx_init()中会调用i2c_add_driver()函数
static int __init ltr559_init(void){ return i2c_add_driver(<r_ps_driver);//ltr_ps_driver是一个struct i2c_driver} static void __exit ltr559_exit(void){ i2c_del_driver(<r_ps_driver); }module_init(ltr559_init);module_exit(ltr559_exit);
2. i2c_add_driver
是一个宏命令,调用 i2c_register_driver
/************************* include/linux/i2c.h *******************************/#define i2c_add_driver(driver) \ i2c_register_driver(THIS_MODULE, driver)
3. i2c_register_driver
在一些 i2c_adapter 相关总线实例, 一个 i2c_driver 可以被一个或多个 i2c_client 设备节点使用去访问 i2c_slave_chip
该函数
/********************** kernel/drivers/i2c/i2c_core.c ************************/int i2c_register_driver(struct module *owner, struct i2c_driver *driver){int res;/*在驱动模块初始化完成后才可以注册 */if (unlikely(WARN_ON(!i2c_bus_type.p)))return -EAGAIN;/* 添加该驱动到i2c驱动链表上 */driver->driver.owner = owner; driver->driver.bus = &i2c_bus_type;/* 当注册完成,驱动代码将调用probe()去匹配设备 */res = driver_register(&driver->driver);INIT_LIST_HEAD(&driver->clients);i2c_for_each_dev(driver, __process_new_driver);return 0;}
4. driver_register
主要的工作还是由 bus_add_driver 来操作
/*************************** kernel/driver/base/driver.c **************************/int driver_register(struct device_driver *drv){int ret;struct device_driver *other;BUG_ON(!drv->bus->p);other = driver_find(drv->name, drv->bus);//通过driver_name在bus上查找该driver,正常返回0ret = bus_add_driver(drv); //主要ret = driver_add_groups(drv, drv->groups);if (ret) {bus_remove_driver(drv);return ret;}kobject_uevent(&drv->p->kobj, KOBJ_ADD);return ret;}
5. bus_add_driver
/**************** kernel/driver/base/bus.c **********************************/int bus_add_driver(struct device_driver *drv){ struct bus_type *bus; struct driver_private *priv; int error = 0; bus = bus_get(drv->bus); priv = kzalloc(sizeof(*priv), GFP_KERNEL); klist_init(&priv->klist_devices, NULL, NULL); priv->driver = drv; drv->p = priv; priv->kobj.kset = bus->p->drivers_kset; error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, "%s", drv->name); klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); if (drv->bus->p->drivers_autoprobe) { error = driver_attach(drv); //尝试绑定 } module_add_driver(drv->owner, drv); error = driver_create_file(drv, &driver_attr_uevent); //为驱动创建文件,继续调用sysfs_create_file() error = driver_add_attrs(bus, drv); if (!drv->suppress_bind_attrs) { error = add_bind_files(drv); } return 0;}
6. driver_attach
/** * driver_attach - try to bind driver to devices. * @drv: driver. * * Walk the list of devices that the bus has on it and try to * match the driver with each one. If driver_probe_device() * returns 0 and the @dev->driver is set, we've found a * compatible pair. */int driver_attach(struct device_driver *drv){return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);}
7. bus_for_each_dev
参数 fn 就是__driver_attach()函数
/** * bus_for_each_dev - device iterator. * @bus: bus type. * @start: device to start iterating from. * @data: data for the callback. * @fn: function to be called for each device. */int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, int (*fn)(struct device *, void *)){struct klist_iter i;struct device *dev;int error = 0;if (!bus || !bus->p)return -EINVAL;klist_iter_init_node(&bus->p->klist_devices, &i, (start ? &start->p->knode_bus : NULL));while ((dev = next_device(&i)) && !error)error = fn(dev, data);klist_iter_exit(&i);return error;}
8. __driver_attach
static int __driver_attach(struct device *dev, void *data){struct device_driver *drv = data;if (!driver_match_device(drv, dev))return 0;if (dev->parent)/* 如果是被usb接口调用,父设备也要上锁*/device_lock(dev->parent);device_lock(dev);if (!dev->driver)driver_probe_device(drv, dev); //device_unlock(dev);if (dev->parent)device_unlock(dev->parent);return 0;}
9. driver_probe_device
如果设备没有注册,则该函数返回 -ENODEV , probe 成功 返回 1 ,失败 返回 0 。该函数被调用时,设备一定要上锁
/********************** kernel/drivers/base/dd.c ********************************* * driver_probe_device - attempt to bind device & driver together * @drv: driver to bind a device to * @dev: device to try to bind to the driver */int driver_probe_device(struct device_driver *drv, struct device *dev){int ret = 0;if (!device_is_registered(dev)) //判断设备是否注册return -ENODEV;pm_runtime_barrier(dev); ret = really_probe(dev, drv);pm_request_idle(dev);return ret;}
10. really_probe
/********************** kernel/drivers/base/dd.c *********************************/static int really_probe(struct device *dev, struct device_driver *drv){int ret = 0;atomic_inc(&probe_count);WARN_ON(!list_empty(&dev->devres_head));dev->driver = drv;ret = pinctrl_bind_pins(dev);if (ret)goto probe_failed;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) {ret = dev->bus->probe(dev);if (ret)goto probe_failed;} else if (drv->probe) {ret = drv->probe(dev); //这里才是正在调用驱动中实现的probe函数if (ret)goto probe_failed;}driver_bound(dev);ret = 1;goto done;probe_failed:devres_release_all(dev);driver_sysfs_remove(dev);dev->driver = NULL;dev_set_drvdata(dev, NULL);if (ret == -EPROBE_DEFER) {/* Driver requested deferred probing */dev_info(dev, "Driver %s requests probe deferral\n", drv->name);driver_deferred_probe_add(dev);} else 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);} else {pr_debug("%s: probe of %s rejects match %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;}
0 0
- 驱动加载到I2C总线,如何运行到probe
- i2c驱动从注册到probe被调用
- linux-i2c驱动 之 i2c设备层的注册过程probe函数如何被调用分析
- I2c总线驱动
- I2C总线驱动
- Linux I2C 总线驱动
- linux i2c总线驱动
- I2C总线驱动代码
- I2C总线驱动
- kernel I2C总线驱动
- 浅析I2C总线驱动
- 如何加载数据库驱动到JBuilder的驱动列表
- 从USB设备插上到驱动probe调用流程分析
- 从USB设备插上到驱动probe调用流程分析
- 从USB设备插上到驱动probe调用流程分析
- 从USB设备插上到驱动probe调用流程分析
- 平台rtc驱动最后的疑惑解决driver->probe到平台->probe
- i2c设备驱动probe函数中platform_data
- 【一步一步的积累】Synthetic Minority Over-sampling TEchnique
- ESB 案例解析和项目实施经验分享
- iOS开发多线程篇—GCD介绍
- laravel5学习笔记(二)
- bash参考手册之七(作业控制)
- 驱动加载到I2C总线,如何运行到probe
- iOS 开发常用开源库,提升开发效率
- android简单实现从网络下载文件到手机sd卡
- Flask RESTful Web服务的开发套路总结
- secureCRT解决中文乱码
- 转化为object
- jquery 判断当前是什么系统
- java执行cmd命令,返回结果中文乱码问题解决
- leetcode[8]:String to Integer (atoi)