// SPDX-License-Identifier: MPL-2.0 //! The console device of Asterinas. #![no_std] #![deny(unsafe_code)] #![feature(fn_traits)] extern crate alloc; use alloc::{collections::BTreeMap, fmt::Debug, string::String, sync::Arc, vec::Vec}; use core::any::Any; use component::{init_component, ComponentInitError}; use ostd::{ mm::{Infallible, VmReader}, sync::{LocalIrqDisabled, SpinLock, SpinLockGuard}, }; use spin::Once; pub type ConsoleCallback = dyn Fn(VmReader) + Send + Sync; pub trait AnyConsoleDevice: Send + Sync + Any + Debug { fn send(&self, buf: &[u8]); /// Registers callback to the console device. /// The callback will be called once the console device receive data. /// /// Since the callback will be called in interrupt context, /// the callback should NEVER sleep. fn register_callback(&self, callback: &'static ConsoleCallback); } pub fn register_device(name: String, device: Arc) { COMPONENT .get() .unwrap() .console_device_table .disable_irq() .lock() .insert(name, device); } pub fn all_devices() -> Vec<(String, Arc)> { let console_devs = COMPONENT .get() .unwrap() .console_device_table .disable_irq() .lock(); console_devs .iter() .map(|(name, device)| (name.clone(), device.clone())) .collect() } pub fn all_devices_lock<'a>( ) -> SpinLockGuard<'a, BTreeMap>, LocalIrqDisabled> { COMPONENT .get() .unwrap() .console_device_table .disable_irq() .lock() } static COMPONENT: Once = Once::new(); #[init_component] fn component_init() -> Result<(), ComponentInitError> { let a = Component::init()?; COMPONENT.call_once(|| a); Ok(()) } #[derive(Debug)] struct Component { console_device_table: SpinLock>>, } impl Component { pub fn init() -> Result { Ok(Self { console_device_table: SpinLock::new(BTreeMap::new()), }) } }