应用层与内核层进行数据交互

8 、 应用层与内核层进行数据交互

还是以上节的杂项设备为例

因为linux一切皆文件、所以驱动设备在linux中也是以文件的方式存在的。

应用层与内核层数据交互也是以文件方式进行

struct file_operations 文件操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0E8hrXcI-1618902071139)(linux驱动.assets/image-20210411205813611.png)]

当应用层使用open打开设备文件时,就会触发驱动设备中的open函数

int (*open) (struct inode *, struct file *);

当应用层使用close关闭设备文件时,就会触发驱动设备中的release函数

int (*release) (struct inode *, struct file *);

当应用层使用read读取设备文件时,就会触发驱动设备中的read函数

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

当应用层使用write写入设备文件时,就会触发驱动设备中的write函数

ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

当应用层使用ioctl操作设备文件时,就会触发驱动设备中的unlocked_ioctl函数

long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2RGCFpZA-1618902071142)(linux驱动.assets/image-20210411205354737.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rT8SxmQF-1618902071144)(linux驱动.assets/file_operation(文件操作集)]-1618360706452.png)

内核空间数据copy到用户空间

copy_from_user函数目的是从用户空间拷贝数据到内核空间,失败返回没有被拷贝的字节数,成功返回0。从用户空间拷贝数据到内核中时必须非常小心,如果用户空间的数据地址是个非法的地址,或是超出用户空间的范围,或是那些地址还没有被映射到,都可能对内核产生很大的影响。copy_from_user函数的功能就不只是从用户空间拷贝数据那样简单了,它还要做一些指针检查以及处理这些问题的方法。

copy_from_user 原型

unsigned long copy_from_user(void *to, const void __user *from, unsigned long n)
{
	if (likely(access_ok(VERIFY_READ, from, n)))
		n = __copy_from_user(to, from, n);
	else
		memset(to, 0, n);
	return n;
}

用户空间copy到内核空间

copy_to_user函数则是从内核空间拷贝内容到用户空间,用户空间的进程无法直接访问内核空间的内容。这个函数做了数据合法判断。然后进行拷贝。 成功返回0, 失败返回非0

copy_to_user

unsigned long copy_to_user(void __user *to, const void *from, unsigned long n)
{
	if (likely(access_ok(VERIFY_WRITE, to, n)))
		n = __copy_to_user(to, from, n);
	return n;
}

实例

驱动程序

#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>	//杂项设备的头文件struct miscdevice
#include <linux/fs.h>		//文件操作的头文件  struct file_operations 
#include <linux/uaccess.h>  //这个是copy_to/from_user 的头文件
//第二步填充file_operations结构体
ssize_t misc_read (struct file *file, char __user * user, size_t size, loff_t *loff_t)
{
	char buf[64] = "hello world";
	printk("misc_read!\n");
	
//	copy_to_user(void __user * to, const void * from, unsigned long n)  将数据由内核空间copy到用户空间
// 成返回0  失败返回非0
	if (copy_to_user(user, buf, strlen(buf)) != 0)  //将内核空间数据copy到user空间
	{
		printk("copy to user is error!\n");
		return -1;
	}
	printk("copy to user is success!\n");

	return 0;
}
ssize_t misc_write (struct file * file, const char __user *user, size_t n, loff_t *loff_t)
{
	char buf[64] = {0};
	
	printk("misc_write!\n");
	
	if (copy_from_user(buf, user, n) != 0) //从user空间copy数据到内核空间
	{
		printk("copy from user is error!\n");
		return -1;
	}
	printk("copy from user is success!\n");
	printk("misc write :%s\n", buf);
	return 0;
}
int misc_open (struct inode *inode, struct file *file)
{
	printk("misc_open!\n");
	return 0;
}
int misc_release (struct inode *inode, struct file *file)
{
	printk("misc_release!\n");
	return 0;
}

struct file_operations misc_fops = {
	.owner = THIS_MODULE,			//	当前用户拥有		
	.open = misc_open,				//open
	.write = misc_write,			//write
	.read = misc_read				//read
};
//第一步填充miscdevice结构体
struct miscdevice miscdev = {
	.minor = MISC_DYNAMIC_MINOR,  	//自动获取次设备号
	.name = "hello_misc",  			//杂项设备名称
	.fops = &misc_fops				//文件操作集
};
static int misc_init(void)
{
	int ret;
	//第三步 注册杂项设备并生成设备节点
	ret = misc_register(&miscdev);
	if (0 > ret)
	{	
		printk("misc register is error!\n");
		return -1;
	}
	printk("misc register is success!\n");
	return 0;
}
static void misc_exit(void)
{
	misc_deregister(&miscdev);  //卸载
	printk("byb byb\n");  // 这里打印函数需要用printk 因为printf是C库函数
}
module_init(misc_init);  		//入口
module_exit(misc_exit);			//出口
MODULE_LICENSE("GPL");			//协议声明

makefile

# -m 就是说要把驱动编译成模块
obj-m += misc.o
# 内核路径
KDIR := /home/now/kernel3.0/iTop4412_Kernel_3.0
#获取当前路径
PWD = $(shell pwd)
all:
	make -C $(KDIR) M=$(PWD) modules

应用层程序

#include<stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
int main(int argc,char *argv[])
{
	int fd;
	char buf[64] ={0};
	char *str = "hello world";
	fd = open(argv[1], O_RDWR);
	if (fd == -1)
	{
		perror("open");
		return -1;
	}
	int ret = read(fd, buf, sizeof(buf));
	if (ret == -1)
	{
		perror("read");
		return -1;
	}
	printf("read:%s\n", buf);
	ret = write(fd, str, strlen(str));
	if (ret == -1)
	{
		perror("write");
		return -1;
	}
	close(fd);
	return 0;
}

首先在ubuntu上执行make, 编译出.ko文件,然后将ko文件copy到开发板,执行insmod加载驱动

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RBoZBkft-1618902071147)(linux驱动.assets/image-20210412093023869.png)]

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值