Improve XHCI driver
This commit is contained in:
+1
-1
@@ -142,7 +142,7 @@ fn main() {
|
||||
command.arg(&arg);
|
||||
}
|
||||
|
||||
println!("PCID SPAWN {:?}", command);
|
||||
//println!("PCID SPAWN {:?}", command);
|
||||
|
||||
match command.spawn() {
|
||||
Ok(mut child) => match child.wait() {
|
||||
|
||||
+11
-56
@@ -1,59 +1,12 @@
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
extern crate syscall;
|
||||
|
||||
use std::{env, slice};
|
||||
use syscall::io::{Mmio, Io};
|
||||
use std::env;
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct XhciCap {
|
||||
len: Mmio<u8>,
|
||||
_rsvd: Mmio<u8>,
|
||||
hci_ver: Mmio<u16>,
|
||||
hcs_params1: Mmio<u32>,
|
||||
hcs_params2: Mmio<u32>,
|
||||
hcs_params3: Mmio<u32>,
|
||||
hcc_params1: Mmio<u32>,
|
||||
db_offset: Mmio<u32>,
|
||||
rts_offset: Mmio<u32>,
|
||||
hcc_params2: Mmio<u32>
|
||||
}
|
||||
use xhci::Xhci;
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct XhciOp {
|
||||
usb_cmd: Mmio<u32>,
|
||||
usb_std: Mmio<u32>,
|
||||
page_size: Mmio<u32>,
|
||||
_rsvd: [Mmio<u32>; 2],
|
||||
dn_ctrl: Mmio<u32>,
|
||||
crcr: [Mmio<u32>; 2],
|
||||
_rsvd2: [Mmio<u32>; 4],
|
||||
dcbaap: [Mmio<u32>; 2],
|
||||
config: Mmio<u32>,
|
||||
}
|
||||
|
||||
pub struct Xhci {
|
||||
cap: &'static mut XhciCap,
|
||||
op: &'static mut XhciOp,
|
||||
ports: &'static mut [Mmio<u32>]
|
||||
}
|
||||
|
||||
impl Xhci {
|
||||
pub fn new(address: usize) -> Xhci {
|
||||
let cap = unsafe { &mut *(address as *mut XhciCap) };
|
||||
|
||||
let op_base = address + cap.len.read() as usize;
|
||||
let op = unsafe { &mut *(op_base as *mut XhciOp) };
|
||||
|
||||
let port_base = op_base + 0x400;
|
||||
let port_len = ((cap.hcs_params1.read() & 0xFF000000) >> 24) as usize;
|
||||
let ports = unsafe { slice::from_raw_parts_mut(port_base as *mut Mmio<u32>, port_len) };
|
||||
|
||||
Xhci {
|
||||
cap: cap,
|
||||
op: op,
|
||||
ports: ports
|
||||
}
|
||||
}
|
||||
}
|
||||
mod xhci;
|
||||
|
||||
fn main() {
|
||||
let mut args = env::args().skip(1);
|
||||
@@ -69,10 +22,12 @@ 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") };
|
||||
{
|
||||
let mut xhci = Xhci::new(address);
|
||||
for (i, port) in xhci.ports.iter().enumerate() {
|
||||
println!("XHCI Port {}: {:X}", i, port.read());
|
||||
match Xhci::new(address) {
|
||||
Ok(mut xhci) => {
|
||||
xhci.init();
|
||||
},
|
||||
Err(err) => {
|
||||
println!("xhcid: error: {}", err);
|
||||
}
|
||||
}
|
||||
unsafe { let _ = syscall::physunmap(address); }
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
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,
|
||||
}
|
||||
|
||||
impl Trb {
|
||||
pub fn from_type(trb_type: u32) -> Self {
|
||||
Trb {
|
||||
data: 0,
|
||||
status: 0,
|
||||
control: (trb_type & 0x3F) << 10,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct XhciCap {
|
||||
len: Mmio<u8>,
|
||||
_rsvd: Mmio<u8>,
|
||||
hci_ver: Mmio<u16>,
|
||||
hcs_params1: Mmio<u32>,
|
||||
hcs_params2: Mmio<u32>,
|
||||
hcs_params3: Mmio<u32>,
|
||||
hcc_params1: Mmio<u32>,
|
||||
db_offset: Mmio<u32>,
|
||||
rts_offset: Mmio<u32>,
|
||||
hcc_params2: Mmio<u32>
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct XhciOp {
|
||||
usb_cmd: Mmio<u32>,
|
||||
usb_sts: Mmio<u32>,
|
||||
page_size: Mmio<u32>,
|
||||
_rsvd: [Mmio<u32>; 2],
|
||||
dn_ctrl: Mmio<u32>,
|
||||
crcr: Mmio<u64>,
|
||||
_rsvd2: [Mmio<u32>; 4],
|
||||
dcbaap: Mmio<u64>,
|
||||
config: Mmio<u32>,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
flags XhciPortFlags: u32 {
|
||||
const PORT_CCS = 1 << 0,
|
||||
const PORT_PED = 1 << 1,
|
||||
const PORT_OCA = 1 << 3,
|
||||
const PORT_PR = 1 << 4,
|
||||
const PORT_PP = 1 << 9,
|
||||
const PORT_PIC_AMB = 1 << 14,
|
||||
const PORT_PIC_GRN = 1 << 15,
|
||||
const PORT_LWS = 1 << 16,
|
||||
const PORT_CSC = 1 << 17,
|
||||
const PORT_PEC = 1 << 18,
|
||||
const PORT_WRC = 1 << 19,
|
||||
const PORT_OCC = 1 << 20,
|
||||
const PORT_PRC = 1 << 21,
|
||||
const PORT_PLC = 1 << 22,
|
||||
const PORT_CEC = 1 << 23,
|
||||
const PORT_CAS = 1 << 24,
|
||||
const PORT_WCE = 1 << 25,
|
||||
const PORT_WDE = 1 << 26,
|
||||
const PORT_WOE = 1 << 27,
|
||||
const PORT_DR = 1 << 30,
|
||||
const PORT_WPR = 1 << 31,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct XhciPort(Mmio<u32>);
|
||||
|
||||
impl XhciPort {
|
||||
fn read(&self) -> u32 {
|
||||
self.0.read()
|
||||
}
|
||||
|
||||
fn state(&self) -> u32 {
|
||||
(self.read() & (0b111 << 5)) >> 5
|
||||
}
|
||||
|
||||
fn speed(&self) -> u32 {
|
||||
(self.read() & (0b1111 << 10)) >> 10
|
||||
}
|
||||
|
||||
fn flags(&self) -> XhciPortFlags {
|
||||
XhciPortFlags::from_bits_truncate(self.read())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct XhciDoorbell(Mmio<u32>);
|
||||
|
||||
impl XhciDoorbell {
|
||||
fn read(&self) -> u32 {
|
||||
self.0.read()
|
||||
}
|
||||
|
||||
fn write(&mut self, data: u32) {
|
||||
self.0.write(data);
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct XhciSlotContext {
|
||||
inner: [u8; 32]
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct XhciEndpointContext {
|
||||
inner: [u8; 32]
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct XhciDeviceContext {
|
||||
slot: XhciSlotContext,
|
||||
endpoints: [XhciEndpointContext; 15]
|
||||
}
|
||||
|
||||
pub struct Xhci {
|
||||
cap: &'static mut XhciCap,
|
||||
op: &'static mut XhciOp,
|
||||
ports: &'static mut [XhciPort],
|
||||
dbs: &'static mut [XhciDoorbell],
|
||||
dev_baa: Dma<[u64; 256]>,
|
||||
dev_ctxs: Vec<Dma<XhciDeviceContext>>,
|
||||
cmds: Dma<[Trb; 256]>,
|
||||
}
|
||||
|
||||
impl Xhci {
|
||||
pub fn new(address: usize) -> Result<Xhci> {
|
||||
let cap = unsafe { &mut *(address as *mut XhciCap) };
|
||||
|
||||
let op_base = address + cap.len.read() as usize;
|
||||
let op = unsafe { &mut *(op_base as *mut XhciOp) };
|
||||
|
||||
let max_slots;
|
||||
let max_ports;
|
||||
|
||||
{
|
||||
// Wait until controller is ready
|
||||
while op.usb_sts.readf(1 << 11) {
|
||||
println!(" - Waiting for XHCI ready");
|
||||
}
|
||||
|
||||
// Set run/stop to 0
|
||||
op.usb_cmd.writef(1, false);
|
||||
|
||||
// Wait until controller not running
|
||||
while ! op.usb_sts.readf(1) {
|
||||
println!(" - Waiting for XHCI stopped");
|
||||
}
|
||||
|
||||
// Read maximum slots and ports
|
||||
let hcs_params1 = cap.hcs_params1.read();
|
||||
max_slots = hcs_params1 & 0xFF;
|
||||
max_ports = (hcs_params1 & 0xFF000000) >> 24;
|
||||
|
||||
println!(" - Max Slots: {}, Max Ports {}", max_slots, max_ports);
|
||||
|
||||
// Set enabled slots
|
||||
op.config.write(max_slots);
|
||||
println!(" - Enabled Slots: {}", op.config.read() & 0xFF);
|
||||
}
|
||||
|
||||
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 dbs = unsafe { slice::from_raw_parts_mut(db_base as *mut XhciDoorbell, 256) };
|
||||
|
||||
let mut xhci = Xhci {
|
||||
cap: cap,
|
||||
op: op,
|
||||
ports: ports,
|
||||
dbs: dbs,
|
||||
dev_baa: Dma::zeroed()?,
|
||||
dev_ctxs: Vec::new(),
|
||||
cmds: Dma::zeroed()?,
|
||||
};
|
||||
|
||||
{
|
||||
// Create device context buffers for each slot
|
||||
for i in 0..max_slots as usize {
|
||||
let dev_ctx: Dma<XhciDeviceContext> = Dma::zeroed()?;
|
||||
xhci.dev_baa[i] = dev_ctx.physical() as u64;
|
||||
xhci.dev_ctxs.push(dev_ctx);
|
||||
}
|
||||
|
||||
// Set device context address array pointer
|
||||
xhci.op.dcbaap.write(xhci.dev_baa.physical() as u64);
|
||||
|
||||
// Set command ring control register
|
||||
xhci.op.crcr.write(xhci.cmds.physical() as u64);
|
||||
|
||||
// Set run/stop to 1
|
||||
xhci.op.usb_cmd.writef(1, true);
|
||||
|
||||
// Wait until controller is running
|
||||
while xhci.op.usb_sts.readf(1) {
|
||||
println!(" - Waiting for XHCI running");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(xhci)
|
||||
}
|
||||
|
||||
pub fn init(&mut self) {
|
||||
for (i, port) in self.ports.iter().enumerate() {
|
||||
let data = port.read();
|
||||
let state = port.state();
|
||||
let speed = port.speed();
|
||||
let flags = port.flags();
|
||||
println!(" + XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", i, data, state, speed, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user