惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

大猫的无限游戏
大猫的无限游戏
云风的 BLOG
云风的 BLOG
小众软件
小众软件
V
V2EX
博客园 - Franky
博客园 - 司徒正美
Apple Machine Learning Research
Apple Machine Learning Research
量子位
博客园 - 【当耐特】
雷峰网
雷峰网
WordPress大学
WordPress大学
Jina AI
Jina AI
Google DeepMind News
Google DeepMind News
N
Netflix TechBlog - Medium
爱范儿
爱范儿
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
阮一峰的网络日志
阮一峰的网络日志
IT之家
IT之家
Blog — PlanetScale
Blog — PlanetScale
Hugging Face - Blog
Hugging Face - Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
V
Visual Studio Blog
Microsoft Security Blog
Microsoft Security Blog

博客园 - 蓝天上的云℡

简洁低消耗字节内存池设计 ARM崩溃堆栈报错寄存器分析定位 ARM NEON&Thumb加速指令集 事件编程之eventfd 事件驱动编程模式之EventLoop syslog日志查看器GUI图形界面,支持Windows/Linux/Macos开箱即用 ERRNO链条分析 ARM AMBA总线之AXI系 Linux Kernel Init Bootstrap 内核初始化启动 RK芯片平台GPIO控制 远程调试桥接-网络-ADB-GDB 斐讯N1盒子安装飞牛FNOS NAS 安卓以太网链路检测 安卓原生开发-Recovery使用minui绘制图形 蓝牙音频协议——安卓开发 RKxx系列的RK628摄像头配置影响HDMI出图 usb储存之BOT/UAS内核驱动 现代操作系统-音频处理技术1 Linux驱动底层 Linux驱动适配I2C/SPI例子 模块编译的pr_debug Linux内核/GKI内核主线更新-usb网卡名称变更引出的BUG 为Kernel代码生成VSCODE索引,快速跳转 安卓开机时间/性能优化 Linux/Golang/glibC系统调用 SGDMA与普通DMA Linux内核源码-存储驱动之 QSPI Flash golang数据转换技巧
Linux USB子系统之Gadget设备端驱动
蓝天上的云℡ · 2026-02-27 · via 博客园 - 蓝天上的云℡

源码路径:
usb/gadget/

USB层级例子
root -> port -> device -> 多个EP 端点

如以下这个设备的描述符树

    USB_Core -->|配置描述符| Config0
    Config0 --> Interface0(HID音量接口)
    Config0 --> Interface1(其他功能接口)

    Interface0 --> HID_Descriptor
    Interface0 --> EP1(IN端点1)

    Interface1 --> EP2(端点2)
    Interface1 --> EP3(端点3)
   
    HID_Descriptor --> Report_Descriptor

ps : usb控制器有带宽和端点的限制,所以device不能超过控制器端点数量限制,否则无法枚举完成。

层级

  • usb/gadget/configfs.c
  • usb/gadget/functions.c
  • usb/gadget/function/f_rndis.c

以下是device层级的

RNDIS驱动

例子:
RNDIS驱动,安卓手机接入电脑能作为USB网卡就用这个
usb/gadget/function/f_rndis.c

驱动注册:

DECLARE_USB_FUNCTION_INIT(rndis, rndis_alloc_inst, rndis_alloc);

宏的定义很简单
image

  • 驱动加载时调用usb function注册,卸载反之
  • 赋值两个行为函数指针
    • alloc_inst 这个是usb实例初始化注册
    • alloc_func 这个是usb功能注册,用于configfs,端点描述符等处理

image
图源:https://www.usbzh.com/article/detail-1062.html

UVC例子

usb/gadget/function/

内核选项:USB_CONFIGFS、USB_LIBCOMPOSITE、USB_CONFIGFS_F_UVC 和 USB_F_UVC
层级
f_uvc.c 适配层L2
uvc_v4l2.c 底层转换支持L1

usb/gadget/function/f_uvc.c
通过uvc->vdev私有数据管理下属v4l2虚拟设备

主要通过v4l2的api注册虚拟设备,其中的fops函数指针作为数据转换读写的通道。(吐槽一下,内核没有统一使用通道这种设计是有点捞了)

  • 注册
  • video_register_device
  • video_set_drvdata

usb/gadget/function/uvc_v4l2.c
关键ops函数,实现v4l2框架所需的接口即可

  • uvc_v4l2_fops
    image

  • uvc_v4l2_ioctl_ops
    image

端口排查

带宽工具,基于usbmon驱动
https://github.com/aguinet/usbtop

命令查看端点

cat /sys/kernel/debug/usb/devices
# cat /sys/kernel/debug/usb/devices

T:  Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=480  MxCh= 1
B:  Alloc=  0/800 us ( 0%), #Int=  0, #Iso=  0
D:  Ver= 2.00 Cls=09(hub  ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=1d6b ProdID=0002 Rev= 6.01
S:  Manufacturer=Linux 6.1.141 ehci_hcd
S:  Product=EHCI Host Controller
S:  SerialNumber=21480000.usb
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=  0mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
E:  Ad=81(I) Atr=03(Int.) MxPS=   4 Ivl=256ms

T:  Bus=02 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12   MxCh= 1
B:  Alloc=  0/900 us ( 0%), #Int=  0, #Iso=  0
D:  Ver= 1.10 Cls=09(hub  ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=1d6b ProdID=0001 Rev= 6.01
S:  Manufacturer=Linux 6.1.141 ohci_hcd
S:  Product=Generic Platform OHCI controller
S:  SerialNumber=214c0000.usb
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=  0mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
E:  Ad=81(I) Atr=03(Int.) MxPS=   2 Ivl=255ms

B代表带宽,而且还需要留意Int+Iso的数量
控制器会有设备数限制和端点数限制
这里的端点数限制指周期端点,包括 int中断传输,isoc基于时间固定带宽传输两种
EP一般有IN/OUT,EP IN + EP OUT = 2个端点

关于alt,usb支持设备布局 https://learn.microsoft.com/zh-cn/windows-hardware/drivers/usbcon/usb-device-layout
image

驱动里面一般也有处理,当USB主机发送USB_REQ_SET_INTERFACE命令时,驱动会调用set_alt函数
例如uac2驱动的afunc_set_alt函数,会根据intf值来切换录制和播放设备类型