diff --git a/Cargo.lock b/Cargo.lock index 1c8f413c60..56c5b23ca3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1534,6 +1534,16 @@ dependencies = [ "xhcid", ] +[[package]] +name = "usbhubd" +version = "0.1.0" +dependencies = [ + "log", + "redox-log", + "redox_syscall 0.5.1", + "xhcid", +] + [[package]] name = "usbscsid" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index ec66f52ad5..65715466f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "vboxd", "xhcid", "usbctl", + "usbhubd", "usbhidd", "inputd", "virtio-core", diff --git a/usbhubd/.gitignore b/usbhubd/.gitignore new file mode 100644 index 0000000000..ea8c4bf7f3 --- /dev/null +++ b/usbhubd/.gitignore @@ -0,0 +1 @@ +/target diff --git a/usbhubd/Cargo.toml b/usbhubd/Cargo.toml new file mode 100644 index 0000000000..abc8eb8abc --- /dev/null +++ b/usbhubd/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "usbhubd" +version = "0.1.0" +edition = "2018" +license = "MIT" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +log = "0.4" +redox-log = "0.1" +redox_syscall = "0.5" +xhcid = { path = "../xhcid" } diff --git a/usbhubd/src/main.rs b/usbhubd/src/main.rs new file mode 100644 index 0000000000..7c95cb6b5d --- /dev/null +++ b/usbhubd/src/main.rs @@ -0,0 +1,132 @@ +use std::collections::VecDeque; +use std::env; +use std::fs::File; +use std::io::{Read, Write}; + +use redox_log::{OutputBuilder, RedoxLogger}; +use xhcid_interface::{plain, usb, ConfigureEndpointsReq, DevDesc, DeviceReqData, EndpDirection, EndpointTy, PortReqRecipient, PortReqTy, XhciClientHandle}; + +fn setup_logging() -> Option<&'static RedoxLogger> { + let mut logger = RedoxLogger::new().with_output( + OutputBuilder::stderr() + .with_filter(log::LevelFilter::Info) // limit global output to important info + .with_ansi_escape_codes() + .flush_on_newline(true) + .build(), + ); + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("usb", "device", "hub.log") { + Ok(b) => { + logger = logger.with_output( + // TODO: Add a configuration file for this + b.with_filter(log::LevelFilter::Info) + .flush_on_newline(true) + .build(), + ) + } + Err(error) => eprintln!("Failed to create hub.log: {}", error), + } + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("usb", "device", "hub.ansi.log") { + Ok(b) => { + logger = logger.with_output( + b.with_filter(log::LevelFilter::Info) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build(), + ) + } + Err(error) => eprintln!("Failed to create hub.ansi.log: {}", error), + } + + match logger.enable() { + Ok(logger_ref) => { + eprintln!("usbhubd: enabled logger"); + Some(logger_ref) + } + Err(error) => { + eprintln!("usbhubd: failed to set default logger: {}", error); + None + } + } +} + +fn main() { + let _logger_ref = setup_logging(); + + let mut args = env::args().skip(1); + + const USAGE: &'static str = "usbhubd "; + + let scheme = args.next().expect(USAGE); + let port = args + .next() + .expect(USAGE) + .parse::() + .expect("Expected integer as input of port"); + let interface_num = args + .next() + .expect(USAGE) + .parse::() + .expect("Expected integer as input of interface"); + + log::info!( + "USB HUB driver spawned with scheme `{}`, port {}, interface {}", + scheme, + port, + interface_num + ); + + let handle = XhciClientHandle::new(scheme, port); + let desc: DevDesc = handle + .get_standard_descs() + .expect("Failed to get standard descriptors"); + log::info!("{:X?}", desc); + + let (conf_desc, conf_num, if_desc) = desc + .config_descs + .iter() + .enumerate() + .find_map(|(conf_num, conf_desc)| { + let if_desc = conf_desc.interface_descs.iter().find_map(|if_desc| { + if if_desc.number == interface_num { + Some(if_desc.clone()) + } else { + None + } + })?; + Some(( + conf_desc.clone(), + conf_num, + if_desc, + )) + }) + .expect("Failed to find suitable configuration"); + + /*TODO + handle + .configure_endpoints(&ConfigureEndpointsReq { + config_desc: conf_num as u8, + interface_desc: Some(interface_num), + alternate_setting: Some(if_desc.alternate_setting), + }) + .expect("Failed to configure endpoints"); + */ + + let mut hub_desc = usb::HubDescriptor::default(); + handle + .device_request( + PortReqTy::Class, + PortReqRecipient::Device, + 0x6, + 0, + //TODO: should this be an index into interface_descs? + interface_num as u16, + DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut hub_desc) }), + ) + .expect("Failed to retrieve hub descriptor"); + + log::info!("{:X?}", hub_desc); +} diff --git a/xhcid/drivers.toml b/xhcid/drivers.toml index 8c154af55a..8b28dbd8d4 100644 --- a/xhcid/drivers.toml +++ b/xhcid/drivers.toml @@ -4,6 +4,12 @@ class = 8 # Mass Storage class subclass = 6 # SCSI transparent command set command = ["/bin/usbscsid", "$SCHEME", "$PORT", "$IF_PROTO"] +[[drivers]] +name = "USB HUB" +class = 9 # HUB class +subclass = -1 +command = ["/bin/usbhubd", "$SCHEME", "$PORT", "$IF_NUM"] + [[drivers]] name = "USB HID" class = 3 # HID class diff --git a/xhcid/src/lib.rs b/xhcid/src/lib.rs index e5e4b806ab..16b3d91b64 100644 --- a/xhcid/src/lib.rs +++ b/xhcid/src/lib.rs @@ -1,4 +1,6 @@ +pub extern crate plain; + mod driver_interface; -mod usb; +pub mod usb; pub use driver_interface::*; diff --git a/xhcid/src/usb/hub.rs b/xhcid/src/usb/hub.rs index 227c075d04..b81d86a74b 100644 --- a/xhcid/src/usb/hub.rs +++ b/xhcid/src/usb/hub.rs @@ -1,4 +1,3 @@ - #[repr(packed)] #[derive(Clone, Copy, Debug)] pub struct HubDescriptor { @@ -12,3 +11,19 @@ pub struct HubDescriptor { // power_control_mask: bitmap of ports, maximum of 256 bits (32 bytes) bitmaps: [u8; 64] } + +unsafe impl plain::Plain for HubDescriptor {} + +impl Default for HubDescriptor { + fn default() -> Self { + Self { + length: 0, + kind: 0, + ports: 0, + characteristics: 0, + power_on_good: 0, + current: 0, + bitmaps: [0; 64] + } + } +}