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 内核配置与编译流程总览
下图展示了从内核配置到目标板运行的完整流程,帮助你建立全局视角。
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公头线直连主机。请根据硬件手册确认。