> **作者**: 郑智乾
> **职位**: LINUX驱动开发
> **日期**: 2026-02-01
> **平台**: RK3566 LubanCat 开发板
> **系统**: Ubuntu 20.04 (Focal) Lite
> **内核**: Linux 6.1
---
## 前言
这是一篇完整的技术复盘文章,记录了我在 RK3566 LubanCat 开发板上配置 USB Gadget 功能(NCM 网卡 + ADB 调试)的全过程。从最初的需求分析,到中途踩过的各种坑,再到最终成功解决问题,整个过程充满了曲折。希望这篇文章能帮助到同样在嵌入式 Linux USB 功能配置上遇到困难的开发者。
---
## 第一章:需求分析与背景
### 1.1 我的需求是什么?
我有一块 RK3566 LubanCat 开发板,希望实现以下功能:
| 功能 | 描述 | 用途 |
|------|------|------|
| **USB NCM 网卡** | 通过 USB OTG Type-C 连接电脑后,在电脑上创建一个虚拟网卡 | 方便调试,不依赖网线 |
| **ADB 调试** | 支持 Android Debug Bridge | 文件传输、命令行调试 |
| **USB ACM 串口** | USB 虚拟串口 | 日志输出、串口调试 |
| **以太网 DHCP** | 插网线后自动获取 IP | 正常上网 |
| **SSH 远程登录** | 允许 root 用户通过 SSH 登录 | 远程管理 |
### 1.2 网络架构设计
```
┌─────────────────┐
│ 路由器 │
│ (DHCP 服务器) │
└────────┬────────┘
│ eth0 (DHCP: 如 192.168.1.100)
│ ← 上网用,默认网关
┌──────────────────┐ │
│ Windows/Mac │ ┌────┴────┐
│ 192.168.100.2 │ │ RK3566 │
└────────┬─────────┘ │ 开发板 │
│ └──────────┘
└──────────────┤
usb0 (NCM)
192.168.100.1 (无网关,本地通信)
```
设计要点:
- **以太网 eth0**:通过 DHCP 自动获取 IP,用于上网,有默认网关
- **USB NCM usb0**:静态 IP 192.168.100.1,仅用于开发板与电脑的本地通信,**无网关**(避免路由冲突)
### 1.3 技术背景知识
#### 什么是 USB Gadget?
USB Gadget 是 Linux 内核提供的一种机制,允许设备作为 USB 从设备(Device)与主机(Host)通信。常见的 USB Gadget 功能包括:
| 功能 | 缩写 | 说明 |
|------|------|------|
| Android Debug Bridge | ADB | 安卓调试桥,支持文件传输和命令行 |
| Network Control Model | NCM | USB 网卡,macOS/Linux 原生支持 |
| Remote NDIS | RNDIS | USB 网卡,Windows 原生支持 |
| USB Video Class | UVC | USB 摄像头 |
| Abstract Control Model | ACM | USB 虚拟串口 |
| Mass Storage | MSC | USB 大容量存储 |
#### LubanCat SDK 构建系统
LubanCat SDK 是野火针对 RK3566/RK3568 芯片定制的开发套件,基于 Rockchip 官方 SDK。其构建流程大致如下:
```
./build.sh defconfig → 加载板卡配置
./build.sh kernel → 编译内核
./build.sh rootfs → 编译根文件系统
./build.sh all → 编译全部
./rkflash.sh → 烧录到开发板
```
---
## 第二章:第一次尝试——修改错误的配置文件
### 2.1 最初的错误思路
一开始,我直接去修改 `output/.config` 文件,以为这样就能改变编译配置:
# 错误的做法!
vim output/.config
# 添加 RK_USB_NCM=y 等配置
然后重新编译... 结果发现配置没有生效。
### 2.2 问题分析
`output/.config` 是编译时**自动生成**的临时配置文件,每次执行 `./build.sh defconfig` 都会被覆盖。真正的永久配置文件在:
```
device/rockchip/.chips/rk3566_rk3568/LubanCat_rk3566_ubuntu_lite_defconfig
```
这是一个关键的认知错误,浪费了不少时间。
### 2.3 正确的做法
修改板卡的 defconfig 文件:
# device/rockchip/.chips/rk3566_rk3568/LubanCat_rk3566_ubuntu_lite_defconfig
# USB Gadget functions
RK_USB_NCM=y
RK_USB_ACM=y
# RK_USB_UVC is not set # 不启用摄像头功能
**教训一**:永远要搞清楚配置文件的层级关系,修改源头配置而非生成的临时文件。
---
## 第三章:第二次尝试——内核缺少 NCM 支持
### 3.1 新的错误信息
修改 defconfig 后重新编译,启动开发板发现新的错误:
```
Your kernel doesn't support USB gadget: ncm
Please enable: CONFIG_USB_CONFIGFS_NCM
```
### 3.2 问题分析
SDK 的 defconfig 只是告诉编译系统"我需要 NCM 功能",但内核本身也需要支持这个功能。内核配置和 SDK 配置是**两套独立的系统**。
### 3.3 解决方案
需要同时修改内核的 defconfig:
# kernel-6.1/arch/arm64/configs/lubancat_linux_rk356x_defconfig
# 添加以下配置
CONFIG_USB_CONFIGFS_NCM=y
CONFIG_USB_CONFIGFS_ECM=y
然后重新编译内核:
./build.sh kernel
**教训二**:USB Gadget 功能需要**双重配置**——SDK defconfig + 内核 defconfig。
---
## 第四章:第三次尝试——Ubuntu rootfs 不执行 overlay 脚本
### 4.1 又一个坑
按照 Rockchip 官方文档,USB Gadget 的运行时配置应该放在:
```
device/rockchip/common/overlays/rootfs/usb-gadget/
```
然后通过 `post-hooks` 机制在编译时复制到 rootfs 中。
我按照这个思路创建了配置文件,编译后挂载 rootfs 镜像检查... 配置文件不存在!
### 4.2 深入分析
通过阅读编译脚本,我发现了一个关键事实:
> **Ubuntu rootfs 的构建流程不会执行 `device/rockchip/common/post-hooks/` 中的脚本!**
这个机制只对 Buildroot 和 Debian 系统生效。对于 Ubuntu 系统,overlay 文件必须直接放在:
ubuntu20.04/overlay/
这个目录下的文件会被**直接复制**到 rootfs 根目录。
### 4.3 正确的文件结构
ubuntu20.04/overlay/
├── etc/
│ ├── profile.d/
│ │ └── usbdevice.sh # USB 功能环境变量
│ ├── usbdevice.d/
│ │ └── ncm.sh # NCM 网卡 IP 配置
│ ├── ssh/
│ │ └── sshd_config # SSH 配置
│ ├── netplan/
│ │ └── 01-network-manager-all.yaml # 以太网 DHCP
│ └── systemd/system/
│ └── sysinit.target.wants/
│ └── usbdevice.service # 软链接,启用服务
**教训三**:不同的 rootfs 类型有不同的 overlay 机制,一定要阅读构建脚本确认。
## 第五章:第四次尝试——usbdevice 服务未启用
### 5.1 服务没有自动启动
配置文件都放对位置了,编译烧录后开机... USB 功能还是不工作。
在开发板上检查:
systemctl status usbdevice
# 结果:inactive (dead)
服务没有启动!
### 5.2 问题根源
虽然 `usbdevice.service` 文件存在于 `/lib/systemd/system/` 目录,但 systemd 不会自动启用它。需要创建一个软链接来告诉 systemd "开机时启动这个服务"。
### 5.3 解决方案
在 overlay 中创建启用软链接:
mkdir -p ubuntu20.04/overlay/etc/systemd/system/sysinit.target.wants
ln -sf /lib/systemd/system/usbdevice.service \
ubuntu20.04/overlay/etc/systemd/system/sysinit.target.wants/usbdevice.service
这个软链接会被复制到 rootfs 中,系统启动时 systemd 就会自动启动 usbdevice 服务。
**教训四**:systemd 服务需要显式启用,即使服务文件存在也不会自动运行。
---
## 第六章:第五次尝试——UVC 导致整个 USB Gadget 崩溃
### 6.1 最棘手的问题
这是整个调试过程中最难发现的问题。
之前为了"以后可能会用到",我启用了 UVC(USB 摄像头)功能:
export USB_FUNCS="adb acm uvc ncm"
结果开发板连接电脑后,Windows **完全没有任何反应**。以前至少会有"咚"的一声提示音,现在连这个都没有了。
### 6.2 诊断过程
在开发板上查看日志:
cat /tmp/usbdevice.log
发现大量错误:
Starting functions: uvc adb acm ncm
/usr/bin/usbdevice: 369: cd: can't cd to .../uvc.gs6/...
ln: failed to create symbolic link '...': Device or resource busy
mkdir: cannot create directory '480p': Operation not permitted
mkdir: cannot create directory '720p': Operation not permitted
### 6.3 问题分析
UVC 功能需要硬件支持(实际的摄像头传感器)。当开发板上没有连接摄像头时,UVC 驱动初始化失败。
关键问题在于:**UVC 初始化失败会导致整个 USB Gadget 配置过程中断**,后续的 ADB、ACM、NCM 功能也无法正常工作。
### 6.4 解决方案
移除不需要的 UVC 功能:
# ubuntu20.04/overlay/etc/profile.d/usbdevice.sh
export USB_FUNCS="adb acm ncm" # 移除 uvc
同时修改 defconfig:
# device/rockchip/.chips/rk3566_rk3568/LubanCat_rk3566_ubuntu_lite_defconfig
RK_USB_NCM=y
RK_USB_ACM=y
# RK_USB_UVC is not set # 禁用 UVC
**教训五**:不要启用不需要的功能!一个功能的失败可能导致整个子系统崩溃。YAGNI(You Aren't Gonna Need It)原则在嵌入式开发中尤为重要。
## 第七章:SSH 连接卡顿问题
### 7.1 意外发现的问题
在调试 USB 问题的过程中,我发现了另一个问题:SSH 连接特别慢,ping 开发板也很卡,好几秒才响应一次。
### 7.2 问题分析
这是一个经典的 SSH 配置问题。SSH 服务端默认会对客户端 IP 进行反向 DNS 查询,用于日志记录和访问控制。
但在局域网环境中,私有 IP(如 192.168.x.x)在 DNS 服务器上没有记录,查询会超时。每次操作都要等待 DNS 超时,导致严重卡顿。
### 7.3 解决方案
禁用 SSH 的 DNS 反向查询:
# ubuntu20.04/overlay/etc/ssh/sshd_config
UseDNS no
GSSAPIAuthentication no
- **UseDNS no**:禁止 SSH 对客户端 IP 做反向 DNS 查询
- **GSSAPIAuthentication no**:禁用 Kerberos 认证(开发板用不到)
这两个选项对开发板场景没有任何负面影响,却能显著提升 SSH 响应速度。
**教训六**:遇到网络卡顿问题,优先考虑 DNS 相关配置。
---
## 第八章:最终配置清单
经过多次调试,以下是最终成功的完整配置:
### 8.1 SDK defconfig
**文件**: `device/rockchip/.chips/rk3566_rk3568/LubanCat_rk3566_ubuntu_lite_defconfig`
RK_UBUNTU_FOCAL=y
RK_ROOTFS_SYSTEM_UBUNTU=y
RK_ROOTFS_TARGET_LITE=y
RK_KERNEL_PREFERRED="6.1"
RK_KERNEL_CFG="lubancat_linux_rk356x_defconfig"
# ... 其他配置 ...
# USB Gadget functions
RK_USB_NCM=y
RK_USB_ACM=y
# RK_USB_UVC is not set
### 8.2 内核 defconfig
**文件**: `kernel-6.1/arch/arm64/configs/lubancat_linux_rk356x_defconfig`
CONFIG_USB_CONFIGFS_NCM=y
CONFIG_USB_CONFIGFS_ECM=y
CONFIG_USB_CONFIGFS_RNDIS=y # 已有
### 8.3 USB 功能环境变量
**文件**: `ubuntu20.04/overlay/etc/profile.d/usbdevice.sh`
# USB Gadget configuration
export USB_FUNCS="adb acm ncm"
export USB_VENDOR_ID="0x2207"
export USB_FW_VERSION="0x0310"
export USB_MANUFACTURER="Rockchip"
export USB_PRODUCT="rk3xxx"
### 8.4 NCM 网卡 IP 配置
**文件**: `ubuntu20.04/overlay/etc/usbdevice.d/ncm.sh`
#!/bin/sh
# NCM USB Network Configuration
ncm_post_start_hook()
{
# Wait for usb0 interface to appear
for i in $(seq 50); do
if ip link show usb0 >/dev/null 2>&1; then
break
fi
sleep 0.1
done
# Configure static IP for the device side
ip addr add 192.168.100.1/24 dev usb0 2>/dev/null || true
ip link set usb0 up
}
### 8.5 ADB 配置
**文件**: `ubuntu20.04/overlay/etc/profile.d/adbd.sh`
[ -x /bin/bash ] && export ADBD_SHELL=/bin/bash
export ADB_TCP_PORT=5555
### 8.6 SSH 配置
**文件**: `ubuntu20.04/overlay/etc/ssh/sshd_config`
# LubanCat SSH Server Configuration
PermitRootLogin yes
PasswordAuthentication yes
PermitEmptyPasswords no
ChallengeResponseAuthentication no
UsePAM yes
X11Forwarding yes
PrintMotd no
AcceptEnv LANG LC_*
Subsystem sftp /usr/lib/openssh/sftp-server
# Performance optimization - disable DNS reverse lookup
UseDNS no
GSSAPIAuthentication no
### 8.7 以太网 DHCP 配置
**文件**: `ubuntu20.04/overlay/etc/netplan/01-network-manager-all.yaml`
```yaml
network:
renderer: NetworkManager
ethernets:
eth0:
dhcp4: true
optional: true
eth1:
dhcp4: true
optional: true
### 8.8 usbdevice 服务启用
**文件**: `ubuntu20.04/overlay/etc/systemd/system/sysinit.target.wants/usbdevice.service`
这是一个软链接,指向 `/lib/systemd/system/usbdevice.service`
---
## 第九章:编译与验证
### 9.1 编译命令
cd /home/zzq/workspace/rk3566/LubanCat_SDK
# 清理缓存(重要!确保使用最新配置)
rm -f output/ubuntu/.stamp*
rm -f ubuntu20.04/ubuntu-rk356x-lite-rootfs.img
# 编译 rootfs
./build.sh rootfs
# 烧录
./rkflash.sh rootfs
### 9.2 验证步骤
开发板重启后,进行以下验证:
# 1. 检查 USB 功能配置
echo $USB_FUNCS
# 预期输出: adb acm ncm
# 2. 检查 usbdevice 服务状态
systemctl status usbdevice
# 预期: active (running)
# 3. 检查 USB 网卡
ifconfig usb0
# 预期: 192.168.100.1
# 4. 在 Windows 电脑上
# - 设备管理器应出现 NCM 网卡
# - 执行 adb devices 应能看到设备
# 5. 测试 SSH 连接速度
# 应该秒连,不再卡顿
## 第十章:经验总结
### 10.1 踩过的坑
| 序号 | 问题 | 原因 | 解决方案 |
|------|------|------|----------|
| 1 | 修改 output/.config 无效 | 临时生成文件,会被覆盖 | 修改 defconfig 源文件 |
| 2 | 内核不支持 NCM | 内核 defconfig 未配置 | 添加 CONFIG_USB_CONFIGFS_NCM=y |
| 3 | overlay 文件未生效 | Ubuntu 不使用 post-hooks | 使用 ubuntu20.04/overlay/ 目录 |
| 4 | usbdevice 服务未启动 | 缺少 systemd 启用软链接 | 创建 sysinit.target.wants 软链接 |
| 5 | USB 设备完全无法识别 | UVC 初始化失败导致全崩 | 移除不需要的 UVC 功能 |
| 6 | SSH 连接卡顿 | DNS 反向查询超时 | 添加 UseDNS no |
### 10.2 核心原则
通过这次调试,我深刻体会到几个软件工程原则的重要性:
1. **KISS(Keep It Simple, Stupid)**
- 不要过度设计,能用简单方案解决的问题不要复杂化
- USB 功能只启用需要的,不要"以备将来使用"
2. **YAGNI(You Aren't Gonna Need It)**
- 不需要的功能就不要启用
- UVC 的教训:一个不需要的功能导致整个系统崩溃
3. **分层调试**
- 遇到问题先确定是哪一层的问题
- SDK 配置 → 内核配置 → 运行时配置 → 服务启动
4. **阅读源码**
- 不要完全依赖文档,构建脚本才是真相
- Ubuntu 不执行 post-hooks 这个坑,只有读脚本才能发现
### 10.3 调试技巧
1. **检查日志**
cat /tmp/usbdevice.log
dmesg | grep -i usb
journalctl -u usbdevice
2. **验证配置是否生效**
# 挂载 rootfs 镜像检查
sudo mount -o loop,ro xxx.img /tmp/check
cat /tmp/check/etc/profile.d/usbdevice.sh
sudo umount /tmp/check
3. **清理缓存**
rm -f output/ubuntu/.stamp*
rm -f ubuntu20.04/ubuntu-rk356x-lite-rootfs.img
## 结语
嵌入式 Linux 开发的魅力和痛苦并存。一个看似简单的"配置 USB 网卡"需求,实际上涉及到:
- SDK 构建系统
- Linux 内核配置
- USB Gadget 子系统
- systemd 服务管理
- 网络配置
- SSH 服务优化
每一层都可能出问题,每一个细节都需要正确配置。
但正是这种复杂性,让问题解决后的成就感更加强烈。希望这篇复盘文章能帮助到遇到类似问题的开发者,少走一些弯路。
**记住**:当你觉得"配置应该没问题"的时候,问题往往就藏在那些被忽略的细节里。
---
## 附录:完整文件清单
ubuntu20.04/overlay/
├── etc/
│ ├── profile.d/
│ │ ├── usbdevice.sh # USB 功能环境变量
│ │ └── adbd.sh # ADB 配置
│ ├── usbdevice.d/
│ │ └── ncm.sh # NCM IP 配置脚本
│ ├── ssh/
│ │ └── sshd_config # SSH 优化配置
│ ├── netplan/
│ │ └── 01-network-manager-all.yaml # 以太网 DHCP
│ └── systemd/system/
│ └── sysinit.target.wants/
│ └── usbdevice.service # 服务启用软链接
device/rockchip/.chips/rk3566_rk3568/
└── LubanCat_rk3566_ubuntu_lite_defconfig # SDK 板卡配置
kernel-6.1/arch/arm64/configs/
└── lubancat_linux_rk356x_defconfig # 内核配置

1483

被折叠的 条评论
为什么被折叠?



