1use enum_primitive::enum_from_primitive;
8
9use kernel::grant::{AllowRoCount, AllowRwCount, Grant, GrantKernelData, UpcallCount};
10use kernel::hil::i2c;
11use kernel::processbuffer::{ReadableProcessBuffer, WriteableProcessBuffer};
12use kernel::syscall::{CommandReturn, SyscallDriver};
13use kernel::utilities::cells::{MapCell, OptionalCell, TakeCell};
14use kernel::{ErrorCode, ProcessId};
15
16use crate::driver;
18pub const DRIVER_NUM: usize = driver::NUM::I2cMaster as usize;
19
20mod rw_allow {
22 pub const BUFFER: usize = 1;
23 pub const COUNT: u8 = 2;
25}
26
27#[derive(Default)]
28pub struct App;
29
30pub const BUFFER_LENGTH: usize = 64;
31
32struct Transaction {
33 processid: ProcessId,
36 read_len: OptionalCell<usize>,
38}
39
40pub struct I2CMasterDriver<'a, I: i2c::I2CMaster<'a>> {
41 i2c: &'a I,
42 buf: TakeCell<'static, [u8]>,
43 tx: MapCell<Transaction>,
44 apps: Grant<App, UpcallCount<1>, AllowRoCount<0>, AllowRwCount<{ rw_allow::COUNT }>>,
45}
46
47impl<'a, I: i2c::I2CMaster<'a>> I2CMasterDriver<'a, I> {
48 pub fn new(
49 i2c: &'a I,
50 buf: &'static mut [u8],
51 apps: Grant<App, UpcallCount<1>, AllowRoCount<0>, AllowRwCount<{ rw_allow::COUNT }>>,
52 ) -> I2CMasterDriver<'a, I> {
53 I2CMasterDriver {
54 i2c,
55 buf: TakeCell::new(buf),
56 tx: MapCell::empty(),
57 apps,
58 }
59 }
60
61 fn operation(
62 &self,
63 processid: ProcessId,
64 kernel_data: &GrantKernelData,
65 command: Cmd,
66 addr: u8,
67 wlen: usize,
68 rlen: usize,
69 ) -> Result<(), ErrorCode> {
70 kernel_data
71 .get_readwrite_processbuffer(rw_allow::BUFFER)
72 .and_then(|buffer| {
73 buffer.enter(|app_buffer| {
74 self.buf.take().map_or(Err(ErrorCode::NOMEM), |buffer| {
75 app_buffer[..wlen].copy_to_slice(&mut buffer[..wlen]);
76
77 let read_len = if rlen == 0 {
78 OptionalCell::empty()
79 } else {
80 OptionalCell::new(rlen)
81 };
82 self.tx.put(Transaction {
83 processid,
84 read_len,
85 });
86
87 let res = match command {
88 Cmd::Ping => {
89 self.buf.put(Some(buffer));
90 return Err(ErrorCode::INVAL);
91 }
92 Cmd::Write => self.i2c.write(addr, buffer, wlen),
93 Cmd::Read => self.i2c.read(addr, buffer, rlen),
94 Cmd::WriteRead => self.i2c.write_read(addr, buffer, wlen, rlen),
95 };
96 match res {
97 Ok(()) => Ok(()),
98 Err((error, data)) => {
99 self.buf.put(Some(data));
100 Err(error.into())
101 }
102 }
103 })
104 })
105 })
106 .unwrap_or(Err(ErrorCode::INVAL))
107 }
108}
109
110use enum_primitive::cast::FromPrimitive;
111
112enum_from_primitive! {
113#[derive(Debug, PartialEq, Clone, Copy)]
114pub enum Cmd {
115 Ping = 0,
116 Write = 1,
117 Read = 2,
118 WriteRead = 3,
119}
120}
121
122impl<'a, I: i2c::I2CMaster<'a>> SyscallDriver for I2CMasterDriver<'a, I> {
123 fn command(
137 &self,
138 cmd_num: usize,
139 arg1: usize,
140 arg2: usize,
141 processid: ProcessId,
142 ) -> CommandReturn {
143 if let Some(cmd) = Cmd::from_usize(cmd_num) {
144 match cmd {
145 Cmd::Ping => CommandReturn::success(),
146 Cmd::Write => self
147 .apps
148 .enter(processid, |_, kernel_data| {
149 let addr = arg1 as u8;
150 let write_len = arg2;
151 self.operation(processid, kernel_data, Cmd::Write, addr, write_len, 0)
152 .into()
153 })
154 .unwrap_or_else(|err| err.into()),
155 Cmd::Read => self
156 .apps
157 .enter(processid, |_, kernel_data| {
158 let addr = arg1 as u8;
159 let read_len = arg2;
160 self.operation(processid, kernel_data, Cmd::Read, addr, 0, read_len)
161 .into()
162 })
163 .unwrap_or_else(|err| err.into()),
164 Cmd::WriteRead => {
165 let addr = arg1 as u8;
166 let write_len = arg1 >> 8; let read_len = arg2; self.apps
169 .enter(processid, |_, kernel_data| {
170 self.operation(
171 processid,
172 kernel_data,
173 Cmd::WriteRead,
174 addr,
175 write_len,
176 read_len,
177 )
178 .into()
179 })
180 .unwrap_or_else(|err| err.into())
181 }
182 }
183 } else {
184 CommandReturn::failure(ErrorCode::NOSUPPORT)
185 }
186 }
187
188 fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
189 self.apps.enter(processid, |_, _| {})
190 }
191}
192
193impl<'a, I: i2c::I2CMaster<'a>> i2c::I2CHwMasterClient for I2CMasterDriver<'a, I> {
194 fn command_complete(&self, buffer: &'static mut [u8], status: Result<(), i2c::Error>) {
195 self.tx.take().map(|tx| {
196 self.apps.enter(tx.processid, |_, kernel_data| {
197 if let Some(read_len) = tx.read_len.take() {
198 let _ = kernel_data
199 .get_readwrite_processbuffer(rw_allow::BUFFER)
200 .and_then(|app_buffer| {
201 app_buffer.mut_enter(|app_buffer| {
202 app_buffer[..read_len].copy_from_slice(&buffer[..read_len]);
203 })
204 });
205 }
206
207 kernel_data
209 .schedule_upcall(
210 0,
211 (
212 kernel::errorcode::into_statuscode(status.map_err(|e| e.into())),
213 0,
214 0,
215 ),
216 )
217 .ok();
218 })
219 });
220
221 self.buf.put(Some(buffer));
223 }
224}