From dd4dd952d051ac23b147e01ec625bfabee505646 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 12 Jan 2020 13:18:39 +1100 Subject: [PATCH] Improve (subjective...) the descriptor fetching. --- xhcid/src/main.rs | 2 +- xhcid/src/usb/bos.rs | 134 ++++++++++++++++++++ xhcid/src/usb/config.rs | 2 + xhcid/src/usb/device.rs | 2 + xhcid/src/usb/endpoint.rs | 12 ++ xhcid/src/usb/mod.rs | 6 +- xhcid/src/xhci/context.rs | 3 +- xhcid/src/xhci/mod.rs | 20 ++- xhcid/src/xhci/scheme.rs | 254 ++++++++++++++++++++++++++++---------- xhcid/src/xhci/trb.rs | 12 ++ 10 files changed, 380 insertions(+), 67 deletions(-) create mode 100644 xhcid/src/usb/bos.rs diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index c97a0f382f..5ec46d9ee9 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -37,7 +37,7 @@ fn main() { // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { - let socket_fd = syscall::open(format!(":usb/{}-{}-{}", name, bar_str, irq_str), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("xhcid: failed to create usb scheme"); + let socket_fd = syscall::open(format!(":usb/{}", name), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("xhcid: failed to create usb scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); let mut irq_file = File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file"); diff --git a/xhcid/src/usb/bos.rs b/xhcid/src/usb/bos.rs new file mode 100644 index 0000000000..f72563fbee --- /dev/null +++ b/xhcid/src/usb/bos.rs @@ -0,0 +1,134 @@ +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct BosDescriptor { + pub len: u8, + pub kind: u8, + pub total_len: u16, + pub cap_count: u8, +} + +unsafe impl plain::Plain for BosDescriptor {} + +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct BosDevDescriptorBase { + pub len: u8, + pub kind: u8, + pub cap_ty: u8, +} + +unsafe impl plain::Plain for BosDevDescriptorBase {} + +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct BosSuperSpeedDesc { + pub len: u8, + pub kind: u8, + pub cap_ty: u8, + + pub attrs: u8, + pub speed_supp: u16, + pub func_supp: u8, + pub u1_dev_exit_lat: u8, + pub u2_dev_exit_lat: u16, +} +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct BosUsb2ExtDesc { + pub len: u8, + pub kind: u8, + pub cap_ty: u8, + + pub attrs: u32, +} + +unsafe impl plain::Plain for BosUsb2ExtDesc {} + +#[repr(u8)] +pub enum DeviceCapability { + Usb2Ext = 2, + SuperSpeed = 3, +} + +unsafe impl plain::Plain for BosSuperSpeedDesc {} + +pub struct BosDevDescIter<'a> { + bytes: &'a [u8], +} +impl<'a> BosDevDescIter<'a> { + pub fn new(bytes: &'a [u8]) -> Self { + Self { + bytes, + } + } +} +impl<'a> From<&'a [u8]> for BosDevDescIter<'a> { + fn from(slice: &'a [u8]) -> Self { + Self::new(slice) + } +} +impl<'a> Iterator for BosDevDescIter<'a> { + type Item = (BosDevDescriptorBase, &'a [u8]); + + fn next(&mut self) -> Option { + if let Some(desc) = plain::from_bytes::(self.bytes).ok() { + if desc.len as usize > self.bytes.len() { return None }; + let bytes_ret = &self.bytes[..desc.len as usize]; + self.bytes = &self.bytes[desc.len as usize..]; + Some((*desc, bytes_ret)) + } else { + return None; + } + } +} + +#[derive(Debug)] +pub enum BosAnyDevDesc { + SuperSpeed(BosSuperSpeedDesc), + Usb2Ext(BosUsb2ExtDesc), +} + +impl BosAnyDevDesc { + pub fn is_superspeed(&self) -> bool { + match self { + Self::SuperSpeed(_) => true, + _ => false, + } + } +} + +pub struct BosAnyDevDescIter<'a> { + inner: BosDevDescIter<'a>, +} +impl<'a> From> for BosAnyDevDescIter<'a> { + fn from(ll: BosDevDescIter<'a>) -> Self { + Self { inner: ll } + } +} +impl<'a> From<&'a [u8]> for BosAnyDevDescIter<'a> { + fn from(slice: &'a [u8]) -> Self { + Self::from(BosDevDescIter::from(slice)) + } +} +impl<'a> Iterator for BosAnyDevDescIter<'a> { + type Item = BosAnyDevDesc; + + fn next(&mut self) -> Option { + let (base, slice) = self.inner.next()?; + + if base.cap_ty == DeviceCapability::Usb2Ext as u8 { + Some(BosAnyDevDesc::Usb2Ext(*plain::from_bytes(slice).ok()?)) + } else if base.cap_ty == DeviceCapability::SuperSpeed as u8 { + Some(BosAnyDevDesc::SuperSpeed(*plain::from_bytes(slice).ok()?)) + } else if base.cap_ty == 0 { + // TODO + return None; + } else { + unimplemented!("USB device capability of type: {}", base.cap_ty) + } + } +} + +pub fn bos_capability_descs<'a>(desc: BosDescriptor, data: &'a [u8]) -> impl Iterator + 'a { + BosAnyDevDescIter::from(&data[..desc.total_len as usize - std::mem::size_of_val(&desc)]).take(desc.cap_count as usize) +} diff --git a/xhcid/src/usb/config.rs b/xhcid/src/usb/config.rs index e387c731dc..28dfe96199 100644 --- a/xhcid/src/usb/config.rs +++ b/xhcid/src/usb/config.rs @@ -10,3 +10,5 @@ pub struct ConfigDescriptor { pub attributes: u8, pub max_power: u8, } + +unsafe impl plain::Plain for ConfigDescriptor {} diff --git a/xhcid/src/usb/device.rs b/xhcid/src/usb/device.rs index 5ca20c6498..baeff1828a 100644 --- a/xhcid/src/usb/device.rs +++ b/xhcid/src/usb/device.rs @@ -16,3 +16,5 @@ pub struct DeviceDescriptor { pub serial_str: u8, pub configurations: u8, } + +unsafe impl plain::Plain for DeviceDescriptor {} diff --git a/xhcid/src/usb/endpoint.rs b/xhcid/src/usb/endpoint.rs index b06648f151..b50e0fa82a 100644 --- a/xhcid/src/usb/endpoint.rs +++ b/xhcid/src/usb/endpoint.rs @@ -12,3 +12,15 @@ pub struct EndpointDescriptor { } unsafe impl Plain for EndpointDescriptor {} + +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct SuperSpeedCompanionDescriptor { + pub length: u8, + pub kind: u8, + pub max_burst: u8, + pub attributes: u8, + pub bytes_per_interval: u16, +} + +unsafe impl Plain for SuperSpeedCompanionDescriptor {} diff --git a/xhcid/src/usb/mod.rs b/xhcid/src/usb/mod.rs index 27d0e94b6d..86496898e0 100644 --- a/xhcid/src/usb/mod.rs +++ b/xhcid/src/usb/mod.rs @@ -1,6 +1,7 @@ +pub use self::bos::{BosDescriptor, BosAnyDevDesc, BosSuperSpeedDesc, bos_capability_descs}; pub use self::config::ConfigDescriptor; pub use self::device::DeviceDescriptor; -pub use self::endpoint::EndpointDescriptor; +pub use self::endpoint::{EndpointDescriptor, SuperSpeedCompanionDescriptor}; pub use self::interface::InterfaceDescriptor; pub use self::setup::Setup; @@ -16,8 +17,11 @@ pub enum DescriptorKind { OtherSpeedConfiguration, InterfacePower, OnTheGo, + BinaryObjectStorage = 15, + SuperSpeedCompanion = 48, } +mod bos; mod config; mod device; mod endpoint; diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index 5f9a978bfe..bd8fb7c464 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -23,7 +23,8 @@ pub struct EndpointContext { #[repr(packed)] pub struct DeviceContext { pub slot: SlotContext, - pub endpoints: [EndpointContext; 15] + pub endpoints: [EndpointContext; 15], + // Shouldn't this be 31 (both for in and out)? } #[repr(packed)] diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 1a3255f137..4aceacd553 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -88,6 +88,16 @@ impl<'a> Device<'a> { Ok(*desc) } + fn get_bos(&mut self) -> Result<(usb::BosDescriptor, [u8; 4087])> { + let mut desc = Dma::<(usb::BosDescriptor, [u8; 4087])>::zeroed()?; + self.get_desc( + usb::DescriptorKind::BinaryObjectStorage, + 0, + &mut desc, + ); + Ok(*desc) + } + fn get_string(&mut self, index: u8) -> Result { let mut sdesc = Dma::<(u8, u8, [u16; 127])>::zeroed()?; self.get_desc( @@ -295,13 +305,19 @@ impl Xhci { { input.add_context.write(1 << 1 | 1); - input.device.slot.a.write((1 << 27) | (speed << 20)); + input.device.slot.a.write((1 << 27) | (speed << 20)); // FIXME: The speed field, bits 23:20, is deprecated. input.device.slot.b.write(((i as u32 + 1) & 0xFF) << 16); - input.device.endpoints[0].b.write(4096 << 16 | 4 << 3 | 3 << 1); + // control endpoint? + input.device.endpoints[0].b.write(4096 << 16 | 4 << 3 | 3 << 1); // packet size | control endpoint | allowed error count let tr = ring.register(); input.device.endpoints[0].trh.write((tr >> 32) as u32); input.device.endpoints[0].trl.write(tr as u32); + + // TODO: I presume that there should be additional endpoint contexts, for the + // endpoints specified in the USB descriptors. Perhaps the specific USB drivers + // (HID drivers, mass storage drivers, etc.) should enable these endpoints + // themselves. } { diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 218779b5cf..3f63908f6f 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1,4 +1,5 @@ use std::{cmp, mem, str}; +use std::convert::TryFrom; use std::io::prelude::*; use plain::Plain; @@ -23,6 +24,8 @@ pub enum Handle { TopLevel(usize, Vec), // offset, contents (ports) Port(usize, usize, Vec), // port, offset, contents PortDesc(usize, usize, Vec), // port, offset, contents + Endpoints(usize, usize, Vec), // port, offset, contents + Endpoint(usize, usize, usize), // port, endpoint, offset } #[derive(Serialize)] @@ -70,6 +73,17 @@ struct EndpDescJson { max_packet_size: u16, interval: u8, } +impl From for EndpDescJson { + fn from(d: usb::EndpointDescriptor) -> Self { + Self { + kind: d.kind, + address: d.address, + attributes: d.attributes, + interval: d.interval, + max_packet_size: d.max_packet_size, + } + } +} #[derive(Serialize)] struct IfDescJson { @@ -81,7 +95,81 @@ struct IfDescJson { sub_class: u8, protocol: u8, interface_str: Option, - endpoints: SmallVec<[EndpDescJson; 2]>, + endpoints: SmallVec<[AnyEndpDescJson; 4]>, +} +impl IfDescJson { + fn new(dev: &mut Device, desc: usb::InterfaceDescriptor, endps: impl IntoIterator) -> Result { + Ok(Self { + alternate_setting: desc.alternate_setting, + class: desc.class, + interface_str: if desc.interface_str > 0 { Some(dev.get_string(desc.interface_str)?) } else { None }, + kind: desc.kind, + number: desc.number, + protocol: desc.protocol, + sub_class: desc.sub_class, + endpoints: endps.into_iter().collect(), + }) + } +} + +#[derive(Serialize)] +struct SuperSpeedCmpJson { + kind: u8, + max_burst: u8, + attributes: u8, + bytes_per_interval: u16, +} + +impl From for SuperSpeedCmpJson { + fn from(d: usb::SuperSpeedCompanionDescriptor) -> Self { + Self { + kind: d.kind, + attributes: d.attributes, + bytes_per_interval: d.bytes_per_interval, + max_burst: d.max_burst, + } + } +} + +#[derive(Serialize)] +enum AnyEndpDescJson { + Endp(EndpDescJson), + SuperSpeedCmp(SuperSpeedCmpJson), +} + +/// Any descriptor that can be stored in the config desc "data" area. +#[derive(Debug)] +enum AnyDescriptor { + // These are the ones that I have found, but there are more. + Device(usb::DeviceDescriptor), + Config(usb::ConfigDescriptor), + Interface(usb::InterfaceDescriptor), + Endpoint(usb::EndpointDescriptor), + SuperSpeedCompanion(usb::SuperSpeedCompanionDescriptor), +} + +impl AnyDescriptor { + fn parse(bytes: &[u8]) -> Option<(Self, usize)> { + // There has to be at least two bytes for the kind and length. + if bytes.len() < 2 { return None } + + let len = bytes[0]; + let kind = bytes[1]; + + if bytes.len() < len.into() { return None } + + Some((match kind { + 1 => Self::Device(*plain::from_bytes(bytes).ok()?), + 2 => Self::Config(*plain::from_bytes(bytes).ok()?), + 4 => Self::Interface(*plain::from_bytes(bytes).ok()?), + 5 => Self::Endpoint(*plain::from_bytes(bytes).ok()?), + 48 => Self::SuperSpeedCompanion(*plain::from_bytes(bytes).ok()?), + _ => { + //println!("Descriptor unknown {}: bytes {:#0x?}", kind, bytes); + return None; + } + }, len.into())) + } } impl Xhci { @@ -118,6 +206,11 @@ impl Xhci { } else { None }, ); + let (bos_desc, bos_data) = dev.get_bos()?; + writeln!(contents, "BOS BASE {:?}", bos_desc).unwrap(); + + let has_superspeed = usb::bos_capability_descs(bos_desc, &bos_data).inspect(|item| println!("{:?}", item)).any(|desc| desc.is_superspeed()); + let config_descs = (0..raw_dd.configurations).map(|index| -> Result<_> { // TODO: Actually, it seems like all descriptors contain a length field, and I // encountered a SuperSpeed descriptor when endpoints were expected. The right way @@ -127,48 +220,45 @@ impl Xhci { let (desc, data) = dev.get_config(index)?; let extra_length = desc.total_length as usize - mem::size_of_val(&desc); + let data = &data[..extra_length]; let mut i = 0; + let mut descriptors = Vec::new(); - let mut interface_descs = SmallVec::with_capacity(desc.interfaces as usize); + while let Some((descriptor, len)) = AnyDescriptor::parse(&data[i..]) { + descriptors.push(descriptor); + i += len; + } - for _ in 0..desc.interfaces { - let mut idesc = usb::InterfaceDescriptor::default(); - if i < extra_length && i < data.len() && idesc.copy_from_bytes(&data[i..extra_length]).is_ok() { - i += mem::size_of_val(&idesc); + let mut interface_descs = SmallVec::new(); + let mut iter = descriptors.into_iter(); - let mut endpoints = SmallVec::with_capacity(idesc.endpoints as usize); + while let Some(item) = iter.next() { + if let AnyDescriptor::Interface(idesc) = item { + let mut endpoints = SmallVec::<[AnyEndpDescJson; 4]>::new(); - while endpoints.len() < idesc.endpoints as usize { - let mut edesc = usb::EndpointDescriptor::default(); - if i < extra_length && i < data.len() && edesc.copy_from_bytes(&data[i..extra_length]).is_ok() { - match edesc.kind { - // TODO: Constants - 5 => i += mem::size_of_val(&edesc), - 48 => { i += 6; continue } // SuperSpeed Endpoint Companion Descriptor - _ => unimplemented!(), - } + for _ in 0..idesc.endpoints { + let next = match iter.next() { + Some(AnyDescriptor::Endpoint(n)) => n, + _ => break, + }; + endpoints.push(AnyEndpDescJson::Endp(EndpDescJson::from(next))); - endpoints.push(EndpDescJson { - address: edesc.address, - attributes: edesc.attributes, - interval: edesc.interval, - kind: edesc.kind, - max_packet_size: edesc.max_packet_size, - }) - } else { break } + if has_superspeed { + dbg!(); + let next = match iter.next() { + Some(AnyDescriptor::SuperSpeedCompanion(n)) => n, + _ => break, + }; + dbg!(); + endpoints.push(AnyEndpDescJson::SuperSpeedCmp(SuperSpeedCmpJson::from(next))); + } } - interface_descs.push(IfDescJson { - kind: idesc.kind, - number: idesc.number, - alternate_setting: idesc.alternate_setting, - class: idesc.class, - sub_class: idesc.sub_class, - protocol: idesc.protocol, - interface_str: if idesc.interface_str > 0 { Some(dev.get_string(idesc.interface_str)?) } else { None }, - endpoints, - }); + interface_descs.push(IfDescJson::new(&mut dev, idesc, endpoints)?); + } else { + // TODO + break; } } @@ -236,32 +326,66 @@ impl SchemeMut for Xhci { let num_str = &path_str[4..slash_idx.unwrap_or(path_str.len())]; let num = num_str.parse::().or(Err(Error::new(ENOENT)))?; - if slash_idx.is_some() && slash_idx.unwrap() + 1 < path_str.len() && &path_str[slash_idx.unwrap() + 1..] == "descriptors" { - if flags & O_DIRECTORY != 0 { - return Err(Error::new(ENOTDIR)); - } - - let mut contents = Vec::new(); - self.write_port_desc(num, &mut contents)?; - - let fd = self.next_handle; - self.handles.insert(fd, Handle::PortDesc(num, 0, contents)); - self.next_handle += 1; - return Ok(fd); - } - - if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 { - let mut contents = Vec::new(); - - write!(contents, "descriptors\n").unwrap(); - - let fd = self.next_handle; - self.handles.insert(fd, Handle::Port(num, 0, contents)); - self.next_handle += 1; - Ok(fd) + let subdir_str = if slash_idx.is_some() && slash_idx.unwrap() + 1 < path_str.len() { + Some(&path_str[slash_idx.unwrap() + 1..]) } else { - return Err(Error::new(EISDIR)); - } + None + }; + + let handle = match subdir_str { + Some("descriptors") => { + if flags & O_DIRECTORY != 0 { + return Err(Error::new(ENOTDIR)); + } + + let mut contents = Vec::new(); + self.write_port_desc(num, &mut contents)?; + + Handle::PortDesc(num, 0, contents) + } + Some(other) if other.contains('/') => { + let slash_idx = other.chars().position(|c| c == '/').ok_or(Error::new(ENOENT))?; + if slash_idx + 2 >= other.len() { + return Err(Error::new(ENOENT)); + } + + let slice = &other[slash_idx + 2..]; + let endpoint_num = slice.parse::().or(Err(Error::new(ENOENT)))?; + Handle::Endpoint(num, endpoint_num, 0) + } + Some("endpoints") => { + if flags & O_DIRECTORY == 0 && flags & O_STAT == 0 { + return Err(Error::new(EISDIR)); + }; + let mut contents = Vec::new(); + let ps = &self.port_states[&num]; + + for (ep_num, _) in ps.input_context.device.endpoints.iter().enumerate().filter(|(_, ep)| ep.a.read() & 0b111 == 1) { + write!(contents, "i{}", ep_num).unwrap(); + } + for (ep_num, _) in self.dev_ctx.contexts[ps.slot as usize].endpoints.iter().enumerate().filter(|(_, ep)| ep.a.read() & 0b111 == 1) { + write!(contents, "o{}", ep_num).unwrap(); + } + + Handle::Endpoints(num, 0, contents) + } + Some(_) => return Err(Error::new(ENOENT)), + None => if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 { + let mut contents = Vec::new(); + + write!(contents, "descriptors\n").unwrap(); + + Handle::Port(num, 0, contents) + } else { + return Err(Error::new(EISDIR)); + } + }; + + let fd = self.next_handle; + self.next_handle += 1; + self.handles.insert(fd, handle); + + Ok(fd) } else { return Err(Error::new(ENOSYS)); } @@ -269,7 +393,7 @@ impl SchemeMut for Xhci { fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { match self.handles.get(&id).ok_or(Error::new(EBADF))? { - Handle::TopLevel(_, ref buf) | Handle::Port(_, _, ref buf) => { + Handle::TopLevel(_, ref buf) | Handle::Port(_, _, ref buf) | Handle::Endpoints(_, _, ref buf) => { // TODO: Known size perhaps? stat.st_mode = MODE_DIR; stat.st_size = buf.len() as u64; @@ -280,12 +404,16 @@ impl SchemeMut for Xhci { stat.st_size = buf.len() as u64; Ok(0) } + Handle::Endpoint(_, _, _) => { + stat.st_mode = MODE_FILE; + Ok(0) + } } } fn seek(&mut self, fd: usize, pos: usize, whence: usize) -> Result { match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::TopLevel(ref mut offset, ref buf) | Handle::Port(_, ref mut offset, ref buf) | Handle::PortDesc(_, ref mut offset, ref buf) => { + Handle::TopLevel(ref mut offset, ref buf) | Handle::Port(_, ref mut offset, ref buf) | Handle::PortDesc(_, ref mut offset, ref buf) | Handle::Endpoints(_, ref mut offset, ref buf) => { *offset = match whence { SEEK_SET => cmp::max(0, cmp::min(pos, buf.len())), SEEK_CUR => cmp::max(0, cmp::min(*offset + pos, buf.len())), @@ -294,12 +422,13 @@ impl SchemeMut for Xhci { }; Ok(*offset) } + Handle::Endpoint(_, _, _) => unimplemented!(), } } fn read(&mut self, fd: usize, buf: &mut [u8]) -> Result { match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::TopLevel(ref mut offset, ref src_buf) | Handle::Port(_, ref mut offset, ref src_buf) | Handle::PortDesc(_, ref mut offset, ref src_buf) => { + Handle::TopLevel(ref mut offset, ref src_buf) | Handle::Port(_, ref mut offset, ref src_buf) | Handle::PortDesc(_, ref mut offset, ref src_buf) | Handle::Endpoints(_, ref mut offset, ref src_buf) => { let max_bytes_to_read = cmp::min(src_buf.len(), buf.len()); let bytes_to_read = cmp::max(max_bytes_to_read, *offset) - *offset; @@ -308,6 +437,7 @@ impl SchemeMut for Xhci { Ok(bytes_to_read) } + Handle::Endpoint(_, _, _) => unimplemented!(), } } fn close(&mut self, fd: usize) -> Result { diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 459fdc6b4a..49db6e5115 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -164,6 +164,18 @@ impl Trb { (cycle as u32) ); } + // Synchronizes the input context endpoints with the device context endpoints, it think. + pub fn configure_endpoint(&mut self, slot_id: u8, input_ctx_ptr: usize, cycle: bool) { + assert_eq!(input_ctx_ptr & 0xFFFF_FFFF_FFFF_FFF0, input_ctx_ptr); + + self.set( + (input_ctx_ptr >> 4) as u64, + 0, + (u32::from(slot_id) << 24) | + ((TrbType::ConfigureEndpoint as u32) << 10) | + (cycle as u32), + ) + } pub fn setup(&mut self, setup: usb::Setup, transfer: TransferKind, cycle: bool) { self.set(