linux powerpc i2c驱动 之 i2c设备层的注册过程

Linuxi2c驱动的加载过程,分为i2c设备层、i2c adapter层与i2c核心层

i2c设备驱动层也就是我们为特定i2c设备编写的驱动,下面是我自己理解的i2c驱动的注册过程

在我们写的i2c设备驱动中,我们会调用i2c_add_driver()开始i2c设备驱动的注册,该函数调用i2c_register_driver完成所有注册操作

 

 

[plain] view plaincopyprint?
  1. static inline int i2c_add_driver(struct i2c_driver *driver)  
  2. {  
  3. return i2c_register_driver(THIS_MODULE, driver);  
  4. }  

i2c_register_driver会调用driver_register() 来将设备驱动添加到总线的设备驱动链表中

[plain] view plaincopyprint?
  1. int i2c_register_driver(struct module *owner, struct i2c_driver *driver)  
  2. {  
  3. int res;  
  4. /* Can't register until after driver model init */  
  5. if (unlikely(WARN_ON(!i2c_bus_type.p)))  
  6. return -EAGAIN;  
  7. driver->driver.owner = owner;  
  8. driver->driver.bus = &i2c_bus_type;  
  9. /* When registration returns, the driver core  
  10.  * will have called probe() for all matching-but-unbound devices.  
  11.  */  
  12. res = <strong>driver_register</strong>(&driver->driver);  
  13. if (res)  
  14. return res;  
  15. pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);  
  16. INIT_LIST_HEAD(&driver->clients);  
  17. /* Walk the adapters that are already present */  
  18. mutex_lock(&core_lock);  
  19. bus_for_each_dev(&i2c_bus_type, NULL, driver, __attach_adapter);  
  20. mutex_unlock(&core_lock);  
  21. return 0;  
  22. }  


driver_register,通过driver_find来判断驱动是否已经注册,然后会调用

bus_add_drive

将设备驱动添加到总线上

[plain] view plaincopyprint?
  1. int driver_register(struct device_driver *drv)  
  2. {  
  3. int ret;  
  4. struct device_driver *other;  
  5. BUG_ON(!drv->bus->p);  
  6. if ((drv->bus->probe && drv->probe) ||  
  7.     (drv->bus->remove && drv->remove) ||  
  8.     (drv->bus->shutdown && drv->shutdown))  
  9. printk(KERN_WARNING "Driver '%s' needs updating - please use "  
  10. "bus_type methods\n", drv->name);  
  11. other = driver_find(drv->name, drv->bus);  
  12. if (other) {  
  13. put_driver(other);  
  14. printk(KERN_ERR "Error: Driver '%s' is already registered, "  
  15. "aborting...\n", drv->name);  
  16. return -EBUSY;  
  17. }  
  18. ret = <strong>bus_add_driver</strong>(drv);  
  19. if (ret)  
  20. return ret;  
  21. ret = driver_add_groups(drv, drv->groups);  
  22. if (ret)  
  23. bus_remove_driver(drv);  
  24. return ret;  
  25. }  


bus_add_driver中初始化priv->klist_devices的值,并将priv赋值给drv->p

通过调用klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers)将驱动信息保存到总线结构中,在此之前将调用driver_attach()

[plain] view plaincopyprint?
  1. int bus_add_driver(struct device_driver *drv)  
  2. {  
  3. struct bus_type *bus;  
  4. struct driver_private *priv;  
  5. int error = 0;  
  6. bus = bus_get(drv->bus);  
  7. if (!bus)  
  8. return -EINVAL;  
  9. pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);  
  10. priv = kzalloc(sizeof(*priv), GFP_KERNEL);  
  11. if (!priv) {  
  12. error = -ENOMEM;  
  13. goto out_put_bus;  
  14. }  
  15. <strong>klist_init</strong>(&priv->klist_devices, NULL, NULL);  
  16. priv->driver = drv;  
  17. drv->p = priv;  
  18. priv->kobj.kset = bus->p->drivers_kset;  
  19. error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,  
  20.      "%s", drv->name);  
  21. if (error)  
  22. goto out_unregister;  
  23. if (drv->bus->p->drivers_autoprobe) {  
  24. error = <strong>driver_attach</strong>(drv);  
  25. if (error)  
  26. goto out_unregister;  
  27. }  
  28. <strong>klist_add_tail</strong>(&priv->knode_bus, &bus->p->klist_drivers);  
  29. module_add_driver(drv->owner, drv);  
  30. error = driver_create_file(drv, &driver_attr_uevent);  
  31. if (error) {  
  32. printk(KERN_ERR "%s: uevent attr (%s) failed\n",  
  33. __func__, drv->name);  
  34. }  
  35. error = driver_add_attrs(bus, drv);  
  36. if (error) {  
  37. /* How the hell do we get out of this pickle? Give up */  
  38. printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",  
  39. __func__, drv->name);  
  40. }  
  41. if (!drv->suppress_bind_attrs) {  
  42. error = add_bind_files(drv);  
  43. if (error) {  
  44. /* Ditto */  
  45. printk(KERN_ERR "%s: add_bind_files(%s) failed\n",  
  46. __func__, drv->name);  
  47. }  
  48. }  
  49. kobject_uevent(&priv->kobj, KOBJ_ADD);  
  50. return 0;  
  51. out_unregister:  
  52. kfree(drv->p);  
  53. drv->p = NULL;  
  54. kobject_put(&priv->kobj);  
  55. out_put_bus:  
  56. bus_put(bus);  
  57. return error;  
  58. }  


driver_attach中,通过调用bus_for_each_dev,遍历在总线上挂载的所有设备,并对每个设备(dev)调用__driver_attach()

[plain] view plaincopyprint?
  1. int driver_attach(struct device_driver *drv)  
  2. {  
  3. return bus_for_each_dev(drv->bus, NULL, drv, <strong>__driver_attach</strong>);  
  4. }  

__driver_attach里会调用driver_match_device()来判断devdrivid是否相同,在i2c驱动里就会调用i2c_bus_type->match程序进行判断,

id相同时,将会调用driver_probe_device()

[plain] view plaincopyprint?
  1. static int __driver_attach(struct device *dev, void *data)  
  2. {  
  3. struct device_driver *drv = data;  
  4. /*  
  5.  * Lock device and try to bind to it. We drop the error  
  6.  * here and always return 0, because we need to keep trying  
  7.  * to bind to devices and some drivers will return an error  
  8.  * simply if it didn't support the device.  
  9.  *  
  10.  * driver_probe_device() will spit a warning if there  
  11.  * is an error.  
  12.  */  
  13. if (!<strong>driver_match_device</strong>(drv, dev))  
  14. return 0;  
  15. if (dev->parent) /* Needed for USB */  
  16. down(&dev->parent->sem);  
  17. down(&dev->sem);  
  18. if (!dev->driver)  
  19. <strong>driver_probe_device</strong>(drv, dev);  
  20. up(&dev->sem);  
  21. if (dev->parent)  
  22. up(&dev->parent->sem);  
  23. return 0;  
  24. }  


在driver_probe_device(),首先会调用device_is_registered()判断dev是否注册,若没注册则返回;若已经注册,则调用really_probe

[plain] view plaincopyprint?
  1. int driver_probe_device(struct device_driver *drv, struct device *dev)  
  2. {  
  3. int ret = 0;  
  4. if (!device_is_registered(dev))  
  5. return -ENODEV;  
  6. pr_debug("bus: '%s': %s: matched device %s with driver %s\n",  
  7.  drv->bus->name, __func__, dev_name(dev), drv->name);  
  8. pm_runtime_get_noresume(dev);  
  9. pm_runtime_barrier(dev);  
  10. ret = <strong>really_probe</strong>(dev, drv);  
  11. pm_runtime_put_sync(dev);  
  12. return ret;  
  13. }  


在really_probe()里,首先将drv赋值给dev->driver,然后会调用总线的probe函数,在i2c驱动里,

此时将会调用i2c总线的probe函数:i2c_device_probe

[plain] view plaincopyprint?
  1. static int really_probe(struct device *dev, struct device_driver *drv)  
  2. {  
  3. int ret = 0;  
  4. atomic_inc(&probe_count);  
  5. pr_debug("bus: '%s': %s: probing driver %s with device %s\n",  
  6.  drv->bus->name, __func__, drv->name, dev_name(dev));  
  7. WARN_ON(!list_empty(&dev->devres_head));  
  8. dev->driver = drv;  
  9. if (driver_sysfs_add(dev)) {  
  10. printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",  
  11. __func__, dev_name(dev));  
  12. goto probe_failed;  
  13. }  
  14. if (dev->bus->probe)   
  15. {  
  16. //此处调用i2c总线的probe函数  
  17. ret = dev->bus->probe(dev);  
  18. if (ret)  
  19. goto probe_failed;  
  20. }   
  21. else if (drv->probe)   
  22. {  
  23. ret = drv->probe(dev);  
  24. if (ret)  
  25. goto probe_failed;  
  26. }  
  27. driver_bound(dev);  
  28. ret = 1;  
  29. pr_debug("bus: '%s': %s: bound device %s to driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name);  
  30. goto done;  
  31. probe_failed:  
  32. devres_release_all(dev);  
  33. driver_sysfs_remove(dev);  
  34. dev->driver = NULL;  
  35. if (ret != -ENODEV && ret != -ENXIO)   
  36. {  
  37. /* driver matched but the probe failed */  
  38. printk(KERN_WARNING       "%s: probe of %s failed with error %d\n",       drv->name, dev_name(dev), ret);  
  39. }  
  40. /* * Ignore errors returned by ->probe so that the next driver can try * its luck. */  
  41. ret = 0;  
  42. done:  
  43. atomic_dec(&probe_count);  
  44. wake_up(&probe_waitqueue);  
  45. return ret;  
  46. }  



i2c_device_probe()里,会根据to_i2c_driver(dev->driver)获取i2c驱动,也就是我们编写的具体的i2c设备驱动的结构体i2c_driver,即

[plain] view plaincopyprint?
  1. static struct i2c_driver XXX_driver = {  
  2. .driver = {  
  3. .name = "XXXX_name",  
  4. .owner = THIS_MODULE,  
  5. },  
  6. .probe = XXX_probe,  
  7. .remove = XXX_remove,  
  8. .id_table = XXX_id,  
  9. };  


这样就调用了我们驱动的probe()了,这就是我们在驱动里调用i2c_add_driver(),通过driver_register()的一系列调用,最后执行我们所写的probe()

[plain] view plaincopyprint?
  1. static int i2c_device_probe(struct device *dev)  
  2. {  
  3. struct i2c_client *client = i2c_verify_client(dev);  
  4. struct i2c_driver *driver;  
  5. int status;  
  6. if (!client)  
  7. return 0;  
  8. driver = to_i2c_driver(dev->driver);  
  9. if (!driver->probe || !driver->id_table)  
  10. return -ENODEV;  
  11. client->driver = driver;  
  12. if (!device_can_wakeup(&client->dev))  
  13. device_init_wakeup(&client->dev,  
  14. client->flags & I2C_CLIENT_WAKE);  
  15. dev_dbg(dev, "probe\n");  
  16. status = <strong>driver->probe</strong>(client, i2c_match_id(driver->id_table, client));//执行我们写的probe函数  
  17. if (status)  
  18. client->driver = NULL;  
  19. return status;  
  20. }  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/434738.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

易宝支付碰到 交易签名无效问题 (2)

无意中翻了翻旧日的代码&#xff0c;原来在上一次交易签名无效的问题仅仅是出现在一个调用的问题上&#xff0c;merchantProperties.php被调用了两次&#xff0c;当第一次被调用的时候是正确加载的&#xff0c;而在第二次调用的时候出就会出现参数丢失的现象&#xff0c;正因为…

北斗三号b1c频点带宽_北斗三号导航信号的创新设计(一)

《测绘学报》构建与学术的桥梁 拉近与权威的距离一需求与挑战1.1 卫星导航信号的作用与意义卫星导航信号是由导航卫星向地球表面播发的无线电测量信号&#xff0c;承担着传递时空基准信息和实施被动测距两大任务&#xff0c;是卫星导航系统实现三边定位的核心载体。卫星导航信号…

g++ linux 编译开栈_linux gcc和g++版本的修改

##编译的时候容易遇到&#xff1a;unsupported GNU version! gcc versions later than 6 are not supported这样的错误。所以我们要更改系统的gcc和g编译器版本。首先我们要知道一个基础的常识&#xff0c;一般而言&#xff0c;linux系统会把gcc和g默认安装在/usr/bin/的目录下…

使用FFmpeg从视频中截图的命令

截取一张352x240尺寸大小的&#xff0c;格式为jpg的图片&#xff1a; ffmpeg -i test.asf -y -f image2 -t 0.001 -s 352x240 a.jpg 把视频的前&#xff13;&#xff10;帧转换成一个Animated Gif &#xff1a; ffmpeg -i test.asf -vframes 30 -y -f gif a.gif 目前还没有找…

Linux I2C核心、总线与设备驱动(一)

本章导读 I2C总线仅仅使用SCL、SDA两根信号线就实现了设备之间的数据交互&#xff0c;极大地简化对硬件资源和PCB板布线空间的占用。因此&#xff0c;I2C总线被非常广泛地应用在EEPROM、实时钟、小型LCD等设备与CPU的接口中。 Linux定义了系统的I2C驱动体系结构&#xff0c;在L…

微软企业库4.1学习笔记(十)企业库的设计

在设计整个企业库的过程中&#xff0c;使用了一系列的最佳实践。下面列出一些里面的最佳实践&#xff1a; 在核心库中使用了Common模块  使用了统一的命名约定和统一的版本  在设计的过程中使用单元测试  在所有模块中包含基础结构在企业库的模块中包含了下面的模式&…

ebay注册流程_跨境电商平台eBay企业入驻流程

整个流程一共包括8个部分了解企业入驻通道企业入驻通道将帮助现有eBay大中华卖家申请并获得高刊登额度的新账户&#xff0c;以满足卖家在品类拓展以及站点拓展的需求。准备材料1.营业执照2.法人代表身份证明&#xff0c;或eBay帐户注册人身份证明&#xff08;根据地区法规有不同…

Linux I2C核心、总线与设备驱动(二)

从上面的分析可知&#xff0c;虽然I2C硬件体系结构比较简单&#xff0c;但是I2C体系结构在Linux中的实现却相当复杂。当工程师拿到实际的电路板&#xff0c;面对复杂的 Linux I2C子系统&#xff0c;应该如何下手写驱动呢&#xff1f;究竟有哪些是需要亲自做的&#xff0c;哪些是…

解决Android中的ERROR: the user data image is used by another emulator. aborting的方法

解决Android中的ERROR: the user data image is used by another emulator. aborting的方法 今天调试代码的时候&#xff0c;突然出现这个错误&#xff0c;折腾了很久没有解决。最后在google上找到了大家给出的两种解决方案&#xff0c;下面给出这两种方法的链接博客&#xff1…

mtu设置失败_Oracle RAC该调整网卡MTU值

在Oracle RAC的环境中&#xff0c;如果我们发现OSW监控数据显示包重组失败率过高&#xff0c;就需要引起足够的重视&#xff0c;因为这很可能会引发member kill/Node kill等重大故障&#xff0c;甚至在有些场景会连带影响到所有RAC节点不可用。一般我们会选择调整ipfrag相关参数…

i2c_add_driver函数用法

I2C的设备驱动是通过i2c_add_driver(&my_driver)向i2c-core注册的&#xff0c;my_driver中的核心是detach和attach函数&#xff0c;在attach中通过probe探测到总线上的设备并把设备和 驱动建立连接以完成设备的初始化。如何探测总线上的设备、Linux中i2c设备地址如何标识并…

基因组印记

基因组印记是指来自父方和母方的等位基因在通过精子和卵子传递给子代时发生了修饰&#xff0c;使带有亲代印记的等位基因具有不同的表达特性&#xff0c;这种修饰常为DNA甲基化修饰&#xff0c;也包括组蛋白乙酰化、甲基化等修饰。在生殖细胞形成早期&#xff0c;来自父方和母方…

判断字段长度大于某长度_判断数据库性能只能通过count(*)?No,这些优化方案了解一下!...

大多数用户在体验数据库时&#xff0c;接触到的最早的sql语句就是count(*)&#xff0c;因此用户判断数据库性能时通常也会通过count(*)进行比较。但在执行时通常会出现一个问题&#xff1a;对某个表做count(*)时需对全表数据进行扫描&#xff0c;当表中包含数据量较大的字段时&…

linux下i2c接口的电容触摸屏驱动开发

原文地址&#xff1a; http://hi.baidu.com/god_sperm/blog/item/2aaac228e8a1ece8e7cd400a.html 电容触摸屏 2011-01-14 15:36 1.Kconfig文件    增加宏定义 2.Makefile文件 增加编译处理 3.添加程序源码 Touch screen remote control design document 2010…

10 款基于 jQuery 的切换效果插件推荐

本文整理了 10 款非常好用的jQuery切换效果插件&#xff0c;包括平滑切换和重叠动画等&#xff0c;这些插件可以实现不同元素之间的动态切换。 1. InnerFade 这是一个基于jQuery的小插件&#xff0c;可以实现页面内的元素淡入淡出效果。 源码/演示 2. HighlightFade 该插件可以…

r语言ggplot2一夜多图_ggplot2绘图:多张图合并为一张

以下内容来自教程 R语言中多张图画到同一个页面上常用的函数为par()和layout() par()函数详解 layout()函数的简单使用 但是这两个函数不适用于ggplot2;ggplot2作图如果希望把多张图放到同一个页面上基本的解决办法是使用(The basic solution is to use the gridExtra R packa…

电容屏原理

电容屏 电容技术的触摸屏是一块四层复合玻璃屏&#xff0c;如下图所示。玻璃屏的内表面和夹层各涂有一层ITO导电层&#xff0c;最外层是只有0.0015毫米厚的矽土玻璃保护层。内层ITO作为屏蔽层&#xff0c;以保证良好的工作环境&#xff0c;夹层ITO涂层作为检测定位的工作层&am…

js矢量图类库:Raphaël—JavaScript Library

官方网址&#xff1a;http://raphaeljs.com/ Raphal is a small JavaScript library that should simplify your work with vector graphics on the web. If you want to create your own specific chart or image crop and rotate widget, for example, you can achieve it si…

sklearn 绘制roc曲线_如何用Tensorflow和scikit-learn绘制ROC曲线?

我试图从tensorflow提供的CIFAR-10示例的修改版本绘制ROC曲线。它现在为2类&#xff0c;而不是10如何用Tensorflow和scikit-learn绘制ROC曲线&#xff1f;的网络的输出被称为logits并采取以下形式&#xff1a;[[-2.57313061 2.57966399] [0.04221377 -0.04033273] [-1.42880082…

Linux的I2C 设备驱动 -- mini2440 上i2c接口触摸屏驱动

本篇记录在友善之臂 mini2440 平台上挂载I2C接口触摸屏的驱动开发过程。内核版本linux-2.6.32.2, 平台是ARM9 S3C2440I2C接口的触摸屏如上篇 Linux的I2C驱动体系结构讲述http://www.lupaworld.com/273398/viewspace-204237.html要挂载新的I2C设备&#xff0c;需要实现3部分&…