diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 741871db4b..60dc85bd61 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -1,3 +1,5 @@ +#![feature(core_intrinsics)] + #[macro_use] extern crate bitflags; extern crate syscall; @@ -22,7 +24,7 @@ fn main() { // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { let address = unsafe { syscall::physmap(bar, 4096, syscall::MAP_WRITE).expect("xhcid: failed to map address") }; - /* + match Xhci::new(address) { Ok(mut xhci) => { xhci.init(); @@ -31,7 +33,7 @@ fn main() { println!("xhcid: error: {}", err); } } - */ + unsafe { let _ = syscall::physunmap(address); } } } diff --git a/xhcid/src/xhci/event.rs b/xhcid/src/xhci/event.rs new file mode 100644 index 0000000000..e811442ad6 --- /dev/null +++ b/xhcid/src/xhci/event.rs @@ -0,0 +1,8 @@ +use syscall::io::Mmio; + +pub struct EventRingSte { + pub address: Mmio, + pub size: Mmio, + _rsvd: Mmio, + _rsvd2: Mmio, +} diff --git a/xhcid/src/xhci.rs b/xhcid/src/xhci/mod.rs similarity index 77% rename from xhcid/src/xhci.rs rename to xhcid/src/xhci/mod.rs index 63b7b2d9ba..96f23e9ebe 100644 --- a/xhcid/src/xhci.rs +++ b/xhcid/src/xhci/mod.rs @@ -2,22 +2,11 @@ use std::slice; use syscall::error::Result; use syscall::io::{Dma, Mmio, Io}; -#[repr(packed)] -struct Trb { - pub data: u64, - pub status: u32, - pub control: u32, -} +mod event; +mod trb; -impl Trb { - pub fn from_type(trb_type: u32) -> Self { - Trb { - data: 0, - status: 0, - control: (trb_type & 0x3F) << 10, - } - } -} +use self::event::*; +use self::trb::*; #[repr(packed)] pub struct XhciCap { @@ -46,6 +35,21 @@ pub struct XhciOp { config: Mmio, } +pub struct XhciInterrupter { + iman: Mmio, + imod: Mmio, + erstsz: Mmio, + _rsvd: Mmio, + erstba: Mmio, + erdp: Mmio, +} + +pub struct XhciRun { + mfindex: Mmio, + _rsvd: [Mmio; 7], + ints: [XhciInterrupter; 1024], +} + bitflags! { flags XhciPortFlags: u32 { const PORT_CCS = 1 << 0, @@ -131,9 +135,11 @@ pub struct Xhci { op: &'static mut XhciOp, ports: &'static mut [XhciPort], dbs: &'static mut [XhciDoorbell], + run: &'static mut XhciRun, dev_baa: Dma<[u64; 256]>, dev_ctxs: Vec>, cmds: Dma<[Trb; 256]>, + event_rings: Dma<[EventRingSte; 1]>, } impl Xhci { @@ -175,17 +181,22 @@ impl Xhci { let port_base = op_base + 0x400; let ports = unsafe { slice::from_raw_parts_mut(port_base as *mut XhciPort, max_ports as usize) }; - let db_base = op_base + cap.db_offset.read() as usize; + let db_base = address + cap.db_offset.read() as usize; let dbs = unsafe { slice::from_raw_parts_mut(db_base as *mut XhciDoorbell, 256) }; + let run_base = address + cap.rts_offset.read() as usize; + let run = unsafe { &mut *(run_base as *mut XhciRun) }; + let mut xhci = Xhci { cap: cap, op: op, ports: ports, dbs: dbs, + run: run, dev_baa: Dma::zeroed()?, dev_ctxs: Vec::new(), cmds: Dma::zeroed()?, + event_rings: Dma::zeroed()?, }; { @@ -200,7 +211,10 @@ impl Xhci { xhci.op.dcbaap.write(xhci.dev_baa.physical() as u64); // Set command ring control register - xhci.op.crcr.write(xhci.cmds.physical() as u64); + xhci.op.crcr.write(xhci.cmds.physical() as u64 | 1); + + // Set event ring segment table registers + //TODO // Set run/stop to 1 xhci.op.usb_cmd.writef(1, true); @@ -209,6 +223,9 @@ impl Xhci { while xhci.op.usb_sts.readf(1) { println!(" - Waiting for XHCI running"); } + + // Ring command doorbell + xhci.dbs[0].write(0); } Ok(xhci) @@ -222,5 +239,23 @@ impl Xhci { let flags = port.flags(); println!(" + XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", i, data, state, speed, flags); } + + self.cmds[0].no_op_cmd(true); + + println!("Before"); + println!("USBSTS: {:X}", self.op.usb_sts.read()); + println!("CRCR: {:X}", self.op.crcr.read()); + println!("data: {:X}", self.cmds[0].data.read()); + println!("status: {:X}", self.cmds[0].status.read()); + println!("control: {:X}", self.cmds[0].control.read()); + + self.dbs[0].write(0); + + println!("After"); + println!("USBSTS: {:X}", self.op.usb_sts.read()); + println!("CRCR: {:X}", self.op.crcr.read()); + println!("data: {:X}", self.cmds[0].data.read()); + println!("status: {:X}", self.cmds[0].status.read()); + println!("control: {:X}", self.cmds[0].control.read()); } } diff --git a/xhcid/src/xhci/termios.rs b/xhcid/src/xhci/termios.rs new file mode 100644 index 0000000000..a9bac08040 --- /dev/null +++ b/xhcid/src/xhci/termios.rs @@ -0,0 +1,102 @@ +use std::cell::RefCell; +use std::ops::{Deref, DerefMut}; +use std::rc::Weak; + +use syscall::error::{Error, Result, EBADF, EINVAL, EPIPE}; +use syscall::flag::{F_GETFL, F_SETFL, O_ACCMODE}; + +use pty::Pty; +use resource::Resource; + +/// Read side of a pipe +#[derive(Clone)] +pub struct PtyTermios { + pty: Weak>, + flags: usize, +} + +impl PtyTermios { + pub fn new(pty: Weak>, flags: usize) -> Self { + PtyTermios { + pty: pty, + flags: flags, + } + } +} + +impl Resource for PtyTermios { + fn boxed_clone(&self) -> Box { + Box::new(self.clone()) + } + + fn pty(&self) -> Weak> { + self.pty.clone() + } + + fn flags(&self) -> usize { + self.flags + } + + fn path(&self, buf: &mut [u8]) -> Result { + if let Some(pty_lock) = self.pty.upgrade() { + pty_lock.borrow_mut().path(buf) + } else { + Err(Error::new(EPIPE)) + } + } + + fn read(&self, buf: &mut [u8]) -> Result { + if let Some(pty_lock) = self.pty.upgrade() { + let pty = pty_lock.borrow(); + let termios: &[u8] = pty.termios.deref(); + + let mut i = 0; + while i < buf.len() && i < termios.len() { + buf[i] = termios[i]; + i += 1; + } + Ok(i) + } else { + Ok(0) + } + } + + fn write(&self, buf: &[u8]) -> Result { + if let Some(pty_lock) = self.pty.upgrade() { + let mut pty = pty_lock.borrow_mut(); + let termios: &mut [u8] = pty.termios.deref_mut(); + + let mut i = 0; + while i < buf.len() && i < termios.len() { + termios[i] = buf[i]; + i += 1; + } + Ok(i) + } else { + Err(Error::new(EPIPE)) + } + } + + fn sync(&self) -> Result { + Ok(0) + } + + fn fcntl(&mut self, cmd: usize, arg: usize) -> Result { + match cmd { + F_GETFL => Ok(self.flags), + F_SETFL => { + self.flags = (self.flags & O_ACCMODE) | (arg & ! O_ACCMODE); + Ok(0) + }, + _ => Err(Error::new(EINVAL)) + } + } + + fn fevent(&self) -> Result<()> { + Err(Error::new(EBADF)) + } + + fn fevent_count(&self) -> Option { + None + } +} diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs new file mode 100644 index 0000000000..2e54fd3430 --- /dev/null +++ b/xhcid/src/xhci/trb.rs @@ -0,0 +1,123 @@ +use syscall::io::{Io, Mmio}; + +#[repr(u8)] +pub enum TrbType { + Reserved, + /* Transfer */ + Normal, + SetupStage, + DataStage, + StatusStage, + Isoch, + Link, + EventData, + NoOp, + /* Command */ + EnableSlot, + DisableSlot, + AddressDevice, + ConfigureEndpoint, + EvaluateContext, + ResetEndpoint, + StopEndpoint, + SetTrDequeuePointer, + ResetDevice, + ForceEvent, + NegotiateBandwidth, + SetLatencyToleranceValue, + GetPortBandwidth, + ForceHeader, + NoOpCmd, + /* Reserved */ + Rsv24, + Rsv25, + Rsv26, + Rsv27, + Rsv28, + Rsv29, + Rsv30, + Rsv31, + /* Events */ + Transfer, + CommandCompletion, + PortStatusChange, + BandwidthRequest, + Doorbell, + HostController, + DeviceNotification, + MfindexWrap, + /* Reserved from 40 to 47, vendor devined from 48 to 63 */ +} + +#[repr(u8)] +pub enum TrbCompletionCode { + Invalid, + Success, + DataBuffer, + BabbleDetected, + UsbTransaction, + Trb, + Stall, + Resource, + Bandwidth, + NoSlotsAvailable, + InvalidStreamType, + SlotNotEnabled, + EndpointNotEnabled, + ShortPacket, + RingUnderrun, + RingOverrun, + VfEventRingFull, + Parameter, + BandwidthOverrun, + ContextState, + NoPingResponse, + EventRingFull, + IncompatibleDevice, + MissedService, + CommandRingStopped, + CommandAborted, + Stopped, + StoppedLengthInvalid, + StoppedShortPacket, + MaxExitLatencyTooLarge, + Rsv30, + IsochBuffer, + EventLost, + Undefined, + InvalidStreamId, + SecondaryBandwidth, + SplitTransaction, + /* Values from 37 to 191 are reserved */ + /* 192 to 223 are vendor defined errors */ + /* 224 to 255 are vendor defined information */ +} + +#[repr(packed)] +pub struct Trb { + pub data: Mmio, + pub status: Mmio, + pub control: Mmio, +} + +impl Trb { + pub fn reset(&mut self, param: u64, status: u32, control: u16, trb_type: TrbType, evaluate_next: bool, cycle: bool) { + let full_control = + (control as u32) << 16 | + ((trb_type as u32) & 0x3F) << 10 | + if evaluate_next { 1 << 1 } else { 0 } | + if cycle { 1 << 0 } else { 0 }; + + self.data.write(param); + self.status.write(status); + self.control.write(full_control); + } + + pub fn no_op_cmd(&mut self, cycle: bool) { + self.reset(0, 0, 0, TrbType::NoOpCmd, false, cycle); + } + + pub fn enable_slot(&mut self, slot_type: u8, cycle: bool) { + self.reset(0, 0, (slot_type as u16) & 0x1F, TrbType::EnableSlot, false, cycle); + } +}