个人声明:转发请注明出处,个人原创,实属不易。本人水平有限,文章若有不妥之处,还请留言批评指正,不胜感激。
本文参考博客并做了一些延伸。
前言
(废话再说一遍)Linux系统下一切皆文件,所以我们对外围设备的操作也就是对Linux系统中/dev/下设备文件的open、read、write和close。但是,为什么操作这些文件的open、read、write和close就可以对外围设备进行操作呢???
-
用户空间与内核空间的通信
本文主要介绍copy_to_user和copy_from_user,这两种通信方式都是单工的,copy_to_user只能从内核空间发送数据到用户空间,而copy_from_user只能从用户空间发送数据到内核空间。 -
用户空间的open、read、write和close与内核驱动中files_operations结构体内的操作集的关系
用户空间对/dev/下文件进行open、read、write和close操作,就会调用内核驱动中files_operations结构体里面对应的open、read、write和release函数接口。 -
测试代码
内核驱动files_operations结构体的操作集函数
static int ap3216c_open(struct inode *nd, struct file *filp)
{
int ret = 0;
unsigned char val=0;
filp->private_data = &ap3216cdev;
printk("%s:%s %d \r\n",__FILE__,__func__,__LINE__);
/* 初始化AP3216C */
ap3216c_write_reg(&ap3216cdev,AP3216C_SYSTEMCONG,0x4); /* 复位 */
mdelay(50);
ap3216c_write_reg(&ap3216cdev,AP3216C_SYSTEMCONG,0x3); /* 复位 */
val = ap3216c_read_reg(&ap3216cdev,AP3216C_SYSTEMCONG);
printk("AP3216C_SYSTEMCONG reg = %#x\r\n",val);
return ret;
}
static int aps216c_release(struct inode *nd, struct file *filp)
{
int ret = 0;
printk("%s:%s %d \r\n",__FILE__,__func__,__LINE__);
return ret;
}
/* fpos */
static struct file_operations ap3216c_fops = {
.owner = THIS_MODULE,
.open = ap3216c_open,
.read = ap3216c_read,
.write = ap3216c_write,
.release = aps216c_release,
};
用户空间的APP测试程序(部分)
/* open ap3216c driver */
fd = open(filename,O_RDWR);
printf("ap3216c is open!\r\n");
if(fd<0)
{
printf("file %s open failed!\r\n",filename);
return -1;
}
while(i<5)
{
ret = read(fd,data,sizeof(data));
if(ret==0)
{
ir = data[0];
ps = data[1];
als = data[2];
printf("AP3216C ir = %d, ps = %d, als = %d\r\n",ir,ps,als);
}
usleep(2000000); /* 2000ms */
i++;
}
printf("ap3216c read!\r\n");
if(ret<0)
{
printf("read data failed!\r\n");
close(fd);
return -1;
}
ret = close(fd); /* close file */
if(fd<0)
{
printf("file %s close failed!\r\n",filename);
return -1;
}
printf("ap3216c is closed!\r\n");
4. 测试结果
/home/***/Linux/IMX6ULL/linux_drivers/7_i2c/ap3216c.c:ap3216c_open 154
AP3216C_SYSTEMCONG reg = 0x3
ap3216c is open!
/home/***/Linux/IMX6ULL/linux_drivers/7_i2c/ap3216c.c:ap3216c_read 140
AP3216C ir = 0, ps = 0, als = 0
/home/***/Linux/IMX6ULL/linux_drivers/7_i2c/ap3216c.c:ap3216c_read 140
AP3216C ir = 11, ps = 161, als = 177
/home/***/Linux/IMX6ULL/linux_drivers/7_i2c/ap3216c.c:ap3216c_read 140
AP3216C ir = 35, ps = 159, als = 181
/home/***/Linux/IMX6ULL/linux_drivers/7_i2c/ap3216c.c:ap3216c_read 140
AP3216C ir = 0, ps = 158, als = 181
/home/***/Linux/IMX6ULL/linux_drivers/7_i2c/ap3216c.c:ap3216c_read 140
AP3216C ir = 18, ps = 138, als = 187
/home/***/Linux/IMX6ULL/linux_drivers/7_i2c/ap3216c.c:aps216c_release 167
ap3216c is closed!
总结
用户空间用read读取一次ap3216c的数据,就会内核驱动中file_operations结构体里面的read函数接口,所以终端先打印输出printk语句,最终内核驱动把获取到的数据通过copy_to_user发送给用户空间,至此用户空间就完成了对外围设备数据的读取操作。同样地,当应用层调用open函数、write函数和close函数都会调用内核ap3216c驱动中file_operations结构体对应的open函数、write函数和release函数。