一、用户态驱动模型





1.1 I2C通用驱动代码

i2c_dev_init:

  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);                                                          //注册一个I2C的设备驱动
  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. }

i2cdev_fops:

  1. static const struct file_operations i2cdev_fops = {
  2. .owner        = THIS_MODULE,
  3. .llseek        = no_llseek,
  4. .read        = i2cdev_read,
  5. .write        = i2cdev_write,
  6. .unlocked_ioctl    = i2cdev_ioctl,
  7. .open        = i2cdev_open,
  8. .release    = i2cdev_release,
  9. };

i2cdev_ioctl:

  1. static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  2. {
  3. struct i2c_client *client = (struct i2c_client *)file->private_data;
  4. unsigned long funcs;
  5. dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",
  6. cmd, arg);
  7. switch ( cmd ) {
  8. case I2C_SLAVE:
  9. case I2C_SLAVE_FORCE:
  10. /* NOTE: devices set up to work with "new style" drivers
  11. * can't use I2C_SLAVE, even when the device node is not
  12. * bound to a driver. Only I2C_SLAVE_FORCE will work.
  13. *
  14. * Setting the PEC flag here won't affect kernel drivers,
  15. * which will be using the i2c_client node registered with
  16. * the driver model core. Likewise, when that client has
  17. * the PEC flag already set, the i2c-dev driver won't see
  18. * (or use) this setting.
  19. */
  20. if ((arg > 0x3ff) ||
  21. (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
  22. return -EINVAL;
  23. if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))
  24. return -EBUSY;
  25. /* REVISIT: address could become busy later */
  26. client->addr = arg;
  27. return 0;
  28. case I2C_TENBIT:
  29. if (arg)
  30. client->flags |= I2C_M_TEN;
  31. else
  32. client->flags &= ~I2C_M_TEN;
  33. return 0;
  34. case I2C_PEC:
  35. if (arg)
  36. client->flags |= I2C_CLIENT_PEC;
  37. else
  38. client->flags &= ~I2C_CLIENT_PEC;
  39. return 0;
  40. case I2C_FUNCS:
  41. funcs = i2c_get_functionality(client->adapter);
  42. return put_user(funcs, (unsigned long __user *)arg);
  43. case I2C_RDWR:                                                                             //这里是读写命令
  44. return i2cdev_ioctl_rdrw(client, arg);
  45. case I2C_SMBUS:
  46. return i2cdev_ioctl_smbus(client, arg);
  47. case I2C_RETRIES:
  48. client->adapter->retries = arg;
  49. break;
  50. case I2C_TIMEOUT:
  51. /* For historical reasons, user-space sets the timeout
  52. * value in units of 10 ms.
  53. */
  54. client->adapter->timeout = msecs_to_jiffies(arg * 10);
  55. break;
  56. default:
  57. /* NOTE: returning a fault code here could cause trouble
  58. * in buggy userspace code. Some old kernel bugs returned
  59. * zero in this case, and userspace code might accidentally
  60. * have depended on that bug.
  61. */
  62. return -ENOTTY;
  63. }
  64. return 0;
  65. }

i2cdev_ioctl_rdrw:

  1. static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
  2. unsigned long arg)
  3. {
  4. struct i2c_rdwr_ioctl_data rdwr_arg;
  5. struct i2c_msg *rdwr_pa;
  6. u8 __user **data_ptrs;
  7. int i, res;
  8. if (copy_from_user(&rdwr_arg,
  9. (struct i2c_rdwr_ioctl_data __user *)arg,                        //传给ioctl的arg值,强制转换成i2c_rdwr_ioctl_data
  10. sizeof(rdwr_arg)))
  11. return -EFAULT;
  12. /* Put an arbitrary limit on the number of messages that can
  13. * be sent at once */
  14. if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
  15. return -EINVAL;
  16. rdwr_pa = (struct i2c_msg *)
  17. kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg),
  18. GFP_KERNEL);
  19. if (!rdwr_pa)
  20. return -ENOMEM;
  21. if (copy_from_user(rdwr_pa, rdwr_arg.msgs,
  22. rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {
  23. kfree(rdwr_pa);
  24. return -EFAULT;
  25. }
  26. data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);
  27. if (data_ptrs == NULL) {
  28. kfree(rdwr_pa);
  29. return -ENOMEM;
  30. }
  31. res = 0;
  32. for (i = 0; i < rdwr_arg.nmsgs; i++) {
  33. /* Limit the size of the message to a sane amount;
  34. * and don't let length change either. */
  35. if ((rdwr_pa[i].len > 8192) ||
  36. (rdwr_pa[i].flags & I2C_M_RECV_LEN)) {
  37. res = -EINVAL;
  38. break;
  39. }
  40. data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
  41. rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);
  42. if (rdwr_pa[i].buf == NULL) {
  43. res = -ENOMEM;
  44. break;
  45. }
  46. if (copy_from_user(rdwr_pa[i].buf, data_ptrs[i],
  47. rdwr_pa[i].len)) {
  48. ++i; /* Needs to be kfreed too */
  49. res = -EFAULT;
  50. break;
  51. }
  52. }
  53. if (res < 0) {
  54. int j;
  55. for (j = 0; j < i; ++j)
  56. kfree(rdwr_pa[j].buf);
  57. kfree(data_ptrs);
  58. kfree(rdwr_pa);
  59. return res;
  60. }
  61. res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs);                           //发送数据来源于i2c核心
  62. while (i-- > 0) {
  63. if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) {
  64. if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf,
  65. rdwr_pa[i].len))
  66. res = -EFAULT;
  67. }
  68. kfree(rdwr_pa[i].buf);
  69. }
  70. kfree(data_ptrs);
  71. kfree(rdwr_pa);
  72. return res;
  73. }

i2c_rdwr_ioctl_data:

  1. struct i2c_rdwr_ioctl_data {
  2. struct i2c_msg __user *msgs;    /* pointers to i2c_msgs */                    消息指针
  3. __u32 nmsgs;            /* number of i2c_msgs */                              有多少条消息
  4. };

一条消息(一个读操作和写操作):

  1. struct i2c_msg {
  2. __u16 addr;    /* slave address            */                                //从设备地址
  3. __u16 flags;                                                                 //读还是写
  4. #define I2C_M_TEN        0x0010    /* this is a ten bit chip address */
  5. #define I2C_M_RD        0x0001    /* read data, from slave to master */
  6. #define I2C_M_NOSTART        0x4000    /* if I2C_FUNC_PROTOCOL_MANGLING */
  7. #define I2C_M_REV_DIR_ADDR    0x2000    /* if I2C_FUNC_PROTOCOL_MANGLING */
  8. #define I2C_M_IGNORE_NAK    0x1000    /* if I2C_FUNC_PROTOCOL_MANGLING */
  9. #define I2C_M_NO_RD_ACK        0x0800    /* if I2C_FUNC_PROTOCOL_MANGLING */
  10. #define I2C_M_RECV_LEN        0x0400    /* length will be first received byte */
  11. __u16 len;        /* msg length                */                             //消息里面有多少字节
  12. __u8 *buf;        /* pointer to msg data            */                        //消息里面的数据
  13. };

i2c_transfer:

  1. int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
  2. {
  3. int ret;
  4. if (adap->algo->master_xfer) {
  5. #ifdef DEBUG
  6. for (ret = 0; ret < num; ret++) {
  7. dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
  8. "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
  9. ? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
  10. (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
  11. }
  12. #endif
  13. if (in_atomic() || irqs_disabled()) {
  14. ret = mutex_trylock(&adap->bus_lock);
  15. if (!ret)
  16. /* I2C activity is ongoing. */
  17. return -EAGAIN;
  18. } else {
  19. mutex_lock_nested(&adap->bus_lock, adap->level);
  20. }
  21. ret = adap->algo->master_xfer(adap,msgs,num);                               //找到adapter(控制器)->algo(算法)->master_xfer(发送)
  22. mutex_unlock(&adap->bus_lock);
  23. return ret;
  24. } else {
  25. dev_dbg(&adap->dev, "I2C level transfers not supported\n");
  26. return -EOPNOTSUPP;
  27. }
  28. }

二、EEPROM用户态驱动编写

i2c-app-drv.c:

  1. #include <sys/stat.h>
  2. #include <fcntl.h>
  3. #include <stdio.h>
  4. #include <unistd.h>
  5. #include <linux/types.h>
  6. #define I2C_RDWR 0x0707
  7. struct i2c_msg {
  8. unsigned short addr;    /* slave address            */
  9. unsigned short flags;
  10. unsigned short len;        /* msg length                */
  11. unsigned char *buf;        /* pointer to msg data            */
  12. };
  13. struct i2c_rdwr_ioctl_data {
  14. struct i2c_msg *msgs;    /* pointers to i2c_msgs */
  15. unsigned int nmsgs;            /* number of i2c_msgs */
  16. };
  17. int main()
  18. {
  19. int fd;
  20. struct i2c_rdwr_ioctl_data e2prom_data;
  21. //1.打开通用设备文件
  22. fd = open("/dev/i2c-0", O_RDWR);
  23. e2prom_data.msgs = (struct i2c_msg *)malloc(2*sizeof(struct i2c_msg));
  24. //2.构造写数据到eeprom的消息
  25. e2prom_data.nmsgs = 1;
  26. (e2prom_data.msgs[0]).len = 2;
  27. (e2prom_data.msgs[0]).addr = 0x50;
  28. (e2prom_data.msgs[0]).flags = 0;
  29. (e2prom_data.msgs[0]).buf = (unsigned char *)malloc(2);
  30. (e2prom_data.msgs[0]).buf[0] = 0x10;
  31. (e2prom_data.msgs[0]).buf[1] = 0xF0;
  32. //3.利用ioctl写入数据
  33. ioctl(fd, I2C_RDWR, (unsigned long)&e2prom_data);
  34. //4.构造从eeprom读书据的消息
  35. e2prom_data.nmsgs = 2;
  36. (e2prom_data.msgs[0]).len = 1;
  37. (e2prom_data.msgs[0]).addr = 0x50;
  38. (e2prom_data.msgs[0]).flags = 0;
  39. (e2prom_data.msgs[0]).buf[0] = 0x10;
  40. (e2prom_data.msgs[1]).len = 1;
  41. (e2prom_data.msgs[1]).addr = 0x50;
  42. (e2prom_data.msgs[1]).flags = 1;
  43. (e2prom_data.msgs[1]).buf = (unsigned char *)malloc(2);
  44. (e2prom_data.msgs[1]).buf[0] = 0;
  45. //5.使用ioctl读出数据
  46. ioctl(fd, I2C_RDWR, (unsigned long)&e2prom_data);
  47. printf("buf[0]=%x\n",(e2prom_data.msgs[1]).buf[0]);
  48. //6.关闭设备
  49. close(fd);
  50. }

遇到的问题:

  1. # ./i2c-app-drv
  2. s3c2440-i2c s3c2440-i2c: cannot get bus (error -110)
  3. s3c2440-i2c s3c2440-i2c: cannot get bus (error -110)
  4. s3c2440-i2c s3c2440-i2c: cannot get bus (error -110)
  5. s3c2440-i2c s3c2440-i2c: cannot get bus (error -110)
  6. buf[0]=0

内核中的i2c和视频模块冲突了。所以要在内核中去掉视频模块:

Device Drivers>>Multimedia devices>>Video For Linux



结果:

  1. # ./i2c-app-drv
  2. buf[0]=f0

I2C用户态驱动设计的更多相关文章

  1. [国嵌攻略][155][I2C用户态驱动设计]

    用户态驱动模型 用户态驱动模型首先是一个应用程序,其次是在这个用户程序中通过内核调用来驱动设备. IIC通用驱动代码 IIC通用驱动程序的代码在/drivers/i2c/i2c-dev.c中.一次读操 ...

  2. Linux用户态驱动设计

    聊聊Linux用户态驱动设计   序言 设备驱动可以运行在内核态,也可以运行在用户态,用户态驱动的利弊网上有很多的讨论,而且有些还上升到政治性上,这里不再多做讨论.不管用户态驱动还是内核态驱动,他们都 ...

  3. 聊聊Linux用户态驱动设计

    序言 设备驱动可以运行在内核态,也可以运行在用户态,用户态驱动的利弊网上有很多的讨论,而且有些还上升到政治性上,这里不再多做讨论.不管用户态驱动还是内核态驱动,他们都有各自的缺点.内核态驱动的问题是: ...

  4. Linux I2C驱动--用户态驱动简单示例

    1. Linux内核支持I2C通用设备驱动(用户态驱动:由应用层实现对硬件的控制可以称之为用户态驱动),实现文件位于drivers/i2c/i2c-dev.c,设备文件为/dev/i2c-0 2. I ...

  5. linuxok6410的I2C驱动分析---用户态驱动

    3  i2c-dev 3.1 概述 之前在介绍I2C子系统时,提到过使用i2c-dev.c文件在应用程序中实现我们的I2C从设备驱动.不过,它实现的是一个虚拟,临时的i2c_client,随着设备文件 ...

  6. 用户态驱动--UIO机制的实现【转】

    转自:https://blog.csdn.net/u013982161/article/details/51584900 1 uio理论部分   1.1为什么出现了UIO? 硬件设备可以根据功能分为网 ...

  7. tiny6410在I2c用户态中的程序设计eeprom

    在读写的过程中,发现写数据成功但是读取数据却失败,猜测是因为iic的读写操作过快,故在写操作后给一定的延迟,进而读写成功. 代码如下: #include <stdio.h>#include ...

  8. [中英对照]User-Space Device Drivers in Linux: A First Look | 初识Linux用户态设备驱动程序

    如对Linux用户态驱动程序开发有兴趣,请阅读本文,否则请飘过. User-Space Device Drivers in Linux: A First Look | 初识Linux用户态设备驱动程序 ...

  9. [windows驱动]内核态驱动架构

    1.windows驱动简介: 1.1 windows组件简介: 1.2 windows驱动类型: windows驱动分为两种基本类型: 用户态驱动在用户态下执行.它们一般提供一套win32应用程序和内 ...

随机推荐

  1. POJ 3525 Most Distant Point from the Sea (半平面交)

    Description The main land of Japan called Honshu is an island surrounded by the sea. In such an isla ...

  2. 【Dart学习】--Dart之超级父类之Object

    一,概述 -- Object Dart语言和Java一样,都是面向对象语言,所有的类也都有个公共的父类----->Object.该类位于Dart sdk核心库core目录下. 二,构造方法 // ...

  3. js练习题之图片背景轮播

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  4. (转)VirtualBox下安装CentOS7系统

    转:https://www.cnblogs.com/hihtml5/p/8217062.html 本文假定你已经知道如何安装VirtualBox虚拟机软件,并且已经安装好了. 首先我们需要准备好cen ...

  5. 术语-MOSS-微软协作工具:MOSS(微软协作工具)

    ylbtech-术语-MOSS-微软协作工具:MOSS(微软协作工具) MOSS -- Microsoft Office Sharepoint Server,是一款为企业客户而设计的.基于web的内容 ...

  6. 凉经-Mozilla Firefox Ltd-前端工程师

    北京谋智火狐信息技术有限公司(北京市东城区建国门华润大厦 17 层)过去面试的时候感觉电梯好神奇啊!一边的电梯是直达 18 层以上的,我按了 18 层准备到了再往下走一层,一个老司机和我说要做另一边的 ...

  7. day 109结算中心.

    from django.db import models from django.contrib.contenttypes.fields import GenericForeignKey,Generi ...

  8. 记录规则(recording rules)与告警规则(alerting rule)

    记录规则(recording rules) 配置规则 Prometheus支持两种类型的规则,可以对其进行配置,然后定期进行评估:记录规则和警报规则.要在Prometheus中包含规则,请创建一个包含 ...

  9. Linux下docker安装教程

    目前最新版本的docker19.03支持nvidia显卡与容器的无缝对接,从而摆脱了对nvidia-docker的依赖.因此毫不犹豫安装19.03版本的docker,安装教程可参考官方教程Centos ...

  10. XX-net 3.11.9 登陆Google等出现没有开启cookie的问题

    糟糕!您的浏览器似乎禁用了 Cookie.请务必启用 Cookie 或尝试打开一个新的浏览器窗口. 出现这个问题解决方法: 1.配置好X-tunnel,即登录账号2.打开谷歌浏览器或者你用的浏览器,设 ...