USB 驱动开发 --- Gadget 驱动框架梳理(一)

news/2025/1/15 22:18:43/

本文由 Linux 内核文档翻译与总结而来,个人学习笔记仅供参考。

Gadget 框架

在 USB 协议交互过程中,角色定义:

  • the device driver is the master (or “client driver”)

    Linux 内核中称为 HCD(Host Controller Driver),负责与 USB 主机控制器硬件(通常是计算机的 USB 控制器)进行交互,管理 USB 数据传输。

  • the gadget driver is the slave (or “function driver”)

    Linux 内核中称为 UDC(USB Device Controller),管理连接到 USB 设备端的硬件,处理设备端的数据传输、设备枚举和其他 USB 设备相关的操作。

在这里插入图片描述

USB Controller Driver(UDC 驱动)

  • <linux/usb/gadget.h> 定义的API中,对底层 USB 控制器端点硬件抽象成 endpoint (能够接收 IN/OUT 数据流),通过回调与 Gadget Driver 交互。
  • Controller Driver 采用分时复用的方式进而可以对接任意数量的 Gadget Driver 交互;

Gadget Driver

对 USB Controller 的硬件抽象以支持 USB Function 开发,形式为各种调用接口。Gadget Driver 工作职责如下:

  • 响应 setup 请求, 由 ep0 负责的相关协议的应答也包含 calss 类别相关功能实现;
  • 响应 configuration、String 描述符;
  • (重新)设定 Configuration 和 Interface, 包含对端点的 使能与配置;
  • 报告 活动事件,例如:绑定到硬件、挂起/恢复、远程唤醒、断连等;
  • 管理 所有端点的 IN/OUT 收发;

Linux 社区并不鼓励通过这个方式添加如此多的专有驱动。

Upper Level

在 Gadget driver 之上可以连接到 Linux 内核的其他驱动或框架,通过绑定的形式与 Dadget 驱动完成数据的收发。可参考:

  • 用户空间,使用 gadgetfs 或 /dev 下相应节点操作;
  • 网络子系统,如:CDC Ethernet Model gadget 驱动;
  • 其他:Input 子系统(HID gadgets)、Sound 子系统(Aduio gadget)、文件系统(PTP gadget)等;

Additional Layers

可选的层,如:内核网络模块栈、用户应用、标准 POSIX 系统调用等。

Gadget API

在这里插入图片描述

数据结构

gadget driver 使用struct usb_gadget_driver包含自身信息之外还包含另外三种数据类型。理解这些数据类型和使用方法就算是掌握了API。

  • usb_gadget_driver dadget信息;

    //----> linux_5.10/include/linux/usb/gadget.hstruct usb_gadget_driver {...int			(*setup)(struct usb_gadget *, const struct usb_ctrlrequest *);        
    
  • usb_gadget,枚举信息;

    struct usb_gadget {...struct usb_udc			*udc;    
    
  • usb_ep,端点配置;

    struct usb_ep {...const struct usb_ep_ops	*ops;     ...struct usb_ep_caps	caps;        ...u8			address;const struct usb_endpoint_descriptor	*desc;    
    
  • usb_request,数据收发;

    struct usb_request {void			*buf;unsigned		length;
    
  • linux/usb/ch9.h,Gadget 驱动使用的在USB ch9 中定义的公共的 USB 数据结构,不分 Host 与 Device。

使用中关注:

  • 规定使用端点0作为作为各种硬件限定信息的配置与管理,如:发送类型、地址、包大小、缓存和其他能力集;
  • USB message 臃肿(chunky),一个IO请求需要由一个或多个”数据包“组成且边界可被驱动感知;
  • USB 协议更像是异步通信协议(如:HDLC,每帧有 N 个 Byte,多个地址,Host 第一站,Device 其次)超过异步通信协议(如:TTY,每帧8个 Bit,无奇偶检验位,无停止位);
  • USB 数据包是有边界的,如: 一个 USB IN 包数据是 two-byte 一个单元,因此不能将两个单字节直接写入一个单元;

对象与方法

Gadget 设备
核心
  • <linux/usb/gadget.h>, 定义了 Gadget 驱动核心对象与方法;
可选

核心 API 已足够支撑 Gadget 驱动开发,但还另外提供了一些可选工具用以简化常用任务。

  • drivers/usb/gadget/usbstring.c
  • drivers/usb/gadget/config.c
composite 设备

核心 API 已足够开发 Composite 设备(一个 configuration 中有多个功能)和 多功能设备驱动的开发,composite 复合框架将简化这些设备驱动的开发。

框架

composite 设备框架定义了一个设备结构体 struct usb_composite_driver ,其内可关联多个struct usb_configuration 实例。每个 configuration 又包含多个 struct usb_function 定义。在 function 中定义了用户可感知的设备角色,如:Network Link、mass storage device,也可包含管理功能,如:Device Firmware Upgrade。

  • include/linux/usb/composite.h,数据结构定义;
  • drivers/usb/gadget/composite.c,框架实现;
功能

当前只要是使用 DECLARE_USB_FUNCTION_INIT声明的 Gadget 驱动就都是 composite设备,可对应查看源码 drivers/usb/gadget/function/f_xxx.c

Legacy 设备

源码目录 drivers/usb/gadget/legacy/xxx.c

活动事件

Gadget 驱动执行I/O请求时时不用关注硬件细节要求,而当驱动执行 setup/configuration 时就需要关注流程:

  1. 注册 UDC 驱动(USB Device Controller,作为**设备(Slave)**角色的 USB 控制器驱动);

    当前作为设备插入 Host 后会处于 attached 初始化状态( USB ch9 中定义)。此时既无功率消耗也法被使用(还不支持枚举)。

    因为当前数据线上的上拉未使能,所以即使 VBus 正常供电,Host 也无法感知到当前设备的存在(Host 通过设备是否上拉数据线探测设备)。

  2. 注册 Gadget 驱动;

    这些更高层级的 Fuction 驱动将调用 bind() 绑定到具体的 gadget 设备( struct usb_gadget 对象) 。有时这些 Function会在识别到 VBUS 后使能数据线上拉。

  3. 硬件驱动开始枚举;

    此时设备可以接受 USB powerset_address 请求,余下步骤由 gadget driver 接管。如果 dadget driver 在枚举前还未加载,忽略其后步骤直接跳转至步骤 7,执行 unbind()

  4. 实现 Gadget 驱动中 setup()方法;

    setup()方法将返回当前设备的:描述符、硬件接口和能力集等信息。如果硬件允许,甚至可以执行更复杂的设定和配置。

  5. 实现 set_configuration 请求的应答;

    Gadget 驱动需要在setup()方法中实现对主机set_configuration请求的应答(枚举的最后一步),使用所有在 Configuration 中使用的端点 和 默认 settings 中的接口;

  6. 实现数据收发;

  7. 实现 Gadget 驱动中 unbind()方法;

    当 Gadget 驱动卸载时,同时卸载 UDC 驱动;

注:

  1. 在设备连接到Hub后会导致Hub的D+或D-电平变化,Hub根据变化的引脚分辨接进来的是全速设备还是低速设备:

    • 低速设备内部的D-有1.5K的上拉电阻;

    • 全速设备内部的D+有1.5K的上拉电阻;

    • 高速设备一开始也是作为全速设备被识别的,高速模式时,D+的上拉电阻是断开的;

UDC 驱动

UDC(USB Device Controller),即USB从机(设备)控制器,内核文档也称为 Peripheral Controller Drivers。内核中第一个支持的硬件的是 NetChip 2280 控制器(基于PCI 的支持 USB 2.0 调整模式)。其他的控制器基于 gadget 框架开发,见驱动源码文件: linux_5.10/drivers/usb/gadget/udc/xxx_udc.c

虚拟UDC

方便硬件控制器未准备好(缺失或功能异常)时的软件调试,内核实例了一个虚拟的 UDC 驱动。它像 net2280、pxa25x 和 sa11x0 等硬件控制器一样指代多个端点和速率模式,也能够模拟 控制传输、批量传输 和 中断传输。这也就方便了开发支持在

Gadget 驱动

gadget_Zero驱动(主要用于UDC功能验证)之外,内核还有示例了多个常用的 gadget 驱动。

CDC 类

CDC(Communications Device Class)是太网模型的两个强制选项之一,也是电缆调制解调器交互操作性的标准之一。在USB主机看来,使用此代码的gadget 就像是以个太网适配器。

CDC类实现源码文件位于:drivers/usb/gadget/function/f_xxx.c,其下包含:

  • USB CDC serial 类: ACM;
  • USB CDC Ethernet 类:ECM、EEM、RNDIS,简单辨析如下:
    请添加图片描述

注:暂且把 微软的 RNDIS 驱动也纳入CDC Ethernet 类,因为 RNDIS 更适合运行在轻量化的 USB 控制器设备中。RNDIS 为设备接入 Windows 系统使用提供了便捷。

MSC 类

MSC(Mass Storage class)指常用的存储设备,如:U盘、CD-ROM等。大容量存储类设备驱动使用一种不同于 MS-Windows 和 MacOS 的交互方式:

  • USB 设备端,驱动使用一个具体的文件或块设备作为其后端存储介质;
  • USB 主机端,主机遵循 BBB, CB 或 CBI 版本的 MSC 类规格要求使用 SCSI 命令访问后端不认介质;

MSC 类实现源码文件包含:

  • drivers/usb/gadget/function/f_mass_storage.c,被主机视为 磁盘、CD-ROM 等存储设备访问;
  • drivers/usb/gadget/function/f_loopback.c,主要用于应用回环测试;

OTG 功能

USB OTG(USB On-The-GO)指代可以进制双角色切换机制的 USB 控制器:

  • 作为 Host时,使用标准 Linux-USB 主机侧驱动栈;
  • 作为 Device时,使用 Gadget 框架;

见下图,可以看到:Host Controllere、 Device Controller、OTG Bus Monitor 三个重要组成
请添加图片描述

在不同角色下,系统都应尽量复用顶层已申请的、硬件无关的顶层控制器驱动(Host, usb_bus;Device, usb_gadget)内存池;保证功能正常的最小修改;保证对非 OTG 产品的影响。可以抽象出以下几个控制特性:

  • is_otg,Gadget 驱动检查这个标记以确认是否需要在其 configurations 中添加 OTG 描述符;
  • b_hnp_enable, Gadget 驱动如果需要支持两种新的 OTG 协议:
    • HNP, 通过用户接口(如:两个 LED 灯)指示当前设备被 Host 挂起;
    • SRP, 可由用户发起(就像远程唤醒),如按下相关按键;
  • 白名单,如同主机侧,驱动必须支持 OTG 目标外设名单,用以声明支持的 OTG 控制器,即 OTG 白名单。修改文件 otg_whitelist.h

需知

  1. 每个 USB Function 都会在 config_groups 中定义期望用户配置的内容,可配置参考对应 Function 的实现文件:drivers/usb/gadget/f_*.c
  2. 主要阅读 USB 规范章节9 和 内核 gadget.rst 文档,以免忽略掉关键信息,如:端点自动配置,否则需要同时参考头文件与示例源码(如 Gadget Zere);

参考

  • 内核文档 linux_5.10/Documentation/usb/gadget_configfs.rst
  • 11_Gadget驱动程序框架

http://www.ppmy.cn/news/1563438.html

相关文章

Flask表单处理与验证

Flask是一个轻量级的Python框架&#xff0c;它通过扩展库提供了对表单处理与验证的支持。WTForms是一个流行的Flask扩展库&#xff0c;用于创建和验证Web表单。它提供了一种声明式的方法来定义表单结构和验证逻辑&#xff0c;使得表单处理更为简洁和优雅。下面&#xff0c;我们…

第一章:走入HTML

目录 一、HTML的简介  1.介绍 2.HTML的概念和功能 3.HTML的发展历史 二、准备工作 1.编译器的安装 2.相关插件 &#xff08;1&#xff09;中文插件 &#xff08;2&#xff09;Live Server插件 3.快捷键配置方式 三、HTML的基本结构 1.HTML的基本结构 2.快捷方式 四、总…

4Hive计算引擎

4Hive计算引擎 1 MR计算引擎2 Tez计算引擎3 Spark计算引擎 目前Hive支持MapReduce、Tez和Spark 三种计算引擎。 1 MR计算引擎 MR运行的完整过程&#xff1a; Map在读取数据时&#xff0c;先将数据拆分成若干数据&#xff0c;并读取到Map方法中被处理。数据在输出的时候&#…

6.1 MySQL数字函数和条件函数

以前我们在课程中使用过一些mysql的内置函数&#xff0c;比如说四舍五入的round函数&#xff0c;做日期计算的data, datediff函数等等。那么本次课程咱们就来系统的学习一下mysql的这些内置函数&#xff0c;我们使用编程语言写程序的时候&#xff0c;通常会把某一项业务功能封装…

linux stdout/stderr重定向到文件,>或tee

正常情况下直接使用 >或者tee命令只能把stdout的终端输出重定向到文件中&#xff0c;而stderr的输出是无法写到文件中的。 比如在使用svn up时遇到svn 报错的错误&#xff0c;svn ERROR/WARNING 用下面的语句是不会将ERROR/WARNING行写到svn.log的 svn up | tee svn.log…

好用的php商城源码有哪些?

选择一个优秀的商城工具&#xff0c;能更好地帮助大家建立一个好用的商城系统。目前比较流行的都是开源PHP商城系统&#xff0c;那么现实中都有哪些好用的PHP商城源码值得推荐呢&#xff1f;下面就带大家一起来了解一下。 1.TigShop 【推荐指数】&#xff1a;★★★★★☆ 【推…

【MySQL数据库】基础总结

目录 前言 一、概述 二、 SQL 1. SQL通用语法 2. SQL分类 3. DDL 3.1 数据库操作 3.2 表操作 4. DML 5. DQL 5.1 基础查询 5.2 条件查询 5.3 聚合函数 5.4 分组查询 5.5 排序查询 5.6 分页查询 6. DCL 6.1 管理用户 6.2 权限控制 三、数据类型 1. 数值类…

CentOS 6.8 安装 Nginx

个人博客地址&#xff1a;CentOS 6.8 安装 Nginx | 一张假钞的真实世界 提前安装&#xff1a; # sudo yum install yum-utils 一般情况下这个工具系统已经安装。 创建文件/etc/yum.repos.d/nginx.repo&#xff0c;输入内容如下&#xff1a; [nginx-stable] namenginx stab…