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(",") }
|
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 ─────────────────────*/
|
/*─────────────────── tonic service ─────────────────────*/
|
||||||
struct Handler {
|
struct Handler {
|
||||||
kb: Arc<Mutex<tokio::fs::File>>,
|
kb: Arc<Mutex<tokio::fs::File>>,
|
||||||
@ -112,6 +121,8 @@ impl Handler {
|
|||||||
gadget.cycle()?;
|
gadget.cycle()?;
|
||||||
|
|
||||||
let ctrl = UsbGadget::find_controller()?;
|
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)?;
|
let state = UsbGadget::wait_state_any(&ctrl, 5_000)?;
|
||||||
match state.as_str() {
|
match state.as_str() {
|
||||||
"configured" => info!("✅ host enumerated (configured)"),
|
"configured" => info!("✅ host enumerated (configured)"),
|
||||||
@ -155,30 +166,34 @@ impl Relay for Handler {
|
|||||||
let (tx, rx) =
|
let (tx, rx) =
|
||||||
tokio::sync::mpsc::channel::<Result<KeyboardReport, Status>>(32);
|
tokio::sync::mpsc::channel::<Result<KeyboardReport, Status>>(32);
|
||||||
let kb = self.kb.clone();
|
let kb = self.kb.clone();
|
||||||
|
let gadget = self.gadget.clone();
|
||||||
|
let ctrl = UsbGadget::find_controller().unwrap_or_default();
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let mut s = req.into_inner();
|
let mut s = req.into_inner();
|
||||||
while let Some(pkt) = s.next().await.transpose()? {
|
while let Some(pkt) = s.next().await.transpose()? {
|
||||||
// kb.lock().await.write_all(&pkt.data).await?;
|
/* try to write once */
|
||||||
const SPINS: usize = 20;
|
let mut guard = kb.lock().await;
|
||||||
for _ in 0..SPINS {
|
if let Err(e) = guard.write_all(&pkt.data).await {
|
||||||
match kb.lock().await.write(&pkt.data).await {
|
/* host vanished ? */
|
||||||
Ok(n) if n == pkt.data.len() => break, // success
|
if matches!(e.raw_os_error(),
|
||||||
Ok(_) => continue, // short write
|
Some(libc::ESHUTDOWN)|Some(libc::ENODEV)|Some(libc::EPIPE)) {
|
||||||
Err(ref e) if matches!(e.raw_os_error(),
|
warn!("host disappeared – recycling gadget");
|
||||||
Some(libc::EPIPE)|Some(libc::ENODEV)) => break, // host gone
|
gadget.cycle().map_err(|e| Status::internal(e.to_string()))?;
|
||||||
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
|
wait_configured(&ctrl, 10_000).await
|
||||||
std::hint::spin_loop();
|
.map_err(|e| Status::internal(e.to_string()))?;
|
||||||
continue;
|
/* reopen endpoint & swap into mutex */
|
||||||
}
|
*guard = open_with_retry("/dev/hidg0").await
|
||||||
Err(e) => { tracing::error!("hid write: {e}"); break; }
|
.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::<(), Status>(())
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(Response::new(ReceiverStream::new(rx)))
|
Ok(Response::new(ReceiverStream::new(rx)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,30 +204,34 @@ impl Relay for Handler {
|
|||||||
let (tx, rx) =
|
let (tx, rx) =
|
||||||
tokio::sync::mpsc::channel::<Result<MouseReport, Status>>(4096);
|
tokio::sync::mpsc::channel::<Result<MouseReport, Status>>(4096);
|
||||||
let ms = self.ms.clone();
|
let ms = self.ms.clone();
|
||||||
|
let gadget = self.gadget.clone();
|
||||||
|
let ctrl = UsbGadget::find_controller().unwrap_or_default();
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let mut s = req.into_inner();
|
let mut s = req.into_inner();
|
||||||
let mut boot_mode = true;
|
|
||||||
while let Some(pkt) = s.next().await.transpose()? {
|
while let Some(pkt) = s.next().await.transpose()? {
|
||||||
loop {
|
/* try to write once */
|
||||||
match ms.lock().await.write(&pkt.data).await {
|
let mut guard = ms.lock().await;
|
||||||
Ok(n) if n == pkt.data.len() => break, // success
|
if let Err(e) = guard.write_all(&pkt.data).await {
|
||||||
Ok(_) => continue, // short write
|
/* host vanished ? */
|
||||||
Err(ref e) if matches!(e.raw_os_error(),
|
if matches!(e.raw_os_error(),
|
||||||
Some(libc::EPIPE)|Some(libc::ENODEV)) => break, // host gone
|
Some(libc::ESHUTDOWN)|Some(libc::ENODEV)|Some(libc::EPIPE)) {
|
||||||
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
|
warn!("host disappeared – recycling gadget");
|
||||||
std::hint::spin_loop();
|
gadget.cycle().map_err(|e| Status::internal(e.to_string()))?;
|
||||||
continue;
|
wait_configured(&ctrl, 10_000).await
|
||||||
}
|
.map_err(|e| Status::internal(e.to_string()))?;
|
||||||
Err(e) => { tracing::error!("hid write: {e}"); break; }
|
/* 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()));
|
||||||
}
|
}
|
||||||
} // <-- closes `loop {`
|
}
|
||||||
|
drop(guard); /* release lock before await */
|
||||||
let _ = tx.send(Ok(pkt)).await;
|
tx.send(Ok(pkt)).await.ok(); /* best‑effort echo */
|
||||||
}
|
}
|
||||||
Ok::<(), Status>(())
|
Ok::<(), Status>(())
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(Response::new(ReceiverStream::new(rx)))
|
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 ––––*/
|
/*–––– helpers ––––*/
|
||||||
|
|
||||||
/// Find the first controller in /sys/class/udc (e.g. `1000480000.usb`)
|
/// Find the first controller in /sys/class/udc (e.g. `1000480000.usb`)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user