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}