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 核心驅動程式會插入自己的回呼 (如果未設定直接標記),或是透過要求 (如果已設定直接標記) 傳遞至 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 要求額外空間),但您無法修改不公開區域外的任何資料 (從 usb_request_t 結尾到 usb_request_t 結束)。parent_req_size

USB 要求堆疊範例 (HCI)

xHCI (主機控制器) -> usb-bus -> usb-device (核心 USB 裝置驅動程式庫) -> usb-mass-storage

USB 要求堆疊範例 (DCI)

dwc2 (裝置端控制器) -> usb-peripheral (週邊裝置核心驅動程式) -> usb-function (核心功能驅動程式庫) -> cdc-eth-function (乙太網路週邊模式驅動程式庫)