驱动移植与I2C驱动适配:设备驱动工程实践环境配置实战 - 第2节
2.1 内核源码树布局:从顶层到驱动目录
嵌入式 Linux 内核源码采用树形结构组织,顶层目录按功能模块划分。理解源码树布局是驱动移植的第一步,它决定了驱动代码应该放在哪个位置、依赖哪些核心子系统。
核心原则:驱动代码遵循“设备类型 + 总线”分类法。字符设备、块设备、网络设备、I2C 设备、SPI 设备等各有专属目录,驱动开发者只需关注对应子目录下的 Kconfig 和 Makefile。
2.1.1 顶层目录功能速查
| 目录名 | 功能描述 | 驱动开发者关注度 |
|---|---|---|
arch/ |
体系结构相关代码(ARM、x86、RISC-V 等) | ⭐⭐⭐⭐⭐(移植必需) |
drivers/ |
所有设备驱动代码 | ⭐⭐⭐⭐⭐(核心工作区) |
include/ |
内核头文件,包含 linux/、uapi/、asm/ |
⭐⭐⭐⭐(API 定义) |
kernel/ |
核心调度、进程管理、中断 | ⭐⭐(调试时参考) |
fs/ |
文件系统实现 | ⭐⭐(块驱动相关) |
net/ |
网络协议栈 | ⭐⭐(网络驱动相关) |
Documentation/ |
内核文档、设备树绑定说明 | ⭐⭐⭐(查阅规范) |
scripts/ |
编译脚本、Kconfig 解析工具 | ⭐(自动化构建) |
2.1.2 drivers/ 子目录:驱动代码的“家”
drivers/ 是驱动开发的主战场,其内部按设备类型和总线协议进一步细分:
- i2c/ — I2C 总线控制器驱动 + I2C 设备驱动(本课程核心)
- spi/ — SPI 总线驱动
- gpio/ — GPIO 控制器驱动
- input/ — 输入设备(触摸、按键、传感器)
- char/ — 字符设备(杂项、mem、random)
- misc/ — 杂项设备
- pinctrl/ — 引脚控制子系统
- clk/ — 时钟框架
- regulator/ — 电压调节器
实战提示:在移植 I2C 触摸屏驱动时,驱动文件应放入
drivers/input/touchscreen/,而非 drivers/i2c/。I2C 总线控制器驱动才放入 drivers/i2c/busses/。设备类型优先于总线类型。
2.2 Kconfig 与 Makefile 机制:驱动编译的“开关”与“配方”
Kconfig 定义驱动的配置选项,Makefile 根据配置决定是否编译以及如何编译。两者配合实现内核的模块化构建。
2.2.1 Kconfig 语法核心
Kconfig 文件位于每个驱动目录下,使用 menuconfig 工具解析。一个典型的 I2C 驱动 Kconfig 条目如下:
config TOUCHSCREEN_GT911
tristate "Goodix GT911 I2C touchscreen"
depends on I2C
help
Say Y here to support Goodix GT911 I2C touchscreen controller.
If unsure, say N.
To compile this driver as a module, choose M here.
| 关键字 | 含义 | 可选值 |
|---|---|---|
tristate |
三态选项:不编译 / 编译进内核(Y) / 编译为模块(M) | Y / M / N |
bool |
布尔选项:只能 Y 或 N,不能编译为模块 | Y / N |
depends on |
依赖条件,只有条件满足时该选项才可见 | I2C、SPI、OF(设备树) 等 |
select |
反向选择,选中本选项时自动选中另一选项 | 如 select REGMAP_I2C |
help |
帮助文本,描述驱动功能 | 自由文本 |
常见错误:忘记添加
depends on I2C 会导致在非 I2C 平台上也能看到该驱动选项,编译时因缺少 I2C 核心头文件而报错。移植驱动时务必检查依赖链。
2.2.2 Makefile 编译规则
Makefile 使用 obj-$(CONFIG_xxx) 模式控制编译:
# drivers/input/touchscreen/Makefile
obj-$(CONFIG_TOUCHSCREEN_GT911) += gt911.o
obj-$(CONFIG_TOUCHSCREEN_EDT_FT5X06) += edt-ft5x06.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o
当 CONFIG_TOUCHSCREEN_GT911 为 y 时,gt911.o 被编译进内核;为 m 时编译为 gt911.ko 模块;为 n 时不编译。
2.2.3 Kconfig 层级与菜单结构
Kconfig 通过 source 语句形成树状菜单:
# drivers/Kconfig
source "drivers/i2c/Kconfig"
source "drivers/input/Kconfig"
source "drivers/gpio/Kconfig"
# drivers/input/Kconfig
source "drivers/input/touchscreen/Kconfig"
执行 make menuconfig 时,配置界面呈现为:
- Device Drivers → Input device support → Touchscreens → Goodix GT911 I2C touchscreen
2.3 内核配置与编译基础:从零构建可运行内核
内核配置与编译是驱动移植的“入场券”。本节以 ARM 平台为例,演示完整流程。
2.3.1 配置内核的三种方式
| 命令 | 界面类型 | 适用场景 |
|---|---|---|
make menuconfig |
文本菜单(ncurses) | 最常用,SSH 终端友好 |
make xconfig |
图形界面(Qt) | 桌面环境,搜索方便 |
make defconfig |
默认配置 | 快速生成平台默认配置 |
make oldconfig |
交互式更新 | 升级内核版本时保留旧配置 |
2.3.2 编译内核的完整步骤
- 清理环境:
make distclean(彻底清理)或make clean(仅清理目标文件) - 加载默认配置:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- defconfig - 自定义配置:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig - 编译内核:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4 zImage - 编译设备树:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs - 编译模块:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules - 安装模块:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules_install INSTALL_MOD_PATH=/path/to/rootfs
关键参数说明:
ARCH=arm— 指定目标体系结构CROSS_COMPILE=arm-linux-gnueabihf-— 交叉编译工具链前缀-j4— 并行编译线程数,通常设为 CPU 核心数 × 1.5zImage— 压缩后的内核镜像,ARM 平台常用
2.3.3 .config 文件结构解析
.config 是内核配置的最终输出文件,位于源码根目录。每行格式为:
# 注释行
CONFIG_TOUCHSCREEN_GT911=y # 编译进内核
CONFIG_TOUCHSCREEN_EDT_FT5X06=m # 编译为模块
# CONFIG_TOUCHSCREEN_GOODIX is not set # 不编译
调试技巧:当驱动未生效时,首先检查
.config 中对应的 CONFIG_xxx 是否被正确设置为 y 或 m。使用 grep CONFIG_TOUCHSCREEN_GT911 .config 快速定位。
2.4 本章小结:驱动移植的“地图”与“工具”
- 源码树布局是驱动移植的“地图”——知道驱动放哪里,依赖哪些子系统。
- Kconfig 与 Makefile 是驱动编译的“开关”与“配方”——添加新驱动时必须同时修改这两个文件