Merge pull request #1144 from embassy-rs/usb-control-docs
usb/driver: document ControlPipe.
This commit is contained in:
		| @@ -215,6 +215,70 @@ pub trait EndpointOut: Endpoint { | ||||
|     async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError>; | ||||
| } | ||||
|  | ||||
| /// Trait for USB control pipe. | ||||
| /// | ||||
| /// The USB control pipe owns both OUT ep 0 and IN ep 0 in a single | ||||
| /// unit, and manages them together to implement the control pipe state machine. | ||||
| /// | ||||
| /// The reason this is a separate trait instead of using EndpointOut/EndpointIn is that | ||||
| /// many USB peripherals treat the control pipe endpoints differently (different registers, | ||||
| /// different procedures), usually to accelerate processing in hardware somehow. A separate | ||||
| /// trait allows the driver to handle it specially. | ||||
| /// | ||||
| /// The call sequences made by the USB stack to the ControlPipe are the following: | ||||
| /// | ||||
| /// - control in/out with len=0: | ||||
| /// | ||||
| /// ```not_rust | ||||
| /// setup() | ||||
| /// (...processing...) | ||||
| /// accept() or reject() | ||||
| /// ``` | ||||
| /// | ||||
| /// - control out with len != 0: | ||||
| /// | ||||
| /// ```not_rust | ||||
| /// setup() | ||||
| /// data_out(first=true, last=false) | ||||
| /// data_out(first=false, last=false) | ||||
| /// ... | ||||
| /// data_out(first=false, last=false) | ||||
| /// data_out(first=false, last=true) | ||||
| /// (...processing...) | ||||
| /// accept() or reject() | ||||
| /// ``` | ||||
| /// | ||||
| /// - control in with len != 0, accepted: | ||||
| /// | ||||
| /// ```not_rust | ||||
| /// setup() | ||||
| /// (...processing...) | ||||
| /// data_in(first=true, last=false) | ||||
| /// data_in(first=false, last=false) | ||||
| /// ... | ||||
| /// data_in(first=false, last=false) | ||||
| /// data_in(first=false, last=true) | ||||
| /// (NO `accept()`!!! This is because calling `data_in` already implies acceptance.) | ||||
| /// ``` | ||||
| /// | ||||
| /// - control in with len != 0, rejected: | ||||
| /// | ||||
| /// ```not_rust | ||||
| /// setup() | ||||
| /// (...processing...) | ||||
| /// reject() | ||||
| /// ``` | ||||
| /// | ||||
| /// The driver is responsible for handling the status stage. The stack DOES NOT do zero-length | ||||
| /// calls to `data_in` or `data_out` for the status zero-length packet. The status stage should | ||||
| /// be triggered by either `accept()`, or `data_in` with `last = true`. | ||||
| /// | ||||
| /// Note that the host can abandon a control request and send a new STATUS packet any time. If | ||||
| /// a STATUS packet arrives at any time during `data_out`, `data_in`, `accept` or `reject`, | ||||
| /// the driver must immediately return (with `EndpointError::Disabled` from `data_in`, `data_out`) | ||||
| /// to let the stack call `setup()` again to start handling the new control request. Not doing | ||||
| /// so will cause things to get stuck, because the host will never read/send the packet we're | ||||
| /// waiting for. | ||||
| pub trait ControlPipe { | ||||
|     /// Maximum packet size for the control pipe | ||||
|     fn max_packet_size(&self) -> usize; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user