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");
 	}
 }