aboutsummaryrefslogtreecommitdiff
path: root/src/ioctl.rs
diff options
context:
space:
mode:
authorkbleeke <[email protected]>2023-03-02 15:34:08 +0100
committerkbleeke <[email protected]>2023-03-27 11:48:58 +0200
commit6f547cf05ddd1a27c8ec4e107ac227f7f9520ba6 (patch)
treee6e374b2b67ef4a1be8fa2a7cedbaf29d2c9cc9c /src/ioctl.rs
parent5da6108bec0c977841df21ae4140c4ac61a5369f (diff)
asyncify outgoing events
Diffstat (limited to 'src/ioctl.rs')
-rw-r--r--src/ioctl.rs111
1 files changed, 111 insertions, 0 deletions
diff --git a/src/ioctl.rs b/src/ioctl.rs
new file mode 100644
index 000000000..2d4cdb871
--- /dev/null
+++ b/src/ioctl.rs
@@ -0,0 +1,111 @@
1use core::cell::{Cell, RefCell};
2use core::future::poll_fn;
3use core::task::{Poll, Waker};
4
5use embassy_sync::blocking_mutex::raw::NoopRawMutex;
6use embassy_sync::blocking_mutex::Mutex;
7use embassy_sync::waitqueue::WakerRegistration;
8
9#[derive(Clone, Copy)]
10pub enum IoctlType {
11 Get = 0,
12 Set = 2,
13}
14
15#[derive(Clone, Copy)]
16pub struct PendingIoctl {
17 pub buf: *mut [u8],
18 pub kind: IoctlType,
19 pub cmd: u32,
20 pub iface: u32,
21}
22
23#[derive(Clone, Copy)]
24enum IoctlStateInner {
25 Pending(PendingIoctl),
26 Sent { buf: *mut [u8] },
27 Done { resp_len: usize },
28}
29
30pub struct IoctlState {
31 state: Cell<IoctlStateInner>,
32 wakers: Mutex<NoopRawMutex, RefCell<(WakerRegistration, WakerRegistration)>>,
33}
34
35impl IoctlState {
36 pub fn new() -> Self {
37 Self {
38 state: Cell::new(IoctlStateInner::Done { resp_len: 0 }),
39 wakers: Mutex::new(RefCell::default()),
40 }
41 }
42
43 fn wake_control(&self) {
44 self.wakers.lock(|f| {
45 f.borrow_mut().0.wake();
46 })
47 }
48
49 fn register_control(&self, waker: &Waker) {
50 self.wakers.lock(|f| f.borrow_mut().0.register(waker));
51 }
52
53 fn wake_runner(&self) {
54 self.wakers.lock(|f| {
55 f.borrow_mut().1.wake();
56 })
57 }
58
59 fn register_runner(&self, waker: &Waker) {
60 self.wakers.lock(|f| f.borrow_mut().1.register(waker));
61 }
62
63 pub async fn wait_complete(&self) -> usize {
64 poll_fn(|cx| {
65 if let IoctlStateInner::Done { resp_len } = self.state.get() {
66 Poll::Ready(resp_len)
67 } else {
68 self.register_control(cx.waker());
69 Poll::Pending
70 }
71 })
72 .await
73 }
74
75 pub async fn wait_pending(&self) -> PendingIoctl {
76 let pending = poll_fn(|cx| {
77 if let IoctlStateInner::Pending(pending) = self.state.get() {
78 warn!("found pending ioctl");
79 Poll::Ready(pending)
80 } else {
81 self.register_runner(cx.waker());
82 Poll::Pending
83 }
84 })
85 .await;
86
87 self.state.set(IoctlStateInner::Sent { buf: pending.buf });
88 pending
89 }
90
91 pub async fn do_ioctl(&self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize {
92 warn!("doing ioctl");
93 self.state
94 .set(IoctlStateInner::Pending(PendingIoctl { buf, kind, cmd, iface }));
95 self.wake_runner();
96 self.wait_complete().await
97 }
98
99 pub fn ioctl_done(&self, response: &[u8]) {
100 if let IoctlStateInner::Sent { buf } = self.state.get() {
101 warn!("ioctl complete");
102 // TODO fix this
103 (unsafe { &mut *buf }[..response.len()]).copy_from_slice(response);
104
105 self.state.set(IoctlStateInner::Done {
106 resp_len: response.len(),
107 });
108 self.wake_control();
109 }
110 }
111}