2025-02-13 11:41:15 +02:00

186 lines
4.4 KiB
Rust

//! Intel 8042 PS/2 controller driver implemenation
use abi::{
error::Error,
io::{KeyboardKey, KeyboardKeyEvent},
};
use alloc::sync::Arc;
use device_api::{
device::{Device, DeviceInitContext},
interrupt::{InterruptHandler, Irq, IrqVector},
};
use kernel_arch_x86::{
intrinsics::{IoPort, IoPortAccess},
ISA_IRQ_OFFSET,
};
use libk::device::external_interrupt_controller;
use libk_util::sync::IrqSafeSpinlock;
use codeset::{CODE_SET_1_00, CODE_SET_1_E0};
mod codeset;
struct Inner {
command: IoPort<u8>,
data: IoPort<u8>,
}
/// PS/2 controller driver
pub struct PS2Controller {
primary_irq: Irq,
#[allow(unused)]
auxiliary_irq: Irq,
inner: IrqSafeSpinlock<Inner>,
}
fn translate(e0: bool, key: u8) -> KeyboardKey {
debug_assert!(key < 0x80);
if e0 {
CODE_SET_1_E0[key as usize]
} else {
CODE_SET_1_00[key as usize]
}
}
impl Inner {
const STATUS_OUTPUT_FULL: u8 = 1 << 0;
const STATUS_INPUT_FULL: u8 = 1 << 1;
fn send_command(&mut self, cmd: u8) {
while self.command.read() & Self::STATUS_INPUT_FULL != 0 {
core::hint::spin_loop();
}
self.command.write(cmd);
}
// fn recv_timeout(&mut self, timeout: u64) -> Option<u8> {
// let mut counter = 0;
// while self.command.read() & Self::STATUS_OUTPUT_FULL == 0 {
// counter += 1;
// if counter > timeout {
// return None;
// }
// core::hint::spin_loop();
// }
// Some(self.data.read())
// }
fn try_recv(&mut self) -> Option<u8> {
if self.command.read() & Inner::STATUS_OUTPUT_FULL != 0 {
Some(self.data.read())
} else {
None
}
}
}
impl InterruptHandler for PS2Controller {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
let mut count = 0;
let mut inner = self.inner.lock();
let mut e0 = false;
loop {
let Some(mut scancode) = inner.try_recv() else {
break;
};
count += 1;
if scancode == 0xE0 {
e0 = true;
continue;
}
let release = scancode >= 0x80;
if release {
scancode -= 0x80;
}
let key = translate(e0, scancode);
let event = if release {
KeyboardKeyEvent::Released(key)
} else {
KeyboardKeyEvent::Pressed(key)
};
e0 = false;
ygg_driver_input::send_event(event);
}
count != 0
}
}
impl Device for PS2Controller {
fn display_name(&self) -> &'static str {
"PS/2 Controller"
}
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
Ok(())
}
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
let intc = external_interrupt_controller()?;
let mut inner = self.inner.lock();
// let intc = PLATFORM.interrupt_controller();
intc.register_irq(self.primary_irq, Default::default(), self.clone())?;
// Disable PS/2 devices from sending any further data
inner.send_command(0xAD);
inner.send_command(0xA7);
// Flush the buffer
while inner.command.read() & Inner::STATUS_OUTPUT_FULL != 0 {
inner.data.read();
}
// Enable primary port
inner.send_command(0xAE);
intc.enable_irq(self.primary_irq)?;
intc.enable_irq(self.auxiliary_irq)?;
Ok(())
}
}
impl PS2Controller {
/// Constructs a new instance of the device
const fn new(primary_irq: Irq, auxiliary_irq: Irq, cmd_port: u16, data_port: u16) -> Self {
let inner = Inner {
command: IoPort::new(cmd_port),
data: IoPort::new(data_port),
};
Self {
primary_irq,
auxiliary_irq,
inner: IrqSafeSpinlock::new(inner),
}
}
pub fn setup() -> Result<Arc<Self>, Error> {
let this = Arc::new(PS2Controller::new(
Irq::External(ISA_IRQ_OFFSET + 1),
Irq::External(ISA_IRQ_OFFSET + 12),
0x64,
0x60,
));
unsafe { this.clone().init_irq() }?;
Ok(this)
}
}
// pub static PS2: PS2Controller = PS2Controller::new(
// Irq::External(ISA_IRQ_OFFSET + 1),
// Irq::External(ISA_IRQ_OFFSET + 12),
// 0x64,
// 0x60,
// );