RK3588 kernel-6.1 drivers/usb/usbip 代码功能与实现原理
1. USB/IP 是什么
USB/IP 把 USB 传输语义封装成 网络报文,使:
- 设备所在机器(Server):真实 USB 设备仍插在本机,由 stub(usbip-host) 绑定并转发 URB;
- 使用方机器(Client):加载 VHCI(虚拟主机控制器),对
usbcore与应用而言像本地接了 USB 设备,实际通过 TCP 与对端通信。
用户态工具(如 usbip bind/attach)负责建连与协商;内核模块负责 URB ↔ 网络 PDU 的转换与 虚拟 Root Hub / 端口状态 维护。
2. 内核模块划分(Makefile / Kconfig)
| 配置项 | 生成模块 | 作用 |
|---|---|---|
CONFIG_USBIP_CORE |
usbip-core |
公共协议头、调试、socket 收发辅助、事件处理(eh) |
CONFIG_USBIP_VHCI_HCD |
vhci-hcd |
客户端虚拟 HCD + 虚拟 Root Hub |
CONFIG_USBIP_HOST |
usbip-host |
服务端 stub:抢占指定 busid 设备并导出 |
CONFIG_USBIP_VUDC |
usbip-vudc |
虚拟 UDC:本机作为 USB 设备 通过 USB/IP 对远端暴露(依赖 Gadget) |
均依赖 NET;USBIP_CORE 还 select USB_COMMON、SGL_ALLOC。
3. 网络协议与 URB 的对应(usbip_common.h)
内核侧 PDU 与 include/uapi/linux/usbip.h 对齐,核心命令四类:
| 命令 | 方向 | 含义 |
|---|---|---|
USBIP_CMD_SUBMIT (0x0001) |
Client → Server | 等价 usb_submit_urb():携带 pipe 衍生的 ep/dir、transfer_flags、长度、(控制传输)setup[8] 等 |
USBIP_RET_SUBMIT (0x0003) |
Server → Client | SUBMIT 完成:status、actual_length、ISO 相关字段 |
USBIP_CMD_UNLINK (0x0002) |
Client → Server | 等价 usb_unlink_urb(),按 seqnum 取消 |
USBIP_RET_UNLINK (0x0004) |
Server → Client | UNLINK 结果 |
usbip_header_basic 含 seqnum(每连接递增)、devid(stub 侧常为 (busnum<<16)|devnum,用于在多设备导出场景中区分设备)、direction、ep。
实现原理:USB/IP 不改变 USB 逻辑协议,只是把 usbcore 已构造好的 URB 序列化到网络上;远端 stub 再 填充真实 URB 并调用本地 usb_submit_urb。
4. 公共层:usbip_common.c + usbip_event.c
4.1 usbip_common.c
- 调试:
usbip_debug_flag、按模块细分usbip_debug_*。 usbip_pack_pdu/ unpack:在usbip_header与struct urb之间拷贝字段(含 ISO 包描述符等)。- Socket:
kernel_sock*、kernel_sendmsg/recvmsg等封装(用于内核线程收发)。 - PDU dump:开发时打印管道类型、设备等。
4.2 usbip_event.c — Event Handler(EH)
usbip_device 上挂载 eh_ops(shutdown / reset / unusable)。usbip_event_add() 把事件放入全局链表,由 usbip_event 单线程 workqueue 顺序执行:
USBIP_EH_SHUTDOWN:连接拆除、清理;USBIP_EH_RESET:复位路径;USBIP_EH_UNUSABLE:标记不可用。
原理:网络断开或异常时 不能与 ISR 杂糅,统一落到 workqueue + mutex,避免与 sysfs 并发冲突(注释强调 shutdown 优先)。
5. 客户端:vhci-hcd(vhci_hcd.c + vhci_tx.c + vhci_rx.c + vhci_sysfs.c)
5.1 虚拟主机控制器
vhci_hcd.c 注册 hc_driver(名称 vhci_hcd),提供与其它 HCD 相同的:
urb_enqueue/urb_dequeuehub_control/hub_status_data— 软件 Root Hub(端口连接、速度、复位、SuperSpeed 端口状态扩展bit_desc_ss等)
rh_port_connect() 等函数模拟 端口 CONNECT:更新 port_status,唤醒 hub 枚举 —— 与真实控制器 PRTSC 中断效果类似,只是状态由 USB/IP 守护者与内核线程 驱动。
5.2 发送路径 vhci_tx.c
setup_cmd_submit_pdu() 把 urb 打成 USBIP_CMD_SUBMIT:
1 | static void setup_cmd_submit_pdu(struct usbip_header *pdup, struct urb *urb) |
随后 kernel_sendmsg 发送 header +(OUT 时)scatter-gather 数据。vhci_priv 维护 seqnum 与 priv_tx/priv_rx 链表,保证 请求与完成 配对。
5.3 接收路径 vhci_rx.c
解析 USBIP_RET_*,根据 seqnum 找到 vhci_priv,回填 urb->status、actual_length,必要时拷贝 IN 数据,调用 usb_hcd_giveback_urb()。
5.4 Sysfs vhci_sysfs.c
导出 控制器/端口 属性,与用户态 usbip attach 协作(绑定远端 busid、触发 vdev 创建等)。
Kconfig:USBIP_VHCI_HC_PORTS、USBIP_VHCI_NR_HCS 决定 虚拟端口数 / 虚拟 HCD 个数,等价「多块虚拟 USB 主控」。
6. 服务端:usbip-host(stub_main.c + stub_dev.c + stub_rx.c + stub_tx.c)
6.1 busid 表 stub_main.c
最多 MAX_BUSID 个条目,记录可被 bind/export 的 busid(形如 1-1.2)。match_busid sysfs 与用户态约定格式,动态增删 允许导出的设备。
6.2 stub_dev.c
把 stub 注册为 USB device driver(绑定 整个设备 而非单接口),在 export 时 接管设备,使本地其它接口驱动 detach,转由 stub_rx/stub_tx 线程完成 IO。
6.3 stub_rx.c
内核线程 接收 USBIP_CMD_*:
SUBMIT:构造struct urb(必要时tweak_*修正 clear_halt、set_interface 等与远程 devnum/pipe 不一致的控制传输),usb_submit_urb到 真实总线;UNLINK:usb_unlink_urb;- 对 reset port 等控制语义做识别(
is_reset_device_cmd等)。
6.4 stub_tx.c
URB 完成回调 中组装 USBIP_RET_SUBMIT/RET_UNLINK,把 状态与数据 发回客户端。
原理小结:stub = 真实 HCD 之上的「代理驱动」;VHCI = 无线的 fake HCD。二者通过 PDU + seqnum 保持 URB 语义一致。
7. usbip-vudc(可选)
vudc_main.c 注册 platform_driver,可实例化多个 虚拟 UDC。vudc_*.c:在 Gadget 框架下模拟设备控制器,RX/TX/transfer 与 USB/IP 对端交互,使 本机可作为 USB 设备 出现在远端 usbip client 上。
适用场景:反向共享、测试、嵌入式扮演复合设备等。
8. 数据流简图
1 | [Client 应用 / usb-storage 等] |
9. 局限与安全提示(实现层面)
- 加密与鉴权:传统 USB/IP 多为 明文 TCP,需在部署层用 VPN/SSH 隧道 或替换传输。
- 延迟与 ISO:同步传输对 时延抖动 敏感,USB/IP 通常不适合 硬实时音频 等场景。
- 权限:绑定导出设备涉及 物理安全,需配合用户态 特权工具 与策略。
10. 延伸阅读
- 用户态项目历史主页(Kconfig 引用):http://usbip.sourceforge.net/
- 本仓库 USB 文档:
linuxDoc/usb/下 core / dwc2 / dwc3 / 枚举 等笔记。
基于 rk3588/kernel-6.1/drivers/usb/usbip 源码归纳。
正在加载留言…