diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 1a3e35e03b..4077bdb912 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -25,7 +25,11 @@ use syscall::io::Io; use crate::xhci::{InterruptMethod, Xhci}; -mod driver_interface; +// Declare as pub so that no warnings appear due to parts of the interface code not being used by +// the driver. Since there's also a dedicated crate for the driver interface, those warnings don't +// mean anything. +pub mod driver_interface; + mod usb; mod xhci; @@ -181,7 +185,7 @@ fn main() { table_entry_pointer.msg_data.write(msg_data); table_entry_pointer.vec_ctl.writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); - (Some(interrupt_handle), InterruptMethod::MsiX(info)) + (Some(interrupt_handle), InterruptMethod::MsiX(Mutex::new(info))) } } else if pci_config.func.legacy_interrupt_pin.is_some() { // legacy INTx# interrupt pins. @@ -212,8 +216,9 @@ fn main() { File::from_raw_fd(socket_fd as RawFd) })); - let hci = Arc::new(Xhci::new(name, address, interrupt_method, irq_file.as_mut(), pcid_handle).expect("xhcid: failed to allocate device")); - hci.probe().expect("xhcid: failed to probe"); + let hci = Arc::new(Xhci::new(name, address, interrupt_method, pcid_handle).expect("xhcid: failed to allocate device")); + xhci::start_irq_reactor(&hci, irq_file); + futures::executor::block_on(hci.probe()).expect("xhcid: failed to probe"); let mut event_queue = EventQueue::<()>::new().expect("xhcid: failed to create event queue"); @@ -223,49 +228,12 @@ fn main() { let todo = Arc::new(Mutex::new(Vec::::new())); let todo_futures = Arc::new(Mutex::new(Vec:: + Send + Sync + 'static>>>::new())); - if let Some(irq_file) = irq_file { - let hci_irq = hci.clone(); - let socket_irq = socket.clone(); - let todo_irq = todo.clone(); - event_queue - .add(irq_file.as_raw_fd(), move |_| -> io::Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; - - let hci = hci_irq.lock().unwrap(); - let socket = socket_irq.lock().unwrap(); - let todo = todo_irq.lock().unwrap(); - - if hci.received_irq() { - hci.on_irq(); - - irq_file.write(&mut irq)?; - - let mut i = 0; - while i < todo.len() { - let a = todo[i].a; - hci.handle(&mut todo[i]); - if todo[i].a == (-EWOULDBLOCK) as usize { - todo[i].a = a; - i += 1; - } else { - socket.write(&todo[i])?; - todo.remove(i); - } - } - } - - Ok(None) - }) - .expect("xhcid: failed to catch events on IRQ file"); - } - let socket_fd = socket.lock().unwrap().as_raw_fd(); let socket_packet = socket.clone(); event_queue .add(socket_fd, move |_| -> io::Result> { let mut socket = socket_packet.lock().unwrap(); - let mut hci = hci.lock().unwrap(); + let mut hci = hci; let mut todo = todo.lock().unwrap(); loop { diff --git a/xhcid/src/xhci/capability.rs b/xhcid/src/xhci/capability.rs index 98750bc12c..4ec7b10a15 100644 --- a/xhcid/src/xhci/capability.rs +++ b/xhcid/src/xhci/capability.rs @@ -56,13 +56,13 @@ impl CapabilityRegs { ((self.hcc_params1.read() & HCC_PARAMS1_XECP_MASK) >> HCC_PARAMS1_XECP_SHIFT) as u16 } pub fn max_scratchpad_bufs_lo(&self) -> u8 { - ((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_MASK) >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_SHIFT) + ((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_MASK) >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_SHIFT) as u8 } pub fn spr(&self) -> bool { self.hcs_params2.readf(HCS_PARAMS2_SPR_BIT) } pub fn max_scratchpad_bufs_hi(&self) -> u8 { - ((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_MASK) >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_SHIFT) + ((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_MASK) >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_SHIFT) as u8 } pub fn max_scratchpad_bufs(&self) -> u16 { u16::from(self.max_scratchpad_bufs_lo()) diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index f3eb970737..1093a6e250 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -161,7 +161,6 @@ impl StreamContextArray { } #[repr(packed)] -#[derive(Clone, Debug)] pub struct ScratchpadBufferEntry { pub value: Mmio, } @@ -179,21 +178,20 @@ impl ScratchpadBufferArray { pub fn new(entries: u16) -> Result { let mut entries = unsafe { Dma::zeroed_unsized(entries as usize)? }; - let pages = entries.iter_mut().map(|entry| { - // TODO: When a better memory allocation API arrives (like the `mem:` scheme which I think is - // being worked on), no assumptions about the page size always being 4k will have to be - // made. - let pointer = syscall::physalloc(4096); + let pages = entries.iter_mut().map(|entry: &mut ScratchpadBufferEntry| -> Result { + // TODO: Get the page size using fstatvfs on the `memory:` scheme. + let pointer = syscall::physalloc(4096)?; assert_eq!(pointer & 0xFFFF_FFFF_FFFF_F000, pointer, "physically allocated pointer (physalloc) wasn't 4k page-aligned"); - entry.set_addr(pointer); - }); + entry.set_addr(pointer as u64); + Ok(pointer) + }).collect::, _>>()?; Ok(Self { entries, pages, }) } - pub fn register(&self) -> u64 { + pub fn register(&self) -> usize { self.entries.physical() } } diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 4d808f6f30..977fa56584 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; use std::fs::File; use std::future::Future; +use std::io::prelude::*; use std::pin::Pin; use std::sync::{Arc, Mutex}; use std::sync::atomic::{self, AtomicUsize}; @@ -8,6 +9,7 @@ use std::{mem, task, thread}; use crossbeam_channel::{Sender, Receiver}; use futures::Stream; +use syscall::Io; use super::Xhci; use super::ring::Ring; @@ -31,10 +33,19 @@ pub struct NextEventTrb { // indexed using this struct instead. #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct RingId { - pub slot: u8, + pub port: u8, pub endpoint_num: u8, pub stream_id: u16, } +impl RingId { + pub const fn default_control_pipe(port: u8) -> Self { + Self { + port, + endpoint_num: 0, + stream_id: 0, + } + } +} /// The state specific to a TRB-type. Since some of the event TDs may asynchronously appear, for /// example the Command Completion Event and the Transfer Event TDs, they have to be @@ -52,10 +63,10 @@ pub enum StateKind { impl StateKind { pub fn trb_type(&self) -> TrbType { - match self.kind { - Self::CommandCompletion { .. } => TrbType::CommandCompletion, - Self::Transfer { .. } => TrbType::Transfer, - Self::Other(ty) => ty, + match self { + &Self::CommandCompletion { .. } => TrbType::CommandCompletion, + &Self::Transfer { .. } => TrbType::Transfer, + &Self::Other(ty) => ty, } } } @@ -63,7 +74,6 @@ impl StateKind { pub struct IrqReactor { hci: Arc, - current_count: Arc, irq_file: Option, receiver: Receiver, @@ -75,18 +85,13 @@ pub struct IrqReactor { pub type NewPendingTrb = State; -pub fn start_irq_reactor(hci: Arc, irq_file: Option) -> thread::JoinHandle<()> { - thread::spawn(move || { - IrqReactor::new(hci, irq_file).run() - }) -} - impl IrqReactor { - pub fn new(hci: Arc, irq_file: Option) -> Self { + pub fn new(hci: Arc, receiver: Receiver, irq_file: Option) -> Self { Self { hci, irq_file, - current_count: Arc::new(AtomicUsize::new()), + receiver, + states: Vec::new(), } } // TODO: Configure the amount of time to be awaited when no more work can be done. @@ -97,30 +102,31 @@ impl IrqReactor { loop { self.handle_requests(); - let index = self.hci.primary_event_ring.lock().unwrap().next_index(); + let index = self.hci.primary_event_ring.lock().unwrap().ring.next_index(); let mut trb; 'busy_waiting: loop { - trb = self.hci.primary_event_ring.lock().unwrap().trbs[index]; + trb = self.hci.primary_event_ring.lock().unwrap().ring.trbs[index]; if trb.completion_code() == TrbCompletionCode::Invalid as u8 { self.pause(); continue 'busy_waiting; } } + if self.check_event_ring_full(&trb) { continue } self.acknowledge(trb); self.update_erdp(); } } fn run_with_irq_file(mut self) { + let irq_file = self.irq_file.as_mut().expect("Calling IrqReactor::run_with_irq_file without the IRQ file being None"); + 'event_loop: loop { self.handle_requests(); - let irq_file = self.irq_file.as_mut().unwrap(); - let mut buffer = [0u8; 8]; - let bytes_read = self.irq_file.read(&mut buffer).expect("Failed to read from irq scheme"); + let bytes_read = irq_file.read(&mut buffer).expect("Failed to read from irq scheme"); if bytes_read < mem::size_of::() { panic!("wrong number of bytes read from `irq:`: expected {}, got {}", mem::size_of::(), bytes_read); } @@ -129,30 +135,38 @@ impl IrqReactor { continue; } - let _ = self.irq_file.write(&buffer); + let _ = irq_file.write(&buffer); // TODO: More event rings, probably even with different IRQs. let event_ring = self.hci.primary_event_ring.lock().unwrap(); - let trb = event_ring.next(); - if trb.completion_code() == TrbCompletionCode::Invalid as u8 { - println!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt."); - continue 'event_loop; + let mut count = 0; + + 'trb_loop: loop { + let trb = event_ring.next(); + + if trb.completion_code() == TrbCompletionCode::Invalid as u8 { + if count == 0 { println!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") } + continue 'event_loop; + } else { count += 1 } + + if self.check_event_ring_full(trb) { + continue 'trb_loop; + } + self.acknowledge(*trb); + trb.reserved(false); + + self.update_erdp(); } - - self.acknowledge(*trb); - trb.reserved(false); - - self.update_erdp(); } } fn update_erdp(&self) { - let dequeue_pointer_and_dcs = self.hci.primary_event_ring.lock().unwrap().register(); + let dequeue_pointer_and_dcs = self.hci.primary_event_ring.lock().unwrap().erdp(); let dequeue_pointer = dequeue_pointer_and_dcs & 0xFFFF_FFFF_FFFF_FFFE; assert_eq!(dequeue_pointer & 0xFFFF_FFFF_FFFF_FFF0, dequeue_pointer, "unaligned ERDP received from primary event ring"); - self.xhci.run.lock().unwrap().ints[0].erdp.write(dequeue_pointer); + self.hci.run.lock().unwrap().ints[0].erdp.write(dequeue_pointer); } fn handle_requests(&mut self) { self.states.extend(self.receiver.try_iter()); @@ -163,11 +177,11 @@ impl IrqReactor { loop { match self.states[index].kind { StateKind::CommandCompletion { phys_ptr } if trb.trb_type() == TrbType::CommandCompletion as u8 => if trb.completion_trb_pointer() == Some(phys_ptr) { - let state = self.states.remove(index).unwrap(); + let state = self.states.remove(index); // Before waking, it's crucial that the command TRB that generated this event // be fetched before removing this event TRB from the queue. - let command_trb = match self.hci.command_ring.lock().unwrap().ring.phys_addr_to_entry_mut(phys_ptr) { + let command_trb = match self.hci.cmd.lock().unwrap().phys_addr_to_entry_mut(phys_ptr) { Some(command_trb) => { let t = command_trb.clone(); command_trb.reserved(false); @@ -181,7 +195,7 @@ impl IrqReactor { // TODO: Validate the command TRB. *state.message.lock().unwrap() = Some(NextEventTrb { - src_trb: command_trb.clone(), + src_trb: Some(command_trb.clone()), event_trb: trb, }); @@ -194,13 +208,13 @@ impl IrqReactor { continue; } - StateKind::Transfer { phys_ptr, ring_id } if trb.trb_type() == TrbType::Transfer as u8 => if let Some(src_trb) = self.xhc.lock().unwrap().get_transfer_trb(trb.transfer_event_trb_pointer(), ring_id) { + StateKind::Transfer { phys_ptr, ring_id } if trb.trb_type() == TrbType::Transfer as u8 => if let Some(src_trb) = trb.transfer_event_trb_pointer().map(|ptr| self.hci.get_transfer_trb(ptr, ring_id)).flatten() { if trb.transfer_event_trb_pointer() == Some(phys_ptr) { // Give the source transfer TRB together with the event TRB, to the future. - let state = self.states.remove(index).unwrap(); + let state = self.states.remove(index); *state.message.lock().unwrap() = Some(NextEventTrb { - src_trb, + src_trb: Some(src_trb), event_trb: trb, }); state.waker.wake(); @@ -225,7 +239,7 @@ impl IrqReactor { } else { continue } StateKind::Other(trb_type) if trb_type as u8 == trb.trb_type() => { - let state = self.states.remove(index).unwrap(); + let state = self.states.remove(index); state.waker.wake(); } @@ -239,7 +253,7 @@ impl IrqReactor { } } } - pub fn acknowledge_failed_transfer_trbs(&mut self, trb: Trb) { + fn acknowledge_failed_transfer_trbs(&mut self, trb: Trb) { let mut index = 0; loop { @@ -250,7 +264,7 @@ impl IrqReactor { } continue; } - let state = self.states.remove(index).unwrap(); + let state = self.states.remove(index); *state.message.lock().unwrap() = Some(NextEventTrb { event_trb: trb, src_trb: None, @@ -258,6 +272,23 @@ impl IrqReactor { state.waker.wake(); } } + /// Checks if an event TRB is a Host Controller Event, with the completion code Event Ring + /// Full. If so, it grows the event ring. The return value is whether the event ring was full, + /// and then grown. + fn check_event_ring_full(&mut self, event_trb: &Trb) -> bool { + let had_event_ring_full_error = event_trb.trb_type() == TrbType::HostController as u8 && event_trb.completion_code() == TrbCompletionCode::EventRingFull as u8; + + if had_event_ring_full_error { + self.grow_event_ring(); + } + had_event_ring_full_error + } + /// Grows the event ring + fn grow_event_ring(&mut self) { + // TODO + println!("TODO: grow event ring"); + } + pub fn run(mut self) { if self.irq_file.is_some() { self.run_with_irq_file(); @@ -291,7 +322,7 @@ impl Future for EventTrbFuture { sender.send(State { message: Arc::clone(&state.message), is_isoch_or_vf: state.is_isoch_or_vf, - state_kind: state.state_kind, + kind: state.state_kind, waker: context.waker().clone(), }).expect("IRQ reactor thread unexpectedly stopped"); @@ -304,12 +335,12 @@ impl Future for EventTrbFuture { impl Xhci { pub fn get_transfer_trb(&self, paddr: u64, id: RingId) -> Option { - self.with_ring(id, |ring| ring.phys_addr_to_entry(paddr)) + self.with_ring(id, |ring| ring.phys_addr_to_entry(paddr)).flatten() } - pub fn with_ring T>(&self, id: RingId, function: F) -> T { + pub fn with_ring T>(&self, id: RingId, function: F) -> Option { use super::RingOrStreams; - let slot_state = self.slot_states.get(&id.slot)?; + let slot_state = self.port_states.get(&(id.port as usize))?; let endpoint_state = slot_state.endpoint_states.get(&id.endpoint_num)?; let ring_ref = match endpoint_state.transfer { @@ -317,12 +348,12 @@ impl Xhci { RingOrStreams::Streams(ref ctx_arr) => ctx_arr.rings.get(&id.stream_id)?, }; - function(ring_ref) + Some(function(ring_ref)) } - pub fn with_ring_mut T>(&self, id: RingId, function: F) -> T { + pub fn with_ring_mut T>(&self, id: RingId, function: F) -> Option { use super::RingOrStreams; - let slot_state = self.slot_states.get(&id.slot)?; + let slot_state = self.port_states.get(&(id.port as usize))?; let endpoint_state = slot_state.endpoint_states.get_mut(&id.endpoint_num)?; let ring_ref = match endpoint_state.transfer { @@ -330,7 +361,7 @@ impl Xhci { RingOrStreams::Streams(ref mut ctx_arr) => ctx_arr.rings.get_mut(&id.stream_id)?, }; - function(ring_ref) + Some(function(ring_ref)) } pub fn next_transfer_event_trb(&self, ring_id: RingId, trb: &Trb) -> impl Future + Send + Sync + 'static { if ! trb.is_transfer_trb() { @@ -344,7 +375,7 @@ impl Xhci { is_isoch_or_vf, state_kind: StateKind::Transfer { ring_id, - phys_ptr: self.with_ring(ring_id, |ring| ring.trb_phys_ptr(trb)/*.expect("Invalid TRB: transfer TRB wasn't in the ring specified. Only direct references to the TRBs of a ring can be used (ring address range: {:p}-{:p}).", ring.start_addr(), ring.end_addr())*/), + phys_ptr: self.with_ring(ring_id, |ring| ring.trb_phys_ptr(trb)).unwrap(), }, message: Arc::new(Mutex::new(None)), }, @@ -363,7 +394,7 @@ impl Xhci { // This is only possible for transfers if they are isochronous, or for Force Event TRBs (virtualization). is_isoch_or_vf: false, state_kind: StateKind::CommandCompletion { - phys_ptr: command_ring.trb_phys_ptr(trb),//.expect("Invalid TRB: expected a command TRB within the address range of the command TRB ({:p} {:p}), found TRB {:?} at {:p}", ring.start_addr(), ring.end_addr(), trb, trb) + phys_ptr: command_ring.trb_phys_ptr(trb), }, message: Arc::new(Mutex::new(None)), }, @@ -379,7 +410,7 @@ impl Xhci { TrbType::DeviceNotification as u8, TrbType::MfindexWrap as u8, ]; - if ! valid_trb_types.contains(&trb_type) { + if ! valid_trb_types.contains(&(trb_type as u8)) { panic!("Invalid TRB type given to next_misc_event_trb(): {:?}. Only event TRB types that are neither transfer events or command completion events can be used.", trb_type) } EventTrbFuture::Pending { @@ -391,4 +422,5 @@ impl Xhci { sender: self.irq_reactor_sender.clone(), } } + } diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 3970677053..e2da2a887a 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -4,13 +4,16 @@ use std::fs::File; use std::future::Future; use std::pin::Pin; use std::ptr::NonNull; -use std::sync::{atomic::AtomicBool, Arc, Mutex, Weak}; +use std::sync::{Arc, Mutex, MutexGuard, Weak}; +use std::sync::atomic::{AtomicBool, AtomicUsize}; + use std::{mem, process, slice, sync::atomic, task, thread}; use chashmap::CHashMap; -use crossbeam_channel::Sender; +use crossbeam_channel::{Receiver, Sender}; use serde::Deserialize; use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT}; +use syscall::flag::O_RDONLY; use syscall::io::{Dma, Io}; use crate::usb; @@ -34,14 +37,14 @@ mod trb; use self::capability::CapabilityRegs; use self::context::{DeviceContextList, InputContext, ScratchpadBufferArray, StreamContextArray}; use self::doorbell::Doorbell; -use self::irq_reactor::NewPendingTrb; +use self::irq_reactor::{IrqReactor, NewPendingTrb, RingId}; use self::event::EventRing; use self::extended::{CapabilityId, ExtendedCapabilitiesIter, ProtocolSpeed, SupportedProtoCap}; use self::operational::OperationalRegs; use self::port::Port; use self::ring::Ring; use self::runtime::{Interrupter, RuntimeRegs}; -use self::trb::{TransferKind, TrbCompletionCode, TrbType}; +use self::trb::{TransferKind, Trb, TrbCompletionCode, TrbType}; use self::scheme::EndpIfState; @@ -88,70 +91,61 @@ impl MsixInfo { } } -struct Device<'a> { - ring: &'a mut Ring, - cmd: &'a mut Ring, - db: &'a mut Doorbell, - int: &'a mut Interrupter, -} - -impl<'a> Device<'a> { - fn get_desc(&mut self, kind: usb::DescriptorKind, index: u8, desc: &mut Dma) { +impl Xhci { + /// Gets descriptors, before the port state is initiated. + async fn get_desc_raw(&self, port: usize, slot: u8, kind: usb::DescriptorKind, index: u8, ring: &mut Ring, desc: &mut Dma) -> Result<()> { let len = mem::size_of::(); - { - let (cmd, cycle) = self.ring.next(); + let future = { + let (cmd, cycle) = ring.next(); cmd.setup( usb::Setup::get_descriptor(kind, index, 0, len as u16), TransferKind::In, cycle, ); - } - { - let (cmd, cycle) = self.ring.next(); + let (cmd, cycle) = ring.next(); cmd.data(desc.physical(), len as u16, true, cycle); - } - { - let (cmd, cycle) = self.ring.next(); - cmd.status(false, cycle); - } + let (cmd, cycle) = ring.next(); + cmd.status(0, true, true, false, false, cycle); - self.db.write(1); + self.next_transfer_event_trb(RingId::default_control_pipe(port as u8), &cmd) + }; - { - let event = self.cmd.next_event(); - // TODO: Replace polling here as well. - while event.data.read() == 0 { - println!(" - Waiting for event"); - } - } + self.dbs.lock().unwrap()[usize::from(slot)].write(Self::def_control_endp_doorbell()); - self.int.erdp.write(self.cmd.erdp() | (1 << 3)); + let trbs = future.await; + let event_trb = trbs.event_trb; + let status_trb = trbs.src_trb.unwrap(); + + self::scheme::handle_transfer_event_trb("GET_DESC", &event_trb, &status_trb)?; + + self.event_handler_finished(); + Ok(()) } - fn get_device(&mut self) -> Result { + async fn fetch_dev_desc(&mut self, port: usize, slot: u8, ring: &mut Ring) -> Result { let mut desc = Dma::::zeroed()?; - self.get_desc(usb::DescriptorKind::Device, 0, &mut desc); + self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, ring, &mut desc).await?; Ok(*desc) } - fn get_config(&mut self, config: u8) -> Result<(usb::ConfigDescriptor, [u8; 4087])> { + async fn fetch_config_desc(&mut self, port: usize, slot: u8, ring: &mut Ring, config: u8) -> Result<(usb::ConfigDescriptor, [u8; 4087])> { let mut desc = Dma::<(usb::ConfigDescriptor, [u8; 4087])>::zeroed()?; - self.get_desc(usb::DescriptorKind::Configuration, config, &mut desc); + self.get_desc_raw(port, slot, usb::DescriptorKind::Configuration, config, ring, &mut desc).await?; Ok(*desc) } - fn get_bos(&mut self) -> Result<(usb::BosDescriptor, [u8; 4087])> { + async fn fetch_bos_desc(&mut self, port: usize, slot: u8, ring: &mut Ring) -> Result<(usb::BosDescriptor, [u8; 4087])> { let mut desc = Dma::<(usb::BosDescriptor, [u8; 4087])>::zeroed()?; - self.get_desc(usb::DescriptorKind::BinaryObjectStorage, 0, &mut desc); + self.get_desc_raw(port, slot, usb::DescriptorKind::BinaryObjectStorage, 0, ring, &mut desc).await?; Ok(*desc) } - fn get_string(&mut self, index: u8) -> Result { + async fn fetch_string_desc(&mut self, port: usize, slot: u8, ring: &mut Ring, index: u8) -> Result { let mut sdesc = Dma::<(u8, u8, [u16; 127])>::zeroed()?; - self.get_desc(usb::DescriptorKind::String, index, &mut sdesc); + self.get_desc_raw(port, slot, usb::DescriptorKind::String, index, ring, &mut sdesc).await?; let len = sdesc.0 as usize; if len > 2 { @@ -165,6 +159,7 @@ impl<'a> Device<'a> { pub struct Xhci { // immutable cap: &'static CapabilityRegs, + page_size: usize, // XXX: It would be really useful to be able to mutably access individual elements of a slice, // without having to wrap every element in a lock (which wouldn't work since they're packed). @@ -183,7 +178,7 @@ pub struct Xhci { base: *const u8, handles: CHashMap, - next_handle: usize, + next_handle: AtomicUsize, port_states: CHashMap, drivers: CHashMap, @@ -191,16 +186,25 @@ pub struct Xhci { interrupt_method: InterruptMethod, pcid_handle: Mutex, - irq_reactor: Option>, + + irq_reactor: Mutex>>, + irq_reactor_sender: Sender, + + // not used, but still stored so that the thread, when created, can get the channel without the + // channel being in a mutex. + irq_reactor_receiver: Receiver, } +unsafe impl Send for Xhci {} +unsafe impl Sync for Xhci {} + struct PortState { slot: u8, cfg_idx: Option, if_idx: Option, input_context: Mutex>, - dev_desc: DevDesc, + dev_desc: Option, endpoint_states: BTreeMap, } @@ -227,6 +231,13 @@ impl Xhci { let cap = unsafe { &mut *(address as *mut CapabilityRegs) }; println!(" - CAP {:X}", address); + let page_size = { + let memory_fd = syscall::open("memory:", O_RDONLY)?; + let mut stat = syscall::data::StatVfs::default(); + syscall::fstatvfs(memory_fd, &mut stat)?; + stat.f_bsize as usize + }; + let op_base = address + cap.len.read() as usize; let op = unsafe { &mut *(op_base as *mut OperationalRegs) }; println!(" - OP {:X}", op_base); @@ -276,25 +287,42 @@ impl Xhci { let run = unsafe { &mut *(run_base as *mut RuntimeRegs) }; println!(" - RUNTIME {:X}", run_base); - let mut xhci = Xhci { - base: address as *const u8, - cap, - op, - ports, - dbs, - run, - dev_ctx: DeviceContextList::new(max_slots)?, - cmd: Ring::new(), - primary_event_ring: EventRing::new(), - handles: BTreeMap::new(), - next_handle: 0, - port_states: BTreeMap::new(), + // Create the command ring with 4096 / 16 (TRB size) entries, so that it uses all of the + // DMA allocation (which is at least a 4k page). + let entries_per_page = page_size / mem::size_of::(); + let cmd = Ring::new(entries_per_page, true)?; - drivers: BTreeMap::new(), + let (irq_reactor_sender, irq_reactor_receiver) = crossbeam_channel::unbounded(); + + let mut xhci = Self { + base: address as *const u8, + + cap, + page_size, + + op: Mutex::new(op), + ports: Mutex::new(ports), + dbs: Mutex::new(dbs), + run: Mutex::new(run), + + dev_ctx: DeviceContextList::new(max_slots)?, + scratchpad_buf_arr: None, // initialized in init() + + cmd: Mutex::new(cmd), + primary_event_ring: Mutex::new(EventRing::new()?), + handles: CHashMap::new(), + next_handle: AtomicUsize::new(0), + port_states: CHashMap::new(), + + drivers: CHashMap::new(), scheme_name, interrupt_method, pcid_handle: Mutex::new(pcid_handle), + + irq_reactor: Mutex::new(None), + irq_reactor_sender, + irq_reactor_receiver, }; xhci.init(max_slots); @@ -302,37 +330,37 @@ impl Xhci { Ok(xhci) } - pub fn init(&mut self, max_slots: u8) { + pub fn init(&mut self, max_slots: u8) -> Result<()> { // Set enabled slots println!(" - Set enabled slots to {}", max_slots); - self.op.get_mut().config.write(max_slots as u32); - println!(" - Enabled Slots: {}", self.op.get_mut().config.read() & 0xFF); + self.op.get_mut().unwrap().config.write(max_slots as u32); + println!(" - Enabled Slots: {}", self.op.get_mut().unwrap().config.read() & 0xFF); // Set device context address array pointer let dcbaap = self.dev_ctx.dcbaap(); println!(" - Write DCBAAP: {:X}", dcbaap); - self.op.get_mut().dcbaap.write(dcbaap as u64); + self.op.get_mut().unwrap().dcbaap.write(dcbaap as u64); // Set command ring control register - let crcr = self.cmd.get_mut().register(); + let crcr = self.cmd.get_mut().unwrap().register(); assert_eq!(crcr & 0xFFFF_FFFF_FFFF_FFC1, crcr, "unaligned CRCR"); println!(" - Write CRCR: {:X}", crcr); - self.op.get_mut().crcr.write(crcr as u64); + self.op.get_mut().unwrap().crcr.write(crcr as u64); // Set event ring segment table registers - println!(" - Interrupter 0: {:X}", self.run.ints.as_ptr() as usize); + println!(" - Interrupter 0: {:X}", self.run.get_mut().unwrap().ints.as_ptr() as usize); { - let int = &mut self.run.get_mut().ints[0]; + let int = &mut self.run.get_mut().unwrap().ints[0]; let erstz = 1; println!(" - Write ERSTZ: {}", erstz); int.erstsz.write(erstz); - let erdp = self.primary_event_ring.get_mut().erdp(); + let erdp = self.primary_event_ring.get_mut().unwrap().erdp() | (!1); println!(" - Write ERDP: {:X}", erdp); int.erdp.write(erdp as u64 | (1 << 3)); - let erstba = self.primary_event_ring.get_mut().erstba(); + let erstba = self.primary_event_ring.get_mut().unwrap().erstba(); println!(" - Write ERSTBA: {:X}", erstba); int.erstba.write(erstba as u64); @@ -343,49 +371,66 @@ impl Xhci { int.iman.writef(1 << 1, true); } - self.op.get_mut().usb_cmd.writef(1 << 2, true); + self.op.get_mut().unwrap().usb_cmd.writef(1 << 2, true); // Setup the scratchpad buffers that are required for the xHC to function. - self.setup_scratchpads(); + self.setup_scratchpads()?; // Set run/stop to 1 println!(" - Start"); - self.op.get_mut().usb_cmd.writef(1, true); + self.op.get_mut().unwrap().usb_cmd.writef(1, true); // Wait until controller is running println!(" - Wait for running"); - while self.op.get_mut().usb_sts.readf(1) { + while self.op.get_mut().unwrap().usb_sts.readf(1) { println!(" - Waiting for XHCI running"); } - println!("IP={}", self.run.get_mut().ints[0].iman.readf(1)); + println!("IP={}", self.run.get_mut().unwrap().ints[0].iman.readf(1)); // Ring command doorbell println!(" - Ring doorbell"); - self.dbs.get_mut()[0].write(0); + self.dbs.get_mut().unwrap()[0].write(0); println!(" - XHCI initialized"); + + if self.cap.cic() { + self.op.lock().unwrap().set_cie(true); + } + + Ok(()) } pub fn setup_scratchpads(&mut self) -> Result<()> { let buf_count = self.cap.max_scratchpad_bufs(); if buf_count == 0 { - return; + return Ok(()); } - self.scratchpad_buf_arr = Some(ScratchpadBufferArray::new(buf_count)?); - self.dev_ctx.dcbaa[0] = self.scratchpad_buf_arr.register(); + let scratchpad_buf_arr = ScratchpadBufferArray::new(buf_count)?; + self.dev_ctx.dcbaa[0] = scratchpad_buf_arr.register() as u64; + self.scratchpad_buf_arr = Some(scratchpad_buf_arr); + + Ok(()) } - pub fn enable_port_slot(&mut self, slot_ty: u8) -> Result { + pub async fn enable_port_slot(&mut self, slot_ty: u8) -> Result { assert_eq!(slot_ty & 0x1F, slot_ty); - let cloned_event_trb = - self.execute_command("ENABLE_SLOT", |cmd, cycle| cmd.enable_slot(slot_ty, cycle))?; - Ok(cloned_event_trb.event_slot()) + let (event_trb, command_trb) = + self.execute_command(|cmd, cycle| cmd.enable_slot(slot_ty, cycle)).await; + + self::scheme::handle_event_trb("ENABLE_SLOT", &event_trb, &command_trb); + self.event_handler_finished(); + + Ok(event_trb.event_slot()) } - pub fn disable_port_slot(&mut self, slot: u8) -> Result<()> { - self.execute_command("DISABLE_SLOT", |cmd, cycle| cmd.disable_slot(slot, cycle))?; + pub async fn disable_port_slot(&mut self, slot: u8) -> Result<()> { + let (event_trb, command_trb) = self.execute_command(|cmd, cycle| cmd.disable_slot(slot, cycle)).await; + + self::scheme::handle_event_trb("DISABLE_SLOT", &event_trb, &command_trb); + self.event_handler_finished(); + Ok(()) } @@ -415,29 +460,19 @@ impl Xhci { .supported_protocol(i as u8) .expect("Failed to find supported protocol information for port") .proto_slot_ty(); - let slot = self.enable_port_slot(slot_ty)?; + let slot = self.enable_port_slot(slot_ty).await?; println!(" - Slot {}", slot); let mut input = Dma::::zeroed()?; let mut ring = self.address_device(&mut input, i, slot_ty, slot, speed).await?; - let dev_desc = Self::get_dev_desc_raw( - &mut *self.ports.lock().unwrap(), - &mut *self.run.lock().unwrap(), - &mut *self.cmd.lock().unwrap(), - &mut *self.dbs.lock().unwrap(), - i, - slot, - &mut ring, - )?; - - self.update_default_control_pipe(&mut input, slot, &dev_desc)?; + // TODO: Should the descriptors be cached in PortState, or refetched? let mut port_state = PortState { slot, input_context: Mutex::new(input), - dev_desc, + dev_desc: None, cfg_idx: None, if_idx: None, endpoint_states: std::iter::once(( @@ -450,9 +485,9 @@ impl Xhci { .collect::>(), }; - if self.cap.cic() { - self.op.lock().unwrap().set_cie(true); - } + let dev_desc = self.get_desc(i, slot, &mut ring).await?; + port_state.dev_desc = Some(dev_desc); + self.update_default_control_pipe(&mut input, slot, &dev_desc).await?; /*match self.spawn_drivers(i, &mut port_state) { Ok(()) => (), @@ -466,7 +501,7 @@ impl Xhci { Ok(()) } - pub fn update_default_control_pipe( + pub async fn update_default_control_pipe( &mut self, input_context: &mut Dma, slot_id: u8, @@ -486,9 +521,13 @@ impl Xhci { b |= (new_max_packet_size) << 16; endp_ctx.b.write(b); - self.execute_command("EVALUATE_CONTEXT", |trb, cycle| { + let (event_trb, command_trb) = self.execute_command(|trb, cycle| { trb.evaluate_context(slot_id, input_context.physical(), false, cycle) - })?; + }).await; + + self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb); + self.event_handler_finished(); + Ok(()) } @@ -598,15 +637,16 @@ impl Xhci { pub fn uses_msix(&self) -> bool { if let InterruptMethod::MsiX(_) = self.interrupt_method { true } else { false } } - pub fn msix_info(&self) -> Option<&MsixInfo> { + // TODO: Perhaps use an rwlock? + pub fn msix_info(&self) -> Option> { match self.interrupt_method { - InterruptMethod::MsiX(ref info) => Some(info), + InterruptMethod::MsiX(ref info) => Some(info.lock().unwrap()), _ => None, } } - pub fn msix_info_mut(&mut self) -> Option<&mut MsixInfo> { + pub fn msix_info_mut(&mut self) -> Option> { match self.interrupt_method { - InterruptMethod::MsiX(ref mut info) => Some(info), + InterruptMethod::MsiX(ref info) => Some(info.lock().unwrap()), _ => None, } } @@ -614,18 +654,20 @@ impl Xhci { /// Checks whether an IRQ has been received from *this* device, in case of an interrupt. Always /// true when using MSI/MSI-X. pub fn received_irq(&mut self) -> bool { + let runtime_regs = self.run.lock().unwrap(); + if self.uses_msi() || self.uses_msix() { // Since using MSI and MSI-X implies having no IRQ sharing whatsoever, the IP bit // doesn't have to be touched. - println!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", self.run.ints[0].iman.readf(1), self.run.ints[0].erdp.readf(3)); + println!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), runtime_regs.ints[0].erdp.readf(3)); println!("MSI-X PB={}", self.msix_info_mut().unwrap().pba(0)); let entry = self.msix_info_mut().unwrap().table_entry_pointer(0); println!("MSI-X entry (addr_lo, addr_hi, msg_data, vec_ctl: {:#0x} {:#0x} {:#0x} {:#0x}", entry.addr_lo.read(), entry.addr_hi.read(), entry.msg_data.read(), entry.vec_ctl.read()); true - } else if self.run.ints[0].iman.readf(1) { + } else if runtime_regs.ints[0].iman.readf(1) { // If MSI and/or MSI-X are not used, the interrupt might have to be shared, and thus there is // a special register to specify whether the IRQ actually came from the xHC. - self.run.ints[0].iman.writef(1, true); + runtime_regs.ints[0].iman.writef(1, true); // The interrupt came from the xHC. true @@ -634,8 +676,6 @@ impl Xhci { false } - } - pub fn on_irq(&mut self) { } fn spawn_drivers(&mut self, port: usize, ps: &mut PortState) -> Result<()> { // TODO: There should probably be a way to select alternate interfaces, and not just the @@ -645,12 +685,14 @@ impl Xhci { let ifdesc = &ps .dev_desc + .as_ref().unwrap() .config_descs .first() .ok_or(Error::new(EBADF))? .interface_descs .first() .ok_or(Error::new(EBADF))?; + let drivers_usercfg: &DriversConfig = &DRIVERS_CONFIG; if let Some(driver) = drivers_usercfg.drivers.iter().find(|driver| { @@ -787,6 +829,15 @@ impl Xhci { .find(|speed| speed.psiv() == psiv) } } +pub fn start_irq_reactor(hci: &Arc, irq_file: Option) { + let receiver = hci.irq_reactor_receiver.clone(); + let hci_clone = Arc::clone(&hci); + + *hci.irq_reactor.lock().unwrap() = Some(thread::spawn(move || { + IrqReactor::new(hci_clone, receiver, irq_file).run() + })); +} + #[derive(Deserialize)] struct DriverConfig { name: String, diff --git a/xhcid/src/xhci/ring.rs b/xhcid/src/xhci/ring.rs index 26d0433277..2e067efce3 100644 --- a/xhcid/src/xhci/ring.rs +++ b/xhcid/src/xhci/ring.rs @@ -64,9 +64,10 @@ impl Ring { /// /// # Panics /// Panics if paddr is not a multiple of 16 bytes, i.e. the size of a TRB. + // TODO: Use usize instead of u64. pub fn phys_addr_to_index(&self, paddr: u64) -> Option { let base = self.trbs.physical(); - let offset = paddr.checked_sub(base)?; + let offset = paddr.checked_sub(base as u64)? as usize; assert_eq!(offset % mem::size_of::(), 0, "unaligned TRB physical address"); @@ -79,29 +80,29 @@ impl Ring { Some(index) } pub fn phys_addr_to_entry_ref(&self, paddr: u64) -> Option<&Trb> { - &self.trbs[self.phys_addr_to_index(paddr)] + Some(&self.trbs[self.phys_addr_to_index(paddr)?]) } pub fn phys_addr_to_entry_mut(&self, paddr: u64) -> Option<&mut Trb> { - &mut self.trbs[self.phys_addr_to_index(paddr)] + Some(&mut self.trbs[self.phys_addr_to_index(paddr)?]) } pub fn phys_addr_to_entry(&self, paddr: u64) -> Option { - self.trbs[self.phys_addr_to_index(paddr)].clone() + Some(self.trbs[self.phys_addr_to_index(paddr)?].clone()) } pub(crate) fn start_virt_addr(&self) -> *const Trb { self.trbs.as_ptr() } pub(crate) fn end_virt_addr(&self) -> *const Trb { - unsafe { self.start_virt_addr().offset(self.trbs.len()) } + unsafe { self.start_virt_addr().offset(self.trbs.len() as isize) } } pub fn trb_phys_ptr(&self, trb: &Trb) -> u64 { let trb_virt_pointer = trb as *const Trb; let trbs_base_virt_pointer = self.trbs.as_ptr(); - if trb_virt_pointer < trbs_base_virt_pointer || trb_virt_pointer > trbs_base_virt_pointer + self.trbs.len() * mem::size_of::() { + if (trb_virt_pointer as usize) < (trbs_base_virt_pointer as usize) || (trb_virt_pointer as usize) > (trbs_base_virt_pointer as usize) + self.trbs.len() * mem::size_of::() { panic!("Gave a TRB outside of the ring, when retrieving its physical address in that ring. TRB: {:?} (at address {:p})", trb, trb); } - let trbs_base_phys_ptr = self.trbs.physical(); - let trb_phys_ptr = trb_virt_pointer - trbs_base_phys_ptr; + let trbs_base_phys_ptr = self.trbs.physical() as u64; + let trb_phys_ptr = trb_virt_pointer as u64 - trbs_base_phys_ptr; trb_phys_ptr } /* diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index c96d3d9c08..3ecc690cae 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1,7 +1,9 @@ use std::convert::TryFrom; use std::io::prelude::*; +use std::sync::atomic; use std::{cmp, io, mem, path, str}; +use futures::executor::block_on; use serde::{Deserialize, Serialize}; use smallvec::{smallvec, SmallVec}; @@ -15,7 +17,7 @@ use syscall::{ }; use super::{port, usb}; -use super::{Device, EndpointState, Xhci}; +use super::{EndpointState, Xhci}; use super::context::{ InputContext, SlotState, StreamContext, StreamContextArray, StreamContextType, @@ -23,6 +25,7 @@ use super::context::{ }; use super::doorbell::Doorbell; use super::extended::ProtocolSpeed; +use super::irq_reactor::RingId; use super::operational::OperationalRegs; use super::ring::Ring; use super::runtime::RuntimeRegs; @@ -139,31 +142,6 @@ impl From for SuperSpeedPlusIsochCmp { } } -impl IfDesc { - fn new( - dev: &mut Device, - desc: usb::InterfaceDescriptor, - endps: impl IntoIterator, - hid_descs: 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(), - hid_descs: hid_descs.into_iter().collect(), - }) - } -} - /// Any descriptor that can be stored in the config desc "data" area. #[derive(Debug)] pub enum AnyDescriptor { @@ -210,8 +188,35 @@ impl AnyDescriptor { } impl Xhci { + async fn new_if_desc( + &self, + port_id: usize, + slot: u8, + ring: &mut Ring, + desc: usb::InterfaceDescriptor, + endps: impl IntoIterator, + hid_descs: impl IntoIterator, + ) -> Result { + Ok(IfDesc { + alternate_setting: desc.alternate_setting, + class: desc.class, + interface_str: if desc.interface_str > 0 { + Some(self.fetch_string_desc(port_id, slot, ring, desc.interface_str).await?) + } else { + None + }, + kind: desc.kind, + number: desc.number, + protocol: desc.protocol, + sub_class: desc.sub_class, + endpoints: endps.into_iter().collect(), + hid_descs: hid_descs.into_iter().collect(), + }) + } pub fn execute_command_noreply(&self, f: F) { - let (cmd, cycle) = self.cmd.lock().unwrap(); + let command_ring = self.cmd.lock().unwrap(); + + let (cmd, cycle) = command_ring.next(); f(cmd, cycle); self.dbs.lock().unwrap()[0].write(0); @@ -243,7 +248,7 @@ impl Xhci { (event_trb, command_trb) } - pub fn execute_control_transfer( + pub async fn execute_control_transfer( &mut self, port_num: usize, setup: usb::Setup, @@ -254,62 +259,60 @@ impl Xhci { where D: FnMut(&mut Trb, bool) -> ControlFlow, { - let slot = self.port_state(port_num)?.slot; - let ring = self - .endpoint_state_mut(port_num, 0)? - .ring() - .ok_or(Error::new(EIO))?; + let port_state = self.port_state(port_num)?; + let slot = port_state.slot; + + let future = { + let endpoint_state = port_state + .endpoint_states + .get_mut(&0).ok_or(Error::new(EIO))?; + + let ring = endpoint_state + .ring() + .ok_or(Error::new(EIO))?; - { let (cmd, cycle) = ring.next(); cmd.setup(setup, tk, cycle); - } - if tk != TransferKind::NoData { - loop { - let (trb, cycle) = ring.next(); - match d(trb, cycle) { - ControlFlow::Break => break, - ControlFlow::Continue => continue, + + if tk != TransferKind::NoData { + loop { + let (trb, cycle) = ring.next(); + match d(trb, cycle) { + ControlFlow::Break => break, + ControlFlow::Continue => continue, + } } } - } - { + let (cmd, cycle) = ring.next(); - cmd.status(tk == TransferKind::In, cycle); - } - self.dbs[usize::from(slot)].write(Self::def_control_endp_doorbell()); - let cloned_trb = { - let event = self.cmd.next_event(); - while event.data.read() == 0 { - println!(" - {} Waiting for event", name); - } + let interrupter = 0; + let ioc = true; + let ch = false; + let ent = false; - if event.completion_code() != TrbCompletionCode::Success as u8 - || event.trb_type() != TrbType::Transfer as u8 - { - println!( - "{} CONTROL TRANSFER ERROR, EVENT TRB {:#0x} {:#0x} {:#0}ยป", - name, - event.data.read(), - event.status.read(), - event.control.read() - ); - } - event.reserved(false); - event.clone() + cmd.status(interrupter, tk == TransferKind::In, ioc, ch, ent, cycle); + self.next_transfer_event_trb(RingId::default_control_pipe(port_num as u8), cmd) }; - self.run.ints[0].erdp.write(self.cmd.erdp() | (1 << 3)); + self.dbs.lock().unwrap()[usize::from(slot)].write(Self::def_control_endp_doorbell()); - Ok(cloned_trb) + let trbs = future.await; + let event_trb = trbs.event_trb; + let status_trb = trbs.src_trb.unwrap(); + + handle_transfer_event_trb("CONTROL_TRANSFER", &event_trb, &status_trb)?; + + self.event_handler_finished(); + + Ok(event_trb) } /// NOTE: There has to be AT LEAST one successful invocation of `d`, that actually updates the /// TRB (it could be a NO-OP in the worst case). /// The function is also required to set the Interrupt on Completion flag, or this function /// will never complete. pub async fn execute_transfer( - &mut self, + &self, port_num: usize, endp_num: u8, stream_id: u16, @@ -326,7 +329,7 @@ impl Xhci { _ => return Err(Error::new(EIO)), }; - let endp_desc = port_state.dev_desc.config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; + let endp_desc = port_state.dev_desc.as_ref().unwrap().config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; let slot = port_state.slot; let endp_state = port_state @@ -353,7 +356,7 @@ impl Xhci { match d(trb, cycle) { ControlFlow::Break => { - break self.next_transfer_event_trb(super::irq_reactor::RingId { slot, endpoint_num: endp_num, stream_id }, &trb); + break self.next_transfer_event_trb(super::irq_reactor::RingId { port: port_num as u8, endpoint_num: endp_num, stream_id }, &trb); } ControlFlow::Continue => continue, } @@ -386,20 +389,20 @@ impl Xhci { Ok(event_trb) } - fn device_req_no_data(&mut self, port: usize, req: usb::Setup) -> Result<()> { + async fn device_req_no_data(&mut self, port: usize, req: usb::Setup) -> Result<()> { self.execute_control_transfer( port, req, TransferKind::NoData, "DEVICE_REQ_NO_DATA", |_, _| ControlFlow::Break, - )?; + ).await?; Ok(()) } - fn set_configuration(&mut self, port: usize, config: u8) -> Result<()> { - self.device_req_no_data(port, usb::Setup::set_configuration(config)) + async fn set_configuration(&mut self, port: usize, config: u8) -> Result<()> { + self.device_req_no_data(port, usb::Setup::set_configuration(config)).await } - fn set_interface( + async fn set_interface( &mut self, port: usize, interface_num: u8, @@ -408,7 +411,7 @@ impl Xhci { self.device_req_no_data( port, usb::Setup::set_interface(interface_num, alternate_setting), - ) + ).await } async fn reset_endpoint(&mut self, port_num: usize, endp_num: u8, tsp: bool) -> Result<()> { @@ -419,7 +422,7 @@ impl Xhci { _ => return Err(Error::new(EIO)), }; - let endp_desc = port_state.dev_desc.config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; + let endp_desc = port_state.dev_desc.as_ref().unwrap().config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); let slot = self @@ -534,7 +537,7 @@ impl Xhci { let (endp_desc_count, new_context_entries, configuration_value) = { let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; - let config_desc = port_state.dev_desc.config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?; + let config_desc = port_state.dev_desc.as_ref().unwrap().config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?; let endpoints = config_desc.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints; @@ -588,7 +591,7 @@ impl Xhci { let endp_num = endp_idx + 1; let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; - let dev_desc = &port_state.dev_desc; + let dev_desc = port_state.dev_desc.as_ref().unwrap(); let endpoints = &dev_desc.config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints; let endp_desc = endpoints.get(endp_idx as usize).ok_or(Error::new(EIO))?; @@ -731,12 +734,12 @@ impl Xhci { handle_event_trb("CONFIGURE_ENDPOINT", &event_trb, &command_trb)?; // Tell the device about this configuration. - self.set_configuration(port, configuration_value)?; + self.set_configuration(port, configuration_value).await?; if let (Some(interface_num), Some(alternate_setting)) = (req.interface_desc, req.alternate_setting) { - self.set_interface(port, interface_num, alternate_setting)?; + self.set_interface(port, interface_num, alternate_setting).await?; } Ok(()) @@ -747,28 +750,36 @@ impl Xhci { endp_idx: u8, buf: &mut [u8], ) -> Result<(u8, u32)> { + if buf.is_empty() { + return Err(Error::new(EINVAL)); + } + let dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(buf.len())? }; + + let (completion_code, bytes_transferred) = self.transfer( + port_num, + endp_idx, + Some(dma_buffer), + PortReqDirection::DeviceToHost, + ).await?; + + buf.copy_from_slice(&*dma_buffer.as_ref()); + Ok((completion_code, bytes_transferred)) + } + async fn transfer_write(&mut self, port_num: usize, endp_idx: u8, sbuf: &[u8]) -> Result<(u8, u32)> { + if sbuf.is_empty() { + return Err(Error::new(EINVAL)); + } + let mut dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(sbuf.len()) }?; + dma_buffer.copy_from_slice(sbuf); + self.transfer( port_num, endp_idx, - if !buf.is_empty() { - DeviceReqData::In(buf) - } else { - DeviceReqData::NoData - }, + Some(dma_buffer), + PortReqDirection::HostToDevice, ).await } - async fn transfer_write(&mut self, port_num: usize, endp_idx: u8, buf: &[u8]) -> Result<(u8, u32)> { - self.transfer( - port_num, - endp_idx, - if !buf.is_empty() { - DeviceReqData::Out(buf) - } else { - DeviceReqData::NoData - }, - ).await - } - const fn def_control_endp_doorbell() -> u32 { + pub const fn def_control_endp_doorbell() -> u32 { 1 } // TODO: Wrap DCIs and driver-level endp_num into distinct types, due to the high chance of @@ -794,39 +805,23 @@ impl Xhci { } // TODO: Rename DeviceReqData to something more general. async fn transfer( - &mut self, + &self, port_num: usize, endp_idx: u8, - mut buf: DeviceReqData, + dma_buf: Option>, + direction: PortReqDirection, ) -> Result<(u8, u32)> { // TODO: Check that only readable enpoints are read, etc. let endp_num = endp_idx + 1; - // TODO: Check that buf has a nonzero size, otherwise (at least for Rust's GlobalAlloc), - // UB. - let dma_buffer = match buf { - DeviceReqData::Out(sbuf) => { - if sbuf.is_empty() { - return Err(Error::new(EINVAL)); - } - let mut dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(sbuf.len()) }?; - dma_buffer.copy_from_slice(sbuf); - Some(dma_buffer) - } - DeviceReqData::In(ref dbuf) => { - if dbuf.is_empty() { - return Err(Error::new(EINVAL)); - } - Some(unsafe { Dma::<[u8]>::zeroed_unsized(dbuf.len()) }?) - } - DeviceReqData::NoData => None, - }; let port_state = self .port_states .get_mut(&port_num) .ok_or(Error::new(EBADFD))?; + let endp_desc: &EndpDesc = port_state .dev_desc + .as_ref().unwrap() .config_descs .get(0) .ok_or(Error::new(EIO))? @@ -843,7 +838,7 @@ impl Xhci { return Err(Error::new(ENOSYS)); } - if EndpDirection::from(buf.direction()) != endp_desc.direction() { + if EndpDirection::from(direction) != endp_desc.direction() { return Err(Error::new(EBADF)); } @@ -852,23 +847,22 @@ impl Xhci { let (buffer, idt, estimated_td_size) = { let (buffer, idt) = - if buf.len() <= 8 && max_packet_size >= 8 && direction != EndpDirection::In { - buf.map_buf(|sbuf| { + if dma_buf.map(|buf| buf.len()).unwrap_or(0) <= 8 && max_packet_size >= 8 && direction != EndpDirection::In { + dma_buf.map(|sbuf| { let mut bytes = [0u8; 8]; - bytes[..buf.len()].copy_from_slice(&sbuf[..buf.len()]); - // FIXME: little endian, right? + bytes[..sbuf.len()].copy_from_slice(&sbuf); (u64::from_le_bytes(bytes), true) }) .unwrap_or((0, false)) } else { ( - dma_buffer.as_ref().map(|dma| dma.physical()).unwrap_or(0) as u64, + dma_buf.as_ref().map(|dma| dma.physical()).unwrap_or(0) as u64, false, ) }; let estimated_td_size = cmp::min( u8::try_from( - div_round_up(buf.len(), max_transfer_size as usize) * mem::size_of::(), + div_round_up(dma_buf.map(|buf| buf.len()).unwrap_or(0), max_transfer_size as usize) * mem::size_of::(), ) .ok() .unwrap_or(0x1F), @@ -879,7 +873,7 @@ impl Xhci { let stream_id = 1u16; - let mut bytes_left = buf.len(); + let mut bytes_left = dma_buf.map(|buf| buf.len()).unwrap_or(0); let event = self.execute_transfer( port_num, @@ -918,162 +912,120 @@ impl Xhci { ).await?; self.event_handler_finished(); - let bytes_transferred = buf.len() as u32 - event.transfer_length(); - - if let DeviceReqData::In(dbuf) = &mut buf { - dbuf.copy_from_slice(&*dma_buffer.as_ref().unwrap()); - } + let bytes_transferred = dma_buf.map(|buf| buf.len() as u32 - event.transfer_length()).unwrap_or(0); Ok((event.completion_code(), bytes_transferred)) } - pub(crate) fn get_dev_desc(&mut self, port_id: usize) -> Result { - let st = self - .port_states - .get_mut(&port_id) - .ok_or(Error::new(ENOENT))?; - let ports = self.ports.lock().unwrap(); - let run = self.run.lock().unwrap(); - let cmd = self.cmd.lock().unwrap(); - let dbs = self.dbs.lock().unwrap(); - - Self::get_dev_desc_raw( - &mut *ports, - &mut *run, - &mut *cmd, - &mut *dbs, - port_id, - st.slot, - st.endpoint_states - .get_mut(&0) - .ok_or(Error::new(EIO))? - .ring() - .ok_or(Error::new(EIO))?, - ) - } - pub(crate) fn get_dev_desc_raw( - ports: &mut [port::Port], - run: &mut RuntimeRegs, - cmd: &mut Ring, - dbs: &mut [Doorbell], + pub async fn get_desc( + &self, port_id: usize, slot: u8, ring: &mut Ring, ) -> Result { - let port = ports.get(port_id).ok_or(Error::new(ENOENT))?; + let port = self.ports.lock().unwrap().get(port_id).ok_or(Error::new(ENOENT))?; if !port.flags().contains(port::PortFlags::PORT_CCS) { return Err(Error::new(ENOENT)); } - // TODO: Should the descriptors be stored in PortState? - - run.ints[0].erdp.write(cmd.register() | (1 << 3)); - - let mut dev = Device { - ring, - cmd, - db: &mut dbs[slot as usize], - int: &mut run.ints[0], - }; - - let raw_dd = dev.get_device()?; + let raw_dd = self.fetch_dev_desc(port_id, slot, ring).await?; let (manufacturer_str, product_str, serial_str) = ( if raw_dd.manufacturer_str > 0 { - Some(dev.get_string(raw_dd.manufacturer_str)?) + Some(self.fetch_string_desc(port_id, slot, ring, raw_dd.manufacturer_str).await?) } else { None }, if raw_dd.product_str > 0 { - Some(dev.get_string(raw_dd.product_str)?) + Some(self.fetch_string_desc(port_id, slot, ring, raw_dd.product_str).await?) } else { None }, if raw_dd.serial_str > 0 { - Some(dev.get_string(raw_dd.serial_str)?) + Some(self.fetch_string_desc(port_id, slot, ring, raw_dd.serial_str).await?) } else { None }, ); - let (bos_desc, bos_data) = dev.get_bos()?; + let (bos_desc, bos_data) = self.fetch_bos_desc(port_id, slot, ring).await?; let supports_superspeed = usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeed()); let supports_superspeedplus = usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeedplus()); - let config_descs = (0..raw_dd.configurations) - .map(|index| -> Result<_> { - let (desc, data) = dev.get_config(index)?; + let mut config_descs = SmallVec::new(); - let extra_length = desc.total_length as usize - mem::size_of_val(&desc); - let data = &data[..extra_length]; + for index in 0..raw_dd.configurations { + let (desc, data) = self.fetch_config_desc(port_id, slot, ring, index).await?; - let mut i = 0; - let mut descriptors = Vec::new(); + let extra_length = desc.total_length as usize - mem::size_of_val(&desc); + let data = &data[..extra_length]; - while let Some((descriptor, len)) = AnyDescriptor::parse(&data[i..]) { - descriptors.push(descriptor); - i += len; - } + let mut i = 0; + let mut descriptors = Vec::new(); - let mut interface_descs = SmallVec::new(); - let mut iter = descriptors.into_iter(); + while let Some((descriptor, len)) = AnyDescriptor::parse(&data[i..]) { + descriptors.push(descriptor); + i += len; + } - while let Some(item) = iter.next() { - if let AnyDescriptor::Interface(idesc) = item { - let mut endpoints = SmallVec::<[EndpDesc; 4]>::new(); - let mut hid_descs = SmallVec::<[HidDesc; 1]>::new(); + let mut interface_descs = SmallVec::new(); + let mut iter = descriptors.into_iter(); - for _ in 0..idesc.endpoints { + while let Some(item) = iter.next() { + if let AnyDescriptor::Interface(idesc) = item { + let mut endpoints = SmallVec::<[EndpDesc; 4]>::new(); + let mut hid_descs = SmallVec::<[HidDesc; 1]>::new(); + + for _ in 0..idesc.endpoints { + let next = match iter.next() { + Some(AnyDescriptor::Endpoint(n)) => n, + Some(AnyDescriptor::Hid(h)) if idesc.class == 3 => { + hid_descs.push(h.into()); + break; + } + _ => break, + }; + let mut endp = EndpDesc::from(next); + + if supports_superspeed { let next = match iter.next() { - Some(AnyDescriptor::Endpoint(n)) => n, - Some(AnyDescriptor::Hid(h)) if idesc.class == 3 => { - hid_descs.push(h.into()); - break; - } + Some(AnyDescriptor::SuperSpeedCompanion(n)) => n, _ => break, }; - let mut endp = EndpDesc::from(next); + endp.ssc = Some(SuperSpeedCmp::from(next)); - if supports_superspeed { + if endp.has_ssp_companion() && supports_superspeedplus { let next = match iter.next() { - Some(AnyDescriptor::SuperSpeedCompanion(n)) => n, + Some(AnyDescriptor::SuperSpeedPlusCompanion(n)) => n, _ => break, }; - endp.ssc = Some(SuperSpeedCmp::from(next)); - - if endp.has_ssp_companion() && supports_superspeedplus { - let next = match iter.next() { - Some(AnyDescriptor::SuperSpeedPlusCompanion(n)) => n, - _ => break, - }; - endp.sspc = Some(SuperSpeedPlusIsochCmp::from(next)); - } + endp.sspc = Some(SuperSpeedPlusIsochCmp::from(next)); } - endpoints.push(endp); } - - interface_descs.push(IfDesc::new(&mut dev, idesc, endpoints, hid_descs)?); - } else { - // TODO - break; + endpoints.push(endp); } - } - Ok(ConfDesc { - kind: desc.kind, - configuration: if desc.configuration_str > 0 { - Some(dev.get_string(desc.configuration_str)?) - } else { - None - }, - configuration_value: desc.configuration_value, - attributes: desc.attributes, - max_power: desc.max_power, - interface_descs, - }) - }) - .collect::>>()?; + interface_descs.push(self.new_if_desc(port_id, slot, ring, idesc, endpoints, hid_descs).await?); + } else { + // TODO + break; + } + } + + config_descs.push(ConfDesc { + kind: desc.kind, + configuration: if desc.configuration_str > 0 { + Some(self.fetch_string_desc(port_id, slot, ring, desc.configuration_str).await?) + } else { + None + }, + configuration_value: desc.configuration_value, + attributes: desc.attributes, + max_power: desc.max_power, + interface_descs, + }); + }; Ok(DevDesc { kind: raw_dd.kind, @@ -1108,7 +1060,7 @@ impl Xhci { bytes_to_read } - fn port_req_transfer( + async fn port_req_transfer( &mut self, port_num: usize, data_buffer: Option<&mut Dma<[u8]>>, @@ -1129,7 +1081,7 @@ impl Xhci { ); ControlFlow::Break }, - )?; + ).await?; Ok(()) } fn port_req_init_st(&mut self, port_num: usize, req: &PortReq) -> Result { @@ -1169,7 +1121,7 @@ impl Xhci { // FIXME: Make sure there aren't any other PortReq handles, perhaps by storing the state in // PortState? } - fn handle_port_req_write( + async fn handle_port_req_write( &mut self, fd: usize, port_num: usize, @@ -1184,7 +1136,7 @@ impl Xhci { if let PortReqState::TmpSetup(setup) = st { // No need for any additional reads or writes, before completing. - self.port_req_transfer(port_num, None, setup, TransferKind::NoData)?; + self.port_req_transfer(port_num, None, setup, TransferKind::NoData).await?; st = PortReqState::Init; } @@ -1196,7 +1148,7 @@ impl Xhci { } dma_buffer.copy_from_slice(buf); - self.port_req_transfer(port_num, Some(&mut dma_buffer), setup, TransferKind::Out)?; + self.port_req_transfer(port_num, Some(&mut dma_buffer), setup, TransferKind::Out).await?; st = PortReqState::Init; buf.len() @@ -1211,7 +1163,7 @@ impl Xhci { } Ok(bytes_written) } - fn handle_port_req_read( + async fn handle_port_req_read( &mut self, fd: usize, port_num: usize, @@ -1223,7 +1175,7 @@ impl Xhci { if buf.len() != dma_buffer.len() { return Err(Error::new(EINVAL)); } - self.port_req_transfer(port_num, Some(&mut dma_buffer), setup, TransferKind::In)?; + self.port_req_transfer(port_num, Some(&mut dma_buffer), setup, TransferKind::In).await?; buf.copy_from_slice(&dma_buffer); st = PortReqState::Init; @@ -1413,8 +1365,7 @@ impl SchemeMut for Xhci { _ => return Err(Error::new(ENOENT)), }; - let fd = self.next_handle; - self.next_handle += 1; + let fd = self.next_handle.fetch_add(1, atomic::Ordering::Relaxed); self.handles.insert(fd, handle); Ok(fd) @@ -1545,7 +1496,7 @@ impl SchemeMut for Xhci { &mut Handle::Endpoint(port_num, endp_num, ref mut st) => match st { EndpointHandleTy::Ctl => self.on_read_endp_ctl(port_num, endp_num, buf), - EndpointHandleTy::Data => self.on_read_endp_data(port_num, endp_num, buf), + EndpointHandleTy::Data => block_on(self.on_read_endp_data(port_num, endp_num, buf)), EndpointHandleTy::Root(_, _) => return Err(Error::new(EBADF)), }, &mut Handle::PortState(port_num, ref mut offset) => { @@ -1574,7 +1525,7 @@ impl SchemeMut for Xhci { } &mut Handle::PortReq(port_num, ref mut st) => { let state = std::mem::replace(st, PortReqState::Tmp); - self.handle_port_req_read(fd, port_num, state, buf) + block_on(self.handle_port_req_read(fd, port_num, state, buf)) } } } @@ -1582,17 +1533,17 @@ impl SchemeMut for Xhci { let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; match &mut *guard { &mut Handle::ConfigureEndpoints(port_num) => { - self.configure_endpoints(port_num, buf)?; + block_on(self.configure_endpoints(port_num, buf))?; Ok(buf.len()) } &mut Handle::Endpoint(port_num, endp_num, ref ep_file_ty) => match ep_file_ty { - EndpointHandleTy::Ctl => self.on_write_endp_ctl(port_num, endp_num, buf), - EndpointHandleTy::Data => self.on_write_endp_data(port_num, endp_num, buf), + EndpointHandleTy::Ctl => block_on(self.on_write_endp_ctl(port_num, endp_num, buf)), + EndpointHandleTy::Data => block_on(self.on_write_endp_data(port_num, endp_num, buf)), EndpointHandleTy::Root(_, _) => return Err(Error::new(EBADF)), }, &mut Handle::PortReq(port_num, ref mut st) => { let state = std::mem::replace(st, PortReqState::Tmp); - self.handle_port_req_write(fd, port_num, state, buf) + block_on(self.handle_port_req_write(fd, port_num, state, buf)) } // TODO: Introduce PortReqState::Waiting, which this write call changes to // PortReqState::ReadyToWrite when all bytes are written. @@ -1608,13 +1559,28 @@ impl SchemeMut for Xhci { } impl Xhci { pub fn get_endp_status(&mut self, port_num: usize, endp_num: u8) -> Result { - let slot = self + let port_state = self .port_states .get(&port_num) - .ok_or(Error::new(EBADFD))? - .slot; + .ok_or(Error::new(EBADFD))?; + + let slot = port_state.slot; + + let endp_desc = port_state + .dev_desc + .as_ref().unwrap() + .config_descs + .get(0) + .ok_or(Error::new(EIO))? + .interface_descs + .get(0) + .ok_or(Error::new(EIO))? + .endpoints + .get(endp_num as usize - 1) + .ok_or(Error::new(EBADFD))?; + let endp_num_xhc = if endp_num != 0 { - Self::endp_num_to_dci(endp_num, self.endp_desc(port_num, endp_num)?) + Self::endp_num_to_dci(endp_num, endp_desc) } else { 1 }; @@ -1664,7 +1630,7 @@ impl Xhci { index: 0, // TODO: interface num length: 0, }, - )?; + ).await?; } Ok(()) } @@ -1676,6 +1642,7 @@ impl Xhci { let endp_desc = port_state .dev_desc + .as_ref().unwrap() .config_descs .get(0) .ok_or(Error::new(EIO))? @@ -1727,6 +1694,7 @@ impl Xhci { .get(&port_num) .ok_or(Error::new(EIO))? .dev_desc + .as_ref().unwrap() .config_descs .first() .ok_or(Error::new(EIO))? @@ -1755,7 +1723,7 @@ impl Xhci { _ => return Err(Error::new(EIO)), }; - let endp_desc = port_state.dev_desc.config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; + let endp_desc = port_state.dev_desc.as_ref().unwrap().config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); let (event_trb, command_trb) = self.execute_command(|trb, cycle| { @@ -1806,7 +1774,7 @@ impl Xhci { // Yield the result directly because no bytes have to be sent or received // beforehand. let (completion_code, bytes_transferred) = - self.transfer(port_num, endp_num - 1, DeviceReqData::NoData).await?; + self.transfer(port_num, endp_num - 1, None, PortReqDirection::DeviceToHost).await?; if bytes_transferred > 0 { return Err(Error::new(EIO)); } @@ -1853,7 +1821,7 @@ impl Xhci { bytes_transferred, } } - pub fn on_write_endp_data( + pub async fn on_write_endp_data( &mut self, port_num: usize, endp_num: u8, @@ -1874,7 +1842,7 @@ impl Xhci { return Err(Error::new(EINVAL)); } let (completion_code, some_bytes_transferred) = - self.transfer_write(port_num, endp_num - 1, buf)?; + self.transfer_write(port_num, endp_num - 1, buf).await?; let result = Self::transfer_result(completion_code, some_bytes_transferred); // To avoid having to read from the Ctl interface file, the client should stop @@ -1937,7 +1905,7 @@ impl Xhci { serde_json::to_writer(&mut cursor, &res).or(Err(Error::new(EIO)))?; Ok(cursor.seek(io::SeekFrom::Current(0)).unwrap() as usize) } - pub fn on_read_endp_data( + pub async fn on_read_endp_data( &mut self, port_num: usize, endp_num: u8, @@ -1962,7 +1930,7 @@ impl Xhci { } let (completion_code, some_bytes_transferred) = - self.transfer_read(port_num, endp_num - 1, buf)?; + self.transfer_read(port_num, endp_num - 1, buf).await?; // Just as with on_write_endp_data, a client issuing multiple reads must always // stop reading if one read returns fewer bytes than expected. @@ -2001,7 +1969,7 @@ impl Xhci { self.run.lock().unwrap().ints[0].erdp.writef(1 << 3, true); } } -fn handle_event_trb(name: &str, event_trb: &Trb, command_trb: &Trb) -> Result<()> { +pub fn handle_event_trb(name: &str, event_trb: &Trb, command_trb: &Trb) -> Result<()> { if event_trb.completion_code() == TrbCompletionCode::Success as u8 { Ok(()) } else { @@ -2009,7 +1977,7 @@ fn handle_event_trb(name: &str, event_trb: &Trb, command_trb: &Trb) -> Result<() Err(Error::new(EIO)) } } -fn handle_transfer_event_trb(name: &str, event_trb: &Trb, transfer_trb: &Trb) -> Result<()> { +pub fn handle_transfer_event_trb(name: &str, event_trb: &Trb, transfer_trb: &Trb) -> Result<()> { if event_trb.completion_code() == TrbCompletionCode::Success as u8 || event_trb.completion_code() == TrbCompletionCode::ShortPacket as u8 { Ok(()) } else { diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index c23f543a38..1a91800bbf 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -374,10 +374,10 @@ impl Trb { ); } - pub fn status(&mut self, input: bool, cycle: bool) { + pub fn status(&mut self, interrupter: u16, input: bool, ioc: bool, ch: bool, ent: bool, cycle: bool) { self.set( 0, - 0, + u32::from(interrupter) << 22, ((input as u32) << 16) | ((TrbType::StatusStage as u32) << 10) | (1 << 5)