rockbox/docs/usb-api.md
mojyack 2291aa24f2 usb: refactor control request handling
this commit is a combination of the following changes, which
significantly refactors usb core and class drivers.

1. unify usb buffers of each class driver to reduce iram usage
currently, many class drivers allocate their own buffer to receive
control out data, which is a waste of iram.
share one common buffer for that usage to address the issue.

2. simplify control request handling by implicitly receiving write
   request data packets
change 1 above fixed the data destination. therefore, having the core
receive the data allows us to reduce the class driver's work and
simplifies the api.

3. enhance usb core's control request handling and unify the legacy
   driver api
in order to implement change 2, both the legacy and new driver apis
should be supported. so that, using the designware driver as a
reference, the new driver api functionality is move into usb core.
this simplifies the usb device drivers by requiring them to implement
only the functionalities equivalent to the legacy api.

tested with ipodvideo(arc) and erosqnative(designware)

Change-Id: I3627daa90278751f599e2108ec150ec3f8f6c524
2026-05-25 12:42:36 +01:00

44 lines
2 KiB
Markdown

Handling USB control requests
=============================
API overview
------------
A control request goes through from device driver to class drivers, via usb core.
Each step is done by those functions:
# from device driver to usb core
void usb_core_setup_received(struct usb_ctrlrequest* req);
# from usb core to class drivers
bool usb_class_driver::control_request(struct usb_ctrlrequest* req);
Also control response goes through the inverse steps, and the following
functions are used:
# from class drivers to usb core
void usb_core_control_response(enum usb_control_response response, const void* data, size_t size);
# from usb core to device drivers
int usb_drv_{send,recv}_nonblocking(int endpoint, void *ptr, int length);
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_setup_received(req)`, passing the setup packet in `req`.
If the request was a Non-data transfer, the core or recipient class driver will
call `usb_core_control_response(USB_CONTROL_ACK, NULL, 0)` for ACK or
`usb_core_control_response(USB_CONTROL_STALL, NULL, 0)` for NAK.
If the request was a Control read transfer, the core or recipient class driver
will call `usb_core_control_response(USB_CONTROL_ACK, data, size)` to send data packets,
or `usb_core_control_response(false, USB_CONTROL_STALL, 0)` for NAK.
If the request was a Control write transfer, the core firstly receive data packets
using `usb_drv_recv_nonblocking`. Once it's done, the core or recipient class
driver will process it, then `usb_core_control_response(USB_CONTROL_ACK, NULL, 0)` for ACK
or `usb_core_control_response(USB_CONTROL_STALL, NULL, 0)` for NAK.