USB Raw Gadget

USB Raw Gadget 是一个 gadget 驱动程序,它使用户空间能够对 gadget 的通信过程进行底层控制。

与任何其他 gadget 驱动程序一样,Raw Gadget 通过 USB gadget API 实现 USB 设备。与大多数 gadget 驱动程序不同的是,Raw Gadget 本身不实现任何具体的 USB 功能,而是要求用户空间来完成。

Raw Gadget 目前仅用于调试,不应在生产环境中使用。请改用 GadgetFS。

通过 CONFIG_USB_RAW_GADGET 启用。

与 GadgetFS 的比较

Raw Gadget 与 GadgetFS 类似,但为用户空间提供了对 USB gadget 层更直接的访问。主要区别在于:

  1. Raw Gadget 将每个 USB 请求传递给用户空间以获取响应,而 GadgetFS 则根据提供的描述符在内部响应某些 USB 请求。请注意,UDC 驱动程序可能会自行响应某些请求,而永远不会将其转发给 gadget 层。

  2. Raw Gadget 允许提供任意数据作为对 USB 请求的响应,而 GadgetFS 会对提供的 USB 描述符进行健全性检查。这使得 Raw Gadget 非常适合通过提供畸形数据作为 USB 请求的响应来进行模糊测试。

  3. Raw Gadget 提供了一种选择要绑定的 UDC 设备/驱动程序的方法,而 GadgetFS 目前绑定到第一个可用的 UDC。这允许将多个 Raw Gadget 实例绑定到不同的 UDC。

  4. Raw Gadget 显式公开有关端点地址和功能的信息。这允许用户编写与 UDC 无关的 gadget。

  5. Raw Gadget 使用基于 ioctl 的接口,而不是基于文件系统的接口。

用户空间接口

用户可以通过打开 /dev/raw-gadget 并发出 ioctl 调用来与 Raw Gadget 进行交互;详情请参阅 include/uapi/linux/usb/raw_gadget.h 中的注释。可以同时使用多个 Raw Gadget 实例(绑定到不同的 UDC)。

Raw Gadget 的典型使用场景

  1. 通过打开 /dev/raw-gadget 创建一个 Raw Gadget 实例。

  2. 通过 USB_RAW_IOCTL_INIT 初始化该实例。

  3. 使用 USB_RAW_IOCTL_RUN 启动该实例。

  4. 在循环中发出 USB_RAW_IOCTL_EVENT_FETCH 以接收来自 Raw Gadget 的事件,并根据需要实现的 USB gadget 类型对这些事件做出响应。

请注意,某些 UDC 驱动程序为端点分配了固定地址,因此不能在描述符中使用任意端点地址。尽管如此,Raw Gadget 还是提供了一种编写与 UDC 无关的 USB gadget 的方法。一旦通过 USB_RAW_IOCTL_EVENT_FETCH 收到 USB_RAW_EVENT_CONNECT,就可以使用 USB_RAW_IOCTL_EPS_INFO 来查找有关 UDC 驱动程序所拥有的端点的信息。在此基础上,用户空间必须为 gadget 选择 UDC 端点,并相应地在端点描述符中分配地址。

Raw Gadget 使用示例和测试套件

https://github.com/xairy/raw-gadget

内部细节

每个 Raw Gadget 端点的读/写 ioctl 都会提交一个 USB 请求并等待其完成。这样做是为了通过单个系统调用完整处理单个 USB 请求,从而辅助覆盖率引导的模糊测试。此功能必须保留在实现中。

未来的潜在改进

  • 支持 O_NONBLOCK I/O。这将是另一种操作模式,在这种模式下,Raw Gadget 不会等待每个 USB 请求完成。

  • 支持 USB 3 功能(在启用端点时接受 SS 端点伴随描述符;允许为批量传输提供 stream_id)。

  • 支持等时 (ISO) 传输功能(为已完成的请求公开 frame_number)。