diff --git a/kernel/driver/bus/usb/src/address.rs b/kernel/driver/bus/usb/src/address.rs new file mode 100644 index 00000000..139c8046 --- /dev/null +++ b/kernel/driver/bus/usb/src/address.rs @@ -0,0 +1,58 @@ +use core::fmt; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct UsbRoute { + bus: u16, + ports: [u8; 8], + len: u8, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct UsbBusAddress { + pub bus: u16, + pub device: u8, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct UsbInterfaceAddress { + pub device: UsbBusAddress, + pub interface: u8, +} + +impl UsbBusAddress { + pub fn with_interface(self, interface: u8) -> UsbInterfaceAddress { + UsbInterfaceAddress { + device: self, + interface, + } + } +} + +impl fmt::Display for UsbBusAddress { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "", self.bus, self.device) + } +} + +impl fmt::Display for UsbInterfaceAddress { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "", + self.device.bus, self.device.device, self.interface + ) + } +} + +impl fmt::Display for UsbRoute { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}-", self.bus)?; + for (i, &port) in self.ports[..self.len as usize].iter().enumerate() { + if i != 0 { + write!(f, ".")?; + } + write!(f, "{port}")?; + } + Ok(()) + } +} diff --git a/kernel/driver/bus/usb/src/bus.rs b/kernel/driver/bus/usb/src/bus.rs index 2f94eeb8..36a8670f 100644 --- a/kernel/driver/bus/usb/src/bus.rs +++ b/kernel/driver/bus/usb/src/bus.rs @@ -1,21 +1,19 @@ use core::sync::atomic::{AtomicU16, Ordering}; use alloc::{collections::BTreeMap, format, sync::Arc}; -use libk::fs::sysfs::{self, object::KObject}; use libk_util::{queue::UnboundedMpmcQueue, sync::spin_rwlock::IrqSafeRwLock, OneTimeInit}; use crate::{ + address::UsbBusAddress, class_driver, - device::{UsbBusAddress, UsbDevice, UsbDeviceAccess}, + device::{UsbDevice, UsbDeviceAccess}, + sysfs::{self, UsbBusKObject}, UsbHostController, }; -pub type UsbBusKObject = Arc>>; -pub type UsbDeviceKObject = Arc>>; - pub struct UsbBusWrapper { - hc: Arc, - index: u16, + pub(crate) hc: Arc, + pub(crate) index: u16, kobject: OneTimeInit, } @@ -27,30 +25,11 @@ pub struct UsbBusManager { } impl UsbBusWrapper { - pub fn register_sysfs_object(self: &Arc) { - let root = sysfs_usb_root(); - let bus_kobject = self.kobject.init(KObject::new(self.clone())); - self.hc.register_sysfs_properties(bus_kobject); - root.add_object(format!("bus{}", self.index), bus_kobject.clone()) - .ok(); - } - pub fn kobject(&self) -> &UsbBusKObject { self.kobject.get() } } -fn sysfs_usb_root() -> &'static Arc> { - static USB_ROOT: OneTimeInit>> = OneTimeInit::new(); - - USB_ROOT.or_init_with(|| { - let bus_object = sysfs::bus().expect("bus object"); - let usb_object = KObject::new(()); - bus_object.add_object("usb", usb_object.clone()).ok(); - usb_object - }) -} - impl UsbBusManager { pub fn register_bus(hc: Arc) -> (u16, Arc) { let i = BUS_MANAGER.last_bus_address.fetch_add(1, Ordering::AcqRel); @@ -60,7 +39,7 @@ impl UsbBusManager { kobject: OneTimeInit::new(), }); BUS_MANAGER.busses.write().insert(i, wrapper.clone()); - wrapper.register_sysfs_object(); + wrapper.kobject.init(sysfs::register_bus_kobject(&wrapper)); (i, wrapper) } @@ -71,7 +50,7 @@ impl UsbBusManager { .devices .write() .insert(device.bus_address(), device.clone()); - device.register_sysfs_object(); + device.kobject.init(sysfs::register_device_kobject(&device)); QUEUE.push_back(device); } @@ -94,7 +73,11 @@ pub async fn bus_handler() { new_device.bus_address() ); - class_driver::spawn_driver(new_device).await.ok(); + let address = new_device.bus_address(); + if let Err(error) = class_driver::setup_device(new_device).await { + log::warn!("USB device {address} setup error: {error:?}",); + } + // class_driver::spawn_driver(new_device).await.ok(); } } diff --git a/kernel/driver/bus/usb/src/class_driver/hid_keyboard.rs b/kernel/driver/bus/usb/src/class_driver/hid_keyboard.rs index cfe0124d..585dd081 100644 --- a/kernel/driver/bus/usb/src/class_driver/hid_keyboard.rs +++ b/kernel/driver/bus/usb/src/class_driver/hid_keyboard.rs @@ -4,9 +4,12 @@ use alloc::{boxed::Box, sync::Arc}; use async_trait::async_trait; use yggdrasil_abi::io::{KeyboardKey, KeyboardKeyEvent}; -use crate::{device::UsbDeviceAccess, error::UsbError, info::UsbDeviceClass}; - -use super::{UsbClassInfo, UsbDriver}; +use crate::{ + class_driver::{UsbInterfaceClass, UsbInterfaceDriver}, + device::UsbDeviceAccess, + error::UsbError, + info::UsbInterfaceInfo, +}; pub struct UsbHidKeyboardDriver; @@ -125,10 +128,14 @@ impl KeyboardState { } #[async_trait] -impl UsbDriver for UsbHidKeyboardDriver { - async fn run(self: Arc, device: Arc) -> Result<(), UsbError> { +impl UsbInterfaceDriver for UsbHidKeyboardDriver { + async fn run( + self: Arc, + device: Arc, + interface: UsbInterfaceInfo, + ) -> Result<(), UsbError> { // TODO not sure whether to use boot protocol (easy) or GetReport - let config = device.select_configuration(|_| true).await?.unwrap(); + let config = device.current_configuration().unwrap(); log::info!("Setup HID keyboard"); let pipe = device @@ -156,7 +163,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 +172,18 @@ 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, + device: &UsbDeviceAccess, + interface: &UsbInterfaceInfo, + class: UsbInterfaceClass, + ) -> bool { + let _ = (device, interface); + class + == UsbInterfaceClass { + class: 3, + subclass: 1, + protocol: 1, + } } } diff --git a/kernel/driver/bus/usb/src/class_driver/hid_mouse.rs b/kernel/driver/bus/usb/src/class_driver/hid_mouse.rs new file mode 100644 index 00000000..037ad365 --- /dev/null +++ b/kernel/driver/bus/usb/src/class_driver/hid_mouse.rs @@ -0,0 +1,64 @@ +use alloc::{boxed::Box, sync::Arc}; +use async_trait::async_trait; +use yggdrasil_abi::io::{ButtonMask, MouseEvent}; + +use crate::{ + class_driver::{UsbInterfaceClass, UsbInterfaceDriver}, + device::UsbDeviceAccess, + error::UsbError, + info::UsbInterfaceInfo, +}; + +pub struct UsbHidMouseDriver; + +#[async_trait] +impl UsbInterfaceDriver for UsbHidMouseDriver { + async fn run( + self: Arc, + device: Arc, + interface: UsbInterfaceInfo, + ) -> Result<(), UsbError> { + let config = device.current_configuration().unwrap(); + + log::info!("Setup HID mouse"); + let pipe = device + .open_interrupt_in_pipe(1, config.endpoints[0].max_packet_size as u16) + .await?; + + let mut buffer = [0; 16]; + let mut button_state = 0; + + loop { + let len = pipe.read(&mut buffer).await?; + if len < 4 { + continue; + } + + let event = MouseEvent { + buttons: ButtonMask(buffer[0]), + dx: (buffer[1] as i8) as i32, + dy: (buffer[2] as i8) as i32, + }; + + ygg_driver_input::send_mouse_event(event); + } + } + + fn name(&self) -> &'static str { + "USB HID Mouse" + } + + fn probe( + &self, + device: &UsbDeviceAccess, + interface: &UsbInterfaceInfo, + class: UsbInterfaceClass, + ) -> bool { + class + == UsbInterfaceClass { + class: 3, + subclass: 1, + protocol: 2, + } + } +} 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 9d0728a8..2bd629ea 100644 --- a/kernel/driver/bus/usb/src/class_driver/mass_storage.rs +++ b/kernel/driver/bus/usb/src/class_driver/mass_storage.rs @@ -1,273 +1,273 @@ -use core::mem::MaybeUninit; - -use alloc::{boxed::Box, sync::Arc}; -use async_trait::async_trait; -use bytemuck::{Pod, Zeroable}; -use libk::{ - dma::{DmaBuffer, DmaSliceMut}, - error::Error, -}; -use ygg_driver_scsi::{transport::ScsiTransport, ScsiEnclosure}; - -use crate::{ - communication::UsbDirection, - device::{UsbDeviceAccess, UsbDeviceDetachHandler}, - error::UsbError, - info::{UsbDeviceClass, UsbEndpointType}, - pipe::{ - control::{ControlTransferSetup, UsbClassSpecificRequest}, - normal::{UsbBulkInPipeAccess, UsbBulkOutPipeAccess}, - }, -}; - -use super::{UsbClassInfo, UsbDriver}; - -pub struct UsbMassStorageDriverBulkOnly; - -#[derive(Debug, Clone, Copy, Zeroable, Pod)] -#[repr(C)] -struct Cbw { - signature: u32, // 0x00 - tag: u32, // 0x04 - transfer_length: u32, // 0x08 - flags: u8, // 0x0C - lun: u8, // 0x0D - cb_length: u8, // 0x0E - cb_data: [u8; 16], // 0x0F - // Not sent - _0: u8, -} - -#[derive(Debug, Clone, Copy, Zeroable, Pod)] -#[repr(C)] -struct Csw { - signature: u32, - tag: u32, - data_residue: u32, - status: u8, - _0: [u8; 3], -} - -struct Bbb { - #[allow(unused)] - device: Arc, - in_pipe: UsbBulkInPipeAccess, - out_pipe: UsbBulkOutPipeAccess, - last_tag: u32, -} - -struct DetachHandler(Arc); - -impl Bbb { - pub fn new( - device: Arc, - in_pipe: UsbBulkInPipeAccess, - out_pipe: UsbBulkOutPipeAccess, - ) -> Result { - Ok(Self { - device, - in_pipe, - out_pipe, - last_tag: 0, - }) - } -} - -impl Bbb { - async fn send_cbw( - &mut self, - lun: u8, - host_to_dev: bool, - command: &[u8], - response_len: usize, - ) -> Result { - self.last_tag = self.last_tag.wrapping_add(1); - - let flags = if !host_to_dev { 1 << 7 } else { 0 }; - let tag = self.last_tag; - let mut cbw_bytes = [0; 32]; - let cbw = bytemuck::from_bytes_mut::(&mut cbw_bytes); - - cbw.signature = 0x43425355; - cbw.transfer_length = response_len as u32; - cbw.flags = flags; - cbw.tag = tag; - cbw.lun = lun; - cbw.cb_length = command.len() as u8; - cbw.cb_data[..command.len()].copy_from_slice(command); - - self.out_pipe - .write(&cbw_bytes[..31]) - .await - .inspect_err(|error| log::error!("msc: CBW send error: {error:?}"))?; - - Ok(tag) - } - - async fn read_csw(&mut self, tag: u32) -> Result<(), Error> { - let mut csw_bytes = [0; 16]; - self.in_pipe - .read_exact(&mut csw_bytes[..13]) - .await - .inspect_err(|error| log::error!("msc: CSW receive error: {error:?}"))?; - let csw = bytemuck::from_bytes::(&csw_bytes); - - if csw.signature != 0x53425355 { - log::warn!("msc: invalid csw signature"); - return Err(Error::InvalidArgument); - } - if csw.tag != tag { - let csw_tag = csw.tag; - log::warn!("msc: invalid csw tag (got {}, expected {tag})", csw_tag); - return Err(Error::InvalidArgument); - } - if csw.status != 0x00 { - return Err(Error::InvalidArgument); - } - Ok(()) - } - - async fn read_response_data( - &mut self, - buffer: DmaSliceMut<'_, MaybeUninit>, - ) -> Result { - if buffer.len() == 0 { - return Ok(0); - } - let len = self - .in_pipe - .read_dma(buffer) - .await - .inspect_err(|error| log::error!("msc: DMA read error: {error:?}"))?; - Ok(len) - } -} - -#[async_trait] -impl ScsiTransport for Bbb { - fn allocate_buffer(&self, size: usize) -> Result]>, Error> { - Ok(self.in_pipe.allocate_dma_buffer(size)?) - } - - async fn perform_request_raw( - &mut self, - lun: u8, - request_data: &[u8], - response_buffer: DmaSliceMut<'_, MaybeUninit>, - ) -> Result { - if request_data.len() > 16 || response_buffer.len() > self.max_bytes_per_request() { - return Err(Error::InvalidArgument); - } - - let tag = self - .send_cbw(lun, false, request_data, response_buffer.len()) - .await?; - let response_len = self.read_response_data(response_buffer).await?; - self.read_csw(tag).await?; - Ok(response_len) - } - - fn max_bytes_per_request(&self) -> usize { - 32768 - } -} - -impl UsbDeviceDetachHandler for DetachHandler { - fn handle_device_detach(&self) { - log::info!("Mass storage detached"); - self.0.detach(); - } -} - -#[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) - .await?; - let out_pipe = device - .open_bulk_out_pipe(out_index, out_info.max_packet_size as u16) - .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, - w_value: 0, - w_index: 0, - w_length: 0, - }) - .await?; - - // Get max LUN - // TODO on devices which do not support multiple LUNs, this command may STALL - let mut buffer = [MaybeUninit::uninit()]; - let len = control_pipe - .control_transfer_in( - ControlTransferSetup { - bm_request_type: GetMaxLun::BM_REQUEST_TYPE, - b_request: GetMaxLun::B_REQUEST, - w_value: 0, - w_index: 0, - w_length: 1, - }, - &mut buffer, - ) - .await?; - let max_lun = if len < 1 { - 0 - } else { - unsafe { buffer[0].assume_init() } - }; - - let bbb = Bbb::new(device.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)); - - Ok(()) - } - - fn name(&self) -> &'static str { - "USB Mass Storage" - } - - fn probe(&self, class: &UsbClassInfo, _device: &UsbDeviceAccess) -> bool { - // TODO support other protocols - class.class == UsbDeviceClass::MassStorage && class.interface_protocol_number == 0x50 - } -} +// use core::mem::MaybeUninit; +// +// use alloc::{boxed::Box, sync::Arc}; +// use async_trait::async_trait; +// use bytemuck::{Pod, Zeroable}; +// use libk::{ +// dma::{DmaBuffer, DmaSliceMut}, +// error::Error, +// }; +// use ygg_driver_scsi::{transport::ScsiTransport, ScsiEnclosure}; +// +// use crate::{ +// communication::UsbDirection, +// device::{UsbDeviceAccess, UsbDeviceDetachHandler}, +// error::UsbError, +// info::{UsbDeviceClass, UsbEndpointType}, +// pipe::{ +// control::{ControlTransferSetup, UsbClassSpecificRequest}, +// normal::{UsbBulkInPipeAccess, UsbBulkOutPipeAccess}, +// }, +// }; +// +// use super::{UsbClassInfo, UsbDriver}; +// +// pub struct UsbMassStorageDriverBulkOnly; +// +// #[derive(Debug, Clone, Copy, Zeroable, Pod)] +// #[repr(C)] +// struct Cbw { +// signature: u32, // 0x00 +// tag: u32, // 0x04 +// transfer_length: u32, // 0x08 +// flags: u8, // 0x0C +// lun: u8, // 0x0D +// cb_length: u8, // 0x0E +// cb_data: [u8; 16], // 0x0F +// // Not sent +// _0: u8, +// } +// +// #[derive(Debug, Clone, Copy, Zeroable, Pod)] +// #[repr(C)] +// struct Csw { +// signature: u32, +// tag: u32, +// data_residue: u32, +// status: u8, +// _0: [u8; 3], +// } +// +// struct Bbb { +// #[allow(unused)] +// device: Arc, +// in_pipe: UsbBulkInPipeAccess, +// out_pipe: UsbBulkOutPipeAccess, +// last_tag: u32, +// } +// +// struct DetachHandler(Arc); +// +// impl Bbb { +// pub fn new( +// device: Arc, +// in_pipe: UsbBulkInPipeAccess, +// out_pipe: UsbBulkOutPipeAccess, +// ) -> Result { +// Ok(Self { +// device, +// in_pipe, +// out_pipe, +// last_tag: 0, +// }) +// } +// } +// +// impl Bbb { +// async fn send_cbw( +// &mut self, +// lun: u8, +// host_to_dev: bool, +// command: &[u8], +// response_len: usize, +// ) -> Result { +// self.last_tag = self.last_tag.wrapping_add(1); +// +// let flags = if !host_to_dev { 1 << 7 } else { 0 }; +// let tag = self.last_tag; +// let mut cbw_bytes = [0; 32]; +// let cbw = bytemuck::from_bytes_mut::(&mut cbw_bytes); +// +// cbw.signature = 0x43425355; +// cbw.transfer_length = response_len as u32; +// cbw.flags = flags; +// cbw.tag = tag; +// cbw.lun = lun; +// cbw.cb_length = command.len() as u8; +// cbw.cb_data[..command.len()].copy_from_slice(command); +// +// self.out_pipe +// .write(&cbw_bytes[..31]) +// .await +// .inspect_err(|error| log::error!("msc: CBW send error: {error:?}"))?; +// +// Ok(tag) +// } +// +// async fn read_csw(&mut self, tag: u32) -> Result<(), Error> { +// let mut csw_bytes = [0; 16]; +// self.in_pipe +// .read_exact(&mut csw_bytes[..13]) +// .await +// .inspect_err(|error| log::error!("msc: CSW receive error: {error:?}"))?; +// let csw = bytemuck::from_bytes::(&csw_bytes); +// +// if csw.signature != 0x53425355 { +// log::warn!("msc: invalid csw signature"); +// return Err(Error::InvalidArgument); +// } +// if csw.tag != tag { +// let csw_tag = csw.tag; +// log::warn!("msc: invalid csw tag (got {}, expected {tag})", csw_tag); +// return Err(Error::InvalidArgument); +// } +// if csw.status != 0x00 { +// return Err(Error::InvalidArgument); +// } +// Ok(()) +// } +// +// async fn read_response_data( +// &mut self, +// buffer: DmaSliceMut<'_, MaybeUninit>, +// ) -> Result { +// if buffer.len() == 0 { +// return Ok(0); +// } +// let len = self +// .in_pipe +// .read_dma(buffer) +// .await +// .inspect_err(|error| log::error!("msc: DMA read error: {error:?}"))?; +// Ok(len) +// } +// } +// +// #[async_trait] +// impl ScsiTransport for Bbb { +// fn allocate_buffer(&self, size: usize) -> Result]>, Error> { +// Ok(self.in_pipe.allocate_dma_buffer(size)?) +// } +// +// async fn perform_request_raw( +// &mut self, +// lun: u8, +// request_data: &[u8], +// response_buffer: DmaSliceMut<'_, MaybeUninit>, +// ) -> Result { +// if request_data.len() > 16 || response_buffer.len() > self.max_bytes_per_request() { +// return Err(Error::InvalidArgument); +// } +// +// let tag = self +// .send_cbw(lun, false, request_data, response_buffer.len()) +// .await?; +// let response_len = self.read_response_data(response_buffer).await?; +// self.read_csw(tag).await?; +// Ok(response_len) +// } +// +// fn max_bytes_per_request(&self) -> usize { +// 32768 +// } +// } +// +// impl UsbDeviceDetachHandler for DetachHandler { +// fn handle_device_detach(&self) { +// log::info!("Mass storage detached"); +// self.0.detach(); +// } +// } +// +// #[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) +// .await?; +// let out_pipe = device +// .open_bulk_out_pipe(out_index, out_info.max_packet_size as u16) +// .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, +// w_value: 0, +// w_index: 0, +// w_length: 0, +// }) +// .await?; +// +// // Get max LUN +// // TODO on devices which do not support multiple LUNs, this command may STALL +// let mut buffer = [MaybeUninit::uninit()]; +// let len = control_pipe +// .control_transfer_in( +// ControlTransferSetup { +// bm_request_type: GetMaxLun::BM_REQUEST_TYPE, +// b_request: GetMaxLun::B_REQUEST, +// w_value: 0, +// w_index: 0, +// w_length: 1, +// }, +// &mut buffer, +// ) +// .await?; +// let max_lun = if len < 1 { +// 0 +// } else { +// unsafe { buffer[0].assume_init() } +// }; +// +// let bbb = Bbb::new(device.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)); +// +// Ok(()) +// } +// +// fn name(&self) -> &'static str { +// "USB Mass Storage" +// } +// +// fn probe(&self, class: &UsbClassInfo, _device: &UsbDeviceAccess) -> bool { +// // TODO support other protocols +// class.class == UsbDeviceClass::MassStorage && class.interface_protocol_number == 0x50 +// } +// } diff --git a/kernel/driver/bus/usb/src/class_driver/mod.rs b/kernel/driver/bus/usb/src/class_driver/mod.rs index 6979aa45..821d7611 100644 --- a/kernel/driver/bus/usb/src/class_driver/mod.rs +++ b/kernel/driver/bus/usb/src/class_driver/mod.rs @@ -1,117 +1,208 @@ +use core::mem::MaybeUninit; + 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::{ + address::UsbInterfaceAddress, device::UsbDeviceAccess, error::UsbError, - info::{UsbDeviceClass, UsbDeviceProtocol}, + info::{UsbInterfaceInfo, CLASS_FROM_INTERFACE}, + pipe::control::{ControlTransferSetup, UsbClassSpecificRequest}, }; +// 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, +// error::UsbError, +// info::{UsbDeviceClass, UsbDeviceProtocol}, +// }; +// pub mod hid_keyboard; -pub mod mass_storage; - -#[derive(Debug)] -pub struct UsbClassInfo { - pub class: UsbDeviceClass, +pub mod hid_mouse; +// 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, +// } +// +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct UsbInterfaceClass { + pub class: u8, pub subclass: u8, - pub protocol: UsbDeviceProtocol, - pub device_protocol_number: u8, - pub interface_protocol_number: u8, + pub protocol: u8, } #[async_trait] -pub trait UsbDriver: Send + Sync { - async fn run(self: Arc, device: Arc) -> Result<(), UsbError>; +pub trait UsbInterfaceDriver: Send + Sync { + async fn run( + self: Arc, + device: Arc, + interface: UsbInterfaceInfo, + ) -> Result<(), UsbError>; fn name(&self) -> &'static str; - fn probe(&self, class: &UsbClassInfo, device: &UsbDeviceAccess) -> bool; + fn probe( + &self, + device: &UsbDeviceAccess, + interface: &UsbInterfaceInfo, + class: UsbInterfaceClass, + ) -> 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 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?; +// +// if config_info.interfaces.len() >= 1 { +// 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) +// } +// } +// +// async fn pick_driver( +// device: &UsbDeviceAccess, +// ) -> Result>, UsbError> { +// let Some(class) = extract_class_info(device).await? else { +// return Ok(None); +// }; +// +// for driver in USB_DEVICE_DRIVERS.read().iter() { +// if driver.probe(&class, device) { +// return Ok(Some(driver.clone())); +// } +// } +// Ok(None) +// } +// +// 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, +// // ); +// +// // e +// // } +// // e => e, +// // } +// // }) +// // .map_err(UsbError::SystemError)?; +// // } +// Ok(()) +// } - if config_info.interfaces.len() >= 1 { - 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) - } -} - -async fn pick_driver( - device: &UsbDeviceAccess, -) -> Result>, UsbError> { - let Some(class) = extract_class_info(device).await? else { - return Ok(None); +async fn setup_interface( + device: &Arc, + address: UsbInterfaceAddress, + interface: &UsbInterfaceInfo, +) -> Result<(), UsbError> { + let class = UsbInterfaceClass { + class: interface.interface_class, + subclass: interface.interface_subclass, + protocol: interface.interface_protocol, }; - - for driver in USB_DEVICE_DRIVERS.read().iter() { - if driver.probe(&class, device) { - return Ok(Some(driver.clone())); - } - } - Ok(None) -} - -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, - ); - - e + let drivers = USB_INTERFACE_DRIVERS.read(); + for driver in drivers.iter() { + if driver.probe(device, interface, class) { + let driver = driver.clone(); + let device = device.clone(); + let interface = interface.clone(); + runtime::spawn(async move { + let name = driver.name(); + match driver.run(device, interface).await { + e @ Err(UsbError::DeviceDisconnected) => { + log::warn!("{address} did not exit cleanly: device disconnected ({name})"); + e + } + e => e, } - e => e, - } - }) - .map_err(UsbError::SystemError)?; + }) + .map_err(UsbError::SystemError)?; + break; + } } Ok(()) } -pub fn register_driver(driver: Arc) { +pub async fn setup_device(device: Arc) -> Result<(), UsbError> { + // If device has only one configuration available, use it + // TODO support devices with multiple configurations + let address = device.bus_address(); + log::info!("Setup USB device @ {address}"); + + let Some(config_info) = device.use_default_configuration().await? else { + log::warn!("{address} has multiple configurations, not supported yet",); + return Ok(()); + }; + + // Setup drivers for interfaces + log::info!("{address}: {config_info:#?}"); + + // TODO device-level drivers + for interface in config_info.interfaces.iter() { + let address = address.with_interface(interface.number); + if let Err(error) = setup_interface(&device, address, interface).await { + log::error!("{}: {:?}", address, error); + } + } + + Ok(()) +} + +pub fn register_driver(driver: Arc) { // TODO check for duplicates - USB_DEVICE_DRIVERS.write().push(driver); + USB_INTERFACE_DRIVERS.write().push(driver); } pub fn register_default_class_drivers() { register_driver(Arc::new(hid_keyboard::UsbHidKeyboardDriver)); - register_driver(Arc::new(mass_storage::UsbMassStorageDriverBulkOnly)); + register_driver(Arc::new(hid_mouse::UsbHidMouseDriver)); + // register_driver(Arc::new(mass_storage::UsbMassStorageDriverBulkOnly)); } -static USB_DEVICE_DRIVERS: IrqSafeRwLock>> = +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..40640611 100644 --- a/kernel/driver/bus/usb/src/descriptor.rs +++ b/kernel/driver/bus/usb/src/descriptor.rs @@ -2,9 +2,9 @@ use bytemuck::{Pod, Zeroable}; use crate::{ communication::UsbDirection, - device::UsbSpeed, + device::{self, UsbSpeed}, error::UsbError, - info::{UsbDeviceClass, UsbDeviceProtocol, UsbEndpointType, UsbVersion}, + info::UsbEndpointType, }; #[derive(Clone, Copy, Debug, Default, Pod, Zeroable)] @@ -91,15 +91,15 @@ 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) - } -} +// 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 { @@ -127,16 +127,16 @@ impl UsbEndpointDescriptor { } impl UsbDeviceDescriptor { - pub fn class(&self) -> UsbDeviceClass { - UsbDeviceClass::try_from(self.device_class).unwrap_or(UsbDeviceClass::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 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) { + pub fn max_packet_size(&self, version: u16, speed: UsbSpeed) -> Result { + match (is_version_3(version), speed, self.max_packet_size_0) { (true, UsbSpeed::Super, 9) => Ok(1 << 9), (true, _, _) => todo!("Non-GenX speed USB3+ maxpacketsize0"), (false, _, 8) => Ok(8), @@ -147,3 +147,7 @@ impl UsbDeviceDescriptor { } } } + +pub fn is_version_3(version: u16) -> bool { + version & 0xFF00 == 0x300 +} diff --git a/kernel/driver/bus/usb/src/device.rs b/kernel/driver/bus/usb/src/device.rs index e8327bcd..2b8d8a16 100644 --- a/kernel/driver/bus/usb/src/device.rs +++ b/kernel/driver/bus/usb/src/device.rs @@ -1,4 +1,7 @@ -use core::{fmt, ops::Deref}; +use core::{ + fmt, + ops::{Deref, Sub}, +}; use alloc::{ boxed::Box, @@ -8,24 +11,18 @@ use alloc::{ vec::Vec, }; use async_trait::async_trait; -use libk::{ - error::Error, - fs::sysfs::{ - attribute::{StringAttribute, StringAttributeOps}, - object::KObject, - }, -}; +use libk::error::Error; use libk_util::{ sync::spin_rwlock::{IrqSafeRwLock, IrqSafeRwLockReadGuard}, OneTimeInit, }; use crate::{ - bus::{UsbBusWrapper, UsbDeviceKObject}, + address::UsbBusAddress, + bus::UsbBusWrapper, error::UsbError, info::{ - UsbConfigurationInfo, UsbDeviceClass, UsbDeviceInfo, UsbEndpointInfo, UsbEndpointType, - UsbInterfaceInfo, UsbVersion, + UsbConfigurationInfo, UsbDeviceInfo, UsbEndpointInfo, UsbEndpointType, UsbInterfaceInfo, }, pipe::{ control::{ConfigurationDescriptorEntry, UsbControlPipeAccess}, @@ -34,24 +31,26 @@ use crate::{ UsbNormalPipeOut, }, }, + sysfs::UsbDeviceKObject, UsbHostController, }; // High-level structures for info provided through descriptors -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] -pub struct UsbBusAddress { - pub bus: u16, - pub device: u8, -} +// #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] +// pub struct UsbBusAddress { +// pub bus: u16, +// pub device: u8, +// } pub struct UsbDeviceAccess { pub device: Arc, pub bus: Arc, pub info: UsbDeviceInfo, - pub current_configuration: IrqSafeRwLock>, + pub configurations: Vec, + current_configuration: IrqSafeRwLock>, - kobject: OneTimeInit, + pub(crate) kobject: OneTimeInit, } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] @@ -98,76 +97,6 @@ pub trait UsbDevice: Send + Sync { } impl UsbDeviceAccess { - pub(crate) fn register_sysfs_object(self: &Arc) { - struct Class; - struct Version; - struct IdVendor; - struct IdProduct; - - impl StringAttributeOps for Class { - type Data = Arc; - const NAME: &'static str = "class"; - - fn read(state: &Self::Data) -> Result { - let s = match state.info.device_class { - UsbDeviceClass::Hid => "hid", - UsbDeviceClass::MassStorage => "mass-storage", - UsbDeviceClass::FromInterface => "-", - UsbDeviceClass::Unknown => "unknown", - }; - Ok(s.into()) - } - } - - impl StringAttributeOps for Version { - type Data = Arc; - const NAME: &'static str = "version"; - - fn read(state: &Self::Data) -> Result { - Ok(state.info.usb_version.to_string()) - } - } - - impl StringAttributeOps for IdProduct { - type Data = Arc; - const NAME: &'static str = "product"; - - fn read(state: &Self::Data) -> Result { - Ok(format!("{:x}", state.info.id_product)) - } - } - impl StringAttributeOps for IdVendor { - type Data = Arc; - const NAME: &'static str = "vendor"; - - fn read(state: &Self::Data) -> Result { - Ok(format!("{:x}", state.info.id_vendor)) - } - } - - let bus_kobject = self.bus.kobject(); - let device_kobject = self.kobject.init(KObject::new(self.clone())); - - device_kobject - .add_attribute(StringAttribute::from(Class)) - .ok(); - device_kobject - .add_attribute(StringAttribute::from(Version)) - .ok(); - device_kobject - .add_attribute(StringAttribute::from(IdVendor)) - .ok(); - device_kobject - .add_attribute(StringAttribute::from(IdProduct)) - .ok(); - - let address = self.bus_address(); - - bus_kobject - .add_object(format!("{}", address.device), device_kobject.clone()) - .ok(); - } - /// Expected device state: /// /// * Link-layer stuff has been reset and established properly by the HCD @@ -179,43 +108,36 @@ impl UsbDeviceAccess { let device_desc = control.query_device_descriptor().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}", - raw.bus_address(), - bcd_usb - ) - })?; - let manufacturer = control.query_string(device_desc.manufacturer_str).await?; let product = control.query_string(device_desc.product_str).await?; + // Query device let info = UsbDeviceInfo { manufacturer, product, - usb_version, + usb_version: device_desc.bcd_usb, id_vendor: device_desc.id_vendor, id_product: device_desc.id_product, - device_class: device_desc.class(), + device_class: device_desc.device_class, device_subclass: device_desc.device_subclass, - device_protocol: device_desc.protocol(), - device_protocol_number: device_desc.device_protocol, + device_protocol: device_desc.device_protocol, num_configurations: device_desc.num_configurations, - max_packet_size: device_desc.max_packet_size(usb_version, raw.speed())?, + max_packet_size: device_desc.max_packet_size(device_desc.bcd_usb, raw.speed())?, }; + let configurations = + Self::query_configurations(control, device_desc.num_configurations).await?; + Ok(Self { device: raw, bus, info, current_configuration: IrqSafeRwLock::new(None), + configurations, kobject: OneTimeInit::new(), }) @@ -257,45 +179,54 @@ impl UsbDeviceAccess { Ok(UsbBulkOutPipeAccess(pipe)) } - pub fn read_current_configuration( - &self, - ) -> IrqSafeRwLockReadGuard<'_, Option> { - self.current_configuration.read() + pub fn current_configuration(&self) -> Option<&UsbConfigurationInfo> { + let index = (*self.current_configuration.read())?; + Some(&self.configurations[index]) } - pub async fn select_configuration bool>( + pub async fn use_default_configuration( &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())); - } + if self.configurations.len() != 1 { + return Ok(None); } - Ok(None) + self.set_configuration(0).await.map(Some) } - pub async fn query_configuration_info( - &self, - index: u8, - ) -> Result { - if index >= self.info.num_configurations { + pub async fn set_configuration(&self, index: usize) -> Result { + if index >= self.configurations.len() { return Err(UsbError::InvalidConfiguration); } + + let mut current = self.current_configuration.write(); let control_pipe = self.control_pipe(); + let info = self.configurations[index].clone(); + + control_pipe + .set_configuration(info.config_value as _) + .await?; + *current = Some(index); + + Ok(info) + } + + async fn query_configurations( + control_pipe: &UsbControlPipeAccess, + num_configurations: u8, + ) -> Result, UsbError> { + let mut configurations = Vec::new(); + for i in 0..num_configurations { + let configuration = Self::query_configuration(control_pipe, i).await?; + configurations.push(configuration); + } + Ok(configurations) + } + + async fn query_configuration( + control_pipe: &UsbControlPipeAccess, + index: u8, + ) -> Result { let query = control_pipe.query_configuration_descriptor(index).await?; let configuration_name = control_pipe @@ -321,10 +252,9 @@ impl UsbDeviceAccess { name, number: iface.interface_number, - interface_class: iface.class(), + interface_class: iface.interface_class, interface_subclass: iface.interface_subclass, - interface_protocol: iface.protocol(), - interface_protocol_number: iface.interface_protocol, + interface_protocol: iface.interface_protocol, }); } _ => (), @@ -341,6 +271,13 @@ impl UsbDeviceAccess { Ok(info) } + // pub async fn query_configuration_info( + // &self, + // index: u8, + // ) -> Result { + // let control_pipe = self.control_pipe(); + // } + pub fn set_detach_handler(&self, handler: Arc) { self.device.set_detach_handler(handler); } @@ -353,9 +290,3 @@ impl Deref for UsbDeviceAccess { &*self.device } } - -impl fmt::Display for UsbBusAddress { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}:{}", self.bus, self.device) - } -} diff --git a/kernel/driver/bus/usb/src/info.rs b/kernel/driver/bus/usb/src/info.rs index 4366f851..3b0f6c29 100644 --- a/kernel/driver/bus/usb/src/info.rs +++ b/kernel/driver/bus/usb/src/info.rs @@ -29,41 +29,51 @@ pub enum UsbUsageType { Reserved, } -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] -pub enum UsbVersion { - Usb11, - Usb20, - Usb21, - Usb30, - Usb31, - Usb32, -} +// #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] +// pub enum UsbVersion { +// Usb11, +// Usb20, +// Usb21, +// Usb30, +// Usb31, +// Usb32, +// } -primitive_enum! { - pub enum UsbDeviceClass: u8 { - FromInterface = 0x00, - Hid = 0x03, - MassStorage = 0x08, - Unknown = 0xFF, - } -} +pub const CLASS_FROM_INTERFACE: u8 = 0x00; +pub const CLASS_HID: u8 = 0x03; +pub const CLASS_MASS_STORAGE: u8 = 0x08; -primitive_enum! { - pub enum UsbDeviceProtocol: u8 { - FromInterface = 0x00, - Unknown = 0xFF, - } -} +// primitive_enum! { +// pub enum UsbDeviceClass: u8 { +// FromInterface = 0x00, +// Hid = 0x03, +// MassStorage = 0x08, +// Unknown = 0xFF, +// } +// } +// +// primitive_enum! { +// pub enum UsbDeviceProtocol: u8 { +// FromInterface = 0x00, +// Unknown = 0xFF, +// } +// } #[derive(Debug, Clone)] pub struct UsbInterfaceInfo { pub name: String, pub number: 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, + // pub name: String, + // pub number: u8, + + // pub interface_class: UsbDeviceClass, + // pub interface_subclass: u8, + // pub interface_protocol: UsbDeviceProtocol, + // pub interface_protocol_number: u8, } #[derive(Debug, Clone)] @@ -87,15 +97,14 @@ pub struct UsbDeviceInfo { pub manufacturer: String, pub product: String, - pub usb_version: UsbVersion, + pub usb_version: u16, pub id_vendor: u16, pub id_product: u16, - pub device_class: UsbDeviceClass, + pub device_class: u8, pub device_subclass: u8, - pub device_protocol: UsbDeviceProtocol, - pub device_protocol_number: u8, + pub device_protocol: u8, /// Max packet size for endpoint zero pub max_packet_size: usize, @@ -103,37 +112,37 @@ pub struct UsbDeviceInfo { pub num_configurations: u8, } -impl UsbVersion { - pub fn is_version_3(&self) -> bool { - matches!(self, Self::Usb30 | Self::Usb31 | Self::Usb32) - } - - pub fn from_bcd_usb(value: u16) -> Option { - match value { - 0x110 => Some(UsbVersion::Usb11), - 0x200..=0x20F => Some(UsbVersion::Usb20), - 0x210..=0x21F => Some(UsbVersion::Usb21), - 0x300 => Some(UsbVersion::Usb30), - 0x310 => Some(UsbVersion::Usb31), - 0x320 => Some(UsbVersion::Usb32), - _ => None, - } - } -} - -impl fmt::Display for UsbVersion { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let string = match self { - Self::Usb11 => "USB1.1", - Self::Usb20 => "USB2.0", - Self::Usb21 => "USB2.1", - Self::Usb30 => "USB3.0", - Self::Usb31 => "USB3.1", - Self::Usb32 => "USB3.2", - }; - f.write_str(string) - } -} +// impl UsbVersion { +// pub fn is_version_3(&self) -> bool { +// matches!(self, Self::Usb30 | Self::Usb31 | Self::Usb32) +// } +// +// pub fn from_bcd_usb(value: u16) -> Option { +// match value { +// 0x110 => Some(UsbVersion::Usb11), +// 0x200..=0x20F => Some(UsbVersion::Usb20), +// 0x210..=0x21F => Some(UsbVersion::Usb21), +// 0x300 => Some(UsbVersion::Usb30), +// 0x310 => Some(UsbVersion::Usb31), +// 0x320 => Some(UsbVersion::Usb32), +// _ => None, +// } +// } +// } +// +// impl fmt::Display for UsbVersion { +// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// let string = match self { +// Self::Usb11 => "USB1.1", +// Self::Usb20 => "USB2.0", +// Self::Usb21 => "USB2.1", +// Self::Usb30 => "USB3.0", +// Self::Usb31 => "USB3.1", +// Self::Usb32 => "USB3.2", +// }; +// f.write_str(string) +// } +// } impl UsbEndpointInfo { pub fn is(&self, ty: UsbEndpointType, dir: UsbDirection) -> bool { diff --git a/kernel/driver/bus/usb/src/interface.rs b/kernel/driver/bus/usb/src/interface.rs new file mode 100644 index 00000000..1ef4a52d --- /dev/null +++ b/kernel/driver/bus/usb/src/interface.rs @@ -0,0 +1 @@ +pub struct UsbInterface {} diff --git a/kernel/driver/bus/usb/src/lib.rs b/kernel/driver/bus/usb/src/lib.rs index 1de1d6bf..4f02bff1 100644 --- a/kernel/driver/bus/usb/src/lib.rs +++ b/kernel/driver/bus/usb/src/lib.rs @@ -8,17 +8,20 @@ maybe_uninit_fill )] -use crate::bus::UsbBusKObject; +use crate::sysfs::UsbBusKObject; extern crate alloc; +pub mod address; pub mod bus; pub mod communication; pub mod descriptor; pub mod device; pub mod error; pub mod info; +pub mod interface; pub mod pipe; +pub mod sysfs; pub mod util; pub mod class_driver; diff --git a/kernel/driver/bus/usb/src/pipe/control.rs b/kernel/driver/bus/usb/src/pipe/control.rs index 5133c31f..af00657a 100644 --- a/kernel/driver/bus/usb/src/pipe/control.rs +++ b/kernel/driver/bus/usb/src/pipe/control.rs @@ -37,6 +37,7 @@ pub trait UsbDeviceRequest: Sized + Pod { pub trait UsbClassSpecificRequest: Sized + Pod { const BM_REQUEST_TYPE: u8; const B_REQUEST: u8; + const W_VALUE: u16 = 0; } pub trait UsbDescriptorRequest: UsbDeviceRequest { diff --git a/kernel/driver/bus/usb/src/sysfs.rs b/kernel/driver/bus/usb/src/sysfs.rs new file mode 100644 index 00000000..6a51577f --- /dev/null +++ b/kernel/driver/bus/usb/src/sysfs.rs @@ -0,0 +1,129 @@ +use alloc::{format, sync::Arc}; +use libk::{ + error::Error, + fs::sysfs::{ + self, + attribute::{IntegerAttribute, IntegerAttributeFormat, IntegerAttributeOps}, + object::KObject, + }, +}; +use libk_util::OneTimeInit; + +use crate::{bus::UsbBusWrapper, device::UsbDeviceAccess}; + +pub type UsbBusKObject = Arc>>; +pub type UsbDeviceKObject = Arc>>; + +pub(crate) fn register_bus_kobject(bus: &Arc) -> UsbBusKObject { + let root = sysfs_usb_root(); + let bus_kobject = KObject::new(bus.clone()); + bus.hc.register_sysfs_properties(&bus_kobject); + root.add_object(format!("{}", bus.index), bus_kobject.clone()) + .ok(); + bus_kobject +} + +pub(crate) fn register_device_kobject(device: &Arc) -> UsbDeviceKObject { + struct Class; + struct Subclass; + struct Protocol; + struct Version; + struct IdVendor; + struct IdProduct; + + impl IntegerAttributeOps for Class { + type Data = Arc; + const NAME: &'static str = "class"; + const FORMAT: IntegerAttributeFormat = IntegerAttributeFormat::Hex; + + fn read(state: &Self::Data) -> Result { + Ok(state.info.device_class) + } + } + impl IntegerAttributeOps for Subclass { + type Data = Arc; + const NAME: &'static str = "subclass"; + const FORMAT: IntegerAttributeFormat = IntegerAttributeFormat::Hex; + + fn read(state: &Self::Data) -> Result { + Ok(state.info.device_subclass) + } + } + impl IntegerAttributeOps for Protocol { + type Data = Arc; + const NAME: &'static str = "protocol"; + const FORMAT: IntegerAttributeFormat = IntegerAttributeFormat::Hex; + + fn read(state: &Self::Data) -> Result { + Ok(state.info.device_protocol) + } + } + impl IntegerAttributeOps for Version { + type Data = Arc; + const NAME: &'static str = "version"; + const FORMAT: IntegerAttributeFormat = IntegerAttributeFormat::Hex; + + fn read(state: &Self::Data) -> Result { + Ok(state.info.usb_version) + } + } + impl IntegerAttributeOps for IdVendor { + type Data = Arc; + const NAME: &'static str = "vendor"; + const FORMAT: IntegerAttributeFormat = IntegerAttributeFormat::Hex; + + fn read(state: &Self::Data) -> Result { + Ok(state.info.id_vendor) + } + } + impl IntegerAttributeOps for IdProduct { + type Data = Arc; + const NAME: &'static str = "product"; + const FORMAT: IntegerAttributeFormat = IntegerAttributeFormat::Hex; + + fn read(state: &Self::Data) -> Result { + Ok(state.info.id_product) + } + } + + let bus_kobject = device.bus.kobject(); + let device_kobject = KObject::new(device.clone()); + + device_kobject + .add_attribute(IntegerAttribute::from(Class)) + .ok(); + device_kobject + .add_attribute(IntegerAttribute::from(Subclass)) + .ok(); + device_kobject + .add_attribute(IntegerAttribute::from(Protocol)) + .ok(); + device_kobject + .add_attribute(IntegerAttribute::from(Version)) + .ok(); + device_kobject + .add_attribute(IntegerAttribute::from(IdVendor)) + .ok(); + device_kobject + .add_attribute(IntegerAttribute::from(IdProduct)) + .ok(); + + let address = device.bus_address(); + + bus_kobject + .add_object(format!("{}", address.device), device_kobject.clone()) + .ok(); + + device_kobject +} + +fn sysfs_usb_root() -> &'static Arc> { + static USB_ROOT: OneTimeInit>> = OneTimeInit::new(); + + USB_ROOT.or_init_with(|| { + let bus_object = sysfs::bus().expect("bus object"); + let usb_object = KObject::new(()); + bus_object.add_object("usb", usb_object.clone()).ok(); + usb_object + }) +} diff --git a/kernel/driver/input/src/lib.rs b/kernel/driver/input/src/lib.rs index b3523d3a..34222fe4 100644 --- a/kernel/driver/input/src/lib.rs +++ b/kernel/driver/input/src/lib.rs @@ -9,14 +9,20 @@ use async_trait::async_trait; use device_api::device::Device; use libk::{device::char::CharDevice, vfs::FileReadiness}; use libk_util::{ring::LossyRingQueue, OneTimeInit}; -use yggdrasil_abi::{error::Error, io::KeyboardKeyEvent}; +use yggdrasil_abi::{ + abi_serde::wire, + 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 +39,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 +51,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 +74,68 @@ impl CharDevice for KeyboardDevice { } } -static INPUT_QUEUE: LossyRingQueue = LossyRingQueue::with_capacity(32); +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 { + let ev = MOUSE_INPUT_QUEUE.read().await; + let len = wire::to_slice(&ev, buf)?; + Ok(len) + } + + fn read_nonblocking(&self, buf: &mut [u8]) -> Result { + let ev = MOUSE_INPUT_QUEUE.try_read().ok_or(Error::WouldBlock)?; + let len = wire::to_slice(&ev, buf)?; + Ok(len) + } + + 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 KEYBOARD_DEVICE: OneTimeInit> = OneTimeInit::new(); -pub fn setup() -> Arc { +static MOUSE_INPUT_QUEUE: LossyRingQueue = LossyRingQueue::with_capacity(32); +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_keyboard_event(ev: KeyboardKeyEvent) { + KEYBOARD_INPUT_QUEUE.write(ev); +} + +pub fn send_mouse_event(ev: MouseEvent) { + MOUSE_INPUT_QUEUE.write(ev); } diff --git a/kernel/driver/usb/xhci/src/controller.rs b/kernel/driver/usb/xhci/src/controller.rs index 9a95b2e7..46472107 100644 --- a/kernel/driver/usb/xhci/src/controller.rs +++ b/kernel/driver/usb/xhci/src/controller.rs @@ -25,10 +25,11 @@ use tock_registers::{ }; use ygg_driver_pci::{device::PciDeviceInfo, PciConfigurationSpace}; use ygg_driver_usb::{ + address::UsbBusAddress, bus::{UsbBusManager, UsbBusWrapper}, - device::{UsbBusAddress, UsbDeviceAccess, UsbSpeed}, + descriptor, + device::{UsbDeviceAccess, UsbSpeed}, error::UsbError, - info::UsbVersion, pipe::control::UsbControlPipeAccess, UsbHostController, }; @@ -67,7 +68,7 @@ struct ScratchpadArray { } struct RootHubPort { - version: UsbVersion, + version: u16, slot_type: u8, } @@ -147,9 +148,7 @@ impl Xhci { for cap in regs.extended_capabilities.iter() { match cap { ExtendedCapability::ProtocolSupport(support) => { - let Some(version) = support.usb_revision() else { - continue; - }; + let version = support.usb_revision(); for port in support.port_range() { log::info!("* Port {port}: {version}"); @@ -284,7 +283,7 @@ impl Xhci { .as_ref() .ok_or(UsbError::PortInitFailed)?; - let need_reset = !root_hub_port.version.is_version_3(); + let need_reset = !descriptor::is_version_3(root_hub_port.version); if need_reset { self.reset_port(regs).await?; diff --git a/kernel/driver/usb/xhci/src/device.rs b/kernel/driver/usb/xhci/src/device.rs index 7393a0c9..ad25858d 100644 --- a/kernel/driver/usb/xhci/src/device.rs +++ b/kernel/driver/usb/xhci/src/device.rs @@ -6,8 +6,9 @@ use libk_util::{ }; use xhci_lib::context; use ygg_driver_usb::{ + address::UsbBusAddress, communication::UsbDirection, - device::{UsbBusAddress, UsbDevice, UsbDeviceDetachHandler, UsbSpeed}, + device::{UsbDevice, UsbDeviceDetachHandler, UsbSpeed}, error::UsbError, info::UsbEndpointType, pipe::{ diff --git a/kernel/driver/usb/xhci/src/regs/extended.rs b/kernel/driver/usb/xhci/src/regs/extended.rs index 0bb65b6c..244863a0 100644 --- a/kernel/driver/usb/xhci/src/regs/extended.rs +++ b/kernel/driver/usb/xhci/src/regs/extended.rs @@ -7,7 +7,7 @@ use alloc::vec::Vec; use libk::error::Error; use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo}; use libk_util::sync::spin_rwlock::IrqSafeRwLock; -use ygg_driver_usb::{error::UsbError, info::UsbVersion}; +use ygg_driver_usb::error::UsbError; pub struct ProtocolSupport { words: [u32; 4], @@ -69,8 +69,8 @@ impl ExtendedCapability { } impl ProtocolSupport { - pub fn usb_revision(&self) -> Option { - UsbVersion::from_bcd_usb((self.words[0] >> 16) as u16) + pub fn usb_revision(&self) -> u16 { + (self.words[0] >> 16) as u16 } pub fn slot_type(&self) -> u8 { diff --git a/kernel/libk/src/fs/sysfs/attribute/integer.rs b/kernel/libk/src/fs/sysfs/attribute/integer.rs new file mode 100644 index 00000000..67104488 --- /dev/null +++ b/kernel/libk/src/fs/sysfs/attribute/integer.rs @@ -0,0 +1,239 @@ +use core::{ + any::Any, + marker::PhantomData, + sync::atomic::{AtomicBool, Ordering}, +}; + +use alloc::{ + string::{String, ToString}, + sync::Arc, + vec::Vec, +}; +use libk_util::sync::spin_rwlock::IrqSafeRwLock; +use yggdrasil_abi::{ + error::Error, + io::{FileMode, OpenOptions}, +}; + +use crate::{ + fs::sysfs::object::KObject, + vfs::{CommonImpl, Filename, InstanceData, Metadata, Node, NodeFlags, NodeRef, RegularImpl}, +}; + +use super::Attribute; + +pub trait IntegerAttributeValue: Copy + Sync + Send + 'static { + fn to_bytes(&self, format: IntegerAttributeFormat) -> Vec; +} + +pub enum IntegerAttributeFormat { + Decimal, + Octal, + Hex, +} + +macro_rules! impl_integer_value { + ($($ty:ty),+) => { + $( + impl IntegerAttributeValue for $ty { + fn to_bytes(&self, format: IntegerAttributeFormat) -> Vec { + match format { + IntegerAttributeFormat::Decimal => alloc::format!("{self}"), + IntegerAttributeFormat::Octal => alloc::format!("{self:o}"), + IntegerAttributeFormat::Hex => alloc::format!("{self:x}"), + }.into_bytes() + } + } + )+ + }; +} + +impl_integer_value!(u8, u16, u32, u64); + +pub trait IntegerAttributeOps: Sync + Send + 'static { + type Data: Send + 'static = (); + + const WRITEABLE: bool = false; + const NAME: &'static str; + const FORMAT: IntegerAttributeFormat = IntegerAttributeFormat::Decimal; + + fn read(state: &Self::Data) -> Result { + let _ = state; + Err(Error::NotImplemented) + } + fn write(state: &Self::Data, value: T) -> Result<(), Error> { + let _ = state; + let _ = value; + Err(Error::ReadOnly) + } +} + +pub struct IntegerAttribute>( + PhantomData<(T, V)>, +); + +struct IntegerAttributeNode> { + object: Arc>, + _pd: PhantomData, +} + +struct IntegerAttributeState { + value: IrqSafeRwLock>, + modified: AtomicBool, + _pd: PhantomData, +} + +impl> CommonImpl + for IntegerAttributeNode +{ + fn size(&self, _node: &NodeRef) -> Result { + Ok(0) + } + + fn as_any(&self) -> &dyn Any { + self as _ + } +} + +impl> RegularImpl + for IntegerAttributeNode +{ + fn open( + &self, + _node: &NodeRef, + opts: OpenOptions, + ) -> Result<(u64, Option), Error> { + if opts.contains(OpenOptions::WRITE) && !V::WRITEABLE { + return Err(Error::ReadOnly); + } + + let mut value = V::read(self.object.data())?.to_bytes(V::FORMAT); + value.push(b'\n'); + + let instance = IntegerAttributeState { + value: IrqSafeRwLock::new(value), + modified: AtomicBool::new(false), + _pd: PhantomData::, + }; + + Ok((0, Some(Arc::new(instance)))) + } + + fn close(&self, _node: &NodeRef, instance: Option<&InstanceData>) -> Result<(), Error> { + if V::WRITEABLE { + todo!() + // let instance = instance.ok_or(Error::InvalidFile)?; + // let instance = instance + // .downcast_ref::() + // .ok_or(Error::InvalidFile)?; + + // if instance.modified.load(Ordering::Acquire) { + // let value = instance.value.read(); + // let value_str = + // core::str::from_utf8(&value[..]).map_err(|_| Error::InvalidArgument)?; + + // // Trim whitespace and newlines + // V::write(&self.object.data, value_str.trim())?; + // } + } + + Ok(()) + } + + fn read( + &self, + _node: &NodeRef, + instance: Option<&InstanceData>, + pos: u64, + buf: &mut [u8], + ) -> Result { + let instance = instance.ok_or(Error::InvalidFile)?; + let instance = instance + .downcast_ref::>() + .ok_or(Error::InvalidFile)?; + + let value = instance.value.read(); + let len = value.len(); + if pos >= len as u64 { + return Ok(0); + } + let pos = pos as usize; + let amount = (len - pos).min(buf.len()); + buf[..amount].copy_from_slice(&value[pos..pos + amount]); + + Ok(amount) + } + + fn write( + &self, + _node: &NodeRef, + instance: Option<&InstanceData>, + pos: u64, + buf: &[u8], + ) -> Result { + todo!() + // if !V::WRITEABLE { + // return Err(Error::InvalidFile); + // } + // let instance = instance.ok_or(Error::InvalidFile)?; + // let instance = instance + // .downcast_ref::() + // .ok_or(Error::InvalidFile)?; + + // let mut value = instance.value.write(); + + // let pos: usize = pos.try_into().map_err(|_| Error::InvalidFile)?; + // if pos > value.len() { + // return Err(Error::InvalidArgument); + // } + // if pos + buf.len() > V::LIMIT { + // return Err(Error::InvalidArgument); + // } + + // let amount_copy = (value.len() - pos).min(buf.len()); + + // value[pos..pos + amount_copy].copy_from_slice(&buf[..amount_copy]); + // if amount_copy < buf.len() { + // value.extend_from_slice(&buf[amount_copy..]); + // } + // instance.modified.store(true, Ordering::Release); + + // Ok(buf.len()) + } + + fn truncate(&self, _node: &NodeRef, _new_size: u64) -> Result<(), Error> { + Ok(()) + } +} + +impl> From for IntegerAttribute { + fn from(_value: V) -> Self { + Self(PhantomData) + } +} + +impl> Attribute + for IntegerAttribute +{ + fn instantiate(&self, parent: &Arc>) -> Result, Error> { + let mode = match V::WRITEABLE { + false => FileMode::new(0o444), + true => FileMode::new(0o644), + }; + + Ok(Node::regular( + IntegerAttributeNode { + object: parent.clone(), + _pd: PhantomData::, + }, + NodeFlags::IN_MEMORY_PROPS, + Some(Metadata::now_root(mode, 0)), + None, + )) + } + + // TODO implement this properly + fn name(&self) -> &Filename { + unsafe { Filename::from_str_unchecked(V::NAME) } + } +} diff --git a/kernel/libk/src/fs/sysfs/attribute/mod.rs b/kernel/libk/src/fs/sysfs/attribute/mod.rs index 5617f452..0704da65 100644 --- a/kernel/libk/src/fs/sysfs/attribute/mod.rs +++ b/kernel/libk/src/fs/sysfs/attribute/mod.rs @@ -6,6 +6,7 @@ use crate::vfs::{Filename, NodeRef}; use super::object::KObject; mod bytes; +mod integer; mod string; pub trait Attribute: Sync + Send { @@ -14,4 +15,7 @@ pub trait Attribute: Sync + Send { } pub use bytes::{BytesAttribute, BytesAttributeOps}; +pub use integer::{ + IntegerAttribute, IntegerAttributeFormat, IntegerAttributeOps, IntegerAttributeValue, +}; pub use string::{StringAttribute, StringAttributeOps}; diff --git a/kernel/src/arch/i686/mod.rs b/kernel/src/arch/i686/mod.rs index 3512fbc7..3f8d1b9e 100644 --- a/kernel/src/arch/i686/mod.rs +++ b/kernel/src/arch/i686/mod.rs @@ -140,7 +140,7 @@ impl I686 { TerminalInput::with_capacity(256)?, ConsoleWrapper(textfb), )); - let keyboard_input = ygg_driver_input::setup(); + let keyboard_input = ygg_driver_input::setup_keyboard(); runtime::spawn( textfb_console diff --git a/kernel/src/arch/x86/peripherals/ps2/mod.rs b/kernel/src/arch/x86/peripherals/ps2/mod.rs index 05a907ee..26c87c67 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 cb2a4e9d..0478d24d 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -168,11 +168,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(0o440), + ) { + log::error!("Couldn't add pointer 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..97438f71 100644 --- a/lib/abi/src/io/input.rs +++ b/lib/abi/src/io/input.rs @@ -1,3 +1,5 @@ +use abi_serde::{impl_newtype_serde, impl_struct_serde}; + /// Describes a key pressed/released on a keyboard device // Missing docs: self-explanatory names #[allow(missing_docs)] @@ -47,6 +49,43 @@ pub enum KeyboardKeyEvent { Released(KeyboardKey), } +/// Representation for button press state +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[repr(transparent)] +pub struct ButtonMask(pub u8); + +impl_newtype_serde!(ButtonMask); + +/// Representation for mouse event +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct MouseEvent { + /// Current button state + pub buttons: ButtonMask, + /// X delta + pub dx: i32, + /// Y delta + pub dy: i32, +} + +impl_struct_serde!(MouseEvent: [ + buttons, + dx, + dy +]); + +impl MouseEvent { + /// Returns `true` if the event has corresponding button set + pub fn button(&self, index: usize) -> bool { + if index >= 8 { + false + } else { + self.buttons.0 & (1 << index) != 0 + } + } +} + 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..cecb729e 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::{ButtonMask, KeyboardKey, KeyboardKeyCode, KeyboardKeyEvent, MouseEvent}; pub use terminal::{ TerminalControlCharacters, TerminalInputOptions, TerminalLineOptions, TerminalOptions, TerminalOutputOptions, TerminalSize, diff --git a/lib/runtime/src/io/input.rs b/lib/runtime/src/io/input.rs new file mode 100644 index 00000000..c85bd255 --- /dev/null +++ b/lib/runtime/src/io/input.rs @@ -0,0 +1,7 @@ +use abi::error::Error; +pub use abi::io::{ButtonMask, MouseEvent}; +use abi_serde::wire; + +pub fn parse_mouse_event(buffer: &[u8]) -> Result { + wire::from_slice(buffer).map_err(Error::from) +} diff --git a/lib/runtime/src/io/mod.rs b/lib/runtime/src/io/mod.rs index 5bef99d7..1b9f6c5a 100644 --- a/lib/runtime/src/io/mod.rs +++ b/lib/runtime/src/io/mod.rs @@ -13,6 +13,7 @@ pub use abi::option::OptionSizeHint; pub mod device; pub mod filesystem; +pub mod input; pub mod paths; pub mod terminal; pub use paths::*;