aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2022-05-09 03:25:21 +0200
committerDario Nieuwenhuis <[email protected]>2022-05-09 03:43:24 +0200
commit02ae1138e1b67a18a0fea4f1871751ee1ad858c0 (patch)
tree4bd3c382e664a6eb3ecc9a7029b3ebeafcf8ad4a
parent7ed462a6575cba95e8f07d2d9516d5e7b33d7196 (diff)
usb: merge Control logic into main code.
Now that control stuff is called from just one place, there's no need to keep it as a separate struct.
-rw-r--r--embassy-usb/src/control.rs123
-rw-r--r--embassy-usb/src/lib.rs131
2 files changed, 86 insertions, 168 deletions
diff --git a/embassy-usb/src/control.rs b/embassy-usb/src/control.rs
index 4fc65b6a5..12e5303c3 100644
--- a/embassy-usb/src/control.rs
+++ b/embassy-usb/src/control.rs
@@ -1,7 +1,6 @@
1use core::mem; 1use core::mem;
2 2
3use super::types::*; 3use super::types::*;
4use crate::driver::{self, EndpointError};
5 4
6/// Control request type. 5/// Control request type.
7#[repr(u8)] 6#[repr(u8)]
@@ -194,125 +193,3 @@ pub trait ControlHandler {
194 None 193 None
195 } 194 }
196} 195}
197
198/// Typestate representing a ControlPipe in the DATA IN stage
199#[derive(Debug)]
200#[cfg_attr(feature = "defmt", derive(defmt::Format))]
201pub(crate) struct DataInStage {
202 pub(crate) length: usize,
203}
204
205/// Typestate representing a ControlPipe in the DATA OUT stage
206#[derive(Debug)]
207#[cfg_attr(feature = "defmt", derive(defmt::Format))]
208pub(crate) struct DataOutStage {
209 length: usize,
210}
211
212/// Typestate representing a ControlPipe in the STATUS stage
213#[derive(Debug)]
214#[cfg_attr(feature = "defmt", derive(defmt::Format))]
215pub(crate) struct StatusStage {}
216
217#[derive(Debug)]
218#[cfg_attr(feature = "defmt", derive(defmt::Format))]
219pub(crate) enum Setup {
220 DataIn(Request, DataInStage),
221 DataOut(Request, DataOutStage),
222}
223
224pub(crate) struct ControlPipe<C: driver::ControlPipe> {
225 control: C,
226}
227
228impl<C: driver::ControlPipe> ControlPipe<C> {
229 pub(crate) fn new(control: C) -> Self {
230 ControlPipe { control }
231 }
232
233 pub(crate) async fn setup(&mut self) -> Setup {
234 let req = self.control.setup().await;
235 trace!("control request: {:02x}", req);
236
237 match (req.direction, req.length) {
238 (UsbDirection::Out, n) => Setup::DataOut(
239 req,
240 DataOutStage {
241 length: usize::from(n),
242 },
243 ),
244 (UsbDirection::In, n) => Setup::DataIn(
245 req,
246 DataInStage {
247 length: usize::from(n),
248 },
249 ),
250 }
251 }
252
253 pub(crate) async fn data_out<'a>(
254 &mut self,
255 buf: &'a mut [u8],
256 stage: DataOutStage,
257 ) -> Result<(&'a [u8], StatusStage), EndpointError> {
258 if stage.length == 0 {
259 Ok((&[], StatusStage {}))
260 } else {
261 let req_length = stage.length;
262 let max_packet_size = self.control.max_packet_size();
263 let mut total = 0;
264
265 for chunk in buf.chunks_mut(max_packet_size) {
266 let size = self.control.data_out(chunk).await?;
267 total += size;
268 if size < max_packet_size || total == req_length {
269 break;
270 }
271 }
272
273 let res = &buf[0..total];
274 #[cfg(feature = "defmt")]
275 trace!(" control out data: {:02x}", res);
276 #[cfg(not(feature = "defmt"))]
277 trace!(" control out data: {:02x?}", res);
278
279 Ok((res, StatusStage {}))
280 }
281 }
282
283 pub(crate) async fn accept_in(&mut self, buf: &[u8], stage: DataInStage) {
284 #[cfg(feature = "defmt")]
285 trace!(" control in accept {:02x}", buf);
286 #[cfg(not(feature = "defmt"))]
287 trace!(" control in accept {:02x?}", buf);
288
289 let req_len = stage.length;
290 let len = buf.len().min(req_len);
291 let max_packet_size = self.control.max_packet_size();
292 let need_zlp = len != req_len && (len % usize::from(max_packet_size)) == 0;
293
294 let mut chunks = buf[0..len]
295 .chunks(max_packet_size)
296 .chain(need_zlp.then(|| -> &[u8] { &[] }));
297
298 while let Some(chunk) = chunks.next() {
299 match self.control.data_in(chunk, chunks.size_hint().0 == 0).await {
300 Ok(()) => {}
301 Err(e) => {
302 warn!("control accept_in failed: {:?}", e);
303 return;
304 }
305 }
306 }
307 }
308
309 pub(crate) fn accept(&mut self, _: StatusStage) {
310 trace!(" control accept");
311 self.control.accept();
312 }
313
314 pub(crate) fn reject(&mut self) {
315 trace!(" control reject");
316 self.control.reject();
317 }
318}
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index 690305885..99c0f8237 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -16,6 +16,7 @@ use embassy::util::{select, Either};
16use heapless::Vec; 16use heapless::Vec;
17 17
18use crate::descriptor_reader::foreach_endpoint; 18use crate::descriptor_reader::foreach_endpoint;
19use crate::driver::ControlPipe;
19 20
20use self::control::*; 21use self::control::*;
21use self::descriptor::*; 22use self::descriptor::*;
@@ -101,7 +102,7 @@ struct Interface<'d> {
101 102
102pub struct UsbDevice<'d, D: Driver<'d>> { 103pub struct UsbDevice<'d, D: Driver<'d>> {
103 control_buf: &'d mut [u8], 104 control_buf: &'d mut [u8],
104 control: ControlPipe<D::ControlPipe>, 105 control: D::ControlPipe,
105 inner: Inner<'d, D>, 106 inner: Inner<'d, D>,
106} 107}
107 108
@@ -144,7 +145,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
144 145
145 Self { 146 Self {
146 control_buf, 147 control_buf,
147 control: ControlPipe::new(control), 148 control,
148 inner: Inner { 149 inner: Inner {
149 bus, 150 bus,
150 config, 151 config,
@@ -192,52 +193,12 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
192 } 193 }
193 } 194 }
194 195
195 loop { 196 while !self.inner.suspended {
196 let control_fut = self.control.setup(); 197 let control_fut = self.control.setup();
197 let bus_fut = self.inner.bus.poll(); 198 let bus_fut = self.inner.bus.poll();
198 match select(bus_fut, control_fut).await { 199 match select(bus_fut, control_fut).await {
199 Either::First(evt) => { 200 Either::First(evt) => self.inner.handle_bus_event(evt),
200 self.inner.handle_bus_event(evt); 201 Either::Second(req) => self.handle_control(req).await,
201 if self.inner.suspended {
202 return;
203 }
204 }
205 Either::Second(req) => match req {
206 Setup::DataIn(req, mut stage) => {
207 // If we don't have an address yet, respond with max 1 packet.
208 // The host doesn't know our EP0 max packet size yet, and might assume
209 // a full-length packet is a short packet, thinking we're done sending data.
210 // See https://github.com/hathach/tinyusb/issues/184
211 const DEVICE_DESCRIPTOR_LEN: u8 = 18;
212 if self.inner.pending_address == 0
213 && self.inner.config.max_packet_size_0 < DEVICE_DESCRIPTOR_LEN
214 && (self.inner.config.max_packet_size_0 as usize) < stage.length
215 {
216 trace!("received control req while not addressed: capping response to 1 packet.");
217 stage.length = self.inner.config.max_packet_size_0 as _;
218 }
219
220 match self.inner.handle_control_in(req, &mut self.control_buf) {
221 InResponse::Accepted(data) => self.control.accept_in(data, stage).await,
222 InResponse::Rejected => self.control.reject(),
223 }
224 }
225 Setup::DataOut(req, stage) => {
226 let (data, stage) =
227 match self.control.data_out(self.control_buf, stage).await {
228 Ok(data) => data,
229 Err(_) => {
230 warn!("usb: failed to read CONTROL OUT data stage.");
231 return;
232 }
233 };
234
235 match self.inner.handle_control_out(req, data) {
236 OutResponse::Accepted => self.control.accept(stage),
237 OutResponse::Rejected => self.control.reject(),
238 }
239 }
240 },
241 } 202 }
242 } 203 }
243 } 204 }
@@ -288,6 +249,86 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
288 Err(RemoteWakeupError::InvalidState) 249 Err(RemoteWakeupError::InvalidState)
289 } 250 }
290 } 251 }
252
253 async fn handle_control(&mut self, req: Request) {
254 trace!("control request: {:02x}", req);
255
256 match req.direction {
257 UsbDirection::In => self.handle_control_in(req).await,
258 UsbDirection::Out => self.handle_control_out(req).await,
259 }
260 }
261
262 async fn handle_control_in(&mut self, req: Request) {
263 let mut resp_length = req.length as usize;
264 let max_packet_size = self.control.max_packet_size();
265
266 // If we don't have an address yet, respond with max 1 packet.
267 // The host doesn't know our EP0 max packet size yet, and might assume
268 // a full-length packet is a short packet, thinking we're done sending data.
269 // See https://github.com/hathach/tinyusb/issues/184
270 const DEVICE_DESCRIPTOR_LEN: usize = 18;
271 if self.inner.pending_address == 0
272 && max_packet_size < DEVICE_DESCRIPTOR_LEN
273 && (max_packet_size as usize) < resp_length
274 {
275 trace!("received control req while not addressed: capping response to 1 packet.");
276 resp_length = max_packet_size;
277 }
278
279 match self.inner.handle_control_in(req, &mut self.control_buf) {
280 InResponse::Accepted(data) => {
281 let len = data.len().min(resp_length);
282 let need_zlp = len != resp_length && (len % usize::from(max_packet_size)) == 0;
283
284 let mut chunks = data[0..len]
285 .chunks(max_packet_size)
286 .chain(need_zlp.then(|| -> &[u8] { &[] }));
287
288 while let Some(chunk) = chunks.next() {
289 match self.control.data_in(chunk, chunks.size_hint().0 == 0).await {
290 Ok(()) => {}
291 Err(e) => {
292 warn!("control accept_in failed: {:?}", e);
293 return;
294 }
295 }
296 }
297 }
298 InResponse::Rejected => self.control.reject(),
299 }
300 }
301
302 async fn handle_control_out(&mut self, req: Request) {
303 let req_length = req.length as usize;
304 let max_packet_size = self.control.max_packet_size();
305 let mut total = 0;
306
307 for chunk in self.control_buf[..req_length].chunks_mut(max_packet_size) {
308 let size = match self.control.data_out(chunk).await {
309 Ok(x) => x,
310 Err(e) => {
311 warn!("usb: failed to read CONTROL OUT data stage: {:?}", e);
312 return;
313 }
314 };
315 total += size;
316 if size < max_packet_size || total == req_length {
317 break;
318 }
319 }
320
321 let data = &self.control_buf[0..total];
322 #[cfg(feature = "defmt")]
323 trace!(" control out data: {:02x}", data);
324 #[cfg(not(feature = "defmt"))]
325 trace!(" control out data: {:02x?}", data);
326
327 match self.inner.handle_control_out(req, data) {
328 OutResponse::Accepted => self.control.accept(),
329 OutResponse::Rejected => self.control.reject(),
330 }
331 }
291} 332}
292 333
293impl<'d, D: Driver<'d>> Inner<'d, D> { 334impl<'d, D: Driver<'d>> Inner<'d, D> {