
应用层和内核层数据传输-Linux驱动学习(3)
发布日期:2021-05-20 13:49:40
浏览次数:16
分类:博客文章
本文共 5218 字,大约阅读时间需要 17 分钟。
应用层和内核层的数据传输
【学习笔记】
1、应用层和内核层数据传输常用的函数
在Linux中,文件对应的操作有:打开、关闭、读写,同样与文件类似,设备节点对应的操作有:打开、关闭、读写
如果我们在应用层使用系统IO对设备节点进行打开、关闭、读写等操作会发生什么?
(1)当我们在应用层对设备节点进行read操作时,就会触发驱动里边的read这个函数。
ssize_t(*read)(struct file*, char_user*, size_t, loff_t*);#这里(*read)是函数名字,可以自定义,下面的都是如此
(2)当我们在应用层对设备节点进行write操作时,就会触发驱动里边的write这个函数。
ssize_t(*write)(struct file*, const char _user*, size_t, loff_t*);
(3)当我们在应用层对设备节点进行poll/select操作时,就会触发驱动里边的poll这个函数。
unsigned_t(*poll)(struct file*, struct poll_table_struct*);
(4)当我们在应用层对设备节点进行ioctl操作时,就会触发驱动里边的ioctl这个函数。
long(*unlocked_ioctl)(struct file*, unsigned int, unsigned long);
(5)当我们在应用层对设备节点进行open操作时,就会触发驱动里边的open这个函数。
int(*open)(struct inode*, struct file*);
(6)当我们在应用层对设备节点进行close操作时,就会触发驱动里边的release这个函数。
int(*release)(struct inode*, struct file*);
2、应用层调用驱动的例子
驱动层:驱动file_operations.c
#include#include //杂项设备驱动需要增加两个头文件#include #include int misc_open(struct inode *inode, struct file *file){//(*open)函数实现 printk("hello misc_open\n"); return 0;}int misc_release(struct inode *inode, struct file *file){//(*release)函数实现 printk("bye bye\n"); return 0;}ssize_t misc_read(struct file *file, char _user *ubuf, size_t size, loff_t *loff_t){ printk("hello read\n"); return 0;}ssize_t misc_write(struct file *file, const char _user *ubuf, size_t size, loff_t *loff_t){ printk("hello write\n"); return 0;}//第2步:填充文件操作集struct file_operations misc_fops = { .owner = THIS_MODULE, //这里简单的填充一个owner .open = misc_open, //根据我们自定义的函数名来填充 .release = misc_release, .read = misc_read, .write = misc_write};//第1步:填充杂项设备结构体struct miscdevice misc_dev = { .minor = MISC_DYNAMIC_MINOR, //次设备号,动态分配 .name = "hello_misc", //设备节点的名字 .fops = &misc_fops //填充文件操作集};//第3步;注册到内核static int misc_init(void){ int ret; ret = misc_register(&misc_dev);//存储注册的地址 //判断是否注册成功 if(ret < 0){ printk("misc registe is error\n"); return -1; } printk("misc registe is successful\n"); //内核里不能使用c语言库,所以不能用printf return 0;}//卸载驱动static void misc_exit(void){ misc_deregister(&misc_dev); printk("misc bye bye\n");}//入口和出口module_init(misc_init);module_exit(misc_exit);//声明许可证MODULE_LICENSE("GPL");
应用层:app.c上层函数
#include#include #include #include #include int main(int argc, char *argv[]){//如果打开设备节点成功,这会调用驱动里边的misc_open()函数 int fd; char buf[64] = {0}; fd = open("/dev/hello_misc",O_RDWR);//open the device node if(fd < 0){ //determine whether the opening is successful perror("open error\n");//和printf用法相似 return fd; } read(fd,buf,sizeof(buf));//读取设备节点 //write(fd,buf,sizeof(buf));//写设备节点 close(fd);//关闭节点 return 0;}
如下图,设备节点是内核层和应用层的桥梁
如果驱动文件中相应的操作集没有填充,而应用层又调用了对应的函数,那么将什么都不会发生,也不会报错。
应用层和数据层不能直接进行数据传输,需要使用其他函数
//用户层向内核层传输数据static inline long copy_from_user(void *to, const void _user *from, unsigned long n);//内核层向用户层传输数据static inline long copy_to_user(void *to, const void *from, unsigned long n);
注意这两个函数只能在驱动里边用,不能在应用层使用。
加入数据传输函数后的代码
file_operation.c
#include#include //杂项设备驱动需要增加两个头文件#include #include int misc_open(struct inode *inode, struct file *file){//(*open)函数实现 printk("hello misc_open\n"); return 0;}int misc_release(struct inode *inode, struct file *file){//(*release)函数实现 printk("bye bye\n"); return 0;}ssize_t misc_read(struct file *file, char _user *ubuf, size_t size, loff_t *loff_t){ char kbuf[64] = "mydate";//定义字符串,能够在应用层读取到 if(copy_to_user(ubuf, kbuf, strlen(kbuf)) != 0){//判断是否成功向应用层传输数据 printk("copy_to_user error\n"); return -1; } return 0;}ssize_t misc_write(struct file *file, const char _user *ubuf, size_t size, loff_t *loff_t){ char kbuf[64] = {0}; if(copy_from_user(kbuf, ubuf, size) != 0){//判断是否成功向应用层传输数据 printk("copy_from_user error\n"); return -1; } printk("kbuf is %s\n",kbuf); return 0;}//第2步:填充文件操作集struct file_operations misc_fops = { .owner = THIS_MODULE, //这里简单的填充一个owner .open = misc_open, //根据我们自定义的函数名来填充 .release = misc_release, .read = misc_read, .write = misc_write};//第1步:填充杂项设备结构体struct miscdevice misc_dev = { .minor = MISC_DYNAMIC_MINOR, //次设备号,动态分配 .name = "hello_misc", //设备节点的名字 .fops = &misc_fops //填充文件操作集};//第3步;注册到内核static int misc_init(void){ int ret; ret = misc_register(&misc_dev);//存储注册的地址 //判断是否注册成功 if(ret < 0){ printk("misc registe is error\n"); return -1; } printk("misc registe is successful\n"); //内核里不能使用c语言库,所以不能用printf return 0;}//卸载驱动static void misc_exit(void){ misc_deregister(&misc_dev); printk("misc bye bye\n");}//入口和出口module_init(misc_init);module_exit(misc_exit);//声明许可证MODULE_LICENSE("GPL");
app.c
#include#include #include #include #include int main(int argc, char *argv[]){//如果打开设备节点成功,这会调用驱动里边的misc_open()函数 int fd; char read_buf[64] = {0}; char write_buf[64] = "write date"// fd = open("/dev/hello_misc",O_RDWR);//open the device node if(fd < 0){ //determine whether the opening is successful perror("open error\n");//和printf用法相似 return fd; } read(fd,read_buf,sizeof(read_buf));//读设备节点 printf("read_buf is %s\n",read_buf);//打印从内核层读取的内容 write(fd,write_buf,sizeof(write_buf));//将数据写入设备节点,将应用层数据传入的内核层 close(fd);//关闭节点 return 0;}
整理自
发表评论
最新留言
网站不错 人气很旺了 加油
[***.192.178.218]2025年04月19日 23时23分01秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
什么是redis的缓存雪崩, 穿透, 击穿?
2019-03-16
【转载】DSP基础--定点小数运算
2019-03-16
idea thymeleaf页面变量报错解决
2019-03-16
云游戏,打响5G第一战
2019-03-16
Docker 拉取镜像速度太慢
2019-03-16
HUAWEI防火墙通过IKE方式协商IPSec隧道(采用预共享密钥认证)
2019-03-16
计网复习3
2019-03-16
JDK动态代理的实现原理
2019-03-16
Spring Security 架构与源码分析
2019-03-16
教程丨使用MeterSphere做Dubbo接口测试
2019-03-16
【毕设-STM32f103寄存器版本】智能防盗系统
2019-03-16
勒索病毒Kraken2.0.7分析
2019-03-16
MySQL错误1366处理方法
2019-03-16
pytorch深度学习中每个epoch运行时间的统计代码
2019-03-16
VxWorks 操作系统学习笔记
2019-03-16
驱动程序之_1_字符设备_13_USB设备_1_基本概念
2019-03-16
wxPython下载安装教程
2019-03-16
HERest源码解析
2019-03-16