Skip to content
Snippets Groups Projects
Commit baea5f70 authored by John Hodge's avatar John Hodge
Browse files

Kernel - Fiddling around with USB

parent af76d2a2
No related merge requests found
...@@ -46,6 +46,11 @@ pub struct Object<'a> ...@@ -46,6 +46,11 @@ pub struct Object<'a>
/// Async call stack /// Async call stack
stack: Spinlock<AsyncStack<'a>>, stack: Spinlock<AsyncStack<'a>>,
} }
#[cfg(_false)]
pub struct VoidObject
{
inner: ObjectInner,
}
#[derive(Default)] #[derive(Default)]
struct ObjectInner struct ObjectInner
{ {
...@@ -86,6 +91,41 @@ impl<'a> Object<'a> ...@@ -86,6 +91,41 @@ impl<'a> Object<'a>
pub fn get_stack<'s>(&'s mut self) -> StackPush<'s, 'a> { pub fn get_stack<'s>(&'s mut self) -> StackPush<'s, 'a> {
StackPush::new(self.stack.get_mut()) StackPush::new(self.stack.get_mut())
} }
fn check(&self, idx: usize) -> Option<usize> {
let mut res = self.inner.result.lock().take();
while let Some(res_val) = res
{
// There's a result waiting!
let mut stack_lh = self.stack.lock();
// If there's no handler, return.
if stack_lh.is_empty()
{
log_debug!("check_one: {} result {:#x}", idx, res_val);
return Some(res_val);
}
log_debug!("check_one: {} advance {:#x}", idx, res_val);
// Stack has an entry, so pass the value on to that entry.
let test_ptr: *mut ();
res = {
// - Magic handle that only allows pushing to this (append-only) stack
let (magic_handle, top) = StackPush::new_with_top(&mut stack_lh);
test_ptr = top as *mut _ as *mut ();
top.advance(self.get_handle(), magic_handle, res_val)
};
// If this returns non-None, then pop and continue
if res.is_some()
{
assert!( !stack_lh.is_empty() );
assert_eq!( stack_lh.top_mut().unwrap() as *mut _ as *mut (), test_ptr, "Non-None return from async advance, but it also registered callbacks." );
stack_lh.pop();
}
}
None
}
} }
impl ObjectHandle impl ObjectHandle
{ {
...@@ -127,36 +167,9 @@ impl<'h, 'a: 'h> Waiter<'h, 'a> ...@@ -127,36 +167,9 @@ impl<'h, 'a: 'h> Waiter<'h, 'a>
{ {
for (idx,h) in Iterator::enumerate(self.handles.iter()) for (idx,h) in Iterator::enumerate(self.handles.iter())
{ {
let mut res = h.inner.result.lock().take(); if let Some(res_val) = h.check(idx)
while let Some(res_val) = res
{ {
// There's a result waiting! return Some(WaitResult { slot: idx, result: res_val });
let mut stack_lh = h.stack.lock();
// If there's no handler, return.
if stack_lh.is_empty()
{
log_debug!("check_one: {} result {:#x}", idx, res_val);
return Some(WaitResult { slot: idx, result: res_val });
}
log_debug!("check_one: {} advance {:#x}", idx, res_val);
// Stack has an entry, so pass the value on to that entry.
let test_ptr: *mut ();
res = {
// - Magic handle that only allows pushing to this (append-only) stack
let (magic_handle, top) = StackPush::new_with_top(&mut stack_lh);
test_ptr = top as *mut _ as *mut ();
top.advance(h.get_handle(), magic_handle, res_val)
};
// If this returns non-None, then pop and continue
if res.is_some()
{
assert!( !stack_lh.is_empty() );
assert_eq!( stack_lh.top_mut().unwrap() as *mut _ as *mut (), test_ptr, "Non-None return from async advance, but it also registered callbacks." );
stack_lh.pop();
}
} }
} }
......
...@@ -33,28 +33,36 @@ struct Host ...@@ -33,28 +33,36 @@ struct Host
next_id: u8, next_id: u8,
used_ids: [u8; 128/8], used_ids: [u8; 128/8],
//endpoint_zero_state: (), //// If true, EP0 is currently being enumerated
//endpoint_zero_state: bool,
} }
struct HubDevice struct HubDevice
{ {
host: ArefBorrow<Host>, host: ArefBorrow<Host>,
int_ep: host::Handle<host::InterruptEndpoint>, int_ep: host::Handle<host::InterruptEndpoint>,
} }
///// An endpoint currently being enumerated
//struct EnumeratingDevice
//{
// obj: async::Object,
//}
static WATCH_LIST: ::kernel::sync::Mutex<Vec<Meta>> = ::kernel::sync::Mutex::new(Vec::new_const()); static WATCH_LIST: ::kernel::sync::Mutex<Vec<Meta>> = ::kernel::sync::Mutex::new(Vec::new_const());
static EVENT_QUEUE: ::kernel::sync::Queue<(usize, usize)> = ::kernel::sync::Queue::new_const(); static EVENT_QUEUE: ::kernel::sync::Queue<(usize, usize)> = ::kernel::sync::Queue::new_const();
//static ENUM_ENDPOINTS: ::kernel::sync::Mutex<Vec<Box<Endpoint>>> = ::kernel::sync::Mutex::new(Vec::new_const());
pub fn register_host(mut h: Box<host::HostController>) pub fn register_host(mut h: Box<host::HostController>)
{ {
let mut lh = WATCH_LIST.lock(); let mut lh = WATCH_LIST.lock();
let idx = lh.len(); let idx = lh.len();
// Note: Setting the root waiter should trigger event pushes for any connected port
// - This doesn't race, because the list lock is still held.
h.set_root_waiter(&EVENT_QUEUE, idx); h.set_root_waiter(&EVENT_QUEUE, idx);
lh.push(Meta::RootHub(Aref::new(Host { lh.push(Meta::RootHub(Aref::new(Host {
driver: h, driver: h,
next_id: 1, next_id: 1,
used_ids: [0; 128/8], used_ids: [0; 128/8],
}))); })));
// TODO: Wake the worker and get it to check the root hub.
} }
fn worker_thread() fn worker_thread()
...@@ -74,11 +82,21 @@ fn worker_thread() ...@@ -74,11 +82,21 @@ fn worker_thread()
} }
} }
} }
//fn enum_worker_thread()
//{
// loop
// {
// // 1. Register sleeps on new endpoints
// // - Get device descriptor
// // - Enumerate available configurations
// }
//}
impl Host impl Host
{ {
fn handle_root_event(&self, port_idx: usize) fn handle_root_event(&self, port_idx: usize)
{ {
log_debug!("handle_root_event: ({})", port_idx);
// TODO: Support timing port updates by using large values of `port_idx` // TODO: Support timing port updates by using large values of `port_idx`
if self.driver.get_port_feature(port_idx, host::PortFeature::CConnection) if self.driver.get_port_feature(port_idx, host::PortFeature::CConnection)
{ {
...@@ -88,7 +106,19 @@ impl Host ...@@ -88,7 +106,19 @@ impl Host
// Connection detected, either: // Connection detected, either:
// - Trigger a reset (and record this port as the next EP0) // - Trigger a reset (and record this port as the next EP0)
// - OR, add to a list of to-be-enumerated ports (if EP0 is already in use) // - OR, add to a list of to-be-enumerated ports (if EP0 is already in use)
self.driver.set_port_feature(port_idx, host::PortFeature::Reset); if self.driver.get_port_feature(port_idx, host::PortFeature::Power)
{
//if self.endpoint_zero_in_use {
//}
//else {
// self.endpoint_zero_in_use = true;
self.driver.set_port_feature(port_idx, host::PortFeature::Reset);
//}
}
else
{
todo!("Power on a newly connected port");
}
} }
else else
{ {
...@@ -97,19 +127,31 @@ impl Host ...@@ -97,19 +127,31 @@ impl Host
todo!("Handle port disconnection"); todo!("Handle port disconnection");
} }
} }
else if self.driver.get_port_feature(port_idx, host::PortFeature::CEnable) else if self.driver.get_port_feature(port_idx, host::PortFeature::CReset)
{ {
self.driver.clear_port_feature(port_idx, host::PortFeature::CEnable); self.driver.clear_port_feature(port_idx, host::PortFeature::CReset);
if self.driver.get_port_feature(port_idx, host::PortFeature::Enable) if self.driver.get_port_feature(port_idx, host::PortFeature::Reset)
{ {
// Hand over to EP0 enumeration. }
else if self.driver.get_port_feature(port_idx, host::PortFeature::Enable)
{
// Allocate an ID, allocate a , send the 'set device ID' request
todo!("Push new device to enumeration"); todo!("Push new device to enumeration");
} }
else else
{ {
todo!("Handle port being disabled?"); // Reset complete, but not enabled?
todo!("Handle port completing reset, but not being enabled?");
} }
} }
else if self.driver.get_port_feature(port_idx, host::PortFeature::CEnable)
{
self.driver.clear_port_feature(port_idx, host::PortFeature::CEnable);
log_debug!("Change in enable status...");
}
else
{
}
} }
} }
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
use kernel::prelude::*; use kernel::prelude::*;
use kernel::_async3 as async; use kernel::_async3 as async;
use kernel::lib::mem::aref::{Aref,ArefBorrow}; use kernel::lib::mem::aref::{Aref,ArefBorrow};
use core::sync::atomic::{AtomicPtr,Ordering}; use core::sync::atomic::{AtomicPtr,AtomicUsize,Ordering};
#[macro_use] #[macro_use]
extern crate kernel; extern crate kernel;
...@@ -37,6 +37,8 @@ struct HostInner ...@@ -37,6 +37,8 @@ struct HostInner
irq_handle: Option<::kernel::irqs::ObjectHandle>, irq_handle: Option<::kernel::irqs::ObjectHandle>,
hcca_handle: ::kernel::memory::virt::AllocHandle, hcca_handle: ::kernel::memory::virt::AllocHandle,
nports: u8, nports: u8,
waiter_idx: AtomicUsize,
waiter_ptr: AtomicPtr<::kernel::sync::Queue<(usize,usize)>>,
} }
struct IoWrapper(::kernel::device_manager::IOBinding); struct IoWrapper(::kernel::device_manager::IOBinding);
...@@ -229,6 +231,8 @@ impl HostInner ...@@ -229,6 +231,8 @@ impl HostInner
hcca_handle: handle_hcca, hcca_handle: handle_hcca,
nports: nports, nports: nports,
irq_handle: None, // Filled below, once the allocation is made irq_handle: None, // Filled below, once the allocation is made
waiter_idx: Default::default(),
waiter_ptr: Default::default(),
}); });
// Bind interrupt // Bind interrupt
...@@ -249,9 +253,58 @@ impl HostInner ...@@ -249,9 +253,58 @@ impl HostInner
let v = self.io.read_reg(hw::Regs::HcInterruptStatus); let v = self.io.read_reg(hw::Regs::HcInterruptStatus);
if v != 0 if v != 0
{ {
log_trace!("handle_irq: {:#x}", v);
// SchedulingOverrun
if v & 0x01 != 0
{
log_notice!("USB Scheduling Overrun");
}
// WritebackDoneHead
if v & 0x02 != 0
{
log_debug!("WritebackDoneHead - ");
// TODO: Clear the contents of HccaDoneHead, releasing and completing those TDs
}
// StartofFrame (disabled)
if v & 0x04 != 0
{
}
// ResumeDetected
if v & 0x08 != 0
{
// A device is asking for a resume?
}
// UnrecoverableError
if v & 0x10 != 0
{
log_error!("Unrecoverable error!");
}
// FrameNumberOverflow
if v & 0x20 != 0
{
// Frame number has reached 2^15
}
// RootHubStatusChange
if v & 0x40 != 0
{
// A change to any of the root hub registers
for i in 0 .. self.nports
{
let v = self.io.read_reg(self.get_port_reg(i as usize));
if v & 0xFFFF_0000 != 0 {
log_debug!("Status change on port {} = {:#x}", i, v);
let host_idx = self.waiter_idx.load(Ordering::Relaxed);
let queue_ptr = self.waiter_ptr.load(Ordering::Relaxed);
// SAFE: If this is set, it's to a &'static
unsafe { (*queue_ptr).push( (host_idx, i as usize) ); }
}
}
}
// SAFE: Write clear, no memory unsafety // SAFE: Write clear, no memory unsafety
unsafe { self.io.write_reg(hw::Regs::HcInterruptStatus, v) }; unsafe { self.io.write_reg(hw::Regs::HcInterruptStatus, v) };
log_trace!("handle_irq: {:#x}", v);
true true
} }
...@@ -384,6 +437,14 @@ impl HostInner ...@@ -384,6 +437,14 @@ impl HostInner
}, },
} }
} }
fn get_port_reg(&self, port: usize) -> hw::Regs
{
assert!(port < 16);
assert!(port < self.nports as usize);
// SAFE: Bounds are checked to fit within the alowable range for the enum
unsafe { ::core::mem::transmute(hw::Regs::HcRhPortStatus0 as usize + port) }
}
} }
use ::usb_core::host::{EndpointAddr, PortFeature, Handle}; use ::usb_core::host::{EndpointAddr, PortFeature, Handle};
...@@ -422,7 +483,7 @@ impl ::usb_core::host::HostController for UsbHost ...@@ -422,7 +483,7 @@ impl ::usb_core::host::HostController for UsbHost
// Root hub maintainence // Root hub maintainence
fn set_port_feature(&self, port: usize, feature: PortFeature) { fn set_port_feature(&self, port: usize, feature: PortFeature) {
log_trace!("set_port_feature({}, {:?})", port, feature); log_trace!("set_port_feature({}, {:?})", port, feature);
let r = self.get_port_reg(port); let r = self.host.get_port_reg(port);
// All bits only set on write (some clear on write, but those aren't handled here. // All bits only set on write (some clear on write, but those aren't handled here.
let v = match feature let v = match feature
{ {
...@@ -441,7 +502,7 @@ impl ::usb_core::host::HostController for UsbHost ...@@ -441,7 +502,7 @@ impl ::usb_core::host::HostController for UsbHost
} }
fn clear_port_feature(&self, port: usize, feature: PortFeature) { fn clear_port_feature(&self, port: usize, feature: PortFeature) {
log_trace!("clear_port_feature({}, {:?})", port, feature); log_trace!("clear_port_feature({}, {:?})", port, feature);
let r = self.get_port_reg(port); let r = self.host.get_port_reg(port);
// All bits only set on write (some clear on write, but those aren't handled here. // All bits only set on write (some clear on write, but those aren't handled here.
let v = match feature let v = match feature
{ {
...@@ -463,7 +524,7 @@ impl ::usb_core::host::HostController for UsbHost ...@@ -463,7 +524,7 @@ impl ::usb_core::host::HostController for UsbHost
} }
fn get_port_feature(&self, port: usize, feature: PortFeature) -> bool { fn get_port_feature(&self, port: usize, feature: PortFeature) -> bool {
log_trace!("get_port_feature({}, {:?})", port, feature); log_trace!("get_port_feature({}, {:?})", port, feature);
let r = self.get_port_reg(port); let r = self.host.get_port_reg(port);
let v = self.host.io.read_reg(r); let v = self.host.io.read_reg(r);
let mask = match feature let mask = match feature
{ {
...@@ -486,13 +547,13 @@ impl ::usb_core::host::HostController for UsbHost ...@@ -486,13 +547,13 @@ impl ::usb_core::host::HostController for UsbHost
} }
fn set_root_waiter(&mut self, waiter: &'static ::kernel::sync::Queue<(usize,usize)>, my_idx: usize) { fn set_root_waiter(&mut self, waiter: &'static ::kernel::sync::Queue<(usize,usize)>, my_idx: usize) {
// 1. Store the waiter pointer // 1. Store the waiter pointer
//self.host.waiter_idx.store(my_idx, Ordering::SeqCst); self.host.waiter_idx.store(my_idx, Ordering::SeqCst);
//self.host.waiter_ptr.store(waiter, Ordering::SeqCst); self.host.waiter_ptr.store(waiter as *const _ as *mut _, Ordering::SeqCst);
// 2. For each connected port, push an event/item // 2. For each connected port, push an event/item
// - Don't worry about duplicates from interrupts... // - Don't worry about duplicates from interrupts...
for i in 0 .. self.host.nports as usize for i in 0 .. self.host.nports as usize
{ {
let v = self.host.io.read_reg(self.get_port_reg(i)); let v = self.host.io.read_reg(self.host.get_port_reg(i));
log_debug!("set_root_waiter: Port {} - v={:#x}", i, v); log_debug!("set_root_waiter: Port {} - v={:#x}", i, v);
if v & 0x1 != 0 { if v & 0x1 != 0 {
waiter.push( (my_idx, i) ); waiter.push( (my_idx, i) );
...@@ -500,16 +561,6 @@ impl ::usb_core::host::HostController for UsbHost ...@@ -500,16 +561,6 @@ impl ::usb_core::host::HostController for UsbHost
} }
} }
} }
impl UsbHost
{
fn get_port_reg(&self, port: usize) -> hw::Regs
{
assert!(port < 16);
assert!(port < self.host.nports as usize);
// SAFE: Bounds are checked to fit within the alowable range for the enum
unsafe { ::core::mem::transmute(hw::Regs::HcRhPortStatus0 as usize + port) }
}
}
struct ControlEndpointHandle { struct ControlEndpointHandle {
controller: ArefBorrow<HostInner>, controller: ArefBorrow<HostInner>,
id: EndpointId, id: EndpointId,
......
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