diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-01-05 02:20:05 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-01-05 02:20:05 +0100 |
| commit | b72da125eb064e15cad0da87f5ec09a27080d6be (patch) | |
| tree | 9c5c4bd7e15d278ee2a3745373154ed36480c782 /embassy-usb-driver/src/lib.rs | |
| parent | f339e8518f7ec11da93dfb615ed8aa0ed009358f (diff) | |
| parent | 0ecc54f58c7a75bbaf89c875a23d500137dd52b6 (diff) | |
Merge pull request #1144 from embassy-rs/usb-control-docs
usb/driver: document ControlPipe.
Diffstat (limited to 'embassy-usb-driver/src/lib.rs')
| -rw-r--r-- | embassy-usb-driver/src/lib.rs | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/embassy-usb-driver/src/lib.rs b/embassy-usb-driver/src/lib.rs index 9300ff812..71e5267c6 100644 --- a/embassy-usb-driver/src/lib.rs +++ b/embassy-usb-driver/src/lib.rs | |||
| @@ -215,6 +215,70 @@ pub trait EndpointOut: Endpoint { | |||
| 215 | async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError>; | 215 | async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError>; |
| 216 | } | 216 | } |
| 217 | 217 | ||
| 218 | /// Trait for USB control pipe. | ||
| 219 | /// | ||
| 220 | /// The USB control pipe owns both OUT ep 0 and IN ep 0 in a single | ||
| 221 | /// unit, and manages them together to implement the control pipe state machine. | ||
| 222 | /// | ||
| 223 | /// The reason this is a separate trait instead of using EndpointOut/EndpointIn is that | ||
| 224 | /// many USB peripherals treat the control pipe endpoints differently (different registers, | ||
| 225 | /// different procedures), usually to accelerate processing in hardware somehow. A separate | ||
| 226 | /// trait allows the driver to handle it specially. | ||
| 227 | /// | ||
| 228 | /// The call sequences made by the USB stack to the ControlPipe are the following: | ||
| 229 | /// | ||
| 230 | /// - control in/out with len=0: | ||
| 231 | /// | ||
| 232 | /// ```not_rust | ||
| 233 | /// setup() | ||
| 234 | /// (...processing...) | ||
| 235 | /// accept() or reject() | ||
| 236 | /// ``` | ||
| 237 | /// | ||
| 238 | /// - control out with len != 0: | ||
| 239 | /// | ||
| 240 | /// ```not_rust | ||
| 241 | /// setup() | ||
| 242 | /// data_out(first=true, last=false) | ||
| 243 | /// data_out(first=false, last=false) | ||
| 244 | /// ... | ||
| 245 | /// data_out(first=false, last=false) | ||
| 246 | /// data_out(first=false, last=true) | ||
| 247 | /// (...processing...) | ||
| 248 | /// accept() or reject() | ||
| 249 | /// ``` | ||
| 250 | /// | ||
| 251 | /// - control in with len != 0, accepted: | ||
| 252 | /// | ||
| 253 | /// ```not_rust | ||
| 254 | /// setup() | ||
| 255 | /// (...processing...) | ||
| 256 | /// data_in(first=true, last=false) | ||
| 257 | /// data_in(first=false, last=false) | ||
| 258 | /// ... | ||
| 259 | /// data_in(first=false, last=false) | ||
| 260 | /// data_in(first=false, last=true) | ||
| 261 | /// (NO `accept()`!!! This is because calling `data_in` already implies acceptance.) | ||
| 262 | /// ``` | ||
| 263 | /// | ||
| 264 | /// - control in with len != 0, rejected: | ||
| 265 | /// | ||
| 266 | /// ```not_rust | ||
| 267 | /// setup() | ||
| 268 | /// (...processing...) | ||
| 269 | /// reject() | ||
| 270 | /// ``` | ||
| 271 | /// | ||
| 272 | /// The driver is responsible for handling the status stage. The stack DOES NOT do zero-length | ||
| 273 | /// calls to `data_in` or `data_out` for the status zero-length packet. The status stage should | ||
| 274 | /// be triggered by either `accept()`, or `data_in` with `last = true`. | ||
| 275 | /// | ||
| 276 | /// Note that the host can abandon a control request and send a new STATUS packet any time. If | ||
| 277 | /// a STATUS packet arrives at any time during `data_out`, `data_in`, `accept` or `reject`, | ||
| 278 | /// the driver must immediately return (with `EndpointError::Disabled` from `data_in`, `data_out`) | ||
| 279 | /// to let the stack call `setup()` again to start handling the new control request. Not doing | ||
| 280 | /// so will cause things to get stuck, because the host will never read/send the packet we're | ||
| 281 | /// waiting for. | ||
| 218 | pub trait ControlPipe { | 282 | pub trait ControlPipe { |
| 219 | /// Maximum packet size for the control pipe | 283 | /// Maximum packet size for the control pipe |
| 220 | fn max_packet_size(&self) -> usize; | 284 | fn max_packet_size(&self) -> usize; |
