入门 Linux 驱动开发确实有个陡峭的学习曲线,但路线很清晰:C 语言基础 → Linux 内核基础 → 字符设备驱动 → 进阶。
这是一份针对性很强的入门指南,包含了学习路线、核心概念、推荐书籍和实践建议。
在写驱动之前,你必须掌握以下内容:
malloc/free 对应内核里的 kmalloc/kfree)、链表操作(内核大量使用链表)。强烈建议:使用虚拟机 + Linux 虚拟机 + QEMU/开发板进行学习。
sudo apt-get install linux-sourcecompile_commands.json 看代码体验极佳)。Linux 驱动主要分为三类:字符设备、块设备、网络设备。入门从**字符设备(Character Device)**开始,因为键盘、鼠标、串口、LED、各种传感器都属于这类。
insmod)和卸载(rmmod),不需要每次都重启系统编译内核。/dev 目录下生成一个设备文件,应用程序通过 open, read, write, close 来操作它。创建一个 hello.c:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
// 模块加载时执行
static int __init hello_init(void) {
printk(KERN_INFO "Hello, Linux Kernel!\n"); // 注意:内核里用 printk,不是 printf
return 0; // 0 表示成功
}
// 模块卸载时执行
static void __exit hello_exit(void) {
printk(KERN_INFO "Goodbye, Linux Kernel!\n");
}
module_init(hello_init); // 宏,指定入口
module_exit(hello_exit); // 宏,指定出口
MODULE_LICENSE("GPL"); // 必须声明许可证,否则内核会报污染警告
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A Simple Hello World Module");
同目录下创建 Makefile:
obj-m += hello.o
# 这里需要指向你的内核源码目录,如果是当前系统,通常是 /lib/modules/$(shell uname -r)/build
KDIR := /lib/modules/$(shell uname -r)/build
all:
make -C $(KDIR) M=$(PWD) modules
clean:
make -C $(KDIR) M=$(PWD) clean
make
sudo insmod hello.ko # 插入模块
dmesg | tail # 查看内核日志,应该能看到 "Hello..."
sudo rmmod hello # 移除模块(注意这里不要加 .ko)
dmesg | tail # 应该能看到 "Goodbye..."
lsmod | grep hello # 查看模块是否加载
仅仅打印 Hello 是不够的,你需要学会如何操作硬件(模拟硬件)。你需要掌握以下 API:
register_chrdev_region 或 alloc_chrdev_region。file_operations:
.open, .release, .read, .write 这些函数指针。read() 时,内核就会调用你写的 .read 函数。class_create 和 device_create,这样加载驱动后 /dev/ 下会自动出现设备文件,不用手动 mknod。推荐练习项目:
read 和 write,把数据从用户态拷到内核态(copy_to_user, copy_from_user)。当驱动稍微复杂一点,你必须考虑并发问题:
request_irq。wait_queue。Documentation/ 目录是最好的手册。drivers/char/mem.c(内存设备驱动)。Hello World 模块。理解 insmod 和 rmmod。file_operations,学会 copy_to_user。class_create)。最重要的一点: Linux 驱动内核 API 变化很快。千万不要死记硬背代码,一定要学会查看当前内核版本的源码和头文件。