From b63e04ff957123119d78d59696f0ba3c116bc391 Mon Sep 17 00:00:00 2001 From: Brad Stein Date: Thu, 26 Jun 2025 01:59:53 -0500 Subject: [PATCH] server udc fix --- server/src/usb_gadget.rs | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/server/src/usb_gadget.rs b/server/src/usb_gadget.rs index c11890f..34c29ae 100644 --- a/server/src/usb_gadget.rs +++ b/server/src/usb_gadget.rs @@ -164,25 +164,44 @@ impl UsbGadget { for drv in cand { let root = format!("/sys/bus/platform/drivers/{drv}"); if !Path::new(&root).exists() { continue } - + + /*----------- unbind ------------------------------------------------*/ info!("🔧 unbinding UDC driver ({drv})"); - let _ = Self::write_attr(format!("{root}/unbind"), ctrl); // ignore EINVAL - thread::sleep(Duration::from_millis(300)); + for attempt in 1..=20 { + match Self::write_attr(format!("{root}/unbind"), ctrl) { + Ok(_) => break, + Err(err) if attempt < 20 && Self::is_still_detaching(&err) => { + trace!("unbind in‑progress (#{attempt}) – waiting…"); + thread::sleep(Duration::from_millis(100)); + } + Err(err) => return Err(err) + .context("UDC unbind failed irrecoverably"), + } + } + thread::sleep(Duration::from_millis(150)); // let the core quiesce + /*----------- bind --------------------------------------------------*/ info!("🔧 binding UDC driver ({drv})"); - for attempt in 1..=10 { + for attempt in 1..=20 { match Self::write_attr(format!("{root}/bind"), ctrl) { - Ok(_) => return Ok(()), - Err(e) if attempt < 10 => { + Ok(_) => return Ok(()), // success 🎉 + Err(err) if attempt < 20 && Self::is_still_detaching(&err) => { trace!("bind busy (#{attempt}) – retrying…"); thread::sleep(Duration::from_millis(100)); - continue; } - Err(e) => return Err(e) - .context(format!("bind failed after {attempt} tries")), + Err(err) => return Err(err) + .context("UDC bind failed irrecoverably"), } } } Err(anyhow::anyhow!("no dwc2/dwc3 driver nodes found")) } + + fn is_still_detaching(err: &anyhow::Error) -> bool { + err.downcast_ref::() + .and_then(|io| io.raw_os_error()) + .map_or(false, |code| { + matches!(code, libc::EBUSY | libc::ENOENT | libc::ENODEV) + }) + } }