Commit 096a9a6e authored by Jeremy Soller's avatar Jeremy Soller

Read device, config, interface, and endpoint descriptions

parent dbceebbc
......@@ -3,6 +3,7 @@ name = "xhcid"
version = "0.1.0"
dependencies = [
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"plain 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
"spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
......@@ -352,6 +353,11 @@ name = "percent-encoding"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "plain"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ps2d"
version = "0.1.0"
......@@ -726,6 +732,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba"
"checksum orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9411f6bf9f60d65de1dcb601735ac0c904960f0f6ca03a13e6f02d25f842ea2c"
"checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356"
"checksum plain 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da55423d5704ee357503ce020f88b90269610ec85708331e6a7879dd4cea3122"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf"
"checksum ransid 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "754ed82fc56508fc1353f0ab24affd4b055683a8ad4d53d39f7e4d8764c3efa4"
......
......@@ -4,5 +4,6 @@ version = "0.1.0"
[dependencies]
bitflags = "0.7"
plain = "0.2"
spin = "0.4"
redox_syscall = "0.1"
#[macro_use]
extern crate bitflags;
extern crate plain;
extern crate syscall;
use std::env;
use xhci::Xhci;
mod usb;
mod xhci;
fn main() {
......@@ -35,5 +37,7 @@ fn main() {
}
unsafe { let _ = syscall::physunmap(address); }
let _ = syscall::kill(1, syscall::SIGINT);
}
}
#[repr(packed)]
#[derive(Clone, Copy, Debug, Default)]
pub struct ConfigDescriptor {
pub length: u8,
pub kind: u8,
pub total_length: u16,
pub interfaces: u8,
pub configuration_value: u8,
pub configuration_str: u8,
pub attributes: u8,
pub max_power: u8,
}
#[repr(packed)]
#[derive(Clone, Copy, Debug, Default)]
pub struct DeviceDescriptor {
pub length: u8,
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: u8,
pub product_str: u8,
pub serial_str: u8,
pub configurations: u8,
}
use plain::Plain;
#[repr(packed)]
#[derive(Clone, Copy, Debug, Default)]
pub struct EndpointDescriptor {
pub length: u8,
pub kind: u8,
pub address: u8,
pub attributes: u8,
pub max_packet_size: u16,
pub interval: u8,
}
unsafe impl Plain for EndpointDescriptor {}
use plain::Plain;
#[repr(packed)]
#[derive(Clone, Copy, Debug, Default)]
pub struct InterfaceDescriptor {
pub length: u8,
pub kind: u8,
pub number: u8,
pub alternate_setting: u8,
pub endpoints: u8,
pub class: u8,
pub sub_class: u8,
pub protocol: u8,
pub interface_str: u8,
}
unsafe impl Plain for InterfaceDescriptor {}
pub use self::config::ConfigDescriptor;
pub use self::device::DeviceDescriptor;
pub use self::endpoint::EndpointDescriptor;
pub use self::interface::InterfaceDescriptor;
pub use self::setup::Setup;
#[repr(u8)]
pub enum DescriptorKind {
None,
Device,
Configuration,
String,
Interface,
Endpoint,
DeviceQualifier,
OtherSpeedConfiguration,
InterfacePower,
OnTheGo,
}
mod config;
mod device;
mod endpoint;
mod interface;
mod setup;
use super::DescriptorKind;
#[repr(packed)]
#[derive(Clone, Copy, Debug, Default)]
pub struct Setup {
pub kind: u8,
pub request: u8,
pub value: u16,
pub index: u16,
pub length: u16,
}
impl Setup {
pub fn get_status() -> Self {
Self {
kind: 0b1000_0000,
request: 0x00,
value: 0,
index: 0,
length: 2,
}
}
pub fn clear_feature(feature: u16) -> Self {
Self {
kind: 0b0000_0000,
request: 0x01,
value: feature,
index: 0,
length: 0,
}
}
pub fn set_feature(feature: u16) -> Self {
Self {
kind: 0b0000_0000,
request: 0x03,
value: feature,
index: 0,
length: 0,
}
}
pub fn set_address(address: u16) -> Self {
Self {
kind: 0b0000_0000,
request: 0x05,
value: address,
index: 0,
length: 0,
}
}
pub fn get_descriptor(kind: DescriptorKind, index: u8, language: u16, length: u16) -> Self {
Self {
kind: 0b1000_0000,
request: 0x06,
value: ((kind as u16) << 8) | (index as u16),
index: language,
length: length,
}
}
pub fn set_descriptor(kind: u8, index: u8, language: u16, length: u16) -> Self {
Self {
kind: 0b0000_0000,
request: 0x07,
value: ((kind as u16) << 8) | (index as u16),
index: language,
length: length,
}
}
pub fn get_configuration() -> Self {
Self {
kind: 0b1000_0000,
request: 0x08,
value: 0,
index: 0,
length: 1,
}
}
pub fn set_configuration(value: u16) -> Self {
Self {
kind: 0b0000_0000,
request: 0x09,
value: value,
index: 0,
length: 0,
}
}
}
......@@ -25,6 +25,22 @@ impl CommandRing {
self.trbs.physical() as u64 | 1
}
pub fn next(&mut self) -> (&mut Trb, &mut Trb) {
let cmd_i = self.cmd_i;
self.cmd_i += 1;
if self.cmd_i >= self.trbs.len() {
self.cmd_i = 0;
}
let event_i = self.event_i;
self.event_i += 1;
if self.event_i >= self.events.trbs.len() {
self.event_i = 0;
}
(&mut self.trbs[cmd_i], &mut self.events.trbs[event_i])
}
pub fn next_cmd(&mut self) -> &mut Trb {
let i = self.cmd_i;
self.cmd_i += 1;
......
use std::slice;
use plain::Plain;
use std::{mem, slice};
use syscall::error::Result;
use syscall::io::{Dma, Io};
use usb;
mod capability;
mod command;
......@@ -19,6 +21,58 @@ use self::doorbell::Doorbell;
use self::operational::OperationalRegs;
use self::port::Port;
use self::runtime::RuntimeRegs;
use self::trb::TransferKind;
struct Device<'a> {
trbs: Dma<[trb::Trb; 256]>,
trb_i: usize,
cmd: &'a mut CommandRing,
db: &'a mut Doorbell,
}
impl<'a> Device<'a> {
fn get_desc<T>(&mut self, kind: usb::DescriptorKind, index: u8, desc: &mut Dma<T>) {
let len = mem::size_of::<T>();
self.trbs[self.trb_i].setup(
usb::Setup::get_descriptor(kind, index, 0, len as u16),
TransferKind::In, true
);
self.trbs[self.trb_i + 1].data(desc.physical(), len as u16, true, true);
self.trbs[self.trb_i + 2].status(false, true);
self.db.write(1);
let event = self.cmd.next_event();
while event.data.read() == 0 {
println!(" - Waiting for event");
}
for _i in 0..3 {
self.trbs[self.trb_i].reserved(false);
self.trb_i += 1;
}
event.reserved(false);
}
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
);
let len = sdesc.0 as usize;
if len > 2 {
Ok(String::from_utf16(&sdesc.2[.. (len - 2)/2]).unwrap_or(String::new()))
} else {
Ok(String::new())
}
}
}
pub struct Xhci {
cap: &'static mut CapabilityRegs,
......@@ -150,39 +204,33 @@ impl Xhci {
println!(" + XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", i, data, state, speed, flags);
if flags.contains(port::PORT_CCS) {
println!(" - Running Enable Slot command");
let db = &mut self.dbs[0];
let crcr = &mut self.op.crcr;
let mut run = || {
db.write(0);
while crcr.readf(1 << 3) {
println!(" - Waiting for command completion");
}
};
//TODO: Link TRB when running to the end of the ring buffer
println!(" - Enable slot");
let slot;
{
let cmd = self.cmd.next_cmd();
let (cmd, event) = self.cmd.next();
cmd.enable_slot(0, true);
println!(" - Command: {}", cmd);
run();
cmd.reserved(false);
}
self.dbs[0].write(0);
let slot;
{
let event = self.cmd.next_event();
while event.data.read() == 0 {
println!(" - Waiting for event");
}
println!(" - Response: {}", event);
slot = (event.control.read() >> 24) as u8;
cmd.reserved(false);
event.reserved(false);
}
println!(" Slot {}", slot);
println!(" - Slot {}", slot);
let mut trbs = Dma::<[trb::Trb; 256]>::zeroed()?;
let mut trb_i = 0;
let mut input = Dma::<device::InputContext>::zeroed()?;
{
input.add_context.write(1 << 1 | 1);
......@@ -197,22 +245,89 @@ impl Xhci {
}
{
let cmd = self.cmd.next_cmd();
let (cmd, event) = self.cmd.next();
cmd.address_device(slot, input.physical(), true);
println!(" - Command: {}", cmd);
run();
self.dbs[0].write(0);
while event.data.read() == 0 {
println!(" - Waiting for event");
}
println!(" - Response: {}", event);
cmd.reserved(false);
event.reserved(false);
}
let address;
{
let event = self.cmd.next_event();
println!(" - Response: {}", event);
address = (event.control.read() >> 24) as u8;
let mut dev = Device {
trbs: trbs,
trb_i: trb_i,
cmd: &mut self.cmd,
db: &mut self.dbs[slot as usize],
};
event.reserved(false);
println!(" - Get descriptor");
let mut ddesc = Dma::<usb::DeviceDescriptor>::zeroed()?;
dev.get_desc(
usb::DescriptorKind::Device,
0,
&mut ddesc
);
println!("{:?}", *ddesc);
if ddesc.manufacturer_str > 0 {
println!(" Manufacturer: {}", dev.get_string(ddesc.manufacturer_str)?);
}
if ddesc.product_str > 0 {
println!(" Product: {}", dev.get_string(ddesc.product_str)?);
}
if ddesc.serial_str > 0 {
println!(" Serial: {}", dev.get_string(ddesc.serial_str)?);
}
for config in 0..ddesc.configurations {
let mut cdesc = Dma::<(usb::ConfigDescriptor, [u8; 4087])>::zeroed()?;
dev.get_desc(
usb::DescriptorKind::Configuration,
config,
&mut cdesc
);
println!(" {}: {:?}", config, cdesc.0);
if cdesc.0.configuration_str > 0 {
println!(" Name: {}", dev.get_string(cdesc.0.configuration_str)?);
}
if cdesc.0.total_length as usize > mem::size_of::<usb::ConfigDescriptor>() {
let len = cdesc.0.total_length as usize - mem::size_of::<usb::ConfigDescriptor>();
let data = &cdesc.1[..len];
let mut i = 0;
for interface in 0..cdesc.0.interfaces {
let mut idesc = usb::InterfaceDescriptor::default();
if i < data.len() && idesc.copy_from_bytes(&data[i..]).is_ok() {
i += mem::size_of_val(&idesc);
println!(" {}: {:?}", interface, idesc);
if idesc.interface_str > 0 {
println!(" Name: {}", dev.get_string(idesc.interface_str)?);
}
for endpoint in 0..idesc.endpoints {
let mut edesc = usb::EndpointDescriptor::default();
if i < data.len() && edesc.copy_from_bytes(&data[i..]).is_ok() {
i += mem::size_of_val(&edesc);
println!(" {}: {:?}", endpoint, edesc);
}
}
}
}
}
}
}
}
......
use std::fmt;
use std::{fmt, mem};
use syscall::io::{Io, Mmio};
use usb;
#[repr(u8)]
pub enum TrbType {
......@@ -94,6 +95,14 @@ pub enum TrbCompletionCode {
/* 224 to 255 are vendor defined information */
}
#[repr(u8)]
pub enum TransferKind {
NoData,
Reserved,
Out,
In,
}
#[repr(packed)]
pub struct Trb {
pub data: Mmio<u64>,
......@@ -102,31 +111,74 @@ pub struct Trb {
}
impl Trb {
pub fn reset(&mut self, param: u64, status: u32, control: u16, trb_type: TrbType, cycle: bool) {
let full_control =
(control as u32) << 16 |
((trb_type as u32) & 0x3F) << 10 |
if cycle { 1 << 0 } else { 0 };
self.data.write(param);
self.status.write(status);
self.control.write(full_control);
}
pub fn reserved(&mut self, cycle: bool) {
self.reset(0, 0, 0, TrbType::Reserved, cycle);
self.data.write(0);
self.status.write(0);
self.control.write(
((TrbType::Reserved as u32) << 10) |
(cycle as u32)
);
}
pub fn no_op_cmd(&mut self, cycle: bool) {
self.reset(0, 0, 0, TrbType::NoOpCmd, cycle);
self.data.write(0);
self.status.write(0);
self.control.write(
((TrbType::NoOpCmd as u32) << 10) |
(cycle as u32)
);
}
pub fn enable_slot(&mut self, slot_type: u8, cycle: bool) {
self.reset(0, 0, (slot_type as u16) & 0x1F, TrbType::EnableSlot, cycle);
self.data.write(0);
self.status.write(0);
self.control.write(
(((slot_type as u32) & 0x1F) << 16) |
((TrbType::EnableSlot as u32) << 10) |
(cycle as u32)
);
}
pub fn address_device(&mut self, slot_id: u8, input: usize, cycle: bool) {
self.reset(input as u64, 0, (slot_id as u16) << 8, TrbType::AddressDevice, cycle);
self.data.write(input as u64);
self.status.write(0);
self.control.write(
((slot_id as u32) << 24) |
((TrbType::AddressDevice as u32) << 10) |
(cycle as u32)
);
}
pub fn setup(&mut self, setup: usb::Setup, transfer: TransferKind, cycle: bool) {
self.data.write(unsafe { mem::transmute(setup) });
self.status.write((0 << 22) | 8);
self.control.write(
((transfer as u32) << 16) |
((TrbType::SetupStage as u32) << 10) |
(1 << 6) |
(cycle as u32)
);
}
pub fn data(&mut self, buffer: usize, length: u16, input: bool, cycle: bool) {
self.data.write(buffer as u64);
self.status.write((0 << 22) | length as u32);
self.control.write(
((input as u32) << 16) |
((TrbType::DataStage as u32) << 10) |
(cycle as u32)
);
}
pub fn status(&mut self, input: bool, cycle: bool) {
self.data.write(0);
self.status.write(0 << 22);
self.control.write(
((input as u32) << 16) |
((TrbType::StatusStage as u32) << 10) |
(1 << 5) |
(cycle as u32)
);
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment