usb: simplify buffer handling for Control IN transfers.
This commit is contained in:
		
							parent
							
								
									bfce731982
								
							
						
					
					
						commit
						e99a3a1da4
					
				@ -131,6 +131,13 @@ pub enum OutResponse {
 | 
				
			|||||||
    Rejected,
 | 
					    Rejected,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Copy, Clone, Eq, PartialEq, Debug)]
 | 
				
			||||||
 | 
					#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
				
			||||||
 | 
					pub enum InResponse {
 | 
				
			||||||
 | 
					    Accepted(usize),
 | 
				
			||||||
 | 
					    Rejected,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A trait for implementing USB classes.
 | 
					/// A trait for implementing USB classes.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// All methods are optional callbacks that will be called by
 | 
					/// All methods are optional callbacks that will be called by
 | 
				
			||||||
@ -171,54 +178,7 @@ pub trait ControlHandler {
 | 
				
			|||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// * `req` - The request from the SETUP packet.
 | 
					    /// * `req` - The request from the SETUP packet.
 | 
				
			||||||
    /// * `control` - The control pipe.
 | 
					    /// * `control` - The control pipe.
 | 
				
			||||||
    fn control_in<'a>(&mut self, req: Request, control: ControlIn<'a>) -> InResponse<'a> {
 | 
					    fn control_in(&mut self, req: Request, resp: &mut [u8]) -> InResponse {
 | 
				
			||||||
        control.reject()
 | 
					        InResponse::Rejected
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Handle for a control IN transfer. When implementing a class, use the methods of this object to
 | 
					 | 
				
			||||||
/// response to the transfer with either data or an error (STALL condition). To ignore the request
 | 
					 | 
				
			||||||
/// and pass it on to the next class, call [`Self::ignore()`].
 | 
					 | 
				
			||||||
pub struct ControlIn<'a> {
 | 
					 | 
				
			||||||
    buf: &'a mut [u8],
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Eq, PartialEq, Debug)]
 | 
					 | 
				
			||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
					 | 
				
			||||||
pub struct InResponse<'a> {
 | 
					 | 
				
			||||||
    pub(crate) response: OutResponse,
 | 
					 | 
				
			||||||
    pub(crate) data: &'a [u8],
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<'a> InResponse<'a> {
 | 
					 | 
				
			||||||
    pub fn status(&self) -> OutResponse {
 | 
					 | 
				
			||||||
        self.response
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<'a> ControlIn<'a> {
 | 
					 | 
				
			||||||
    pub(crate) fn new(buf: &'a mut [u8]) -> Self {
 | 
					 | 
				
			||||||
        ControlIn { buf }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Accepts the transfer with the supplied buffer.
 | 
					 | 
				
			||||||
    pub fn accept(self, data: &[u8]) -> InResponse<'a> {
 | 
					 | 
				
			||||||
        assert!(data.len() < self.buf.len());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let buf = &mut self.buf[0..data.len()];
 | 
					 | 
				
			||||||
        buf.copy_from_slice(data);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        InResponse {
 | 
					 | 
				
			||||||
            response: OutResponse::Accepted,
 | 
					 | 
				
			||||||
            data: buf,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Rejects the transfer by stalling the pipe.
 | 
					 | 
				
			||||||
    pub fn reject(self) -> InResponse<'a> {
 | 
					 | 
				
			||||||
        InResponse {
 | 
					 | 
				
			||||||
            response: OutResponse::Rejected,
 | 
					 | 
				
			||||||
            data: &[],
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -278,7 +278,6 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
 | 
				
			|||||||
                _ => self.control.reject(),
 | 
					                _ => self.control.reject(),
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            (RequestType::Class, Recipient::Interface) => {
 | 
					            (RequestType::Class, Recipient::Interface) => {
 | 
				
			||||||
                let mut buf = [0; 128];
 | 
					 | 
				
			||||||
                let handler = self
 | 
					                let handler = self
 | 
				
			||||||
                    .interfaces
 | 
					                    .interfaces
 | 
				
			||||||
                    .iter_mut()
 | 
					                    .iter_mut()
 | 
				
			||||||
@ -286,10 +285,10 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
 | 
				
			|||||||
                    .map(|(_, h)| h);
 | 
					                    .map(|(_, h)| h);
 | 
				
			||||||
                match handler {
 | 
					                match handler {
 | 
				
			||||||
                    Some(handler) => {
 | 
					                    Some(handler) => {
 | 
				
			||||||
                        let resp = handler.control_in(req, ControlIn::new(&mut buf));
 | 
					                        let mut buf = [0; 128];
 | 
				
			||||||
                        match resp.response {
 | 
					                        match handler.control_in(req, &mut buf) {
 | 
				
			||||||
                            OutResponse::Accepted => self.control.accept_in(resp.data).await,
 | 
					                            InResponse::Accepted(len) => self.control.accept_in(&buf[..len]).await,
 | 
				
			||||||
                            OutResponse::Rejected => self.control.reject(),
 | 
					                            InResponse::Rejected => self.control.reject(),
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    None => self.control.reject(),
 | 
					                    None => self.control.reject(),
 | 
				
			||||||
 | 
				
			|||||||
@ -3,7 +3,7 @@ use core::mem::{self, MaybeUninit};
 | 
				
			|||||||
use core::sync::atomic::{AtomicBool, Ordering};
 | 
					use core::sync::atomic::{AtomicBool, Ordering};
 | 
				
			||||||
use defmt::info;
 | 
					use defmt::info;
 | 
				
			||||||
use embassy::blocking_mutex::CriticalSectionMutex;
 | 
					use embassy::blocking_mutex::CriticalSectionMutex;
 | 
				
			||||||
use embassy_usb::control::{self, ControlHandler, ControlIn, InResponse, OutResponse, Request};
 | 
					use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request};
 | 
				
			||||||
use embassy_usb::driver::{Endpoint, EndpointIn, EndpointOut, ReadError, WriteError};
 | 
					use embassy_usb::driver::{Endpoint, EndpointIn, EndpointOut, ReadError, WriteError};
 | 
				
			||||||
use embassy_usb::{driver::Driver, types::*, UsbDeviceBuilder};
 | 
					use embassy_usb::{driver::Driver, types::*, UsbDeviceBuilder};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -120,20 +120,19 @@ impl ControlHandler for Control {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn control_in<'a>(&mut self, req: Request, control: ControlIn<'a>) -> InResponse<'a> {
 | 
					    fn control_in(&mut self, req: Request, resp: &mut [u8]) -> InResponse {
 | 
				
			||||||
        match req.request {
 | 
					        match req.request {
 | 
				
			||||||
            // REQ_GET_ENCAPSULATED_COMMAND is not really supported - it will be rejected below.
 | 
					            // REQ_GET_ENCAPSULATED_COMMAND is not really supported - it will be rejected below.
 | 
				
			||||||
            REQ_GET_LINE_CODING if req.length == 7 => {
 | 
					            REQ_GET_LINE_CODING if req.length == 7 => {
 | 
				
			||||||
                info!("Sending line coding");
 | 
					                info!("Sending line coding");
 | 
				
			||||||
                let coding = self.shared().line_coding.lock(|x| x.get());
 | 
					                let coding = self.shared().line_coding.lock(|x| x.get());
 | 
				
			||||||
                let mut data = [0; 7];
 | 
					                resp[0..4].copy_from_slice(&coding.data_rate.to_le_bytes());
 | 
				
			||||||
                data[0..4].copy_from_slice(&coding.data_rate.to_le_bytes());
 | 
					                resp[4] = coding.stop_bits as u8;
 | 
				
			||||||
                data[4] = coding.stop_bits as u8;
 | 
					                resp[5] = coding.parity_type as u8;
 | 
				
			||||||
                data[5] = coding.parity_type as u8;
 | 
					                resp[6] = coding.data_bits;
 | 
				
			||||||
                data[6] = coding.data_bits;
 | 
					                InResponse::Accepted(7)
 | 
				
			||||||
                control.accept(&data)
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            _ => control.reject(),
 | 
					            _ => InResponse::Rejected,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user