diff --git a/Kernel/Core/async-v3/waiter.rs b/Kernel/Core/async-v3/waiter.rs index 4ff4402e8c72264fc2b709f762db7be1081ec1d6..0d5a2908349554fd904d6949e7e6de4f665ca1f0 100644 --- a/Kernel/Core/async-v3/waiter.rs +++ b/Kernel/Core/async-v3/waiter.rs @@ -158,7 +158,8 @@ impl<'h, 'a: 'h> Waiter<'h, 'a> pub fn new(handles: &'h [&'h Object<'a>]) -> Waiter<'h, 'a> { Waiter { - sleeper: SleepObject::new("Waiter"), + // SAFE: TODO: This isn't safe, the sleep object must have a stable pointer to be safe + sleeper: unsafe { SleepObject::new("Waiter") }, handles: handles, } } diff --git a/Kernel/Core/async/mod.rs b/Kernel/Core/async/mod.rs index 5c706ffa5e2aa6232043833c4148af109c5bca04..aca0e064ebe8c39ca7463893c485b7075cba332a 100644 --- a/Kernel/Core/async/mod.rs +++ b/Kernel/Core/async/mod.rs @@ -141,18 +141,19 @@ impl<'a> Waiter+'a { let completed = { let prim = self.get_waiter(); - let mut obj = ::threads::SleepObject::new("wait_on_list"); - log_trace!("- bind"); - if prim.bind_signal( &mut obj ) { - obj.wait(); - } - else { - while !prim.poll() { - // TODO: Take a nap + ::threads::SleepObject::with_new("wait_on_list", |obj_ref| { + log_trace!("- bind"); + if prim.bind_signal( obj_ref ) { + obj_ref.wait(); } - } - prim.unbind_signal(); - log_trace!("- sleep over"); + else { + while !prim.poll() { + // TODO: Take a nap + } + } + prim.unbind_signal(); + log_trace!("- sleep over"); + }); prim.is_ready() }; // completed = This cycle is done, not everything? @@ -201,46 +202,46 @@ pub fn wait_on_list(waiters: &mut [&mut Waiter], timeout: Option<u64>) -> Option } // - Create an object for them to signal - let mut obj = ::threads::SleepObject::new("wait_on_list"); - let force_poll = waiters.iter_mut() - .filter( |x| !x.is_complete() ) - .fold(false, |v,x| v | !x.get_waiter().bind_signal( &mut obj) ) - // ^ doesn't use .any() becuase of unbind_signal below - ; - - if force_poll - { - log_trace!("- Polling"); - let mut n_passes = 0; - // While none of the active waiters returns true from poll() - 'outer: loop + ::threads::SleepObject::with_new("wait_on_list", |obj| { + let force_poll = waiters.iter_mut() + .filter( |x| !x.is_complete() ) + .fold(false, |v,x| v | !x.get_waiter().bind_signal(obj) ) + // ^ doesn't use .any() becuase of unbind_signal below + ; + + if force_poll { - for w in waiters.iter_mut() + log_trace!("- Polling"); + let mut n_passes = 0; + // While none of the active waiters returns true from poll() + 'outer: loop { - if w.is_complete() { - } - else if w.get_waiter().poll() { - break 'outer; - } - else { + for w in waiters.iter_mut() + { + if w.is_complete() { + } + else if w.get_waiter().poll() { + break 'outer; + } + else { + } } + n_passes += 1; + // TODO: Take a short nap } - n_passes += 1; - // TODO: Take a short nap + log_trace!("- Fire ({} passes)", n_passes); } - log_trace!("- Fire ({} passes)", n_passes); - } - else - { - // - Wait the current thread on that object - log_trace!(" Sleeping"); - obj.wait(); - } - - for ent in waiters.iter_mut().filter(|x| !x.is_complete()) { - ent.get_waiter().unbind_signal(); - } - ::core::mem::drop(obj); + else + { + // - Wait the current thread on that object + log_trace!(" Sleeping"); + obj.wait(); + } + + for ent in waiters.iter_mut().filter(|x| !x.is_complete()) { + ent.get_waiter().unbind_signal(); + } + }); // Run completion handlers (via .is_ready and .complete), counting the number of changed waiters let mut n_complete = 0; diff --git a/Kernel/Core/irqs.rs b/Kernel/Core/irqs.rs index cca20a8158d9af1cf0e90a631e38f9714328ae85..5aa4c91f6a6afc5aa716c6f555519d53777230ae 100644 --- a/Kernel/Core/irqs.rs +++ b/Kernel/Core/irqs.rs @@ -46,9 +46,10 @@ static S_IRQ_WORKER_SIGNAL: ::lib::LazyStatic<::threads::SleepObject<'static>> = static S_IRQ_WORKER: ::lib::LazyStatic<::threads::WorkerThread> = lazystatic_init!(); pub fn init() { - // SAFE: Called in a single-threaded context + // SAFE: Called in a single-threaded context? (Not fully conttrolled) unsafe { - S_IRQ_WORKER_SIGNAL.prep(|| ::threads::SleepObject::new("IRQ Worker")); + // SAFE: The SleepObject here is static, so is never invalidated + S_IRQ_WORKER_SIGNAL.prep(|| /*unsafe*/ { ::threads::SleepObject::new("IRQ Worker") }); S_IRQ_WORKER.prep(|| ::threads::WorkerThread::new("IRQ Worker", irq_worker)); } } diff --git a/Kernel/Core/threads/sleep_object.rs b/Kernel/Core/threads/sleep_object.rs index 60f20108fdedfacac13d54fefcb9f1be66c12a49..d9bbcd6429acae92960f2cd7284386cd021e4db5 100644 --- a/Kernel/Core/threads/sleep_object.rs +++ b/Kernel/Core/threads/sleep_object.rs @@ -44,7 +44,8 @@ unsafe impl ::core::marker::Send for SleepObjectRef {} impl<'a> SleepObject<'a> { /// Create a new sleep object - pub fn new(name: &'static str) -> SleepObject + /// UNSAFE: The caller must ensure that this type's destructor is called (maintaining the correctness of obtained SleepObjectRef instances) + pub unsafe fn new(name: &'static str) -> SleepObject { SleepObject { _nomove: ::core::marker::PhantomData, @@ -56,6 +57,15 @@ impl<'a> SleepObject<'a> }), } } + /// Create a new sleep object and call a closure with it + pub fn with_new<T>(name: &'static str, f: impl FnOnce(&mut SleepObject)->T) -> T { + // SAFE: Destructor is called + unsafe { + let mut v = Self::new(name); + // TODO: Pass a handle instead? + f(&mut v) + } + } /// Wait the current thread on this object pub fn wait(&self) diff --git a/Kernel/Modules/network/nic.rs b/Kernel/Modules/network/nic.rs index fc220cf59edeee6ceb93fba6997d634182896027..aa289a55b4096b6f38b38e2c6928f52d5ac728bd 100644 --- a/Kernel/Modules/network/nic.rs +++ b/Kernel/Modules/network/nic.rs @@ -274,82 +274,83 @@ pub fn register<T: Interface>(mac_addr: [u8; 6], int: T) -> Registration<T> { fn rx_thread(int: &Interface) { - let so = ::kernel::threads::SleepObject::new("rx_thread"); - int.rx_wait_register(&so); - loop - { - so.wait(); - match int.rx_packet() + ::kernel::threads::SleepObject::with_new("rx_thread",|so| { + int.rx_wait_register(&so); + loop { - Ok(pkt) => { - log_notice!("Received packet, len={} (chunks={})", pkt.len(), pkt.num_regions()); - for r in 0 .. pkt.num_regions() { - log_debug!("{} {:?}", r, ::kernel::logging::HexDump(pkt.get_region(r))); - } - // TODO: Should this go in is own module? - // 1. Interpret the `Ethernet II` header - if pkt.len() < 6+6+2 { - log_notice!("Short packet ({} < {})", pkt.len(), 6+6+2); - continue ; - } - let mut r = PacketReader::new(&pkt); - // 2. Hand off to sub-modules depending on the EtherTy field - let src_mac = { - let mut b = [0; 6]; - r.read(&mut b).unwrap(); - b - }; - let _dst_mac = { - let mut b = [0; 6]; - r.read(&mut b).unwrap(); - b - }; - let ether_ty = r.read_u16n().unwrap(); - match ether_ty + so.wait(); + match int.rx_packet() { - 0x0800 => match ::ipv4::handle_rx_ethernet(int, src_mac, r) - { - Ok( () ) => {}, - Err(e) => { - log_warning!("TODO: Unable to hanle IPv4 packet - {:?}", e); - }, + Ok(pkt) => { + log_notice!("Received packet, len={} (chunks={})", pkt.len(), pkt.num_regions()); + for r in 0 .. pkt.num_regions() { + log_debug!("{} {:?}", r, ::kernel::logging::HexDump(pkt.get_region(r))); } - // ARP - 0x0806 => { - // TODO: Pass on to ARP - //::arp::handle_packet(int, r); - // TODO: Length test - let hw_ty = r.read_u16n().unwrap(); - let sw_ty = r.read_u16n().unwrap(); - let hwsize = r.read_u8().unwrap(); - let swsize = r.read_u8().unwrap(); - let code = r.read_u16n().unwrap(); - log_debug!("ARP HW {:04x} {}B SW {:04x} {}B req={}", hw_ty, hwsize, sw_ty, swsize, code); - if hwsize == 6 { - let mac = { - let mut b = [0; 6]; - r.read(&mut b).unwrap(); - b - }; - log_debug!("ARP HW {:?}", ::kernel::logging::HexDump(&mac)); + // TODO: Should this go in is own module? + // 1. Interpret the `Ethernet II` header + if pkt.len() < 6+6+2 { + log_notice!("Short packet ({} < {})", pkt.len(), 6+6+2); + continue ; } - if swsize == 4 { - let ip = { - let mut b = [0; 4]; - r.read(&mut b).unwrap(); - b - }; - log_debug!("ARP SW {:?}", ip); + let mut r = PacketReader::new(&pkt); + // 2. Hand off to sub-modules depending on the EtherTy field + let src_mac = { + let mut b = [0; 6]; + r.read(&mut b).unwrap(); + b + }; + let _dst_mac = { + let mut b = [0; 6]; + r.read(&mut b).unwrap(); + b + }; + let ether_ty = r.read_u16n().unwrap(); + match ether_ty + { + 0x0800 => match ::ipv4::handle_rx_ethernet(int, src_mac, r) + { + Ok( () ) => {}, + Err(e) => { + log_warning!("TODO: Unable to hanle IPv4 packet - {:?}", e); + }, + } + // ARP + 0x0806 => { + // TODO: Pass on to ARP + //::arp::handle_packet(int, r); + // TODO: Length test + let hw_ty = r.read_u16n().unwrap(); + let sw_ty = r.read_u16n().unwrap(); + let hwsize = r.read_u8().unwrap(); + let swsize = r.read_u8().unwrap(); + let code = r.read_u16n().unwrap(); + log_debug!("ARP HW {:04x} {}B SW {:04x} {}B req={}", hw_ty, hwsize, sw_ty, swsize, code); + if hwsize == 6 { + let mac = { + let mut b = [0; 6]; + r.read(&mut b).unwrap(); + b + }; + log_debug!("ARP HW {:?}", ::kernel::logging::HexDump(&mac)); + } + if swsize == 4 { + let ip = { + let mut b = [0; 4]; + r.read(&mut b).unwrap(); + b + }; + log_debug!("ARP SW {:?}", ip); + } + }, + v @ _ => { + log_warning!("TODO: Handle packet with EtherTy={:#x}", v); + }, } }, - v @ _ => { - log_warning!("TODO: Handle packet with EtherTy={:#x}", v); - }, + Err(Error::NoPacket) => {}, + Err(e) => todo!("{:?}", e), } - }, - Err(Error::NoPacket) => {}, - Err(e) => todo!("{:?}", e), } - } + }); } diff --git a/Kernel/Modules/syscalls/threads.rs b/Kernel/Modules/syscalls/threads.rs index dfbb8505a6a5889433536754877e4864d5987b75..6754f28845aa921efb2b65a19cbc55c537c2864a 100644 --- a/Kernel/Modules/syscalls/threads.rs +++ b/Kernel/Modules/syscalls/threads.rs @@ -68,32 +68,33 @@ pub fn newprocess(name: &str, clone_start: usize, clone_end: usize) -> ObjectHa #[inline(never)] pub fn wait(events: &mut [values::WaitItem], wake_time_mono: u64) -> Result<u32,Error> { - let mut waiter = ::kernel::threads::SleepObject::new("wait"); - let mut num_bound = 0; - for ev in events.iter() { - num_bound += try!(::objects::wait_on_object(ev.object, ev.flags, &mut waiter)); - } - - if num_bound == 0 && wake_time_mono == !0 { - // Attempting to sleep on no events with an infinite timeout! Would sleep forever - log_error!("TODO: What to do when a thread tries to sleep forever"); - waiter.wait(); - } - - // A wake time of 0 means to not sleep at all, just check the status of the events - // TODO: There should be a more efficient way of doing this, than binding only to unbind again - if wake_time_mono != 0 { - // !0 indicates an unbounded wait (no need to set a wakeup time) - if wake_time_mono != !0 { - todo!("Set a wakeup timer at {}", wake_time_mono); - //waiter.wait_until(wake_time_mono); + ::kernel::threads::SleepObject::with_new("wait", |waiter: &mut _| { + let mut num_bound = 0; + for ev in events.iter() { + num_bound += try!(::objects::wait_on_object(ev.object, ev.flags, waiter)); } - else { + + if num_bound == 0 && wake_time_mono == !0 { + // Attempting to sleep on no events with an infinite timeout! Would sleep forever + log_error!("TODO: What to do when a thread tries to sleep forever"); waiter.wait(); } - } - Ok( events.iter_mut().fold(0, |total,ev| total + ::objects::clear_wait(ev.object, ev.flags, &mut waiter).unwrap()) ) + // A wake time of 0 means to not sleep at all, just check the status of the events + // TODO: There should be a more efficient way of doing this, than binding only to unbind again + if wake_time_mono > 0 { + // !0 indicates an unbounded wait (no need to set a wakeup time) + if wake_time_mono != !0 { + todo!("Set a wakeup timer at {}", wake_time_mono); + //waiter.wait_until(wake_time_mono); + } + else { + waiter.wait(); + } + } + + Ok( events.iter_mut().fold(0, |total,ev| total + ::objects::clear_wait(ev.object, ev.flags, waiter).unwrap()) ) + }) } pub struct ProtoProcess(::kernel::threads::ProcessHandle); diff --git a/Kernel/Modules/syscalls/vfs.rs b/Kernel/Modules/syscalls/vfs.rs index 369bc1e47c815fc71216eccaa5931400813e3f64..41fc65ba13caecaa3e46d95bb8d719e322923d72 100644 --- a/Kernel/Modules/syscalls/vfs.rs +++ b/Kernel/Modules/syscalls/vfs.rs @@ -74,7 +74,6 @@ fn to_result<T>(r: Result<T, ::kernel::vfs::Error>) -> Result<T, u32> { } pub fn init_handles(loader_handle: ::kernel::vfs::handle::File, init_handle: ::kernel::vfs::handle::File) { - use kernel::vfs::handle; // - Forget the loader (no need) ::core::mem::forget(loader_handle); diff --git a/Kernel/Modules/usb_core/Cargo.toml b/Kernel/Modules/usb_core/Cargo.toml index dcc6d6eb6e40af826476a4bdab7f506dc9c8d050..7363d82a46b3d5e6f30d36ca87ab6df70184085d 100644 --- a/Kernel/Modules/usb_core/Cargo.toml +++ b/Kernel/Modules/usb_core/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "usb-core" version = "0.0.0" +edition = "2018" [lib] path = "lib.rs" diff --git a/Kernel/Modules/usb_core/host.rs b/Kernel/Modules/usb_core/host.rs index 3b90b0ffc22fe51e6dc748222fbfa8598eaa7d16..998bd4a4044167db157fd8dddf2354f7ef2b88dd 100644 --- a/Kernel/Modules/usb_core/host.rs +++ b/Kernel/Modules/usb_core/host.rs @@ -1,10 +1,10 @@ use kernel::prelude::*; -use kernel::_async3 as async; +use kernel::_async3 as kasync; //use handle::{Handle,RemoteFree}; -pub use hub::PortFeature; +pub use crate::hub::PortFeature; /// A double-fat pointer (three words long) pub type Handle<T: ?Sized> = ::stack_dst::ValueA<T, [usize; 3]>; @@ -27,32 +27,33 @@ impl EndpointAddr pub trait InterruptEndpoint: Send + Sync { - fn get_data(&self) -> Handle<::handle::RemoteBuffer>; + fn get_data(&self) -> Handle<crate::handle::RemoteBuffer>; } -// fn tx_async<'a, 's>(&'s self, async: async::ObjectHandle, stack: async::StackPush<'a, 's>, pkt: SparsePacket) -> Result<(), Error>; +// fn tx_async<'a, 's>(&'s self, async_obj: kasync::ObjectHandle, stack: kasync::StackPush<'a, 's>, pkt: SparsePacket) -> Result<(), Error>; pub trait ControlEndpoint { - fn out_only<'a, 's>(&'s self, async: async::ObjectHandle, stack: async::StackPush<'a, 's>, setup_data: async::WriteBufferHandle<'a, '_>, out_data: async::WriteBufferHandle<'a, '_>); - fn in_only<'a, 's>(&'s self, async: async::ObjectHandle, stack: async::StackPush<'a, 's>, setup_data: async::WriteBufferHandle<'a, '_>, in_buf: &'a mut [u8]); + //fn out_only<'a, 'b>(&self, async_pool: &'a kasync::Pool, setup_data: kasync::WriteBuffer<'b>) -> kasync::Alloc<'a, dyn Future<Output=usize> + 'b>; + fn out_only<'a, 's>(&'s self, async_obj: kasync::ObjectHandle, stack: kasync::StackPush<'a, 's>, setup_data: kasync::WriteBufferHandle<'s, '_>, out_data: kasync::WriteBufferHandle<'s, '_>); + fn in_only<'a, 's>(&'s self, async_obj: kasync::ObjectHandle, stack: kasync::StackPush<'a, 's>, setup_data: kasync::WriteBufferHandle<'s, '_>, in_buf: &'s mut [u8]); // The following are more interesting, `out/in` works, but `in/out` has ordering problems... // - Thankfully, these patterns aren't needed? - //fn out_in(&self, waiter: async::WaiterHandle, out_data: async::WriteBufferHandle, in_buf: async::ReadBufferHandle); - //fn in_out(&self, waiter: async::WaiterHandle, in_buf: async::ReadBufferHandle, out_data: async::WriteBufferHandle); + //fn out_in(&self, waiter: kasync::WaiterHandle, out_data: kasync::WriteBufferHandle, in_buf: kasync::ReadBufferHandle); + //fn in_out(&self, waiter: kasync::WaiterHandle, in_buf: kasync::ReadBufferHandle, out_data: kasync::WriteBufferHandle); } pub trait IsochEndpoint: Send + Sync { /// Returns the current controller frame number (for timing) and the matching system time fn get_current_frame_and_time(&self) -> (u32, ::kernel::time::TickCount); /// Start a send to be sent at the specified frame (relative to controller's arbtiary basis) - fn send_at<'a, 's>(&'s self, async: async::ObjectHandle, stack: async::StackPush<'a, 's>, buffer: async::WriteBufferHandle<'a, '_>, abs_frame: u32); + fn send_at<'a, 's>(&'s self, async_obj: kasync::ObjectHandle, stack: kasync::StackPush<'a, 's>, buffer: kasync::WriteBufferHandle<'a, '_>, abs_frame: u32); /// Prepare a receive to complete in the specified frame. - fn recv_at<'a, 's>(&'s self, async: async::ObjectHandle, stack: async::StackPush<'a, 's>, buffer: &'a mut [u8], abs_frame: u32); + fn recv_at<'a, 's>(&'s self, async_obj: kasync::ObjectHandle, stack: kasync::StackPush<'a, 's>, buffer: &'a mut [u8], abs_frame: u32); } pub trait BulkEndpoint: Send + Sync { // Start a send operation of the passed buffers - fn send<'a, 's>(&self, async: async::ObjectHandle, stack: async::StackPush<'a, 's>, buffer: async::WriteBufferHandle<'a, '_>); - fn recv<'a, 's>(&self, async: async::ObjectHandle, stack: async::StackPush<'a, 's>, buffer: &'a mut [u8]); + fn send<'a, 's>(&self, async_obj: kasync::ObjectHandle, stack: kasync::StackPush<'a, 's>, buffer: kasync::WriteBufferHandle<'a, '_>); + fn recv<'a, 's>(&self, async_obj: kasync::ObjectHandle, stack: kasync::StackPush<'a, 's>, buffer: &'a mut [u8]); } pub trait HostController: Send + Sync @@ -60,7 +61,7 @@ pub trait HostController: Send + Sync ///// Obtain a handle to endpoint zero //fn get_control_zero(&self) -> Handle<ControlEndpoint>; /// Begin polling an endpoint at the given rate (buffer used is allocated by the driver to be the interrupt endpoint's size) - fn init_interrupt(&self, endpoint: EndpointAddr, period_ms: usize, waiter: async::ObjectHandle) -> Handle<InterruptEndpoint>; + fn init_interrupt(&self, endpoint: EndpointAddr, period_ms: usize, waiter: kasync::ObjectHandle) -> Handle<InterruptEndpoint>; /// Initialise an ichronous endpoint fn init_isoch(&self, endpoint: EndpointAddr, max_packet_size: usize) -> Handle<IsochEndpoint>; /// Initialise a control endpoint diff --git a/Kernel/Modules/usb_core/lib.rs b/Kernel/Modules/usb_core/lib.rs index 77b71ffb629cd53a85faa0cca856fd9d1051b6b4..f7b4ee8eb91eab64eb1c6d91e58fbcea1f71f252 100644 --- a/Kernel/Modules/usb_core/lib.rs +++ b/Kernel/Modules/usb_core/lib.rs @@ -21,20 +21,28 @@ mod hub; pub mod host; pub mod handle; -enum Meta +enum Hub { - RootHub(Aref<Host>), - Hub(HubDevice), + Root(Aref<Host>), + Device(HubDevice), } -struct Host +#[derive(Default)] +struct AddressPool { - driver: Box<host::HostController>, next_id: u8, used_ids: [u8; 128/8], +} +/// Representation of a host/bus +/// - Used to hold the device address allocation logic/structures +struct Host +{ + driver: Box<host::HostController>, + addresses: ::kernel::sync::Mutex<AddressPool>, //// If true, EP0 is currently being enumerated //endpoint_zero_state: bool, + //ports: Vec<Port>, } struct HubDevice { @@ -47,10 +55,13 @@ struct HubDevice // 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<Hub>> = ::kernel::sync::Mutex::new(Vec::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()); +///// A list of known devices +//static ENUM_DEVICE_LIST: ::kernel::sync::Mutex<Vec< <typeof Port::worker as FnOnce>::Output >> = :kernel::sync::Mutex::new(Vec::new_const()); +//static ENUM_DEVICE_LIST: ::kernel::sync::Mutex<Vec<PortTask>> = :kernel::sync::Mutex::new(Vec::new_const()); +/// Add a new host controller/bus to the system pub fn register_host(mut h: Box<host::HostController>) { let mut lh = WATCH_LIST.lock(); @@ -58,10 +69,12 @@ pub fn register_host(mut h: Box<host::HostController>) // 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); - lh.push(Meta::RootHub(Aref::new(Host { + lh.push(Hub::Root(Aref::new(Host { driver: h, - next_id: 1, - used_ids: [0; 128/8], + addresses: ::kernel::sync::Mutex::new(AddressPool { + next_id: 1, + used_ids: [0; 128/8], + }), }))); } @@ -77,54 +90,145 @@ fn worker_thread() let lh = WATCH_LIST.lock(); match lh[idx] { - Meta::RootHub(ref h) => h.handle_root_event(data), - Meta::Hub(ref h) => h.handle_int(data), + Hub::Root (ref h) => h.handle_root_event(data), + Hub::Device(ref h) => h.handle_int(data), + } + } +} +/* +impl Meta +{ + fn set_port_feature(&self, port_idx: usize, feat: host::PortFeature) + { + match self + { + &Meta::RootHub(ref h) => h.driver.set_port_feature(port_idx, feat), + &Meta::Hub(ref h) => h.set_port_feature(port_idx, feat), + } + } + fn clear_port_feature(&self, port_idx: usize, feat: host::PortFeature) + { + match self + { + &Meta::RootHub(ref h) => h.driver.clear_port_feature(port_idx, feat), + &Meta::Hub(ref h) => h.clear_port_feature(port_idx, feat), + } + } + fn get_port_feature(&self, port_idx: usize, feat: host::PortFeature) -> bool + { + match self + { + &Meta::RootHub(ref h) => h.driver.get_port_feature(port_idx, feat), + &Meta::Hub (ref h) => h.get_port_feature(port_idx, feat), + } + } +} +*/ + +struct Port +{ + //connection_signaller: kernel::r#async::Signaller, + //hub: /*reference to the hub*/, +} +impl Port +{ + //fn set_port_feature(&self, feat: host::PortFeature) { + // self.hub.set_port_feature(self.port_idx, feat) + //} + //fn clear_port_feature(&self, feat: host::PortFeature) { + // self.hub.clear_port_feature(self.port_idx, feat) + //} + //fn get_port_feature(&self, feat: host::PortFeature) -> bool { + // self.hub.get_port_feature(self.port_idx, feat) + //} + //fn getclear_port_feature(&self, feat: host::PortFeature) -> bool { + // let rv = self.get_port_feature(feat) + // if rv { + // self.clear_port_feature(feat); + // } + // rv + //} + + fn signal_connected(&self) + { + //self.connection_signaller.signal(); + } + + #[cfg(false_)] + async fn initialise_port(&self) -> usize + { + let addr0_handle = r#await!( self.host().get_address_zero() ); + if ! self.get_port_feature(host::PortFeature::Power) + { + todo!("Power on a newly connected port"); + } + self.set_port_feature(host::PortFeature::Reset); + r#await!( ::kernel::futures::msleep(50) ); + self.clear_port_feature(host::PortFeature::Reset); + r#await!( ::kernel::futures::msleep(2) ); + self.clear_port_feature(host::PortFeature::Enable); + let address = self.host().allocate_address(); + r#await!( addr0_handle.send_setup_address(address) ); + address + } + + #[cfg(false_)] + async fn worker(&self) + { + loop + { + r#await!( self.connection_signaller.async_wait() ); + let addr = r#await!( self.initialise_port() ); + + let ep0 = self.make_control_endpoint(/*ep_num=*/0, /*max_packet_size=*/64); + // Enumerate device + let dev_descr: hw::DeviceDescriptor = r#await!( ep0.read_descriptor(/*index*/0) ); + log_debug!("dev_descr = {:?}", dev_descr); + log_debug!("dev_descr.manufacturer_str = {}", r#await!(ep0.read_string(dev_descr.manufacturer_str))); + log_debug!("dev_descr.product_str = {}", r#await!(ep0.read_string(dev_descr.product_str))); + log_debug!("dev_descr.serial_number_str = {}", r#await!(ep0.read_string(dev_descr.serial_number_str))); } } } -//fn enum_worker_thread() -//{ -// loop -// { -// // 1. Register sleeps on new endpoints -// // - Get device descriptor -// // - Enumerate available configurations -// } -//} impl Host { + fn allocate_address(&self) -> Option<u8> + { + match self.addresses.lock().allocate() + { + Some(v) => { + assert!(v != 0); + Some(v) + }, + None => None, + } + } + #[cfg(false_)] + async fn get_address_zero(&self) -> EnumDeviceHandle + { + () + } + 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) { self.driver.clear_port_feature(port_idx, host::PortFeature::CConnection); if self.driver.get_port_feature(port_idx, host::PortFeature::Connection) { - // Connection detected, either: - // - 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) - 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"); - } + //self.ports[port_idx].signal_connected(); + // Ensure that the port is on the active list } else { // Was disconnected, need to eliminate all downstream devices // - Requires knowing what devices are on this port. todo!("Handle port disconnection"); + //self.ports[port_idx].signal_disconnected(); } } else if self.driver.get_port_feature(port_idx, host::PortFeature::CReset) @@ -155,6 +259,34 @@ impl Host } } +impl AddressPool +{ + fn allocate(&mut self) -> Option<u8> + { + for i in self.next_id ..= 255 { + let byte = &mut self.used_ids[i as usize / 8]; + let bitmask = 1 << (i%8); + if 0 == *byte & bitmask { + *byte |= bitmask; + self.next_id = i.checked_add(1).unwrap_or(1); + return Some(i); + } + } + // Wraparound! + for i in 1 .. self.next_id { + let byte = &mut self.used_ids[i as usize / 8]; + let bitmask = 1 << (i%8); + if 0 == *byte & bitmask { + *byte |= bitmask; + self.next_id = i.checked_add(1).unwrap_or(1); + return Some(i); + } + } + // Exhausted + None + } +} + impl HubDevice { fn handle_int(&self, _size: usize) @@ -163,6 +295,17 @@ impl HubDevice let data = data_handle.get(); todo!("Process interrupt bytes from host - {:?}", ::kernel::logging::HexDump(data)); } + + fn set_port_feature(&self, port_idx: usize, feat: host::PortFeature) { + todo!("HubDevice::set_port_feature") + } + fn clear_port_feature(&self, port_idx: usize, feat: host::PortFeature) { + todo!("HubDevice::clear_port_feature") + } + fn get_port_feature(&self, port_idx: usize, feat: host::PortFeature) -> bool { + todo!("HubDevice::get_port_feature") + } + } diff --git a/Kernel/Modules/usb_ohci/lib.rs b/Kernel/Modules/usb_ohci/lib.rs index 85e324e808e513c353bce252f7854b90cefb2b5f..3320bfe23d3f247b89a753196fe5919c6ff7f27b 100644 --- a/Kernel/Modules/usb_ohci/lib.rs +++ b/Kernel/Modules/usb_ohci/lib.rs @@ -58,6 +58,15 @@ struct EndpointMetadata { tail: AtomicPtr<hw::GeneralTD>, } + +enum BounceBufferHandle<'a> { + Direct(&'a [u8]), + Bounced { + orig_buf: Option<&'a mut [u8]>, + bounce_buf: ::kernel::memory::virt::AllocHandle, + }, +} + impl BusDev { fn new_boxed(irq: u32, io: ::kernel::device_manager::IOBinding) -> Result<Box<BusDev>, &'static str> @@ -413,7 +422,8 @@ impl HostInner td_handle } - fn get_dma_write(&self, buffer: async::WriteBufferHandle) -> ((), u32, u32) + // Get a handle for a DMA output + fn get_dma_todev<'long,'short>(&self, buffer: async::WriteBufferHandle<'long,'short>) -> (BounceBufferHandle<'long>, u32, u32) { match buffer { @@ -428,7 +438,7 @@ impl HostInner } else { // Good - return ( (), start_phys as u32, last_phys as u32); + return ( BounceBufferHandle::Direct(p), start_phys as u32, last_phys as u32); } todo!("Bounce buffer - long lifetime"); }, @@ -437,6 +447,25 @@ impl HostInner }, } } + // Get a handle for a DMA input + fn get_dma_fromdev<'a>(&self, p: &'a mut [u8]) -> (BounceBufferHandle<'a>, u32, u32) + { + { + let start_phys = ::kernel::memory::virt::get_phys(p.as_ptr()); + let last_phys = ::kernel::memory::virt::get_phys(&p[p.len()-1]); + if start_phys > 0xFFFF_FFFF || last_phys > 0xFFFF_FFFF { + // An address is more than 32-bits, bounce + } + else if start_phys & !0xFFF != last_phys & !0xFFF && (0x1000 - (start_phys & 0xFFF) + last_phys & 0xFFF) as usize != p.len() { + // The buffer spans more than two pages, bounce + } + else { + // Good + return ( BounceBufferHandle::Direct(p), start_phys as u32, last_phys as u32); + } + todo!("Bounce buffer for read"); + } + } fn get_port_reg(&self, port: usize) -> hw::Regs { @@ -567,24 +596,45 @@ struct ControlEndpointHandle { } impl ControlEndpoint for ControlEndpointHandle { - fn out_only<'a, 's>(&'s self, async: async::ObjectHandle, mut stack: async::StackPush<'a, 's>, setup_data: async::WriteBufferHandle<'a, '_>, out_data: async::WriteBufferHandle<'a, '_>) { - // TODO: Figure out this stuff... - let (setup_buf, setup_first_phys, setup_last_phys) = self.controller.get_dma_write(setup_data); - let (out_buf, out_first_phys, out_last_phys) = self.controller.get_dma_write(out_data); - // SAFE: The buffers stay valid because they're moved into the async closure. + fn out_only<'a, 's>(&'s self, async: async::ObjectHandle, mut stack: async::StackPush<'a, 's>, setup_data: async::WriteBufferHandle<'s, '_>, out_data: async::WriteBufferHandle<'s, '_>) + { + // Get (potentially bounced) data handles + let (setup_buf, setup_first_phys, setup_last_phys) = self.controller.get_dma_todev(setup_data); + let (out_buf, out_first_phys, out_last_phys) = self.controller.get_dma_todev(out_data); + + // SAFE: The buffers stay valid because the handles are moved into the async closure. unsafe { self.controller.push_td( &self.id, (0b00 << 19) /* setup */ | (7 << 21) /* no int */, setup_first_phys, setup_last_phys, async.clone() ); self.controller.push_td( &self.id, (0b01 << 19) /* out */ | (0 << 21) /* immediate int */, out_first_phys, out_last_phys, async.clone() ); } - stack.push_closure(move |async, _stack, out_bytes| { + stack.push_closure(move |_async, _stack, out_bytes| { // - Capture buffer handles so they stay valid let _ = setup_buf; let _ = out_buf; // - Pass the result down the chain. Some(out_bytes) - }).unwrap(); + }).expect("Stack exhaustion in ohci::ControlEndpointHandle::out_only"); } - fn in_only<'a, 's>(&'s self, async: async::ObjectHandle, stack: async::StackPush<'a, 's>, setup_data: async::WriteBufferHandle<'a, '_>, in_buf: &'a mut [u8]) { + fn in_only<'a, 's>(&'s self, async: async::ObjectHandle, mut stack: async::StackPush<'a, 's>, setup_data: async::WriteBufferHandle<'s, '_>, in_buf: &'s mut [u8]) + { + // Get (potentially bounced) data handles + let (setup_buf, setup_first_phys, setup_last_phys) = self.controller.get_dma_todev(setup_data); + let (data_buf, data_first_phys, data_last_phys) = self.controller.get_dma_fromdev(in_buf); + // SAFE: The buffers stay valid because they're moved into the async closure. + unsafe { + self.controller.push_td( &self.id, (0b00 << 19) /* setup */ | (7 << 21) /* no int */, setup_first_phys, setup_last_phys, async.clone() ); + self.controller.push_td( &self.id, (0b10 << 19) /* in */ | (0 << 21) /* immediate int */, data_first_phys, data_last_phys, async.clone() ); + } + stack.push_closure(move |_async, _stack, out_bytes| { + // - Capture buffer handles so they stay valid + let _ = setup_buf; + let _ = data_buf; + if let BounceBufferHandle::Bounced { ref orig_buf, ref bounce_buf } = data_buf { + todo!("Copy data back out of the bounce buffer"); + } + // - Pass the result down the chain. + Some(out_bytes) + }).expect("Stack exhaustion in ohci::ControlEndpointHandle::in_only"); } }