capsules_core/i2c_master_slave_driver.rs
1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Provides both an I2C Master and I2C Slave interface to userspace.
6//!
7//! By calling `listen` this module will wait for I2C messages
8//! send to it by other masters on the I2C bus. If this device wants to
9//! transmit as an I2C master, this module will put the I2C hardware in master
10//! mode, transmit the read/write, then go back to listening (if listening
11//! was enabled).
12//!
13//! This capsule must sit directly above the I2C HIL interface (and not
14//! on top of the mux) because there is no way to mux the slave (it can't
15//! listen on more than one address) and because the application may want
16//! to be able to talk to any I2C address.
17
18use core::cell::Cell;
19use core::cmp;
20
21use kernel::hil;
22use kernel::processbuffer::{ReadableProcessBuffer, WriteableProcessBuffer};
23use kernel::syscall::{CommandReturn, SyscallDriver};
24use kernel::utilities::cells::{OptionalCell, TakeCell};
25use kernel::{ErrorCode, ProcessId};
26
27use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount};
28
29pub const BUFFER_LENGTH: usize = 256;
30
31/// Syscall driver number.
32use crate::driver;
33pub const DRIVER_NUM: usize = driver::NUM::I2cMasterSlave as usize;
34
35/// Ids for read-only allow buffers
36mod ro_allow {
37 pub const MASTER_TX: usize = 0;
38 pub const SLAVE_TX: usize = 2;
39 /// The number of allow buffers the kernel stores for this grant
40 pub const COUNT: u8 = 3;
41}
42
43/// Ids for read-write allow buffers
44mod rw_allow {
45 pub const MASTER_RX: usize = 1;
46 pub const SLAVE_RX: usize = 3;
47 /// The number of allow buffers the kernel stores for this grant
48 pub const COUNT: u8 = 4;
49}
50
51#[derive(Default)]
52pub struct App;
53
54#[derive(Clone, Copy, PartialEq)]
55enum MasterAction {
56 Read(u8),
57 Write,
58 WriteRead(u8),
59}
60
61pub struct I2CMasterSlaveDriver<'a, I: hil::i2c::I2CMasterSlave<'a>> {
62 i2c: &'a I,
63 listening: Cell<bool>,
64 master_action: Cell<MasterAction>, // Whether we issued a write or read as master
65 master_buffer: TakeCell<'static, [u8]>,
66 slave_buffer1: TakeCell<'static, [u8]>,
67 slave_buffer2: TakeCell<'static, [u8]>,
68 app: OptionalCell<ProcessId>,
69 apps: Grant<
70 App,
71 UpcallCount<1>,
72 AllowRoCount<{ ro_allow::COUNT }>,
73 AllowRwCount<{ rw_allow::COUNT }>,
74 >,
75}
76
77impl<'a, I: hil::i2c::I2CMasterSlave<'a>> I2CMasterSlaveDriver<'a, I> {
78 pub fn new(
79 i2c: &'a I,
80 master_buffer: &'static mut [u8],
81 slave_buffer1: &'static mut [u8],
82 slave_buffer2: &'static mut [u8],
83 grant: Grant<
84 App,
85 UpcallCount<1>,
86 AllowRoCount<{ ro_allow::COUNT }>,
87 AllowRwCount<{ rw_allow::COUNT }>,
88 >,
89 ) -> I2CMasterSlaveDriver<'a, I> {
90 I2CMasterSlaveDriver {
91 i2c,
92 listening: Cell::new(false),
93 master_action: Cell::new(MasterAction::Write),
94 master_buffer: TakeCell::new(master_buffer),
95 slave_buffer1: TakeCell::new(slave_buffer1),
96 slave_buffer2: TakeCell::new(slave_buffer2),
97 app: OptionalCell::empty(),
98 apps: grant,
99 }
100 }
101}
102
103impl<'a, I: hil::i2c::I2CMasterSlave<'a>> hil::i2c::I2CHwMasterClient
104 for I2CMasterSlaveDriver<'a, I>
105{
106 fn command_complete(&self, buffer: &'static mut [u8], status: Result<(), hil::i2c::Error>) {
107 // Map I2C error to a number we can pass back to the application
108 let status = kernel::errorcode::into_statuscode(match status {
109 Ok(()) => Ok(()),
110 Err(e) => Err(e.into()),
111 });
112
113 // Signal the application layer. Need to copy read in bytes if this
114 // was a read call.
115 match self.master_action.get() {
116 MasterAction::Write => {
117 self.master_buffer.replace(buffer);
118
119 self.app.map(|app| {
120 let _ = self.apps.enter(app, |_, kernel_data| {
121 kernel_data.schedule_upcall(0, (0, status, 0)).ok();
122 });
123 });
124 }
125
126 MasterAction::Read(read_len) => {
127 self.app.map(|app| {
128 let _ = self.apps.enter(app, |_, kernel_data| {
129 // Because this (somewhat incorrectly) doesn't report
130 // back how many bytes were read, the result of mut_enter
131 // is ignored. Note that this requires userspace to keep
132 // track of this information, and if read_len is longer
133 // than the buffer could lead to array overrun errors in
134 // userspace. The I2C syscall API should pass back lengths.
135 // -pal 3/5/21
136 kernel_data
137 .get_readwrite_processbuffer(rw_allow::MASTER_RX)
138 .and_then(|master_rx| {
139 master_rx.mut_enter(move |app_buffer| {
140 let len = cmp::min(app_buffer.len(), read_len as usize);
141
142 for (i, c) in buffer[0..len].iter().enumerate() {
143 app_buffer[i].set(*c);
144 }
145
146 self.master_buffer.replace(buffer);
147 0
148 })
149 })
150 .unwrap_or(0);
151 kernel_data.schedule_upcall(0, (1, status, 0)).ok();
152 });
153 });
154 }
155
156 MasterAction::WriteRead(read_len) => {
157 self.app.map(|app| {
158 let _ = self.apps.enter(app, |_, kernel_data| {
159 // Because this (somewhat incorrectly) doesn't report
160 // back how many bytes were read, the result of mut_enter
161 // is ignored. Note that this requires userspace to keep
162 // track of this information, and if read_len is longer
163 // than the buffer could lead to array overrun errors in
164 // userspace. The I2C syscall API should pass back lengths.
165 // -pal 3/5/21
166 kernel_data
167 .get_readwrite_processbuffer(rw_allow::MASTER_RX)
168 .and_then(|master_rx| {
169 master_rx.mut_enter(move |app_buffer| {
170 let len = cmp::min(app_buffer.len(), read_len as usize);
171 app_buffer[..len].copy_from_slice(&buffer[..len]);
172 self.master_buffer.replace(buffer);
173 0
174 })
175 })
176 .unwrap_or(0);
177 kernel_data.schedule_upcall(0, (7, status, 0)).ok();
178 });
179 });
180 }
181 }
182
183 // Check to see if we were listening as an I2C slave and should re-enable
184 // that mode.
185 if self.listening.get() {
186 hil::i2c::I2CSlave::enable(self.i2c);
187 hil::i2c::I2CSlave::listen(self.i2c);
188 }
189 }
190}
191
192impl<'a, I: hil::i2c::I2CMasterSlave<'a>> hil::i2c::I2CHwSlaveClient
193 for I2CMasterSlaveDriver<'a, I>
194{
195 fn command_complete(
196 &self,
197 buffer: &'static mut [u8],
198 length: usize,
199 transmission_type: hil::i2c::SlaveTransmissionType,
200 ) {
201 // Need to know if read or write
202 // - on write, copy bytes to app slice and do callback
203 // then pass buffer back to hw driver
204 // - on read, just signal upper layer and replace the read buffer
205 // in this driver
206 match transmission_type {
207 hil::i2c::SlaveTransmissionType::Write => {
208 self.app.map(|app| {
209 let _ = self.apps.enter(app, |_, kernel_data| {
210 kernel_data
211 .get_readwrite_processbuffer(rw_allow::SLAVE_RX)
212 .and_then(|slave_rx| {
213 slave_rx.mut_enter(move |app_rx| {
214 // Check bounds for write length
215 // Because this (somewhat incorrectly) doesn't report
216 // back how many bytes were read, the result of mut_map_or
217 // is ignored. Note that this requires userspace to keep
218 // track of this information, and if read_len is longer
219 // than the buffer could lead to array overrun errors in
220 // userspace. The I2C syscall API should pass back lengths.
221 // -pal 3/5/21
222 let buf_len = cmp::min(app_rx.len(), buffer.len());
223 let read_len = cmp::min(buf_len, length);
224
225 for (i, c) in buffer[0..read_len].iter_mut().enumerate() {
226 app_rx[i].set(*c);
227 }
228
229 self.slave_buffer1.replace(buffer);
230 0
231 })
232 })
233 .unwrap_or(0);
234
235 kernel_data.schedule_upcall(0, (3, length, 0)).ok();
236 });
237 });
238 }
239
240 hil::i2c::SlaveTransmissionType::Read => {
241 self.slave_buffer2.replace(buffer);
242
243 // Notify the app that the read finished
244 self.app.map(|app| {
245 let _ = self.apps.enter(app, |_, kernel_data| {
246 kernel_data.schedule_upcall(0, (4, length, 0)).ok();
247 });
248 });
249 }
250 }
251 }
252
253 fn read_expected(&self) {
254 // Pass this up to the client. Not much we can do until the application
255 // has setup a buffer to read from.
256 self.app.map(|app| {
257 let _ = self.apps.enter(app, |_, kernel_data| {
258 // Ask the app to setup a read buffer. The app must call
259 // command 3 after it has setup the shared read buffer with
260 // the correct bytes.
261 kernel_data.schedule_upcall(0, (2, 0, 0)).ok();
262 });
263 });
264 }
265
266 fn write_expected(&self) {
267 // Don't expect this to occur. We will typically have a buffer waiting
268 // to receive bytes because this module has a buffer and may as well
269 // just let the hardware layer have it. But, if it does happen
270 // we can respond.
271 self.slave_buffer1.take().map(|buffer| {
272 // TODO verify errors
273 let _ = hil::i2c::I2CSlave::write_receive(self.i2c, buffer, 255);
274 });
275 }
276}
277
278impl<'a, I: hil::i2c::I2CMasterSlave<'a>> SyscallDriver for I2CMasterSlaveDriver<'a, I> {
279 fn command(
280 &self,
281 command_num: usize,
282 data: usize,
283 _: usize,
284 process_id: ProcessId,
285 ) -> CommandReturn {
286 if command_num == 0 {
287 // Handle unconditional driver existence check.
288 return CommandReturn::success();
289 }
290 // Check if this non-virtualized driver is already in use by
291 // some (alive) process
292 let match_or_empty_or_nonexistant = self.app.map_or(true, |current_process| {
293 self.apps
294 .enter(current_process, |_, _| current_process == process_id)
295 .unwrap_or(true)
296 });
297 if match_or_empty_or_nonexistant {
298 self.app.set(process_id);
299 } else {
300 return CommandReturn::failure(ErrorCode::NOMEM);
301 }
302 let app = process_id;
303
304 match command_num {
305 // Do a write to another I2C device
306 1 => {
307 let address = (data & 0xFFFF) as u8;
308 let len = (data >> 16) & 0xFFFF;
309
310 // No need to check error on enter() -- we entered successfully
311 // above, so grant is allocated, and the app can't disappear
312 // while we are in the kernel.
313 let _ = self.apps.enter(app, |_, kernel_data| {
314 kernel_data
315 .get_readonly_processbuffer(ro_allow::MASTER_TX)
316 .and_then(|master_tx| {
317 master_tx.enter(|app_tx| {
318 // Because this (somewhat incorrectly) doesn't report
319 // back how many bytes are being written, the result of mut_map_or
320 // is ignored. Note that this does not provide useful feedback
321 // to user space if a write is longer than the buffer.
322 // The I2C syscall API should pass back lengths.
323 // -pal 3/5/21
324 self.master_buffer.take().map(|kernel_tx| {
325 // Check bounds for write length
326 let buf_len = cmp::min(app_tx.len(), kernel_tx.len());
327 let write_len = cmp::min(buf_len, len);
328
329 for (i, c) in kernel_tx[0..write_len].iter_mut().enumerate() {
330 *c = app_tx[i].get();
331 }
332
333 self.master_action.set(MasterAction::Write);
334
335 hil::i2c::I2CMaster::enable(self.i2c);
336 // TODO verify errors
337 let _ = hil::i2c::I2CMaster::write(
338 self.i2c, address, kernel_tx, write_len,
339 );
340 });
341 0
342 })
343 })
344 .unwrap_or(0);
345 });
346
347 CommandReturn::success()
348 }
349
350 // Do a read to another I2C device
351 2 => {
352 let address = (data & 0xFFFF) as u8;
353 let len = (data >> 16) & 0xFFFF;
354
355 let _ = self.apps.enter(app, |_, kernel_data| {
356 // Because this (somewhat incorrectly) doesn't report
357 // back how many bytes are being read, the result of mut_map_or
358 // is ignored. Note that this does not provide useful feedback
359 // to user space if a write is longer than the buffer.
360 // The I2C syscall API should pass back lengths.
361 // -pal 3/5/21
362 kernel_data
363 .get_readwrite_processbuffer(rw_allow::MASTER_RX)
364 .and_then(|master_rx| {
365 master_rx.enter(|app_rx| {
366 self.master_buffer.take().map(|kernel_tx| {
367 // Check bounds for write length
368 let buf_len = cmp::min(app_rx.len(), kernel_tx.len());
369 let read_len = cmp::min(buf_len, len);
370
371 for (i, c) in kernel_tx[0..read_len].iter_mut().enumerate() {
372 *c = app_rx[i].get();
373 }
374
375 self.master_action.set(MasterAction::Read(read_len as u8));
376
377 hil::i2c::I2CMaster::enable(self.i2c);
378 // TODO verify errors
379 let _ = hil::i2c::I2CMaster::read(
380 self.i2c, address, kernel_tx, read_len,
381 );
382 });
383 0
384 })
385 })
386 .unwrap_or(0);
387 });
388
389 CommandReturn::success()
390 }
391
392 // Listen for messages to this device as a slave.
393 3 => {
394 // We can always handle a write since this module has a buffer.
395 // .map will handle if we have already done this.
396 self.slave_buffer1.take().map(|buffer| {
397 // TODO verify errors
398 let _ = hil::i2c::I2CSlave::write_receive(self.i2c, buffer, 255);
399 });
400
401 // Actually get things going
402 hil::i2c::I2CSlave::enable(self.i2c);
403 hil::i2c::I2CSlave::listen(self.i2c);
404
405 // Note that we have enabled listening, so that if we switch
406 // to Master mode to send a message we can go back to listening.
407 self.listening.set(true);
408 CommandReturn::success()
409 }
410
411 // Prepare for a read from another Master by passing what's
412 // in the shared slice to the lower level I2C hardware driver.
413 4 => {
414 let _ = self.apps.enter(app, |_, kernel_data| {
415 // Because this (somewhat incorrectly) doesn't report
416 // back how many bytes are being read, the result of mut_map_or
417 // is ignored. Note that this does not provide useful feedback
418 // to user space if a write is longer than the buffer.
419 // The I2C syscall API should pass back lengths.
420 // -pal 3/5/21
421 kernel_data
422 .get_readonly_processbuffer(ro_allow::SLAVE_TX)
423 .and_then(|slave_tx| {
424 slave_tx.enter(|app_tx| {
425 self.slave_buffer2.take().map(|kernel_tx| {
426 // Check bounds for write length
427 let len = data;
428 let buf_len = cmp::min(app_tx.len(), kernel_tx.len());
429 let read_len = cmp::min(buf_len, len);
430
431 for (i, c) in kernel_tx[0..read_len].iter_mut().enumerate() {
432 *c = app_tx[i].get();
433 }
434
435 // TODO verify errors
436 let _ = hil::i2c::I2CSlave::read_send(
437 self.i2c, kernel_tx, read_len,
438 );
439 });
440 0
441 })
442 })
443 .unwrap_or(0);
444 });
445
446 CommandReturn::success()
447 }
448
449 // Stop listening for messages as an I2C slave
450 5 => {
451 hil::i2c::I2CSlave::disable(self.i2c);
452
453 // We are no longer listening for I2C messages from a different
454 // master device.
455 self.listening.set(false);
456 CommandReturn::success()
457 }
458
459 // Setup this device's slave address.
460 6 => {
461 let address = data as u8;
462 // We do not count the R/W bit as part of the address, so the
463 // valid range is 0x00-0x7f
464 if address > 0x7f {
465 return CommandReturn::failure(ErrorCode::INVAL);
466 }
467 // TODO verify errors
468 let _ = hil::i2c::I2CSlave::set_address(self.i2c, address);
469 CommandReturn::success()
470 }
471
472 // Perform write-to then read-from a slave device.
473 // Uses tx buffer for both read and write.
474 7 => {
475 let address = (data & 0xFF) as u8;
476 let read_len = (data >> 8) & 0xFF;
477 let write_len = (data >> 16) & 0xFF;
478 let _ = self.apps.enter(app, |_, kernel_data| {
479 // Because this (somewhat incorrectly) doesn't report
480 // back how many bytes are being read/read, the result of mut_map_or
481 // is ignored. Note that this does not provide useful feedback
482 // to user space if a write is longer than the buffer.
483 // The I2C syscall API should pass back lengths.
484 // -pal 3/5/21
485 let _ = kernel_data
486 .get_readonly_processbuffer(ro_allow::MASTER_TX)
487 .and_then(|master_tx| {
488 master_tx.enter(|app_tx| {
489 self.master_buffer.take().map(|kernel_tx| {
490 // Check bounds for write length
491 let buf_len = cmp::min(app_tx.len(), kernel_tx.len());
492 let write_len = cmp::min(buf_len, write_len);
493 let read_len = cmp::min(buf_len, read_len);
494 app_tx[..write_len].copy_to_slice(&mut kernel_tx[..write_len]);
495 self.master_action
496 .set(MasterAction::WriteRead(read_len as u8));
497 hil::i2c::I2CMaster::enable(self.i2c);
498 // TODO verify errors
499 let _ = hil::i2c::I2CMaster::write_read(
500 self.i2c, address, kernel_tx, write_len, read_len,
501 );
502 });
503 })
504 });
505 });
506 CommandReturn::success()
507 }
508
509 // default
510 _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
511 }
512 }
513
514 fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
515 self.apps.enter(processid, |_, _| {})
516 }
517}