USB 请求的生命周期

术语库

  • HCI -- 主机控制器接口:主机控制器接口驱动程序是 负责将 USB 请求加入队列,以及管理状态, 同时作为 USB 主机运行的设备。
  • DCI -- 设备控制器接口:设备控制器接口 负责将向设备所连接的 USB 主机的 USB 请求加入队列。 连接。

分配

USB 请求生命周期的第一步是分配。USB 请求包含 请求堆栈中所有驱动程序的数据。每个 作为 USB 设备驱动程序上游的驱动程序,应该提供 GetRequestSize 方法, 该方法会返回包含其本地请求上下文所需的大小。当 USB 设备驱动程序分配请求,它应调用此方法来 确定父级请求上下文的大小。

C 示例

size_t parent_req_size = usb_get_request_size(&usb);
usb_request_t* request;
usb_request_alloc(&request, transfer_length, endpoint_addr,
parent_req_size+sizeof(your_context_struct_t));
usb_request_complete_callback_t complete = {
      .callback = usb_request_complete,
      .ctx = your_context_pointer,
};
your_context_pointer.completion = complete;
usb_request_queue(&usb, request, &complete);
...

void usb_request_complete(void* cookie, usb_request_t* request) {
    your_context_struct_t data;
    // memcpy is needed to ensure alignment
    memcpy(&data, cookie, sizeof(data));
    // Do something here to process the response
    // ...

    // Requeue the request
    usb_request_queue(&data.usb, request, &data.completion);
}

C++ 示例

parent_req_size = usb.GetRequestSize();
std::optional<usb::Request<void>> req;
status = usb::Request<void>::Alloc(&req, transfer_length,
endpoint_addr, parent_req_size);
usb_request_complete_callback_t complete = {
      .callback =
          [](void* ctx, usb_request_t* request) {
            static_cast<YourDeviceClass*>(ctx)->YourHandlerFunction(request);
          },
      .ctx = this,
  };
usb.RequestQueue(req->take(), &complete);

C++ 示例(使用 lambda)

size_t parent_size = usb_.GetRequestSize();
using Request = usb::CallbackRequest<sizeof(std::max_align_t) * 4>;
std::optional<Request> request;
Request::Alloc(&request, max_packet_size, endpoint_address,
parent_size, [=](Request request) {
    // Do some processing here.
    // ...
    // Re-queue the request
    Request::Queue(std::move(request), usb_client_);
});

提交内容

您可以使用 RequestQueue 方法定义, 或者 -- 如果是 CallbackRequests(如此处所示),请使用 Request::Queue,或者干脆是 request.Queue(client)。在所有情况下, USB 请求会传输到父级驱动程序(通常为 usb-device)。

USB 请求的典型生命周期(从设备驱动程序到主机) 控制器或设备控制器):

  • USB 设备驱动程序将请求加入队列
  • usb-device 核心驱动程序收到请求,并且现在拥有该请求 对象。
  • usb-device 核心驱动程序会注入自己的回调(如果直接标记 或者将请求(如果设置了 direct 标记)传递给 HCI 或 DCI 驱动程序。
  • HCI 或 DCI 驱动程序现在拥有该请求。HCI 或 DCI 驱动程序提交 向硬件发出此请求
  • 请求完成。在这种情况下,如果设置了直接标记, 回调,并且设备驱动程序现在拥有 请求。如果未设置直接标志,usb-device(核心)驱动程序 现在拥有该请求
  • 请求归核心驱动程序所有;它会添加到队列中 另一个线程。
  • 核心驱动程序最终调用回调,请求现在 设备驱动程序所有。设备驱动程序现在可以重新提交 请求。

取消

请求可通过调用 CancelAll。时间 CancelAll 完成,所有 请求都归调用方所有。用于实现 CancelAll 函数(如 USB 设备核心驱动程序和任何 HCI/DCI 驱动程序)负责 通过 ZX_ERR_CANCELLED 状态代码将所有权转让给子级。

面向 HCI、DCI 或过滤器驱动程序编写人员的实现说明

实现 GetRequestSize

GetRequestSize 的大小 等于您父级发布商的值 GetRequestSize + 大小 请求上下文的一部分,包括加载网页时所需的 确保数据结构的一致性(如果适用)。如果您 实现 HCI 或 DCI 驱动程序,就必须将 sizeof(usb_request_t) 以及您所用的任何其他数据结构之外, 存储容量usb_request_t 没有特殊的对齐要求,因此 为该结构添加内边距所需的操作。

实现 RequestQueue

的实现者 RequestQueue(临时) 假定拥有来自其客户端驱动程序的 USB 请求的所有权。作为实施者 属于 RequestQueue 的一部分, 系统允许访问 usb_request_t 的所有字段, 已附加到 usb_request_t 结构的数据(通过请求 增加空间 GetRequestSize),但 不得修改您私人区域之外的任何数据, 位于 parent_req_size 字节(usb_request_t 结束之后)。

USB 请求堆栈 (HCI) 示例

xHCI(主机控制器)->usb-bus ->usb-device(核心 USB 设备驱动程序)-> usb-mass-storage

USB 请求堆栈 (DCI) 示例

dwc2(设备端控制器)->usb-peripheral(外设核心驱动程序)-> usb-function(核心功能驱动程序)->cdc-eth-function(以太网) 外围设备模式驱动程序)