Linux I2C驱动--用户态驱动简单示例
1. Linux内核支持I2C通用设备驱动(用户态驱动:由应用层实现对硬件的控制可以称之为用户态驱动),实现文件位于drivers/i2c/i2c-dev.c,设备文件为/dev/i2c-0
2. I2C通用设备驱动以字符设备注册进内核的
- static const struct file_operations i2cdev_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = i2cdev_read,
- .write = i2cdev_write,
- .unlocked_ioctl = i2cdev_ioctl,
- .open = i2cdev_open,
- .release = i2cdev_release,
- };
- res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
3. 对设备文件进行读写时,可以调用read、write或者ioctl等方法,他们都是通过调用函数i2c_transfer来实现对I2C设备的操作的
- int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
- {
- int ret;
- /* REVISIT the fault reporting model here is weak:
- *
- * - When we get an error after receiving N bytes from a slave,
- * there is no way to report "N".
- *
- * - When we get a NAK after transmitting N bytes to a slave,
- * there is no way to report "N" ... or to let the master
- * continue executing the rest of this combined message, if
- * that's the appropriate response.
- *
- * - When for example "num" is two and we successfully complete
- * the first message but get an error part way through the
- * second, it's unclear whether that should be reported as
- * one (discarding status on the second message) or errno
- * (discarding status on the first one).
- */
- if (adap->algo->master_xfer) {
- #ifdef DEBUG
- for (ret = ; ret < num; ret++) {
- dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
- "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
- ? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
- (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
- }
- #endif
- if (in_atomic() || irqs_disabled()) {
- ret = mutex_trylock(&adap->bus_lock);
- if (!ret)
- /* I2C activity is ongoing. */
- return -EAGAIN;
- } else {
- mutex_lock_nested(&adap->bus_lock, adap->level);
- }
- ret = adap->algo->master_xfer(adap,msgs,num);
- mutex_unlock(&adap->bus_lock);
- return ret;
- } else {
- dev_dbg(&adap->dev, "I2C level transfers not supported\n");
- return -EOPNOTSUPP;
- }
- }
4. i2c_transfer通过代码可以看出,i2c_transfer 通过调用相应的 adapter 的 master_xfer 方法实现的,而 master_xfer 主要是根据 struct i2c_msg 类型的msgs来进行处理的。
- struct i2c_msg {
- __u16 addr; /* slave address */
- __u16 flags;
- #define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
- #define I2C_M_RD 0x0001 /* read data, from slave to master */
- #define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_PROTOCOL_MANGLING */
- #define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
- #define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
- #define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
- #define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
- __u16 len; /* msg length */
- __u8 *buf; /* pointer to msg data */
- };
5. I2C用户态驱动简单示例
(1)通过read、write实现对I2C设备的操作
- #include <stdio.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <malloc.h>
- #include <sys/ioctl.h>
- #include <string.h>
- #include <linux/i2c.h>
- #include <linux/i2c-dev.h>
- #define SLAVE_ADDRESS 0x50
- #define I2C_WRITE_FLAG 0x00
- #define I2C_READ_FLAG 0x01
- #define USAGE "xxx -r address length\nxxx -w address data1 data2...\n"
- void i2c_write_bytes(int fd, unsigned char address, unsigned char* data, unsigned short len)
- {
- unsigned char* write_data = malloc(len + );
- write_data[] = address;
- memcpy(&write_data[], data, len);
- ioctl(fd, I2C_SLAVE, SLAVE_ADDRESS);
- ioctl(fd, I2C_TIMEOUT, );
- ioctl(fd, I2C_RETRIES, );
- write(fd, write_data, len + );
- printf("Write data success\n");
- if(write_data != NULL)
- {
- free(write_data);
- write_data = NULL;
- }
- }
- void i2c_read_bytes(int fd, unsigned char address, unsigned char* buf, unsigned short len)
- {
- ioctl(fd, I2C_SLAVE, SLAVE_ADDRESS);
- ioctl(fd, I2C_TIMEOUT, );
- ioctl(fd, I2C_RETRIES, );
- write(fd, &address, );
- read(fd, buf, len);
- printf("buf[0] = 0x%x\n", buf[]);
- printf("Read data success\n");
- }
- int main(int argc, char* argv[])
- {
- int opt;
- int fd = -;
- unsigned char address;
- unsigned short len = , i = ;
- unsigned char buf[] = {};
- // Open device file
- fd = open("/dev/i2c-0", O_RDWR);
- if(fd < )
- {
- printf("Open file error\n");
- goto Exit;
- }
- while((opt = getopt(argc, argv, "w:r:")) != -)
- {
- switch(opt)
- {
- case 'w':
- printf("optarg = %s\n", optarg);
- printf("optind = %d\n", optind);
- printf("argc = %d\n", argc);
- printf("argv[optind] = %s\n", argv[optind]);
- address = (unsigned char)strtol(optarg, NULL, );
- printf("address = %x\n", address);
- for(len = ; optind < argc; optind++, len++)
- {
- buf[len] = (unsigned char)strtol(argv[optind], NULL, );
- }
- printf("len = %x\n", len);
- i2c_write_bytes(fd, address, buf, len);
- break;
- case 'r':
- printf("optarg = %s\n", optarg);
- printf("optind = %d\n", optind);
- printf("argv[optind] = %s\n", argv[optind]);
- address = (unsigned char)strtol(optarg, NULL, );
- printf("address = 0x%x\n", address);
- len = (unsigned short)strtol(argv[optind], NULL, );
- printf("len = 0x%x\n", len);
- i2c_read_bytes(fd, address, buf, len);
- printf("Read content:\n");
- for(i = ; i < len; i++)
- {
- printf("0x%x ", buf[i]);
- }
- printf("\n");
- break;
- default:
- printf("Invalid parameter\n");
- printf(USAGE);
- break;
- }
- }
- Exit:
- close(fd);
- return ;
- }
(2)通过ioctl实现对I2C设备的操作
- #include <stdio.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <malloc.h>
- #include <sys/ioctl.h>
- #include <string.h>
- #include <linux/i2c.h>
- #include <linux/i2c-dev.h>
- #define SLAVE_ADDRESS 0x50
- #define I2C_WRITE_FLAG 0x00
- #define I2C_READ_FLAG 0x01
- #define USAGE "xxx -r address length\nxxx -w address data1 data2...\n"
- void i2c_write_bytes(int fd, unsigned char address, unsigned char* data, unsigned short len)
- {
- struct i2c_rdwr_ioctl_data e2prom_write_data;
- e2prom_write_data.nmsgs = ;
- e2prom_write_data.msgs = malloc(sizeof(struct i2c_msg) * e2prom_write_data.nmsgs);
- e2prom_write_data.msgs[].addr = SLAVE_ADDRESS;
- e2prom_write_data.msgs[].flags = I2C_WRITE_FLAG;
- e2prom_write_data.msgs[].len = len + ;//address data
- e2prom_write_data.msgs[].buf = malloc(e2prom_write_data.msgs[].len);
- e2prom_write_data.msgs[].buf[] = address;
- memcpy(&(e2prom_write_data.msgs[].buf[]), data, (size_t)len);
- // Using ioctl to write data
- ioctl(fd, I2C_RDWR, (unsigned long)&e2prom_write_data);
- printf("Write data success\n");
- if(e2prom_write_data.msgs != NULL)
- {
- free(e2prom_write_data.msgs);
- e2prom_write_data.msgs = NULL;
- }
- }
- void i2c_read_bytes(int fd, unsigned char address, unsigned char* buf, unsigned short len)
- {
- struct i2c_rdwr_ioctl_data e2prom_read_data;
- e2prom_read_data.nmsgs = ;//Need writing address first, then reading
- e2prom_read_data.msgs = malloc(sizeof(struct i2c_msg) * e2prom_read_data.nmsgs);
- e2prom_read_data.msgs[].addr = SLAVE_ADDRESS;
- e2prom_read_data.msgs[].flags = I2C_WRITE_FLAG;
- e2prom_read_data.msgs[].len = ;
- e2prom_read_data.msgs[].buf = malloc(e2prom_read_data.msgs[].len);
- e2prom_read_data.msgs[].buf[] = address;
- e2prom_read_data.msgs[].addr = SLAVE_ADDRESS;
- e2prom_read_data.msgs[].flags = I2C_READ_FLAG;
- e2prom_read_data.msgs[].len = len;
- e2prom_read_data.msgs[].buf = malloc(e2prom_read_data.msgs[].len);
- e2prom_read_data.msgs[].buf[] = 0x00;
- // Using ioctl to read data
- ioctl(fd, I2C_RDWR, (unsigned long)&e2prom_read_data);
- printf("e2prom_read_data.msgs[1].buf[0] = 0x%x\n", e2prom_read_data.msgs[].buf[]);
- memcpy((void*)buf, (void*)(e2prom_read_data.msgs[].buf), (unsigned int)len);
- if(e2prom_read_data.msgs != NULL)
- {
- free(e2prom_read_data.msgs);
- e2prom_read_data.msgs = NULL;
- }
- }
- int main(int argc, char* argv[])
- {
- int opt;
- int fd = -;
- unsigned char address;
- unsigned short len = , i = ;
- unsigned char buf[] = {};
- // Open device file
- fd = open("/dev/i2c-0", O_RDWR);
- if(fd < )
- {
- printf("Open file error\n");
- goto Exit;
- }
- while((opt = getopt(argc, argv, "w:r:")) != -)
- {
- switch(opt)
- {
- case 'w':
- printf("optarg = %s\n", optarg);
- printf("optind = %d\n", optind);
- printf("argc = %d\n", argc);
- printf("argv[optind] = %s\n", argv[optind]);
- address = (unsigned char)strtol(optarg, NULL, );
- printf("address = %x\n", address);
- for(len = ; optind < argc; optind++,len++)
- {
- buf[len] = (unsigned char)strtol(argv[optind], NULL, );
- }
- printf("len = %x\n", len);
- i2c_write_bytes(fd, address, buf, len);
- break;
- case 'r':
- printf("optarg = %s\n", optarg);
- printf("optind = %d\n", optind);
- printf("argv[optind] = %s\n", argv[optind]);
- address = (unsigned char)strtol(optarg, NULL, );
- printf("address = 0x%x\n", address);
- len = (unsigned short)strtol(argv[optind], NULL, );
- printf("len = 0x%x\n", len);
- i2c_read_bytes(fd, address, buf, len);
- printf("Read content:\n");
- for(i = ; i < len; i++)
- {
- printf("0x%x ", buf[i]);
- }
- printf("\n");
- break;
- default:
- printf("Invalid parameter\n");
- printf(USAGE);
- break;
- }
- }
- Exit:
- close(fd);
- return ;
- }
Linux I2C驱动--用户态驱动简单示例的更多相关文章
- linuxok6410的I2C驱动分析---用户态驱动
3 i2c-dev 3.1 概述 之前在介绍I2C子系统时,提到过使用i2c-dev.c文件在应用程序中实现我们的I2C从设备驱动.不过,它实现的是一个虚拟,临时的i2c_client,随着设备文件 ...
- 聊聊Linux用户态驱动设计
序言 设备驱动可以运行在内核态,也可以运行在用户态,用户态驱动的利弊网上有很多的讨论,而且有些还上升到政治性上,这里不再多做讨论.不管用户态驱动还是内核态驱动,他们都有各自的缺点.内核态驱动的问题是: ...
- Linux用户态驱动设计
聊聊Linux用户态驱动设计 序言 设备驱动可以运行在内核态,也可以运行在用户态,用户态驱动的利弊网上有很多的讨论,而且有些还上升到政治性上,这里不再多做讨论.不管用户态驱动还是内核态驱动,他们都 ...
- I2C用户态驱动设计
一.用户态驱动模型 1.1 I2C通用驱动代码 i2c_dev_init: static int __init i2c_dev_init(void) { int res; printk(KERN_IN ...
- [国嵌攻略][155][I2C用户态驱动设计]
用户态驱动模型 用户态驱动模型首先是一个应用程序,其次是在这个用户程序中通过内核调用来驱动设备. IIC通用驱动代码 IIC通用驱动程序的代码在/drivers/i2c/i2c-dev.c中.一次读操 ...
- [windows驱动]内核态驱动架构
1.windows驱动简介: 1.1 windows组件简介: 1.2 windows驱动类型: windows驱动分为两种基本类型: 用户态驱动在用户态下执行.它们一般提供一套win32应用程序和内 ...
- useradd linux系统创建用户和设置密码简单脚本-1
useradd linux系统创建用户和设置密码简单脚本-1 linux_wangqiang 2019-12-04 20:51:18 65 收藏展开#!/bin/bash#快速创建用户 使用$1第一个 ...
- 用户态驱动--UIO机制的实现【转】
转自:https://blog.csdn.net/u013982161/article/details/51584900 1 uio理论部分 1.1为什么出现了UIO? 硬件设备可以根据功能分为网 ...
- Linux探秘之用户态与内核态
一. Unix/Linux的体系架构 如上图所示,从宏观上来看,Linux操作系统的体系架构分为用户态和内核态(或者用户空间和内核).内核从本质上看是一种软件——控制计算机的硬件资源,并提供上层应用程 ...
随机推荐
- c语言条件编译#ifdef与#if defined
c语言条件编译#ifdef与#if defined c语言条件编译#ifdef与#if defined 摘自:https://www.cnblogs.com/zhangshenghui/p/566 ...
- HaXe以及OpenFL部署
HaXe以及OpenFL部署 Haxe是一种跨平台的编程语言,本文并未HAXE的教程,只是针对OPENFL以及HAXE的部署教程.HAXE的语法非常类似AS3,由于国内部署HAXE艰难,经常下载到一半 ...
- linux系统学习(二)
文件,目录 pwd:查看当前目录 Print Working Directory cd,ls(ll),mkdir -p Change Directory List Make Directory du ...
- 在Chrome 39中无法使用插件
在chrome 42+版本中在开启npapi选项. 1.打开插件面板,在地址栏中输入 chrome://plugins 2.找到npScreenCapture插件,点击始终允许选框 3允许控件
- “undefined reference to JNI_GetCreatedJavaVM”和“File format not recognized”错误原因分析
"undefined reference to JNI_GetCreatedJavaVM"和"File format not recognized"错误原因分析 ...
- xfce4快捷键设置
xfce4的"Keyboard"可以方便的设置启动应用程序的快捷键. 例如,添加xfce4-terminal和emacs的启动快捷键 Alt+F3打开"Applicati ...
- JavaScript语言精粹 笔记02 函数
函数函数对象函数字面量调用参数返回异常给类型增加方法递归作用域闭包回调模块级联套用记忆 函数 1 函数对象 在JS中函数就是对象.对象是“名/值”对的集合并拥有一个连接到原型对象的隐藏连接.对象字 ...
- Chrome与Firefox对于时间处理的不同
new Date() 函数传参数,在火狐浏览器和谷歌浏览器控制台运行,会得到不同的结果,刚开始觉得不可能,后来实际操作才发现此陷阱. 在Firefox中: var dString = "20 ...
- centos7 安装dnf包管理器和常用命令
Installing DNF Currently the DNF package comes from the EPEL repository, so if your Linux system is ...
- on where having总结
1. ON 和WHERE 所有的查询都回产生一个中间临时报表,查询结果就是从返回临时报表中得到.ON和WHERE后面所跟限制条件的区别,主要与限制条件起作用的时机有关, ON根据限制条件对数据库记录进 ...