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驱动--用户态驱动简单示例的更多相关文章

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

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

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

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

  3. Linux用户态驱动设计

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

  4. I2C用户态驱动设计

    一.用户态驱动模型 1.1 I2C通用驱动代码 i2c_dev_init: static int __init i2c_dev_init(void) { int res; printk(KERN_IN ...

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

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

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

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

  7. useradd linux系统创建用户和设置密码简单脚本-1

    useradd linux系统创建用户和设置密码简单脚本-1 linux_wangqiang 2019-12-04 20:51:18 65 收藏展开#!/bin/bash#快速创建用户 使用$1第一个 ...

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

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

  9. Linux探秘之用户态与内核态

    一. Unix/Linux的体系架构 如上图所示,从宏观上来看,Linux操作系统的体系架构分为用户态和内核态(或者用户空间和内核).内核从本质上看是一种软件——控制计算机的硬件资源,并提供上层应用程 ...

随机推荐

  1. vi/vim 消除搜索后的关键字高亮

    使用vi或vim命令搜索某个关键字之后,取消高亮显示的方法 只要输入:noh即可

  2. Photo3

    Story: 这是一个简朴的家,有用旧了的风扇,木制的桌子,桌子上放了未完成的功课,还有一只正在睡觉的猫.阳光从窗户照进来,微风轻轻的吹着.想象你是坐在窗边吹风的小女孩,你的眼睛正眺望着不远处的风景, ...

  3. 使用Selenium&PhantomJS的方式爬取代理

    前面已经爬取了代理,今天我们使用Selenium&PhantomJS的方式爬取快代理 :快代理 - 高速http代理ip每天更新. 首先分析一下快代理,如下 使用谷歌浏览器,检查,发现每个代理 ...

  4. 从零开始学习前端JAVASCRIPT — 11、JavaScript运动模型及轮播图效果、放大镜效果、自适应瀑布流

    未完待续...... 一.运动原理 通过连续不断的改变物体的位置,而发生移动变化. 使用setInterval实现. 匀速运动:速度值一直保持不变. 多物体同时运动:将定时器绑设置为对象的一个属性. ...

  5. 保证Service不被Kill的解决方案

    1.Service设置成START_STICKY(onStartCommand方法中),kill 后会被重启(等待5秒左右),重传Intent,保持与重启前一样 2.通过 startForegroun ...

  6. Makefile模板

    CC = gcc LD = gcc CFLAGS = -Wall -c LDFLAGS = SRC_DIRS = src test INC_DIRS = inc OBJ_DIR = obj OUT_D ...

  7. TCP三次握手与防火墙规则

    一个(tct)socket连接需要在客户端与服务端开启一个隧道,客户端提供一个端口(new时可指定,也可不指定,随机),服务端的端口和地址一定要指定.在win下,服务端创建监听端口时,防火墙会提示阻止 ...

  8. Spring事务管理—aop:pointcut expression 常见切入点表达式及事物说明

    例: <aop:config>  <aop:pointcut expression="execution(* com.xy.service.*.*(..))"   ...

  9. window.open之postMessage传参数

    这次要实现一个window.open打开子视窗的同时传参数到子视窗,关闭的时候返回参数. 当然简单的做法非常简单,直接在window.open的URL之后接参数即可,但是毕竟get method的参数 ...

  10. LoadRunner10个用户并发测试时分别取不同的参数运行脚本

    使用场景,比如说10个用户使用不同的账户名和密码同时并发登录,此时选择如下参数化策略: 参数选择:select next row 选择unique update value on 选择 once 另一 ...