diff --git a/Cargo.lock b/Cargo.lock index 1ee55272..7067179e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -499,6 +499,7 @@ dependencies = [ [[package]] name = "discrete_range_map" version = "0.6.2" +source = "git+https://git.alnyan.me/yggdrasil/discrete_range_map.git#0c932f7cc7ff55253519e3465ddeea8fe69083be" dependencies = [ "btree_monstrousity", "either", diff --git a/Cargo.toml b/Cargo.toml index acefd093..bd991cbc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,8 +75,7 @@ device-tree.path = "kernel/lib/device-tree" fdt-rs = { version = "0.4.5", default-features = false } aarch64-cpu = "10.0.0" -discrete_range_map.path = "/home/alnyan/build/sandbox/yggdrasil-packages/discrete_range_map-1dba7e4d76e4dd17/6b54882" -# discrete_range_map = { git = "https://git.alnyan.me/yggdrasil/discrete_range_map.git" } +discrete_range_map = { git = "https://git.alnyan.me/yggdrasil/discrete_range_map.git" } # Test dependencies tokio = { version = "1.42.0", default-features = false } diff --git a/kernel/driver/block/scsi/src/lib.rs b/kernel/driver/block/scsi/src/lib.rs index ea70c9f4..5b242013 100644 --- a/kernel/driver/block/scsi/src/lib.rs +++ b/kernel/driver/block/scsi/src/lib.rs @@ -40,7 +40,7 @@ pub mod transport; pub struct ScsiEnclosure { transport: AsyncMutex, - units: Vec>>>, + units: Vec>>>, index: OneTimeInit, shutdown: AtomicBool, } @@ -60,7 +60,7 @@ impl ScsiEnclosure { lun_count: usize, ) -> Result, Error> { let transport = AsyncMutex::new(ScsiTransportWrapper::new(transport)); - let units = (0..lun_count).map(|_| IrqSafeRwLock::new(None)).collect(); + let units = (0..lun_count).map(|_| AsyncMutex::new(None)).collect(); let this = Arc::new(Self { transport, units, @@ -74,7 +74,7 @@ impl ScsiEnclosure { if this.probe_lun(i as u8).await && let Ok(unit) = ScsiUnit::setup(this.clone(), i as u8).await { - *this.units[i].write() = Some(unit); + *this.units[i].lock().await = Some(unit); } } @@ -123,7 +123,7 @@ impl ScsiEnclosure { async fn poll(self: &Arc) { let index = *self.index.get(); for lun in 0..self.units.len() { - let mut slot = self.units[lun].write(); + let mut slot = self.units[lun].lock().await; let present = self.probe_lun(lun as u8).await; if let Some(unit) = slot.as_ref() { @@ -143,12 +143,12 @@ impl ScsiEnclosure { } } - pub fn detach(&self) { + pub async fn detach(&self) { self.shutdown.store(true, Ordering::Release); let index = self.index.try_get().copied(); for unit in self.units.iter() { - if let Some(unit) = unit.write().take() { + if let Some(unit) = unit.lock().await.take() { unit.detach(); } } @@ -368,10 +368,11 @@ fn register_unit(enclosure_index: u32, lun: u8, unit: Arc) { } fn remove_enclosure(index: u32) { + log::info!("scsi: enclosure {index} detached"); + let mut devices = SCSI_ENCLOSURES.lock(); let mut bitmap = SCSI_BITMAP.lock(); *bitmap &= !(1 << index); devices.remove(&index); - log::info!("scsi: enclosure {index} detached"); } diff --git a/kernel/driver/bus/usb/src/bus.rs b/kernel/driver/bus/usb/src/bus.rs index 4583be40..f66e6b8e 100644 --- a/kernel/driver/bus/usb/src/bus.rs +++ b/kernel/driver/bus/usb/src/bus.rs @@ -4,14 +4,14 @@ use alloc::{collections::BTreeMap, sync::Arc}; use libk_util::{queue::UnboundedMpmcQueue, sync::spin_rwlock::IrqSafeRwLock}; use crate::{ - UsbHostController, class_driver, + class_driver, device::{UsbBusAddress, UsbDeviceAccess}, + host::UsbHostController, }; pub struct UsbBusManager { busses: IrqSafeRwLock>>, devices: IrqSafeRwLock>>, - last_bus_address: AtomicU16, } @@ -32,9 +32,9 @@ impl UsbBusManager { QUEUE.push_back(device); } - pub fn detach_device(address: UsbBusAddress) { + pub async fn detach_device(address: UsbBusAddress) { if let Some(device) = BUS_MANAGER.devices.write().remove(&address) { - device.handle_detach(); + device.handle_detach().await; } } } @@ -44,20 +44,26 @@ pub async fn bus_handler() { loop { let new_device = QUEUE.pop_front().await; + let id_vendor = new_device.device_descriptor.id_vendor; + let id_product = new_device.device_descriptor.id_product; log::info!( - "New {:?}-speed USB device connected: {}", + "{} ({}): {:?}-speed USB device connected: {:?} {:?} ({:04x}:{:04x})", + new_device.bus_address(), + new_device.port_string(), new_device.speed(), - new_device.bus_address() + new_device.vendor_str, + new_device.product_str, + id_vendor, + id_product ); - class_driver::spawn_driver(new_device).await.ok(); + class_driver::spawn_driver(new_device).await; } } static BUS_MANAGER: UsbBusManager = UsbBusManager { busses: IrqSafeRwLock::new(BTreeMap::new()), devices: IrqSafeRwLock::new(BTreeMap::new()), - last_bus_address: AtomicU16::new(0), }; static QUEUE: UnboundedMpmcQueue> = UnboundedMpmcQueue::new(); diff --git a/kernel/driver/bus/usb/src/class_driver/hid_keyboard.rs b/kernel/driver/bus/usb/src/class_driver/hid.rs similarity index 63% rename from kernel/driver/bus/usb/src/class_driver/hid_keyboard.rs rename to kernel/driver/bus/usb/src/class_driver/hid.rs index cfe0124d..6b006eea 100644 --- a/kernel/driver/bus/usb/src/class_driver/hid_keyboard.rs +++ b/kernel/driver/bus/usb/src/class_driver/hid.rs @@ -2,13 +2,12 @@ use core::mem::MaybeUninit; use alloc::{boxed::Box, sync::Arc}; use async_trait::async_trait; -use yggdrasil_abi::io::{KeyboardKey, KeyboardKeyEvent}; +use yggdrasil_abi::io::{KeyboardKey, KeyboardKeyEvent, MouseEvent}; -use crate::{device::UsbDeviceAccess, error::UsbError, info::UsbDeviceClass}; - -use super::{UsbClassInfo, UsbDriver}; +use crate::{class_driver::UsbInterfaceDriver, device::UsbInterfaceAccess, error::UsbError}; pub struct UsbHidKeyboardDriver; +pub struct UsbHidMouseDriver; const MODIFIER_MAP: &[KeyboardKey] = &[ KeyboardKey::LControl, @@ -125,14 +124,25 @@ impl KeyboardState { } #[async_trait] -impl UsbDriver for UsbHidKeyboardDriver { - async fn run(self: Arc, device: Arc) -> Result<(), UsbError> { - // TODO not sure whether to use boot protocol (easy) or GetReport - let config = device.select_configuration(|_| true).await?.unwrap(); +impl UsbInterfaceDriver for UsbHidKeyboardDriver { + async fn run(self: Arc, interface: UsbInterfaceAccess) -> Result<(), UsbError> { + log::info!("{}: HID keyboard", interface.address()); - log::info!("Setup HID keyboard"); - let pipe = device - .open_interrupt_in_pipe(1, config.endpoints[0].max_packet_size as u16) + let endpoint_infos = interface.endpoints(); + if endpoint_infos.is_empty() { + log::warn!( + "{}: no available endpoints in interface description", + interface.address() + ); + return Err(UsbError::InvalidConfiguration); + } + + let pipe = interface + .device() + .open_interrupt_in_pipe( + endpoint_infos[0].number, + endpoint_infos[0].max_packet_size as _, + ) .await?; let mut buffer = [0; 8]; @@ -156,7 +166,7 @@ impl UsbDriver for UsbHidKeyboardDriver { for &event in events { log::trace!("Generic Keyboard: {:?}", event); - ygg_driver_input::send_event(event); + ygg_driver_input::send_keyboard_event(event); } } } @@ -165,12 +175,61 @@ impl UsbDriver for UsbHidKeyboardDriver { "USB HID Keyboard" } - fn probe(&self, class: &UsbClassInfo, _device: &UsbDeviceAccess) -> bool { - log::info!( - "class = {:?}, subclass = {:02x}", - class.class, - class.subclass - ); - class.class == UsbDeviceClass::Hid && (class.subclass == 0x00 || class.subclass == 0x01) + fn probe(&self, class: u8, subclass: u8, protocol: u8) -> bool { + class == 0x03 && subclass == 0x01 && protocol == 0x01 + } +} + +#[async_trait] +impl UsbInterfaceDriver for UsbHidMouseDriver { + async fn run(self: Arc, interface: UsbInterfaceAccess) -> Result<(), UsbError> { + log::info!("{}: HID mouse", interface.address()); + + let endpoint_infos = interface.endpoints(); + if endpoint_infos.is_empty() { + log::warn!( + "{}: no available endpoints in interface description", + interface.address() + ); + return Err(UsbError::InvalidConfiguration); + } + + let pipe = interface + .device() + .open_interrupt_in_pipe( + endpoint_infos[0].number, + endpoint_infos[0].max_packet_size as _, + ) + .await?; + + let mut buffer = [0; 8]; + + loop { + let len = pipe.read(&mut buffer).await?; + if len < 4 { + continue; + } + let data = &buffer[..len]; + + let buttons = data[0]; + let dx = data[1] as i8; + let dy = data[2] as i8; + + log::trace!("mouse {dx:+},{dy:+} {buttons:08b}"); + ygg_driver_input::send_mouse_event(MouseEvent { + dx, + dy, + buttons, + unused: 0, + }); + } + } + + fn name(&self) -> &'static str { + "USB HID Mouse" + } + + fn probe(&self, class: u8, subclass: u8, protocol: u8) -> bool { + class == 0x03 && subclass == 0x01 && protocol == 0x02 } } diff --git a/kernel/driver/bus/usb/src/class_driver/hub.rs b/kernel/driver/bus/usb/src/class_driver/hub.rs new file mode 100644 index 00000000..983bde91 --- /dev/null +++ b/kernel/driver/bus/usb/src/class_driver/hub.rs @@ -0,0 +1,384 @@ +use core::{mem::MaybeUninit, num::NonZeroU8, time::Duration}; + +use alloc::{boxed::Box, sync::Arc}; +use async_trait::async_trait; +use libk::{task::runtime, time::monotonic_time}; +use yggdrasil_abi::bitflags; + +use crate::{ + class_driver::UsbDeviceDriver, + descriptor::UsbHubDescriptorHeader, + device::{UsbDeviceAccess, UsbSpeed}, + error::UsbError, + pipe::control::ControlTransferSetup, +}; + +pub struct UsbHubDriver; + +const BM_REQUEST_TYPE_GET_HUB_DESCRIPTOR: u8 = 0b10100000; +const BM_REQUEST_TYPE_GET_PORT_STATUS: u8 = 0b10100011; +const BM_REQUEST_TYPE_PORT_FEATURE: u8 = 0b00100011; + +const B_REQUEST_GET_STATUS: u8 = 0x00; +const B_REQUEST_CLEAR_FEATURE: u8 = 0x01; +const B_REQUEST_SET_FEATURE: u8 = 0x03; +const B_REQUEST_GET_DESCRIPTOR: u8 = 0x06; + +#[allow(unused)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u16)] +pub enum PortFeatureSelector { + PortConnection = 0, + PortEnable = 1, + PortSuspend = 2, + PortOverCurrent = 3, + PortReset = 4, + PortPower = 8, + PortLowSpeed = 9, + CPortConnection = 16, + CPortEnable = 17, + CPortSuspend = 18, + CPortOverCurrent = 19, + CPortReset = 20, + PortTest = 21, + PortIndicator = 22, +} + +bitflags! { + pub struct UsbHubPortStatus: u16 { + const PORT_CONNECTION: bit 0; + const PORT_ENABLE: bit 1; + const PORT_SUSPEND: bit 2; + const PORT_OVER_CURRENT: bit 3; + const PORT_RESET: bit 4; + const PORT_POWER: bit 8; + const PORT_LOW_SPEED: bit 9; + const PORT_HIGH_SPEED: bit 10; + const PORT_TEST: bit 11; + const PORT_INDICATOR: bit 12; + } +} +bitflags! { + pub struct UsbHubPortChange: u16 { + const C_PORT_CONNECTION: bit 0; + const C_PORT_ENABLE: bit 1; + const C_PORT_SUSPEND: bit 2; + const C_PORT_OVER_CURRENT: bit 3; + const C_PORT_RESET: bit 4; + } +} + +struct UsbHub { + device: Arc, + hub_descriptor: UsbHubDescriptorHeader, + children: u64, + // TODO extra info +} + +impl UsbHub { + pub async fn setup(device: Arc) -> Result { + let control_pipe = device.control_pipe(); + let mut hub_descriptor = MaybeUninit::uninit(); + + let len = control_pipe + .control_transfer_in( + ControlTransferSetup { + bm_request_type: BM_REQUEST_TYPE_GET_HUB_DESCRIPTOR, + b_request: B_REQUEST_GET_DESCRIPTOR, + w_value: 0, + w_index: 0, + w_length: size_of::() as _, + }, + hub_descriptor.as_bytes_mut(), + ) + .await?; + if len != size_of::() { + return Err(UsbError::TruncatedDescriptor( + size_of::(), + len, + )); + } + let hub_descriptor: UsbHubDescriptorHeader = unsafe { hub_descriptor.assume_init() }; + if hub_descriptor.b_nr_ports < 1 { + log::warn!( + "{}: ignoring hub with zero downstream ports", + device.device.bus_address() + ); + return Err(UsbError::InvalidDescriptorField); + } + + log::info!( + "{}: setting up {:?}-speed hub, {} downstream ports", + device.device.bus_address(), + device.device.speed(), + hub_descriptor.b_nr_ports + ); + + device.configure_hub(&hub_descriptor).await?; + + // TODO power on the ports? + Ok(Self { + device, + hub_descriptor, + children: 0, + }) + } + + async fn set_port_feature( + &mut self, + port: NonZeroU8, + feature: PortFeatureSelector, + ) -> Result<(), UsbError> { + self.device + .control_pipe() + .control_transfer(ControlTransferSetup { + bm_request_type: BM_REQUEST_TYPE_PORT_FEATURE, + b_request: B_REQUEST_SET_FEATURE, + w_value: feature as _, + w_index: port.get() as _, + w_length: 0, + }) + .await + } + async fn clear_port_feature( + &mut self, + port: NonZeroU8, + feature: PortFeatureSelector, + ) -> Result<(), UsbError> { + self.device + .control_pipe() + .control_transfer(ControlTransferSetup { + bm_request_type: BM_REQUEST_TYPE_PORT_FEATURE, + b_request: B_REQUEST_CLEAR_FEATURE, + w_value: feature as _, + w_index: port.get() as _, + w_length: 0, + }) + .await + } + async fn clear_port_changes( + &mut self, + port: NonZeroU8, + change: UsbHubPortChange, + ) -> Result<(), UsbError> { + if change.contains(UsbHubPortChange::C_PORT_RESET) { + self.clear_port_feature(port, PortFeatureSelector::CPortReset) + .await?; + } + if change.contains(UsbHubPortChange::C_PORT_CONNECTION) { + self.clear_port_feature(port, PortFeatureSelector::CPortConnection) + .await?; + } + if change.contains(UsbHubPortChange::C_PORT_ENABLE) { + self.clear_port_feature(port, PortFeatureSelector::CPortEnable) + .await?; + } + Ok(()) + } + + async fn get_port_status( + &mut self, + port: NonZeroU8, + ) -> Result<(UsbHubPortStatus, UsbHubPortChange), UsbError> { + let mut buffer = [MaybeUninit::uninit(); 2]; + let len = self + .device + .control_pipe() + .control_transfer_in( + ControlTransferSetup { + bm_request_type: BM_REQUEST_TYPE_GET_PORT_STATUS, + b_request: B_REQUEST_GET_STATUS, + w_value: 0, + w_index: port.get() as _, + w_length: 4, + }, + buffer.as_bytes_mut(), + ) + .await?; + if len != 4 { + return Err(UsbError::TruncatedDescriptor(4, len)); + } + let [w0, w1] = unsafe { MaybeUninit::array_assume_init(buffer) }; + let status = UsbHubPortStatus(w0); + let change = UsbHubPortChange(w1); + Ok((status, change)) + } + + async fn reset_port(&mut self, port: NonZeroU8) -> Result { + self.set_port_feature(port, PortFeatureSelector::PortReset) + .await?; + + // Wait for reset to be asserted + let deadline = monotonic_time() + Duration::from_secs(3); + let mut status; + let mut change; + + loop { + (status, change) = self.get_port_status(port).await?; + + self.clear_port_changes(port, change).await?; + + if status.contains(UsbHubPortStatus::PORT_RESET) + || status.contains(UsbHubPortStatus::PORT_ENABLE) + || !status.contains(UsbHubPortStatus::PORT_CONNECTION) + { + // Port reset got asserted or port got enabled + break; + } + + if monotonic_time() >= deadline { + log::warn!("Port reset did not assert in 3 sec"); + return Ok(status); + } + } + + if status.contains(UsbHubPortStatus::PORT_ENABLE) + || !status.contains(UsbHubPortStatus::PORT_CONNECTION) + { + return Ok(status); + } + + todo!() + } + + async fn setup_connected_port(&mut self, port: NonZeroU8) -> Result<(), UsbError> { + let status = self.reset_port(port).await?; + if !status.contains(UsbHubPortStatus::PORT_CONNECTION) { + log::warn!( + "{}: port {} disconnected during reset", + self.device.bus_address(), + port + ); + return Ok(()); + } + if !status.contains(UsbHubPortStatus::PORT_ENABLE) { + log::warn!("{}: port {} did not reset", self.device.bus_address(), port); + return Ok(()); + } + + let usb_speed = match ( + status.contains(UsbHubPortStatus::PORT_LOW_SPEED), + status.contains(UsbHubPortStatus::PORT_HIGH_SPEED), + ) { + (false, false) => UsbSpeed::Full, + (true, false) => UsbSpeed::Low, + (false, true) => UsbSpeed::High, + (true, true) => todo!(), + }; + log::info!( + "{}: hub port {}: {:?}-speed device connected", + self.device.bus_address(), + port, + usb_speed + ); + let port_string = self.device.port_string().append(port); + if let Err(error) = self + .device + .host_controller() + .setup_hub_device(self.device.clone(), port_string, usb_speed) + .await + { + log::error!( + "{}: hub port {} ({}) setup failed: {:?}", + self.device.bus_address(), + port, + port_string, + error + ); + return Ok(()); + } + self.children |= 1 << (port.get() - 1); + + Ok(()) + } + + async fn disconnect_port(&mut self, port: NonZeroU8) -> Result<(), UsbError> { + let port_string = self.device.port_string().append(port); + self.children &= !(1 << (port.get() - 1)); + self.device + .host_controller() + .disconnect_device(port_string) + .await + } + + async fn poll_port(&mut self, port: NonZeroU8) -> Result<(), UsbError> { + let (status, change) = self.get_port_status(port).await?; + if change.contains(UsbHubPortChange::C_PORT_CONNECTION) { + // Clear feature: C_PORT_CONNECTION + self.clear_port_feature(port, PortFeatureSelector::CPortConnection) + .await?; + + if status.contains(UsbHubPortStatus::PORT_CONNECTION) { + self.setup_connected_port(port).await?; + } else if let Err(error) = self.disconnect_port(port).await { + log::warn!( + "{}: hub port {} did not disconnect cleanly: {:?}", + self.device.bus_address(), + port, + error + ); + } + } + + Ok(()) + } + + async fn poll(&mut self) -> bool { + for i in 0..self.hub_descriptor.b_nr_ports { + let port = NonZeroU8::new(i + 1).unwrap(); + if let Err(error) = self.poll_port(port).await { + log::error!( + "{}: hub port {} poll error: {:?}", + self.device.bus_address(), + port, + error + ); + return false; + } + } + true + } + + async fn cleanup(&mut self) { + for i in 0..self.hub_descriptor.b_nr_ports { + let port = NonZeroU8::new(i + 1).unwrap(); + if self.children & (1 << i) != 0 { + if let Err(error) = self.disconnect_port(port).await { + log::warn!( + "{}: downstream {} disconnect error: {:?}", + self.device.bus_address(), + port, + error + ); + } + } + } + } + + async fn run(mut self) -> Result<(), UsbError> { + loop { + if !self.poll().await { + self.cleanup().await; + return Ok(()); + } + runtime::sleep(Duration::from_millis(100)).await; + } + } +} + +#[async_trait] +impl UsbDeviceDriver for UsbHubDriver { + async fn run(self: Arc, device: Arc) -> Result<(), UsbError> { + let hub = UsbHub::setup(device).await?; + hub.run().await + } + + fn name(&self) -> &'static str { + "USB Hub" + } + + fn probe(&self, class: u8, subclass: u8, protocol: u8) -> bool { + let _ = protocol; + class == 0x09 && subclass == 0x00 + } +} diff --git a/kernel/driver/bus/usb/src/class_driver/mass_storage.rs b/kernel/driver/bus/usb/src/class_driver/mass_storage.rs index 8e5e3552..5d91c792 100644 --- a/kernel/driver/bus/usb/src/class_driver/mass_storage.rs +++ b/kernel/driver/bus/usb/src/class_driver/mass_storage.rs @@ -10,17 +10,22 @@ use libk::{ use ygg_driver_scsi::{ScsiEnclosure, transport::ScsiTransport}; use crate::{ + class_driver::UsbInterfaceDriver, communication::UsbDirection, - device::{UsbDeviceAccess, UsbDeviceDetachHandler}, + device::{UsbDeviceDetachHandler, UsbInterfaceAccess}, error::UsbError, - info::{UsbDeviceClass, UsbEndpointType}, + info::UsbEndpointType, pipe::{ - control::{ControlTransferSetup, UsbClassSpecificRequest}, + control::ControlTransferSetup, normal::{UsbBulkInPipeAccess, UsbBulkOutPipeAccess}, }, }; -use super::{UsbClassInfo, UsbDriver}; +const BM_REQUEST_TYPE_BULK_ONLY_MASS_STORAGE_RESET: u8 = 0b00100001; +const BM_REQUEST_TYPE_GET_MAX_LUN: u8 = 0b10100001; + +const B_REQUEST_BULK_ONLY_MASS_STORAGE_RESET: u8 = 0b11111111; +const B_REQUEST_GET_MAX_LUN: u8 = 0b11111110; pub struct UsbMassStorageDriverBulkOnly; @@ -50,7 +55,7 @@ struct Csw { struct Bbb { #[allow(unused)] - device: Arc, + interface: UsbInterfaceAccess, in_pipe: UsbBulkInPipeAccess, out_pipe: UsbBulkOutPipeAccess, last_tag: u32, @@ -60,12 +65,12 @@ struct DetachHandler(Arc); impl Bbb { pub fn new( - device: Arc, + interface: UsbInterfaceAccess, in_pipe: UsbBulkInPipeAccess, out_pipe: UsbBulkOutPipeAccess, ) -> Result { Ok(Self { - device, + interface, in_pipe, out_pipe, last_tag: 0, @@ -172,60 +177,49 @@ impl ScsiTransport for Bbb { } } +#[async_trait] impl UsbDeviceDetachHandler for DetachHandler { - fn handle_device_detach(&self) { - log::info!("Mass storage detached"); - self.0.detach(); + async fn handle_device_detach(&self) { + self.0.detach().await; } } -#[derive(Debug, Pod, Zeroable, Clone, Copy)] -#[repr(C)] -pub struct BulkOnlyMassStorageReset; - -#[derive(Debug, Pod, Zeroable, Clone, Copy)] -#[repr(C)] -pub struct GetMaxLun; - -impl UsbClassSpecificRequest for BulkOnlyMassStorageReset { - const BM_REQUEST_TYPE: u8 = 0b00100001; - const B_REQUEST: u8 = 0b11111111; -} - -impl UsbClassSpecificRequest for GetMaxLun { - const BM_REQUEST_TYPE: u8 = 0b10100001; - const B_REQUEST: u8 = 0b11111110; -} - #[async_trait] -impl UsbDriver for UsbMassStorageDriverBulkOnly { - async fn run(self: Arc, device: Arc) -> Result<(), UsbError> { - // TODO filter to only accept BBB config - let config = device.select_configuration(|_| true).await?.unwrap(); - // Bulk-in, bulk-out - assert_eq!(config.endpoints.len(), 2); - let control_pipe = device.control_pipe(); - let (in_index, in_info) = config - .find_endpoint(|ep| ep.is(UsbEndpointType::Bulk, UsbDirection::In)) - .ok_or(UsbError::InvalidConfiguration)?; - let (out_index, out_info) = config - .find_endpoint(|ep| ep.is(UsbEndpointType::Bulk, UsbDirection::Out)) - .ok_or(UsbError::InvalidConfiguration)?; - let in_pipe = device - .open_bulk_in_pipe(in_index, in_info.max_packet_size as u16) +impl UsbInterfaceDriver for UsbMassStorageDriverBulkOnly { + async fn run(self: Arc, interface: UsbInterfaceAccess) -> Result<(), UsbError> { + let endpoints = interface.endpoints(); + let bulk_in = endpoints + .iter() + .find(|ep| ep.ty == UsbEndpointType::Bulk && ep.direction == UsbDirection::In); + let bulk_out = endpoints + .iter() + .find(|ep| ep.ty == UsbEndpointType::Bulk && ep.direction == UsbDirection::Out); + + let (Some(bulk_in), Some(bulk_out)) = (bulk_in, bulk_out) else { + log::warn!( + "{}: BBB mass storage needs at least 2 bulk endpoints", + interface.address() + ); + return Err(UsbError::InvalidConfiguration); + }; + + let control_pipe = interface.device().control_pipe(); + let in_pipe = interface + .device() + .open_bulk_in_pipe(bulk_in.number, bulk_in.max_packet_size as _) .await?; - let out_pipe = device - .open_bulk_out_pipe(out_index, out_info.max_packet_size as u16) + let out_pipe = interface + .device() + .open_bulk_out_pipe(bulk_out.number, bulk_out.max_packet_size as _) .await?; // Perform a Bulk-Only Mass Storage Reset - // TODO interface id? control_pipe .control_transfer(ControlTransferSetup { - bm_request_type: BulkOnlyMassStorageReset::BM_REQUEST_TYPE, - b_request: BulkOnlyMassStorageReset::B_REQUEST, + bm_request_type: BM_REQUEST_TYPE_BULK_ONLY_MASS_STORAGE_RESET, + b_request: B_REQUEST_BULK_ONLY_MASS_STORAGE_RESET, w_value: 0, - w_index: 0, + w_index: interface.number() as _, w_length: 0, }) .await?; @@ -236,10 +230,10 @@ impl UsbDriver for UsbMassStorageDriverBulkOnly { let len = control_pipe .control_transfer_in( ControlTransferSetup { - bm_request_type: GetMaxLun::BM_REQUEST_TYPE, - b_request: GetMaxLun::B_REQUEST, + bm_request_type: BM_REQUEST_TYPE_GET_MAX_LUN, + b_request: B_REQUEST_GET_MAX_LUN, w_value: 0, - w_index: 0, + w_index: interface.number() as _, w_length: 1, }, &mut buffer, @@ -251,13 +245,13 @@ impl UsbDriver for UsbMassStorageDriverBulkOnly { unsafe { buffer[0].assume_init() } }; - let bbb = Bbb::new(device.clone(), in_pipe, out_pipe)?; + let bbb = Bbb::new(interface.clone(), in_pipe, out_pipe)?; let scsi = ScsiEnclosure::setup(Box::new(bbb), max_lun as usize + 1) .await .inspect_err(|error| log::error!("msc: scsi error {error:?}")) .map_err(|_| UsbError::DriverError)?; let detach = DetachHandler(scsi.clone()); - device.set_detach_handler(Arc::new(detach)); + interface.device().set_detach_handler(Arc::new(detach)); Ok(()) } @@ -266,8 +260,9 @@ impl UsbDriver for UsbMassStorageDriverBulkOnly { "USB Mass Storage" } - fn probe(&self, class: &UsbClassInfo, _device: &UsbDeviceAccess) -> bool { + fn probe(&self, class: u8, subclass: u8, protocol: u8) -> bool { // TODO support other protocols - class.class == UsbDeviceClass::MassStorage && class.interface_protocol_number == 0x50 + let _ = subclass; + class == 0x08 && protocol == 0x50 } } diff --git a/kernel/driver/bus/usb/src/class_driver/mod.rs b/kernel/driver/bus/usb/src/class_driver/mod.rs index 2040759c..52a093d2 100644 --- a/kernel/driver/bus/usb/src/class_driver/mod.rs +++ b/kernel/driver/bus/usb/src/class_driver/mod.rs @@ -1,117 +1,141 @@ +// TODO Split drivers into device and interface drivers use alloc::{boxed::Box, sync::Arc, vec::Vec}; use async_trait::async_trait; use libk::task::runtime; use libk_util::sync::spin_rwlock::IrqSafeRwLock; use crate::{ - device::UsbDeviceAccess, + device::{UsbDeviceAccess, UsbInterfaceAccess}, error::UsbError, - info::{UsbDeviceClass, UsbDeviceProtocol}, }; -pub mod hid_keyboard; -pub mod mass_storage; - -#[derive(Debug)] -pub struct UsbClassInfo { - pub class: UsbDeviceClass, - pub subclass: u8, - pub protocol: UsbDeviceProtocol, - pub device_protocol_number: u8, - pub interface_protocol_number: u8, -} +mod hid; +mod hub; +mod mass_storage; #[async_trait] -pub trait UsbDriver: Send + Sync { +pub trait UsbDeviceDriver: Send + Sync { async fn run(self: Arc, device: Arc) -> Result<(), UsbError>; fn name(&self) -> &'static str; - fn probe(&self, class: &UsbClassInfo, device: &UsbDeviceAccess) -> bool; + fn probe(&self, class: u8, subclass: u8, protocol: u8) -> bool; } -async fn extract_class_info(device: &UsbDeviceAccess) -> Result, UsbError> { - if device.info.num_configurations != 1 { - return Ok(None); - } - let device_info = &device.info; - let config_info = device.query_configuration_info(0).await?; +#[async_trait] +pub trait UsbInterfaceDriver: Send + Sync { + async fn run(self: Arc, interface: UsbInterfaceAccess) -> Result<(), UsbError>; - if !config_info.interfaces.is_empty() { - let if_info = &config_info.interfaces[0]; - - let class = if device_info.device_class == UsbDeviceClass::FromInterface { - if_info.interface_class - } else { - device_info.device_class - }; - let subclass = if device_info.device_subclass == 0 { - if_info.interface_subclass - } else { - device_info.device_subclass - }; - let protocol = if device_info.device_protocol == UsbDeviceProtocol::FromInterface { - if_info.interface_protocol - } else { - device_info.device_protocol - }; - - Ok(Some(UsbClassInfo { - class, - subclass, - protocol, - interface_protocol_number: if_info.interface_protocol_number, - device_protocol_number: device_info.device_protocol_number, - })) - } else { - Ok(None) - } + fn name(&self) -> &'static str; + fn probe(&self, class: u8, subclass: u8, protocol: u8) -> bool; } -async fn pick_driver( - device: &UsbDeviceAccess, -) -> Result>, UsbError> { - let Some(class) = extract_class_info(device).await? else { - return Ok(None); +async fn spawn_device_driver(device: Arc) -> Result { + let class = device.device_descriptor.device_class; + let subclass = device.device_descriptor.device_subclass; + let protocol = device.device_descriptor.device_protocol; + let Some(driver) = USB_DEVICE_DRIVERS.read().iter().find_map(|driver| { + driver + .probe(class, subclass, protocol) + .then(|| driver.clone()) + }) else { + return Ok(false); }; - for driver in USB_DEVICE_DRIVERS.read().iter() { - if driver.probe(&class, device) { - return Ok(Some(driver.clone())); + // if let Some(driver) = pick_driver(&device)? { + runtime::spawn(async move { + let name = driver.name(); + match driver.run(device).await { + e @ Err(UsbError::DeviceDisconnected) => { + log::warn!( + "Driver {:?} did not exit cleanly: device disconnected", + name, + ); + + e + } + e => e, } - } - Ok(None) + }) + .map_err(UsbError::SystemError)?; + + Ok(true) } -pub async fn spawn_driver(device: Arc) -> Result<(), UsbError> { - if let Some(driver) = pick_driver(&device).await? { - runtime::spawn(async move { - let name = driver.name(); - match driver.run(device).await { - e @ Err(UsbError::DeviceDisconnected) => { - log::warn!( - "Driver {:?} did not exit cleanly: device disconnected", - name, - ); +async fn spawn_interface_driver(interface: UsbInterfaceAccess) -> Result<(), UsbError> { + let (class, subclass, protocol) = interface.class(); + let Some(driver) = USB_INTERFACE_DRIVERS.read().iter().find_map(|driver| { + driver + .probe(class, subclass, protocol) + .then(|| driver.clone()) + }) else { + return Ok(()); + }; - e - } - e => e, + runtime::spawn(async move { + let name = driver.name(); + match driver.run(interface).await { + e @ Err(UsbError::DeviceDisconnected) => { + log::warn!( + "Driver {:?} did not exit cleanly: device disconnected", + name, + ); + + e } - }) - .map_err(UsbError::SystemError)?; - } + e => e, + } + }) + .map_err(UsbError::SystemError)?; + Ok(()) } -pub fn register_driver(driver: Arc) { +pub async fn spawn_driver(device: Arc) { + match spawn_device_driver(device.clone()).await { + Ok(true) => return, + Ok(false) => (), + Err(error) => { + log::error!( + "{}: device driver probe failed: {:?}", + device.bus_address(), + error + ); + } + } + // Enumerate interfaces + for index in 0..device.configuration0_info.interfaces.len() as u8 { + let access = device.interface(index); + if let Err(error) = spawn_interface_driver(access).await { + log::error!( + "{}: interface {} driver probe failed: {:?}", + device.bus_address(), + index, + error + ); + } + } +} + +pub fn register_device_driver(driver: Arc) { // TODO check for duplicates USB_DEVICE_DRIVERS.write().push(driver); } -pub fn register_default_class_drivers() { - register_driver(Arc::new(hid_keyboard::UsbHidKeyboardDriver)); - register_driver(Arc::new(mass_storage::UsbMassStorageDriverBulkOnly)); +pub fn register_interface_driver(driver: Arc) { + USB_INTERFACE_DRIVERS.write().push(driver); } -static USB_DEVICE_DRIVERS: IrqSafeRwLock>> = +pub fn register_default_class_drivers() { + register_device_driver(Arc::new(hub::UsbHubDriver)); + register_interface_driver(Arc::new(hid::UsbHidKeyboardDriver)); + register_interface_driver(Arc::new(hid::UsbHidMouseDriver)); + register_interface_driver(Arc::new(mass_storage::UsbMassStorageDriverBulkOnly)); + // register_driver(Arc::new(hub::UsbHubDriver)); + // register_driver(Arc::new(hid_keyboard::UsbHidKeyboardDriver)); + // register_driver(Arc::new(mass_storage::UsbMassStorageDriverBulkOnly)); +} + +static USB_DEVICE_DRIVERS: IrqSafeRwLock>> = + IrqSafeRwLock::new(Vec::new()); +static USB_INTERFACE_DRIVERS: IrqSafeRwLock>> = IrqSafeRwLock::new(Vec::new()); diff --git a/kernel/driver/bus/usb/src/descriptor.rs b/kernel/driver/bus/usb/src/descriptor.rs index 5b388a95..28fd3afb 100644 --- a/kernel/driver/bus/usb/src/descriptor.rs +++ b/kernel/driver/bus/usb/src/descriptor.rs @@ -4,9 +4,22 @@ use crate::{ communication::UsbDirection, device::UsbSpeed, error::UsbError, - info::{UsbDeviceClass, UsbDeviceProtocol, UsbEndpointType, UsbVersion}, + info::{UsbEndpointType, UsbVersion}, + // info::{UsbDeviceClass, UsbDeviceProtocol, UsbEndpointType, UsbVersion}, }; +#[derive(Clone, Copy, Debug, Default, Pod, Zeroable)] +#[repr(C, packed)] +pub struct UsbDeviceDescriptor0 { + pub length: u8, + pub ty: u8, + pub bcd_usb: u16, + pub device_class: u8, + pub device_subclass: u8, + pub device_protocol: u8, + pub max_packet_size_0: u8, +} + #[derive(Clone, Copy, Debug, Default, Pod, Zeroable)] #[repr(C, packed)] pub struct UsbDeviceDescriptor { @@ -91,16 +104,27 @@ pub struct UsbOtherSpeedConfiguration { pub max_power: u8, } -impl UsbInterfaceDescriptor { - pub fn class(&self) -> UsbDeviceClass { - UsbDeviceClass::try_from(self.interface_class).unwrap_or(UsbDeviceClass::Unknown) - } - - pub fn protocol(&self) -> UsbDeviceProtocol { - UsbDeviceProtocol::try_from(self.interface_protocol).unwrap_or(UsbDeviceProtocol::Unknown) - } +#[derive(Clone, Copy, Debug, Default, Pod, Zeroable)] +#[repr(C, packed)] +pub struct UsbHubDescriptorHeader { + pub b_desc_length: u8, + pub b_descriptor_type: u8, + pub b_nr_ports: u8, + pub w_hub_characteristics: u16, + pub b_pwr_on_2_pwr_good: u8, + pub b_hub_contr_current: u8, } +// impl UsbInterfaceDescriptor { +// pub fn class(&self) -> UsbDeviceClass { +// UsbDeviceClass::try_from(self.interface_class).unwrap_or(UsbDeviceClass::Unknown) +// } +// +// pub fn protocol(&self) -> UsbDeviceProtocol { +// UsbDeviceProtocol::try_from(self.interface_protocol).unwrap_or(UsbDeviceProtocol::Unknown) +// } +// } +// impl UsbEndpointDescriptor { pub fn direction(&self) -> UsbDirection { match self.endpoint_address >> 7 { @@ -125,16 +149,16 @@ impl UsbEndpointDescriptor { } } } - +// impl UsbDeviceDescriptor { - pub fn class(&self) -> UsbDeviceClass { - UsbDeviceClass::try_from(self.device_class).unwrap_or(UsbDeviceClass::Unknown) - } - - pub fn protocol(&self) -> UsbDeviceProtocol { - UsbDeviceProtocol::try_from(self.device_protocol).unwrap_or(UsbDeviceProtocol::Unknown) - } - + // pub fn class(&self) -> UsbDeviceClass { + // UsbDeviceClass::try_from(self.device_class).unwrap_or(UsbDeviceClass::Unknown) + // } + // + // pub fn protocol(&self) -> UsbDeviceProtocol { + // UsbDeviceProtocol::try_from(self.device_protocol).unwrap_or(UsbDeviceProtocol::Unknown) + // } + // pub fn max_packet_size(&self, version: UsbVersion, speed: UsbSpeed) -> Result { match (version.is_version_3(), speed, self.max_packet_size_0) { (true, UsbSpeed::Super, 9) => Ok(1 << 9), diff --git a/kernel/driver/bus/usb/src/device.rs b/kernel/driver/bus/usb/src/device.rs index c56e3230..a61b5032 100644 --- a/kernel/driver/bus/usb/src/device.rs +++ b/kernel/driver/bus/usb/src/device.rs @@ -1,16 +1,27 @@ -use core::{fmt, ops::Deref}; +use core::{any::Any, fmt, ops::Deref}; -use alloc::{boxed::Box, sync::Arc, vec::Vec}; +use alloc::{ + boxed::Box, + string::String, + sync::{Arc, Weak}, + vec::Vec, +}; use async_trait::async_trait; -use libk_util::sync::spin_rwlock::{IrqSafeRwLock, IrqSafeRwLockReadGuard}; +use libk::{ + error::Error, + fs::sysfs::{ + self, + attribute::{StringAttribute, StringAttributeOps}, + object::KObject, + }, +}; +use libk_util::OneTimeInit; use crate::{ - UsbHostController, + descriptor::{UsbDeviceDescriptor, UsbHubDescriptorHeader}, error::UsbError, - info::{ - UsbConfigurationInfo, UsbDeviceInfo, UsbEndpointInfo, UsbEndpointType, UsbInterfaceInfo, - UsbVersion, - }, + host::UsbHostController, + info::{PortString, UsbConfigurationInfo, UsbEndpointInfo, UsbEndpointType, UsbInterfaceInfo}, pipe::{ control::{ConfigurationDescriptorEntry, UsbControlPipeAccess}, normal::{ @@ -21,6 +32,7 @@ use crate::{ }; // High-level structures for info provided through descriptors +type UsbDeviceKObject = KObject>; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] pub struct UsbBusAddress { @@ -28,10 +40,28 @@ pub struct UsbBusAddress { pub device: u8, } +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] +pub struct UsbInterfaceAddress { + pub bus: UsbBusAddress, + pub interface: u8, +} + pub struct UsbDeviceAccess { pub device: Arc, - pub info: UsbDeviceInfo, - pub current_configuration: IrqSafeRwLock>, + pub device_descriptor: UsbDeviceDescriptor, + pub product_str: Option, + pub vendor_str: Option, + pub configuration0_info: UsbConfigurationInfo, + + kobject: OneTimeInit>, +} + +// USB device, limited in scope by one interface +#[derive(Clone)] +pub struct UsbInterfaceAccess { + device: Arc, + interface_index: u8, + endpoint_start_index: u8, } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] @@ -42,8 +72,9 @@ pub enum UsbSpeed { Super, } +#[async_trait] pub trait UsbDeviceDetachHandler: Send + Sync { - fn handle_device_detach(&self); + async fn handle_device_detach(&self); } #[async_trait] @@ -66,66 +97,231 @@ pub trait UsbDevice: Send + Sync { ty: UsbEndpointType, ) -> Result, UsbError>; - fn port_number(&self) -> u8; + async fn configure_hub(&self, hub_descriptor: &UsbHubDescriptorHeader) -> Result<(), UsbError>; + + // fn port_number(&self) -> u8; + fn port_string(&self) -> &PortString; fn bus_address(&self) -> UsbBusAddress; fn speed(&self) -> UsbSpeed; - fn controller_ref(&self) -> &dyn UsbHostController; + fn host_controller(&self) -> Arc; + fn as_any(self: Arc) -> Arc; fn set_detach_handler(&self, handler: Arc); - fn handle_detach(&self); + async fn handle_detach(&self); fn debug(&self) {} } impl UsbDeviceAccess { + fn usb_kobject() -> Option<&'static Arc>> { + static USB_KOBJECT: OneTimeInit>> = OneTimeInit::new(); + + USB_KOBJECT.or_init_with_opt(|| { + let bus_kobject = sysfs::bus()?; + let usb_kobject = KObject::new(()); + bus_kobject.add_object("usb", usb_kobject.clone()).ok()?; + Some(usb_kobject) + }) + } + + fn setup_kobject(self: &Arc) -> Result<(), Error> { + struct Id; + struct DeviceClass; + struct VendorString; + struct ProductString; + + impl StringAttributeOps for Id { + type Data = Weak; + const NAME: &'static str = "id"; + + fn read(state: &Self::Data) -> Result { + let state = state.upgrade().ok_or(Error::InvalidOperation)?; + let id_product = state.device_descriptor.id_product; + let id_vendor = state.device_descriptor.id_vendor; + Ok(alloc::format!("{id_vendor:04x}:{id_product:04x}",)) + } + } + + impl StringAttributeOps for DeviceClass { + type Data = Weak; + const NAME: &'static str = "device_class"; + + fn read(state: &Self::Data) -> Result { + let state = state.upgrade().ok_or(Error::InvalidOperation)?; + Ok(alloc::format!( + "{:02x}:{:02x}:{:02x}", + state.device_descriptor.device_class, + state.device_descriptor.device_subclass, + state.device_descriptor.device_protocol + )) + } + } + + impl StringAttributeOps for VendorString { + type Data = Weak; + const NAME: &'static str = "vendor_str"; + + fn read(state: &Self::Data) -> Result { + let state = state.upgrade().ok_or(Error::InvalidOperation)?; + if let Some(vendor_str) = state.vendor_str.as_ref() { + Ok(vendor_str.clone()) + } else { + Ok(String::new()) + } + } + } + + impl StringAttributeOps for ProductString { + type Data = Weak; + const NAME: &'static str = "product_str"; + + fn read(state: &Self::Data) -> Result { + let state = state.upgrade().ok_or(Error::InvalidOperation)?; + if let Some(product_str) = state.product_str.as_ref() { + Ok(product_str.clone()) + } else { + Ok(String::new()) + } + } + } + + let usb_kobject = Self::usb_kobject().ok_or(Error::DoesNotExist)?; + let dev_kobject = KObject::new(Arc::downgrade(self)); + dev_kobject.add_attribute(StringAttribute::from(Id)).ok(); + dev_kobject + .add_attribute(StringAttribute::from(DeviceClass)) + .ok(); + dev_kobject + .add_attribute(StringAttribute::from(ProductString)) + .ok(); + dev_kobject + .add_attribute(StringAttribute::from(VendorString)) + .ok(); + let name = alloc::format!("{}", self.device.bus_address()); + usb_kobject.add_object(name, dev_kobject.clone())?; + self.kobject.init(dev_kobject); + Ok(()) + } + /// Expected device state: /// /// * Link-layer stuff has been reset and established properly by the HCD /// * Device is not yet configured /// * Control pipe for the device has been properly set up /// * Device has been assigned a bus address - pub async fn setup(raw: Arc) -> Result { - let control = raw.control_pipe(); + pub async fn setup(raw: Arc) -> Result, UsbError> { + let control_pipe = raw.control_pipe(); + let device_descriptor = control_pipe.query_device_descriptor().await?; + if device_descriptor.num_configurations < 1 { + return Err(UsbError::InvalidDescriptorField); + } + let config_descriptor = control_pipe.query_configuration_descriptor(0).await?; - let device_desc = control.query_device_descriptor().await?; + // Use configuration 0 + control_pipe + .set_configuration(config_descriptor.configuration().config_val as _) + .await?; - let bcd_usb = device_desc.bcd_usb; - let usb_version = UsbVersion::from_bcd_usb(device_desc.bcd_usb) - .ok_or(UsbError::InvalidDescriptorField) - .inspect_err(|_| { - log::error!( - "{}: unsupported/invalid USB version: {:#x}", + let vendor_str = control_pipe + .query_string(device_descriptor.manufacturer_str) + .await + .inspect_err(|e| { + log::warn!( + "{}: manufacturer string query error: {:?}", raw.bus_address(), - bcd_usb + e ) - })?; + }) + .ok(); + let product_str = control_pipe + .query_string(device_descriptor.product_str) + .await + .inspect_err(|e| { + log::warn!("{}: product string query error: {:?}", raw.bus_address(), e) + }) + .ok(); - let manufacturer = control.query_string(device_desc.manufacturer_str).await?; - let product = control.query_string(device_desc.product_str).await?; + // Extract configuration 0 information + // let query = control_pipe.query_configuration_descriptor(index).await?; - let info = UsbDeviceInfo { - manufacturer, - product, - usb_version, + let configuration_name = control_pipe + .query_string(config_descriptor.configuration().config_str) + .await + .ok(); - id_vendor: device_desc.id_vendor, - id_product: device_desc.id_product, + let mut endpoints = Vec::new(); + let mut interfaces = Vec::new(); - device_class: device_desc.class(), - device_subclass: device_desc.device_subclass, - device_protocol: device_desc.protocol(), - device_protocol_number: device_desc.device_protocol, + for desc in config_descriptor.descriptors() { + match desc { + ConfigurationDescriptorEntry::Interface(iface) => { + let name = control_pipe.query_string(iface.interface_str).await.ok(); + interfaces.push(UsbInterfaceInfo { + name, + number: iface.interface_number, + num_endpoints: iface.num_endpoints, - num_configurations: device_desc.num_configurations, + interface_class: iface.interface_class, + interface_subclass: iface.interface_subclass, + interface_protocol: iface.interface_protocol, + }); + } + ConfigurationDescriptorEntry::Endpoint(ep) => { + endpoints.push(UsbEndpointInfo { + number: ep.number(), + direction: ep.direction(), + max_packet_size: ep.max_packet_size as _, + ty: ep.transfer_type(), + }); + } + _ => (), + } + } - max_packet_size: device_desc.max_packet_size(usb_version, raw.speed())?, + interfaces.sort_by_key(|r| r.number); + endpoints.sort_by_key(|r| r.number); + + let configuration0_info = UsbConfigurationInfo { + name: configuration_name, + config_value: config_descriptor.configuration().config_val, + interfaces, + endpoints, }; - Ok(Self { + let device = Arc::new(Self { device: raw, - info, - current_configuration: IrqSafeRwLock::new(None), - }) + device_descriptor, + product_str, + vendor_str, + configuration0_info, + kobject: OneTimeInit::new(), + }); + + if let Err(error) = device.setup_kobject() { + log::error!( + "{} kobject setup error: {:?}", + device.device.bus_address(), + error + ); + } + + Ok(device) + } + + pub fn interface(self: &Arc, interface_index: u8) -> UsbInterfaceAccess { + let endpoint_start_index = self + .configuration0_info + .interfaces + .iter() + .take(interface_index as usize) + .map(|r| r.num_endpoints) + .sum(); + + UsbInterfaceAccess { + device: self.clone(), + interface_index, + endpoint_start_index, + } } pub async fn open_interrupt_in_pipe( @@ -164,90 +360,6 @@ impl UsbDeviceAccess { Ok(UsbBulkOutPipeAccess(pipe)) } - pub fn read_current_configuration( - &self, - ) -> IrqSafeRwLockReadGuard<'_, Option> { - self.current_configuration.read() - } - - pub async fn select_configuration bool>( - &self, - predicate: F, - ) -> Result, UsbError> { - let mut current_config = self.current_configuration.write(); - let control_pipe = self.control_pipe(); - - for i in 0..self.info.num_configurations { - let info = self.query_configuration_info(i).await?; - - if predicate(&info) { - log::debug!("Selected configuration: {:#?}", info); - let config = current_config.insert(info); - - control_pipe - .set_configuration(config.config_value as _) - .await?; - - return Ok(Some(config.clone())); - } - } - - Ok(None) - } - - pub async fn query_configuration_info( - &self, - index: u8, - ) -> Result { - if index >= self.info.num_configurations { - return Err(UsbError::InvalidConfiguration); - } - let control_pipe = self.control_pipe(); - let query = control_pipe.query_configuration_descriptor(index).await?; - - let configuration_name = control_pipe - .query_string(query.configuration().config_str) - .await?; - - let mut endpoints = Vec::new(); - let mut interfaces = Vec::new(); - - for desc in query.descriptors() { - match desc { - ConfigurationDescriptorEntry::Endpoint(ep) => { - endpoints.push(UsbEndpointInfo { - number: ep.number(), - direction: ep.direction(), - max_packet_size: ep.max_packet_size as _, - ty: ep.transfer_type(), - }); - } - ConfigurationDescriptorEntry::Interface(iface) => { - let name = control_pipe.query_string(iface.interface_str).await?; - interfaces.push(UsbInterfaceInfo { - name, - number: iface.interface_number, - - interface_class: iface.class(), - interface_subclass: iface.interface_subclass, - interface_protocol: iface.protocol(), - interface_protocol_number: iface.interface_protocol, - }); - } - _ => (), - } - } - - let info = UsbConfigurationInfo { - name: configuration_name, - config_value: query.configuration().config_val, - interfaces, - endpoints, - }; - - Ok(info) - } - pub fn set_detach_handler(&self, handler: Arc) { self.device.set_detach_handler(handler); } @@ -266,3 +378,46 @@ impl fmt::Display for UsbBusAddress { write!(f, "{}:{}", self.bus, self.device) } } + +impl fmt::Display for UsbInterfaceAddress { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}.{}", self.bus, self.interface) + } +} + +impl UsbInterfaceAccess { + fn interface_info(&self) -> &UsbInterfaceInfo { + &self.device.configuration0_info.interfaces[self.interface_index as usize] + } + + pub fn number(&self) -> u8 { + self.interface_index + } + + pub fn endpoints(&self) -> &[UsbEndpointInfo] { + let info = self.interface_info(); + let start = self.endpoint_start_index as usize; + let end = start + info.num_endpoints as usize; + &self.device.configuration0_info.endpoints[start..end] + } + + pub fn device(&self) -> &Arc { + &self.device + } + + pub fn address(&self) -> UsbInterfaceAddress { + UsbInterfaceAddress { + bus: self.device.bus_address(), + interface: self.interface_index, + } + } + + pub fn class(&self) -> (u8, u8, u8) { + let i = self.interface_info(); + ( + i.interface_class, + i.interface_subclass, + i.interface_protocol, + ) + } +} diff --git a/kernel/driver/bus/usb/src/error.rs b/kernel/driver/bus/usb/src/error.rs index 48c06995..a3f7f435 100644 --- a/kernel/driver/bus/usb/src/error.rs +++ b/kernel/driver/bus/usb/src/error.rs @@ -7,6 +7,7 @@ pub enum TransferError { BufferError, UsbTransactionError, Stall, + Shutdown, Other(u8), } @@ -29,13 +30,17 @@ pub enum UsbError { DeviceBusy, DeviceDisconnected, TransferFailed(TransferError), + TruncatedDescriptor(usize, usize), // Driver errors DriverError, } impl From for UsbError { fn from(value: TransferError) -> Self { - Self::TransferFailed(value) + match value { + TransferError::Shutdown => Self::DeviceDisconnected, + value => Self::TransferFailed(value), + } } } diff --git a/kernel/driver/bus/usb/src/host.rs b/kernel/driver/bus/usb/src/host.rs new file mode 100644 index 00000000..d30af298 --- /dev/null +++ b/kernel/driver/bus/usb/src/host.rs @@ -0,0 +1,20 @@ +use alloc::{boxed::Box, sync::Arc}; +use async_trait::async_trait; +use device_api::device::Device; + +use crate::{ + device::{UsbDeviceAccess, UsbSpeed}, + error::UsbError, + info::PortString, +}; + +#[async_trait] +pub trait UsbHostController: Device + Sync + Send { + async fn setup_hub_device( + self: Arc, + hub: Arc, + port_string: PortString, + usb_speed: UsbSpeed, + ) -> Result<(), UsbError>; + async fn disconnect_device(self: Arc, port_string: PortString) -> Result<(), UsbError>; +} diff --git a/kernel/driver/bus/usb/src/info.rs b/kernel/driver/bus/usb/src/info.rs index 4366f851..23e875cb 100644 --- a/kernel/driver/bus/usb/src/info.rs +++ b/kernel/driver/bus/usb/src/info.rs @@ -1,7 +1,6 @@ -use core::fmt; +use core::{fmt, num::NonZeroU8}; use alloc::{string::String, vec::Vec}; -use yggdrasil_abi::primitive_enum; use crate::communication::UsbDirection; @@ -39,31 +38,21 @@ pub enum UsbVersion { Usb32, } -primitive_enum! { - pub enum UsbDeviceClass: u8 { - FromInterface = 0x00, - Hid = 0x03, - MassStorage = 0x08, - Unknown = 0xFF, - } -} +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct PortString(u64); -primitive_enum! { - pub enum UsbDeviceProtocol: u8 { - FromInterface = 0x00, - Unknown = 0xFF, - } -} +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct PortStringIter(u64); #[derive(Debug, Clone)] pub struct UsbInterfaceInfo { - pub name: String, + pub name: Option, pub number: u8, + pub num_endpoints: u8, - pub interface_class: UsbDeviceClass, + pub interface_class: u8, pub interface_subclass: u8, - pub interface_protocol: UsbDeviceProtocol, - pub interface_protocol_number: u8, + pub interface_protocol: u8, } #[derive(Debug, Clone)] @@ -76,33 +65,12 @@ pub struct UsbEndpointInfo { #[derive(Debug, Clone)] pub struct UsbConfigurationInfo { - pub name: String, + pub name: Option, pub config_value: u8, pub interfaces: Vec, pub endpoints: Vec, } -#[derive(Debug, Clone)] -pub struct UsbDeviceInfo { - pub manufacturer: String, - pub product: String, - - pub usb_version: UsbVersion, - - pub id_vendor: u16, - pub id_product: u16, - - pub device_class: UsbDeviceClass, - pub device_subclass: u8, - pub device_protocol: UsbDeviceProtocol, - pub device_protocol_number: u8, - - /// Max packet size for endpoint zero - pub max_packet_size: usize, - - pub num_configurations: u8, -} - impl UsbVersion { pub fn is_version_3(&self) -> bool { matches!(self, Self::Usb30 | Self::Usb31 | Self::Usb32) @@ -151,3 +119,59 @@ impl UsbConfigurationInfo { Some((index as u8 + 1, info)) } } + +impl PortString { + pub const fn new_root_port(root_hub_port_number: NonZeroU8) -> Self { + Self(root_hub_port_number.get() as u64) + } + + pub const fn root_hub_port_number(&self) -> NonZeroU8 { + unsafe { NonZeroU8::new_unchecked((self.0 & 0xF) as u8) } + } + + pub fn append(mut self, port: NonZeroU8) -> Self { + for i in 0..16 { + let pos = i * 4; + if (self.0 >> pos) & 0xF == 0 { + self.0 |= (port.get() as u64) << pos; + return self; + } + } + panic!("Port route string too long"); + } + + pub fn parent_hub_port_number(&self) -> Option { + self.iter().last() + } + + pub const fn raw(&self) -> u64 { + self.0 + } + + pub fn iter(&self) -> PortStringIter { + PortStringIter(self.0) + } +} + +impl fmt::Display for PortString { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "") + } +} + +impl Iterator for PortStringIter { + type Item = NonZeroU8; + + fn next(&mut self) -> Option { + let port = NonZeroU8::new((self.0 & 0xF) as u8)?; + self.0 >>= 4; + Some(port) + } +} diff --git a/kernel/driver/bus/usb/src/lib.rs b/kernel/driver/bus/usb/src/lib.rs index 26f2ceec..eda8b1c8 100644 --- a/kernel/driver/bus/usb/src/lib.rs +++ b/kernel/driver/bus/usb/src/lib.rs @@ -4,7 +4,8 @@ generic_const_exprs, iter_array_chunks, maybe_uninit_as_bytes, - maybe_uninit_fill + maybe_uninit_fill, + maybe_uninit_array_assume_init )] extern crate alloc; @@ -14,6 +15,7 @@ pub mod communication; pub mod descriptor; pub mod device; pub mod error; +pub mod host; pub mod info; pub mod pipe; pub mod util; @@ -23,5 +25,3 @@ pub mod class_driver; // pub use communication::{UsbControlTransfer, UsbDirection, UsbTransferStatus, UsbTransferToken}; pub trait UsbEndpoint: Sync {} - -pub trait UsbHostController: Sync + Send {} diff --git a/kernel/driver/bus/usb/src/pipe/control.rs b/kernel/driver/bus/usb/src/pipe/control.rs index ad123717..821e29ce 100644 --- a/kernel/driver/bus/usb/src/pipe/control.rs +++ b/kernel/driver/bus/usb/src/pipe/control.rs @@ -10,8 +10,8 @@ use libk_mm::PageBox; use crate::{ descriptor::{ - UsbConfigurationDescriptor, UsbDeviceDescriptor, UsbDeviceQualifier, UsbEndpointDescriptor, - UsbInterfaceDescriptor, UsbOtherSpeedConfiguration, + UsbConfigurationDescriptor, UsbDeviceDescriptor, UsbDeviceDescriptor0, UsbDeviceQualifier, + UsbEndpointDescriptor, UsbInterfaceDescriptor, UsbOtherSpeedConfiguration, }, error::UsbError, }; @@ -34,11 +34,6 @@ pub trait UsbDeviceRequest: Sized + Pod { const B_REQUEST: u8; } -pub trait UsbClassSpecificRequest: Sized + Pod { - const BM_REQUEST_TYPE: u8; - const B_REQUEST: u8; -} - pub trait UsbDescriptorRequest: UsbDeviceRequest { const DESCRIPTOR_TYPE: u8; } @@ -177,6 +172,25 @@ impl ConfigurationDescriptorQuery { } impl UsbControlPipeAccess { + pub async fn query_device_descriptor_0(&self) -> Result { + assert_eq!(size_of::(), 8); + let mut buffer = MaybeUninit::uninit(); + + self.control_transfer_in( + ControlTransferSetup { + bm_request_type: 0b10000000, + b_request: 0x06, + w_value: 0x100, + w_index: 0, + w_length: size_of::() as _, + }, + buffer.as_bytes_mut(), + ) + .await?; + + Ok(unsafe { buffer.assume_init() }) + } + pub async fn query_device_descriptor(&self) -> Result { let mut buffer = MaybeUninit::uninit(); diff --git a/kernel/driver/input/src/lib.rs b/kernel/driver/input/src/lib.rs index 39812673..f39cfd2d 100644 --- a/kernel/driver/input/src/lib.rs +++ b/kernel/driver/input/src/lib.rs @@ -9,14 +9,19 @@ use async_trait::async_trait; use device_api::device::Device; use libk::{device::char::CharDevice, vfs::FileReadiness}; use libk_util::{OneTimeInit, ring::LossyRingQueue}; -use yggdrasil_abi::{error::Error, io::KeyboardKeyEvent}; +use yggdrasil_abi::{ + error::Error, + io::{KeyboardKeyEvent, MouseEvent}, +}; #[derive(Clone, Copy)] pub struct KeyboardDevice; +#[derive(Clone, Copy)] +pub struct MouseDevice; impl FileReadiness for KeyboardDevice { fn poll_read(&self, cx: &mut Context<'_>) -> Poll> { - INPUT_QUEUE.poll_readable(cx).map(Ok) + KEYBOARD_INPUT_QUEUE.poll_readable(cx).map(Ok) } } @@ -33,7 +38,7 @@ impl CharDevice for KeyboardDevice { return Ok(0); } - let ev = INPUT_QUEUE.read().await; + let ev = KEYBOARD_INPUT_QUEUE.read().await; buf[..4].copy_from_slice(&ev.as_bytes()); @@ -45,7 +50,7 @@ impl CharDevice for KeyboardDevice { return Ok(0); } - let ev = INPUT_QUEUE.try_read().ok_or(Error::WouldBlock)?; + let ev = KEYBOARD_INPUT_QUEUE.try_read().ok_or(Error::WouldBlock)?; buf[..4].copy_from_slice(&ev.as_bytes()); @@ -68,15 +73,84 @@ impl CharDevice for KeyboardDevice { } } -static INPUT_QUEUE: LossyRingQueue = LossyRingQueue::with_capacity(32); -static KEYBOARD_DEVICE: OneTimeInit> = OneTimeInit::new(); +impl MouseDevice { + fn write_report(buf: &mut [u8], report: &MouseEvent) -> Result { + buf[0] = report.dx as u8; + buf[1] = report.dy as u8; + buf[2] = report.buttons; + buf[3] = 0; -pub fn setup() -> Arc { + Ok(4) + } +} + +impl FileReadiness for MouseDevice { + fn poll_read(&self, cx: &mut Context<'_>) -> Poll> { + MOUSE_INPUT_QUEUE.poll_readable(cx).map(Ok) + } +} + +impl Device for MouseDevice { + fn display_name(&self) -> &str { + "Mouse input pseudo-device" + } +} + +#[async_trait] +impl CharDevice for MouseDevice { + async fn read(&self, buf: &mut [u8]) -> Result { + if buf.len() < 4 { + return Ok(0); + } + + let ev = MOUSE_INPUT_QUEUE.read().await; + Self::write_report(buf, &ev) + } + + fn read_nonblocking(&self, buf: &mut [u8]) -> Result { + if buf.len() < 4 { + return Ok(0); + } + + let ev = MOUSE_INPUT_QUEUE.try_read().ok_or(Error::WouldBlock)?; + Self::write_report(buf, &ev) + } + + fn is_writeable(&self) -> bool { + false + } + + fn device_request(&self, option: u32, buffer: &mut [u8], len: usize) -> Result { + let _ = option; + let _ = buffer; + let _ = len; + Err(Error::InvalidOperation) + } + + fn is_terminal(&self) -> bool { + false + } +} + +static KEYBOARD_INPUT_QUEUE: LossyRingQueue = LossyRingQueue::with_capacity(32); +static MOUSE_INPUT_QUEUE: LossyRingQueue = LossyRingQueue::with_capacity(64); +static KEYBOARD_DEVICE: OneTimeInit> = OneTimeInit::new(); +static MOUSE_DEVICE: OneTimeInit> = OneTimeInit::new(); + +pub fn setup_keyboard() -> Arc { KEYBOARD_DEVICE .or_init_with(|| Arc::new(KeyboardDevice)) .clone() } -pub fn send_event(ev: KeyboardKeyEvent) { - INPUT_QUEUE.write(ev); +pub fn setup_mouse() -> Arc { + MOUSE_DEVICE.or_init_with(|| Arc::new(MouseDevice)).clone() +} + +pub fn send_mouse_event(ev: MouseEvent) { + MOUSE_INPUT_QUEUE.write(ev); +} + +pub fn send_keyboard_event(ev: KeyboardKeyEvent) { + KEYBOARD_INPUT_QUEUE.write(ev); } diff --git a/kernel/driver/usb/xhci/src/context.rs b/kernel/driver/usb/xhci/src/context.rs index 5c78eeb7..566b66eb 100644 --- a/kernel/driver/usb/xhci/src/context.rs +++ b/kernel/driver/usb/xhci/src/context.rs @@ -6,7 +6,7 @@ use libk_util::sync::spin_rwlock::IrqSafeRwLock; use xhci_lib::context::{self, DeviceHandler, InputHandler}; use ygg_driver_usb::error::UsbError; -use crate::regs::{ContextSize, PortNumber}; +use crate::regs::ContextSize; pub enum XhciDeviceContext { Context32(IrqSafeRwLock>), @@ -61,46 +61,6 @@ impl XhciInputContext { .map_err(UsbError::MemoryError) } - pub fn new_address_device( - dma: &dyn DmaAllocator, - size: ContextSize, - root_hub_port_number: PortNumber, - max_packet_size: usize, - speed: u8, - dequeue_pointer: BusAddress, - ) -> Result { - let mut cx = Self::new(dma, size)?; - - { - let control = cx.control_mut(); - - control.set_add_context_flag(0); // Enable slot context - control.set_add_context_flag(1); // Enable endpoint 0 context - } - - { - let slot = cx.device_mut().slot_mut(); - - slot.set_context_entries(1); - slot.set_interrupter_target(0); - slot.set_root_hub_port_number(root_hub_port_number.into()); - slot.set_speed(speed); - } - - { - let ep0 = cx.device_mut().endpoint_mut(1); - - ep0.set_endpoint_type(context::EndpointType::Control); - ep0.set_error_count(3); - // Use the provided max_packet_size, or the default one for the given speed - ep0.set_max_packet_size(max_packet_size as u16); - ep0.set_tr_dequeue_pointer(dequeue_pointer.into_u64()); - ep0.set_dequeue_cycle_state(); - } - - Ok(cx) - } - // pub fn physical_address(&self) -> PhysicalAddress { // match self { // Self::Context32(cx) => unsafe { cx.as_physical_address() }, diff --git a/kernel/driver/usb/xhci/src/controller.rs b/kernel/driver/usb/xhci/src/controller.rs index 77114fc6..39a8b7b0 100644 --- a/kernel/driver/usb/xhci/src/controller.rs +++ b/kernel/driver/usb/xhci/src/controller.rs @@ -1,7 +1,4 @@ -use core::{ - mem::MaybeUninit, - sync::atomic::{AtomicU8, Ordering}, -}; +use core::{mem::MaybeUninit, sync::atomic::Ordering}; use alloc::{boxed::Box, collections::btree_map::BTreeMap, sync::Arc, vec::Vec}; use async_trait::async_trait; @@ -17,19 +14,21 @@ use libk::{ }; use libk_util::{ OneTimeInit, + hash_table::DefaultHashTable, sync::{IrqSafeSpinlock, spin_rwlock::IrqSafeRwLock}, }; use tock_registers::{ LocalRegisterCopy, interfaces::{ReadWriteable, Readable, Writeable}, }; +use xhci_lib::context; use ygg_driver_pci::{PciConfigurationSpace, device::PciDeviceInfo}; use ygg_driver_usb::{ - UsbHostController, bus::UsbBusManager, device::{UsbBusAddress, UsbDeviceAccess, UsbSpeed}, error::UsbError, - info::UsbVersion, + host::UsbHostController, + info::{PortString, UsbVersion}, pipe::control::UsbControlPipeAccess, }; use yggdrasil_abi::bitflags; @@ -87,7 +86,7 @@ pub struct Xhci { root_hub_ports: Vec>, pub(crate) endpoints: IrqSafeRwLock>>, pub(crate) slots: Vec>>>, - pub(crate) port_slot_map: Vec, + port_slot_map: IrqSafeRwLock>, bus_index: OneTimeInit, port_event_map: EventBitmap, } @@ -175,7 +174,6 @@ impl Xhci { space.write_u32(INTEL_XUSB2PR, 0xFFFFFFFF); } - let port_slot_map = (0..regs.port_count).map(|_| AtomicU8::new(0)).collect(); let slots = (0..regs.slot_count) .map(|_| IrqSafeRwLock::new(None)) .collect(); @@ -196,7 +194,7 @@ impl Xhci { bus_index: OneTimeInit::new(), endpoints: IrqSafeRwLock::new(BTreeMap::new()), slots, - port_slot_map, + port_slot_map: IrqSafeRwLock::new(DefaultHashTable::new()), port_event_map: EventBitmap::new(), }) } @@ -218,7 +216,7 @@ impl Xhci { async fn allocate_device_slot( self: &Arc, - port_id: PortNumber, + port_string: PortString, slot_type: u8, speed: UsbSpeed, ) -> Result<(u8, Arc, Arc), UsbError> { @@ -233,7 +231,7 @@ impl Xhci { .insert((slot_id, 1), control_ring.clone()); let slot = Arc::new(XhciBusDevice { - port_id, + port_string, slot_id, device_context, control_pipe, @@ -245,7 +243,7 @@ impl Xhci { }); *self.slots[slot_id as usize].write() = Some(slot.clone()); - self.port_slot_map[port_id.index()].store(slot_id, Ordering::Release); + self.port_slot_map.write().insert(port_string, slot_id); Ok((slot_id, slot, control_ring)) } @@ -271,12 +269,102 @@ impl Xhci { Ok(()) } + async fn setup_device( + self: &Arc, + port_string: PortString, + parent_hub_slot_id: Option, + slot_type: u8, + usb_speed: UsbSpeed, + ) -> Result<(), UsbError> { + let xhci_route_string = port_string.raw() >> 4; + let root_hub_port_number = port_string.root_hub_port_number(); + let parent_hub_port_number = port_string.parent_hub_port_number(); + + let (xhci_speed, max_packet_size_0) = match usb_speed { + UsbSpeed::Low => (2, 8), + UsbSpeed::Full => (1, 8), + UsbSpeed::High => (3, 64), + UsbSpeed::Super => (4, 512), + }; + + let (slot_id, slot, control_ring) = self + .allocate_device_slot(port_string, slot_type, usb_speed) + .await?; + let dequeue_pointer = control_ring.bus_address(); + + let mut input_cx = XhciInputContext::new(&*self.dma, self.regs.context_size)?; + + { + let control = input_cx.control_mut(); + + control.set_add_context_flag(0); // Enable slot context + control.set_add_context_flag(1); // Enable endpoint 0 context + } + + { + let slot = input_cx.device_mut().slot_mut(); + + slot.set_context_entries(1); + slot.set_interrupter_target(0); + slot.set_root_hub_port_number(root_hub_port_number.into()); + slot.set_speed(xhci_speed); + slot.set_route_string(xhci_route_string as _); + if let (Some(parent_hub_slot_id), Some(parent_hub_port_number)) = + (parent_hub_slot_id, parent_hub_port_number) + { + slot.set_parent_hub_slot_id(parent_hub_slot_id); + slot.set_parent_port_number(parent_hub_port_number.into()); + } + } + + { + let ep0 = input_cx.device_mut().endpoint_mut(1); + + ep0.set_endpoint_type(context::EndpointType::Control); + ep0.set_error_count(3); + // Use the provided max_packet_size, or the default one for the given speed + ep0.set_max_packet_size(max_packet_size_0); + ep0.set_tr_dequeue_pointer(dequeue_pointer.into_u64()); + ep0.set_dequeue_cycle_state(); + } + + self.command_ring + .address_device(&**self, slot_id, &input_cx, false) + .await + .inspect_err(|error| { + log::error!("Port {port_string} Address Device TRB (BSR=0) failed: {error:?}") + })?; + + let control_pipe = &slot.control_pipe; + let device_descriptor = control_pipe.query_device_descriptor_0().await?; + + if usb_speed == UsbSpeed::Full && device_descriptor.max_packet_size_0 != 8 { + // Setup endpoint 0 max packet size + slot.set_endpoint0_max_packet_size(device_descriptor.max_packet_size_0) + .await?; + } + + let bus_address = slot + .device_context + .map(|device| device.slot().usb_device_address()); + slot.bus_address.init(UsbBusAddress { + bus: *self.bus_index.get(), + device: bus_address, + }); + + let device = UsbDeviceAccess::setup(slot).await?; + UsbBusManager::register_device(device); + + Ok(()) + } + // TODO clean up resources if init fails - async fn setup_port( + async fn setup_root_port( self: &Arc, regs: &PortRegs, number: PortNumber, ) -> Result<(), UsbError> { + let port_string = PortString::new_root_port(number.into()); let root_hub_port = self.root_hub_ports[number.index()] .as_ref() .ok_or(UsbError::PortInitFailed)?; @@ -292,11 +380,11 @@ impl Xhci { let speed = status.read(PORTSC::PS) as u8; let pls = status.read(PORTSC::PLS); - let (usb_speed, max_packet_size) = match speed { - 1 => (UsbSpeed::Full, 8), - 2 => (UsbSpeed::Low, 8), - 3 => (UsbSpeed::High, 64), - 4 => (UsbSpeed::Super, 512), + let usb_speed = match speed { + 1 => UsbSpeed::Full, + 2 => UsbSpeed::Low, + 3 => UsbSpeed::High, + 4 => UsbSpeed::Super, _ => { log::error!("Port {number} invalid speed value {speed}"); return Err(UsbError::DeviceDisconnected); @@ -309,53 +397,20 @@ impl Xhci { return Err(UsbError::DeviceDisconnected); } - let (slot_id, slot, control_ring) = self - .allocate_device_slot(number, root_hub_port.slot_type, usb_speed) - .await?; - - let input_cx = XhciInputContext::new_address_device( - &*self.dma, - self.regs.context_size, - number, - max_packet_size, - speed, - control_ring.bus_address(), - )?; - - self.command_ring - .address_device(&**self, slot_id, &input_cx, false) + self.setup_device(port_string, None, root_hub_port.slot_type, usb_speed) .await - .inspect_err(|error| { - log::error!("Port {number} Address Device TRB (BSR=0) failed: {error:?}") - })?; - - // TODO update max_packet_size for default control endpoint after fetching the device - // descriptor - - let bus_address = slot - .device_context - .map(|device| device.slot().usb_device_address()); - slot.bus_address.init(UsbBusAddress { - bus: *self.bus_index.get(), - device: bus_address, - }); - - let device = UsbDeviceAccess::setup(slot).await?; - UsbBusManager::register_device(device.into()); - - Ok(()) } - async fn handle_disconnect(&self, number: PortNumber) -> Result<(), UsbError> { - let slot_id = self.port_slot_map[number.index()].swap(0, Ordering::Acquire); - if slot_id == 0 { + async fn handle_device_disconnect(&self, port_string: PortString) -> Result<(), UsbError> { + log::info!("{port_string}: disconnect"); + let Some(slot_id) = self.port_slot_map.write().remove(&port_string) else { + log::warn!("Disconnect on non-existent device: {port_string}"); return Ok(()); - } - log::info!("Port {number} disconnected"); + }; let slot = self.slots[slot_id as usize].write().take(); if let Some(slot) = slot { - UsbBusManager::detach_device(*slot.bus_address.get()); + UsbBusManager::detach_device(*slot.bus_address.get()).await; // Clean up xHC resources for (&endpoint_id, endpoint) in slot.endpoints.read().iter() { @@ -372,6 +427,11 @@ impl Xhci { Ok(()) } + async fn handle_root_port_disconnect(&self, number: PortNumber) -> Result<(), UsbError> { + let port_string = PortString::new_root_port(number.into()); + self.handle_device_disconnect(port_string).await + } + async fn port_handler_task(self: Arc) -> Result<(), Error> { // Inject notify for ports that are already connected { @@ -418,13 +478,13 @@ impl Xhci { if let Some(connected) = connected { if connected { log::info!("Port {number} connected"); - if let Err(error) = self.setup_port(regs, number).await { + if let Err(error) = self.setup_root_port(regs, number).await { log::error!("Port {number} setup error: {error:?}"); } } if !connected { - if let Err(error) = self.handle_disconnect(number).await { + if let Err(error) = self.handle_root_port_disconnect(number).await { log::error!("Port {number} disconnect error: {error:?}"); } } @@ -551,4 +611,21 @@ impl InterruptHandler for Xhci { } } -impl UsbHostController for Xhci {} +#[async_trait] +impl UsbHostController for Xhci { + async fn setup_hub_device( + self: Arc, + hub: Arc, + port_string: PortString, + usb_speed: UsbSpeed, + ) -> Result<(), UsbError> { + let hub_device = hub.device.clone().as_any(); + let xhci_hub_device = Arc::downcast::(hub_device).unwrap(); + let parent_hub_slot_id = xhci_hub_device.slot_id; + self.setup_device(port_string, Some(parent_hub_slot_id), 0, usb_speed) + .await + } + async fn disconnect_device(self: Arc, port_string: PortString) -> Result<(), UsbError> { + self.handle_device_disconnect(port_string).await + } +} diff --git a/kernel/driver/usb/xhci/src/device.rs b/kernel/driver/usb/xhci/src/device.rs index eed06133..4f34edd3 100644 --- a/kernel/driver/usb/xhci/src/device.rs +++ b/kernel/driver/usb/xhci/src/device.rs @@ -1,3 +1,5 @@ +use core::any::Any; + use alloc::{boxed::Box, collections::btree_map::BTreeMap, sync::Arc}; use async_trait::async_trait; use libk_util::{ @@ -6,11 +8,12 @@ use libk_util::{ }; use xhci_lib::context; use ygg_driver_usb::{ - UsbHostController, communication::UsbDirection, + descriptor::UsbHubDescriptorHeader, device::{UsbBusAddress, UsbDevice, UsbDeviceDetachHandler, UsbSpeed}, error::UsbError, - info::UsbEndpointType, + host::UsbHostController, + info::{PortString, UsbEndpointType}, pipe::{ control::UsbControlPipeAccess, normal::{UsbNormalPipeIn, UsbNormalPipeOut}, @@ -21,12 +24,11 @@ use crate::{ Xhci, context::{XhciDeviceContext, XhciInputContext}, pipe::{NormalInPipe, NormalOutPipe}, - regs::PortNumber, ring::transfer::TransferRing, }; pub struct XhciBusDevice { - pub(crate) port_id: PortNumber, + pub(crate) port_string: PortString, pub(crate) slot_id: u8, pub(crate) speed: UsbSpeed, pub(crate) bus_address: OneTimeInit, @@ -39,10 +41,27 @@ pub struct XhciBusDevice { pub(crate) detach_handler: IrqSafeSpinlock>>, } +impl XhciBusDevice { + pub(crate) async fn set_endpoint0_max_packet_size( + &self, + max_packet_size_0: u8, + ) -> Result<(), UsbError> { + log::info!( + "{}: set ep0 max packet size = {max_packet_size_0}", + self.port_string + ); + todo!() + } +} + #[async_trait] impl UsbDevice for XhciBusDevice { - fn port_number(&self) -> u8 { - self.port_id.into() + fn as_any(self: Arc) -> Arc { + self + } + + fn port_string(&self) -> &PortString { + &self.port_string } fn bus_address(&self) -> UsbBusAddress { @@ -53,9 +72,9 @@ impl UsbDevice for XhciBusDevice { &self.control_pipe } - fn handle_detach(&self) { + async fn handle_detach(&self) { if let Some(handler) = self.detach_handler.lock().as_ref() { - handler.handle_device_detach(); + handler.handle_device_detach().await; } } @@ -63,8 +82,8 @@ impl UsbDevice for XhciBusDevice { *self.detach_handler.lock() = Some(handler); } - fn controller_ref(&self) -> &dyn UsbHostController { - self.xhci.as_ref() + fn host_controller(&self) -> Arc { + self.xhci.clone() } fn debug(&self) {} @@ -98,6 +117,31 @@ impl UsbDevice for XhciBusDevice { .await?; Ok(Box::new(pipe)) } + + async fn configure_hub(&self, hub_descriptor: &UsbHubDescriptorHeader) -> Result<(), UsbError> { + let mut input_cx = XhciInputContext::new(&*self.xhci.dma, self.xhci.regs.context_size)?; + + { + let control = input_cx.control_mut(); + + control.set_add_context_flag(0); + } + { + let slot = input_cx.device_mut().slot_mut(); + + // TODO TT Think Time + // TODO Multi-TT + slot.set_hub(); + slot.set_number_of_ports(hub_descriptor.b_nr_ports); + } + + self.xhci + .command_ring + .evaluate_context(self.xhci.as_ref(), self.slot_id, &input_cx) + .await?; + + Ok(()) + } } impl XhciBusDevice { diff --git a/kernel/driver/usb/xhci/src/regs/mod.rs b/kernel/driver/usb/xhci/src/regs/mod.rs index 867f9d54..6812c557 100644 --- a/kernel/driver/usb/xhci/src/regs/mod.rs +++ b/kernel/driver/usb/xhci/src/regs/mod.rs @@ -1,4 +1,4 @@ -use core::{fmt, sync::atomic::AtomicU32}; +use core::{fmt, num::NonZeroU8, sync::atomic::AtomicU32}; use alloc::vec::Vec; use capability::{CapabilityRegs, HCCPARAMS1, HCSPARAMS1, HCSPARAMS2}; @@ -41,7 +41,7 @@ pub enum ContextSize { #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[repr(transparent)] -pub struct PortNumber(u8); +pub struct PortNumber(NonZeroU8); impl Regs { const PORT_REGS_OFFSET: usize = 0x400; @@ -162,6 +162,12 @@ pub fn portsc_to_neutral( } impl From for u8 { + fn from(value: PortNumber) -> Self { + value.0.into() + } +} + +impl From for NonZeroU8 { fn from(value: PortNumber) -> Self { value.0 } @@ -169,11 +175,11 @@ impl From for u8 { impl PortNumber { pub fn from_index(index: usize) -> Self { - Self(index as u8 + 1) + Self(NonZeroU8::new(index as u8 + 1).unwrap()) } pub fn index(&self) -> usize { - self.0 as usize - 1 + u8::from(self.0) as usize - 1 } } diff --git a/kernel/driver/usb/xhci/src/ring/command.rs b/kernel/driver/usb/xhci/src/ring/command.rs index d7b302ae..f9034f89 100644 --- a/kernel/driver/usb/xhci/src/ring/command.rs +++ b/kernel/driver/usb/xhci/src/ring/command.rs @@ -122,6 +122,20 @@ impl CommandRing { Ok(()) } + pub async fn evaluate_context( + &self, + executor: &E, + slot_id: u8, + input_context: &XhciInputContext, + ) -> Result<(), UsbError> { + self.submit_and_wait( + executor, + EvaluateContextTrb::new(input_context.bus_address(), slot_id), + ) + .await?; + Ok(()) + } + pub async fn configure_endpoint( &self, executor: &E, @@ -249,6 +263,12 @@ define_bitfields! { } } +define_bitfields! { + pub EvaluateContextCommandFlags: u32 { + (24..32) => slot_id + } +} + define_bitfields! { pub ConfigureEndpointCommandFlags : u32 { (24..32) => slot_id @@ -299,6 +319,14 @@ pub struct AddressDeviceCommandTrb { pub flags: AddressDeviceCommandFlags, } +#[derive(Clone, Copy, Debug, Pod, Zeroable)] +#[repr(C, align(16))] +pub struct EvaluateContextTrb { + pub input_context_address: BusAddress, + _0: u32, + pub flags: EvaluateContextCommandFlags, +} + #[derive(Clone, Copy, Debug, Pod, Zeroable)] #[repr(C, align(16))] pub struct ConfigureEndpointCommandTrb { @@ -368,6 +396,16 @@ impl AddressDeviceCommandTrb { } } +impl EvaluateContextTrb { + pub fn new(input_context_address: BusAddress, slot_id: u8) -> Self { + Self { + input_context_address, + _0: 0, + flags: EvaluateContextCommandFlags::new(slot_id as _), + } + } +} + impl ConfigureEndpointCommandTrb { pub fn new(input_context_address: BusAddress, slot_id: u8) -> Self { Self { @@ -422,6 +460,10 @@ impl CommandTrb for AddressDeviceCommandTrb { const TRB_TYPE: u8 = 11; } +impl CommandTrb for EvaluateContextTrb { + const TRB_TYPE: u8 = 13; +} + impl CommandTrb for ConfigureEndpointCommandTrb { const TRB_TYPE: u8 = 12; } diff --git a/kernel/driver/usb/xhci/src/ring/transfer.rs b/kernel/driver/usb/xhci/src/ring/transfer.rs index 98cd9f85..61dc6a2b 100644 --- a/kernel/driver/usb/xhci/src/ring/transfer.rs +++ b/kernel/driver/usb/xhci/src/ring/transfer.rs @@ -420,7 +420,7 @@ impl Transaction { } TransactionEvent::Shutdown => { log::error!("xhci: abort transaction, endpoint shutdown"); - return Err(TransferError::UsbTransactionError); + return Err(TransferError::Shutdown); } } } @@ -436,7 +436,7 @@ impl Transaction { } TransactionEvent::Shutdown => { log::error!("xhci: abort transaction, endpoint shutdown"); - return Err(TransferError::UsbTransactionError); + return Err(TransferError::Shutdown); } } event.to_result() @@ -481,7 +481,7 @@ impl TransactionEvent { 13 => Err(TransferError::ShortPacket((status as usize) & 0xFFFFFF)), code => Err(TransferError::Other(code as u8)), }, - Self::Shutdown => Err(TransferError::UsbTransactionError), + Self::Shutdown => Err(TransferError::Shutdown), } } } diff --git a/kernel/libk/libk-util/src/hash_table.rs b/kernel/libk/libk-util/src/hash_table.rs index eb511bef..025dd15e 100644 --- a/kernel/libk/libk-util/src/hash_table.rs +++ b/kernel/libk/libk-util/src/hash_table.rs @@ -8,6 +8,11 @@ use alloc::vec::Vec; pub type DefaultHashBuilder = core::hash::BuildHasherDefault; pub type DefaultHashTable = HashTable; +pub struct DrainIter<'a, K, V, H, const N: usize> { + hash_table: &'a mut HashTable, + bucket_index: usize, +} + pub struct HashTable where [Vec<(K, V)>; N]: Sized, @@ -34,6 +39,13 @@ impl HashTable { bucket.clear(); } } + + pub fn drain(&mut self) -> DrainIter<'_, K, V, H, N> { + DrainIter { + hash_table: self, + bucket_index: 0, + } + } } impl HashTable { @@ -99,3 +111,18 @@ impl HashTable { bucket.iter().any(|(k, _)| k.borrow() == key) } } + +impl<'a, K, V, H, const N: usize> Iterator for DrainIter<'a, K, V, H, N> { + type Item = (K, V); + + fn next(&mut self) -> Option { + while self.bucket_index < N { + let Some(head) = self.hash_table.buckets[self.bucket_index].pop() else { + self.bucket_index += 1; + continue; + }; + return Some(head); + } + None + } +} diff --git a/kernel/src/arch/x86/peripherals/ps2/mod.rs b/kernel/src/arch/x86/peripherals/ps2/mod.rs index 8dd4d28b..56f21bd9 100644 --- a/kernel/src/arch/x86/peripherals/ps2/mod.rs +++ b/kernel/src/arch/x86/peripherals/ps2/mod.rs @@ -108,7 +108,7 @@ impl InterruptHandler for PS2Controller { inner.e0 = false; - ygg_driver_input::send_event(event); + ygg_driver_input::send_keyboard_event(event); } count != 0 diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 1e94ce42..1f7cb4f8 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -172,11 +172,20 @@ pub fn kernel_main() -> ! { CPU_INIT_FENCE.wait_all(ArchitectureImpl::cpu_count()); // Add keyboard device - if let Err(error) = - devfs::add_named_char_device(ygg_driver_input::setup(), "kbd", FileMode::new(0o660)) - { + if let Err(error) = devfs::add_named_char_device( + ygg_driver_input::setup_keyboard(), + "kbd", + FileMode::new(0o660), + ) { log::error!("Couldn't add keyboard device: {error:?}"); } + if let Err(error) = devfs::add_named_char_device( + ygg_driver_input::setup_mouse(), + "mouse", + FileMode::new(0o660), + ) { + log::error!("Couldn't add mouse device: {error:?}"); + } task::init().expect("Failed to initialize the scheduler"); diff --git a/lib/abi/src/io/input.rs b/lib/abi/src/io/input.rs index 4ad3dc11..40c31a9d 100644 --- a/lib/abi/src/io/input.rs +++ b/lib/abi/src/io/input.rs @@ -47,6 +47,21 @@ pub enum KeyboardKeyEvent { Released(KeyboardKey), } +/// Representation for a mouse report +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(C)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct MouseEvent { + /// Mouse X-axis delta + pub dx: i8, + /// Mouse Y-axis delta + pub dy: i8, + /// Button press state bitmask + pub buttons: u8, + /// Unused field + pub unused: u8, +} + impl KeyboardKey { /// Converts [KeyboardKey] to its related [KeyboardKeyCode] pub const fn code(self) -> KeyboardKeyCode { diff --git a/lib/abi/src/io/mod.rs b/lib/abi/src/io/mod.rs index b3f5a891..b8dca34b 100644 --- a/lib/abi/src/io/mod.rs +++ b/lib/abi/src/io/mod.rs @@ -13,7 +13,7 @@ pub use crate::generated::{ OpenOptions, PollControl, RawFd, RemoveFlags, TimerOptions, UnmountOptions, UserId, }; pub use file::{FileMetadataUpdate, FileMetadataUpdateMode, FileTimesUpdate, SeekFrom}; -pub use input::{KeyboardKey, KeyboardKeyCode, KeyboardKeyEvent}; +pub use input::{KeyboardKey, KeyboardKeyCode, KeyboardKeyEvent, MouseEvent}; pub use terminal::{ TerminalControlCharacters, TerminalInputOptions, TerminalLineOptions, TerminalOptions, TerminalOutputOptions, TerminalSize,