| //! Trivial capsule to provide minimal debug printing support for userspace. |
| //! |
| //! The default TockOS Console class does heavier-weight stuff with UART |
| //! multiplexing and asynchronous sending and such, which is usually _not_ what |
| //! is wanted in a debug serial port. This capsule implements only one command, |
| //! which dumps data from an allow'ed buffer directly to a memory-mapped UART |
| //! peripheral. |
| //! |
| //! Instantiation: |
| //! let debug_uart = static_init!( |
| //! DebugUart, |
| //! DebugUart { |
| //! tx_busy: StaticRef::new(TX_BUSY_ADDR as *const ReadOnly<u32>), |
| //! tx_port: StaticRef::new(TX_PORT_ADDR as *const WriteOnly<u32>), |
| //! app_data_grant: board_kernel.create_grant(&memory_allocation_cap) |
| //! } |
| //! ); |
| //! |
| //! where TX_BUSY_ADDR is a register whose low bit is 1 if the UART's fifo is |
| //! full and TX_PORT_ADDR is the register we write bytes to. |
| //! |
| //! Usage - send buffer directly to UART: |
| //! let driver_num = capsules::debug_uart::DRIVER_NUM; |
| //! let allow = syscalls::allow(driver_num, 0, &mut buffer); |
| //! let result = syscalls::command(driver_num, 0, buffer.len(), 0); |
| //! drop(allow); |
| |
| //use crate::driver; |
| use kernel::common::registers::{ReadOnly, WriteOnly}; |
| use kernel::common::StaticRef; |
| use kernel::{AppId, AppSlice, Callback, Driver, Grant, ReturnCode, Shared}; |
| |
| //pub const DRIVER_NUM: usize = driver::NUM::DebugUart as usize; |
| pub const DRIVER_NUM: usize = 0x00009 as usize; |
| |
| #[derive(Default)] |
| pub struct AppData { |
| pub buffer: Option<AppSlice<Shared, u8>>, |
| } |
| |
| pub struct DebugUart { |
| pub tx_busy: StaticRef<ReadOnly<u32>>, |
| pub tx_port: StaticRef<WriteOnly<u32>>, |
| pub app_data_grant: Grant<AppData>, |
| } |
| |
| impl Driver for DebugUart { |
| fn subscribe(&self, _: usize, _: Option<Callback>, _: AppId) -> ReturnCode { |
| ReturnCode::EINVAL |
| } |
| |
| fn command(&self, minor_num: usize, r2: usize, _: usize, app_id: AppId) -> ReturnCode { |
| if minor_num != 0 { |
| return ReturnCode::EINVAL; |
| } |
| |
| let _ = self.app_data_grant.enter(app_id, |app_data, _| { |
| if let Some(buf) = &app_data.buffer { |
| for i in 0..r2 { |
| while (self.tx_busy.get() & 1) != 0 {} |
| self.tx_port.set(buf.as_ref()[i] as u32); |
| } |
| } |
| }); |
| return ReturnCode::SUCCESS; |
| } |
| |
| fn allow(&self, app_id: AppId, _: usize, slice: Option<AppSlice<Shared, u8>>) -> ReturnCode { |
| let _ = self.app_data_grant.enter(app_id, |app_data, _| { |
| app_data.buffer = slice; |
| }); |
| return ReturnCode::SUCCESS; |
| } |
| } |