| // 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()) |
| } |
| } |