blob: 0d08f9bf61733a5eb559d6ef9cdd37df554a7880 [file] [log] [blame]
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use core::cell::Cell;
use kernel::common::cells::OptionalCell;
use kernel::{AppId, AppSlice, Callback, Driver, Grant, ReturnCode, Shared};
use matcha_config::*;
use matcha_hal::pinmux_hal::PinmuxHAL;
pub struct AppData {
input_select_callback: Option<Callback>,
output_select_callback: Option<Callback>,
}
impl Default for AppData {
fn default() -> AppData {
AppData {
input_select_callback: None,
output_select_callback: None,
}
}
}
pub struct PinmuxCapsule {
pub app_data_grant: Grant<AppData>,
pub pinmux_hal: OptionalCell<&'static dyn PinmuxHAL>,
pub current_app: Cell<Option<AppId>>,
}
impl PinmuxCapsule {
pub fn new(app_data_grant: Grant<AppData>) -> Self {
PinmuxCapsule {
app_data_grant: app_data_grant,
pinmux_hal: OptionalCell::empty(),
current_app: Cell::new(None),
}
}
pub fn set_pinmux(&self, pinmux: &'static dyn PinmuxHAL) {
self.pinmux_hal.set(pinmux);
}
pub fn handle_command(
&self,
app_id: AppId,
_app_data: &mut AppData,
minor_num: usize,
arg2: usize,
arg3: usize,
) -> ReturnCode {
match minor_num {
CMD_PINMUX_INIT => {
self.current_app.set(Some(app_id));
ReturnCode::SUCCESS
}
CMD_PINMUX_INPUT_SELECT => {
let peripheral: u32 = arg2 as u32;
let pad: u32 = arg3 as u32;
let ret = self.pinmux_hal.map_or_else(
|| { ReturnCode::EINVAL },
|pinmux| {
pinmux.input_select(peripheral, pad)
}
);
self.current_app.get().map(|app_id| {
let _ = self.app_data_grant.enter(app_id, |app_data, _| {
app_data.input_select_callback.map(|mut callback| {
callback.schedule(usize::from(ret), 0, 0);
});
});
});
ret
}
CMD_PINMUX_OUTPUT_SELECT => {
let pad: u32 = arg2 as u32;
let peripheral: u32 = arg3 as u32;
let ret = self.pinmux_hal.map_or_else(
|| { ReturnCode::EINVAL },
|pinmux| {
pinmux.output_select(pad, peripheral)
}
);
self.current_app.get().map(|app_id| {
let _ = self.app_data_grant.enter(app_id, |app_data, _| {
app_data.output_select_callback.map(|mut callback| {
callback.schedule(usize::from(ret), 0, 0);
});
});
});
ret
}
_ => ReturnCode::EINVAL,
}
}
pub fn handle_subscribe(
&self,
_app_id: AppId,
app_data: &mut AppData,
minor_num: usize,
callback: Option<Callback>,
) -> ReturnCode {
match minor_num {
CMD_PINMUX_INPUT_SELECT => {
app_data.input_select_callback = callback;
ReturnCode::SUCCESS
}
CMD_PINMUX_OUTPUT_SELECT => {
app_data.output_select_callback = callback;
ReturnCode::SUCCESS
}
_ => ReturnCode::EINVAL,
}
}
pub fn handle_allow(
&self,
_app_id: AppId,
_app_data: &mut AppData,
minor_num: usize,
_slice: Option<AppSlice<Shared, u8>>,
) -> ReturnCode {
match minor_num {
CMD_PINMUX_INPUT_SELECT => ReturnCode::SUCCESS,
CMD_PINMUX_OUTPUT_SELECT => ReturnCode::SUCCESS,
_ => ReturnCode::EINVAL,
}
}
}
impl Driver for PinmuxCapsule {
fn subscribe(&self, minor_num: usize, callback: Option<Callback>, app_id: AppId) -> ReturnCode {
self.app_data_grant
.enter(app_id, |app_data, _| {
self.handle_subscribe(app_id, app_data, minor_num, callback)
})
.unwrap_or_else(|err| err.into())
}
fn command(&self, minor_num: usize, r2: usize, r3: usize, app_id: AppId) -> ReturnCode {
self.app_data_grant
.enter(app_id, |app_data, _| {
self.handle_command(app_id, app_data, minor_num, r2, r3)
})
.unwrap_or_else(|err| err.into())
}
fn allow(
&self,
app_id: AppId,
minor_num: usize,
slice: Option<AppSlice<Shared, u8>>,
) -> ReturnCode {
self.app_data_grant
.enter(app_id, |app_data, _| {
self.handle_allow(app_id, app_data, minor_num, slice)
})
.unwrap_or_else(|err| err.into())
}
}