I2c_test.c + i2c_dev.c +i2c_s3c3410.c 构成的i2c设备的调用链
来源:互联网 发布:利拉德体测数据 编辑:程序博客网 时间:2024/05/17 08:52
2011.11.21 星期一
I2c_test.c + i2c_dev.c +i2c_s3c3410.c 构成的i2c设备的调用链。
一、从用户空间程序i2c_test.c开始进行流程
//i2c_test.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <stdio.h>
#include <linux/types.h>
#include <assert.h>
#include <string.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#define SLAVE_ADDRESS 0x70
int main(void)
{
struct i2c_rdwr_ioctl_data TP_data;
unsigned int i2c_fd;
int ret;
i2c_fd = open("/dev/i2c/0", O_RDWR);
if (!i2c_fd)
{
printf("Error on opening the device file\n");
return 0;
}
while(1)
{
TP_data.nmsgs = 2;//因为读时序要两次,所以设为2,有几个start nmsgs就设置为几
TP_data.msgs = (struct i2c_msg *)malloc(TP_data.nmsgs * sizeof(struct i2c_msg));
// printf("4");
if (!TP_data.msgs)
{
printf("Memory alloc error\n");
close(i2c_fd);
return 0;
}
ioctl(i2c_fd, I2C_TIMEOUT, 2);//设置超时时间
ioctl(i2c_fd, I2C_RETRIES, 1);//设置重发次数
/*read data from register*/
TP_data.nmsgs = 2;//读时序要两次过程,要发两次I2C消息
TP_data.msgs[0].len = 1;//信息长度为1,第一次要写需要读入的寄存器地址
TP_data.msgs[0].addr = 0x5c;//设备地址
TP_data.msgs[0].flags = 0;//写命令,看读时序理解
TP_data.msgs[0].buf = (unsigned char*)malloc(1);
TP_data.msgs[0].buf[0] = 0x02;//信息值
TP_data.msgs[1].len = 1;
TP_data.msgs[1].addr = 0x5c;
TP_data.msgs[1].flags = I2C_M_RD;//读命令
TP_data.msgs[1].buf = (unsigned char*)malloc(1);
TP_data.msgs[1].buf[0] = 0;//先清空要读的缓冲区
ret = ioctl (i2c_fd, I2C_RDWR, (unsigned long)&TP_data);//好了,读吧
if (ret < 0){
printf ("ioctl read error\n");
}
//printf("read %02x from e2prom address %02x\n",e2prom_data.msgs[1].buf[0], reg_address);
printf("touch num is %d\n",TP_data.msgs[1].buf[0]);
}
close(i2c_fd);
return(0);
}
1、 在用户空间程序 i2c_test.c 中使用i2c_fd = open("/dev/i2c/0", O_RDWR);来打开设备文件,获得文件描述符来进一步对设备进行读写操作。这里的“/dev/i2c/0”据说是在i2c_dev.c中进行注册了,但是目前我没有发现是怎么注册的。这个需要确认一下。
2、 构造了两个结构体i2c_rdwr_ioctl_data和i2c_msg结构体定义如下:
struct i2c_rdwr_ioctl_data {
struct i2c_msg __user *msgs; /* pointers to i2c_msgs */
__u32 nmsgs; /* number of i2c_msgs */
};
struct i2c_msg {
_ _u16 addr; /* slave address */
_ _u16 flags; /* 标志(读、写) */
_ _u16 len; /* msg length */
_ _u8 *buf; /* pointer to msg data */
};
这两个结构体包含了上层调用的参数信息,为操作设备做准备。
3、 ioctl (i2c_fd, I2C_RDWR, (unsigned long)&TP_data);利用ioctl这个函数,对设备进行读写,其中i2c_fd为open中打开的设备文件描述符,I2C_RDWR为命令,(unsigned long)&TP_data为向设备文件传输的信息,其中包含的地址信息,读写信息。
二、进入到设备驱动程序i2c_dev.c
这里有两个问题:1、不知道i2c_test.c中调用open会不会调用到此文件中设备结构体中的open相关函数。
2、 不知道设备文件“dev/i2c/0”在哪里注册的,参考资料上说是在这个文件上注册的但是没有找到。在i2cdev_attach_adapter中进行了注册
I2c_test.c中调用ioctl最终就会调用到这个函数
static int i2cdev_ioctl (
struct inode *inode,
struct file *file, //文件描述符,也就是打开/dev/下创建的设备文件所返回的文件描述符
unsigned int cmd,//命令
unsigned long arg )//从上层传输过来的参数,视cmd的不同含义有所不同
{
struct i2c_client *client = (struct i2c_client *)file->private_data;
struct i2c_rdwr_ioctl_data rdwr_arg;
struct i2c_smbus_ioctl_data data_arg;
union i2c_smbus_data temp;
struct i2c_msg *rdwr_pa; //SMBUS的数据结构体
u8 __user **data_ptrs;
int i,datasize,res;
unsigned long funcs;
//打印信息到设备的LOG中
dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",
cmd, arg);
//根据不同的命令做响应
switch ( cmd ) {
//设备的读写操作,注意传入参数的类型
case I2C_RDWR:
if (copy_from_user(&rdwr_arg,
(struct i2c_rdwr_ioctl_data __user *)arg,
sizeof(rdwr_arg))) //arg是从用户空间传过来的TP_data,rdwr_arg是用户空间,但&rdwr_arg是内核空间,但不知为啥没有先申请内核内存。
return -EFAULT;
//要操作的数据包(msg包)超过最大限制
if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
return -EINVAL;
//申请内存
rdwr_pa = (struct i2c_msg *)
kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg),
GFP_KERNEL);//申请了结构体i2c_msg大小的内核内存,这里要注意一点,申请的内存是装载i2c_msg这个结构体的,其成员buf为指针,申请的内核内存只是装载指针变量的,所以此指针所指向的空间还是用户空间内存
if (rdwr_pa == NULL) return -ENOMEM; //申请失败
//将要操作的数据用用户层复制到内核层
if (copy_from_user(rdwr_pa, rdwr_arg.msgs,
rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {
kfree(rdwr_pa);
return -EFAULT;
}
//申请一组指针,每一个元素指向一个msg包,这里也是申请的是装载指针变量的内核内存,所以指针指向的空间仍然是用户空间
data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);//中间的*是乘号
if (data_ptrs == NULL) {
kfree(rdwr_pa);
return -ENOMEM;
}
res = 0;
for( i=0; i<rdwr_arg.nmsgs; i++ ) {
if ((rdwr_pa[i].len > 8192) || //要操作的数据不能大于8K
(rdwr_pa[i].flags & I2C_M_RECV_LEN)) {
res = -EINVAL;
break;
}
data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf; //指针和用户层数据缓存关联
//根据长度申请内存,注意,此时buf地址关联上的是新申请的内存的地址
rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);
if(rdwr_pa[i].buf == NULL) {
res = -ENOMEM;
break;
}
//将要操作的用户数据COPY到内核缓存中
//如果是读操作,那么这里复制的数据是没有意义的
//如果是写操作,那么这里就将要写入的数据给复制进了缓存中了
if(copy_from_user(rdwr_pa[i].buf,
data_ptrs[i],
rdwr_pa[i].len)) {
++i;
res = -EFAULT;
break;
}
} //for结束
//如果以上操作失败(一般是申请内存失败),则释放内存并返回
if (res < 0) {
int j;
for (j = 0; j < i; ++j)
kfree(rdwr_pa[j].buf);
kfree(data_ptrs);
kfree(rdwr_pa);
return res;
}
//传输数据
res = i2c_transfer(client->adapter,
rdwr_pa,
rdwr_arg.nmsgs);
while(i-- > 0) {
//如果是读操作,则把数据复制出来
if( res>=0 && (rdwr_pa[i].flags & I2C_M_RD)) {
if(copy_to_user(
data_ptrs[i],
rdwr_pa[i].buf,
rdwr_pa[i].len)) {
res = -EFAULT;
}
}
kfree(rdwr_pa[i].buf); //释放内存
}
kfree(data_ptrs);
kfree(rdwr_pa);
return res;
}
这个函数的作用前面已经讲过了,这里的核心函数就是 res = i2c_transfer(client->adapter, rdwr_pa,rdwr_arg.nmsgs);关于这个函数如何往下挖前面也已经讲过了,关于参数client->adapter还是有疑惑。不明白适配器是怎么个调用关系,在i2c_s3c2410.c中挂载了适配器。在这个文件中设备驱动
//设备驱动
static struct i2c_driver i2cdev_driver = {
.driver = {
.name = "dev_driver",
},
.id = I2C_DRIVERID_I2CDEV,
.attach_adapter = i2cdev_attach_adapter,
.detach_adapter = i2cdev_detach_adapter,
.detach_client = i2cdev_detach_client,
};
这其中的几个函数什么时候调用还是不清楚。
- I2c_test.c + i2c_dev.c +i2c_s3c3410.c 构成的i2c设备的调用链
- android设备service从C到java API的构成
- C语言程序的构成
- I2c-dev.c的分析
- Problem C: 字符构成的图形
- i2c.c
- I2C通讯的C语言程序
- I2C通讯的C语言程序
- I2C通讯的C语言程序
- Objective-C中对IPhone设备震动的调用
- MySQL的c调用
- 调用c的printf
- Linux下C开发环境的构成和安装
- Linux下C开发环境的构成和安装
- Linux下C开发环境的构成和安装
- Linux下C开发环境的构成和安装
- Linux下C开发环境的构成和安装
- Linux操作系统下C开发环境的构成与安装
- E2015 Ambiguity between 'ULONG_PTR' and 'Wmplib_tlb::ULONG_PTR' 这个错误怎么解决?终极解决办法
- TableRow平分每列的问题
- Java环境变量设置
- git/github学习笔记
- hdu 2065 红色病毒
- I2c_test.c + i2c_dev.c +i2c_s3c3410.c 构成的i2c设备的调用链
- C#模拟键盘鼠标事件 SendKeys 的特殊键代码表
- python json,copy
- shell脚本入门
- spring3.1+hibernate3.6.5整合xml
- CVS使用手册
- Android 软件开发之数据的 新建 储存 读取 删除 详解(转)
- 对migor_ts.c的修改
- GDB十分钟教程