Fixed the deadlock by only addressing devices in response to attach requests....
This commit is contained in:
committed by
Jeremy Soller
parent
3f33cb96e7
commit
4dedbac4e5
@@ -104,7 +104,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
|
||||
"audio",
|
||||
"pcie",
|
||||
"ihda",
|
||||
log::LevelFilter::Debug,
|
||||
log::LevelFilter::Info,
|
||||
log::LevelFilter::Info,
|
||||
);
|
||||
|
||||
|
||||
+2
-2
@@ -432,8 +432,8 @@ pub fn main() {
|
||||
"misc",
|
||||
"inputd",
|
||||
"inputd",
|
||||
log::LevelFilter::Trace,
|
||||
log::LevelFilter::Trace,
|
||||
log::LevelFilter::Info,
|
||||
log::LevelFilter::Debug,
|
||||
);
|
||||
|
||||
let mut args = std::env::args().skip(1);
|
||||
|
||||
+9
-7
@@ -47,6 +47,7 @@ use pcid_interface::{
|
||||
|
||||
use common::io::Io;
|
||||
use event::{Event, RawEventQueue};
|
||||
use log::info;
|
||||
use syscall::data::Packet;
|
||||
use syscall::error::EWOULDBLOCK;
|
||||
use syscall::flag::EventFlags;
|
||||
@@ -204,7 +205,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
|
||||
"host",
|
||||
&name,
|
||||
log::LevelFilter::Info,
|
||||
log::LevelFilter::Debug,
|
||||
log::LevelFilter::Info,
|
||||
);
|
||||
|
||||
log::debug!("XHCI PCI CONFIG: {:?}", pci_config);
|
||||
@@ -214,8 +215,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
|
||||
.ptr
|
||||
.as_ptr() as usize;
|
||||
|
||||
let (irq_file, interrupt_method) = (None, InterruptMethod::Polling);
|
||||
// TODO: fix interrutps: get_int_method(&mut pcid_handle, address);
|
||||
let (irq_file, interrupt_method) = (None, InterruptMethod::Polling); //get_int_method(&mut pcid_handle, address);
|
||||
//TODO: Fix interrupts.
|
||||
|
||||
println!(" + XHCI {}", pci_config.func.display());
|
||||
|
||||
@@ -227,17 +228,18 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
|
||||
|
||||
daemon.ready().expect("xhcid: failed to notify parent");
|
||||
|
||||
let hci = Arc::new(
|
||||
let mut hci = Arc::new(
|
||||
Xhci::new(scheme_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");
|
||||
xhci::start_device_enumerator(&hci);
|
||||
|
||||
hci.poll();
|
||||
|
||||
//let event_queue = RawEventQueue::new().expect("xhcid: failed to create event queue");
|
||||
|
||||
libredox::call::setrens(0, 0).expect("xhcid: failed to enter null namespace");
|
||||
|
||||
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()));
|
||||
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
use crate::xhci::port::PortFlags;
|
||||
use crate::xhci::scheme::Handle::Port;
|
||||
use crate::xhci::Xhci;
|
||||
use common::io::Io;
|
||||
use crossbeam_channel;
|
||||
use crossbeam_channel::RecvError;
|
||||
use log::{debug, error, info, trace, warn};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
use syscall::EAGAIN;
|
||||
|
||||
//enum HubPortState{
|
||||
// PoweredOff,
|
||||
// Disabled,
|
||||
// Disconnected,
|
||||
// Reset,
|
||||
// Enabled,
|
||||
// Error,
|
||||
// Polling,
|
||||
// Compliance,
|
||||
// Loopback
|
||||
//}
|
||||
//
|
||||
//impl HubPortState{
|
||||
// pub fn from_port_flags(flags: PortFlags, protocol_version: (u8, u8)) -> Self{
|
||||
// let pp = flags.contains(PortFlags::PORT_PP);
|
||||
// let ccs = flags.contains(PortFlags::PORT_CCS);
|
||||
// let ped = flags.contains(PortFlags::PORT_PED);
|
||||
// let pr = flags.contains(PortFlags::PORT_PR);
|
||||
//
|
||||
// match protocol_version {
|
||||
// (2, _) | (1, _) => {
|
||||
// match (pp, ccs, ped, pr) {
|
||||
// (false, false, false, false) => { HubPortState::PoweredOff },
|
||||
// (true, false, false, false) => { HubPortState::Disconnected },
|
||||
// (true, true, false, true) => { HubPortState::Reset },
|
||||
// (true, true, false, false) => { HubPortState::Disabled },
|
||||
// (true, true, true, false) => { HubPortState::Enabled },
|
||||
// (true, true, true, true) => unreachable!(), //PED shouldnt be set when PR is set
|
||||
// (false, _, _, _) => unreachable!(), //None of the other bits should be set when the port is off
|
||||
// _ => unreachable!() //This state shouldn't be valid.
|
||||
// }
|
||||
// }
|
||||
// (3, _) => {
|
||||
// //TO-DO: USB3 state machine.
|
||||
// HubPortState::PoweredOff
|
||||
// },
|
||||
// (_, _) => unreachable!() //We don't support protocols > 3 yet.
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//struct RootHubPortStateMachine{
|
||||
// hci: Arc<Xhci>,
|
||||
// port_num: u8,
|
||||
// port_index: usize,
|
||||
// protocol_major_version: u8,
|
||||
// protocol_minor_version: u8,
|
||||
// state: HubPortState
|
||||
//}
|
||||
//
|
||||
//impl RootHubPortStateMachine{
|
||||
// fn new(port_num: u8, hci: Arc<Xhci>) -> Self{
|
||||
//
|
||||
// let hci = hci.clone();
|
||||
// let port_index = (port_num - 1) as usize;
|
||||
//
|
||||
// //TODO: Get actual protocol version
|
||||
// let (maj, min) = (2u8, 0u8);
|
||||
//
|
||||
// //TODO: Get actual flags
|
||||
// let flags = PortFlags::all();
|
||||
//
|
||||
// RootHubPortStateMachine{
|
||||
// hci,
|
||||
// port_num,
|
||||
// port_index,
|
||||
// protocol_major_version: maj,
|
||||
// protocol_minor_version: min,
|
||||
// state: HubPortState::from_port_flags(flags, (maj, min))
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fn execute(&mut self, port_num: u8){
|
||||
// //TO-DO: Implement the state machine.
|
||||
// }
|
||||
//}
|
||||
|
||||
pub struct DeviceEnumerationRequest {
|
||||
pub port_number: u8,
|
||||
}
|
||||
|
||||
pub struct DeviceEnumerator {
|
||||
hci: Arc<Xhci>,
|
||||
request_queue: crossbeam_channel::Receiver<DeviceEnumerationRequest>,
|
||||
}
|
||||
|
||||
impl DeviceEnumerator {
|
||||
pub fn new(hci: Arc<Xhci>) -> Self {
|
||||
let request_queue = hci.device_enumerator_receiver.clone();
|
||||
DeviceEnumerator { hci, request_queue }
|
||||
}
|
||||
|
||||
pub fn run(&mut self) {
|
||||
loop {
|
||||
trace!("Start Device Enumerator Loop");
|
||||
let request = match self.request_queue.recv() {
|
||||
Ok(req) => req,
|
||||
Err(err) => {
|
||||
panic!("Failed to received an enumeration request! error: {}", err)
|
||||
}
|
||||
};
|
||||
|
||||
let port_array_index = request.port_number - 1;
|
||||
|
||||
let (len, flags) = {
|
||||
let ports = self.hci.ports.lock().unwrap();
|
||||
|
||||
let len = ports.len();
|
||||
|
||||
if port_array_index as usize >= len {
|
||||
warn!(
|
||||
"Received out of bounds Device Enumeration request for port {}",
|
||||
request.port_number
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
(len, ports[port_array_index as usize].flags())
|
||||
};
|
||||
|
||||
if flags.contains(PortFlags::PORT_CCS) {
|
||||
info!(
|
||||
"Received Device Connect Port Status Change Event with port flags {:?}",
|
||||
flags
|
||||
);
|
||||
//If the port isn't enabled (i.e. it's a USB2 port), we need to reset it if it isn't resetting already
|
||||
//A USB3 port won't generate a Connect Status Change until it's already enabled, so this check
|
||||
//will always be skipped for USB3 ports
|
||||
if !flags.contains(PortFlags::PORT_PED) {
|
||||
let disabled_state = flags.contains(PortFlags::PORT_PP)
|
||||
&& flags.contains(PortFlags::PORT_CCS)
|
||||
&& !flags.contains(PortFlags::PORT_PED)
|
||||
&& !flags.contains(PortFlags::PORT_PR);
|
||||
|
||||
if !disabled_state {
|
||||
panic!(
|
||||
"Port {} isn't in the disabled state! Current flags: {:?}",
|
||||
request.port_number, flags
|
||||
);
|
||||
} else {
|
||||
debug!(
|
||||
"Port {} has entered the disabled state.",
|
||||
request.port_number
|
||||
);
|
||||
}
|
||||
|
||||
//THIS LOCKS THE PORTS. DO NOT LOCK PORTS BEFORE THIS POINT
|
||||
info!("Received a device connect on port {}, but it's not enabled. Resetting the port.", request.port_number);
|
||||
self.hci.reset_port((port_array_index as usize));
|
||||
|
||||
let mut ports = self.hci.ports.lock().unwrap();
|
||||
let port = &mut ports[port_array_index as usize];
|
||||
|
||||
port.portsc.writef(PortFlags::PORT_PRC.bits(), true);
|
||||
|
||||
std::thread::sleep(Duration::from_millis(16)); //Some controllers need some extra time to make the transition.
|
||||
|
||||
let flags = port.flags();
|
||||
|
||||
let enabled_state = flags.contains(PortFlags::PORT_PP)
|
||||
&& flags.contains(PortFlags::PORT_CCS)
|
||||
&& flags.contains(PortFlags::PORT_PED)
|
||||
&& !flags.contains(PortFlags::PORT_PR);
|
||||
|
||||
if !enabled_state {
|
||||
warn!(
|
||||
"Port {} isn't in the enabled state! Current flags: {:?}",
|
||||
request.port_number, flags
|
||||
);
|
||||
} else {
|
||||
debug!(
|
||||
"Port {} is in the enabled state. Proceeding with enumeration",
|
||||
request.port_number
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let result = futures::executor::block_on(self.hci.attach_device(port_array_index));
|
||||
match result {
|
||||
Ok(_) => {
|
||||
info!("Device on port {} was attached", port_array_index);
|
||||
}
|
||||
Err(err) => {
|
||||
if err.errno == EAGAIN {
|
||||
info!("Received a device connect notification for an already connected device. Ignoring...")
|
||||
} else {
|
||||
warn!("processing of device attach request failed! Error: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
info!(
|
||||
"Device Enumerator received Detach request on port {} which is in state {}",
|
||||
request.port_number,
|
||||
self.hci.get_pls((port_array_index) as usize)
|
||||
);
|
||||
let result =
|
||||
futures::executor::block_on(self.hci.detach_device(port_array_index as usize));
|
||||
match result {
|
||||
Ok(_) => {
|
||||
info!("Device on port {} was detached", port_array_index);
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("processing of device attach request failed! Error: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+130
-21
@@ -1,24 +1,28 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs::File;
|
||||
use std::future::Future;
|
||||
use std::io::prelude::*;
|
||||
use std::pin::Pin;
|
||||
use std::sync::atomic::{self, AtomicUsize};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::task;
|
||||
use std::{io, mem, task, thread};
|
||||
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
use crossbeam_channel::{Receiver, Sender};
|
||||
use futures::Stream;
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
use event::RawEventQueue;
|
||||
|
||||
use super::doorbell::Doorbell;
|
||||
use super::event::EventRing;
|
||||
use super::ring::Ring;
|
||||
use super::trb::{Trb, TrbCompletionCode, TrbType};
|
||||
use super::Xhci;
|
||||
|
||||
use super::{port, Xhci};
|
||||
use crate::xhci::device_enumerator::DeviceEnumerationRequest;
|
||||
use crate::xhci::port::PortFlags;
|
||||
use crate::xhci::scheme::AnyDescriptor::Device;
|
||||
use common::io::Io as _;
|
||||
use event::{Event, EventQueue, RawEventQueue};
|
||||
|
||||
/// Short-term states (as in, they are removed when the waker is consumed, but probably pushed back
|
||||
/// by the future unless it completed).
|
||||
@@ -87,8 +91,8 @@ impl StateKind {
|
||||
pub struct IrqReactor {
|
||||
hci: Arc<Xhci>,
|
||||
irq_file: Option<File>,
|
||||
receiver: Receiver<NewPendingTrb>,
|
||||
|
||||
irq_receiver: Receiver<NewPendingTrb>,
|
||||
device_enumerator_sender: Sender<DeviceEnumerationRequest>,
|
||||
states: Vec<State>,
|
||||
// TODO: Since the IRQ reactor is the only part of this driver that gets event TRBs, perhaps
|
||||
// the event ring should be owned here?
|
||||
@@ -97,11 +101,15 @@ pub struct IrqReactor {
|
||||
pub type NewPendingTrb = State;
|
||||
|
||||
impl IrqReactor {
|
||||
pub fn new(hci: Arc<Xhci>, receiver: Receiver<NewPendingTrb>, irq_file: Option<File>) -> Self {
|
||||
pub fn new(hci: Arc<Xhci>, irq_file: Option<File>) -> Self {
|
||||
let device_enumerator_sender = hci.device_enumerator_sender.clone();
|
||||
let irq_receiver = hci.irq_reactor_receiver.clone();
|
||||
|
||||
Self {
|
||||
hci,
|
||||
irq_file,
|
||||
receiver,
|
||||
irq_receiver,
|
||||
device_enumerator_sender,
|
||||
states: Vec::new(),
|
||||
}
|
||||
}
|
||||
@@ -133,24 +141,65 @@ impl IrqReactor {
|
||||
continue 'trb_loop;
|
||||
}
|
||||
|
||||
trace!("Found event TRB: {:?}", event_trb);
|
||||
trace!(
|
||||
"Found event TRB at index {} with type {} and cycle bit {}: {:?}",
|
||||
event_trb_index,
|
||||
event_trb.trb_type(),
|
||||
event_trb.cycle() as u8,
|
||||
event_trb
|
||||
);
|
||||
|
||||
if self.check_event_ring_full(event_trb.clone()) {
|
||||
info!("Had to resize event TRB, retrying...");
|
||||
hci_clone.event_handler_finished();
|
||||
continue 'trb_loop;
|
||||
}
|
||||
|
||||
trace!("Handling requests");
|
||||
self.handle_requests();
|
||||
self.acknowledge(event_trb.clone());
|
||||
trace!("Requests handled");
|
||||
|
||||
match event_trb.trb_type() {
|
||||
_ if event_trb.trb_type() == TrbType::PortStatusChange as u8 => {
|
||||
trace!("Received a port status change!");
|
||||
self.handle_port_status_change(event_trb.clone())
|
||||
} //TODO Handle the other unprompted events
|
||||
_ => {
|
||||
self.acknowledge(event_trb.clone());
|
||||
}
|
||||
}
|
||||
|
||||
event_trb.reserved(false);
|
||||
|
||||
self.update_erdp(&*event_ring);
|
||||
hci_clone.event_handler_finished();
|
||||
|
||||
event_trb_index = event_ring.ring.next_index();
|
||||
}
|
||||
}
|
||||
|
||||
fn mask_interrupts(&mut self) {
|
||||
let mut run = self.hci.run.lock().unwrap();
|
||||
|
||||
debug!("Masking interrupts!");
|
||||
|
||||
if !run.ints[0].iman.readf(1 << 1) {
|
||||
warn!("Attempted to mask interrupts when they were already disabled!")
|
||||
}
|
||||
|
||||
run.ints[0].iman.writef(1 << 1, false);
|
||||
}
|
||||
|
||||
fn unmask_interrupts(&mut self) {
|
||||
let mut run = self.hci.run.lock().unwrap();
|
||||
|
||||
debug!("unmasking interrupts!");
|
||||
if run.ints[0].iman.readf(1 << 1) {
|
||||
warn!("Attempted to unmask interrupts when they were already enabled!")
|
||||
}
|
||||
|
||||
run.ints[0].iman.writef(1 << 1, true);
|
||||
}
|
||||
|
||||
fn run_with_irq_file(mut self) {
|
||||
debug!("Running IRQ reactor with IRQ file and event queue");
|
||||
|
||||
@@ -162,6 +211,7 @@ impl IrqReactor {
|
||||
.subscribe(irq_fd as usize, 0, event::EventFlags::READ)
|
||||
.unwrap();
|
||||
|
||||
trace!("IRQ Reactor has created its event queue.");
|
||||
let mut event_trb_index = {
|
||||
hci_clone
|
||||
.primary_event_ring
|
||||
@@ -171,6 +221,7 @@ impl IrqReactor {
|
||||
.next_index()
|
||||
};
|
||||
|
||||
trace!("IRQ reactor has grabbed the next index in the event ring.");
|
||||
for _event in event_queue {
|
||||
trace!("IRQ event queue notified");
|
||||
let mut buffer = [0u8; 8];
|
||||
@@ -188,6 +239,8 @@ impl IrqReactor {
|
||||
break;
|
||||
}
|
||||
|
||||
self.mask_interrupts();
|
||||
|
||||
trace!("IRQ reactor received an IRQ");
|
||||
|
||||
let _ = self.irq_file.as_mut().unwrap().write(&buffer);
|
||||
@@ -199,41 +252,92 @@ impl IrqReactor {
|
||||
let mut count = 0;
|
||||
|
||||
loop {
|
||||
trace!("count: {}", count);
|
||||
let event_trb = &mut event_ring.ring.trbs[event_trb_index];
|
||||
|
||||
if event_trb.completion_code() == TrbCompletionCode::Invalid as u8 {
|
||||
if count == 0 {
|
||||
warn!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.")
|
||||
}
|
||||
// no more events were found, continue the loop
|
||||
//hci_clone.event_handler_finished();
|
||||
self.unmask_interrupts();
|
||||
return;
|
||||
} else {
|
||||
count += 1
|
||||
}
|
||||
|
||||
trace!(
|
||||
"Found event TRB type {}: {:?}",
|
||||
info!(
|
||||
"Found event TRB at index {} with type {} and cycle bit {}: {:?}",
|
||||
event_trb_index,
|
||||
event_trb.trb_type(),
|
||||
event_trb.cycle() as u8,
|
||||
event_trb
|
||||
);
|
||||
|
||||
if self.check_event_ring_full(event_trb.clone()) {
|
||||
info!("Had to resize event TRB, retrying...");
|
||||
hci_clone.event_handler_finished();
|
||||
//hci_clone.event_handler_finished();
|
||||
if self.hci.interrupt_is_pending(0) {
|
||||
warn!("After incrementing the dequeue pointer, the interrupt bit is still pending.")
|
||||
} else {
|
||||
debug!("The interrupt bit is no longer pending.");
|
||||
}
|
||||
self.unmask_interrupts();
|
||||
return;
|
||||
}
|
||||
|
||||
self.handle_requests();
|
||||
self.acknowledge(event_trb.clone());
|
||||
|
||||
match event_trb.trb_type() {
|
||||
_ if event_trb.trb_type() == TrbType::PortStatusChange as u8 => {
|
||||
trace!("Received a port status change!");
|
||||
self.handle_port_status_change(event_trb.clone())
|
||||
} //TODO Handle the other unprompted events
|
||||
_ => {
|
||||
trace!("Received a non-status trb");
|
||||
self.acknowledge(event_trb.clone());
|
||||
}
|
||||
}
|
||||
|
||||
event_trb.reserved(false);
|
||||
|
||||
self.update_erdp(&*event_ring);
|
||||
self.hci.event_handler_finished();
|
||||
|
||||
event_trb_index = event_ring.ring.next_index();
|
||||
}
|
||||
trace!("Exited event loop!");
|
||||
}
|
||||
trace!("IRQ Reactor has finished handling the interrupt");
|
||||
}
|
||||
|
||||
/// Handles device attach/detach events as indicated by a PortStatusChange
|
||||
fn handle_port_status_change(&mut self, trb: Trb) {
|
||||
if let Some(port_num) = trb.port_status_change_port_id() {
|
||||
trace!("Received Port Status Change Request on port {}", port_num);
|
||||
self.device_enumerator_sender
|
||||
.send(DeviceEnumerationRequest {
|
||||
port_number: port_num,
|
||||
})
|
||||
.expect(
|
||||
format!(
|
||||
"Failed to transmit device numeration request on port {}",
|
||||
port_num
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
{
|
||||
let mut ports = self.hci.ports.lock().unwrap();
|
||||
let port = &mut ports[(port_num - 1) as usize];
|
||||
port.portsc.writef(PortFlags::PORT_CSC.bits(), true);
|
||||
}
|
||||
} else {
|
||||
warn!(
|
||||
"Received a TRB of type {}, which was unexpected",
|
||||
trb.trb_type()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn update_erdp(&self, event_ring: &EventRing) {
|
||||
let dequeue_pointer_and_dcs = event_ring.erdp();
|
||||
let dequeue_pointer = dequeue_pointer_and_dcs & 0xFFFF_FFFF_FFFF_FFFE;
|
||||
@@ -254,7 +358,7 @@ impl IrqReactor {
|
||||
}
|
||||
fn handle_requests(&mut self) {
|
||||
self.states.extend(
|
||||
self.receiver
|
||||
self.irq_receiver
|
||||
.try_iter()
|
||||
.inspect(|req| trace!("Received request: {:X?}", req)),
|
||||
);
|
||||
@@ -448,6 +552,7 @@ impl EventDoorbell {
|
||||
pub fn ring(self) {
|
||||
trace!("Ring doorbell {} with data {}", self.index, self.data);
|
||||
self.dbs.lock().unwrap()[self.index].write(self.data);
|
||||
trace!("Doorbell was rung.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,7 +570,7 @@ impl Future for EventTrbFuture {
|
||||
|
||||
fn poll(self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll<Self::Output> {
|
||||
let this = self.get_mut();
|
||||
|
||||
trace!("Start poll!");
|
||||
let message = match this {
|
||||
&mut Self::Pending {
|
||||
ref state,
|
||||
@@ -490,12 +595,12 @@ impl Future for EventTrbFuture {
|
||||
if let Some(doorbell) = doorbell_opt.take() {
|
||||
doorbell.ring();
|
||||
}
|
||||
|
||||
return task::Poll::Pending;
|
||||
}
|
||||
},
|
||||
&mut Self::Finished => panic!("Polling finished EventTrbFuture again."),
|
||||
};
|
||||
trace!("finished!");
|
||||
*this = Self::Finished;
|
||||
task::Poll::Ready(message)
|
||||
}
|
||||
@@ -571,6 +676,10 @@ impl Xhci {
|
||||
trb: &Trb,
|
||||
doorbell: EventDoorbell,
|
||||
) -> impl Future<Output = NextEventTrb> + Send + Sync + 'static {
|
||||
trace!(
|
||||
"Sending command at phys_ptr {:X}",
|
||||
command_ring.trb_phys_ptr(self.cap.ac64(), trb)
|
||||
);
|
||||
if !trb.is_command_trb() {
|
||||
panic!("Invalid TRB type given to next_command_completion_event_trb(): {} (TRB {:?}. Expected command TRB.", trb.trb_type(), trb)
|
||||
}
|
||||
|
||||
+329
-145
@@ -18,15 +18,15 @@ use std::ptr::NonNull;
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize};
|
||||
use std::sync::{Arc, Mutex, MutexGuard, Weak};
|
||||
|
||||
use std::time::Duration;
|
||||
use std::{mem, process, slice, sync::atomic, task, thread};
|
||||
|
||||
use common::io::Io;
|
||||
use syscall::error::{Error, Result, EBADF, EBADMSG, EIO, ENOENT};
|
||||
use syscall::PAGE_SIZE;
|
||||
use syscall::{EAGAIN, PAGE_SIZE};
|
||||
|
||||
use chashmap::CHashMap;
|
||||
use common::dma::Dma;
|
||||
use common::{dma::Dma, io::Io};
|
||||
use crossbeam_channel::{Receiver, Sender};
|
||||
use futures::AsyncReadExt;
|
||||
use log::{debug, error, info, trace, warn};
|
||||
use serde::Deserialize;
|
||||
|
||||
@@ -37,6 +37,7 @@ use pcid_interface::{PciFeature, PciFunctionHandle};
|
||||
|
||||
mod capability;
|
||||
mod context;
|
||||
mod device_enumerator;
|
||||
mod doorbell;
|
||||
mod event;
|
||||
mod extended;
|
||||
@@ -104,6 +105,10 @@ impl Xhci {
|
||||
index: u8,
|
||||
desc: &mut Dma<T>,
|
||||
) -> Result<()> {
|
||||
if self.interrupt_is_pending(0) {
|
||||
warn!("EHB is already set!");
|
||||
self.force_clear_interrupt(0);
|
||||
}
|
||||
let len = mem::size_of::<T>();
|
||||
log::debug!(
|
||||
"get_desc_raw port {} slot {} kind {:?} index {} len {}",
|
||||
@@ -154,13 +159,14 @@ impl Xhci {
|
||||
)
|
||||
};
|
||||
|
||||
debug!("Waiting for the next transfer event TRB...");
|
||||
let trbs = future.await;
|
||||
let event_trb = trbs.event_trb;
|
||||
let status_trb = trbs.src_trb.unwrap();
|
||||
|
||||
trace!("Handling the transfer event TRB!");
|
||||
self::scheme::handle_transfer_event_trb("GET_DESC", &event_trb, &status_trb)?;
|
||||
|
||||
self.event_handler_finished();
|
||||
//self.event_handler_finished();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -265,8 +271,7 @@ pub struct Xhci {
|
||||
handles: CHashMap<usize, scheme::Handle>,
|
||||
next_handle: AtomicUsize,
|
||||
port_states: CHashMap<usize, PortState>,
|
||||
|
||||
drivers: CHashMap<usize, process::Child>,
|
||||
drivers: CHashMap<usize, Mutex<process::Child>>,
|
||||
scheme_name: String,
|
||||
|
||||
interrupt_method: InterruptMethod,
|
||||
@@ -279,6 +284,9 @@ pub struct Xhci {
|
||||
// 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>,
|
||||
device_enumerator: Mutex<Option<thread::JoinHandle<()>>>,
|
||||
device_enumerator_sender: Sender<DeviceEnumerationRequest>,
|
||||
device_enumerator_receiver: Receiver<DeviceEnumerationRequest>,
|
||||
}
|
||||
|
||||
unsafe impl Send for Xhci {}
|
||||
@@ -401,6 +409,8 @@ impl Xhci {
|
||||
|
||||
let (irq_reactor_sender, irq_reactor_receiver) = crossbeam_channel::unbounded();
|
||||
|
||||
let (device_enumerator_sender, device_enumerator_receiver) = crossbeam_channel::unbounded();
|
||||
|
||||
let mut xhci = Self {
|
||||
base: address as *const u8,
|
||||
|
||||
@@ -419,7 +429,6 @@ impl Xhci {
|
||||
handles: CHashMap::new(),
|
||||
next_handle: AtomicUsize::new(0),
|
||||
port_states: CHashMap::new(),
|
||||
|
||||
drivers: CHashMap::new(),
|
||||
scheme_name,
|
||||
|
||||
@@ -429,6 +438,9 @@ impl Xhci {
|
||||
irq_reactor: Mutex::new(None),
|
||||
irq_reactor_sender,
|
||||
irq_reactor_receiver,
|
||||
device_enumerator: Mutex::new(None),
|
||||
device_enumerator_sender,
|
||||
device_enumerator_receiver,
|
||||
};
|
||||
|
||||
xhci.init(max_slots)?;
|
||||
@@ -528,28 +540,109 @@ impl Xhci {
|
||||
|
||||
self.op.get_mut().unwrap().set_cie(self.cap.cic());
|
||||
|
||||
// Reset ports
|
||||
{
|
||||
let mut ports = self.ports.lock().unwrap();
|
||||
for (i, port) in ports.iter_mut().enumerate() {
|
||||
//TODO: only reset if USB 2.0?
|
||||
debug!("XHCI Port {} reset", i);
|
||||
self.print_port_capabilities();
|
||||
|
||||
let instant = std::time::Instant::now();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
port.portsc.writef(port::PortFlags::PORT_PR.bits(), true);
|
||||
while port.portsc.readf(port::PortFlags::PORT_PR.bits()) {
|
||||
//while ! port.flags().contains(port::PortFlags::PORT_PRC) {
|
||||
if instant.elapsed().as_secs() >= 1 {
|
||||
warn!("timeout");
|
||||
break;
|
||||
}
|
||||
std::thread::yield_now();
|
||||
pub fn get_pls(&self, port_num: usize) -> u32 {
|
||||
let mut ports = self.ports.lock().unwrap();
|
||||
let port = ports.get_mut(port_num).unwrap();
|
||||
let state = port.portsc.read();
|
||||
(state >> 5) & 4
|
||||
}
|
||||
|
||||
pub fn poll(&self) {
|
||||
debug!("Polling Initial Devices!");
|
||||
|
||||
let len = self.ports.lock().unwrap().len();
|
||||
|
||||
for index in 0..len {
|
||||
//Get the CCS and CSC flags
|
||||
let (ccs, csc, flags) = {
|
||||
let mut ports = self.ports.lock().unwrap();
|
||||
let port = &mut ports[index];
|
||||
let ccs = port.portsc.readf(PortFlags::PORT_CCS.bits());
|
||||
let csc = port.portsc.readf(PortFlags::PORT_CSC.bits());
|
||||
|
||||
(ccs, csc, port.flags())
|
||||
};
|
||||
|
||||
debug!("Port {} has flags {:?}", index + 1, flags);
|
||||
|
||||
match (ccs, csc) {
|
||||
(false, false) => { // Nothing is connected, and there was no port status change
|
||||
//Do nothing
|
||||
}
|
||||
_ => {
|
||||
//Either something is connected, or nothing is connected and a port status change was asserted.
|
||||
self.device_enumerator_sender
|
||||
.send(DeviceEnumerationRequest {
|
||||
port_number: (index + 1) as u8,
|
||||
})
|
||||
.expect("Failed to generate the port enumeration request!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
pub fn print_port_capabilities(&self) {
|
||||
let len;
|
||||
{
|
||||
let mut ports = self.ports.lock().unwrap();
|
||||
len = ports.len();
|
||||
}
|
||||
|
||||
for port in 0..len {
|
||||
let state = self.get_pls(port);
|
||||
let mut flags;
|
||||
{
|
||||
let mut ports = self.ports.lock().unwrap();
|
||||
|
||||
flags = ports[port].flags();
|
||||
}
|
||||
|
||||
match self.supported_protocol(port as u8) {
|
||||
None => {
|
||||
warn!("No detected supported protocol for port {}", port);
|
||||
}
|
||||
Some(protocol) => {
|
||||
info!(
|
||||
"Port {} is a USB {}.{} port with slot type {} and in current state {}: {:?}",
|
||||
port + 1,
|
||||
protocol.rev_major(),
|
||||
protocol.rev_minor(),
|
||||
protocol.proto_slot_ty(),
|
||||
state,
|
||||
flags
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
pub fn reset_port(&self, port_num: usize) {
|
||||
debug!("XHCI Port {} reset", port_num);
|
||||
|
||||
//TODO handle the second unwrap
|
||||
let mut ports = self.ports.lock().unwrap();
|
||||
let port = ports.get_mut(port_num).unwrap();
|
||||
let instant = std::time::Instant::now();
|
||||
|
||||
let state = port.portsc.read();
|
||||
let pls = (state >> 5) & 4;
|
||||
|
||||
debug!("Port Link State: {}", pls);
|
||||
|
||||
port.portsc.writef(port::PortFlags::PORT_PR.bits(), true);
|
||||
debug!("Flags after setting port reset: {:?}", port.flags());
|
||||
while !port.portsc.readf(port::PortFlags::PORT_PRC.bits()) {
|
||||
debug!("Ran at least once!");
|
||||
if instant.elapsed().as_secs() >= 1 {
|
||||
warn!("timeout");
|
||||
break;
|
||||
}
|
||||
//std::thread::yield_now();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_scratchpads(&mut self) -> Result<()> {
|
||||
@@ -570,6 +663,27 @@ impl Xhci {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn force_clear_interrupt(&self, index: usize) {
|
||||
{
|
||||
// If ERDP EHB bit is set, clear it before sending command
|
||||
//TODO: find out why this bit is set earlier!
|
||||
let mut run = self.run.lock().unwrap();
|
||||
let mut int = &mut run.ints[index];
|
||||
|
||||
if int.erdp_low.readf(1 << 3) {
|
||||
int.erdp_low.writef(1 << 3, true);
|
||||
} else {
|
||||
warn!("Attempted to clear the interrupt bit when no interrupt was pending");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn interrupt_is_pending(&self, index: usize) -> bool {
|
||||
let mut run = self.run.lock().unwrap();
|
||||
let mut int = &mut run.ints[index];
|
||||
int.erdp_low.readf(1 << 3)
|
||||
}
|
||||
|
||||
pub async fn enable_port_slot(&self, slot_ty: u8) -> Result<u8> {
|
||||
assert_eq!(slot_ty & 0x1F, slot_ty);
|
||||
|
||||
@@ -577,8 +691,9 @@ impl Xhci {
|
||||
.execute_command(|cmd, cycle| cmd.enable_slot(slot_ty, cycle))
|
||||
.await;
|
||||
|
||||
trace!("Slot is enabled!");
|
||||
self::scheme::handle_event_trb("ENABLE_SLOT", &event_trb, &command_trb)?;
|
||||
self.event_handler_finished();
|
||||
//self.event_handler_finished();
|
||||
|
||||
Ok(event_trb.event_slot())
|
||||
}
|
||||
@@ -588,7 +703,7 @@ impl Xhci {
|
||||
.await;
|
||||
|
||||
self::scheme::handle_event_trb("DISABLE_SLOT", &event_trb, &command_trb)?;
|
||||
self.event_handler_finished();
|
||||
//self.event_handler_finished();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -611,121 +726,171 @@ impl Xhci {
|
||||
Self::alloc_dma_zeroed_unsized_raw(self.cap.ac64(), count)
|
||||
}
|
||||
|
||||
pub async fn probe(&self) -> Result<()> {
|
||||
debug!(
|
||||
"XHCI capabilities: {:?}",
|
||||
self.capabilities_iter().collect::<Vec<_>>()
|
||||
pub async fn attach_device(&self, port_number: u8) -> syscall::Result<()> {
|
||||
let i = port_number as usize;
|
||||
|
||||
if self.port_states.contains_key(&i) {
|
||||
return Err(syscall::Error::new(EAGAIN));
|
||||
}
|
||||
|
||||
let (data, state, speed, flags) = {
|
||||
let port = &self.ports.lock().unwrap()[i];
|
||||
(port.read(), port.state(), port.speed(), port.flags())
|
||||
};
|
||||
|
||||
info!(
|
||||
"XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}",
|
||||
i, data, state, speed, flags
|
||||
);
|
||||
|
||||
let port_count = { self.ports.lock().unwrap().len() };
|
||||
|
||||
for i in 0..port_count {
|
||||
let (data, state, speed, flags) = {
|
||||
let port = &self.ports.lock().unwrap()[i];
|
||||
(port.read(), port.state(), port.speed(), port.flags())
|
||||
if flags.contains(port::PortFlags::PORT_CCS) {
|
||||
let slot_ty = match self.supported_protocol(i as u8) {
|
||||
Some(protocol) => protocol.proto_slot_ty(),
|
||||
None => {
|
||||
warn!("Failed to find supported protocol information for port");
|
||||
0
|
||||
}
|
||||
};
|
||||
info!(
|
||||
"XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}",
|
||||
i, data, state, speed, flags
|
||||
);
|
||||
|
||||
if flags.contains(port::PortFlags::PORT_CCS) {
|
||||
let slot_ty = match self.supported_protocol(i as u8) {
|
||||
Some(protocol) => protocol.proto_slot_ty(),
|
||||
None => {
|
||||
warn!("Failed to find supported protocol information for port");
|
||||
0
|
||||
}
|
||||
};
|
||||
|
||||
debug!("Slot type: {}", slot_ty);
|
||||
debug!("Enabling slot.");
|
||||
let slot = match self.enable_port_slot(slot_ty).await {
|
||||
Ok(ok) => ok,
|
||||
Err(err) => {
|
||||
error!("Failed to enable slot for port {}: {}", i, err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
info!("Enabled port {}, which the xHC mapped to {}", i, slot);
|
||||
|
||||
let mut input = unsafe { self.alloc_dma_zeroed::<InputContext>()? };
|
||||
let mut ring = match self
|
||||
.address_device(&mut input, i, slot_ty, slot, speed)
|
||||
.await
|
||||
{
|
||||
Ok(ok) => ok,
|
||||
Err(err) => {
|
||||
error!("Failed to address device for port {}: {}", i, err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
debug!("Addressed device");
|
||||
|
||||
// TODO: Should the descriptors be cached in PortState, or refetched?
|
||||
|
||||
let mut port_state = PortState {
|
||||
slot,
|
||||
input_context: Mutex::new(input),
|
||||
dev_desc: None,
|
||||
cfg_idx: None,
|
||||
endpoint_states: std::iter::once((
|
||||
0,
|
||||
EndpointState {
|
||||
transfer: RingOrStreams::Ring(ring),
|
||||
driver_if_state: EndpIfState::Init,
|
||||
},
|
||||
))
|
||||
.collect::<BTreeMap<_, _>>(),
|
||||
};
|
||||
self.port_states.insert(i, port_state);
|
||||
|
||||
// Ensure correct packet size is used
|
||||
let dev_desc_8_byte = self.fetch_dev_desc_8_byte(i, slot).await?;
|
||||
{
|
||||
let mut port_state = self.port_states.get_mut(&i).unwrap();
|
||||
|
||||
let mut input = port_state.input_context.lock().unwrap();
|
||||
|
||||
self.update_max_packet_size(&mut *input, slot, dev_desc_8_byte)
|
||||
.await?;
|
||||
debug!("Slot type: {}", slot_ty);
|
||||
debug!("Enabling slot.");
|
||||
let slot = match self.enable_port_slot(slot_ty).await {
|
||||
Ok(ok) => ok,
|
||||
Err(err) => {
|
||||
error!("Failed to enable slot for port {}: {}", i, err);
|
||||
return Err(err);
|
||||
}
|
||||
};
|
||||
|
||||
let dev_desc = self.get_desc(i, slot).await?;
|
||||
self.port_states.get_mut(&i).unwrap().dev_desc = Some(dev_desc);
|
||||
info!("Enabled port {}, which the xHC mapped to {}", i, slot);
|
||||
|
||||
{
|
||||
let mut port_state = self.port_states.get_mut(&i).unwrap();
|
||||
let mut input = unsafe { self.alloc_dma_zeroed::<InputContext>()? };
|
||||
|
||||
let mut input = port_state.input_context.lock().unwrap();
|
||||
let dev_desc = port_state.dev_desc.as_ref().unwrap();
|
||||
|
||||
self.update_default_control_pipe(&mut *input, slot, dev_desc)
|
||||
.await?;
|
||||
info!("Attempting to address the device");
|
||||
let mut ring = match self
|
||||
.address_device(&mut input, i, slot_ty, slot, speed)
|
||||
.await
|
||||
{
|
||||
Ok(device_ring) => device_ring,
|
||||
Err(err) => {
|
||||
error!("Failed to spawn driver for port {}: `{}`", i, err);
|
||||
return Err(err);
|
||||
}
|
||||
};
|
||||
|
||||
match self.spawn_drivers(i) {
|
||||
Ok(()) => (),
|
||||
Err(err) => error!("Failed to spawn driver for port {}: `{}`", i, err),
|
||||
debug!("Addressed device");
|
||||
|
||||
// TODO: Should the descriptors be cached in PortState, or refetched?
|
||||
|
||||
let mut port_state = PortState {
|
||||
slot,
|
||||
input_context: Mutex::new(input),
|
||||
dev_desc: None,
|
||||
cfg_idx: None,
|
||||
endpoint_states: std::iter::once((
|
||||
0,
|
||||
EndpointState {
|
||||
transfer: RingOrStreams::Ring(ring),
|
||||
driver_if_state: EndpIfState::Init,
|
||||
},
|
||||
))
|
||||
.collect::<BTreeMap<_, _>>(),
|
||||
};
|
||||
self.port_states.insert(i, port_state);
|
||||
debug!("Got port states!");
|
||||
|
||||
// Ensure correct packet size is used
|
||||
let dev_desc_8_byte = self.fetch_dev_desc_8_byte(i, slot).await?;
|
||||
{
|
||||
let mut port_state = self.port_states.get_mut(&i).unwrap();
|
||||
|
||||
let mut input = port_state.input_context.lock().unwrap();
|
||||
|
||||
self.update_max_packet_size(&mut *input, slot, dev_desc_8_byte)
|
||||
.await?;
|
||||
}
|
||||
|
||||
debug!("Got the 8 byte dev descriptor");
|
||||
|
||||
let dev_desc = self.get_desc(i, slot).await?;
|
||||
debug!("Got the full device descriptor!");
|
||||
self.port_states.get_mut(&i).unwrap().dev_desc = Some(dev_desc);
|
||||
|
||||
debug!("Got the port states again!");
|
||||
{
|
||||
let mut port_state = self.port_states.get_mut(&i).unwrap();
|
||||
|
||||
let mut input = port_state.input_context.lock().unwrap();
|
||||
debug!("Got the input context!");
|
||||
let dev_desc = port_state.dev_desc.as_ref().unwrap();
|
||||
|
||||
self.update_default_control_pipe(&mut *input, slot, dev_desc)
|
||||
.await?;
|
||||
}
|
||||
|
||||
debug!("Updated the default control pipe");
|
||||
|
||||
match self.spawn_drivers(i) {
|
||||
Ok(()) => (),
|
||||
Err(err) => {
|
||||
error!("Failed to spawn driver for port {}: `{}`", i, err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warn!("Attempted to attach a device that didnt have CCS=1");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn detach_device(&self, port_number: usize) -> Result<()> {
|
||||
let port_state = self.port_states.get(&port_number);
|
||||
let mut driver_process = self.drivers.get(&port_number);
|
||||
|
||||
if let Some(state) = port_state {
|
||||
let result = self.disable_port_slot(state.slot).await;
|
||||
self.port_states.remove(&port_number);
|
||||
|
||||
//TODO handle killing the child process properly. I'm not sure how
|
||||
//to get a mutable reference that I can kill.
|
||||
|
||||
if let Some(mutex) = driver_process {
|
||||
let mut child = mutex.lock().unwrap();
|
||||
|
||||
match child.kill() {
|
||||
Ok(_) => {
|
||||
info!("Killing {:?}", child)
|
||||
}
|
||||
Err(_) => {
|
||||
warn!("Failed to kill the child process!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.drivers.remove(&port_number);
|
||||
|
||||
result
|
||||
} else {
|
||||
warn!(
|
||||
"Attempted to detach from port {}, which wasn't previously attached.",
|
||||
port_number
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn update_max_packet_size(
|
||||
&self,
|
||||
input_context: &mut Dma<InputContext>,
|
||||
slot_id: u8,
|
||||
dev_desc: usb::DeviceDescriptor8Byte,
|
||||
) -> Result<()> {
|
||||
let new_max_packet_size = if dev_desc.major_usb_vers() == 2 {
|
||||
u32::from(dev_desc.packet_size)
|
||||
} else {
|
||||
1u32 << dev_desc.packet_size
|
||||
};
|
||||
let new_max_packet_size = u32::from(dev_desc.packet_size); //if dev_desc.major_usb_vers() == 2 {
|
||||
//u32::from(dev_desc.packet_size)
|
||||
//} else {
|
||||
// info!("USB 2 device detected. Packet size is: {}", dev_desc.packet_size);
|
||||
// 1u32 << dev_desc.packet_size
|
||||
//};
|
||||
let endp_ctx = &mut input_context.device.endpoints[0];
|
||||
let mut b = endp_ctx.b.read();
|
||||
b &= 0x0000_FFFF;
|
||||
@@ -739,7 +904,7 @@ impl Xhci {
|
||||
.await;
|
||||
|
||||
self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb)?;
|
||||
self.event_handler_finished();
|
||||
//self.event_handler_finished();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -750,14 +915,15 @@ impl Xhci {
|
||||
slot_id: u8,
|
||||
dev_desc: &DevDesc,
|
||||
) -> Result<()> {
|
||||
debug!("Updating default control pipe!");
|
||||
input_context.add_context.write(1 << 1);
|
||||
input_context.drop_context.write(0);
|
||||
|
||||
let new_max_packet_size = if dev_desc.major_version() == 2 {
|
||||
u32::from(dev_desc.packet_size)
|
||||
} else {
|
||||
1u32 << dev_desc.packet_size
|
||||
};
|
||||
let new_max_packet_size = u32::from(dev_desc.packet_size); //if dev_desc.major_version() == 2 {
|
||||
// u32::from(dev_desc.packet_size)
|
||||
//} else {
|
||||
// 1u32 << dev_desc.packet_size
|
||||
//};
|
||||
let endp_ctx = &mut input_context.device.endpoints[0];
|
||||
let mut b = endp_ctx.b.read();
|
||||
b &= 0x0000_FFFF;
|
||||
@@ -769,9 +935,10 @@ impl Xhci {
|
||||
trb.evaluate_context(slot_id, input_context.physical(), false, cycle)
|
||||
})
|
||||
.await;
|
||||
debug!("Completed the command to update the default control pipe");
|
||||
|
||||
self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb)?;
|
||||
self.event_handler_finished();
|
||||
//self.event_handler_finished();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -878,10 +1045,10 @@ impl Xhci {
|
||||
i,
|
||||
event_trb.completion_code()
|
||||
);
|
||||
self.event_handler_finished();
|
||||
//self.event_handler_finished();
|
||||
return Err(Error::new(EIO));
|
||||
}
|
||||
self.event_handler_finished();
|
||||
//self.event_handler_finished();
|
||||
|
||||
Ok(ring)
|
||||
}
|
||||
@@ -952,6 +1119,7 @@ impl Xhci {
|
||||
// suitable here.
|
||||
|
||||
let ps = self.port_states.get(&port).unwrap();
|
||||
trace!("Spawning driver on port: {}", port + 1);
|
||||
|
||||
//TODO: support choosing config?
|
||||
let config_desc = &ps
|
||||
@@ -968,6 +1136,7 @@ impl Xhci {
|
||||
Error::new(EBADF)
|
||||
})?;
|
||||
|
||||
trace!("Got config and device descriptors on port {}", port + 1);
|
||||
let drivers_usercfg: &DriversConfig = &DRIVERS_CONFIG;
|
||||
|
||||
for ifdesc in config_desc.interface_descs.iter() {
|
||||
@@ -986,20 +1155,22 @@ impl Xhci {
|
||||
} else {
|
||||
"/usr/lib/drivers/".to_owned() + command
|
||||
};
|
||||
let process = process::Command::new(command)
|
||||
.args(
|
||||
args.into_iter()
|
||||
.map(|arg| {
|
||||
arg.replace("$SCHEME", &self.scheme_name)
|
||||
.replace("$PORT", &format!("{}", port))
|
||||
.replace("$IF_NUM", &format!("{}", ifdesc.number))
|
||||
.replace("$IF_PROTO", &format!("{}", ifdesc.protocol))
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.stdin(process::Stdio::null())
|
||||
.spawn()
|
||||
.or(Err(Error::new(ENOENT)))?;
|
||||
let process = Mutex::new(
|
||||
process::Command::new(command)
|
||||
.args(
|
||||
args.into_iter()
|
||||
.map(|arg| {
|
||||
arg.replace("$SCHEME", &self.scheme_name)
|
||||
.replace("$PORT", &format!("{}", port))
|
||||
.replace("$IF_NUM", &format!("{}", ifdesc.number))
|
||||
.replace("$IF_PROTO", &format!("{}", ifdesc.protocol))
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.stdin(process::Stdio::null())
|
||||
.spawn()
|
||||
.or(Err(Error::new(ENOENT)))?,
|
||||
);
|
||||
self.drivers.insert(port, process);
|
||||
} else {
|
||||
warn!(
|
||||
@@ -1030,7 +1201,8 @@ impl Xhci {
|
||||
}
|
||||
pub fn supported_protocol(&self, port: u8) -> Option<&'static SupportedProtoCap> {
|
||||
self.supported_protocols_iter()
|
||||
.find(|supp_proto| supp_proto.compat_port_range().contains(&port))
|
||||
.find(|supp_proto| supp_proto.compat_port_range().contains(&(port + 1)))
|
||||
//Increment by 1, because USB ports index themselves by 1.
|
||||
}
|
||||
pub fn supported_protocol_speeds(
|
||||
&self,
|
||||
@@ -1123,14 +1295,24 @@ impl Xhci {
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
debug!("About to start IRQ reactor");
|
||||
|
||||
*hci.irq_reactor.lock().unwrap() = Some(thread::spawn(move || {
|
||||
debug!("Started IRQ reactor thread");
|
||||
IrqReactor::new(hci_clone, receiver, irq_file).run()
|
||||
IrqReactor::new(hci_clone, irq_file).run()
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn start_device_enumerator(hci: &Arc<Xhci>) {
|
||||
let hci_clone = Arc::clone(&hci);
|
||||
|
||||
debug!("About to start Device Enumerator");
|
||||
|
||||
*hci.device_enumerator.lock().unwrap() = Some(thread::spawn(move || {
|
||||
debug!("Started Device Enumerator");
|
||||
DeviceEnumerator::new(hci_clone).run();
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -1151,6 +1333,8 @@ struct DriversConfig {
|
||||
drivers: Vec<DriverConfig>,
|
||||
}
|
||||
|
||||
use crate::xhci::device_enumerator::{DeviceEnumerationRequest, DeviceEnumerator};
|
||||
use crate::xhci::port::PortFlags;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
lazy_static! {
|
||||
|
||||
@@ -6,6 +6,7 @@ bitflags! {
|
||||
const PORT_PED = 1 << 1;
|
||||
const PORT_OCA = 1 << 3;
|
||||
const PORT_PR = 1 << 4;
|
||||
const PORT_PLS = 1 << 5;
|
||||
const PORT_PP = 1 << 9;
|
||||
const PORT_PIC_AMB = 1 << 14;
|
||||
const PORT_PIC_GRN = 1 << 15;
|
||||
|
||||
+19
-16
@@ -555,20 +555,18 @@ impl Xhci {
|
||||
/// # Locking
|
||||
/// This function will lock `Xhci::cmd` and `Xhci::dbs`.
|
||||
pub async fn execute_command<F: FnOnce(&mut Trb, bool)>(&self, f: F) -> (Trb, Trb) {
|
||||
{
|
||||
// If ERDP EHB bit is set, clear it before sending command
|
||||
//TODO: find out why this bit is set earlier!
|
||||
let mut run = self.run.lock().unwrap();
|
||||
let mut int = &mut run.ints[0];
|
||||
if int.erdp_low.readf(1 << 3) {
|
||||
int.erdp_low.writef(1 << 3, true);
|
||||
}
|
||||
//TODO: find out why this bit is set earlier!
|
||||
if self.interrupt_is_pending(0) {
|
||||
warn!("The EHB bit is already set!");
|
||||
//self.force_clear_interrupt(0);
|
||||
}
|
||||
|
||||
let next_event = {
|
||||
let mut command_ring = self.cmd.lock().unwrap();
|
||||
let (cmd_index, cycle) = (command_ring.next_index(), command_ring.cycle);
|
||||
|
||||
info!("Sending command with cycle bit {}", cycle as u8);
|
||||
|
||||
{
|
||||
let command_trb = &mut command_ring.trbs[cmd_index];
|
||||
f(command_trb, cycle);
|
||||
@@ -657,7 +655,7 @@ impl Xhci {
|
||||
|
||||
handle_transfer_event_trb("CONTROL_TRANSFER", &event_trb, &status_trb)?;
|
||||
|
||||
self.event_handler_finished();
|
||||
//self.event_handler_finished();
|
||||
|
||||
Ok(event_trb)
|
||||
}
|
||||
@@ -824,7 +822,7 @@ impl Xhci {
|
||||
trb.reset_endpoint(slot, endp_num_xhc, tsp, cycle);
|
||||
})
|
||||
.await;
|
||||
self.event_handler_finished();
|
||||
//self.event_handler_finished();
|
||||
|
||||
handle_event_trb("RESET_ENDPOINT", &event_trb, &command_trb)
|
||||
}
|
||||
@@ -913,7 +911,11 @@ impl Xhci {
|
||||
self.port_states.get_mut(&port).ok_or(Error::new(EBADF))
|
||||
}
|
||||
|
||||
async fn configure_endpoints_once(&self, port: usize, req: &ConfigureEndpointsReq) -> Result<()> {
|
||||
async fn configure_endpoints_once(
|
||||
&self,
|
||||
port: usize,
|
||||
req: &ConfigureEndpointsReq,
|
||||
) -> Result<()> {
|
||||
let (endp_desc_count, new_context_entries, configuration_value) = {
|
||||
let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?;
|
||||
|
||||
@@ -1148,7 +1150,7 @@ impl Xhci {
|
||||
})
|
||||
.await;
|
||||
|
||||
self.event_handler_finished();
|
||||
//self.event_handler_finished();
|
||||
|
||||
handle_event_trb("CONFIGURE_ENDPOINT", &event_trb, &command_trb)?;
|
||||
}
|
||||
@@ -1177,7 +1179,7 @@ impl Xhci {
|
||||
port_state.cfg_idx == Some(req.config_desc)
|
||||
};
|
||||
|
||||
if ! already_configured {
|
||||
if !already_configured {
|
||||
self.configure_endpoints_once(port, &req).await?;
|
||||
}
|
||||
|
||||
@@ -1381,7 +1383,7 @@ impl Xhci {
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
self.event_handler_finished();
|
||||
//self.event_handler_finished();
|
||||
|
||||
let bytes_transferred = dma_buf
|
||||
.as_ref()
|
||||
@@ -1443,6 +1445,7 @@ impl Xhci {
|
||||
let mut config_descs = SmallVec::new();
|
||||
|
||||
for index in 0..raw_dd.configurations {
|
||||
debug!("Fetching the config descriptor at index {}", index);
|
||||
let (desc, data) = self.fetch_config_desc(port_id, slot, index).await?;
|
||||
log::debug!(
|
||||
"port {} slot {} config {} desc {:X?}",
|
||||
@@ -2198,7 +2201,7 @@ impl Scheme for Xhci {
|
||||
EndpointHandleTy::Data => {
|
||||
block_on(self.on_write_endp_data(port_num, endp_num, buf))
|
||||
}
|
||||
EndpointHandleTy::Root(_, _) => Err(Error::new(EBADF)),
|
||||
EndpointHandleTy::Root(_, _) => return Err(Error::new(EBADF)),
|
||||
},
|
||||
&mut Handle::PortReq(port_num, ref mut st) => {
|
||||
let state = std::mem::replace(st, PortReqState::Tmp);
|
||||
@@ -2395,7 +2398,7 @@ impl Xhci {
|
||||
)
|
||||
})
|
||||
.await;
|
||||
self.event_handler_finished();
|
||||
//self.event_handler_finished();
|
||||
|
||||
handle_event_trb("SET_TR_DEQUEUE_PTR", &event_trb, &command_trb)
|
||||
}
|
||||
|
||||
+21
-4
@@ -1,8 +1,9 @@
|
||||
use crate::usb;
|
||||
use common::io::{Io, Mmio};
|
||||
use std::{fmt, mem};
|
||||
|
||||
use super::context::StreamContextType;
|
||||
use crate::usb;
|
||||
use crate::xhci::trb::TrbType::PortStatusChange;
|
||||
use common::io::{Io, Mmio};
|
||||
use log::trace;
|
||||
use std::{fmt, mem};
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
@@ -196,6 +197,17 @@ impl Trb {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn port_status_change_port_id(&self) -> Option<u8> {
|
||||
debug_assert_eq!(self.trb_type(), TrbType::PortStatusChange as u8);
|
||||
|
||||
if self.has_completion_trb_pointer() {
|
||||
let data = self.read_data();
|
||||
Some(((data >> 24) & 0xFF) as u8)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn event_slot(&self) -> u8 {
|
||||
(self.control.read() >> 24) as u8
|
||||
}
|
||||
@@ -234,6 +246,7 @@ impl Trb {
|
||||
}
|
||||
|
||||
pub fn enable_slot(&mut self, slot_type: u8, cycle: bool) {
|
||||
trace!("Enabling slot with type {}", slot_type);
|
||||
self.set(
|
||||
0,
|
||||
0,
|
||||
@@ -381,6 +394,10 @@ impl Trb {
|
||||
);
|
||||
}
|
||||
|
||||
pub fn cycle(&self) -> bool {
|
||||
self.control.readf(0x01)
|
||||
}
|
||||
|
||||
pub fn status(
|
||||
&mut self,
|
||||
interrupter: u16,
|
||||
|
||||
Reference in New Issue
Block a user