HID reset modified
This commit is contained in:
parent
74cf5a46ee
commit
e8243e5c1c
@ -98,6 +98,15 @@ fn owners_of(path: &str) -> String {
|
||||
if pids.is_empty() { "-".into() } else { pids.join(",") }
|
||||
}
|
||||
|
||||
async fn wait_configured(ctrl: &str, limit_ms: u64) -> anyhow::Result<()> {
|
||||
for _ in 0..=limit_ms/50 {
|
||||
let s = UsbGadget::state(ctrl)?;
|
||||
if s.trim() == "configured" { return Ok(()) }
|
||||
tokio::time::sleep(Duration::from_millis(50)).await;
|
||||
}
|
||||
Err(anyhow::anyhow!("host never configured"))
|
||||
}
|
||||
|
||||
/*─────────────────── tonic service ─────────────────────*/
|
||||
struct Handler {
|
||||
kb: Arc<Mutex<tokio::fs::File>>,
|
||||
@ -112,6 +121,8 @@ impl Handler {
|
||||
gadget.cycle()?;
|
||||
|
||||
let ctrl = UsbGadget::find_controller()?;
|
||||
wait_configured(&ctrl, 10_000).await
|
||||
.context("waiting for host to configure")?;
|
||||
let state = UsbGadget::wait_state_any(&ctrl, 5_000)?;
|
||||
match state.as_str() {
|
||||
"configured" => info!("✅ host enumerated (configured)"),
|
||||
@ -155,30 +166,34 @@ impl Relay for Handler {
|
||||
let (tx, rx) =
|
||||
tokio::sync::mpsc::channel::<Result<KeyboardReport, Status>>(32);
|
||||
let kb = self.kb.clone();
|
||||
let gadget = self.gadget.clone();
|
||||
let ctrl = UsbGadget::find_controller().unwrap_or_default();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mut s = req.into_inner();
|
||||
while let Some(pkt) = s.next().await.transpose()? {
|
||||
// kb.lock().await.write_all(&pkt.data).await?;
|
||||
const SPINS: usize = 20;
|
||||
for _ in 0..SPINS {
|
||||
match kb.lock().await.write(&pkt.data).await {
|
||||
Ok(n) if n == pkt.data.len() => break, // success
|
||||
Ok(_) => continue, // short write
|
||||
Err(ref e) if matches!(e.raw_os_error(),
|
||||
Some(libc::EPIPE)|Some(libc::ENODEV)) => break, // host gone
|
||||
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
|
||||
std::hint::spin_loop();
|
||||
continue;
|
||||
}
|
||||
Err(e) => { tracing::error!("hid write: {e}"); break; }
|
||||
/* try to write once */
|
||||
let mut guard = kb.lock().await;
|
||||
if let Err(e) = guard.write_all(&pkt.data).await {
|
||||
/* host vanished ? */
|
||||
if matches!(e.raw_os_error(),
|
||||
Some(libc::ESHUTDOWN)|Some(libc::ENODEV)|Some(libc::EPIPE)) {
|
||||
warn!("host disappeared – recycling gadget");
|
||||
gadget.cycle().map_err(|e| Status::internal(e.to_string()))?;
|
||||
wait_configured(&ctrl, 10_000).await
|
||||
.map_err(|e| Status::internal(e.to_string()))?;
|
||||
/* reopen endpoint & swap into mutex */
|
||||
*guard = open_with_retry("/dev/hidg0").await
|
||||
.map_err(|e| Status::internal(e.to_string()))?;
|
||||
} else {
|
||||
return Err(Status::internal(e.to_string()));
|
||||
}
|
||||
}
|
||||
tx.send(Ok(pkt)).await;//.ok(); // best-effort echo
|
||||
drop(guard); /* release lock before await */
|
||||
tx.send(Ok(pkt)).await.ok(); /* best‑effort echo */
|
||||
}
|
||||
Ok::<(), Status>(())
|
||||
});
|
||||
|
||||
Ok(Response::new(ReceiverStream::new(rx)))
|
||||
}
|
||||
|
||||
@ -189,30 +204,34 @@ impl Relay for Handler {
|
||||
let (tx, rx) =
|
||||
tokio::sync::mpsc::channel::<Result<MouseReport, Status>>(4096);
|
||||
let ms = self.ms.clone();
|
||||
let gadget = self.gadget.clone();
|
||||
let ctrl = UsbGadget::find_controller().unwrap_or_default();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mut s = req.into_inner();
|
||||
let mut boot_mode = true;
|
||||
while let Some(pkt) = s.next().await.transpose()? {
|
||||
loop {
|
||||
match ms.lock().await.write(&pkt.data).await {
|
||||
Ok(n) if n == pkt.data.len() => break, // success
|
||||
Ok(_) => continue, // short write
|
||||
Err(ref e) if matches!(e.raw_os_error(),
|
||||
Some(libc::EPIPE)|Some(libc::ENODEV)) => break, // host gone
|
||||
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
|
||||
std::hint::spin_loop();
|
||||
continue;
|
||||
/* try to write once */
|
||||
let mut guard = ms.lock().await;
|
||||
if let Err(e) = guard.write_all(&pkt.data).await {
|
||||
/* host vanished ? */
|
||||
if matches!(e.raw_os_error(),
|
||||
Some(libc::ESHUTDOWN)|Some(libc::ENODEV)|Some(libc::EPIPE)) {
|
||||
warn!("host disappeared – recycling gadget");
|
||||
gadget.cycle().map_err(|e| Status::internal(e.to_string()))?;
|
||||
wait_configured(&ctrl, 10_000).await
|
||||
.map_err(|e| Status::internal(e.to_string()))?;
|
||||
/* reopen endpoint & swap into mutex */
|
||||
*guard = open_with_retry("/dev/hidg1").await
|
||||
.map_err(|e| Status::internal(e.to_string()))?;
|
||||
} else {
|
||||
return Err(Status::internal(e.to_string()));
|
||||
}
|
||||
Err(e) => { tracing::error!("hid write: {e}"); break; }
|
||||
}
|
||||
} // <-- closes `loop {`
|
||||
|
||||
let _ = tx.send(Ok(pkt)).await;
|
||||
drop(guard); /* release lock before await */
|
||||
tx.send(Ok(pkt)).await.ok(); /* best‑effort echo */
|
||||
}
|
||||
Ok::<(), Status>(())
|
||||
});
|
||||
|
||||
Ok(Response::new(ReceiverStream::new(rx)))
|
||||
}
|
||||
|
||||
|
||||
@ -17,6 +17,11 @@ impl UsbGadget {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn state(ctrl: &str) -> anyhow::Result<String> {
|
||||
let p = format!("/sys/class/udc/{ctrl}/state");
|
||||
Ok(std::fs::read_to_string(p)?.trim().to_owned())
|
||||
}
|
||||
|
||||
/*–––– helpers ––––*/
|
||||
|
||||
/// Find the first controller in /sys/class/udc (e.g. `1000480000.usb`)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user