接下来以一个实际的例子来看I2C设备驱动,就以drivers/i2c/i2c-dev.c为例。

先看它的初始化和注销函数

[cpp] view plaincopy
  1. static int __init i2c_dev_init(void)
  2. {
  3. int res;
  4. printk(KERN_INFO "i2c /dev entries driver\n");
  5. res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
  6. if (res)
  7. goto out;
  8. i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
  9. if (IS_ERR(i2c_dev_class)) {
  10. res = PTR_ERR(i2c_dev_class);
  11. goto out_unreg_chrdev;
  12. }
  13. res = i2c_add_driver(&i2cdev_driver);
  14. if (res)
  15. goto out_unreg_class;
  16. return 0;
  17. out_unreg_class:
  18. class_destroy(i2c_dev_class);
  19. out_unreg_chrdev:
  20. unregister_chrdev(I2C_MAJOR, "i2c");
  21. out:
  22. printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);
  23. return res;
  24. }
  25. static void __exit i2c_dev_exit(void)
  26. {
  27. i2c_del_driver(&i2cdev_driver);
  28. class_destroy(i2c_dev_class);
  29. unregister_chrdev(I2C_MAJOR,"i2c");
  30. }

首先调用register_chrdev注册了一个字符设备,这是老的字符驱动注册方式。然后到了接下来的主角,i2c_add_driver,在I2C子系统中,I2C设备驱动就是采用这个函数注册,注销一个I2C设备驱动使用下面的i2c_del_driver函数,那就具体看看这个I2C设备驱动注册函数。

[cpp] view plaincopy
  1. static inline int i2c_add_driver(struct i2c_driver *driver)
  2. {
  3. return i2c_register_driver(THIS_MODULE, driver);
  4. }
  5. int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
  6. {
  7. int res;
  8. /* Can't register until after driver model init */
  9. if (unlikely(WARN_ON(!i2c_bus_type.p)))
  10. return -EAGAIN;
  11. /* add the driver to the list of i2c drivers in the driver core */
  12. driver->driver.owner = owner;
  13. driver->driver.bus = &i2c_bus_type; /*指定驱动的总线类型*/
  14. /* When registration returns, the driver core
  15. * will have called probe() for all matching-but-unbound devices.
  16. */
  17. res = driver_register(&driver->driver); /*注册驱动*/
  18. if (res)
  19. return res;
  20. pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
  21. INIT_LIST_HEAD(&driver->clients);
  22. /* Walk the adapters that are already present */
  23. mutex_lock(&core_lock);
  24. bus_for_each_dev(&i2c_bus_type, NULL, driver, __attach_adapter);
  25. mutex_unlock(&core_lock);
  26. return 0;
  27. }

再来看看i2c设备驱动注销函数

[cpp] view plaincopy
  1. void i2c_del_driver(struct i2c_driver *driver)
  2. {
  3. mutex_lock(&core_lock);
  4. bus_for_each_dev(&i2c_bus_type, NULL, driver, __detach_adapter);
  5. mutex_unlock(&core_lock);
  6. driver_unregister(&driver->driver);
  7. pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
  8. }

也没什么,最后调用的就是驱动的注销函数driver_unregister函数。

来看传递给注册和注销i2c驱动函数的参数什么,i2cdev_driver它是structi2c_driver结构类型,i2c设备驱动就是使用这个结构类型描述,这个结构类型定义在include/linux/i2c.h

[cpp] view plaincopy
  1. struct i2c_driver {
  2. unsigned int class;
  3. /* Notifies the driver that a new bus has appeared or is about to be
  4. * removed. You should avoid using this if you can, it will probably
  5. * be removed in a near future.
  6. */
  7. int (*attach_adapter)(struct i2c_adapter *);
  8. int (*detach_adapter)(struct i2c_adapter *);
  9. /* Standard driver model interfaces */
  10. int (*probe)(struct i2c_client *, const struct i2c_device_id *);
  11. int (*remove)(struct i2c_client *);
  12. /* driver model interfaces that don't relate to enumeration  */
  13. void (*shutdown)(struct i2c_client *);
  14. int (*suspend)(struct i2c_client *, pm_message_t mesg);
  15. int (*resume)(struct i2c_client *);
  16. /* a ioctl like command that can be used to perform specific functions
  17. * with the device.
  18. */
  19. int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
  20. struct device_driver driver;
  21. const struct i2c_device_id *id_table;
  22. /* Device detection callback for automatic device creation */
  23. int (*detect)(struct i2c_client *, int kind, struct i2c_board_info *);
  24. const struct i2c_client_address_data *address_data;
  25. struct list_head clients;
  26. };

来看i2c-dev.c中是怎么定义的

[cpp] view plaincopy
  1. static struct i2c_driver i2cdev_driver = {
  2. .driver = {
  3. .name   = "dev_driver",
  4. },
  5. .attach_adapter = i2cdev_attach_adapter,
  6. .detach_adapter = i2cdev_detach_adapter,
  7. };

这是老的方式,所以它只是给attach_adapter和detach_adapter赋了值,由于这里是老的方式,所以我们也就不去具体看这个函数了,我们直接去看它的数据传输部分吧。

[cpp] view plaincopy
  1. static ssize_t i2cdev_read (struct file *file, char __user *buf, size_t count,
  2. loff_t *offset)
  3. {
  4. char *tmp;
  5. int ret;
  6. struct i2c_client *client = (struct i2c_client *)file->private_data;
  7. if (count > 8192)
  8. count = 8192;
  9. tmp = kmalloc(count,GFP_KERNEL);
  10. if (tmp==NULL)
  11. return -ENOMEM;
  12. pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n",
  13. iminor(file->f_path.dentry->d_inode), count);
  14. ret = i2c_master_recv(client,tmp,count);
  15. if (ret >= 0)
  16. ret = copy_to_user(buf,tmp,count)?-EFAULT:ret;
  17. kfree(tmp);
  18. return ret;
  19. }

这是i2c设备读函数,我们看它是调用的i2c_master_recv函数去操作的,去看这个函数

[cpp] view plaincopy
  1. int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
  2. {
  3. struct i2c_adapter *adap=client->adapter;
  4. struct i2c_msg msg;
  5. int ret;
  6. msg.addr = client->addr;
  7. msg.flags = client->flags & I2C_M_TEN;
  8. msg.flags |= I2C_M_RD;
  9. msg.len = count;
  10. msg.buf = buf;
  11. ret = i2c_transfer(adap, &msg, 1);
  12. /* If everything went ok (i.e. 1 msg transmitted), return #bytes
  13. transmitted, else error code. */
  14. return (ret == 1) ? count : ret;
  15. }

i2c设备写函数

[cpp] view plaincopy
  1. static ssize_t i2cdev_write (struct file *file, const char __user *buf, size_t count,
  2. loff_t *offset)
  3. {
  4. int ret;
  5. char *tmp;
  6. struct i2c_client *client = (struct i2c_client *)file->private_data;
  7. if (count > 8192)
  8. count = 8192;
  9. tmp = kmalloc(count,GFP_KERNEL);
  10. if (tmp==NULL)
  11. return -ENOMEM;
  12. if (copy_from_user(tmp,buf,count)) {
  13. kfree(tmp);
  14. return -EFAULT;
  15. }
  16. pr_debug("i2c-dev: i2c-%d writing %zu bytes.\n",
  17. iminor(file->f_path.dentry->d_inode), count);
  18. ret = i2c_master_send(client,tmp,count);
  19. kfree(tmp);
  20. return ret;
  21. }
  22. int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
  23. {
  24. int ret;
  25. struct i2c_adapter *adap=client->adapter;
  26. struct i2c_msg msg;
  27. msg.addr = client->addr;
  28. msg.flags = client->flags & I2C_M_TEN;
  29. msg.len = count;
  30. msg.buf = (char *)buf;
  31. ret = i2c_transfer(adap, &msg, 1);
  32. /* If everything went ok (i.e. 1 msg transmitted), return #bytes
  33. transmitted, else error code. */
  34. return (ret == 1) ? count : ret;
  35. }

这两个函数最终都是调用的i2c_transfer函数去完成数据的传输,只是他们的msg的flags不一样,读操作的flags要加上I2C_M_RD这个标志。

再看它们两个共同的i2c_transfer函数

[cpp] view plaincopy
  1. int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
  2. {
  3. unsigned long orig_jiffies;
  4. int ret, try;
  5. /* REVISIT the fault reporting model here is weak:
  6. *
  7. *  - When we get an error after receiving N bytes from a slave,
  8. *    there is no way to report "N".
  9. *
  10. *  - When we get a NAK after transmitting N bytes to a slave,
  11. *    there is no way to report "N" ... or to let the master
  12. *    continue executing the rest of this combined message, if
  13. *    that's the appropriate response.
  14. *
  15. *  - When for example "num" is two and we successfully complete
  16. *    the first message but get an error part way through the
  17. *    second, it's unclear whether that should be reported as
  18. *    one (discarding status on the second message) or errno
  19. *    (discarding status on the first one).
  20. */
  21. if (adap->algo->master_xfer) {
  22. #ifdef DEBUG
  23. for (ret = 0; ret < num; ret++) {
  24. dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
  25. "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
  26. ? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
  27. (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
  28. }
  29. #endif
  30. if (in_atomic() || irqs_disabled()) {
  31. ret = mutex_trylock(&adap->bus_lock);
  32. if (!ret)
  33. /* I2C activity is ongoing. */
  34. return -EAGAIN;
  35. } else {
  36. mutex_lock_nested(&adap->bus_lock, adap->level);
  37. }
  38. /* Retry automatically on arbitration loss */
  39. orig_jiffies = jiffies;
  40. for (ret = 0, try = 0; try <= adap->retries; try++) {
  41. ret = adap->algo->master_xfer(adap, msgs, num);
  42. if (ret != -EAGAIN)
  43. break;
  44. if (time_after(jiffies, orig_jiffies + adap->timeout))
  45. break;
  46. }
  47. mutex_unlock(&adap->bus_lock);
  48. return ret;
  49. } else {
  50. dev_dbg(&adap->dev, "I2C level transfers not supported\n");
  51. return -EOPNOTSUPP;
  52. }
  53. }

我们看就是调用总线的master_xfer方法,我们在前面分析使用gpio模拟i2c总线时,看过这样一句 .master_xfer =bit_xfer, ,所以最终调用的是这个函数来完成数据传输。使用i2c_master_recv和i2c_master_send函数一次只能传输一个msg,由于它一次只能传输一个msg,所以它的传输方向不能改变,也就是一次只能完成读或写操作,并且读操作时还不能传递设备的基地址,所以通常是不会用这两个函数的,直接的做法时,构造两个msg,一个msg的数据为操作设备基地址,另外一个msg才是我们真正要读写的数据,最后调用i2c_transfer函数去完成数据的传送。

Linux I2C子系统分析-I2C设备驱动相关推荐

  1. linux内核组件分析之--设备驱动模型之bus

    前面我们分析了设备驱动模型中的device和driver,device和driver本来是不相关的东西,只因为bus的存在,才被联系到了一起.本节就来看看设备驱动模型中起枢纽作用的bus.本节的头文件 ...

  2. linux内核部件分析之——设备驱动模型之class

    前面看过了设备驱动模型中的bus.device.driver,这三种都是有迹可循的.其中bus代表实际的总线,device代表实际的设备和接口,而driver则对应存在的驱动.但本节要介绍的class ...

  3. linux内核部件分析(十)——设备驱动模型之class,linux内核部件分析(十)——设备驱动模型之class...

    前面看过了设备驱动模型中的bus.device.driver,这三种都是有迹可循的.其中bus代表实际的总线,device代表实际的设备和接口,而driver则对应存在的驱动.但本节要介绍的class ...

  4. Linux I2C子系统分析-I2C总线驱动

    在drivers/i2c/busses下包含各种I2C总线驱动,如S3C2440的I2C总线驱动i2c-s3c2410.c,使用GPIO模拟I2C总线的驱动i2c-gpio.c,这里只分析i2c-gp ...

  5. linux IIC子系统分析(九)——实例分析通过设备节点访问I2c设备

    在< linux IIC子系统分析(四)--I2c bus初始化> 中我们创建了I2C 总线驱动,I2C adapter device 和adapter drivers也在这时创建 在&l ...

  6. linux IIC子系统分析(二)—— linux i2c 架构概述

    I2C总线因为它及简单的硬件连接和通讯方式,在现在的很多设备上它是一种不可或缺的通讯总线.如果用当单片机直接操作I2C,其实很简单,只要正确把握IIC的操作时序就可以了.但是在linux系统中,I2C ...

  7. 一起分析Linux系统设计思想——05字符设备驱动框架剖析(四)

    在学习资料满天飞的大环境下,知识变得非常零散,体系化的知识并不多,这就导致很多人每天都努力学习到感动自己,最终却收效甚微,甚至放弃学习.我的使命就是过滤掉大量的垃圾信息,将知识体系化,以短平快的方式直 ...

  8. Linux input子系统分析

    输入输出是用户和产品交互的手段,因此输入驱动开发在Linux驱动开发中很常见.同时,input子系统的分层架构思想在Linux驱动设计中极具代表性和先进性,因此对Linux input子系统进行深入分 ...

  9. linux input子系统分析--子系统核心.事件处理层.事件传递过程

    linux input子系统分析--子系统核心.事件处理层.事件传递过程 一.  输入子系统核心分析. 1.输入子系统核心对应与/drivers/input/input.c文件,这个也是作为一个模块注 ...

最新文章

  1. MBZUAI大学招生了,Michael Jordan、Raj Reddy等大佬授课
  2. python随机数程序源码_Python 实现随机数详解及实例代码
  3. hamcrest_重新设计Hamcrest
  4. java 发送16进制数据'_java 16进制数据递增
  5. 大家沉迷短视频无法自拔?Python爬虫进阶,带你玩转短视频
  6. python 下载google文件
  7. 自己动手写操作系统(三)
  8. Xiaojie雷达之路---TI实战笔记---OSAL详解
  9. CentOS安装VMwareTools
  10. APF有源滤波器仿真,三相三线制 谐波电流检测模块基于p-q方法,ip-iq等方法
  11. Updates were rejected because the tip of your current branch is behind hint: its remote counterpart
  12. 干货!一文带你认清SD卡、TF卡、SIM卡!
  13. 4.7/4.8 磁盘挂载
  14. 朱松纯:走向通用人工智能——从大数据到大任务
  15. 8c sql手册 五
  16. scrapy 爬取指定贴吧
  17. 六个SEO关键词分析工具
  18. i.MX6ULL嵌入式Linux开发4-根文件系统构建
  19. cakephp $this-html-css,CakePHP - 中文手册
  20. PTA 7-106 sdut-C语言实验——模拟计算器

热门文章

  1. 日志中的秘密 Windows登录类型知多少?
  2. UML 对象模型图阅读指南 (转)
  3. vb.net連接ACCESS数据库
  4. hdu 4468 spy 极其精彩的一道kmp灵活运用题
  5. iOS 9 学习系列: Xcode Code Coverage
  6. mysql笔记一——安装和设置root密码
  7. 字符串的模式匹配(Java实现)
  8. Microstation研发
  9. 远程ubuntu虚拟机Tensorflow搭建 - 1 SSH连接
  10. JavaScript有关的10个怪癖和秘密