Add KDGKBMODE and KDSKBMODE ioctl support

This commit is contained in:
Ruihan Li 2025-10-23 21:28:21 +08:00 committed by Tate, Hongliang Tian
parent 2ba05a1673
commit 2d74e69b4b
5 changed files with 110 additions and 10 deletions

View File

@ -59,6 +59,21 @@ pub trait AnyConsoleDevice: Send + Sync + Any + Debug {
fn mode(&self) -> Option<mode::ConsoleMode> {
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<mode::KeyboardMode> {
None
}
}
pub fn register_device(name: String, device: Arc<dyn AnyConsoleDevice>) {

View File

@ -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 <https://lct.sourceforge.net/lct/x60.html>.
///
/// Reference: <https://elixir.bootlin.com/linux/v6.17.4/source/include/uapi/linux/kd.h#L81-L85>.
#[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,
}

View File

@ -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<Vec<&'static ConsoleCallback>, LocalIrqDisabled>,
callbacks: SpinLock<ConsoleCallbacks, LocalIrqDisabled>,
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<ConsoleMode> {
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<KeyboardMode> {
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<FrameBuffer>) -> 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);
}

View File

@ -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<D: TtyDriver> FileIo for Tty<D> {
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<dyn Terminal>)
.job_ioctl(cmd, arg, false)?,
}

View File

@ -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,
}