前言:1. 学习参考的是宋宝华linux设备驱动详解。
2.记下的原因有两个,一是加深印象,二是以后忘了可以快速上手。
一般学习都是从helloworld开始,笔者也是,话不多说贴上链接: https://blog.csdn.net/wait_for_taht_day5/article/details/50404572
一、编译环境
需要对应版本的设备树,可用shell命令查看(uname -a),位于/usr/src目录下。如下:
uname -a :4.15.0-47-generic
/usr/src:linux-headers-4.15.0-47
二、驱动实现
驱动的编写主要包含如下6块
模块加载函数、模块卸载函数、模块许可证声明、模块参数(可选)、模块导出符号(可选)、模块作者等信息声明(可选)
1.最基本模块加载,退出。
module_init(globalmem_init);
module_exit(globalmem_exit);
globalmem_init函数的实现
1)通过主设备号和次设备号生成 dev_t。
MKDEV(int major, int minor)
2)分配设备号
int register_chrdev_region(dev_t from, unsigned count, const char *name);
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
const char *name);
3)初始化设备
cdev_init(&xxx_dev.cdev, &xxx_fops);
4)加载设备
cdev_add(&xxx_dev.cdev, xxx_dev_no, 1)
5)创建一个总线类型,会在/sys/class下生成对应模块目录(可选)
dev_class = class_create(THIS_MODULE, "mode_class_name");
6)在/dev/下自动生成cdevdemo设备节点,而如果不调用此函数,需要手动mknod来创建设备节点后再访问。(可选)
device_create(dev_class, NULL, dev_t, NULL, "modename");
globalmem_exit的实现
卸载函数要完成与模块加载函数相反的功能,可以用_ _exit修饰卸载函数,其作用是告诉内核如果相关的模块被直接编译进内 核(即 built-in ),则globalmem_exit ()函