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层往内核写数据要注意安全严谨,容易发生缓冲区溢出