4. 内核配置与编译:配置内核支持USB Gadget、编译内核与设备树、烧录至目标板

本章是搭建USB Gadget调试环境的核心实操环节。你将学习如何配置Linux内核以启用USB Gadget功能、编译内核与设备树(DTB),并将生成的镜像烧录至目标开发板。完成本章后,你的开发板将具备运行USB Gadget驱动程序的基础能力。

前置检查:确保已安装交叉编译工具链(如arm-linux-gnueabihf-)及内核源码树。推荐使用Linux Kernel 5.10 LTS或更新版本,以获得更完善的USB Gadget支持。

4.1 内核配置:启用USB Gadget子系统

USB Gadget功能在内核中由 CONFIG_USB_GADGET 控制。你需要通过内核配置菜单(menuconfig)手动启用该选项及其相关依赖。

4.1.1 进入内核配置界面

# 进入内核源码根目录
cd ~/linux-kernel

# 加载默认配置(以ARM架构为例)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- defconfig

# 启动图形化配置界面
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig

4.1.2 关键配置项清单

以下表格列出了USB Gadget子系统必须启用的核心配置项,以及推荐启用的辅助功能。

配置项 路径 说明 推荐值
CONFIG_USB_GADGET Device Drivers → USB Support → USB Gadget Support USB Gadget总开关 y(编译进内核)
CONFIG_USB_GADGET_DEBUG USB Gadget Support → Debugging 启用Gadget调试信息 y
CONFIG_USB_GADGET_DEBUG_FILES USB Gadget Support → Debugging files 通过debugfs导出Gadget状态 y
CONFIG_USB_GADGET_DEBUG_FS USB Gadget Support → Debug filesystem 挂载debugfs查看Gadget端点信息 y
CONFIG_USB_CONFIGFS USB Gadget Support → USB Gadget functions → USB ConfigFS 用户空间配置Gadget功能(推荐) y
CONFIG_USB_ETH USB Gadget Support → USB Gadget functions → Ethernet USB以太网(RNDIS/ECM) m(模块)
CONFIG_USB_MASS_STORAGE USB Gadget Support → USB Gadget functions → Mass Storage USB大容量存储 m
CONFIG_USB_SERIAL USB Gadget Support → USB Gadget functions → Serial USB串口(ACM) m
常见错误:如果忘记启用 CONFIG_USB_CONFIGFS,后续将无法通过用户空间动态配置Gadget功能,只能使用静态的 g_ether、g_mass_storage 等传统模块。建议始终启用ConfigFS以获得最大灵活性。

4.1.3 配置UDC(USB Device Controller)驱动

UDC驱动是Gadget子系统的硬件抽象层。根据你的目标板SoC选择对应的UDC驱动:

  • Allwinner (sunxi):CONFIG_USB_MV_UDC 或 CONFIG_USB_SUNXI_UDC
  • Rockchip:CONFIG_USB_DWC2 或 CONFIG_USB_DWC3
  • NXP i.MX:CONFIG_USB_CHIPIDEA
  • Raspberry Pi (BCM2835):CONFIG_USB_DWC2
  • TI AM335x:CONFIG_USB_MUSB_AM335X

配置路径:Device Drivers → USB Support → USB Gadget Support → USB Peripheral Controller。

验证配置:保存退出menuconfig后,执行 grep CONFIG_USB_GADGET .config 确认配置项已生效。输出应包含 CONFIG_USB_GADGET=y。

4.2 编译内核与设备树

配置完成后,进入编译阶段。本节涵盖内核镜像(zImage/uImage)和设备树(.dtb)的编译流程。

4.2.1 编译内核镜像

# 编译内核(使用4线程加速)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4 zImage

# 编译设备树
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs

# 编译内核模块(可选,如果配置了=m的驱动)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4 modules
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=./modules modules_install

4.2.2 编译产物清单

文件 路径 说明
zImage arch/arm/boot/zImage 压缩的内核镜像(ARM标准格式)
uImage arch/arm/boot/uImage U-Boot格式的内核镜像(需额外打包)
*.dtb arch/arm/boot/dts/ 编译后的设备树二进制文件
*.ko ./modules/lib/modules/<kernel-version>/ 内核模块文件

4.2.3 设备树中USB Gadget节点的关键属性

设备树(DTS)中需要正确描述USB控制器的工作模式。以下是一个典型DWC2控制器的Gadget模式配置示例:

&usb_otg {
    status = "okay";
    dr_mode = "peripheral";   /* 强制为设备模式 */
    g-rx-fifo-size = <512>;
    g-np-tx-fifo-size = <32>;
    g-tx-fifo-size = <256 128 128 64>;
};

关键属性说明:

  • dr_mode:可选 host、peripheral、otg。Gadget调试时建议设为 peripheral 避免OTG协商干扰。
  • g-rx-fifo-size:接收FIFO大小(单位:32位字)。
  • g-tx-fifo-size:各端点的发送FIFO大小,顺序对应端点号。
调试技巧:如果编译后USB Gadget无法枚举,首先检查设备树中 dr_mode 是否被正确覆盖。某些SoC的bootloader会修改该属性,建议在DTS中显式声明。

4.3 烧录至目标板

根据目标板的不同,烧录方式有所差异。本节以常见的SD卡启动和U-Boot网络烧录为例。

4.3.1 SD卡烧录(适用于Raspberry Pi、Allwinner等)

# 假设SD卡设备为 /dev/sdb(请确认!)
sudo dd if=arch/arm/boot/zImage of=/dev/sdb1 bs=1M
sudo dd if=arch/arm/boot/dts/sun8i-h3-orangepi-pc.dtb of=/dev/sdb1 bs=1M seek=1

# 如果使用U-Boot,需要将内核打包为uImage
mkimage -A arm -O linux -T kernel -C none -a 0x80008000 -e 0x80008000 \
        -n "Linux Kernel" -d arch/arm/boot/zImage uImage
sudo dd if=uImage of=/dev/sdb1 bs=1M

4.3.2 U-Boot网络烧录(TFTP + NFS)

适用于开发阶段快速迭代:

# 在开发主机上启动TFTP服务器,将zImage和dtb放入TFTP目录
sudo cp arch/arm/boot/zImage /srv/tftp/
sudo cp arch/arm/boot/dts/myboard.dtb /srv/tftp/

# 在U-Boot命令行中加载并启动
U-Boot> setenv serverip 192.168.1.100
U-Boot> setenv ipaddr 192.168.1.10
U-Boot> tftp 0x82000000 zImage
U-Boot> tftp 0x83000000 myboard.dtb
U-Boot> bootz 0x82000000 - 0x83000000

4.3.3 烧录后验证

目标板启动后,通过串口终端检查USB Gadget子系统是否加载成功:

# 检查内核启动日志中是否有Gadget相关输出
dmesg | grep -i gadget

# 检查UDC是否注册
ls /sys/class/udc/
# 应输出类似:musb-hdrc.0.auto

# 检查ConfigFS是否可用(如果启用了CONFIG_USB_CONFIGFS)
ls /sys/kernel/config/usb_gadget/
# 应输出空目录(尚未创建Gadget实例)
成功标志:如果 /sys/class/udc/ 下存在UDC设备节点,且 /sys/kernel/config/usb_gadget/ 目录可访问,说明USB Gadget内核配置与编译已正确完成,可以进入下一章的Gadget功能配置。

4.4 内核配置与编译流程总览

下图展示了从内核配置到目标板运行的完整流程,帮助你建立全局视角。

USB Gadget内核配置与编译流程 USB Gadget 内核配置与编译流程 1. 内核配置 menuconfig 2. 编译内核 make zImage dtbs 3. 烧录镜像 dd / TFTP 4. 启动验证 dmesg / sysfs 验证失败?返回重新配置 关键配置项 • CONFIG_USB_GADGET=y • CONFIG_USB_CONFIGFS=y • UDC驱动选择 • dr_mode = peripheral 编译产物 • arch/arm/boot/zImage • arch/arm/boot/dts/*.dtb • 内核模块 *.ko

4.5 常见问题与排查

现象 可能原因 解决方案
启动后 /sys/class/udc/ 为空 UDC驱动未编译或设备树中USB控制器未启用 检查 dmesg | grep dwc2 或对应UDC驱动日志;确认设备树中 status = "okay"
USB插入主机无任何反应 USB ID引脚未拉低,或 dr_mode 仍为 otg 检查硬件ID引脚电平;强制设置 dr_mode = "peripheral"
编译内核时报错 undefined reference Gadget相关依赖未选全 执行 make ARCH=arm CROSS_COMPILE=... olddefconfig 自动补全依赖
ConfigFS目录不存在 CONFIG_USB_CONFIGFS 未启用 重新进入menuconfig,启用USB ConfigFS支持
硬件注意事项:部分开发板(如Raspberry Pi Zero)的USB口仅支持Device模式,无需额外配置。但多数OTG板(如Orange Pi、BeagleBone)需要一根OTG转接头(micro-A转USB-A母头)来模拟主机连接,或使用USB-A转USB-A公头线直连主机。请根据硬件手册确认。