问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

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

创作时间:
作者:
@小白创作中心

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

引用
CSDN
1.
https://m.blog.csdn.net/gaoyang3513/article/details/145150032

USB Gadget驱动框架是Linux内核中用于开发USB设备端驱动的重要组件。本文详细介绍了Gadget驱动框架的基本概念、API、数据结构、事件处理以及OTG功能等内容,对于从事Linux内核开发或USB设备驱动开发的工程师具有很高的参考价值。

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.h
struct 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. 硬件驱动开始枚举;
    此时设备可以接受USBpowerset_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驱动;
    注:

  8. 在设备连接到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驱动程序框架

本文原文来自CSDN

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号