diff --git a/kernel/comps/console/src/lib.rs b/kernel/comps/console/src/lib.rs index 93cc38ee2..b86dd54fe 100644 --- a/kernel/comps/console/src/lib.rs +++ b/kernel/comps/console/src/lib.rs @@ -59,6 +59,21 @@ pub trait AnyConsoleDevice: Send + Sync + Any + Debug { fn mode(&self) -> Option { None } + + /// Sets the keyboard mode (see [`mode::KeyboardMode`]). + /// + /// Returns true if the mode was changed, false if the mode is not supported. + #[must_use] + fn set_keyboard_mode(&self, _mode: mode::KeyboardMode) -> bool { + false + } + + /// Gets the current keyboard mode. + /// + /// Returns the current keyboard mode, or `None` if mode switching is not supported. + fn keyboard_mode(&self) -> Option { + None + } } pub fn register_device(name: String, device: Arc) { diff --git a/kernel/comps/console/src/mode.rs b/kernel/comps/console/src/mode.rs index 12cb715d4..709155b1c 100644 --- a/kernel/comps/console/src/mode.rs +++ b/kernel/comps/console/src/mode.rs @@ -16,3 +16,24 @@ pub enum ConsoleMode { /// and may be used for graphical output (e.g., by X server). Graphics = 1, } + +/// The keyboard mode. +/// +/// This mode determines how a console behaves when it receives input from the keyboard. For more +/// details, see . +/// +/// Reference: . +#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromInt)] +#[repr(i32)] +pub enum KeyboardMode { + /// The scancode mode (`K_RAW` in Linux). + Raw = 0, + /// The ASCII mode (`K_XLATE` in Linux). + Xlate = 1, + /// The keycode mode (`K_MEDIUMRAW` in Linux). + MediumRaw = 2, + /// The Unicode mode (`K_UNICODE` in Linux). + Unicode = 3, + /// The off mode (`K_OFF` in Linux). + Off = 4, +} diff --git a/kernel/comps/framebuffer/src/console.rs b/kernel/comps/framebuffer/src/console.rs index 304b0d09d..3d78a8858 100644 --- a/kernel/comps/framebuffer/src/console.rs +++ b/kernel/comps/framebuffer/src/console.rs @@ -3,7 +3,9 @@ use alloc::{sync::Arc, vec::Vec}; use aster_console::{ - font::BitmapFont, mode::ConsoleMode, AnyConsoleDevice, ConsoleCallback, ConsoleSetFontError, + font::BitmapFont, + mode::{ConsoleMode, KeyboardMode}, + AnyConsoleDevice, ConsoleCallback, ConsoleSetFontError, }; use aster_keyboard::InputKey; use ostd::{ @@ -19,7 +21,7 @@ use crate::{ /// A text console rendered onto the framebuffer. pub struct FramebufferConsole { - callbacks: SpinLock, LocalIrqDisabled>, + callbacks: SpinLock, inner: SpinLock<(ConsoleState, EscapeFsm), LocalIrqDisabled>, } @@ -58,7 +60,7 @@ impl AnyConsoleDevice for FramebufferConsole { } fn register_callback(&self, callback: &'static ConsoleCallback) { - self.callbacks.lock().push(callback); + self.callbacks.lock().callbacks.push(callback); } fn set_font(&self, font: BitmapFont) -> Result<(), ConsoleSetFontError> { @@ -73,11 +75,33 @@ impl AnyConsoleDevice for FramebufferConsole { fn mode(&self) -> Option { Some(self.inner.lock().0.mode()) } + + fn set_keyboard_mode(&self, mode: KeyboardMode) -> bool { + match mode { + KeyboardMode::Xlate => self.callbacks.lock().is_input_enabled = true, + KeyboardMode::Off => self.callbacks.lock().is_input_enabled = false, + _ => return false, + } + true + } + + fn keyboard_mode(&self) -> Option { + if self.callbacks.lock().is_input_enabled { + Some(KeyboardMode::Xlate) + } else { + Some(KeyboardMode::Off) + } + } } impl FramebufferConsole { /// Creates a new framebuffer console. pub(self) fn new(framebuffer: Arc) -> Self { + let callbacks = ConsoleCallbacks { + callbacks: Vec::new(), + is_input_enabled: true, + }; + let state = ConsoleState { x_pos: 0, y_pos: 0, @@ -93,10 +117,23 @@ impl FramebufferConsole { let esc_fsm = EscapeFsm::new(); Self { - callbacks: SpinLock::new(Vec::new()), + callbacks: SpinLock::new(callbacks), inner: SpinLock::new((state, esc_fsm)), } } + + /// Triggers the registered input callbacks with the given data. + pub(self) fn trigger_input_callbacks(&self, bytes: &[u8]) { + let callbacks = self.callbacks.lock(); + if !callbacks.is_input_enabled { + return; + } + + let reader = VmReader::from(bytes); + for callback in callbacks.callbacks.iter() { + callback(reader.clone()); + } + } } impl core::fmt::Debug for FramebufferConsole { @@ -105,6 +142,12 @@ impl core::fmt::Debug for FramebufferConsole { } } +struct ConsoleCallbacks { + callbacks: Vec<&'static ConsoleCallback>, + /// Whether the input characters will be handled by the callbacks. + is_input_enabled: bool, +} + #[derive(Debug)] struct ConsoleState { x_pos: usize, @@ -280,8 +323,5 @@ fn handle_keyboard_input(key: InputKey) { }; let buffer = key.as_xterm_control_sequence(); - for callback in console.callbacks.lock().iter() { - let reader = VmReader::from(buffer); - callback(reader); - } + console.trigger_input_callbacks(buffer); } diff --git a/kernel/src/device/tty/mod.rs b/kernel/src/device/tty/mod.rs index 1b476b744..a48415bad 100644 --- a/kernel/src/device/tty/mod.rs +++ b/kernel/src/device/tty/mod.rs @@ -1,6 +1,10 @@ // SPDX-License-Identifier: MPL-2.0 -use aster_console::{font::BitmapFont, mode::ConsoleMode, AnyConsoleDevice}; +use aster_console::{ + font::BitmapFont, + mode::{ConsoleMode, KeyboardMode}, + AnyConsoleDevice, +}; use ostd::sync::LocalIrqDisabled; use self::{line_discipline::LineDiscipline, termio::CFontOp}; @@ -323,6 +327,20 @@ impl FileIo for Tty { let mode = console.mode().unwrap_or(ConsoleMode::Text); current_userspace!().write_val(arg, &(mode as i32))?; } + IoctlCmd::KDSKBMODE => { + let console = self.console()?; + + let mode = KeyboardMode::try_from(arg as i32)?; + if !console.set_keyboard_mode(mode) { + return_errno_with_message!(Errno::EINVAL, "the keyboard mode is not supported"); + } + } + IoctlCmd::KDGKBMODE => { + let console = self.console()?; + + let mode = console.keyboard_mode().unwrap_or(KeyboardMode::Xlate); + current_userspace!().write_val(arg, &(mode as i32))?; + } _ => (self.weak_self.upgrade().unwrap() as Arc) .job_ioctl(cmd, arg, false)?, } diff --git a/kernel/src/fs/utils/ioctl.rs b/kernel/src/fs/utils/ioctl.rs index 39b368e7c..ef6c389be 100644 --- a/kernel/src/fs/utils/ioctl.rs +++ b/kernel/src/fs/utils/ioctl.rs @@ -8,6 +8,7 @@ use crate::prelude::*; pub enum IoctlCmd { /// Get terminal attributes TCGETS = 0x5401, + /// Set terminal attributes TCSETS = 0x5402, /// Drain the output buffer and set attributes TCSETSW = 0x5403, @@ -21,8 +22,9 @@ pub enum IoctlCmd { TIOCSPGRP = 0x5410, /// Get the number of bytes in the input buffer. FIONREAD = 0x541B, - /// Set window size + /// Get window size TIOCGWINSZ = 0x5413, + /// Set window size TIOCSWINSZ = 0x5414, /// Enable or disable non-blocking I/O mode. FIONBIO = 0x5421, @@ -48,6 +50,10 @@ pub enum IoctlCmd { KDGETMODE = 0x4B3B, /// Set console mode KDSETMODE = 0x4B3A, + /// Get keyboard mode + KDGKBMODE = 0x4B44, + /// Set keyboard mode + KDSKBMODE = 0x4B45, /// Get tdx report using TDCALL TDXGETREPORT = 0xc4405401, }