rustubs/machine/
keyctrl.rsuse self::super::key::*;
use crate::arch::x86_64::is_int_enabled;
use crate::io::*;
use crate::machine::device_io::*;
use crate::proc::sync::semaphore::{Semaphore, SleepSemaphore};
use crate::proc::sync::IRQHandlerEpilogue;
use crate::proc::sync::L3Sync;
use alloc::collections::VecDeque;
use bitflags::bitflags;
use core::cmp::{Eq, PartialEq};
use core::sync::atomic::AtomicU32;
use core::sync::atomic::Ordering;
#[cfg(target_arch = "x86_64")]
use crate::arch::x86_64::interrupt::{pic_8259, pic_8259::PicDeviceInt as PD};
use super::key::Modifiers;
pub static KBCTL_GLOBAL: L3Sync<KeyboardController> =
L3Sync::new(KeyboardController::new());
pub static KEY_BUFFER: SleepSemaphore<VecDeque<Key>> =
SleepSemaphore::new(VecDeque::new());
pub struct KeyboardController {
keystate: KeyState,
gather: AtomicU32,
cport: IOPort,
dport: IOPort,
}
pub struct KeyboardDriver {}
impl IRQHandlerEpilogue for KeyboardDriver {
unsafe fn do_prologue() {
debug_assert!(!is_int_enabled());
KBCTL_GLOBAL.l3_get_ref_mut().fetch_key();
}
unsafe fn do_epilogue() {
debug_assert!(is_int_enabled());
let k = KBCTL_GLOBAL.l3_get_ref_mut_unchecked().consume_key();
if let Some(key) = k {
KEY_BUFFER.v_unguarded(key);
}
}
}
struct KeyState {
modi: Modifiers, prefix: Prefix, scan: Option<u8>,
}
#[derive(Clone, Copy, Eq, PartialEq)]
enum Prefix {
PREFIX1,
PREFIX2,
NONE, }
impl Prefix {
fn try_from_u8(val: u8) -> Option<Prefix> {
match val {
Defs::C_PREFIX1 => Some(Self::PREFIX1),
Defs::C_PREFIX2 => Some(Self::PREFIX2),
_ => None,
}
}
}
impl KeyState {
pub const fn new() -> Self {
Self {
modi: Modifiers::NONE,
prefix: Prefix::NONE,
scan: None,
}
}
fn get_leds(&self) -> u8 { return self.modi.bits() & 0b111; }
}
impl KeyboardController {
pub const fn new() -> Self {
Self {
keystate: KeyState::new(),
cport: IOPort::new(Defs::CTRL),
dport: IOPort::new(Defs::DATA),
gather: AtomicU32::new(Key::NONE_KEY),
}
}
fn toggle_lock(&mut self, lock: Modifiers) {
self.keystate.modi.toggle(lock);
self.update_led();
}
fn update_led(&self) {
let leds = self.keystate.get_leds();
self.dport.outb(Cmd::SetLed as u8);
unsafe { self.__block_until_data_available() }
let reply = self.dport.inb();
if reply == Msg::ACK as u8 {
self.dport.outb(leds);
}
unsafe {
self.__block_until_data_available();
}
}
fn update_state(&mut self, code: u8) {
self.keystate.scan = Some(code);
if let Some(p) = Prefix::try_from_u8(code) {
self.keystate.prefix = p;
return;
}
if code & Defs::BREAK_BIT == 0 {
if self.press_event() {
self.decode_key();
}
} else {
self.release_event();
}
self.keystate.prefix = Prefix::NONE;
}
fn press_event(&mut self) -> bool {
let mut should_decode_ascii = false;
let code = self.keystate.scan.unwrap();
match code {
Defs::C_SHIFT_L | Defs::C_SHIFT_R => {
self.keystate.modi.insert(Modifiers::SHIFT)
}
Defs::C_ALT => match self.keystate.prefix {
Prefix::PREFIX1 => {
self.keystate.modi.insert(Modifiers::ALT_RIGHT)
}
_ => self.keystate.modi.insert(Modifiers::ALT_LEFT),
},
Defs::C_CTRL => match self.keystate.prefix {
Prefix::PREFIX1 => {
self.keystate.modi.insert(Modifiers::CTRL_RIGHT)
}
_ => self.keystate.modi.insert(Modifiers::CTRL_LEFT),
},
Defs::C_CAPSLOCK => self.toggle_lock(Modifiers::CAPSLOCK),
Defs::C_NUM_P => {
if !self.keystate.modi.contains(Modifiers::CTRL_LEFT) {
self.toggle_lock(Modifiers::NUMLOCK);
}
}
Defs::C_SCRLOCK => self.toggle_lock(Modifiers::SCROLL_LOCK),
Defs::C_DEL => {
if self
.keystate
.modi
.contains(Modifiers::CTRL_LEFT | Modifiers::ALT_LEFT)
{
unsafe {
self.reboot();
}
}
}
_ => {
should_decode_ascii = true;
}
}
should_decode_ascii
}
fn release_event(&mut self) {
let code = self.keystate.scan.unwrap() & !Defs::BREAK_BIT;
match code {
Defs::C_SHIFT_L | Defs::C_SHIFT_R => {
self.keystate.modi.remove(Modifiers::SHIFT)
}
Defs::C_ALT => match self.keystate.prefix {
Prefix::PREFIX1 => {
self.keystate.modi.remove(Modifiers::ALT_RIGHT)
}
_ => self.keystate.modi.remove(Modifiers::ALT_LEFT),
},
Defs::C_CTRL => match self.keystate.prefix {
Prefix::PREFIX1 => {
self.keystate.modi.remove(Modifiers::CTRL_RIGHT)
}
_ => self.keystate.modi.remove(Modifiers::CTRL_LEFT),
},
_ => {}
}
}
#[inline(always)]
fn read_status(&self) -> Option<StatusReg> {
Some(StatusReg::from_bits_truncate(self.cport.inb()))
}
fn fetch_key(&mut self) {
let was_masked = Self::is_int_masked();
if !was_masked {
Self::disable_keyboard_int();
}
let sr = self.read_status().unwrap();
if !sr.contains(StatusReg::OUTB) || sr.contains(StatusReg::AUXB) {
return;
}
self.update_state(self.dport.inb());
if !was_masked {
Self::enable_keyboard_int();
}
}
#[inline]
fn consume_key(&mut self) -> Option<Key> {
let res = self.gather.swap(Key::NONE_KEY, Ordering::Relaxed);
return Key::from_u32(res);
}
fn decode_key(&mut self) {
let s = self.keystate.scan.unwrap();
let c = s & !Defs::BREAK_BIT;
let m = self.keystate.modi;
let p = self.keystate.prefix;
if c == 53 && p == Prefix::PREFIX1 {
let k = Key { asc: b'/', modi: m, scan: s };
self.gather.store(k.to_u32(), Ordering::Relaxed);
return;
}
let asc = if m.contains(Modifiers::NUMLOCK)
&& p == Prefix::NONE
&& (71..=83).contains(&c)
{
ASC_NUM_TAB[c as usize - 71]
} else if m.contains(Modifiers::ALT_RIGHT) {
ALT_TAB[c as usize]
} else if m.contains(Modifiers::SHIFT) {
SHIFT_TAB[c as usize]
} else if m.contains(Modifiers::CAPSLOCK) {
if (16..=26).contains(&c)
|| (30..=40).contains(&c)
|| (44..=50).contains(&c)
{
SHIFT_TAB[c as usize]
} else {
NORMAL_TAB[c as usize]
}
} else {
NORMAL_TAB[c as usize]
};
let k = Key { asc, modi: m, scan: s };
self.gather.store(k.to_u32(), Ordering::Relaxed);
}
fn cycle_repeat_rate() {
todo!();
}
fn cycle_deley() {
todo!();
}
#[inline(always)]
unsafe fn __block_until_cmd_buffer_empty(&self) {
loop {
let s = self.read_status().unwrap();
if !s.contains(StatusReg::INB) {
break;
};
}
}
#[inline(always)]
unsafe fn __block_until_data_available(&self) {
loop {
let status = self.read_status().unwrap();
if status.contains(StatusReg::OUTB) {
break;
}
}
}
}
#[cfg(target_arch = "x86_64")]
impl KeyboardController {
#[inline(always)]
fn disable_keyboard_int() { pic_8259::forbid(PD::KEYBOARD); }
#[inline(always)]
fn enable_keyboard_int() { pic_8259::allow(PD::KEYBOARD); }
#[inline(always)]
fn is_int_masked() -> bool { pic_8259::is_masked(PD::KEYBOARD) }
}
impl KeyboardController {
pub unsafe fn reboot(&self) {
println!("reboot...");
*(0x472 as *mut u16) = 0x1234;
self.__block_until_cmd_buffer_empty();
self.cport.outb(Cmd::CpuReset as u8);
}
}
enum Cmd {
SetLed = 0xed,
ScanCode = 0xf0, SetSpeed = 0xf3,
CpuReset = 0xfe,
}
bitflags! {
#[derive(Debug)]
struct StatusReg:u8 {
const NONE = 0;
const OUTB = 1 << 0; const INB = 1 << 1; const SYS = 1 << 2; const CMD_DATA = 1 << 3; const NOT_LOCKED = 1 << 4; const AUXB = 1 << 5; const TIMEOUT = 1 << 6; const PARITY_ERR = 1 << 7;
}
}
enum Msg {
ACK = 0xfa,
}
struct Defs;
impl Defs {
pub const CTRL: u16 = 0x64;
pub const DATA: u16 = 0x60;
pub const CPU_RESET: u8 = 0xfe;
pub const BREAK_BIT: u8 = 1 << 7;
pub const C_PREFIX1: u8 = 0xe0;
pub const C_PREFIX2: u8 = 0xe1;
pub const C_SHIFT_L: u8 = 0x2a;
pub const C_SHIFT_R: u8 = 0x36;
pub const C_ALT: u8 = 0x38;
pub const C_CTRL: u8 = 0x1d;
pub const C_CAPSLOCK: u8 = 0x3a;
pub const C_SCRLOCK: u8 = 0x46;
pub const C_NUM_P: u8 = 0x45; pub const C_F1: u8 = 0x3b;
pub const C_DEL: u8 = 0x53;
pub const C_UP: u8 = 0x48;
pub const C_DOWN: u8 = 0x50;
pub const C_LEFT: u8 = 0x4b;
pub const C_RIGHT: u8 = 0x4d;
pub const C_DIV: u8 = 0x8;
}