linuxok6410的I2C驱动分析---用户态驱动
3 i2c-dev
3.1 概述
之前在介绍I2C子系统时,提到过使用i2c-dev.c文件在应用程序中实现我们的I2C从设备驱动。不过,它实现的是一个虚拟,临时的i2c_client,随着设备文件的打开而产生,并随着设备文件的关闭而撤销。I2c-dev.c针对每个I2C适配器生成一个主设备号为89的设备文件,实现了i2c_driver的成员函数以及文件操作接口,所以i2c-dev.c的主题是”i2c_driver成员函数+字符设备驱动”。
3.2 i2c-dev.c源码分析
初始化模块
- static int __init i2c_dev_init(void)
- {
- res= register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
- i2c_dev_class= class_create(THIS_MODULE, "i2c-dev");
- /*Keep track of adapters which will be added or removed later */
- res= bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);
- /*绑定已经存在的适配器 */
- i2c_for_each_dev(NULL,i2cdev_attach_adapter);
- }
I2c-dev初始化函数主要做了注册名为”i2c”的字符设备文件和”i2c-dev”的类
i2cdev_read和i2cdev_write
I2c-dev.c中实现的i2cdev_read和i2cdev_write函数不具有太强的通用性,只适合下面这种单开始信号情况:

而不适合多开始信号的情况:

所以我们经常会使用i2cdev_ioctl函数的I2C_RDWR,在分析i2cdev_ioctl函数之前,我们需要了解一个结构体:
- /* This is the structure as used in theI2C_RDWR ioctl call */
- struct i2c_rdwr_ioctl_data {
- structi2c_msg __user *msgs; /* pointersto i2c_msgs */
- __u32nmsgs; /* number ofi2c_msgs */
- };
Msgs 表示单个开始信号传递的数据;
Nmsgs 表示有多少个msgs,比如上图,单开始信号时,nmsgs等于1;多开始信号时,nmsgs等于2
- struct i2c_msg {
- __u16addr; /* slave address */
- __u16flags; /* 默认为写入 */
- #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 */
- __u16len; /* msg length */
- __u8*buf; /* pointer to msgdata */
- };
3.3 eeprom实例
预备知识
使用的ok6410开发板,eeprom的地址为0x50,实验完成一个数据的读写,先看下读写时序
AT24C02任意地址字节写的时序:

AT24C02任意地址字节写的时序:

用户态驱动:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdlib.h>
//#include <linux/types.h>
#define I2C_RDWR 0x0707
struct i2c_msg {
unsigned short addr; /* slave address */
unsigned short flags;
unsigned short len; /* msg length */
unsigned char *buf; /* pointer to msg data */
};
struct i2c_rdwr_ioctl_data {
struct i2c_msg *msgs; /* pointers to i2c_msgs */
unsigned int nmsgs; /* number of i2c_msgs */
};
int main()
{
int fd;
struct i2c_rdwr_ioctl_data e2prom_data;
//1. 打开通用设备文件
fd = open("/dev/i2c-0", O_RDWR);
//为i2c_rdwr_ioctl_data中的struct i2c_msg *分配空间
e2prom_data.msgs = (struct i2c_msg *)malloc(2*sizeof(struct i2c_msg)); // 构造两条消息
//2. 构造写数据到eeprom
e2prom_data.nmsgs = 1; // 只有一条消息
(e2prom_data.msgs[0]).len = 2; //长度等于2,第一个字节代表的是i2c设备的内部地址,第二个字节代表的是写入的数据
(e2prom_data.msgs[0]).addr = 0x50; // 从设备地址(e2prom的地址),注意这里是不带方向的!
(e2prom_data.msgs[0]).flags = 0; // 方向由flag标志位来指明,0代表了写,1代表了读
(e2prom_data.msgs[0]).buf = (unsigned char*)malloc(2); // 这里只分配两个字节(内部偏移地址一字节,数据1字节)
(e2prom_data.msgs[0]).buf[0] = 0x10; // 数据将写入e2prom中的内部0x10地址中
(e2prom_data.msgs[0]).buf[1] = 0x60; // 写入e2prom中内 部0x10地址中的数据位0x60
//3. 使用ioctl写入数据
ioctl(fd, I2C_RDWR, (unsigned long)&e2prom_data, I2C_RDWR); // 这里面的命令参数对应的是驱动内部的ioctl中的case语句中的参数
//4. 构造从eeprom读数据的消息
e2prom_data.nmsgs = 2; // 读数据需要两条消息
(e2prom_data.msgs[0]).len = 1; //长度为一个字节,代表的是i2c设备的内部地址
(e2prom_data.msgs[0]).addr = 0x50; // 从设备地址(e2prom的地址),注意这里是不带方向的!
(e2prom_data.msgs[0]).flags = 0; // 方向由flag标志位来指明,0代表了写,1代表了读
(e2prom_data.msgs[0]).buf[0] = 0x10; // 数据将写入e2prom中的内部0x10地址中
// 第二条消息(读数据)
(e2prom_data.msgs[1]).len = 1; //长度为一个字节,代表的是i2c设备的内部地址
(e2prom_data.msgs[1]).addr = 0x50; // 从设备地址(e2prom的地址),注意这里是不带方向的!
(e2prom_data.msgs[1]).flags = 1; // 方向由flag标志位来指明,0代表了写,1代表了读
(e2prom_data.msgs[1]).buf = (unsigned char*)malloc(2);
(e2prom_data.msgs[1]).buf[0] = 0; // 数据从e2prom中的内部0x10地址中读出
//5. 使用ioctl读出数据
ioctl(fd, I2C_RDWR, (unsigned long)&e2prom_data);
printf("buf[0] = %x\n", (e2prom_data.msgs[1]).buf[0]);
//6. 关闭设备
close(fd);
}
linuxok6410的I2C驱动分析---用户态驱动的更多相关文章
- [国嵌攻略][155][I2C用户态驱动设计]
用户态驱动模型 用户态驱动模型首先是一个应用程序,其次是在这个用户程序中通过内核调用来驱动设备. IIC通用驱动代码 IIC通用驱动程序的代码在/drivers/i2c/i2c-dev.c中.一次读操 ...
- Linux I2C驱动--用户态驱动简单示例
1. Linux内核支持I2C通用设备驱动(用户态驱动:由应用层实现对硬件的控制可以称之为用户态驱动),实现文件位于drivers/i2c/i2c-dev.c,设备文件为/dev/i2c-0 2. I ...
- I2C用户态驱动设计
一.用户态驱动模型 1.1 I2C通用驱动代码 i2c_dev_init: static int __init i2c_dev_init(void) { int res; printk(KERN_IN ...
- Linux I2C驱动分析(三)----i2c_dev驱动和应用层分析 【转】
本文转载自:http://blog.chinaunix.net/uid-21558711-id-3959287.html 分类: LINUX 原文地址:Linux I2C驱动分析(三)----i2c_ ...
- 聊聊Linux用户态驱动设计
序言 设备驱动可以运行在内核态,也可以运行在用户态,用户态驱动的利弊网上有很多的讨论,而且有些还上升到政治性上,这里不再多做讨论.不管用户态驱动还是内核态驱动,他们都有各自的缺点.内核态驱动的问题是: ...
- Linux用户态驱动设计
聊聊Linux用户态驱动设计 序言 设备驱动可以运行在内核态,也可以运行在用户态,用户态驱动的利弊网上有很多的讨论,而且有些还上升到政治性上,这里不再多做讨论.不管用户态驱动还是内核态驱动,他们都 ...
- v79.01 鸿蒙内核源码分析(用户态锁篇) | 如何使用快锁Futex(上) | 百篇博客分析OpenHarmony源码
百篇博客分析|本篇为:(用户态锁篇) | 如何使用快锁Futex(上) 进程通讯相关篇为: v26.08 鸿蒙内核源码分析(自旋锁) | 当立贞节牌坊的好同志 v27.05 鸿蒙内核源码分析(互斥锁) ...
- 用户态驱动--UIO机制的实现【转】
转自:https://blog.csdn.net/u013982161/article/details/51584900 1 uio理论部分 1.1为什么出现了UIO? 硬件设备可以根据功能分为网 ...
- tiny4412 串口驱动分析六 --- TTY驱动架构
转载: http://www.linuxidc.com/Linux/2013-11/92639.htm 参考: http://blog.csdn.net/lamdoc/article/details/ ...
随机推荐
- [VB.NET]拖动操作的技术基础
1.设置需要接受拖动事件的控件的AllowDrop属性为True,在开发界面时配置,不可通过代码配置 2.在DragEnter事件处理程序里,为e.Effet设置枚举值,否则拖动无效 Private ...
- jdk线程的死锁
两个线程相互等着对方释放同步监听器:等着要对方的结果后才能继续执行就会发生死锁. 男对女说:你先嫁给我,我再给你买房子:女对男说:你先给我买房子,我再嫁给你. 多个线程同时锁住同一个监听对象. 在开发 ...
- vc 递归删除非空文件夹
我觉得这是一个非常不错的递归例子 头文件 #pragma once #include <atlstr.h> #include <io.h> #include <strin ...
- PostMan入门使用教程
最近需要测试产品中的REST API,无意中发现了PostMan这个chrome插件,把玩了一下,发现postman秉承了一贯以来google工具强大,易用的特质.独乐乐不如众乐乐,特此共享出来给大伙 ...
- 【练习】显示MYSQL客户机选项
[oracle@enmo ~]$ mysql --help mysql Ver , for Linux (x86_64) using EditLine wrapper Copyright (c) , ...
- U盘无法拷贝超过4G的大文件
现在U盘的容量越来越大了,8G闪存满天飞,几乎已成“标配”,市面上再见难觅64M.128M等U盘的踪迹,可是细心的你也许已经发现,即使是8G或更大体积的U盘,仍然不能拷贝存储体积超过4G的大文件,这是 ...
- Oracle 事务
begin begin savepoint p1; DELETE FROM sys_re_xxx; //红色部分替换为需要一起执行的SQL即可 DELETE FROM SYS_xxxx; ...... ...
- Java学习一
Java程序的运行机制和JVM JVM(java 虚拟机) Java Virtual Machine java语言比较特殊,由Java语言编写的程序需要经过编译步骤, JDK java SE ...
- Magento修改css样式
Magento研究了第四天才开始搞明白怎么运行. 首先对于前端开发来说要修改样式的话需要运行: grunt less:luma 如果提示: 那就说明grunt配置的路径不对,默认是英文的,如果我们用中 ...
- 第五章_PHP流程控制
1.顺序结构 2.分支结构 2.1 if...else <?php $today=date("w"); //获取今天星期几 if($today==0){ echo 'Sund ...