capsules_core/i2c_master.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.
//! SyscallDriver for an I2C Master interface.
use enum_primitive::enum_from_primitive;
use kernel::grant::{AllowRoCount, AllowRwCount, Grant, GrantKernelData, UpcallCount};
use kernel::hil::i2c;
use kernel::processbuffer::{ReadableProcessBuffer, WriteableProcessBuffer};
use kernel::syscall::{CommandReturn, SyscallDriver};
use kernel::utilities::cells::{MapCell, OptionalCell, TakeCell};
use kernel::{ErrorCode, ProcessId};
/// Syscall driver number.
use crate::driver;
pub const DRIVER_NUM: usize = driver::NUM::I2cMaster as usize;
/// Ids for read-write allow buffers
mod rw_allow {
pub const BUFFER: usize = 1;
/// The number of allow buffers the kernel stores for this grant
pub const COUNT: u8 = 2;
}
#[derive(Default)]
pub struct App;
pub const BUFFER_LENGTH: usize = 64;
struct Transaction {
/// The buffer containing the bytes to transmit as it should be returned to
/// the client
processid: ProcessId,
/// The total amount to transmit
read_len: OptionalCell<usize>,
}
pub struct I2CMasterDriver<'a, I: i2c::I2CMaster<'a>> {
i2c: &'a I,
buf: TakeCell<'static, [u8]>,
tx: MapCell<Transaction>,
apps: Grant<App, UpcallCount<1>, AllowRoCount<0>, AllowRwCount<{ rw_allow::COUNT }>>,
}
impl<'a, I: i2c::I2CMaster<'a>> I2CMasterDriver<'a, I> {
pub fn new(
i2c: &'a I,
buf: &'static mut [u8],
apps: Grant<App, UpcallCount<1>, AllowRoCount<0>, AllowRwCount<{ rw_allow::COUNT }>>,
) -> I2CMasterDriver<'a, I> {
I2CMasterDriver {
i2c,
buf: TakeCell::new(buf),
tx: MapCell::empty(),
apps,
}
}
fn operation(
&self,
processid: ProcessId,
kernel_data: &GrantKernelData,
command: Cmd,
addr: u8,
wlen: usize,
rlen: usize,
) -> Result<(), ErrorCode> {
kernel_data
.get_readwrite_processbuffer(rw_allow::BUFFER)
.and_then(|buffer| {
buffer.enter(|app_buffer| {
self.buf.take().map_or(Err(ErrorCode::NOMEM), |buffer| {
app_buffer[..wlen].copy_to_slice(&mut buffer[..wlen]);
let read_len = if rlen == 0 {
OptionalCell::empty()
} else {
OptionalCell::new(rlen)
};
self.tx.put(Transaction {
processid,
read_len,
});
let res = match command {
Cmd::Ping => {
self.buf.put(Some(buffer));
return Err(ErrorCode::INVAL);
}
Cmd::Write => self.i2c.write(addr, buffer, wlen),
Cmd::Read => self.i2c.read(addr, buffer, rlen),
Cmd::WriteRead => self.i2c.write_read(addr, buffer, wlen, rlen),
};
match res {
Ok(()) => Ok(()),
Err((error, data)) => {
self.buf.put(Some(data));
Err(error.into())
}
}
})
})
})
.unwrap_or(Err(ErrorCode::INVAL))
}
}
use enum_primitive::cast::FromPrimitive;
enum_from_primitive! {
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Cmd {
Ping = 0,
Write = 1,
Read = 2,
WriteRead = 3,
}
}
impl<'a, I: i2c::I2CMaster<'a>> SyscallDriver for I2CMasterDriver<'a, I> {
/// Setup shared buffers.
///
/// ### `allow_num`
///
/// - `1`: buffer for command
// Setup callbacks.
//
// ### `subscribe_num`
//
// - `0`: Write buffer completed callback
/// Initiate transfers
fn command(
&self,
cmd_num: usize,
arg1: usize,
arg2: usize,
processid: ProcessId,
) -> CommandReturn {
if let Some(cmd) = Cmd::from_usize(cmd_num) {
match cmd {
Cmd::Ping => CommandReturn::success(),
Cmd::Write => self
.apps
.enter(processid, |_, kernel_data| {
let addr = arg1 as u8;
let write_len = arg2;
self.operation(processid, kernel_data, Cmd::Write, addr, write_len, 0)
.into()
})
.unwrap_or_else(|err| err.into()),
Cmd::Read => self
.apps
.enter(processid, |_, kernel_data| {
let addr = arg1 as u8;
let read_len = arg2;
self.operation(processid, kernel_data, Cmd::Read, addr, 0, read_len)
.into()
})
.unwrap_or_else(|err| err.into()),
Cmd::WriteRead => {
let addr = arg1 as u8;
let write_len = arg1 >> 8; // can extend to 24 bit write length
let read_len = arg2; // can extend to 32 bit read length
self.apps
.enter(processid, |_, kernel_data| {
self.operation(
processid,
kernel_data,
Cmd::WriteRead,
addr,
write_len,
read_len,
)
.into()
})
.unwrap_or_else(|err| err.into())
}
}
} else {
CommandReturn::failure(ErrorCode::NOSUPPORT)
}
}
fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
self.apps.enter(processid, |_, _| {})
}
}
impl<'a, I: i2c::I2CMaster<'a>> i2c::I2CHwMasterClient for I2CMasterDriver<'a, I> {
fn command_complete(&self, buffer: &'static mut [u8], status: Result<(), i2c::Error>) {
self.tx.take().map(|tx| {
self.apps.enter(tx.processid, |_, kernel_data| {
if let Some(read_len) = tx.read_len.take() {
let _ = kernel_data
.get_readwrite_processbuffer(rw_allow::BUFFER)
.and_then(|app_buffer| {
app_buffer.mut_enter(|app_buffer| {
app_buffer[..read_len].copy_from_slice(&buffer[..read_len]);
})
});
}
// signal to driver that tx complete
kernel_data
.schedule_upcall(
0,
(
kernel::errorcode::into_statuscode(status.map_err(|e| e.into())),
0,
0,
),
)
.ok();
})
});
//recover buffer
self.buf.put(Some(buffer));
}
}