use core::cell::{Cell, RefCell}; use core::future::poll_fn; use core::task::{Poll, Waker}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; use embassy_sync::waitqueue::WakerRegistration; #[derive(Clone, Copy)] pub enum IoctlType { Get = 0, Set = 2, } #[derive(Clone, Copy)] pub struct PendingIoctl { pub buf: *mut [u8], pub kind: IoctlType, pub cmd: u32, pub iface: u32, } #[derive(Clone, Copy)] enum IoctlStateInner { Pending(PendingIoctl), Sent { buf: *mut [u8] }, Done { resp_len: usize }, } pub struct IoctlState { state: Cell, wakers: Mutex>, } impl IoctlState { pub fn new() -> Self { Self { state: Cell::new(IoctlStateInner::Done { resp_len: 0 }), wakers: Mutex::new(RefCell::default()), } } fn wake_control(&self) { self.wakers.lock(|f| { f.borrow_mut().0.wake(); }) } fn register_control(&self, waker: &Waker) { self.wakers.lock(|f| f.borrow_mut().0.register(waker)); } fn wake_runner(&self) { self.wakers.lock(|f| { f.borrow_mut().1.wake(); }) } fn register_runner(&self, waker: &Waker) { self.wakers.lock(|f| f.borrow_mut().1.register(waker)); } pub async fn wait_complete(&self) -> usize { poll_fn(|cx| { if let IoctlStateInner::Done { resp_len } = self.state.get() { Poll::Ready(resp_len) } else { self.register_control(cx.waker()); Poll::Pending } }) .await } pub async fn wait_pending(&self) -> PendingIoctl { let pending = poll_fn(|cx| { if let IoctlStateInner::Pending(pending) = self.state.get() { warn!("found pending ioctl"); Poll::Ready(pending) } else { self.register_runner(cx.waker()); Poll::Pending } }) .await; self.state.set(IoctlStateInner::Sent { buf: pending.buf }); pending } pub async fn do_ioctl(&self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize { warn!("doing ioctl"); self.state .set(IoctlStateInner::Pending(PendingIoctl { buf, kind, cmd, iface })); self.wake_runner(); self.wait_complete().await } pub fn ioctl_done(&self, response: &[u8]) { if let IoctlStateInner::Sent { buf } = self.state.get() { warn!("ioctl complete"); // TODO fix this (unsafe { &mut *buf }[..response.len()]).copy_from_slice(response); self.state.set(IoctlStateInner::Done { resp_len: response.len(), }); self.wake_control(); } } }