aboutsummaryrefslogtreecommitdiff
path: root/src/ioctl.rs
diff options
context:
space:
mode:
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..6a7465593
--- /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::waitqueue::WakerRegistration;
6
7#[derive(Clone, Copy)]
8pub enum IoctlType {
9 Get = 0,
10 Set = 2,
11}
12
13#[derive(Clone, Copy)]
14pub struct PendingIoctl {
15 pub buf: *mut [u8],
16 pub kind: IoctlType,
17 pub cmd: u32,
18 pub iface: u32,
19}
20
21#[derive(Clone, Copy)]
22enum IoctlStateInner {
23 Pending(PendingIoctl),
24 Sent { buf: *mut [u8] },
25 Done { resp_len: usize },
26}
27
28#[derive(Default)]
29struct Wakers {
30 control: WakerRegistration,
31 runner: WakerRegistration,
32}
33
34pub struct IoctlState {
35 state: Cell<IoctlStateInner>,
36 wakers: RefCell<Wakers>,
37}
38
39impl IoctlState {
40 pub fn new() -> Self {
41 Self {
42 state: Cell::new(IoctlStateInner::Done { resp_len: 0 }),
43 wakers: Default::default(),
44 }
45 }
46
47 fn wake_control(&self) {
48 self.wakers.borrow_mut().control.wake();
49 }
50
51 fn register_control(&self, waker: &Waker) {
52 self.wakers.borrow_mut().control.register(waker);
53 }
54
55 fn wake_runner(&self) {
56 self.wakers.borrow_mut().runner.wake();
57 }
58
59 fn register_runner(&self, waker: &Waker) {
60 self.wakers.borrow_mut().runner.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}