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的层次结构:

ConfigFS 层次结构 /sys/kernel/config/usb_gadget/ g1/ (Gadget实例) g2/ (Gadget实例) ...更多实例 configs/ functions/ strings/ UDC ecm.usb0 gser.usb0 mass_storage.usb0 说明: 每个Gadget实例(g1)下包含configs、functions、strings和UDC四个核心子目录。 functions目录下可创建多个功能符号链接,实现复合设备。

4.3 内核编译步骤

以下步骤基于Linux 5.x/6.x内核,适用于大多数嵌入式平台。请根据你的目标硬件调整交叉编译工具链。

  1. 获取内核源码:从kernel.org或厂商BSP获取源码,解压并进入源码目录。
  2. 加载默认配置:使用目标平台的默认配置文件,例如make ARCH=arm defconfig或make ARCH=arm multi_v7_defconfig。
  3. 配置USB Gadget:运行make ARCH=arm menuconfig,按4.1节表格逐项启用相关选项。
  4. 保存配置:退出menuconfig并保存为.config文件。
  5. 编译内核与模块:执行make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4 zImage和make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4 modules。
  6. 安装模块: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图总结了从配置到编译的完整流程:

内核配置与编译流程图 1. 获取内核源码 2. 加载默认配置 3. menuconfig 配置Gadget 4. 保存 .config 5. make zImage & modules 6. 安装模块到rootfs

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动态创建虚拟网卡与虚拟串口,并实现联合调试。