首页/目录/全部文章

全部文章

八个专题的源码、算法与协议笔记都在这里。

笔记列表

RK3588 kernel-6.1 drivers/usb/typec 代码功能与实现原理

RK3588 kernel-6.1 drivers/usb/typec 代码功能与实现原理

1. 子系统在 Linux 中的定位

drivers/usb/typec 实现 USB Type‑C 连接器类(connector class) 与用户可见的设备模型,并串联:

  • CC(Configuration Channel) 检测结果(接入方向、角色、供电模式)
  • USB PD(Power Delivery) 能力协商(电压/电流、.swap)
  • Alternate Mode(替换模式)(如 DisplayPort)与 物理开关orientation mux / SBU mux / retimer

它不替代 drivers/usb/coredwc3 的 USB 数据通路本身;而是通过 typec_portusb_role_switchpdmux告知或驱动 SoC 上 USB/Pinctrl/DRM 等相关组件。

内核文档:Documentation/driver-api/usb/typec.rst,ABI:Documentation/ABI/testing/sysfs-class-typec


2. 顶层构建(Makefile

对象 源文件 / 子目录 作用
typec class.omux.obus.opd.oretimer.o 连接器类、Mux/Switch、Alt Mode 总线、PD sysfs、Retimer 绑定
altmodes/ DP Alt Mode 等 替换模式高层驱动
tcpm/ CONFIG_TYPEC_TCPM Type‑C Port Manager + PD 协议状态机在软件侧的实现(适配 TCPM/I²C PHY)
ucsi/ CONFIG_TYPEC_UCSI UACPI/UCSI:OS 通过规范接口驱动 PPM(Platform Policy Manager),常见于笔记本 ACPI
tipd/ CONFIG_TYPEC_TPS6598X TI TPS6598x:片上 PD 固件为主,驱动暴露 typec/role
mux/ CONFIG_TYPEC_MUX_* Cross-switch / PI3USB30532 / FSA4480mux 芯片驱动
单片端口控制器 anx7411hd3ss3220stusb160xrt1719wusb3801qcom-pmic-typec 绑定 DT,调用 typec/TCPM API

3. 核心对象模型(class.h / class.c

  • struct typec_port
    对应 一个物理 Type‑C 口数据角色(DFP/UFP)电源角色(Source/Sink)VCONN功率档位 pwr_opmode朝向 orientation,以及 cap/ops(底层端口驱动回调)。
    关联 typec_switch(插头翻转)、typec_mux(SBU/USB 路由)、typec_retimer(高速/redriver)。

  • struct typec_partner
    对端插头侧设备节点:是否 USB PDCable Identitypd_revision、挂 usb_power_delivery

  • struct typec_cable
    线缆身份(主动/被动等)。

  • class.c
    注册 /sys/class/typec/ 下层次结构,导出 partner、cable、端口属性(PD Identity、product type、端口类型切换 sysfs 等)。

原理:把规范里的 连接器状态 变成 统一的 Linux device/class,便于 udev、电源管理、DRM DP Alt Mode 订阅。


4. Alternate Mode 子系统(bus.c

bus.c 提供 typec_altmode_* API:

  • typec_altmode_enter / exit:进入/退出某 SVID 模式。
  • typec_altmode_notifyAlt Mode 驱动 ↔ 端口/Mux:把协商好的 引脚配置 传到 typec_mux_set,并可回调 notify

原理:PD Vendor Defined Message / Structured VDM 协商出的 模式号,落到 内核 Alt Mode 驱动(如 DP),再 驱动 muxSuperSpeed 线与 DP Lane 接到正确 PHY。


5. Mux / Switch / Retimer(mux.cmux/retimer.c

  • mux.cfwnode_typec_switch_getfwnode_typec_mux_get,通过 设备树 graph / 属性(如 orientation-switch)解析 多颗开关
  • mux/*.c:具体芯片 设置 SAFE/USB/USB+SBU/DP 等路由。
  • retimer.cUSB‑C Retimer(高速链路中继)与 端口 绑定,fwnode_typec_retimer_get

原理:Type‑C 插头正反插Alt Mode 都要求 模拟开关 在电气层切换;与 PD 逻辑解耦,由 class + DT 组合装配。


6. USB PD sysfs(pd.c

注册 usb_power_delivery class,把 PDO(Power Data Object)RDO 等变成属性(固定供电、dual_role_powerEPR 等相关字段)。

原理:用户空间 功率面板 / 调试 可读协商结果;电源路径仍由 PMIC/charger端口驱动 实际控制。


7. TCPM:tcpm/tcpm.cCONFIG_TYPEC_TCPM

TCPM(Type‑C Port Manager)tcpm.c 中实现大规模 状态机(文件头注明 USB Power Delivery protocol stack),涵盖:

  • SRC_*/SNK_*:供电端/用电端 附加、能力广播、协商、Transition
  • DR_SWAP / PR_SWAP / VCONN_SWAP / FR_SWAP
  • Hard/Soft ResetTry.SRC/SNKAccessory(音频/Debug)

底层通过 tcpc_dev(如 FUSB302、TCPci)收发 PD 消息;对上 typec_register_port、通知 partner/cable、触发 role switch

适用PD 状态机在操作系统运行 的方案(简单 TCPC + PHY)。


8. UCSI:ucsi/ucsi.cCONFIG_TYPEC_UCSI

UCSI = OS 与 嵌入式策略模块(PPM) 之间的 命令/事件 ABI(常见于 ACPI _DSM/UCMT)。

驱动:sync_write/read 执行 GET_CONNECTOR_STATUSSET_UORSET_PDR 等;Connector Change 中断后经 ucsi_execute 同步 typec 世界。

适用笔记本/平板电脑,PD 策略与 PHY 多在 EC/PMIC 固件,OS 只做高层策略与 sysfs


9. TIPD(TPS6598x):tipd/core.c

I²C 访问 TI PD 控制器寄存器;芯片内部跑 任务式固件(APP/DISC/BIST),驱动侧:

  • STATUS / POWER_STATUS
  • 处理 中断
  • 注册 typec port、usb_role_switchpower_supply

与 TCPM 区别:许多逻辑在 芯片 FW,驱动偏 寄存器适配,不一定跑完整 tcpm.c 状态机。


10. Alt Mode 示例:altmodes/displayport.c

实现 DisplayPort Alt Mode

  • 解析 VDMpin assignmentDFP_D/UFP_D
  • drm_connector / typec_displayport_data 协作
  • 通过 typec_altmode_notify 切换 mux(USB 仅 / DP 仅 / 多功能)

11. ACPI:port-mapper.cCONFIG_ACPI

ACPI 机器上映射 物理连接器编号 ↔ Type‑C 设备,便于 没有统一 DT 的 x86 平台注册端口。


12. 实现原理总览(一张图)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
      ┌─────────────────────────────────────────┐
│ sysfs / userspace (policy, charging UI) │
└─────────────────────────────────────────┘

┌────────────────────┼────────────────────┐
▼ ▼ ▼
typec_class pd_class altmode bus
(class.c) (pd.c) (bus.c)
│ │ │
└────────────────────┼────────────────────┘

┌───────────────┴───────────────┐
▼ ▼
TCPM (tcpm.c) UCSI (ucsi.c)
+ tcpci/fusb302 + ACPI/CCG/STM32…
│ │
└───────────────┬───────────────┘

┌───────────────┼───────────────┐
▼ ▼ ▼
usb_role_switch mux/switch retimer
│ │ │
└───────────────┴───────────────┘

SoC USB (DWC3…) / DP PHY / charger

13. RK3588 相关提示

RK3588 常见:端口控制器 + PHY + dwc3;具体启用 TCPM/TYPEC_* 哪几项取决于 板级 PD 芯片(独立 TCPC、PMIC 集成 UCSI、或仅 Sink)。需在 arch/arm64/boot/dts/rockchip/ 中核对 typectcpcivbusextcon 节点与 drivers/usb/typeccompatible 是否匹配。


14. 延伸阅读(本仓库)

文档
drivers-usb目录结构与分层原理.md
drivers-usb-dwc3详细分析.md

基于 rk3588/kernel-6.1/drivers/usb/typec 源码归纳。

RK3588 kernel-6.1 drivers/usb/usbip 代码功能与实现原理

RK3588 kernel-6.1 drivers/usb/usbip 代码功能与实现原理

1. USB/IP 是什么

USB/IPUSB 传输语义封装成 网络报文,使:

  • 设备所在机器(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

均依赖 NETUSBIP_COREselect USB_COMMONSGL_ALLOC


3. 网络协议与 URB 的对应(usbip_common.h

内核侧 PDU 与 include/uapi/linux/usbip.h 对齐,核心命令四类:

命令 方向 含义
USBIP_CMD_SUBMIT (0x0001) Client → Server 等价 usb_submit_urb():携带 pipe 衍生的 ep/dirtransfer_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_basicseqnum(每连接递增)、devid(stub 侧常为 (busnum<<16)|devnum,用于在多设备导出场景中区分设备)、directionep

实现原理: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_headerstruct urb 之间拷贝字段(含 ISO 包描述符等)。
  • Socketkernel_sock*kernel_sendmsg/recvmsg 等封装(用于内核线程收发)。
  • PDU dump:开发时打印管道类型、设备等。

4.2 usbip_event.c — Event Handler(EH)

usbip_device 上挂载 eh_opsshutdown / reset / unusable)。
usbip_event_add() 把事件放入全局链表,由 usbip_event 单线程 workqueue 顺序执行:

  • USBIP_EH_SHUTDOWN:连接拆除、清理;
  • USBIP_EH_RESET:复位路径;
  • USBIP_EH_UNUSABLE:标记不可用。

原理:网络断开或异常时 不能与 ISR 杂糅,统一落到 workqueue + mutex,避免与 sysfs 并发冲突(注释强调 shutdown 优先)。


5. 客户端:vhci-hcdvhci_hcd.c + vhci_tx.c + vhci_rx.c + vhci_sysfs.c

5.1 虚拟主机控制器

vhci_hcd.c 注册 hc_driver(名称 vhci_hcd),提供与其它 HCD 相同的:

  • urb_enqueue / urb_dequeue
  • hub_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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static void setup_cmd_submit_pdu(struct usbip_header *pdup,  struct urb *urb)
{
struct vhci_priv *priv = ((struct vhci_priv *)urb->hcpriv);
struct vhci_device *vdev = priv->vdev;
...
pdup->base.command = USBIP_CMD_SUBMIT;
pdup->base.seqnum = priv->seqnum;
pdup->base.devid = vdev->devid;
pdup->base.direction = usb_pipein(urb->pipe) ?
USBIP_DIR_IN : USBIP_DIR_OUT;
pdup->base.ep = usb_pipeendpoint(urb->pipe);

usbip_pack_pdu(pdup, urb, USBIP_CMD_SUBMIT, 1);

if (urb->setup_packet)
memcpy(pdup->u.cmd_submit.setup, urb->setup_packet, 8);
}

随后 kernel_sendmsg 发送 header +(OUT 时)scatter-gather 数据vhci_priv 维护 seqnumpriv_tx/priv_rx 链表,保证 请求与完成 配对。

5.3 接收路径 vhci_rx.c

解析 USBIP_RET_*,根据 seqnum 找到 vhci_priv,回填 urb->statusactual_length,必要时拷贝 IN 数据,调用 usb_hcd_giveback_urb()

5.4 Sysfs vhci_sysfs.c

导出 控制器/端口 属性,与用户态 usbip attach 协作(绑定远端 busid、触发 vdev 创建等)。

KconfigUSBIP_VHCI_HC_PORTSUSBIP_VHCI_NR_HCS 决定 虚拟端口数 / 虚拟 HCD 个数,等价「多块虚拟 USB 主控」。


6. 服务端:usbip-hoststub_main.c + stub_dev.c + stub_rx.c + stub_tx.c

6.1 busid 表 stub_main.c

最多 MAX_BUSID 个条目,记录可被 bind/exportbusid(形如 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真实总线
  • UNLINKusb_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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[Client 应用 / usb-storage 等]
│ urb

usbcore ──► vhci_hcd.urb_enqueue
│ │
│ ├─► vhci_tx: USBIP_CMD_SUBMIT ──► TCP socket
│ │
│ └─► vhci_rx: ◄── USBIP_RET_SUBMIT

(虚拟 Root Hub 枚举出的「远程设备」)

═══════ 网络 ═══════

stub_rx: ◄── CMD_SUBMIT


usb_submit_urb(真实控制器)


真实 USB 设备


stub_tx: RET_SUBMIT ──► socket

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 源码归纳。

RK3588 kernel-6.1 drivers/usb 目录结构与分层设计原理

RK3588 kernel-6.1 drivers/usb 目录结构与分层设计原理

1. 范围与目标

本文针对目录:

  • rk3588/kernel-6.1/drivers/usb

说明:

  • 顶层 Makefile / Kconfig 如何汇总各子系统;
  • 主机(Host)usbcoreHCDGadgetType‑C / 角色切换 等在源码树中的位置;
  • Linux USB 在 drivers/usb 层面的 分层设计原理(与 include/linux/usb*.hDocumentation/usb/ 内核文档互补)。

更细的 枚举、hub.c 调用链、URB、接口驱动匹配 见同目录:

  • rk3588-kernel-6.1-USB总线枚举匹配与数据传输分析.md

2. 顶层构建:drivers/usb/Makefile

drivers/usb/Makefile配置项 挂接子目录,体现「主机 core / PHY / 各类控制器 / Gadget / 类驱动 / 周边」的划分:

变量前缀 典型目录 含义
CONFIG_USB_COMMON common/ Host/Gadget 共用符号(若启用)
CONFIG_USB core/ usbcore:hub、hcd、urb、driver 等
CONFIG_USB_SUPPORT phy/ USB PHY 框架与驱动入口
CONFIG_USB_DWC3DWC2ISP1760CDNS*MTU3MUSBCHIPIDEARENESAS_USBHS dwc3/dwc2/ 片上 USB IP,常含 DRD(双角色) glue
CONFIG_USB_*_HCDCONFIG_USB_PCI host/ xHCI/EHCI/OHCI/UHCI 及 PCI/platform glue
CONFIG_USB_MON mon/ usbmon 监视
CONFIG_USB_*(class/storage 等) class/storage/image/ 标准类与海量存储等
CONFIG_USB_SERIAL serial/ USB 串口子系统
CONFIG_USB_GADGET gadget/ Gadget:UDC + composite + functions
CONFIG_USBIP_CORE usbip/ USB/IP
CONFIG_TYPEC typec/ Type‑C、PD、TCPM、mux 等
CONFIG_USB_ROLE_SWITCH roles/ USB 角色切换 class

设计要点:编译边界与 Kconfig 菜单一致,便于裁剪嵌入式镜像;控制器实现dwc3/host/)与 协议与设备模型core/)分离。


3. 主机核心:drivers/usb/core/usbcore

drivers/usb/core/Makefile 将主机通用逻辑链接为 usbcore

1
2
3
4
usbcore-y := usb.o hub.o hcd.o urb.o message.o driver.o
usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o
usbcore-y += devio.o notify.o generic.o quirks.o devices.o
usbcore-y += phy.o port.o

模块语义概要:

对象文件 职责
hcd.o Host Controller Driver 抽象:usb_hcdhc_driver,连接具体 HCD 与 core
hub.o Root hub / 外部 hub枚举、端口事件
urb.omessage.o URB 生命周期与 同步控制/批量 等消息路径
driver.o usb_driverusb_interface 绑定、总线类型注册
config.oendpoint.odevices.o 配置/端点/设备对象与 sysfs
usb.o core 初始化与通用辅助
phy.o drivers/usb/phy/ 协作(电源、链路侧能力等)

原理硬件差异止于各 HCD / SoC glue协议拓扑与驱动模型统一在 usbcore,避免每个设备驱动直接访问控制器寄存器。


4. 主机控制器:drivers/usb/host/

host/ 提供标准 HCD(如 xhci-hcdehci-hcdohci-hcduhci-hcd)及:

  • PCIehci-pciohci-pcixhci-pci 等;
  • Platformxhci-platehci-platformohci-platform 等;
  • SoC 专用:xhci-tegraehci-exynos 等。

RK3588 常见衔接:片上 DWC3 在 host 模式下往往与 platform xHCI(如 xhci-plat.c)路径配合(具体以 BSP DTS/驱动绑定为准),之上仍是同一 usbcore


5. 片上 IP 与双角色:dwc3/dwc2/musb/chipidea/cdns3/mtu3/

这些目录对应 集成 USB 控制器,特点:

  • 同一 IP 常支持 Host / Device / OTG
  • 驱动负责 时钟、复位、寄存器映射、PHY 握手、模式切换
  • 向内核注册 HCD(主机)和/或 UDC(Gadget),而不是替代 usbcore

设计要点:把 SoC/Board 差异收敛在单独目录,与通用 host/ 里的纯标准 HCD 并存。


6. Gadget:drivers/usb/gadget/

gadget/Makefile 典型组成:

  • libcompositecomposite.cconfigfs.cfunctions.c 等——复合设备框架;
  • udc/:各 USB Device Controller 驱动;
  • function/USB Function(mass storage、rndis、hid 等);
  • legacy/:旧式 gadget 驱动。

原理UDC 提供 peripheral 侧端点能力;上层通过 composite/configfs 组装配置与接口,与主机侧 usb_driver 对称但模型不同。


7. 功能类与设备驱动:class/storage/serial/image/misc/

  • class/:内核内置 USB class 驱动(如 ACM、printer、WDM、TMC)。
  • storage/serial/:按应用场景划分的 USB 设备驱动,通过 usb_register() 绑定 接口,属于 USB 设备功能层,不实现总线控制器。

8. Type‑C、PD、角色:typec/roles/

  • typec/连接器与电源协商(TCPM、PD、mux、UCSI 等),与 usbcore 并行,通过端口/notifier 与控制器协同。
  • roles/USB role switch(例如 intel-xhci-usb-role-switch.c),用于 host/peripheral 视图切换。

二者解决的是 物理端口与电源/角色策略,不是替代 USB 协议栈本身


9. 其它:usbip/mon/early/atm/cdns3/ 双路径等

  • usbip/:通过网络导出/导入 USB 设备;
  • mon/usbmon,抓包/调试;
  • early/:早期 printk USB(极少平台);
  • usb-skeleton.c:示例驱动。

10. 主机侧逻辑分层小结(与 drivers/usb 对应)

1
2
3
4
5
6
7
USB 接口级功能驱动(storage/serial/class/...)
↑ usb_driver / usb_interface
drivers/usb/core(usbcore:hub、hcd、urb、driver)
↑ usb_hcd / hc_driver
drivers/usb/host 与 SoC 目录(xHCI/EHCI/DWC3 glue…)
↑ MMIO / IRQ / DMA + PHY
USB 电缆与外设

11. 阅读顺序建议

  1. 本文:drivers/usb 目录与分层
  2. 同目录:rk3588-kernel-6.1-USB总线枚举匹配与数据传输分析.md —— 枚举与 URB
  3. 内核上游文档:Documentation/usb/Documentation/devicetree/bindings/usb/
  4. RK3588 板级:设备树中 snps,dwc3physdr_moderole-switch 等节点。

文档生成依据:rk3588/kernel-6.1/drivers/usb/Makefiledrivers/usb/core/Makefiledrivers/usb/host/Makefiledrivers/usb/gadget/Makefiledrivers/usb/Kconfig

UDC 核心与 Gadget 设备模型

UDC 核心与 Gadget 设备模型

1. 三类对象

对象 提供者 含义
struct usb_gadget UDC 硬件驱动 一个 Device 模式控制器实例,含ep_listep0、速度能力和状态
struct usb_gadget_driver libcomposite/legacy 上层协议驱动:bind/unbind/setup/disconnect等回调
struct usb_udc udc/core.c 把 gadget 发布到/sys/class/udc并与 gadget driver 配对

usb_ep表示一个端点,usb_request表示一次异步传输。Gadget API 与 Host 侧 URB 模型对称但方向相反:数据方向以 Host 为参照(IN=设备到主机)。

2. UDC 注册

UDC 硬件驱动(如 DWC3)初始化完成后调用:

1
2
3
4
5
usb_add_gadget()                          udc/core.c:1378
-> device_add(&gadget->dev)
-> 分配 struct usb_udc 并加入 udc_list
-> device_add(&udc->dev) -> /sys/class/udc/<name>
-> usb_gadget_set_state(NOT_ATTACHED)

注销入口usb_del_gadget()位于udc/core.c:1521/sys/class/udc/下的名字就是 ConfigFS UDC属性要写入的字符串(RK3588 上通常是fc000000.usb)。

3. Gadget driver 绑定

Linux 6.1 中 gadget driver 已走标准 driver core 匹配:

1
2
3
4
5
6
7
8
usb_gadget_register_driver_owner()        udc/core.c:1666
-> driver_register(&driver->driver) (gadget bus)
-> 匹配空闲 UDC
-> gadget_bind_driver() udc/core.c:1578
-> udc->driver = driver
-> driver->bind(gadget) = composite/configfs bind
-> usb_gadget_udc_start()
-> usb_gadget_connect() (软连接/pullup)

解绑路径gadget_unbind_driver()位于 1633 行:先usb_gadget_disconnect(),再调用 driver 的unbind,最后udc_stop

usb_gadget_connect()(743 行)/usb_gadget_disconnect()(805 行)操作 D+ 上拉,对应 ConfigFS 写 UDC 属性后 Host 才看得到设备;soft_connect sysfs 属性也走这两个函数。

4. 端点 API

Function 驱动通过统一 API 操作端点(均在udc/core.c):

API 行号 语义
usb_ep_enable() 113 按当前 descriptor 使能端点
usb_ep_disable() 156 停用并取消所有在队请求
usb_ep_queue() 288 提交usb_request(异步,完成回调)
usb_ep_dequeue() 326 取消指定请求

约束:

  • enable/disable不可在中断上下文调用,queue/dequeue可以;
  • disable后所有未完成请求以-ESHUTDOWN完成;
  • completion 回调内可以再次 queue,但要防递归和释放竞争;
  • request 的 buf/dma 生命周期由 function 管理,完成前不得释放。

5. usb_request 生命周期

1
2
3
4
5
6
7
8
usb_ep_alloc_request()
-> 填 buf/length/complete/zero/short_not_ok
-> usb_ep_queue()
-> UDC 硬件传输 (DWC3 TRB/DMA)
-> 完成中断
-> req->status/actual 更新
-> req->complete(ep, req)
-> 重新 queue 或 usb_ep_free_request()

status常见值:0 成功、-ECONNRESET被 dequeue、-ESHUTDOWN端点禁用/断开。OUT 方向actual可能小于length(短包),协议层必须处理。

6. 端点自动分配

Function bind 阶段不硬编码端点号,而是用epautoconf.c

  • usb_ep_autoconfig():149 行;
  • usb_ep_autoconfig_ss():63 行(带 SuperSpeed companion);
  • usb_ep_autoconfig_release():187 行;
  • usb_ep_autoconfig_reset():203 行(composite unbind 时复位)。

分配器按 descriptor 的类型/方向/包长在gadget->ep_list中挑选可用硬件端点,并回填bEndpointAddress。同一 gadget 中多个 function 竞争有限端点,是组合过多 function 失败(bind 返回-ENODEV)的常见原因。DWC3 的端点能力(数量、类型)决定可组合的 function 上限。

7. 状态机与 sysfs

usb_gadget_set_state()维护USB_STATE_NOT_ATTACHED/ATTACHED/POWERED/DEFAULT/ADDRESS/CONFIGURED等状态,经/sys/class/udc/<name>/state可见。

其它常用属性:

  • soft_connect:手动 connect/disconnect;
  • current_speed/maximum_speed
  • function:当前绑定的 gadget driver 名。

8. VBUS 与电源

UDC 可上报 VBUS session(usb_gadget_vbus_connect/disconnect),composite 在 SET_CONFIGURATION 后按配置的MaxPower调用usb_gadget_vbus_draw()。Rockchip 配置USB_GADGET_VBUS_DRAW=500,即默认最大 500mA。挂起时按规范应降到 suspend 电流,composite_suspend()会处理。

9. 本目录 UDC 驱动与 RK3588

udc/下的具体控制器驱动(renesas_usb3atmel_usbaaspeed-vhubbdcnet2280等)都不服务 RK3588。RK3588 的 gadget 数据面由drivers/usb/dwc3/gadget.c实现,它同样通过usb_add_gadget()接入本框架,DTS 中dr_mode = "otg"的 DWC3 实例(usb@fc000000)即默认 OTG/Device 口。

dummy_hcd是唯一平台无关的 UDC:它同时注册模拟 HCD 和 UDC,可在无硬件时本机验证 function/composite 逻辑,适合开发自定义 function(如本树f_bytrans)时做回归。

10. 排障入口

现象 检查
/sys/class/udc/为空 DWC3 probe、dr_mode、PHY、extcon/role switch
写 UDC 属性报-ENODEV UDC 名拼写、是否已被其它 gadget 占用
bind 失败-ENODEV 端点数量不足(autoconfig 失败)
Host 不识别 pullup 是否执行、EP0 setup 日志、描述符合法性
传输卡死 request 队列、completion status、DWC3 event buffer

Composite 框架、EP0 与描述符管理

Composite 框架、EP0 与描述符管理

1. 对象模型

libcomposite 把一个 USB 设备组织为三级:

1
2
3
usb_composite_dev (cdev)        整个设备:设备描述符、strings、EP0
-> usb_configuration 一个配置:bConfigurationValue、MaxPower
-> usb_function 一个功能:接口/端点描述符、数据面
  • usb_composite_driver:一个 gadget 方案(VID/PID、strings、bind 回调);
  • usb_function_driver:function 类型注册表项(functions.c管理,按名字如”acm”、”mass_storage”查找);
  • usb_function_instance:一个 function 的配置实例(ConfigFS 目录对应物);
  • usb_function:实例绑定到某配置后的运行对象。

2. 注册与 bind 主链

1
2
3
4
5
6
7
8
9
10
11
12
13
usb_composite_probe()                     composite.c:2568
-> composite_driver_template
-> usb_gadget_register_driver_owner()
-> gadget_bind_driver()
-> composite_bind() composite.c:2425
-> composite_dev_prepare() composite.c:2308
-> 分配 EP0 req (cdev->req)
-> usb_ep_autoconfig_reset()
-> composite->bind(cdev)
-> usb_add_config() composite.c:1072
-> config->bind
-> usb_add_function() composite.c:314
-> function->bind (分配接口号/端点/描述符)

Function bind 中常用:

  • usb_interface_id()composite.c:479,分配接口号;
  • usb_string_id():1351 行,分配字符串 ID;
  • usb_ep_autoconfig():分配端点;
  • usb_assign_descriptors():登记 FS/HS/SS 描述符组。

卸载走composite_unbind()(2265 行)→ __composite_unbind()(2233 行),逆序释放 configuration/function 和 EP0 请求。

3. EP0 Setup 分发

UDC 收到 SETUP 包后调用 gadget driver 的setup回调,即:

1
2
3
4
5
6
7
8
9
10
composite_setup()                         composite.c:1745
标准请求:
GET_DESCRIPTOR -> 组装 device/config/string/BOS 描述符
config 走 config_buf() composite.c:567
SET_CONFIGURATION -> set_config() composite.c:915
GET_CONFIGURATION / SET_INTERFACE / GET_INTERFACE / GET_STATUS
类/厂商请求:
按 wIndex 接口号或端点找到 usb_function
-> f->setup() (如 UVC/UAC2/HID 的 class request)
无人处理 -> EP0 stall

响应数据经cdev->req在 EP0 queue,完成回调composite_setup_complete()(1540 行)。若 function 需要延迟状态阶段(如 UVC 等待用户态应答),setup 返回USB_GADGET_DELAYED_STATUS,之后调用usb_composite_setup_continue()(2612 行)恢复。

4. SET_CONFIGURATION 与 SET_INTERFACE

set_config()(915 行):

  1. wValue找到usb_configuration
  2. 对每个 function 调f->set_alt(f, intf, 0)
  3. function 在set_altusb_ep_enable()并 queue 初始请求;
  4. usb_gadget_vbus_draw()按 MaxPower 上报取电;
  5. 设备进入 CONFIGURED 状态。

SET_INTERFACE 直接分发到对应 function 的set_alt;带 isochronous 端点的 function(UAC/UVC)用 alt 0/1 表示流关闭/开启,是音视频启停的真正入口。

5. 描述符三速组织

Function 为 FS/HS/SS 各准备一组描述符,包长与间隔字段不同(bulk 64/512/1024;isoc/int 的 bInterval 语义也不同)。config_buf()按当前协商速度选择对应组拼接返回。SS 还需usb_ss_ep_comp_descriptor描述 burst/streams。仅提供 HS 描述符的 function 在 SS 链路上会 bind 失败或降级,这是 DWC3 SuperSpeed 口上常见问题。

6. Disconnect / Suspend / Resume

事件 入口 动作
断开/复位 composite_disconnect() composite.c:2204 调各 function disable,回到未配置状态
挂起 composite_suspend() 2476 行 分发f->suspend,降 VBUS 电流
恢复 composite_resume() 2500 行 分发f->resume,恢复取电

Function 的disable必须停止端点并容忍随后所有请求以-ESHUTDOWN完成;拔线可在任意传输中途发生。

7. 锁与并发要点

  • EP0 setup 由 UDC 中断上下文串行发起,function setup回调不得睡眠(延迟状态机制用于需要等待的场景);
  • cdev->lock(spinlock)保护配置切换与 EP0 请求状态;
  • disconnect 与数据面 completion 并发,function 私有状态需要自己的锁;
  • bind/unbind 受 gadget driver 绑定流程串行化,但与用户态 ConfigFS 操作交互时要注意实例仍被引用的情况。

8. 与 ConfigFS 的关系

Legacy gadget 在内核里静态调用usb_composite_probe();ConfigFS 则动态构造等价物:configfs.c自己实现usb_gadget_driver(bind=configfs_composite_bind),把用户在 configfs 中创建的目录/符号链接翻译为usb_add_config()/usb_add_function()调用。两条路径最终在 composite 层汇合。

ConfigFS 组装 Gadget 与 Android/UEVENT 扩展

ConfigFS 组装 Gadget 与 Android/UEVENT 扩展

1. 目录模型

挂载 configfs 后,/sys/kernel/config/usb_gadget/下每个子目录是一个 gadget:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
usb_gadget/g1/
├── idVendor / idProduct / bcdDevice / bcdUSB
├── bDeviceClass / bDeviceSubClass / bDeviceProtocol
├── max_speed
├── strings/0x409/{manufacturer,product,serialnumber}
├── functions/
│ ├── acm.usb0/ (mkdir 创建 usb_function_instance)
│ ├── mass_storage.0/lun.0/file
│ └── ffs.adb/
├── configs/c.1/
│ ├── MaxPower
│ ├── strings/0x409/configuration
│ └── acm.usb0 -> ../../functions/acm.usb0 (symlink 绑定)
└── UDC (写UDC名触发bind)

标准操作序列:

1
2
3
4
5
6
7
8
9
10
mount -t configfs none /sys/kernel/config
cd /sys/kernel/config/usb_gadget
mkdir g1 && cd g1
echo 0x2207 > idVendor; echo 0x0011 > idProduct
mkdir -p strings/0x409 configs/c.1/strings/0x409
echo "RK3588" > strings/0x409/product
mkdir functions/acm.usb0
ln -s functions/acm.usb0 configs/c.1/
echo fc000000.usb > UDC # 绑定并 soft-connect
echo "" > UDC # 解绑

2. 内核侧翻译

用户操作 内核入口
mkdir usb_gadget/g1 gadgets_make() 分配gadget_info并注册 configfs group
mkdir functions/acm.usb0 按”.”前缀查usb_function_driver,调用其alloc_inst()生成usb_function_instance
mkdir configs/c.1 创建config_usb_cfg
ln -s functions/... configs/c.1/ cfg_link把 instance 挂到该配置的 func_list
echo <udc> > UDC gadget_dev_desc_UDC_store() configfs.c:293

写 UDC 后:

1
2
3
4
5
6
7
8
gadget_dev_desc_UDC_store()               configfs.c:293
-> usb_gadget_register_driver_owner()
-> gadget_bind_driver()
-> configfs_composite_bind() configfs.c:1319
-> 校验有 config 且每个 config 有 function
-> 组装设备描述符/strings
-> 对每个 symlink: usb_get_function() + usb_add_function()
-> usb_gadget_connect()

解绑(写空串)走configfs_composite_unbind()(1519 行)。EP0 与断开分发使用configfs_composite_setup()(1590 行)和configfs_composite_disconnect()(1617 行)。

3. Function 命名约定

mkdir functions/<type>.<instance>中的<type>必须与DECLARE_USB_FUNCTION_INIT注册名一致:

名称 模块 备注
acm usb_f_acm /dev/ttyGS*
mass_storage usb_f_mass_storage lun.N 子目录
ffs usb_f_fs 实例名即 mount 时的 dev 名
uvc usb_f_uvc 需在 configfs 下构建 formats/streaming
uac1/uac2 usb_f_uac1/2 虚拟声卡
hid usb_f_hid report desc 经属性写入
ncm/ecm/rndis/eem u_ether 系 网络
bytrans usb_f_bytrans(本树自定义) /dev/msgtrans*
audio_raw usb_f_audio_raw(本树自定义) 原始音频字符设备

模块化 function 依赖ldisc式按名自动加载(unregister前需无实例)。自定义 function 只要正确DECLARE_USB_FUNCTION_INIT并加载模块,即可像内置 function 一样mkdir

4. Android UEVENT 扩展

本树启用CONFIG_USB_CONFIGFS_UEVENT(三份 Rockchip defconfig 均开)。该扩展在configfs.c中:

  • gadget 目录下多出android设备节点;
  • android_setup()configfs.c:1547)包装 EP0 setup,跟踪连接状态;
  • 状态变化通过 uevent 上报USB_STATE=CONNECTED/DISCONNECTED/CONFIGURED
  • 用户态(Android/Rockchip usb service)据此切换 ADB/MTP 等组合。

这是 AOSP 系补丁,上游内核没有;移植主线时注意此差异。

5. OS Descriptor 支持

os_desc子目录支持 Microsoft OS descriptors(WinUSB 自动安装等):useb_vendor_codeqw_sign属性,以及 function 级interface.<n>扩展属性。RNDIS 在 Windows 上通常依赖它选择正确驱动。

6. 典型多 Function 组合

1
2
3
4
configs/c.1/
├── ffs.adb (ADB)
├── mass_storage.0 (U盘)
└── acm.usb0 (串口)

注意事项:

  • 组合受 UDC 端点资源限制(DWC3 端点数有限);
  • RNDIS 与其它 function 组合时接口顺序影响 Windows 识别,常需 os_desc;
  • ffs实例必须等用户态 daemon 写完描述符后写 UDC 才能成功 bind(否则-ENODEV);
  • 更换 function 组合必须先解绑 UDC。

7. 权限与安全

  • ConfigFS 写权限即等于重定义整个 USB 身份,量产系统必须限 root 并由受控服务操作;
  • 锁屏/未授权状态不应暴露 ADB/网络/可写存储 function;
  • VID/PID 与 strings 应固定,避免被用户态随意伪装其它设备。

FunctionFS:用户态实现 USB Function

FunctionFS:用户态实现 USB Function

1. 定位

f_fs.c(FunctionFS)把接口/端点的定义与数据面交给用户态进程,内核只负责与 composite/UDC 的桥接。ADB 是最典型用户。与 GadgetFS(legacy/inode.c,整设备级、已过时)不同,FunctionFS 是 function 级,可与内核 function 在同一 gadget 中组合。

2. 使用流程

1
2
3
4
5
6
7
8
9
10
mkdir functions/ffs.adb           (configfs)
ln -s functions/ffs.adb configs/c.1/
mount -t functionfs adb /dev/usb-ffs/adb
daemon:
open ep0
write DESCRIPTORS (FS/HS/SS + strings)
open ep1/ep2...
echo fc000000.usb > UDC (此后才能bind成功)
daemon: read ep0 获取 ENABLE/DISABLE/SETUP 事件
read/write epN 收发数据

挂载点下文件由内核动态生成:ep0一个,数据端点按描述符声明数量生成ep1..epN(按声明顺序,不是端点地址)。

3. 内核侧关键入口(function/f_fs.c

函数 行号 职责
functionfs_init() 1667 注册 functionfs 文件系统类型
ffs_ep0_write() 331 接收描述符 blob 与字符串表(两阶段状态机)
ffs_ep0_read() 507 向 daemon 投递事件(BIND/ENABLE/SETUP/SUSPEND…)
ffs_epfile_read_iter() 1238 OUT 端点数据读
ffs_epfile_write_iter() 1201 IN 端点数据写
ffs_epfile_ioctl() 1300 FIFO status/flush、descriptor 查询、异步
ffs_func_bind() 3295 把用户描述符接入 composite(autoconfig 端点)
ffs_func_setup() 3366 class/vendor setup 转发为 ep0 事件

描述符格式为usb_functionfs_descs_head_v2+ 标志(FS/HS/SS/OS descriptor 支持),UAPI 在include/uapi/linux/usb/functionfs.h

4. 事件模型

daemon 必须持续读ep0处理事件:

事件 含义
FUNCTIONFS_BIND/UNBIND function 接入/移出 gadget
FUNCTIONFS_ENABLE/DISABLE SET_CONFIGURATION/alt 切换,数据端点可用性变化
FUNCTIONFS_SETUP 需要 daemon 应答的 EP0 请求(read/write ep0 完成数据/状态阶段)
FUNCTIONFS_SUSPEND/RESUME 总线挂起恢复

ENABLE 前读写数据端点会失败;DISABLE 后在途 I/O 以错误完成。daemon 崩溃退出会导致 function 不可用,管理服务需负责重启并重放描述符。

5. 数据面语义

  • 端点文件支持同步 read/write 与 AIO(io_submit),ADB 使用 AIO 提升吞吐;
  • OUT 读长度应为 maxpacket 的整数倍以避免 babble;短包正常结束一次传输;
  • FUNCTIONFS_ENDPOINT_DESC ioctl 可取实际生效的描述符(含协商速度包长);
  • 大传输由 UDC/DWC3 自动分包,daemon 无需按包切分,但一次 I/O 即一次 USB 传输边界。

6. 与 ConfigFS 的装配顺序

ffs.<name>实例在 daemon 写完描述符前处于”未就绪”状态,configfs_composite_bind会失败。正确顺序是:创建实例 → mount → daemon 写描述符 → 写 UDC。Android 的 setup 脚本即按此顺序处理 adbd。

7. 安全

  • FunctionFS 让用户态完全定义接口行为,挂载点与 ep 文件权限必须限制到专用服务账户;
  • Host 发来的 SETUP 内容对 daemon 而言是不可信输入;
  • 描述符 blob 有长度与结构校验,但业务协议(如 ADB 认证)完全在用户态,内核不提供额外保护。

Mass Storage 与存储类 Function

Mass Storage 与存储类 Function

1. 组成

文件 职责
function/f_mass_storage.c BOT(Bulk-Only Transport) + SCSI 命令仿真主体
function/storage_common.c LUN 抽象:backing file/block device、只读/可移除属性
function/f_tcm.c 接入 LIO target core 的 BOT/UAS fabric(可选)
legacy/mass_storage.c 预组装g_mass_storage模块

Rockchip defconfig 启用USB_CONFIGFS_MASS_STORAGEf_tcm未启用。

2. 运行模型

f_mass_storage 每个 common 一个内核线程,串行处理 BOT 事务:

1
2
3
4
5
6
7
8
9
fsg_main_thread()                 f_mass_storage.c:2560
loop:
get_next_command() :2253 收 CBW (bulk-out)
do_scsi_command() 解析 SCSI CDB
do_read() :605 文件读 -> bulk-in
do_write() :736 bulk-out -> 文件写
INQUIRY/READ_CAPACITY/MODE_SENSE/START_STOP/...
发送 CSW (状态)
异常: handle_exception() :2425 reset/config变化/信号

EP0 侧fsg_setup()(456 行)处理 class 请求Bulk-Only Mass Storage ResetGet Max LUNfsg_bind()(3026 行)分配 bulk 端点并起线程。

3. LUN 配置

ConfigFS 路径:

1
2
3
4
5
6
7
8
functions/mass_storage.0/
├── stall 是否允许bulk stall
├── luns 默认 lun.0/
│ ├── file backing 文件或块设备路径
│ ├── ro 只读
│ ├── removable 可移除介质语义
│ ├── cdrom 模拟CD-ROM
│ └── nofua 忽略FUA

file可在绑定后动态换(模拟换盘),前提removable=1。写file时内核 open 该路径,失败即拒绝。

4. 数据一致性核心问题

Backing 存储在 Host 眼中是裸块设备,Host 端文件系统直接写扇区:

  • 绝不允许设备本机同时挂载读写同一 backing 文件/分区,否则两侧页缓存不一致必然损坏文件系统;
  • 切换所有权(本机用 ↔ Host 用)必须先卸载一侧并 sync;
  • nofua/写缓存意味着掉电可能丢数据,量产建议尊重 FUA 并评估断电场景;
  • 只读导出(ro=1)是最安全模式。

5. 性能相关

  • CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS(默认 2)决定流水线缓冲数,VFS 突发延迟大时可增大;
  • 吞吐路径:Host ↔ DWC3 bulk ↔ 内核线程 ↔ VFS/块层,瓶颈通常在存储介质而非 USB;
  • SuperSpeed 下 bulk 1024B×burst,backing 为 eMMC/NVMe 时可达数百 MB/s。

6. f_tcm 简述

f_tcm.c把 gadget 作为 LIO target 的 fabric,支持 BOT(alt 0)与 UAS(alt 1)。UAS 使用 SS streams,需要 UDC 支持(DWC3 支持)。适合需要完整 SCSI target 语义(多 initiator、PR 等)的场景;简单 U 盘导出用 f_mass_storage 足够。

7. 排障

现象 检查
Host 识别但无盘符 lun file 是否设置、大小是否非零
写入后文件损坏 双侧同时挂载(见第4节)
拷贝中途 I/O 错误 backing 介质错误、common 线程信号/异常日志
速度慢 协商速度(lsusb -t)、NUM_BUFFERS、介质本身
弹出后无法再绑定 removable/退出状态、重新写 file

串口类与网络类 Function

串口类与网络类 Function

1. 串口类:u_serial 公共层

u_serial.c实现 gadget 侧 TTY(/dev/ttyGS<N>),被 f_acm/f_serial/f_obex 复用:

1
2
3
4
5
6
7
8
tty写:  gs_write()        u_serial.c:732
-> port写环形buffer
-> gs_start_tx() :229 组request queue到IN端点
USB收: OUT complete -> 数据推入 TTY flip buffer -> ldisc
连接: function set_alt
-> gserial_connect() :1299 绑定gs_port与usb端点, gs_start_io() :538
断开: gserial_disconnect 端点禁用, tty侧hangup语义
行分配: gserial_alloc_line() :1267 / gserial_free_line() :1202

CONFIG_U_SERIAL_CONSOLE可把 ttyGS 作为内核 console(本树 Kconfig 提供,defconfig 未开)。

f_acm 与 f_serial 的区别

f_acm f_serial
模型 CDC ACM:控制接口+数据接口,带 line coding/DTR 通知 裸 bulk in/out 单接口
Host 驱动 Windows/Linux 标准 cdc-acm 需 vendor 驱动或 usbserial generic
用途 与 PC 互操作的串口 私有协议简单通道

f_acm 的 SET_LINE_CODING/SET_CONTROL_LINE_STATE 由其 setup 处理并通过 notify 中断端点上报状态变化;波特率对虚拟串口无实际速率意义,仅透传给应用。

2. 网络类:u_ether 公共层

u_ether.c实现 gadget 侧网卡(默认usb0),被 ECM/NCM/RNDIS/EEM/subset 复用:

1
2
3
4
5
6
7
发送: eth_start_xmit()     u_ether.c:475
-> skb(经function wrap回调封包) -> IN request queue
-> tx_complete() :441 释放skb补队列
接收: OUT request complete -> rx_complete() u_ether.c:256
-> function unwrap解包 -> netif_rx
注册: gether_register_netdev() :871 (MAC来自configfs属性)
断链: gether_disconnect() :1167 停端点、清队列、carrier off

qmult模块参数控制高速下请求队列深度,影响吞吐。

协议选择

Function 协议 Host 兼容性
f_ecm CDC ECM Linux/macOS 原生;Windows 需驱动
f_ncm CDC NCM,多帧聚合 现代三平台较好,吞吐最优
f_rndis Microsoft RNDIS 老 Windows 原生;rndis.c实现控制消息状态机
f_eem CDC EEM 简单,少用
f_subset ECM 子集 极简硬件

RNDIS 控制通道走 class request + notify 端点,rndis.c维护 OID 查询/设置;与 Windows 互操作常需 os_desc(见 ConfigFS 章)。NCM 的 NTB 参数(聚合大小/对齐)影响吞吐与内存占用。

3. 组合与命名

网络 function 的 configfs 属性含dev_addr/host_addr(两端 MAC)、ifname。同一 gadget 可同时含 acm+ncm 等;接口顺序由 symlink 创建顺序决定,影响 Windows 枚举行为。

4. RK3588 场景

Rockchip defconfig 启用 ACM 与 F_FS,网络 function 未默认启用(USB_CONFIGFS_NCM/ECM/RNDIS未设),需要 USB 网络共享时要在产品配置补齐相应CONFIG_USB_CONFIGFS_*。DWC3 SuperSpeed 下 NCM 单流可到数 Gbps 量级,瓶颈转向 CPU 软中断与内存拷贝。

5. 排障

现象 检查
/dev/ttyGS0不出现 function 是否 bind、gserial_alloc_line 日志
打开 ttyGS 阻塞 对端未配置(未 SET_CONFIGURATION 前 open 会等)
usb0 有设备无流量 carrier 状态、Host 侧驱动、unwrap 错误统计
Windows 不识别 RNDIS os_desc、接口顺序、驱动签名策略
网络吞吐低 协商速度、qmult、NCM 聚合参数、CPU 占用

UAC 音频与 UVC 视频 Function

UAC 音频与 UVC 视频 Function

1. UAC 架构

1
2
3
4
Host (USB Audio Class driver)
<-isoc-> f_uac1/f_uac2 (描述符+EP0 class request)
-> u_audio.c (isoc数据 <-> ALSA PCM)
-> 虚拟声卡 (本机应用 arecord/aplay 对接)

音频数据不接真实 codec:Host 放音变成本机 PCM capture,本机 playback 变成 Host 的录音源。真正连接硬件 codec 的是f_uac1_legacy(需板级 codec,较少用)。

关键入口

函数 位置 职责
g_audio_setup() u_audio.c:1426 创建 ALSA card/PCM,连接 uac 参数
u_audio_start_capture() u_audio.c:594 Host->设备 方向 isoc OUT 流启动
u_audio_start_playback() u_audio.c:722 设备->Host 方向 isoc IN 流启动
afunc_bind() f_uac2.c:1033 UAC2 描述符/端点分配
afunc_set_alt() f_uac2.c:1418 alt 0/1 开关流
afunc_setup() f_uac2.c:1822 Clock Source/Volume/Mute 等 class request
afunc_disable() f_uac2.c:1493 断开停流

UAC1 vs UAC2

UAC1 UAC2
速度 FS 语义(HS 可跑但描述符老) HS/SS,推荐
时钟模型 无显式 clock entity Clock Source/Selector,支持多采样率切换
反馈 adaptive/sync 支持显式 feedback EP(异步模式)
Windows 原生 Win10+ 原生

ConfigFS 属性配置采样率(c_srate/p_srate)、位宽(c_ssize/p_ssize)、通道掩码(c_chmask/p_chmask)、音量/静音控制暴露等。修改必须在绑定 UDC 前完成。

音频要点

  • isoc 无重传,欠载/过载直接表现为爆音;每包字节数由采样率/包间隔推出,非整数采样率下有 ±1 帧抖动处理;
  • 异步模式需 feedback 端点向 Host 报速率,否则长时间播放产生漂移;
  • ALSA period/buffer 设置过小会在系统调度抖动时 underrun。

2. UVC 架构

1
2
3
4
Host (UVC driver, 如Windows相机)
<-EP0 class-> f_uvc.c (control: PU/CT/SU 请求转发到用户态)
<-isoc/bulk-> uvc_video.c (payload封装) <- uvc_queue.c(videobuf2)
<- 用户态V4L2 (/dev/videoX 输出设备)

UVC function 把控制与数据都交给用户态:控制请求经 V4L2 event(UVC_EVENT_SETUP/DATA/STREAMON/STREAMOFF)投递给应用,视频帧由应用向/dev/videoX(V4L2 OUTPUT 设备)QBUF。

关键入口

函数 位置 职责
uvc_alloc() f_uvc.c:1281 实例化 function
uvc_function_bind() f_uvc.c:800 控制/流接口、端点、V4L2 设备注册
uvc_function_setup() f_uvc.c:295 class 请求转为 V4L2 event(DELAYED_STATUS)
uvc_function_setup_continue() f_uvc.c:342 用户应答后恢复 EP0 状态阶段
uvc_function_set_alt() f_uvc.c:380 alt 0/1 停/起流
uvc_v4l2_open() uvc_v4l2.c:617 用户态打开 V4L2 节点
uvcg_video_enable() uvc_video.c:784 组织 request 队列开始推流

ConfigFS 描述符树

UVC 的格式/分辨率/帧率在 configfs 中搭建(uvc_configfs.c):

1
2
3
4
5
6
7
functions/uvc.0/
├── control/ (header, processing/terminal)
├── streaming/
│ ├── uncompressed/u/ (格式) └── 360p/720p... (帧)
│ ├── mjpeg/m/...
│ └── header/h -> 链接格式;class/fs|hs|ss -> 链接header
└── streaming_maxpacket / streaming_interval

漏建任一层链接都会 bind 失败。带宽由 maxpacket×burst×interval 决定,1080p MJPEG 以上通常需要 HS isoc 3×1024 或 SS。

UVC 要点

  • 应用必须及时处理 STREAMON/OFF 与 setup event,否则 Host 侧超时;
  • isoc 模式丢包即丢帧数据,Host 端表现花屏;bulk 模式无带宽保证但不丢;
  • SS 下 companion 描述符的 burst 配置直接决定可用带宽。

3. RK3588 配置现状

rockchip_linux_defconfig启用USB_CONFIGFS_F_UVC(相机产品线),rockchip_cpcem_linux_defconfig启用 UAC1/UAC2/HID(音频类产品),electric 仅基础 ACM/MSC/FFS。本树另有自定义f_audio_raw绕开 UAC 标准协议做原始音频传输(见厂商自定义 Function 章)。