广告网站模板,汕头网站建设方案开发,wordpress侧边栏编辑,聚名网域名转出1设备号#xff1a; cat /proc/devices
编写驱动模块需要要想加载到内核并与设备正常通信#xff0c;那就需要申请一个设备号#xff0c;用cat /proc/devices可以查看已经被占用的设备号 设备号有什么用#xff1f;不同设备其驱动实现不同用设备号去区分#xff0c;例如字…1设备号 cat /proc/devices
编写驱动模块需要要想加载到内核并与设备正常通信那就需要申请一个设备号用cat /proc/devices可以查看已经被占用的设备号 设备号有什么用不同设备其驱动实现不同用设备号去区分例如字符驱动键盘块设备驱动固态硬盘这两种设备不同驱动实现方式不同所以用不同主设备号区分什么会是从设备号例如串口一台电脑接入两根串口这俩串口用的驱动是一样的但是要区分不同的串口就用从设备号区分
2.注册节点
为什么要注册节点?Linux上一切皆文件例如你写了串口驱动你要调用接到你电脑上的串口串口接到你的电脑上电脑识别后就会创建这样一个节点供open函数打开串口做后续操作 目前刚学习是手动创建后面估计会用一些方法自动创建
3.实现流程
驱动代码
#include linux/module.h
#include linux/kernel.h
#include linux/init.h
#include linux/fs.h#define CHREDEVBASE_MAJOR 200 // 主设备号
#define CHRDEVNAME chrdevbase // 名字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){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);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);makefile:
# 设置绝对路径避免相对路径引发的错误
KERNELDIR : /home/saisi/RK3568/SDK/linux/rk3568_linux_sdk/kernel
CURRENT_PATH : $(shell pwd)# 必须明确指定架构和交叉编译器
ARCH : arm64
# 关键修正点使用ARM官方工具链的正确前缀和路径
TOOLCHAIN_PATH : /usr/local/arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-linux-gnu/bin
CROSS_COMPILE : $(TOOLCHAIN_PATH)/aarch64-none-linux-gnu-# 模块名称
obj-m : chrdevbase.obuild: kernel_moduleskernel_modules:$(MAKE) -C $(KERNELDIR) M$(CURRENT_PATH) ARCH$(ARCH) CROSS_COMPILE$(CROSS_COMPILE) modulesclean:$(MAKE) -C $(KERNELDIR) M$(CURRENT_PATH) ARCH$(ARCH) cleanrm -rf app
app:/usr/local/arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-gcc chrdevbaseApp.c -o appapp代码:
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include stdio.h
#include unistd.hint main(int argc, char* argv[]){int ret 0;int fd;char readbuf[10], writebuf[50];char* filename;filename argv[1];fd open(filename, O_RDWR);if(fd 0){printf(cant open file %s\r\n, filename);return -1;}ret read(fd, readbuf, 10);if(ret 0){printf(read file %s failed\r\n, filename);return -1;}ret write(fd, writebuf, 50);if(ret 0){printf(write file %s failed!\r\n, filename);}close(fd);return 0;
}驱动代码中register_chrdev和unregister_chrdev是用于注册字符驱动和注销字符驱动的函数也就是指明你的驱动类型其中要指定你的主设备号和名字把这些写好后挂载模块后能在系统里找到你注册的信息 lsmod显示的只是你的这个模块名字 注意注册完节点后我们的这个驱动会被当做一个文件就像linux上的摄像头设备一样/dev/video0也是一个文件 用我们写的程序在应用层去打开、读、写的时候本质会调用到我们自己写的驱动 这张图片的含金量还在增加 4.最后总结
Linux中为何一切皆文件open函数打开txt文件调用的是读取txt文件的函数open函数打开串口是调用串口的驱动函数打开chrdevbase文件就是调用我们自己写的驱动函数也就是说每一个设备都有其对应的实现驱动模块open打开他的时候就会去调用这个接口我们要做的就是实现这些驱动的接口创建一个节点/dev节点也就是所谓文件open调用这个文件的时候能正确的调用我们的驱动模块实现我们的目的
最开始没有学驱动的时候我摸不着头脑觉得驱动它遥不可及当我真正下定决心去学的时候当我迈出第一步的时候我发现它并非不可能无论是学习还是人生最难的应该是迈出第一步试试呗