内核驱动层与应用层的数据交互copy_to_usr和copy_from_usr


一、实现应用层和内核驱动层的数据交互

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>

#define BUF_LEN 		100		//内核空间大小

int major = 11; 		//主设备号
int minor = 0; 			//次设备号
int mychar_num = 1; 	//设备数量

struct cdev mydev; 		//每一类设备都有一个cdev结构体

char mydev_buf[BUF_LEN];//内核空间
int curlen = 0; 		//有效数字从零开始


int mychar_open(struct inode *pnode, struct file *pfile)
{
   
	printk("mychar open is called!!!\n");
	return 0;
}

ssize_t mychar_read(struct file *pfile, char __user *pbuf, size_t count, loff_t *ppos)
{
   
	int size = 0;		//记录读走多少个字节
	int ret = 0;

	if (count > curlen)
	{
   
		size = curlen;
	}
	else
	{
   
		size = count;
	}


	ret = copy_to_user(pbuf, mydev_buf, size);
	if (ret)
	{
   
		printk("copy_to_user failed!\n");
		return -1;
	}

	memcpy(mydev_buf, mydev_buf + size, curlen - size);   //把在mydev_buf中剩下有效数据存放在以mydev_buf的首地址中
	curlen -= size; 			//读走的字节要被减去

	return size;
}

ssize_t mychar_write(struct file *pfile, const char __user *pbuf, size_t count, loff_t *ppos)
{
   
	int size = 0;
	int ret = 0;

	if (count < BUF_LEN - curlen)
	{
   
		size = count;
	}
	else
	{
   
		size = BUF_LEN - curlen;
	}

	ret = copy_from_user(mydev_buf + curlen, pbuf, size);
	if (ret)
	{
   
		printk("copy_from_user failed!\n");
		return -1;
	}

	curlen += size;

	return size;
}

int mychar_close(struct inode *pnode, struct file *pfile)
{
   

	printk("mychar clsoe is called!!!\n");
	return 0;
}

/* 对字符设备的操作函数 */
struct file_operations myops = {
   
	.owner = THIS_MODULE,
	.open = mychar_open,
	.write = mychar_write,
	.read = mychar_read,
	.release = mychar_close,
};

int __init mychar_init(void)
{
   
	int ret = 0;

	dev_t devno = MKDEV(major, minor); 										//组合设备号

	ret = register_chrdev_region(devno, mychar_num, "mychar"); 				//手动申请设备号
	if (ret) 																//返回值为0表示申请成功
	{
   
		ret = alloc_chrdev_region(&devno, 0, mychar_num, "mychar"); 	//申请失败则系统自动分配
		if (ret)
		{
   
			printk("get devno failed!\n");
			return -1;
		}
		major = MAJOR(devno); 												//从系统分配的设备号中取出主设备号
		minor = MINOR(devno); 												//从系统分配的设备号中取出次设备号
		devno = MKDEV(major, minor); 										//组合设备号
	}

	/* 使得设备具有myops中的函数操作方法 */
	cdev_init(&mydev, &myops);
	mydev.owner = THIS_MODULE;

	/* 将设备号为devno的这个设备(mydev)添加到内核(内核hash链表中) */
	cdev_add(&mydev, devno, mychar_num);


	printk("hello world!\n");
	return 0;
}

void __exit mychar_exit(void)
{
   
	dev_t devno = MKDEV(major, minor); 					//组合设备号
	
	unregister_chrdev_region(devno, mychar_num); 		//注销设备号

	/* 从内核中删除mydev这个设备 */
	cdev_del(&mydev);
	printk("bye bye!!!\n");
}

MODULE_LICENSE("GPL");
module_init(mychar_init);
module_exit(mychar_exit);

收获:
1.本程序中主要涉及到mychar_read函数和mychar_write函数,其余和上一个例程完全一致
2.首先要应用层和内核驱动进行数据交互,那么需要搞清楚的就是数据空间和数据流向即可
(1)数据空间:驱动层定义了一个char mydev_buf[BUF_LEN]类型的空间,其中BUF_LEN=100
(2)数据流向:
在mychar_read函数中:
首先判断应用层需要读取的字节数count与目前内核空间可读取字节数curlen的大小,
如果想要读取的字节数>内核目前的字节数curlen,那么全部读走,并且curlen清零
如果想要读取的字节数<内核目前的字节数curlen,那么读取count个字节,并且curlen-=count;那么此时mydev_buf中的前count个数据是被读走的(对于驱动无意义了),那么此时需要将count+1处的数据统一向前平移到0位置处,读取函数为copy_to_usr();
在mychar_write函数中:
首先需要判断想要写入到内核空间的字节数count与内核空间剩余资源数BUF_LEN-curlen的大小
如果count < BUF_LEN-curlen,那么直接在curlen+1处继续写入即可,可以全部写入
如果count > BUF_LEN-curlen,那么最多就只能写BUF_LEN-curlen个字节的数据了
写入后记得给curlen+=count;
写入函数为copy_from_usr();

二、应用层

#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>

int main(int argc, const char *argv[])
{
   
	int fd = -1;
	char buf[6];

	if (argc < 2)
	{
   
		printf("the arguement is too few!\n");
		return -1;
	}
	fd = open(argv[1], O_RDWR);
	if(fd < 0)
	{
   
		printf("fail to open %s\n", argv[1]);
		return -1;
	}
	write(fd, "hello", 6);
	read(fd, buf, 6);
	printf("buf = %s\n", buf);
	close(fd);
	fd = -1;

	return 0;
}

应用层程序的基本逻辑为,通过文件fd对设备进行读写操作,首先使用write对设备进行写操作,写入字符串"hello",其次使用read函数从内核中读取数据并进行打印。


总结

希望大家在条件允许的情况下还是需要亲自动手验证一下,这些比较基础的驱动程序代码不需要依赖硬件,所以一定得亲手验证一下!不懂的小伙伴可以评论区留言,博主知无不言,言无不尽!最后,各位小伙伴们如果有收获,可以点赞收藏哦,你们的认可是我创作的动力,一起加油!

最近更新

  1. TCP协议是安全的吗?

    2024-02-23 16:32:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-23 16:32:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-23 16:32:02       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-23 16:32:02       20 阅读

热门阅读

  1. Cookies

    2024-02-23 16:32:02       28 阅读
  2. kafka消费消息并对消息进行RSA公钥解密

    2024-02-23 16:32:02       31 阅读
  3. 【Ant Design】【List】

    2024-02-23 16:32:02       29 阅读
  4. 服务器防火墙的应用技术有哪些类型?

    2024-02-23 16:32:02       24 阅读
  5. 快速上手vue指南

    2024-02-23 16:32:02       38 阅读
  6. 【LeetCode】升级打怪之路 Day 03:链表 part 1

    2024-02-23 16:32:02       37 阅读
  7. HarmonyOS Stage模型 权限申请

    2024-02-23 16:32:02       28 阅读
  8. 观察者模式

    2024-02-23 16:32:02       30 阅读
  9. phpspreadsheet导出数据和图片到excel

    2024-02-23 16:32:02       31 阅读