summaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2021-09-19 11:44:38 +0100
committerAidan MacDonald <amachronic@protonmail.com>2021-10-16 15:58:43 -0400
commitec164c389c99d8129f9d6cacda2731bde9b08257 (patch)
tree224a2f675de8e6ce82f179b38cbe44326db30ddd /docs
parent71cc1e78fd81818428cbd1b55fcf096979b529ef (diff)
downloadrockbox-ec164c389c99d8129f9d6cacda2731bde9b08257.tar.gz
rockbox-ec164c389c99d8129f9d6cacda2731bde9b08257.zip
usb: introduce new control request API
Change-Id: I6545d8985ab683c026f28f6a7c0e23b40d0a6506
Diffstat (limited to 'docs')
-rw-r--r--docs/usb-api.md144
1 files changed, 144 insertions, 0 deletions
diff --git a/docs/usb-api.md b/docs/usb-api.md
new file mode 100644
index 0000000000..a21d6fd703
--- /dev/null
+++ b/docs/usb-api.md
@@ -0,0 +1,144 @@
+Handling USB control requests
+=============================
+
+API overview
+------------
+
+ enum usb_control_response {
+ USB_CONTROL_ACK,
+ USB_CONTROL_STALL,
+ USB_CONTROL_RECEIVE,
+ };
+
+ void usb_core_control_request(struct usb_ctrlrequest* req, void* reqdata);
+ void usb_core_control_complete(int status);
+ void usb_drv_control_response(enum usb_control_response resp,
+ void* data, int length);
+
+The two `usb_core` functions are common to all targets with a USB stack and
+are implemented in `usb_core.c`. The USB driver calls them to inform the core
+when a control request arrives or is completed.
+
+Each USB driver implements `usb_drv_control_response()`. The core calls this
+to let the driver know how to respond to each control request.
+
+### Legacy API
+
+ void usb_core_legacy_control_request(struct usb_ctrlrequest* req);
+
+The old control request API is available through this function. Drivers which
+don't yet implement the new API can use the legacy API instead. To support
+legacy drivers, the USB core implements all functions in the new API and
+emulates the old control request handling behavior, bugs included.
+
+This is intended as a stopgap measure so that old drivers keep working as-is.
+The core can start using the new API right away, and drivers can be ported
+one-by-one as time allows. Once all drivers are ported to the new API, all
+legacy driver support can be removed.
+
+Request handling process
+------------------------
+
+The driver submits control requests to the USB core one at a time. Once a
+request is submitted, it must be completed before the next request can be
+submitted. This mirrors normal USB operation.
+
+When the USB driver receives a setup packet from the host, it submits it
+to the core to begin handling the control transfer. The driver calls
+`usb_core_control_request(req, NULL)`, passing the setup packet in `req`.
+The second argument, `reqdata`, is not used at this time and is passed
+as `NULL`.
+
+The core processes the setup packet and calls `usb_drv_control_response()`
+when it's done. The allowed responses depend on the type of control transfer
+being processed.
+
+### Non-data transfers
+
+- `USB_CONTROL_ACK`, to indicate the request was processed successfully.
+- `USB_CONTROL_STALL`, if the request is unsupported or cannot be processed.
+
+### Control read transfers
+
+- `USB_CONTROL_ACK`, to indicate the request was processed successfully.
+ The core must provide a valid `data` buffer with `length` not exceeding
+ the `wLength` field in the setup packet; otherwise, driver behavior is
+ undefined. The driver will transfer this data to the host during the
+ data phase of the control transfer, and then acknowledge the host's OUT
+ packet to complete the transfer successfully.
+- `USB_CONTROL_STALL`, if the request is unsupported or cannot be processed.
+
+### Control write transfers
+
+The driver calls `usb_core_control_request()` twice to handle control writes.
+The first call allows the core to handle the setup packet, and if the core
+decides to accept the data phase, the second call is made when the data has
+been received without error.
+
+#### Setup phase
+
+The first call is made at the end of the setup phase, after receiving the
+setup packet. The driver passes `reqdata = NULL` to indicate this.
+
+The core can decide whether it wants to receive the data phase:
+
+- `USB_CONTROL_RECEIVE`, if the core wishes to continue to the data phase.
+ The core must provide a valid `data` buffer with `length` greater than or
+ equal to the `wLength` specified in the setup packet; otherwise, driver
+ behavior is undefined. The driver will proceed to the data phase and store
+ received data into the provided buffer.
+- `USB_CONTROL_STALL`, if the request is unsupported or cannot be processed.
+
+If the core accepts the data phase, the driver will re-submit the request
+when the data phase is completed correctly. If any error occurs during the
+data phase, the driver will not re-submit the request; instead, it will
+call `usb_core_control_complete()` with a non-zero status code.
+
+#### Status phase
+
+The second call to `usb_core_control_request()` is made at the end of the data
+phase. The `reqdata` passed by the driver is the same one that the core passed
+in its `USB_CONTROL_RECEIVE` response.
+
+The core's allowed responses are:
+
+- `USB_CONTROL_ACK`, to indicate the request was processed successfully.
+- `USB_CONTROL_STALL`, if the request is unsupported or cannot be processed.
+
+### Request completion
+
+The driver will notify the core when a request has completed by calling
+`usb_core_control_complete()`. A status code of zero means the request was
+completed successfully; a non-zero code means it failed. Note that failure
+can occur even if the request was successful from the core's perspective.
+
+If the core response is `USB_CONTROL_STALL` at any point, the request is
+considered complete. In this case, the driver won't deliver a completion
+notification because it would be redundant.
+
+The driver may only complete a request after the core has provided a response
+to any pending `usb_core_control_request()` call. Specifically, if the core
+has not yet responded to a request, the driver needs to defer the completion
+notification until it sees the core's response. If the core's response is a
+stall, then the notification should be silently dropped.
+
+### Notes
+
+- Driver behavior is undefined if the core makes an inappropriate response
+ to a request, for example, responding with `USB_CONTROL_ACK` in the setup
+ phase of a control write or `USB_CONTROL_RECEIVE` to a non-data request.
+ The only permissible responses are the documented ones.
+
+- If a response requires a buffer, then `data` must be non-NULL unless the
+ `length` is also zero. If a buffer is not required, the core must pass
+ `data = NULL` and `length = 0`. Otherwise, driver behavior is undefined.
+ There are two responses which require a buffer:
+ + `USB_CONTROL_ACK` to a control read
+ + `USB_CONTROL_RECEIVE` to the setup phase of a control write
+
+- Drivers must be prepared to accept a setup packet at any time, including
+ in the middle of a control request. In such a case, devices are required
+ to abort the ongoing request and start handling the new request. (This is
+ intended as an error recovery mechanism and should not be abused by hosts
+ in normal operation.) The driver must take care to notify the core of the
+ current request's failure, and then submit the new request.