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 super::class::ControlHandler;
 | 
			
		||||
use super::control::ControlHandler;
 | 
			
		||||
use super::descriptor::{BosWriter, DescriptorWriter};
 | 
			
		||||
use super::driver::{Driver, EndpointAllocError};
 | 
			
		||||
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)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[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;
 | 
			
		||||
 | 
			
		||||
mod builder;
 | 
			
		||||
pub mod class;
 | 
			
		||||
pub mod control;
 | 
			
		||||
pub mod descriptor;
 | 
			
		||||
pub mod driver;
 | 
			
		||||
@ -15,7 +14,6 @@ mod util;
 | 
			
		||||
 | 
			
		||||
use heapless::Vec;
 | 
			
		||||
 | 
			
		||||
use self::class::{ControlHandler, RequestStatus};
 | 
			
		||||
use self::control::*;
 | 
			
		||||
use self::descriptor::*;
 | 
			
		||||
use self::driver::*;
 | 
			
		||||
@ -288,7 +286,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
 | 
			
		||||
                    .map(|(_, h)| h);
 | 
			
		||||
                match 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 {
 | 
			
		||||
                            RequestStatus::Accepted => self.control.accept_in(resp.data).await,
 | 
			
		||||
                            RequestStatus::Rejected => self.control.reject(),
 | 
			
		||||
 | 
			
		||||
@ -3,8 +3,9 @@ use core::mem::{self, MaybeUninit};
 | 
			
		||||
use core::sync::atomic::{AtomicBool, Ordering};
 | 
			
		||||
use defmt::info;
 | 
			
		||||
use embassy::blocking_mutex::CriticalSectionMutex;
 | 
			
		||||
use embassy_usb::class::{ControlHandler, ControlInRequestStatus, RequestStatus};
 | 
			
		||||
use embassy_usb::control::{self, Request};
 | 
			
		||||
use embassy_usb::control::{
 | 
			
		||||
    self, ControlHandler, ControlIn, ControlInRequestStatus, Request, RequestStatus,
 | 
			
		||||
};
 | 
			
		||||
use embassy_usb::driver::{Endpoint, EndpointIn, EndpointOut, ReadError, WriteError};
 | 
			
		||||
use embassy_usb::{driver::Driver, types::*, UsbDeviceBuilder};
 | 
			
		||||
 | 
			
		||||
@ -124,7 +125,7 @@ impl ControlHandler for Control {
 | 
			
		||||
    fn control_in<'a>(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        req: Request,
 | 
			
		||||
        control: embassy_usb::class::ControlIn<'a>,
 | 
			
		||||
        control: ControlIn<'a>,
 | 
			
		||||
    ) -> ControlInRequestStatus<'a> {
 | 
			
		||||
        match req.request {
 | 
			
		||||
            // REQ_GET_ENCAPSULATED_COMMAND is not really supported - it will be rejected below.
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user