1.代码
驱动代码:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>#define CHREDEVBASE_MAJOR 200 // 主设备号
#define CHRDEVNAME "chrdevbase" // 名字static char kernaldata[20] = {"kerndata"};static int chrdevbase_open(struct inode* inode, struct file* filp){printk("chrdevbase_open\r\n");return 0;
}static int chrdevbase_release(struct inode* inode, struct file* filp){//printk("chrdevbase_release\r\n");return 0;
}static ssize_t chrdevbase_read(struct file* filp, __user char* buf, size_t count, loff_t* ppos){int ret = 0;// 应用程序不能直接访问内核,必须借助其他函数ret = copy_to_user(buf, kernaldata, count); // 将内核数据copy到用户if(ret < 0){printk("copy to user error\r\n");return -1;} //printk("hrdevbase_read\r\n");return 0;
}static ssize_t chrdevbase_write(struct file* filp, const char __user *buf, size_t count, loff_t* ppos){//printk("chrdevbase_write\r\n");int ret = 0;ret = copy_from_user(kernaldata, buf, count);if(ret < 0){printk("copy from user error\r\n");return -1;}printk("write msg is %s\r\n", kernaldata);return 0;
}// 字符设备操作集合
static struct file_operations chrdevbase_fops={.owner = THIS_MODULE, // 属于这个驱动模块.open = chrdevbase_open,.release = chrdevbase_release,.read = chrdevbase_read,.write = chrdevbase_write,
};static int __init chrdevbase_init(void){ int ret = 0;printk("chrdevbase_init\r\n");// 注册字符设备ret = register_chrdev(CHREDEVBASE_MAJOR, CHRDEVNAME, &chrdevbase_fops);if(ret < 0){printk("chrdevbase init failed\r\n");unregister_chrdev(CHREDEVBASE_MAJOR, CHRDEVNAME);}return 0;
}static void __exit chrdevbase_exit(void){printk("chrdevbase_exit\r\n");
}// 核心修正点:添加以下声明
MODULE_LICENSE("GPL"); // 必须声明许可证(例如GPL)
MODULE_AUTHOR("Narnat"); // 可选:作者信息
MODULE_DESCRIPTION("chrdevbase"); // 可选:模块描述// 模块入口与出口
module_init(chrdevbase_init);
module_exit(chrdevbase_exit);
app代码:
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>int main(int argc, char* argv[]){int ret = 0;int fd;char readbuf[10], writebuf[50];static char userdata[] = {"helloa"};if(argc != 3){printf("ERROR USAGE!\r\n");return -1;}char* filename;filename = argv[1];fd = open(filename, O_RDWR);if(fd < 0){printf("cant open file %s\r\n", filename);return -1;}if(atoi(argv[2]) == 1){ // 读ret = read(fd, readbuf, sizeof(readbuf));if(ret < 0){printf("read file %s failed\r\n", filename);return -1;}else{printf("RERAD DATA: %s\r\n", readbuf);}}if(atoi(argv[2]) == 2){ // 读memcpy(writebuf, userdata, sizeof(userdata));ret = write(fd, writebuf, sizeof(userdata));if(ret < 0){printf("write file %s failed!\r\n", filename);}}close(fd);return 0;
}
2.实验现象:
3.总结分析:
用户层在调用open函数打开设备节点后,应用层上的write和read函数调用的是我们自己实现的驱动函数,同理在linux操作系统上调用write和read函数去操作txt文件的时候调用的是系统实现的函数
需要注意的是:
应用层没办法直接读取或写入数据到内核里,所以要借助接口函数copy_to_user、copy_from_user函数去做
app层往内核写数据要注意安全严谨,容易发生缓冲区溢出