#![no_std]
#![feature(abi_x86_interrupt)]
use core::sync::atomic::{AtomicBool, Ordering};
use keycodes_ascii::{Keycode, KeyboardModifiers, KEY_RELEASED_OFFSET, KeyAction, KeyEvent};
use log::{error, warn, debug};
use once_cell::unsync::Lazy;
use spin::Once;
use mpmc::Queue;
use event_types::Event;
use ps2::{PS2Keyboard, KeyboardType, LEDState, ScancodeSet};
use x86_64::structures::idt::InterruptStackFrame;
const PS2_KEYBOARD_IRQ: u8 = interrupts::IRQ_BASE_OFFSET + 0x1;
static mut KBD_MODIFIERS: Lazy<KeyboardModifiers> = Lazy::new(KeyboardModifiers::new);
static KEYBOARD: Once<KeyboardInterruptParams> = Once::new();
struct KeyboardInterruptParams {
keyboard: PS2Keyboard<'static>,
queue: Queue<Event>,
}
pub fn init(keyboard: PS2Keyboard<'static>, keyboard_queue_producer: Queue<Event>) -> Result<(), &'static str> {
match keyboard.keyboard_detect() {
Ok(KeyboardType::AncientATKeyboard) => debug!("The PS/2 keyboard type is: Ancient AT Keyboard with translator enabled in the PS/2 Controller"),
Ok(KeyboardType::MF2Keyboard) => debug!("The PS/2 keyboard type is: MF2Keyboard"),
Ok(KeyboardType::MF2KeyboardWithPSControllerTranslator) => debug!("The PS/2 keyboard type is: MF2 Keyboard with translator enabled in PS/2 Controller"),
Err(e) => {
error!("Failed to detect the PS/2 keyboard type: {e}");
return Err("Failed to detect the PS/2 keyboard type");
}
}
keyboard.set_keyboard_scancode_set(ScancodeSet::Set1)?;
interrupts::register_interrupt(PS2_KEYBOARD_IRQ, ps2_keyboard_handler).map_err(|e| {
error!("PS/2 keyboard IRQ {PS2_KEYBOARD_IRQ:#X} was already in use by handler {e:#X}! Sharing IRQs is currently unsupported.");
"PS/2 keyboard IRQ was already in use! Sharing IRQs is currently unsupported."
})?;
KEYBOARD.call_once(|| KeyboardInterruptParams { keyboard, queue: keyboard_queue_producer });
Ok(())
}
extern "x86-interrupt" fn ps2_keyboard_handler(_stack_frame: InterruptStackFrame) {
static EXTENDED_SCANCODE: AtomicBool = AtomicBool::new(false);
if let Some(KeyboardInterruptParams { keyboard, queue }) = KEYBOARD.get() {
let scan_code = keyboard.read_scancode();
let extended = EXTENDED_SCANCODE.load(Ordering::SeqCst);
if scan_code == 0xE0 {
if extended {
error!("ps2_keyboard_handler: got two extended scancodes (0xE0) in a row! Shouldn't happen.");
}
EXTENDED_SCANCODE.store(true, Ordering::SeqCst);
} else if scan_code == 0xE1 {
error!("ps2_keyboard_handler: PAUSE/BREAK key pressed ... ignoring it!");
EXTENDED_SCANCODE.store(true, Ordering::SeqCst);
} else { if extended {
EXTENDED_SCANCODE.store(false, Ordering::SeqCst);
}
if scan_code != 0 && scan_code != 0xFA {
if let Err(e) = handle_keyboard_input(keyboard, queue, scan_code, extended) {
error!("ps2_keyboard_handler: error handling PS2_PORT input: {e:?}");
}
}
}
} else {
warn!("ps2_keyboard_handler(): KEYBOARD isn't initialized yet, skipping interrupt.");
}
interrupts::eoi(PS2_KEYBOARD_IRQ);
}
fn handle_keyboard_input(keyboard: &PS2Keyboard, queue: &Queue<Event>, scan_code: u8, extended: bool) -> Result<(), &'static str> {
let modifiers = unsafe { &mut KBD_MODIFIERS };
match scan_code.try_into() {
Ok(Keycode::Control) => {
modifiers.insert(if extended {
KeyboardModifiers::CONTROL_RIGHT
} else {
KeyboardModifiers::CONTROL_LEFT
});
}
Ok(Keycode::Alt) => {
modifiers.insert(KeyboardModifiers::ALT);
}
Ok(Keycode::LeftShift) => {
modifiers.insert(KeyboardModifiers::SHIFT_LEFT);
}
Ok(Keycode::RightShift) => {
modifiers.insert(KeyboardModifiers::SHIFT_RIGHT);
}
Ok(Keycode::SuperKeyLeft) => {
modifiers.insert(KeyboardModifiers::SUPER_KEY_LEFT);
}
Ok(Keycode::SuperKeyRight) => {
modifiers.insert(KeyboardModifiers::SUPER_KEY_RIGHT);
}
Ok(Keycode::ControlReleased) => {
modifiers.remove(if extended {
KeyboardModifiers::CONTROL_RIGHT
} else {
KeyboardModifiers::CONTROL_LEFT
});
}
Ok(Keycode::AltReleased) => {
modifiers.remove(KeyboardModifiers::ALT);
}
Ok(Keycode::LeftShiftReleased) => {
modifiers.remove(KeyboardModifiers::SHIFT_LEFT);
}
Ok(Keycode::RightShiftReleased) => {
modifiers.remove(KeyboardModifiers::SHIFT_RIGHT);
}
Ok(Keycode::SuperKeyLeftReleased) => {
modifiers.remove(KeyboardModifiers::SUPER_KEY_LEFT);
}
Ok(Keycode::SuperKeyRightReleased) => {
modifiers.remove(KeyboardModifiers::SUPER_KEY_RIGHT);
}
Ok(Keycode::CapsLock) => {
modifiers.toggle(KeyboardModifiers::CAPS_LOCK);
set_keyboard_led(keyboard, modifiers);
}
Ok(Keycode::ScrollLock) => {
modifiers.toggle(KeyboardModifiers::SCROLL_LOCK);
set_keyboard_led(keyboard, modifiers);
}
Ok(Keycode::NumLock) => {
modifiers.toggle(KeyboardModifiers::NUM_LOCK);
set_keyboard_led(keyboard, modifiers);
}
_ => {} }
let (adjusted_scan_code, action) = if scan_code < KEY_RELEASED_OFFSET {
(scan_code, KeyAction::Pressed)
} else {
(scan_code - KEY_RELEASED_OFFSET, KeyAction::Released)
};
if let Ok(keycode) = Keycode::try_from(adjusted_scan_code) {
let event = Event::new_keyboard_event(KeyEvent::new(keycode, action, **modifiers));
queue.push(event).map_err(|_| "keyboard input queue is full")
} else {
error!("handle_keyboard_input(): Unknown scancode: {scan_code:?}, adjusted scancode: {adjusted_scan_code:?}");
Err("unknown keyboard scancode")
}
}
fn set_keyboard_led(keyboard: &PS2Keyboard, modifiers: &KeyboardModifiers) {
if let Err(e) = keyboard.set_keyboard_led(
LEDState::new()
.with_scroll_lock(modifiers.is_scroll_lock())
.with_number_lock(modifiers.is_num_lock())
.with_caps_lock(modifiers.is_caps_lock()),
) {
error!("{e}");
}
}