Linux驱动开发学习
1.1 驱动模块框架
模块代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
MODULE_LICENSE("GPL");
static int __init demo_init(void)
{
printk("%s,%d\n", __func__, __LINE__);
printk("val:%d\n", 1);
return 0;
}
static void __exit demo_exit(void)
{
printk("%s,%d\n", __func__, __LINE__);
}
// 注册模块入口与出口
module_init(demo_init);
module_exit(demo_exit);
Makefile编写
#内核的源码路径, ?= 条件赋值, uname -r 得到内核的版本号
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
# := 立即赋值, 得到当前的绝对路径
PWD := $(shell pwd)
obj-m := chardevbase.o
build: kernel_modules
# -C 切换工作路径, make -c
kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
${MAKE} -C ${KERNELDIR} M=${PWD} clean
1.2 驱动模块的加载和卸载
Linux驱动程序可以编译到kernel中,也就是zImage,也可以编译为模块,.ko文件。测试的时候只需要加载.ko文件即可。
insmod: insmod 命令不能解决模块的依赖关系
insmod drv.ko
modprobe: 需要将模块移入/lib/modules/kernel-version目录中,会分析模块的依赖关系,将所有依赖模块加载到内核中,在/lib/modules/kernel-version 目录中查找模块;卸载模块会卸载其依赖模块(已经没被其他模块使用),故一般用rmmod
rmmod: 用于模块的卸载
rmmod drv.ko
或 modprobe -r drv.ko
lsmod: 查看加载的模块
P.S.编写驱动的注意事项:
- 编译驱动时需要Linux内核源码
1.3 字符设备的注册与注销
// 不好用,会将次设备号全分走
register_chrdev(unsigned int major, const char *name, const struct file_operations *fops)
// 同上
unregister_chrdev()
register_chrdev_region()
unregister_chrdev_region()
设备号:32bit,分为主设备号(前12bit)和次设备号(后20bit),根据宏定义位数
struct file_operations:用于实现各类字符设备API
1.4 创建设备节点
先通过insmod创建节点
mknod /dev/chardevbase c "major" "minor"
c指明为一个字符设备
major, minor为主设备号和次设备号
创建后即可对该字符设备,以文件的形式操作
1.5 删除设备节点
rmmod后,通过rm命令即可删除