forked from len0rd/rockbox
		
	
		
			
				
	
	
		
			144 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			144 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| 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.
 |