Fix most high-level errors in xhcid.

This commit is contained in:
4lDO2
2020-03-27 23:44:01 +01:00
parent bae238bbef
commit 6791429cd2
8 changed files with 503 additions and 485 deletions
+10 -42
View File
@@ -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::<Packet>::new()));
let todo_futures = Arc::new(Mutex::new(Vec::<Pin<Box<dyn Future<Output = usize> + 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<Option<()>> {
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<Option<()>> {
let mut socket = socket_packet.lock().unwrap();
let mut hci = hci.lock().unwrap();
let mut hci = hci;
let mut todo = todo.lock().unwrap();
loop {
+2 -2
View File
@@ -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())
+7 -9
View File
@@ -161,7 +161,6 @@ impl StreamContextArray {
}
#[repr(packed)]
#[derive(Clone, Debug)]
pub struct ScratchpadBufferEntry {
pub value: Mmio<u64>,
}
@@ -179,21 +178,20 @@ impl ScratchpadBufferArray {
pub fn new(entries: u16) -> Result<Self> {
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<usize> {
// 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::<Result<Vec<usize>, _>>()?;
Ok(Self {
entries,
pages,
})
}
pub fn register(&self) -> u64 {
pub fn register(&self) -> usize {
self.entries.physical()
}
}
+83 -51
View File
@@ -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<Xhci>,
current_count: Arc<AtomicUsize>,
irq_file: Option<File>,
receiver: Receiver<NewPendingTrb>,
@@ -75,18 +85,13 @@ pub struct IrqReactor {
pub type NewPendingTrb = State;
pub fn start_irq_reactor(hci: Arc<Xhci>, irq_file: Option<File>) -> thread::JoinHandle<()> {
thread::spawn(move || {
IrqReactor::new(hci, irq_file).run()
})
}
impl IrqReactor {
pub fn new(hci: Arc<Xhci>, irq_file: Option<File>) -> Self {
pub fn new(hci: Arc<Xhci>, receiver: Receiver<NewPendingTrb>, irq_file: Option<File>) -> 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::<usize>() {
panic!("wrong number of bytes read from `irq:`: expected {}, got {}", mem::size_of::<usize>(), 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<Trb> {
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, F: FnOnce(&Ring) -> T>(&self, id: RingId, function: F) -> T {
pub fn with_ring<T, F: FnOnce(&Ring) -> T>(&self, id: RingId, function: F) -> Option<T> {
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, F: FnOnce(&mut Ring) -> T>(&self, id: RingId, function: F) -> T {
pub fn with_ring_mut<T, F: FnOnce(&mut Ring) -> T>(&self, id: RingId, function: F) -> Option<T> {
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<Output = NextEventTrb> + 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(),
}
}
}
+161 -110
View File
@@ -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<T>(&mut self, kind: usb::DescriptorKind, index: u8, desc: &mut Dma<T>) {
impl Xhci {
/// Gets descriptors, before the port state is initiated.
async fn get_desc_raw<T>(&self, port: usize, slot: u8, kind: usb::DescriptorKind, index: u8, ring: &mut Ring, desc: &mut Dma<T>) -> Result<()> {
let len = mem::size_of::<T>();
{
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<usb::DeviceDescriptor> {
async fn fetch_dev_desc(&mut self, port: usize, slot: u8, ring: &mut Ring) -> Result<usb::DeviceDescriptor> {
let mut desc = Dma::<usb::DeviceDescriptor>::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<String> {
async fn fetch_string_desc(&mut self, port: usize, slot: u8, ring: &mut Ring, index: u8) -> Result<String> {
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<usize, scheme::Handle>,
next_handle: usize,
next_handle: AtomicUsize,
port_states: CHashMap<usize, PortState>,
drivers: CHashMap<usize, process::Child>,
@@ -191,16 +186,25 @@ pub struct Xhci {
interrupt_method: InterruptMethod,
pcid_handle: Mutex<PcidServerHandle>,
irq_reactor: Option<thread::JoinHandle<()>>,
irq_reactor: Mutex<Option<thread::JoinHandle<()>>>,
irq_reactor_sender: Sender<NewPendingTrb>,
// 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<NewPendingTrb>,
}
unsafe impl Send for Xhci {}
unsafe impl Sync for Xhci {}
struct PortState {
slot: u8,
cfg_idx: Option<u8>,
if_idx: Option<u8>,
input_context: Mutex<Dma<InputContext>>,
dev_desc: DevDesc,
dev_desc: Option<DevDesc>,
endpoint_states: BTreeMap<u8, EndpointState>,
}
@@ -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::<Trb>();
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<u8> {
pub async fn enable_port_slot(&mut self, slot_ty: u8) -> Result<u8> {
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::<InputContext>::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::<BTreeMap<_, _>>(),
};
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<InputContext>,
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<MutexGuard<'_, MsixInfo>> {
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<MutexGuard<'_, MsixInfo>> {
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<Xhci>, irq_file: Option<File>) {
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,
+9 -8
View File
@@ -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<usize> {
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::<Trb>(), 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<Trb> {
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::<Trb>() {
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::<Trb>() {
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
}
/*
+229 -261
View File
@@ -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<usb::SuperSpeedPlusIsochCmpDescriptor> for SuperSpeedPlusIsochCmp {
}
}
impl IfDesc {
fn new(
dev: &mut Device,
desc: usb::InterfaceDescriptor,
endps: impl IntoIterator<Item = EndpDesc>,
hid_descs: impl IntoIterator<Item = HidDesc>,
) -> Result<Self> {
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<Item = EndpDesc>,
hid_descs: impl IntoIterator<Item = HidDesc>,
) -> Result<IfDesc> {
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<F: FnOnce(&mut Trb, bool)>(&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<D>(
pub async fn execute_control_transfer<D>(
&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<D>(
&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<Dma<[u8]>>,
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::<Trb>(),
div_round_up(dma_buf.map(|buf| buf.len()).unwrap_or(0), max_transfer_size as usize) * mem::size_of::<Trb>(),
)
.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<DevDesc> {
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<DevDesc> {
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::<Result<SmallVec<_>>>()?;
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<PortReqState> {
@@ -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<EndpointStatus> {
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 {
+2 -2
View File
@@ -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)