Add a driver interface accessible to class drivers.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
use std::env;
|
||||
|
||||
pub mod protocol;
|
||||
|
||||
fn main() {
|
||||
let mut args = env::args().skip(1);
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
use super::Protocol;
|
||||
|
||||
pub const CBW_SIGNATURE: u32 = 0x43425355;
|
||||
|
||||
/// 0 means host to dev, 1 means dev to host
|
||||
pub const CBW_FLAGS_DIRECTION_BIT: u8 = 1 << CBW_FLAGS_DIRECTION_SHIFT;
|
||||
pub const CBW_FLAGS_DIRECTION_SHIFT: u8 = 7;
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct CommandBlockWrapper {
|
||||
pub signature: u32,
|
||||
pub tag: u32,
|
||||
pub data_transfer_len: u32,
|
||||
pub flags: u8, // upper nibble reserved
|
||||
pub lun: u8, // bits 7:5 reserved
|
||||
pub cb_len: u8,
|
||||
pub command_block: [u8; 16],
|
||||
}
|
||||
|
||||
pub const CSW_SIGNATURE: u32 = 0x53425355;
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum CswStatus {
|
||||
Passed = 0,
|
||||
Failed = 1,
|
||||
PhaseError = 2,
|
||||
// the rest are reserved
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct CommandStatusWrapper {
|
||||
pub signature: u32,
|
||||
pub tag: u32,
|
||||
pub data_residue: u32,
|
||||
pub status: u8,
|
||||
}
|
||||
|
||||
pub struct BulkOnlyTransport;
|
||||
|
||||
impl Protocol for BulkOnlyTransport {
|
||||
fn send_command_block(&mut self, cb: &[u8]) {
|
||||
todo!()
|
||||
}
|
||||
fn recv_command_block(&mut self, cb: &mut [u8]) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
pub trait Protocol {
|
||||
fn send_command_block(&mut self, cb: &[u8]);
|
||||
fn recv_command_block(&mut self, cb: &mut [u8]);
|
||||
}
|
||||
|
||||
/// Bulk-only transport
|
||||
pub mod bot;
|
||||
|
||||
/// Control-Bulk-Interface transpoint
|
||||
mod cbi {
|
||||
// TODO
|
||||
}
|
||||
@@ -3,6 +3,14 @@ name = "xhcid"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[[bin]]
|
||||
name = "xhcid"
|
||||
path = "src/main.rs"
|
||||
|
||||
[lib]
|
||||
name = "xhcid_interface"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1"
|
||||
plain = "0.2"
|
||||
|
||||
+1
-1
@@ -2,4 +2,4 @@
|
||||
name = "SCSI over USB"
|
||||
class = 8 # Mass Storage class
|
||||
subclass = 6 # SCSI transparent command set
|
||||
command = ["usbscsid", "$SCHEME", "$PORT", "$IF_PROTO"]
|
||||
command = ["/bin/usbscsid", "$SCHEME", "$PORT", "$IF_PROTO"]
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
pub extern crate serde;
|
||||
pub extern crate smallvec;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use smallvec::SmallVec;
|
||||
use syscall::{Error, Result, EINVAL};
|
||||
|
||||
pub use crate::usb::{EndpointTy, ENDP_ATTR_TY_MASK};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct ConfigureEndpointsReq {
|
||||
/// Index into the configuration descriptors of the device descriptor.
|
||||
pub config_desc: usize,
|
||||
// TODO: Support multiple alternate interfaces as well.
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct DevDesc {
|
||||
pub kind: u8,
|
||||
pub usb: u16,
|
||||
pub class: u8,
|
||||
pub sub_class: u8,
|
||||
pub protocol: u8,
|
||||
pub packet_size: u8,
|
||||
pub vendor: u16,
|
||||
pub product: u16,
|
||||
pub release: u16,
|
||||
pub manufacturer_str: Option<String>,
|
||||
pub product_str: Option<String>,
|
||||
pub serial_str: Option<String>,
|
||||
pub config_descs: SmallVec<[ConfDesc; 1]>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct ConfDesc {
|
||||
pub kind: u8,
|
||||
pub configuration_value: u8,
|
||||
pub configuration: Option<String>,
|
||||
pub attributes: u8,
|
||||
pub max_power: u8,
|
||||
pub interface_descs: SmallVec<[IfDesc; 1]>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub struct EndpDesc {
|
||||
pub kind: u8,
|
||||
pub address: u8,
|
||||
pub attributes: u8,
|
||||
pub max_packet_size: u16,
|
||||
pub interval: u8,
|
||||
pub ssc: Option<SuperSpeedCmp>,
|
||||
}
|
||||
pub enum EndpDirection {
|
||||
Out,
|
||||
In,
|
||||
Bidirectional,
|
||||
}
|
||||
|
||||
impl EndpDesc {
|
||||
pub fn ty(self) -> EndpointTy {
|
||||
match self.attributes & ENDP_ATTR_TY_MASK {
|
||||
0 => EndpointTy::Ctrl,
|
||||
1 => EndpointTy::Interrupt,
|
||||
2 => EndpointTy::Bulk,
|
||||
3 => EndpointTy::Isoch,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
pub fn is_control(&self) -> bool {
|
||||
self.ty() == EndpointTy::Ctrl
|
||||
}
|
||||
pub fn is_interrupt(&self) -> bool {
|
||||
self.ty() == EndpointTy::Interrupt
|
||||
}
|
||||
pub fn is_bulk(&self) -> bool {
|
||||
self.ty() == EndpointTy::Bulk
|
||||
}
|
||||
pub fn is_isoch(&self) -> bool {
|
||||
self.ty() == EndpointTy::Isoch
|
||||
}
|
||||
pub fn direction(&self) -> EndpDirection {
|
||||
if self.is_control() {
|
||||
return EndpDirection::Bidirectional;
|
||||
}
|
||||
if self.address & 0x80 != 0 {
|
||||
EndpDirection::In
|
||||
} else {
|
||||
EndpDirection::Out
|
||||
}
|
||||
}
|
||||
pub fn xhci_ep_type(&self) -> Result<u8> {
|
||||
Ok(match self.direction() {
|
||||
EndpDirection::Out if self.is_isoch() => 1,
|
||||
EndpDirection::Out if self.is_bulk() => 2,
|
||||
EndpDirection::Out if self.is_interrupt() => 3,
|
||||
EndpDirection::Bidirectional if self.is_control() => 4,
|
||||
EndpDirection::In if self.is_isoch() => 5,
|
||||
EndpDirection::In if self.is_bulk() => 6,
|
||||
EndpDirection::In if self.is_interrupt() => 7,
|
||||
_ => return Err(Error::new(EINVAL)),
|
||||
})
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct IfDesc {
|
||||
pub kind: u8,
|
||||
pub number: u8,
|
||||
pub alternate_setting: u8,
|
||||
pub class: u8,
|
||||
pub sub_class: u8,
|
||||
pub protocol: u8,
|
||||
pub interface_str: Option<String>,
|
||||
pub endpoints: SmallVec<[EndpDesc; 4]>,
|
||||
pub hid_descs: SmallVec<[HidDesc; 1]>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub struct SuperSpeedCmp {
|
||||
pub kind: u8,
|
||||
pub max_burst: u8,
|
||||
pub attributes: u8,
|
||||
pub bytes_per_interval: u16,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub struct HidDesc {
|
||||
pub kind: u8,
|
||||
pub hid_spec_release: u16,
|
||||
pub country: u8,
|
||||
pub desc_count: u8,
|
||||
pub desc_ty: u8,
|
||||
pub desc_len: u16,
|
||||
pub optional_desc_ty: u8,
|
||||
pub optional_desc_len: u16,
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
mod driver_interface;
|
||||
mod usb;
|
||||
|
||||
pub use driver_interface::*;
|
||||
+75
-53
@@ -6,18 +6,19 @@ extern crate syscall;
|
||||
|
||||
use event::{Event, EventQueue};
|
||||
use std::cell::RefCell;
|
||||
use std::{io, env};
|
||||
use std::fs::File;
|
||||
use std::io::{Result, Read, Write};
|
||||
use std::io::{Read, Result, Write};
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||
use std::sync::Arc;
|
||||
use std::{env, io};
|
||||
use syscall::data::Packet;
|
||||
use syscall::flag::{CloneFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE};
|
||||
use syscall::error::EWOULDBLOCK;
|
||||
use syscall::flag::{CloneFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE};
|
||||
use syscall::scheme::SchemeMut;
|
||||
|
||||
use crate::xhci::Xhci;
|
||||
|
||||
mod driver_interface;
|
||||
mod usb;
|
||||
mod xhci;
|
||||
|
||||
@@ -33,22 +34,38 @@ fn main() {
|
||||
let irq_str = args.next().expect("xhcid: no IRQ provided");
|
||||
let irq = irq_str.parse::<u8>().expect("xhcid: failed to parse irq");
|
||||
|
||||
print!("{}", format!(" + XHCI {} on: {:X} IRQ: {}\n", name, bar, irq));
|
||||
print!(
|
||||
"{}",
|
||||
format!(" + XHCI {} on: {:X} IRQ: {}\n", name, bar, irq)
|
||||
);
|
||||
|
||||
// Daemonize
|
||||
if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 {
|
||||
let socket_fd = syscall::open(format!(":usb/{}", name), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("xhcid: failed to create usb scheme");
|
||||
let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) }));
|
||||
let socket_fd = syscall::open(
|
||||
format!(":usb/{}", name),
|
||||
syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK,
|
||||
)
|
||||
.expect("xhcid: failed to create usb scheme");
|
||||
let socket = Arc::new(RefCell::new(unsafe {
|
||||
File::from_raw_fd(socket_fd as RawFd)
|
||||
}));
|
||||
|
||||
let mut irq_file = File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file");
|
||||
let mut irq_file =
|
||||
File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file");
|
||||
|
||||
let address = unsafe { syscall::physmap(bar, 65536, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("xhcid: failed to map address") };
|
||||
let address = unsafe {
|
||||
syscall::physmap(bar, 65536, PHYSMAP_WRITE | PHYSMAP_NO_CACHE)
|
||||
.expect("xhcid: failed to map address")
|
||||
};
|
||||
{
|
||||
let hci = Arc::new(RefCell::new(Xhci::new(name, address).expect("xhcid: failed to allocate device")));
|
||||
let hci = Arc::new(RefCell::new(
|
||||
Xhci::new(name, address).expect("xhcid: failed to allocate device"),
|
||||
));
|
||||
|
||||
hci.borrow_mut().probe().expect("xhcid: failed to probe");
|
||||
|
||||
let mut event_queue = EventQueue::<()>::new().expect("xhcid: failed to create event queue");
|
||||
let mut event_queue =
|
||||
EventQueue::<()>::new().expect("xhcid: failed to create event queue");
|
||||
|
||||
syscall::setrens(0, 0).expect("xhcid: failed to enter null namespace");
|
||||
|
||||
@@ -57,62 +74,67 @@ fn main() {
|
||||
let hci_irq = hci.clone();
|
||||
let socket_irq = socket.clone();
|
||||
let todo_irq = todo.clone();
|
||||
event_queue.add(irq_file.as_raw_fd(), move |_| -> Result<Option<()>> {
|
||||
let mut irq = [0; 8];
|
||||
irq_file.read(&mut irq)?;
|
||||
event_queue
|
||||
.add(irq_file.as_raw_fd(), move |_| -> Result<Option<()>> {
|
||||
let mut irq = [0; 8];
|
||||
irq_file.read(&mut irq)?;
|
||||
|
||||
if hci_irq.borrow_mut().trigger_irq() {
|
||||
irq_file.write(&mut irq)?;
|
||||
if hci_irq.borrow_mut().trigger_irq() {
|
||||
irq_file.write(&mut irq)?;
|
||||
|
||||
let mut todo = todo_irq.borrow_mut();
|
||||
let mut i = 0;
|
||||
while i < todo.len() {
|
||||
let a = todo[i].a;
|
||||
hci_irq.borrow_mut().handle(&mut todo[i]);
|
||||
if todo[i].a == (-EWOULDBLOCK) as usize {
|
||||
todo[i].a = a;
|
||||
i += 1;
|
||||
} else {
|
||||
socket_irq.borrow_mut().write(&mut todo[i])?;
|
||||
todo.remove(i);
|
||||
let mut todo = todo_irq.borrow_mut();
|
||||
let mut i = 0;
|
||||
while i < todo.len() {
|
||||
let a = todo[i].a;
|
||||
hci_irq.borrow_mut().handle(&mut todo[i]);
|
||||
if todo[i].a == (-EWOULDBLOCK) as usize {
|
||||
todo[i].a = a;
|
||||
i += 1;
|
||||
} else {
|
||||
socket_irq.borrow_mut().write(&mut todo[i])?;
|
||||
todo.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}).expect("xhcid: failed to catch events on IRQ file");
|
||||
Ok(None)
|
||||
})
|
||||
.expect("xhcid: failed to catch events on IRQ file");
|
||||
|
||||
let socket_fd = socket.borrow().as_raw_fd();
|
||||
let socket_packet = socket.clone();
|
||||
event_queue.add(socket_fd, move |_| -> Result<Option<()>> {
|
||||
loop {
|
||||
let mut packet = Packet::default();
|
||||
match socket_packet.borrow_mut().read(&mut packet) {
|
||||
Ok(0) => break,
|
||||
Err(err) if err.kind() == io::ErrorKind::WouldBlock => break,
|
||||
Ok(_) => (),
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
event_queue
|
||||
.add(socket_fd, move |_| -> Result<Option<()>> {
|
||||
loop {
|
||||
let mut packet = Packet::default();
|
||||
match socket_packet.borrow_mut().read(&mut packet) {
|
||||
Ok(0) => break,
|
||||
Err(err) if err.kind() == io::ErrorKind::WouldBlock => break,
|
||||
Ok(_) => (),
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
|
||||
let a = packet.a;
|
||||
hci.borrow_mut().handle(&mut packet);
|
||||
if packet.a == (-EWOULDBLOCK) as usize {
|
||||
packet.a = a;
|
||||
todo.borrow_mut().push(packet);
|
||||
} else {
|
||||
socket_packet.borrow_mut().write(&mut packet)?;
|
||||
let a = packet.a;
|
||||
hci.borrow_mut().handle(&mut packet);
|
||||
if packet.a == (-EWOULDBLOCK) as usize {
|
||||
packet.a = a;
|
||||
todo.borrow_mut().push(packet);
|
||||
} else {
|
||||
socket_packet.borrow_mut().write(&mut packet)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}).expect("xhcid: failed to catch events on scheme file");
|
||||
Ok(None)
|
||||
})
|
||||
.expect("xhcid: failed to catch events on scheme file");
|
||||
|
||||
event_queue.trigger_all(Event {
|
||||
fd: 0,
|
||||
flags: 0
|
||||
}).expect("xhcid: failed to trigger events");
|
||||
event_queue
|
||||
.trigger_all(Event { fd: 0, flags: 0 })
|
||||
.expect("xhcid: failed to trigger events");
|
||||
|
||||
event_queue.run().expect("xhcid: failed to handle events");
|
||||
}
|
||||
unsafe { let _ = syscall::physunmap(address); }
|
||||
unsafe {
|
||||
let _ = syscall::physunmap(address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-6
@@ -57,9 +57,7 @@ pub struct BosDevDescIter<'a> {
|
||||
}
|
||||
impl<'a> BosDevDescIter<'a> {
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Self {
|
||||
bytes,
|
||||
}
|
||||
Self { bytes }
|
||||
}
|
||||
}
|
||||
impl<'a> From<&'a [u8]> for BosDevDescIter<'a> {
|
||||
@@ -72,7 +70,9 @@ impl<'a> Iterator for BosDevDescIter<'a> {
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(desc) = plain::from_bytes::<BosDevDescriptorBase>(self.bytes).ok() {
|
||||
if desc.len as usize > self.bytes.len() { return None };
|
||||
if desc.len as usize > self.bytes.len() {
|
||||
return None;
|
||||
};
|
||||
let bytes_ret = &self.bytes[..desc.len as usize];
|
||||
self.bytes = &self.bytes[desc.len as usize..];
|
||||
Some((*desc, bytes_ret))
|
||||
@@ -129,6 +129,10 @@ impl<'a> Iterator for BosAnyDevDescIter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bos_capability_descs<'a>(desc: BosDescriptor, data: &'a [u8]) -> impl Iterator<Item = BosAnyDevDesc> + 'a {
|
||||
BosAnyDevDescIter::from(&data[..desc.total_len as usize - std::mem::size_of_val(&desc)]).take(desc.cap_count as usize)
|
||||
pub fn bos_capability_descs<'a>(
|
||||
desc: BosDescriptor,
|
||||
data: &'a [u8],
|
||||
) -> impl Iterator<Item = BosAnyDevDesc> + 'a {
|
||||
BosAnyDevDescIter::from(&data[..desc.total_len as usize - std::mem::size_of_val(&desc)])
|
||||
.take(desc.cap_count as usize)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
pub use self::bos::{BosDescriptor, BosAnyDevDesc, BosSuperSpeedDesc, bos_capability_descs};
|
||||
pub use self::bos::{bos_capability_descs, BosAnyDevDesc, BosDescriptor, BosSuperSpeedDesc};
|
||||
pub use self::config::ConfigDescriptor;
|
||||
pub use self::device::DeviceDescriptor;
|
||||
pub use self::endpoint::{EndpointDescriptor, HidDescriptor, SuperSpeedCompanionDescriptor, EndpointTy, ENDP_ATTR_TY_MASK};
|
||||
pub use self::endpoint::{
|
||||
EndpointDescriptor, EndpointTy, HidDescriptor, SuperSpeedCompanionDescriptor, ENDP_ATTR_TY_MASK,
|
||||
};
|
||||
pub use self::interface::InterfaceDescriptor;
|
||||
pub use self::setup::Setup;
|
||||
|
||||
|
||||
@@ -108,7 +108,12 @@ impl Setup {
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn get_descriptor(kind: DescriptorKind, index: u8, language: u16, length: u16) -> Self {
|
||||
pub const fn get_descriptor(
|
||||
kind: DescriptorKind,
|
||||
index: u8,
|
||||
language: u16,
|
||||
length: u16,
|
||||
) -> Self {
|
||||
Self {
|
||||
kind: 0b1000_0000,
|
||||
request: 0x06,
|
||||
|
||||
@@ -11,7 +11,7 @@ pub struct CapabilityRegs {
|
||||
pub hcc_params1: Mmio<u32>,
|
||||
pub db_offset: Mmio<u32>,
|
||||
pub rts_offset: Mmio<u32>,
|
||||
pub hcc_params2: Mmio<u32>
|
||||
pub hcc_params2: Mmio<u32>,
|
||||
}
|
||||
|
||||
pub const HCC_PARAMS1_MAXPSASIZE_MASK: u32 = 0xF000; // 15:12
|
||||
@@ -28,6 +28,7 @@ impl CapabilityRegs {
|
||||
self.hcc_params2.readf(HCC_PARAMS2_CIC_BIT)
|
||||
}
|
||||
pub fn max_psa_size(&self) -> u8 {
|
||||
((self.hcc_params1.read() & HCC_PARAMS1_MAXPSASIZE_MASK) >> HCC_PARAMS1_MAXPSASIZE_SHIFT) as u8
|
||||
((self.hcc_params1.read() & HCC_PARAMS1_MAXPSASIZE_MASK) >> HCC_PARAMS1_MAXPSASIZE_SHIFT)
|
||||
as u8
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use syscall::error::Result;
|
||||
|
||||
|
||||
use super::event::EventRing;
|
||||
use super::ring::Ring;
|
||||
use super::trb::Trb;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use syscall::error::Result;
|
||||
use syscall::io::{Dma, Mmio, Io};
|
||||
use syscall::io::{Dma, Io, Mmio};
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct SlotContext {
|
||||
@@ -55,7 +55,17 @@ pub struct InputContext {
|
||||
}
|
||||
impl InputContext {
|
||||
pub fn dump_control(&self) {
|
||||
println!("INPUT CONTEXT: {} {} [{} {} {} {} {}] {}", self.drop_context.read(), self.add_context.read(), self._rsvd[0].read(), self._rsvd[1].read(), self._rsvd[2].read(), self._rsvd[3].read(), self._rsvd[4].read(), self.control.read());
|
||||
println!(
|
||||
"INPUT CONTEXT: {} {} [{} {} {} {} {}] {}",
|
||||
self.drop_context.read(),
|
||||
self.add_context.read(),
|
||||
self._rsvd[0].read(),
|
||||
self._rsvd[1].read(),
|
||||
self._rsvd[2].read(),
|
||||
self._rsvd[3].read(),
|
||||
self._rsvd[4].read(),
|
||||
self.control.read()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +88,7 @@ impl DeviceContextList {
|
||||
|
||||
Ok(DeviceContextList {
|
||||
dcbaa: dcbaa,
|
||||
contexts: contexts
|
||||
contexts: contexts,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
+76
-49
@@ -1,11 +1,11 @@
|
||||
use std::{mem, slice, process, sync::atomic, task};
|
||||
use std::collections::BTreeMap;
|
||||
use std::ffi::OsStr;
|
||||
use std::pin::Pin;
|
||||
use std::sync::{Arc, Mutex, Weak, atomic::AtomicBool};
|
||||
use std::sync::{atomic::AtomicBool, Arc, Mutex, Weak};
|
||||
use std::{mem, process, slice, sync::atomic, task};
|
||||
|
||||
use serde::Deserialize;
|
||||
use syscall::error::{EBADF, EBADMSG, ENOENT, Error, Result};
|
||||
use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT};
|
||||
use syscall::io::{Dma, Io};
|
||||
|
||||
use crate::usb;
|
||||
@@ -17,8 +17,8 @@ mod doorbell;
|
||||
mod event;
|
||||
mod operational;
|
||||
mod port;
|
||||
mod runtime;
|
||||
mod ring;
|
||||
mod runtime;
|
||||
mod scheme;
|
||||
mod trb;
|
||||
|
||||
@@ -29,9 +29,11 @@ use self::doorbell::Doorbell;
|
||||
use self::operational::OperationalRegs;
|
||||
use self::port::Port;
|
||||
use self::ring::Ring;
|
||||
use self::runtime::{RuntimeRegs, Interrupter};
|
||||
use self::runtime::{Interrupter, RuntimeRegs};
|
||||
use self::trb::{TransferKind, TrbCompletionCode, TrbType};
|
||||
|
||||
use crate::driver_interface::*;
|
||||
|
||||
struct Device<'a> {
|
||||
ring: &'a mut Ring,
|
||||
cmd: &'a mut CommandRing,
|
||||
@@ -47,7 +49,8 @@ impl<'a> Device<'a> {
|
||||
let (cmd, cycle) = self.ring.next();
|
||||
cmd.setup(
|
||||
usb::Setup::get_descriptor(kind, index, 0, len as u16),
|
||||
TransferKind::In, cycle
|
||||
TransferKind::In,
|
||||
cycle,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -75,45 +78,29 @@ impl<'a> Device<'a> {
|
||||
|
||||
fn get_device(&mut self) -> Result<usb::DeviceDescriptor> {
|
||||
let mut desc = Dma::<usb::DeviceDescriptor>::zeroed()?;
|
||||
self.get_desc(
|
||||
usb::DescriptorKind::Device,
|
||||
0,
|
||||
&mut desc
|
||||
);
|
||||
self.get_desc(usb::DescriptorKind::Device, 0, &mut desc);
|
||||
Ok(*desc)
|
||||
}
|
||||
|
||||
fn get_config(&mut self, 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(usb::DescriptorKind::Configuration, config, &mut desc);
|
||||
Ok(*desc)
|
||||
}
|
||||
|
||||
fn get_bos(&mut self) -> Result<(usb::BosDescriptor, [u8; 4087])> {
|
||||
let mut desc = Dma::<(usb::BosDescriptor, [u8; 4087])>::zeroed()?;
|
||||
self.get_desc(
|
||||
usb::DescriptorKind::BinaryObjectStorage,
|
||||
0,
|
||||
&mut desc,
|
||||
);
|
||||
self.get_desc(usb::DescriptorKind::BinaryObjectStorage, 0, &mut desc);
|
||||
Ok(*desc)
|
||||
}
|
||||
|
||||
fn get_string(&mut self, 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(usb::DescriptorKind::String, index, &mut sdesc);
|
||||
|
||||
let len = sdesc.0 as usize;
|
||||
if len > 2 {
|
||||
Ok(String::from_utf16(&sdesc.2[.. (len - 2)/2]).unwrap_or(String::new()))
|
||||
Ok(String::from_utf16(&sdesc.2[..(len - 2) / 2]).unwrap_or(String::new()))
|
||||
} else {
|
||||
Ok(String::new())
|
||||
}
|
||||
@@ -150,7 +137,7 @@ pub struct Xhci {
|
||||
struct PortState {
|
||||
slot: u8,
|
||||
input_context: Dma<InputContext>,
|
||||
dev_desc: scheme::DevDesc,
|
||||
dev_desc: DevDesc,
|
||||
endpoint_states: BTreeMap<u8, EndpointState>,
|
||||
}
|
||||
|
||||
@@ -197,7 +184,7 @@ impl Xhci {
|
||||
|
||||
println!(" - Wait for not running");
|
||||
// Wait until controller not running
|
||||
while ! op.usb_sts.readf(1) {
|
||||
while !op.usb_sts.readf(1) {
|
||||
println!(" - Waiting for XHCI stopped");
|
||||
}
|
||||
|
||||
@@ -217,7 +204,8 @@ impl Xhci {
|
||||
}
|
||||
|
||||
let port_base = op_base + 0x400;
|
||||
let ports = unsafe { slice::from_raw_parts_mut(port_base as *mut Port, max_ports as usize) };
|
||||
let ports =
|
||||
unsafe { slice::from_raw_parts_mut(port_base as *mut Port, max_ports as usize) };
|
||||
println!(" - PORT {:X}", port_base);
|
||||
|
||||
let db_base = address + cap.db_offset.read() as usize;
|
||||
@@ -331,14 +319,12 @@ impl Xhci {
|
||||
for i in 0..self.ports.len() {
|
||||
let (data, state, speed, flags) = {
|
||||
let port = &self.ports[i];
|
||||
(
|
||||
port.read(),
|
||||
port.state(),
|
||||
port.speed(),
|
||||
port.flags(),
|
||||
)
|
||||
(port.read(), port.state(), port.speed(), port.flags())
|
||||
};
|
||||
println!(" + XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", i, data, state, speed, flags);
|
||||
println!(
|
||||
" + XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}",
|
||||
i, data, state, speed, flags
|
||||
);
|
||||
|
||||
if flags.contains(port::PortFlags::PORT_CCS) {
|
||||
//TODO: Link TRB when running to the end of the ring buffer
|
||||
@@ -362,7 +348,9 @@ impl Xhci {
|
||||
input.device.slot.b.write(((i as u32 + 1) & 0xFF) << 16);
|
||||
|
||||
// control endpoint?
|
||||
input.device.endpoints[0].b.write(4096 << 16 | 4 << 3 | 3 << 1); // packet size | control endpoint | allowed error count
|
||||
input.device.endpoints[0]
|
||||
.b
|
||||
.write(4096 << 16 | 4 << 3 | 3 << 1); // packet size | control endpoint | allowed error count
|
||||
let tr = ring.register();
|
||||
input.device.endpoints[0].trh.write((tr >> 32) as u32);
|
||||
input.device.endpoints[0].trl.write(tr as u32);
|
||||
@@ -379,7 +367,9 @@ impl Xhci {
|
||||
println!(" - Waiting for event");
|
||||
}
|
||||
|
||||
if event.completion_code() != TrbCompletionCode::Success as u8 || event.trb_type() != TrbType::CommandCompletion as u8 {
|
||||
if event.completion_code() != TrbCompletionCode::Success as u8
|
||||
|| event.trb_type() != TrbType::CommandCompletion as u8
|
||||
{
|
||||
panic!("ADDRESS DEVICE FAILED");
|
||||
}
|
||||
|
||||
@@ -387,14 +377,24 @@ impl Xhci {
|
||||
event.reserved(false);
|
||||
}
|
||||
|
||||
let dev_desc = Self::get_dev_desc_raw(&mut self.ports, &mut self.run, &mut self.cmd, &mut self.dbs, i, slot, &mut ring)?;
|
||||
let dev_desc = Self::get_dev_desc_raw(
|
||||
&mut self.ports,
|
||||
&mut self.run,
|
||||
&mut self.cmd,
|
||||
&mut self.dbs,
|
||||
i,
|
||||
slot,
|
||||
&mut ring,
|
||||
)?;
|
||||
let mut port_state = PortState {
|
||||
slot,
|
||||
input_context: input,
|
||||
dev_desc,
|
||||
endpoint_states: std::iter::once((0, EndpointState::Ready(
|
||||
RingOrStreams::Ring(ring),
|
||||
))).collect::<BTreeMap<_, _>>(),
|
||||
endpoint_states: std::iter::once((
|
||||
0,
|
||||
EndpointState::Ready(RingOrStreams::Ring(ring)),
|
||||
))
|
||||
.collect::<BTreeMap<_, _>>(),
|
||||
};
|
||||
|
||||
match self.spawn_drivers(i, &mut port_state) {
|
||||
@@ -431,7 +431,7 @@ impl Xhci {
|
||||
}
|
||||
pub(crate) fn irq(&self) -> IrqFuture {
|
||||
IrqFuture {
|
||||
state: IrqFutureState::Pending(Arc::downgrade(&self.irq_state))
|
||||
state: IrqFutureState::Pending(Arc::downgrade(&self.irq_state)),
|
||||
}
|
||||
}
|
||||
fn spawn_drivers(&mut self, port: usize, ps: &mut PortState) -> Result<()> {
|
||||
@@ -440,16 +440,39 @@ impl Xhci {
|
||||
// TODO: Now that there are some good error crates, I don't think errno.h error codes are
|
||||
// suitable here.
|
||||
|
||||
let ifdesc = &ps.dev_desc.config_descs.first().ok_or(Error::new(EBADF))?.interface_descs.first().ok_or(Error::new(EBADF))?;
|
||||
let ifdesc = &ps
|
||||
.dev_desc
|
||||
.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| driver.class == ifdesc.class && driver.subclass == ifdesc.sub_class) {
|
||||
if let Some(driver) = drivers_usercfg
|
||||
.drivers
|
||||
.iter()
|
||||
.find(|driver| driver.class == ifdesc.class && driver.subclass == ifdesc.sub_class)
|
||||
{
|
||||
println!("Loading driver \"{}\"", driver.name);
|
||||
let (command, args) = driver.command.split_first().ok_or(Error::new(EBADMSG))?;
|
||||
|
||||
let if_proto = ifdesc.protocol;
|
||||
|
||||
let process = process::Command::new(command).args(args.into_iter().map(|arg| arg.replace("$SCHEME", &self.scheme_name).replace("$PORT", &format!("{}", port)).replace("$IF_PROTO", &format!("{}", if_proto))).collect::<Vec<_>>()).stdin(process::Stdio::null()).spawn().or(Err(Error::new(ENOENT)))?;
|
||||
let process = process::Command::new(command)
|
||||
.args(
|
||||
args.into_iter()
|
||||
.map(|arg| {
|
||||
arg.replace("$SCHEME", &self.scheme_name)
|
||||
.replace("$PORT", &format!("{}", port))
|
||||
.replace("$IF_PROTO", &format!("{}", if_proto))
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.stdin(process::Stdio::null())
|
||||
.spawn()
|
||||
.or(Err(Error::new(ENOENT)))?;
|
||||
self.drivers.insert(port, process);
|
||||
} else {
|
||||
return Err(Error::new(ENOENT));
|
||||
@@ -481,7 +504,9 @@ lazy_static! {
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) struct IrqFuture { state: IrqFutureState }
|
||||
pub(crate) struct IrqFuture {
|
||||
state: IrqFutureState,
|
||||
}
|
||||
|
||||
struct IrqState {
|
||||
triggered: AtomicBool,
|
||||
@@ -503,7 +528,9 @@ impl std::future::Future for IrqFuture {
|
||||
match &mut this.state {
|
||||
// TODO: Ordering?
|
||||
IrqFutureState::Pending(state_weak) => {
|
||||
let state = state_weak.upgrade().expect("IRQ futures keep getting polled even after the driver has been deinitialized");
|
||||
let state = state_weak.upgrade().expect(
|
||||
"IRQ futures keep getting polled even after the driver has been deinitialized",
|
||||
);
|
||||
|
||||
if state.triggered.load(atomic::Ordering::SeqCst) {
|
||||
this.state = IrqFutureState::Finished;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use syscall::io::{Mmio, Io};
|
||||
use syscall::io::{Io, Mmio};
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct OperationalRegs {
|
||||
|
||||
@@ -28,10 +28,10 @@ bitflags! {
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct Port {
|
||||
pub portsc : Mmio<u32>,
|
||||
pub portpmsc : Mmio<u32>,
|
||||
pub portli : Mmio<u32>,
|
||||
pub porthlpmc : Mmio<u32>,
|
||||
pub portsc: Mmio<u32>,
|
||||
pub portpmsc: Mmio<u32>,
|
||||
pub portli: Mmio<u32>,
|
||||
pub porthlpmc: Mmio<u32>,
|
||||
}
|
||||
|
||||
impl Port {
|
||||
|
||||
+399
-307
File diff suppressed because it is too large
Load Diff
+39
-41
@@ -1,6 +1,6 @@
|
||||
use crate::usb;
|
||||
use std::{fmt, mem};
|
||||
use syscall::io::{Io, Mmio};
|
||||
use crate::usb;
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum TrbType {
|
||||
@@ -127,12 +127,7 @@ impl Trb {
|
||||
}
|
||||
|
||||
pub fn reserved(&mut self, cycle: bool) {
|
||||
self.set(
|
||||
0,
|
||||
0,
|
||||
((TrbType::Reserved as u32) << 10) |
|
||||
(cycle as u32)
|
||||
);
|
||||
self.set(0, 0, ((TrbType::Reserved as u32) << 10) | (cycle as u32));
|
||||
}
|
||||
|
||||
pub fn completion_code(&self) -> u8 {
|
||||
@@ -149,28 +144,21 @@ impl Trb {
|
||||
self.set(
|
||||
address as u64,
|
||||
0,
|
||||
((TrbType::Link as u32) << 10) |
|
||||
((toggle as u32) << 1) |
|
||||
(cycle as u32)
|
||||
((TrbType::Link as u32) << 10) | ((toggle as u32) << 1) | (cycle as u32),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn no_op_cmd(&mut self, cycle: bool) {
|
||||
self.set(
|
||||
0,
|
||||
0,
|
||||
((TrbType::NoOpCmd as u32) << 10) |
|
||||
(cycle as u32)
|
||||
);
|
||||
self.set(0, 0, ((TrbType::NoOpCmd as u32) << 10) | (cycle as u32));
|
||||
}
|
||||
|
||||
pub fn enable_slot(&mut self, slot_type: u8, cycle: bool) {
|
||||
self.set(
|
||||
0,
|
||||
0,
|
||||
(((slot_type as u32) & 0x1F) << 16) |
|
||||
((TrbType::EnableSlot as u32) << 10) |
|
||||
(cycle as u32)
|
||||
(((slot_type as u32) & 0x1F) << 16)
|
||||
| ((TrbType::EnableSlot as u32) << 10)
|
||||
| (cycle as u32),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -178,21 +166,23 @@ impl Trb {
|
||||
self.set(
|
||||
input as u64,
|
||||
0,
|
||||
((slot_id as u32) << 24) |
|
||||
((TrbType::AddressDevice as u32) << 10) |
|
||||
(cycle as u32)
|
||||
((slot_id as u32) << 24) | ((TrbType::AddressDevice as u32) << 10) | (cycle as u32),
|
||||
);
|
||||
}
|
||||
// Synchronizes the input context endpoints with the device context endpoints, I think.
|
||||
pub fn configure_endpoint(&mut self, slot_id: u8, input_ctx_ptr: usize, cycle: bool) {
|
||||
assert_eq!(input_ctx_ptr & 0xFFFF_FFFF_FFFF_FF80, input_ctx_ptr, "unaligned input context ptr");
|
||||
assert_eq!(
|
||||
input_ctx_ptr & 0xFFFF_FFFF_FFFF_FF80,
|
||||
input_ctx_ptr,
|
||||
"unaligned input context ptr"
|
||||
);
|
||||
|
||||
self.set(
|
||||
input_ctx_ptr as u64,
|
||||
0,
|
||||
(u32::from(slot_id) << 24) |
|
||||
((TrbType::ConfigureEndpoint as u32) << 10) |
|
||||
(cycle as u32),
|
||||
(u32::from(slot_id) << 24)
|
||||
| ((TrbType::ConfigureEndpoint as u32) << 10)
|
||||
| (cycle as u32),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -200,10 +190,10 @@ impl Trb {
|
||||
self.set(
|
||||
unsafe { mem::transmute(setup) },
|
||||
8,
|
||||
((transfer as u32) << 16) |
|
||||
((TrbType::SetupStage as u32) << 10) |
|
||||
(1 << 6) |
|
||||
(cycle as u32)
|
||||
((transfer as u32) << 16)
|
||||
| ((TrbType::SetupStage as u32) << 10)
|
||||
| (1 << 6)
|
||||
| (cycle as u32),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -211,9 +201,7 @@ impl Trb {
|
||||
self.set(
|
||||
buffer as u64,
|
||||
length as u32,
|
||||
((input as u32) << 16) |
|
||||
((TrbType::DataStage as u32) << 10) |
|
||||
(cycle as u32)
|
||||
((input as u32) << 16) | ((TrbType::DataStage as u32) << 10) | (cycle as u32),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -221,24 +209,34 @@ impl Trb {
|
||||
self.set(
|
||||
0,
|
||||
0,
|
||||
((input as u32) << 16) |
|
||||
((TrbType::StatusStage as u32) << 10) |
|
||||
(1 << 5) |
|
||||
(cycle as u32)
|
||||
((input as u32) << 16)
|
||||
| ((TrbType::StatusStage as u32) << 10)
|
||||
| (1 << 5)
|
||||
| (cycle as u32),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Trb {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Trb {{ data: {:>016X}, status: {:>08X}, control: {:>08X} }}",
|
||||
self.data.read(), self.status.read(), self.control.read())
|
||||
write!(
|
||||
f,
|
||||
"Trb {{ data: {:>016X}, status: {:>08X}, control: {:>08X} }}",
|
||||
self.data.read(),
|
||||
self.status.read(),
|
||||
self.control.read()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Trb {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "({:>016X}, {:>08X}, {:>08X})",
|
||||
self.data.read(), self.status.read(), self.control.read())
|
||||
write!(
|
||||
f,
|
||||
"({:>016X}, {:>08X}, {:>08X})",
|
||||
self.data.read(),
|
||||
self.status.read(),
|
||||
self.control.read()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user