usb: move all control-related stuff to mod control.
				
					
				
			This commit is contained in:
		
							parent
							
								
									15cc97d794
								
							
						
					
					
						commit
						2b547f311e
					
				@ -1,6 +1,6 @@
 | 
				
			|||||||
use heapless::Vec;
 | 
					use heapless::Vec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::class::ControlHandler;
 | 
					use super::control::ControlHandler;
 | 
				
			||||||
use super::descriptor::{BosWriter, DescriptorWriter};
 | 
					use super::descriptor::{BosWriter, DescriptorWriter};
 | 
				
			||||||
use super::driver::{Driver, EndpointAllocError};
 | 
					use super::driver::{Driver, EndpointAllocError};
 | 
				
			||||||
use super::types::*;
 | 
					use super::types::*;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,104 +0,0 @@
 | 
				
			|||||||
use crate::control::Request;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
 | 
					 | 
				
			||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
					 | 
				
			||||||
pub enum RequestStatus {
 | 
					 | 
				
			||||||
    Accepted,
 | 
					 | 
				
			||||||
    Rejected,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// A trait for implementing USB classes.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// All methods are optional callbacks that will be called by
 | 
					 | 
				
			||||||
/// [`UsbDevice::run()`](crate::UsbDevice::run)
 | 
					 | 
				
			||||||
pub trait ControlHandler {
 | 
					 | 
				
			||||||
    /// Called after a USB reset after the bus reset sequence is complete.
 | 
					 | 
				
			||||||
    fn reset(&mut self) {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Called when a control request is received with direction HostToDevice.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// All requests are passed to classes in turn, which can choose to accept, ignore or report an
 | 
					 | 
				
			||||||
    /// error. Classes can even choose to override standard requests, but doing that is rarely
 | 
					 | 
				
			||||||
    /// necessary.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// When implementing your own class, you should ignore any requests that are not meant for your
 | 
					 | 
				
			||||||
    /// class so that any other classes in the composite device can process them.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// # Arguments
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// * `req` - The request from the SETUP packet.
 | 
					 | 
				
			||||||
    /// * `data` - The data from the request.
 | 
					 | 
				
			||||||
    fn control_out(&mut self, req: Request, data: &[u8]) -> RequestStatus {
 | 
					 | 
				
			||||||
        RequestStatus::Rejected
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Called when a control request is received with direction DeviceToHost.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// All requests are passed to classes in turn, which can choose to accept, ignore or report an
 | 
					 | 
				
			||||||
    /// error. Classes can even choose to override standard requests, but doing that is rarely
 | 
					 | 
				
			||||||
    /// necessary.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// See [`ControlIn`] for how to respond to the transfer.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// When implementing your own class, you should ignore any requests that are not meant for your
 | 
					 | 
				
			||||||
    /// class so that any other classes in the composite device can process them.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// # Arguments
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// * `req` - The request from the SETUP packet.
 | 
					 | 
				
			||||||
    /// * `control` - The control pipe.
 | 
					 | 
				
			||||||
    fn control_in<'a>(
 | 
					 | 
				
			||||||
        &mut self,
 | 
					 | 
				
			||||||
        req: Request,
 | 
					 | 
				
			||||||
        control: ControlIn<'a>,
 | 
					 | 
				
			||||||
    ) -> ControlInRequestStatus<'a> {
 | 
					 | 
				
			||||||
        control.reject()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// 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 ControlInRequestStatus<'a> {
 | 
					 | 
				
			||||||
    pub(crate) status: RequestStatus,
 | 
					 | 
				
			||||||
    pub(crate) data: &'a [u8],
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<'a> ControlInRequestStatus<'a> {
 | 
					 | 
				
			||||||
    pub fn status(&self) -> RequestStatus {
 | 
					 | 
				
			||||||
        self.status
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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]) -> ControlInRequestStatus<'a> {
 | 
					 | 
				
			||||||
        assert!(data.len() < self.buf.len());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let buf = &mut self.buf[0..data.len()];
 | 
					 | 
				
			||||||
        buf.copy_from_slice(data);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        ControlInRequestStatus {
 | 
					 | 
				
			||||||
            status: RequestStatus::Accepted,
 | 
					 | 
				
			||||||
            data: buf,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Rejects the transfer by stalling the pipe.
 | 
					 | 
				
			||||||
    pub fn reject(self) -> ControlInRequestStatus<'a> {
 | 
					 | 
				
			||||||
        ControlInRequestStatus {
 | 
					 | 
				
			||||||
            status: RequestStatus::Rejected,
 | 
					 | 
				
			||||||
            data: &[],
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -123,3 +123,106 @@ impl Request {
 | 
				
			|||||||
        ((self.value >> 8) as u8, self.value as u8)
 | 
					        ((self.value >> 8) as u8, self.value as u8)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Copy, Clone, Eq, PartialEq, Debug)]
 | 
				
			||||||
 | 
					#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
				
			||||||
 | 
					pub enum RequestStatus {
 | 
				
			||||||
 | 
					    Accepted,
 | 
				
			||||||
 | 
					    Rejected,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// A trait for implementing USB classes.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// All methods are optional callbacks that will be called by
 | 
				
			||||||
 | 
					/// [`UsbDevice::run()`](crate::UsbDevice::run)
 | 
				
			||||||
 | 
					pub trait ControlHandler {
 | 
				
			||||||
 | 
					    /// Called after a USB reset after the bus reset sequence is complete.
 | 
				
			||||||
 | 
					    fn reset(&mut self) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Called when a control request is received with direction HostToDevice.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// All requests are passed to classes in turn, which can choose to accept, ignore or report an
 | 
				
			||||||
 | 
					    /// error. Classes can even choose to override standard requests, but doing that is rarely
 | 
				
			||||||
 | 
					    /// necessary.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// When implementing your own class, you should ignore any requests that are not meant for your
 | 
				
			||||||
 | 
					    /// class so that any other classes in the composite device can process them.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Arguments
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// * `req` - The request from the SETUP packet.
 | 
				
			||||||
 | 
					    /// * `data` - The data from the request.
 | 
				
			||||||
 | 
					    fn control_out(&mut self, req: Request, data: &[u8]) -> RequestStatus {
 | 
				
			||||||
 | 
					        RequestStatus::Rejected
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Called when a control request is received with direction DeviceToHost.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// All requests are passed to classes in turn, which can choose to accept, ignore or report an
 | 
				
			||||||
 | 
					    /// error. Classes can even choose to override standard requests, but doing that is rarely
 | 
				
			||||||
 | 
					    /// necessary.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// See [`ControlIn`] for how to respond to the transfer.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// When implementing your own class, you should ignore any requests that are not meant for your
 | 
				
			||||||
 | 
					    /// class so that any other classes in the composite device can process them.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Arguments
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// * `req` - The request from the SETUP packet.
 | 
				
			||||||
 | 
					    /// * `control` - The control pipe.
 | 
				
			||||||
 | 
					    fn control_in<'a>(
 | 
				
			||||||
 | 
					        &mut self,
 | 
				
			||||||
 | 
					        req: Request,
 | 
				
			||||||
 | 
					        control: ControlIn<'a>,
 | 
				
			||||||
 | 
					    ) -> ControlInRequestStatus<'a> {
 | 
				
			||||||
 | 
					        control.reject()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// 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 ControlInRequestStatus<'a> {
 | 
				
			||||||
 | 
					    pub(crate) status: RequestStatus,
 | 
				
			||||||
 | 
					    pub(crate) data: &'a [u8],
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> ControlInRequestStatus<'a> {
 | 
				
			||||||
 | 
					    pub fn status(&self) -> RequestStatus {
 | 
				
			||||||
 | 
					        self.status
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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]) -> ControlInRequestStatus<'a> {
 | 
				
			||||||
 | 
					        assert!(data.len() < self.buf.len());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let buf = &mut self.buf[0..data.len()];
 | 
				
			||||||
 | 
					        buf.copy_from_slice(data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ControlInRequestStatus {
 | 
				
			||||||
 | 
					            status: RequestStatus::Accepted,
 | 
				
			||||||
 | 
					            data: buf,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Rejects the transfer by stalling the pipe.
 | 
				
			||||||
 | 
					    pub fn reject(self) -> ControlInRequestStatus<'a> {
 | 
				
			||||||
 | 
					        ControlInRequestStatus {
 | 
				
			||||||
 | 
					            status: RequestStatus::Rejected,
 | 
				
			||||||
 | 
					            data: &[],
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,6 @@
 | 
				
			|||||||
pub(crate) mod fmt;
 | 
					pub(crate) mod fmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod builder;
 | 
					mod builder;
 | 
				
			||||||
pub mod class;
 | 
					 | 
				
			||||||
pub mod control;
 | 
					pub mod control;
 | 
				
			||||||
pub mod descriptor;
 | 
					pub mod descriptor;
 | 
				
			||||||
pub mod driver;
 | 
					pub mod driver;
 | 
				
			||||||
@ -15,7 +14,6 @@ mod util;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use heapless::Vec;
 | 
					use heapless::Vec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use self::class::{ControlHandler, RequestStatus};
 | 
					 | 
				
			||||||
use self::control::*;
 | 
					use self::control::*;
 | 
				
			||||||
use self::descriptor::*;
 | 
					use self::descriptor::*;
 | 
				
			||||||
use self::driver::*;
 | 
					use self::driver::*;
 | 
				
			||||||
@ -288,7 +286,7 @@ 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, class::ControlIn::new(&mut buf));
 | 
					                        let resp = handler.control_in(req, ControlIn::new(&mut buf));
 | 
				
			||||||
                        match resp.status {
 | 
					                        match resp.status {
 | 
				
			||||||
                            RequestStatus::Accepted => self.control.accept_in(resp.data).await,
 | 
					                            RequestStatus::Accepted => self.control.accept_in(resp.data).await,
 | 
				
			||||||
                            RequestStatus::Rejected => self.control.reject(),
 | 
					                            RequestStatus::Rejected => self.control.reject(),
 | 
				
			||||||
 | 
				
			|||||||
@ -3,8 +3,9 @@ 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::class::{ControlHandler, ControlInRequestStatus, RequestStatus};
 | 
					use embassy_usb::control::{
 | 
				
			||||||
use embassy_usb::control::{self, Request};
 | 
					    self, ControlHandler, ControlIn, ControlInRequestStatus, Request, RequestStatus,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
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};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -124,7 +125,7 @@ impl ControlHandler for Control {
 | 
				
			|||||||
    fn control_in<'a>(
 | 
					    fn control_in<'a>(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        req: Request,
 | 
					        req: Request,
 | 
				
			||||||
        control: embassy_usb::class::ControlIn<'a>,
 | 
					        control: ControlIn<'a>,
 | 
				
			||||||
    ) -> ControlInRequestStatus<'a> {
 | 
					    ) -> ControlInRequestStatus<'a> {
 | 
				
			||||||
        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.
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user