usb: unify ControlHandler+DeviceStateHandler, route all control requests to all handlers.
- Allows classes to handle vendor requests. - Allows classes to use a single handler for multiple interfaces. - Allows classes to access the other events (previously only `reset` was available).
This commit is contained in:
@ -6,10 +6,10 @@ use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use embassy_sync::blocking_mutex::CriticalSectionMutex;
|
||||
|
||||
use crate::control::{self, ControlHandler, InResponse, OutResponse, Request};
|
||||
use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType};
|
||||
use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
|
||||
use crate::types::*;
|
||||
use crate::Builder;
|
||||
use crate::{Builder, Handler};
|
||||
|
||||
/// This should be used as `device_class` when building the `UsbDevice`.
|
||||
pub const USB_CLASS_CDC: u8 = 0x02;
|
||||
@ -67,6 +67,7 @@ pub struct CdcAcmClass<'d, D: Driver<'d>> {
|
||||
}
|
||||
|
||||
struct Control<'a> {
|
||||
comm_if: InterfaceNumber,
|
||||
shared: &'a ControlShared,
|
||||
}
|
||||
|
||||
@ -98,7 +99,7 @@ impl<'a> Control<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> ControlHandler for Control<'d> {
|
||||
impl<'d> Handler for Control<'d> {
|
||||
fn reset(&mut self) {
|
||||
let shared = self.shared();
|
||||
shared.line_coding.lock(|x| x.set(LineCoding::default()));
|
||||
@ -106,12 +107,18 @@ impl<'d> ControlHandler for Control<'d> {
|
||||
shared.rts.store(false, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
fn control_out(&mut self, req: control::Request, data: &[u8]) -> OutResponse {
|
||||
fn control_out(&mut self, req: control::Request, data: &[u8]) -> Option<OutResponse> {
|
||||
if (req.request_type, req.recipient, req.index)
|
||||
!= (RequestType::Class, Recipient::Interface, self.comm_if.0 as u16)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
match req.request {
|
||||
REQ_SEND_ENCAPSULATED_COMMAND => {
|
||||
// We don't actually support encapsulated commands but pretend we do for standards
|
||||
// compatibility.
|
||||
OutResponse::Accepted
|
||||
Some(OutResponse::Accepted)
|
||||
}
|
||||
REQ_SET_LINE_CODING if data.len() >= 7 => {
|
||||
let coding = LineCoding {
|
||||
@ -123,7 +130,7 @@ impl<'d> ControlHandler for Control<'d> {
|
||||
self.shared().line_coding.lock(|x| x.set(coding));
|
||||
debug!("Set line coding to: {:?}", coding);
|
||||
|
||||
OutResponse::Accepted
|
||||
Some(OutResponse::Accepted)
|
||||
}
|
||||
REQ_SET_CONTROL_LINE_STATE => {
|
||||
let dtr = (req.value & 0x0001) != 0;
|
||||
@ -134,13 +141,19 @@ impl<'d> ControlHandler for Control<'d> {
|
||||
shared.rts.store(rts, Ordering::Relaxed);
|
||||
debug!("Set dtr {}, rts {}", dtr, rts);
|
||||
|
||||
OutResponse::Accepted
|
||||
Some(OutResponse::Accepted)
|
||||
}
|
||||
_ => OutResponse::Rejected,
|
||||
_ => Some(OutResponse::Rejected),
|
||||
}
|
||||
}
|
||||
|
||||
fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> {
|
||||
fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> Option<InResponse<'a>> {
|
||||
if (req.request_type, req.recipient, req.index)
|
||||
!= (RequestType::Class, Recipient::Interface, self.comm_if.0 as u16)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
match req.request {
|
||||
// REQ_GET_ENCAPSULATED_COMMAND is not really supported - it will be rejected below.
|
||||
REQ_GET_LINE_CODING if req.length == 7 => {
|
||||
@ -151,9 +164,9 @@ impl<'d> ControlHandler for Control<'d> {
|
||||
buf[4] = coding.stop_bits as u8;
|
||||
buf[5] = coding.parity_type as u8;
|
||||
buf[6] = coding.data_bits;
|
||||
InResponse::Accepted(&buf[0..7])
|
||||
Some(InResponse::Accepted(&buf[0..7]))
|
||||
}
|
||||
_ => InResponse::Rejected,
|
||||
_ => Some(InResponse::Rejected),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -162,17 +175,12 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
|
||||
/// Creates a new CdcAcmClass with the provided UsbBus and max_packet_size in bytes. For
|
||||
/// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64.
|
||||
pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, max_packet_size: u16) -> Self {
|
||||
let control = state.control.write(Control { shared: &state.shared });
|
||||
|
||||
let control_shared = &state.shared;
|
||||
|
||||
assert!(builder.control_buf_len() >= 7);
|
||||
|
||||
let mut func = builder.function(USB_CLASS_CDC, CDC_SUBCLASS_ACM, CDC_PROTOCOL_NONE);
|
||||
|
||||
// Control interface
|
||||
let mut iface = func.interface();
|
||||
iface.handler(control);
|
||||
let comm_if = iface.interface_number();
|
||||
let data_if = u8::from(comm_if) + 1;
|
||||
let mut alt = iface.alt_setting(USB_CLASS_CDC, CDC_SUBCLASS_ACM, CDC_PROTOCOL_NONE, None);
|
||||
@ -213,6 +221,16 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
|
||||
let read_ep = alt.endpoint_bulk_out(max_packet_size);
|
||||
let write_ep = alt.endpoint_bulk_in(max_packet_size);
|
||||
|
||||
drop(func);
|
||||
|
||||
let control = state.control.write(Control {
|
||||
shared: &state.shared,
|
||||
comm_if,
|
||||
});
|
||||
builder.handler(control);
|
||||
|
||||
let control_shared = &state.shared;
|
||||
|
||||
CdcAcmClass {
|
||||
_comm_ep: comm_ep,
|
||||
_data_if: data_if,
|
||||
|
@ -17,10 +17,10 @@
|
||||
use core::intrinsics::copy_nonoverlapping;
|
||||
use core::mem::{size_of, MaybeUninit};
|
||||
|
||||
use crate::control::{self, ControlHandler, InResponse, OutResponse, Request};
|
||||
use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType};
|
||||
use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
|
||||
use crate::types::*;
|
||||
use crate::Builder;
|
||||
use crate::{Builder, Handler};
|
||||
|
||||
pub mod embassy_net;
|
||||
|
||||
@ -117,8 +117,7 @@ fn byteify<T>(buf: &mut [u8], data: T) -> &[u8] {
|
||||
|
||||
/// Internal state for the CDC-NCM class.
|
||||
pub struct State<'a> {
|
||||
comm_control: MaybeUninit<CommControl<'a>>,
|
||||
data_control: MaybeUninit<DataControl>,
|
||||
control: MaybeUninit<Control<'a>>,
|
||||
shared: ControlShared,
|
||||
}
|
||||
|
||||
@ -126,8 +125,7 @@ impl<'a> State<'a> {
|
||||
/// Create a new `State`.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
comm_control: MaybeUninit::uninit(),
|
||||
data_control: MaybeUninit::uninit(),
|
||||
control: MaybeUninit::uninit(),
|
||||
shared: Default::default(),
|
||||
}
|
||||
}
|
||||
@ -144,29 +142,55 @@ impl Default for ControlShared {
|
||||
}
|
||||
}
|
||||
|
||||
struct CommControl<'a> {
|
||||
struct Control<'a> {
|
||||
mac_addr_string: StringIndex,
|
||||
shared: &'a ControlShared,
|
||||
mac_addr_str: [u8; 12],
|
||||
comm_if: InterfaceNumber,
|
||||
data_if: InterfaceNumber,
|
||||
}
|
||||
|
||||
impl<'d> ControlHandler for CommControl<'d> {
|
||||
fn control_out(&mut self, req: control::Request, _data: &[u8]) -> OutResponse {
|
||||
impl<'d> Handler for Control<'d> {
|
||||
fn set_alternate_setting(&mut self, iface: InterfaceNumber, alternate_setting: u8) {
|
||||
if iface != self.data_if {
|
||||
return;
|
||||
}
|
||||
|
||||
match alternate_setting {
|
||||
ALTERNATE_SETTING_ENABLED => info!("ncm: interface enabled"),
|
||||
ALTERNATE_SETTING_DISABLED => info!("ncm: interface disabled"),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn control_out(&mut self, req: control::Request, _data: &[u8]) -> Option<OutResponse> {
|
||||
if (req.request_type, req.recipient, req.index)
|
||||
!= (RequestType::Class, Recipient::Interface, self.comm_if.0 as u16)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
match req.request {
|
||||
REQ_SEND_ENCAPSULATED_COMMAND => {
|
||||
// We don't actually support encapsulated commands but pretend we do for standards
|
||||
// compatibility.
|
||||
OutResponse::Accepted
|
||||
Some(OutResponse::Accepted)
|
||||
}
|
||||
REQ_SET_NTB_INPUT_SIZE => {
|
||||
// TODO
|
||||
OutResponse::Accepted
|
||||
Some(OutResponse::Accepted)
|
||||
}
|
||||
_ => OutResponse::Rejected,
|
||||
_ => Some(OutResponse::Rejected),
|
||||
}
|
||||
}
|
||||
|
||||
fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> {
|
||||
fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> Option<InResponse<'a>> {
|
||||
if (req.request_type, req.recipient, req.index)
|
||||
!= (RequestType::Class, Recipient::Interface, self.comm_if.0 as u16)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
match req.request {
|
||||
REQ_GET_NTB_PARAMETERS => {
|
||||
let res = NtbParameters {
|
||||
@ -187,9 +211,9 @@ impl<'d> ControlHandler for CommControl<'d> {
|
||||
max_datagram_count: 1, // We only decode 1 packet per NTB
|
||||
},
|
||||
};
|
||||
InResponse::Accepted(byteify(buf, res))
|
||||
Some(InResponse::Accepted(byteify(buf, res)))
|
||||
}
|
||||
_ => InResponse::Rejected,
|
||||
_ => Some(InResponse::Rejected),
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,18 +238,6 @@ impl<'d> ControlHandler for CommControl<'d> {
|
||||
}
|
||||
}
|
||||
|
||||
struct DataControl {}
|
||||
|
||||
impl ControlHandler for DataControl {
|
||||
fn set_alternate_setting(&mut self, alternate_setting: u8) {
|
||||
match alternate_setting {
|
||||
ALTERNATE_SETTING_ENABLED => info!("ncm: interface enabled"),
|
||||
ALTERNATE_SETTING_DISABLED => info!("ncm: interface disabled"),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// CDC-NCM class
|
||||
pub struct CdcNcmClass<'d, D: Driver<'d>> {
|
||||
_comm_if: InterfaceNumber,
|
||||
@ -253,11 +265,6 @@ impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> {
|
||||
// Control interface
|
||||
let mut iface = func.interface();
|
||||
let mac_addr_string = iface.string();
|
||||
iface.handler(state.comm_control.write(CommControl {
|
||||
mac_addr_string,
|
||||
shared: &state.shared,
|
||||
mac_addr_str: [0; 12],
|
||||
}));
|
||||
let comm_if = iface.interface_number();
|
||||
let mut alt = iface.alt_setting(USB_CLASS_CDC, CDC_SUBCLASS_NCM, CDC_PROTOCOL_NONE, None);
|
||||
|
||||
@ -307,13 +314,23 @@ impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> {
|
||||
|
||||
// Data interface
|
||||
let mut iface = func.interface();
|
||||
iface.handler(state.data_control.write(DataControl {}));
|
||||
let data_if = iface.interface_number();
|
||||
let _alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NTB, None);
|
||||
let mut alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NTB, None);
|
||||
let read_ep = alt.endpoint_bulk_out(max_packet_size);
|
||||
let write_ep = alt.endpoint_bulk_in(max_packet_size);
|
||||
|
||||
drop(func);
|
||||
|
||||
let control = state.control.write(Control {
|
||||
mac_addr_string,
|
||||
shared: &state.shared,
|
||||
mac_addr_str: [0; 12],
|
||||
comm_if,
|
||||
data_if,
|
||||
});
|
||||
builder.handler(control);
|
||||
|
||||
CdcNcmClass {
|
||||
_comm_if: comm_if,
|
||||
comm_ep,
|
||||
|
@ -9,9 +9,10 @@ use ssmarshal::serialize;
|
||||
#[cfg(feature = "usbd-hid")]
|
||||
use usbd_hid::descriptor::AsInputReport;
|
||||
|
||||
use crate::control::{ControlHandler, InResponse, OutResponse, Request, RequestType};
|
||||
use crate::control::{InResponse, OutResponse, Recipient, Request, RequestType};
|
||||
use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
|
||||
use crate::Builder;
|
||||
use crate::types::InterfaceNumber;
|
||||
use crate::{Builder, Handler};
|
||||
|
||||
const USB_CLASS_HID: u8 = 0x03;
|
||||
const USB_SUBCLASS_NONE: u8 = 0x00;
|
||||
@ -100,17 +101,11 @@ fn build<'d, D: Driver<'d>>(
|
||||
config: Config<'d>,
|
||||
with_out_endpoint: bool,
|
||||
) -> (Option<D::EndpointOut>, D::EndpointIn, &'d AtomicUsize) {
|
||||
let control = state.control.write(Control::new(
|
||||
config.report_descriptor,
|
||||
config.request_handler,
|
||||
&state.out_report_offset,
|
||||
));
|
||||
|
||||
let len = config.report_descriptor.len();
|
||||
|
||||
let mut func = builder.function(USB_CLASS_HID, USB_SUBCLASS_NONE, USB_PROTOCOL_NONE);
|
||||
let mut iface = func.interface();
|
||||
iface.handler(control);
|
||||
let if_num = iface.interface_number();
|
||||
let mut alt = iface.alt_setting(USB_CLASS_HID, USB_SUBCLASS_NONE, USB_PROTOCOL_NONE, None);
|
||||
|
||||
// HID descriptor
|
||||
@ -139,6 +134,16 @@ fn build<'d, D: Driver<'d>>(
|
||||
None
|
||||
};
|
||||
|
||||
drop(func);
|
||||
|
||||
let control = state.control.write(Control::new(
|
||||
if_num,
|
||||
config.report_descriptor,
|
||||
config.request_handler,
|
||||
&state.out_report_offset,
|
||||
));
|
||||
builder.handler(control);
|
||||
|
||||
(ep_out, ep_in, &state.out_report_offset)
|
||||
}
|
||||
|
||||
@ -400,6 +405,7 @@ pub trait RequestHandler {
|
||||
}
|
||||
|
||||
struct Control<'d> {
|
||||
if_num: InterfaceNumber,
|
||||
report_descriptor: &'d [u8],
|
||||
request_handler: Option<&'d dyn RequestHandler>,
|
||||
out_report_offset: &'d AtomicUsize,
|
||||
@ -408,11 +414,13 @@ struct Control<'d> {
|
||||
|
||||
impl<'d> Control<'d> {
|
||||
fn new(
|
||||
if_num: InterfaceNumber,
|
||||
report_descriptor: &'d [u8],
|
||||
request_handler: Option<&'d dyn RequestHandler>,
|
||||
out_report_offset: &'d AtomicUsize,
|
||||
) -> Self {
|
||||
Control {
|
||||
if_num,
|
||||
report_descriptor,
|
||||
request_handler,
|
||||
out_report_offset,
|
||||
@ -438,88 +446,100 @@ impl<'d> Control<'d> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> ControlHandler for Control<'d> {
|
||||
impl<'d> Handler for Control<'d> {
|
||||
fn reset(&mut self) {
|
||||
self.out_report_offset.store(0, Ordering::Release);
|
||||
}
|
||||
|
||||
fn get_descriptor<'a>(&'a mut self, req: Request, _buf: &'a mut [u8]) -> InResponse<'a> {
|
||||
match (req.value >> 8) as u8 {
|
||||
HID_DESC_DESCTYPE_HID_REPORT => InResponse::Accepted(self.report_descriptor),
|
||||
HID_DESC_DESCTYPE_HID => InResponse::Accepted(&self.hid_descriptor),
|
||||
_ => InResponse::Rejected,
|
||||
fn control_out(&mut self, req: Request, data: &[u8]) -> Option<OutResponse> {
|
||||
if (req.request_type, req.recipient, req.index)
|
||||
!= (RequestType::Class, Recipient::Interface, self.if_num.0 as u16)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
fn control_out(&mut self, req: Request, data: &[u8]) -> OutResponse {
|
||||
trace!("HID control_out {:?} {=[u8]:x}", req, data);
|
||||
if let RequestType::Class = req.request_type {
|
||||
match req.request {
|
||||
HID_REQ_SET_IDLE => {
|
||||
if let Some(handler) = self.request_handler {
|
||||
let id = req.value as u8;
|
||||
let id = (id != 0).then(|| ReportId::In(id));
|
||||
let dur = u32::from(req.value >> 8);
|
||||
let dur = if dur == 0 { u32::MAX } else { 4 * dur };
|
||||
handler.set_idle_ms(id, dur);
|
||||
}
|
||||
OutResponse::Accepted
|
||||
}
|
||||
HID_REQ_SET_REPORT => match (ReportId::try_from(req.value), self.request_handler) {
|
||||
(Ok(id), Some(handler)) => handler.set_report(id, data),
|
||||
_ => OutResponse::Rejected,
|
||||
},
|
||||
HID_REQ_SET_PROTOCOL => {
|
||||
if req.value == 1 {
|
||||
OutResponse::Accepted
|
||||
} else {
|
||||
warn!("HID Boot Protocol is unsupported.");
|
||||
OutResponse::Rejected // UNSUPPORTED: Boot Protocol
|
||||
}
|
||||
}
|
||||
_ => OutResponse::Rejected,
|
||||
}
|
||||
} else {
|
||||
OutResponse::Rejected // UNSUPPORTED: SET_DESCRIPTOR
|
||||
}
|
||||
}
|
||||
|
||||
fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> {
|
||||
trace!("HID control_in {:?}", req);
|
||||
match req.request {
|
||||
HID_REQ_GET_REPORT => {
|
||||
let size = match ReportId::try_from(req.value) {
|
||||
Ok(id) => self.request_handler.and_then(|x| x.get_report(id, buf)),
|
||||
Err(_) => None,
|
||||
};
|
||||
|
||||
if let Some(size) = size {
|
||||
InResponse::Accepted(&buf[0..size])
|
||||
} else {
|
||||
InResponse::Rejected
|
||||
}
|
||||
}
|
||||
HID_REQ_GET_IDLE => {
|
||||
HID_REQ_SET_IDLE => {
|
||||
if let Some(handler) = self.request_handler {
|
||||
let id = req.value as u8;
|
||||
let id = (id != 0).then(|| ReportId::In(id));
|
||||
if let Some(dur) = handler.get_idle_ms(id) {
|
||||
let dur = u8::try_from(dur / 4).unwrap_or(0);
|
||||
buf[0] = dur;
|
||||
InResponse::Accepted(&buf[0..1])
|
||||
} else {
|
||||
InResponse::Rejected
|
||||
}
|
||||
let dur = u32::from(req.value >> 8);
|
||||
let dur = if dur == 0 { u32::MAX } else { 4 * dur };
|
||||
handler.set_idle_ms(id, dur);
|
||||
}
|
||||
Some(OutResponse::Accepted)
|
||||
}
|
||||
HID_REQ_SET_REPORT => match (ReportId::try_from(req.value), self.request_handler) {
|
||||
(Ok(id), Some(handler)) => Some(handler.set_report(id, data)),
|
||||
_ => Some(OutResponse::Rejected),
|
||||
},
|
||||
HID_REQ_SET_PROTOCOL => {
|
||||
if req.value == 1 {
|
||||
Some(OutResponse::Accepted)
|
||||
} else {
|
||||
InResponse::Rejected
|
||||
warn!("HID Boot Protocol is unsupported.");
|
||||
Some(OutResponse::Rejected) // UNSUPPORTED: Boot Protocol
|
||||
}
|
||||
}
|
||||
HID_REQ_GET_PROTOCOL => {
|
||||
// UNSUPPORTED: Boot Protocol
|
||||
buf[0] = 1;
|
||||
InResponse::Accepted(&buf[0..1])
|
||||
_ => Some(OutResponse::Rejected),
|
||||
}
|
||||
}
|
||||
|
||||
fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> Option<InResponse<'a>> {
|
||||
if req.index != self.if_num.0 as u16 {
|
||||
return None;
|
||||
}
|
||||
|
||||
match (req.request_type, req.recipient) {
|
||||
(RequestType::Standard, Recipient::Interface) => match req.request {
|
||||
Request::GET_DESCRIPTOR => match (req.value >> 8) as u8 {
|
||||
HID_DESC_DESCTYPE_HID_REPORT => Some(InResponse::Accepted(self.report_descriptor)),
|
||||
HID_DESC_DESCTYPE_HID => Some(InResponse::Accepted(&self.hid_descriptor)),
|
||||
_ => Some(InResponse::Rejected),
|
||||
},
|
||||
|
||||
_ => Some(InResponse::Rejected),
|
||||
},
|
||||
(RequestType::Class, Recipient::Interface) => {
|
||||
trace!("HID control_in {:?}", req);
|
||||
match req.request {
|
||||
HID_REQ_GET_REPORT => {
|
||||
let size = match ReportId::try_from(req.value) {
|
||||
Ok(id) => self.request_handler.and_then(|x| x.get_report(id, buf)),
|
||||
Err(_) => None,
|
||||
};
|
||||
|
||||
if let Some(size) = size {
|
||||
Some(InResponse::Accepted(&buf[0..size]))
|
||||
} else {
|
||||
Some(InResponse::Rejected)
|
||||
}
|
||||
}
|
||||
HID_REQ_GET_IDLE => {
|
||||
if let Some(handler) = self.request_handler {
|
||||
let id = req.value as u8;
|
||||
let id = (id != 0).then(|| ReportId::In(id));
|
||||
if let Some(dur) = handler.get_idle_ms(id) {
|
||||
let dur = u8::try_from(dur / 4).unwrap_or(0);
|
||||
buf[0] = dur;
|
||||
Some(InResponse::Accepted(&buf[0..1]))
|
||||
} else {
|
||||
Some(InResponse::Rejected)
|
||||
}
|
||||
} else {
|
||||
Some(InResponse::Rejected)
|
||||
}
|
||||
}
|
||||
HID_REQ_GET_PROTOCOL => {
|
||||
// UNSUPPORTED: Boot Protocol
|
||||
buf[0] = 1;
|
||||
Some(InResponse::Accepted(&buf[0..1]))
|
||||
}
|
||||
_ => Some(InResponse::Rejected),
|
||||
}
|
||||
}
|
||||
_ => InResponse::Rejected,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user