4. 内核配置与编译
在开始编写Gadget驱动之前,必须确保Linux内核正确配置了USB Gadget支持以及ConfigFS文件系统。本章将引导你完成从内核源码准备、配置选项选择到编译与模块安装的完整流程。正确的内核配置是后续虚拟网卡(Ethernet Gadget)与虚拟串口(Serial Gadget)联合调试的基础。
4.1 内核配置概览
USB Gadget功能在内核中分为三个层次:UDC驱动层(底层硬件控制器驱动)、Gadget功能驱动层(如Ethernet、Serial、Mass Storage)以及ConfigFS接口层(用户空间配置接口)。以下表格列出了核心配置选项及其依赖关系:
| 配置选项 | 内核路径 | 说明 | 推荐值 |
|---|---|---|---|
CONFIG_USB_GADGET |
Device Drivers → USB Support → USB Gadget Support | 主开关,启用USB Gadget框架 | M 或 Y |
CONFIG_USB_GADGET_DEBUG |
USB Gadget Support → Debugging | 启用Gadget调试信息 | Y(调试阶段) |
CONFIG_USB_CONFIGFS |
USB Gadget Support → USB Gadget Drivers → USB ConfigFS | 启用ConfigFS接口,允许用户空间动态配置Gadget | M |
CONFIG_USB_ETH |
USB Gadget Support → USB Gadget Drivers → Ethernet Gadget | 虚拟网卡功能驱动 | M |
CONFIG_USB_G_SERIAL |
USB Gadget Support → USB Gadget Drivers → Serial Gadget | 虚拟串口功能驱动 | M |
CONFIG_USB_GADGETFS |
USB Gadget Support → USB Gadget Drivers → Gadget Filesystem | 旧版Gadget文件系统接口(可选) | N(推荐使用ConfigFS) |
提示: 对于嵌入式开发板(如Raspberry Pi、BeagleBone Black),建议将Gadget驱动编译为模块(M),以便在运行时动态加载和卸载,避免内核镜像过大。
4.2 配置ConfigFS
ConfigFS是当前Linux USB Gadget配置的标准方式。它通过虚拟文件系统暴露配置接口,允许用户空间通过创建目录和写入文件来动态构建USB Gadget设备。以下SVG图展示了ConfigFS的层次结构:
4.3 内核编译步骤
以下步骤基于Linux 5.x/6.x内核,适用于大多数嵌入式平台。请根据你的目标硬件调整交叉编译工具链。
- 获取内核源码:从kernel.org或厂商BSP获取源码,解压并进入源码目录。
- 加载默认配置:使用目标平台的默认配置文件,例如
make ARCH=arm defconfig或make ARCH=arm multi_v7_defconfig。 - 配置USB Gadget:运行
make ARCH=arm menuconfig,按4.1节表格逐项启用相关选项。 - 保存配置:退出menuconfig并保存为
.config文件。 - 编译内核与模块:执行
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4 zImage和make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4 modules。 - 安装模块:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules_install INSTALL_MOD_PATH=/path/to/rootfs。
关键点: 如果使用模块方式(M),编译后需要将
.ko文件复制到目标文件系统的/lib/modules/$(uname -r)/目录,并运行depmod更新依赖。
4.4 验证配置是否生效
编译完成后,可以通过以下方法验证USB Gadget配置是否正确启用:
- 检查内核模块列表:在目标系统上运行
lsmod | grep usb,应看到g_ether、g_serial或usb_f_ecm、usb_f_serial等模块。 - 检查ConfigFS挂载:运行
mount | grep configfs,应显示configfs on /sys/kernel/config type configfs。 - 检查UDC设备:运行
ls /sys/class/udc,应列出可用的UDC控制器,如musb-hdrc.0或dwc2.0。
常见问题: 如果
/sys/kernel/config目录不存在,说明内核未启用ConfigFS支持。请检查CONFIG_CONFIGFS_FS选项是否设置为Y或M,并在启动后手动挂载:mount -t configfs none /sys/kernel/config。
4.5 编译后模块清单
以下表格列出了编译成功后应生成的关键模块文件及其路径:
| 模块文件 | 内核路径 | 功能 |
|---|---|---|
libcomposite.ko |
drivers/usb/gadget/ | USB Gadget复合设备核心库 |
usb_f_ecm.ko |
drivers/usb/gadget/function/ | Ethernet Control Model(虚拟网卡) |
usb_f_serial.ko |
drivers/usb/gadget/function/ | 通用串口功能 |
usb_f_acm.ko |
drivers/usb/gadget/function/ | ACM串口(与g_serial配合) |
configfs.ko |
fs/configfs/ | ConfigFS文件系统 |
4.6 内核配置与编译流程图
以下SVG图总结了从配置到编译的完整流程:
4.7 常见配置错误与解决方法
- 错误:
configfs: Unknown symbol configfs_register_subsystem
解决: 确保CONFIG_CONFIGFS_FS已编译进内核(Y)或作为模块加载,且模块依赖顺序正确。 - 错误:
libcomposite: Unknown symbol usb_ep_autoconfig
解决: 检查CONFIG_USB_GADGET是否启用,以及UDC驱动是否已编译。 - 错误: 编译时提示
No rule to make target 'debian/certs/signing_key.pem'
解决: 在.config中禁用模块签名:CONFIG_MODULE_SIG=n。 - 错误: 目标系统启动后
/sys/kernel/config为空
解决: 手动挂载ConfigFS:mount -t configfs none /sys/kernel/config,并检查启动脚本是否包含自动挂载。
调试建议: 在menuconfig中启用
CONFIG_USB_GADGET_DEBUG和CONFIG_USB_GADGET_VERBOSE,编译后通过dmesg | grep gadget查看详细日志,快速定位配置问题。
完成本章配置后,你的内核已具备USB Gadget基本支持。下一阶段将进入实战:通过ConfigFS动态创建虚拟网卡与虚拟串口,并实现联合调试。