server udc fix

This commit is contained in:
Brad Stein 2025-06-26 01:59:53 -05:00
parent 4419b5ce73
commit b63e04ff95

View File

@ -165,24 +165,43 @@ impl UsbGadget {
let root = format!("/sys/bus/platform/drivers/{drv}"); let root = format!("/sys/bus/platform/drivers/{drv}");
if !Path::new(&root).exists() { continue } if !Path::new(&root).exists() { continue }
/*----------- unbind ------------------------------------------------*/
info!("🔧 unbinding UDC driver ({drv})"); info!("🔧 unbinding UDC driver ({drv})");
let _ = Self::write_attr(format!("{root}/unbind"), ctrl); // ignore EINVAL for attempt in 1..=20 {
thread::sleep(Duration::from_millis(300)); match Self::write_attr(format!("{root}/unbind"), ctrl) {
Ok(_) => break,
Err(err) if attempt < 20 && Self::is_still_detaching(&err) => {
trace!("unbind inprogress (#{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})"); info!("🔧 binding UDC driver ({drv})");
for attempt in 1..=10 { for attempt in 1..=20 {
match Self::write_attr(format!("{root}/bind"), ctrl) { match Self::write_attr(format!("{root}/bind"), ctrl) {
Ok(_) => return Ok(()), Ok(_) => return Ok(()), // success 🎉
Err(e) if attempt < 10 => { Err(err) if attempt < 20 && Self::is_still_detaching(&err) => {
trace!("bind busy (#{attempt}) retrying…"); trace!("bind busy (#{attempt}) retrying…");
thread::sleep(Duration::from_millis(100)); thread::sleep(Duration::from_millis(100));
continue;
} }
Err(e) => return Err(e) Err(err) => return Err(err)
.context(format!("bind failed after {attempt} tries")), .context("UDC bind failed irrecoverably"),
} }
} }
} }
Err(anyhow::anyhow!("no dwc2/dwc3 driver nodes found")) Err(anyhow::anyhow!("no dwc2/dwc3 driver nodes found"))
} }
fn is_still_detaching(err: &anyhow::Error) -> bool {
err.downcast_ref::<std::io::Error>()
.and_then(|io| io.raw_os_error())
.map_or(false, |code| {
matches!(code, libc::EBUSY | libc::ENOENT | libc::ENODEV)
})
}
} }