From 68760cf5af55cf24798d53dec4d3a8ea299b8015 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 20 Mar 2025 13:24:45 -0600 Subject: [PATCH] Improve USB hub driver --- usbhubd/src/main.rs | 114 +++++++++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 44 deletions(-) diff --git a/usbhubd/src/main.rs b/usbhubd/src/main.rs index d3ed91f182..c029c278c7 100644 --- a/usbhubd/src/main.rs +++ b/usbhubd/src/main.rs @@ -1,7 +1,7 @@ -use std::env; +use std::{env, thread, time}; use xhcid_interface::{ - plain, usb, DevDesc, DeviceReqData, PortReqRecipient, PortReqTy, XhciClientHandle, + plain, usb, ConfigureEndpointsReq, DevDesc, DeviceReqData, PortReqRecipient, PortReqTy, XhciClientHandle, }; fn main() { @@ -42,11 +42,10 @@ fn main() { .expect("Failed to get standard descriptors"); log::info!("{:X?}", desc); - let (conf_desc, conf_num, if_desc) = desc + let (conf_desc, if_desc) = desc .config_descs .iter() - .enumerate() - .find_map(|(conf_num, conf_desc)| { + .find_map(|conf_desc| { let if_desc = conf_desc.interface_descs.iter().find_map(|if_desc| { if if_desc.number == interface_num { Some(if_desc.clone()) @@ -54,11 +53,10 @@ fn main() { None } })?; - Some((conf_desc.clone(), conf_num, if_desc)) + Some((conf_desc.clone(), if_desc)) }) .expect("Failed to find suitable configuration"); - /*TODO handle .configure_endpoints(&ConfigureEndpointsReq { config_desc: conf_desc.configuration_value, @@ -66,7 +64,6 @@ fn main() { alternate_setting: Some(if_desc.alternate_setting), }) .expect("Failed to configure endpoints"); - */ let mut hub_desc = usb::HubDescriptor::default(); handle @@ -82,50 +79,79 @@ fn main() { .expect("Failed to retrieve hub descriptor"); log::info!("{:X?}", hub_desc); - for port in 1..=hub_desc.ports { - log::info!("power on port {port}"); - handle - .device_request( - PortReqTy::Class, - PortReqRecipient::Other, - usb::SetupReq::SetFeature as u8, - usb::HubFeature::PortPower as u16, - port as u16, - DeviceReqData::NoData, - ) - .expect("Failed to set port power"); - } - - for port in 1..=hub_desc.ports { - let mut port_sts = usb::HubPortStatus::default(); - handle - .device_request( - PortReqTy::Class, - PortReqRecipient::Other, - usb::SetupReq::GetStatus as u8, - 0, - port as u16, - DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut port_sts) }), - ) - .expect("Failed to retrieve port status"); - log::info!("port {} status {:X?}", port, port_sts); - - if port_sts.contains(usb::HubPortStatus::CONNECTION) { - /*TODO - log::info!("reset port {port}"); + //TODO: use change flags? + let mut last_port_statuses = vec![usb::HubPortStatus::default(); hub_desc.ports.into()]; + loop { + for port in 1..=hub_desc.ports { + let mut port_sts = usb::HubPortStatus::default(); handle .device_request( PortReqTy::Class, PortReqRecipient::Other, - usb::SetupReq::SetFeature as u8, - usb::HubFeature::PortReset as u16, + usb::SetupReq::GetStatus as u8, + 0, port as u16, - DeviceReqData::NoData, + DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut port_sts) }), ) - .expect("Failed to set port enable"); - */ + .expect("Failed to retrieve port status"); + + { + let port_idx: usize = port.checked_sub(1).unwrap().into(); + let last_port_sts = last_port_statuses.get_mut(port_idx).unwrap(); + if *last_port_sts != port_sts { + *last_port_sts = port_sts; + log::info!("port {} status {:X?}", port, port_sts); + } + } + + // Ensure port is powered on + if !port_sts.contains(usb::HubPortStatus::POWER) { + log::info!("power on port {port}"); + handle + .device_request( + PortReqTy::Class, + PortReqRecipient::Other, + usb::SetupReq::SetFeature as u8, + usb::HubFeature::PortPower as u16, + port as u16, + DeviceReqData::NoData, + ) + .expect("Failed to set port power"); + continue; + } + + // Ignore disconnected port + //TODO: turn off disconnected ports? + if !port_sts.contains(usb::HubPortStatus::CONNECTION) { + continue; + } + + // Ignore port in reset + if port_sts.contains(usb::HubPortStatus::RESET) { + continue; + } + + // Ensure port is enabled + if !port_sts.contains(usb::HubPortStatus::ENABLE) { + log::info!("reset port {port}"); + handle + .device_request( + PortReqTy::Class, + PortReqRecipient::Other, + usb::SetupReq::SetFeature as u8, + usb::HubFeature::PortReset as u16, + port as u16, + DeviceReqData::NoData, + ) + .expect("Failed to set port enable"); + continue; + } + //TODO: address device } + + //TODO: use interrupts or poll faster? + thread::sleep(time::Duration::new(1, 0)); } //TODO: read interrupt port for changes