Linux 驱动开发的完整流程
·
👶 什么是 Linux 驱动?
先打个比方:
👉 驱动程序(Driver)就像是“桥梁”
-
把 Linux 操作系统 和 硬件设备(比如摄像头、串口、按键等)连接起来。
-
没有驱动,系统根本不知道怎么跟设备“说话”。
📚 入门准备:需要了解的基本知识
| 项目 | 说明 |
|---|---|
| Linux 系统基础 | 熟悉 Linux 的终端、命令、目录结构(比如 /dev, /proc, /sys) |
| C 语言基础 | 驱动开发 99% 都是 C 语言 |
| Makefile | 用来编译驱动的配置文件 |
| 交叉编译工具链 | 比如 arm-linux-gnueabihf-gcc,用来给嵌入式板子编译驱动 |
🛠 驱动开发流程总览
① 确定目标设备(我要写什么驱动)
比如:
-
LED 灯控制
-
按键输入
-
串口通信
-
I2C、SPI 外设控制
👉 先明确要控制哪个硬件,然后查看该硬件是否已有驱动源码(可能在内核里)或芯片手册。
② 获取内核源码 + 配置编译环境
a. 获取内核源码
下载与你平台对应的 Linux 内核源码,比如文章中提到的:
/home/linux/kernel/linux-stm32mp-5.10.61-ok/linux-5.10.61
b. 配置 VSCode 环境(提高开发体验)
这就是你上面提到的:
-
配置
c_cpp_properties.json,让智能提示可用 -
配置软链接,统一源码路径
③ 编写驱动代码(重点!)
最小驱动结构长这样(以字符设备为例):
static int __init my_driver_init(void) {
printk("驱动加载\n");
return 0;
}
static void __exit my_driver_exit(void) {
printk("驱动卸载\n");
}
module_init(my_driver_init);
module_exit(my_driver_exit);
MODULE_LICENSE("GPL");
驱动通常实现的接口包括:
-
open():打开设备 -
read():读数据 -
write():写数据 -
release():关闭设备
如果是硬件相关的驱动,还要操作寄存器或调用平台总线(platform bus)等内容。
④ 编写 Makefile(用于编译)
一个典型驱动 Makefile(假设叫 my_driver.c):
obj-m := my_driver.o
KDIR := /home/linux/linux-5.10.61
PWD := $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
clean:
make -C $(KDIR) M=$(PWD) clean
运行 make 就能生成内核模块 .ko 文件。
⑤ 加载驱动 & 查看效果
insmod my_driver.ko # 加载驱动模块
rmmod my_driver # 卸载驱动模块
dmesg # 查看内核打印信息
如果一切正常,你会在 dmesg 里看到 驱动加载 这些提示。
⑥ 编写测试程序(用户空间验证)
驱动加载成功只是第一步,我们还要在用户空间测试它。
比如写个简单 C 程序调用 /dev/mydev 进行 open/read/write:
int fd = open("/dev/mydev", O_RDWR);
write(fd, buffer, len);
read(fd, buffer, len);
close(fd);
⑦ 注册设备号 & 创建设备节点
-
使用
alloc_chrdev_region()动态申请主设备号 -
使用
class_create()创建/dev/mydev -
用
mknod手动创建设备节点(或者用 udev 自动生成)
🔚 总结:驱动开发整体思维导图
硬件设备
↓
设备手册 / 规范
↓
编写驱动(C语言 + 驱动模型接口)
↓
Makefile 编译模块 (.ko)
↓
内核加载 insmod/rmmod
↓
用户空间测试程序
↓
调试优化(dmesg, printk)
📦 关键点
| 名词 | 说明 |
|---|---|
.ko 模块 | 编译好的驱动模块文件 |
insmod/rmmod | 加载/卸载驱动 |
dmesg | 查看内核日志 |
/dev/mydev | 用户空间访问设备的接口 |
c_cpp_properties.json | VSCode 驱动开发智能提示配置 |
软链接 | 简化头文件路径管理 |
更多推荐
所有评论(0)