diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/io.rs | 3 | ||||
| -rw-r--r-- | src/machine/kbd_defs.rs | 76 | ||||
| -rw-r--r-- | src/machine/key.rs | 52 | ||||
| -rw-r--r-- | src/machine/keyctrl.rs | 186 | ||||
| -rw-r--r-- | src/machine/mod.rs | 3 |
5 files changed, 224 insertions, 96 deletions
@@ -1,11 +1,12 @@ use crate::machine::cgascr::CGAScreen; +use crate::machine::keyctrl::KeyboardController; use core::fmt; use lazy_static::lazy_static; use spin::Mutex; // TODO I want my own locking primitive for practice, instead of stock spin lock lazy_static! { - // TODO perhaps remove the 'a lifetime from the struc defs pub static ref CGASCREEN_GLOBAL: Mutex<CGAScreen> = Mutex::new(CGAScreen::new()); + pub static ref KBCTL_GLOBAL: Mutex<KeyboardController> = Mutex::new(KeyboardController::new()); } #[macro_export] diff --git a/src/machine/kbd_defs.rs b/src/machine/kbd_defs.rs deleted file mode 100644 index a59d75a..0000000 --- a/src/machine/kbd_defs.rs +++ /dev/null @@ -1,76 +0,0 @@ -use core::ffi::c_uchar; - -// bit masks for modifier keys -pub enum Mbit { - Shift = 0b00000001, - AltLeft = 0b00000010, - AltRight = 0b00000100, - CtrlLeft = 0b00001000, - CtrlRight = 0b00010000, - CapsLock = 0b00100000, - NumLock = 0b01000000, - ScrollLock = 0b10000000, -} - -// scan codes of a few specific keys -pub enum Scan { - F1 = 0x3b, - Del = 0x53, - Up = 72, - Down = 80, - Left = 75, - Right = 77, - Div = 8, -} - -// Decoding tables ... this shit is so ugly, thanks to rust's strong typing system!!! -// Also, this is a german layout keyboard -// oh btw, the code translation is done by ChatGPT if it's wrong complain to the AI! -const NORMAL_TAB: [c_uchar; 89] = [ - 0, 0, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 225, 39, 8, 0, 113, 119, 101, 114, 116, 122, 117, - 105, 111, 112, 129, 43, 10, 0, 97, 115, 100, 102, 103, 104, 106, 107, 108, 148, 132, 94, 0, 35, - 121, 120, 99, 118, 98, 110, 109, 44, 46, 45, 0, 42, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 45, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, -]; - -const SHIFT_TAB: [c_uchar; 89] = [ - 0, 0, 33, 34, 21, 36, 37, 38, 47, 40, 41, 61, 63, 96, 0, 0, 81, 87, 69, 82, 84, 90, 85, 73, 79, - 80, 154, 42, 0, 0, 65, 83, 68, 70, 71, 72, 74, 75, 76, 153, 142, 248, 0, 39, 89, 88, 67, 86, - 66, 78, 77, 59, 58, 95, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, -]; - -const ALT_TAB: [c_uchar; 89] = [ - 0, 0, 0, 253, 0, 0, 0, 0, 123, 91, 93, 125, 92, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 126, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 0, 0, -]; - -const ASC_NUM_TAB: [c_uchar; 13] = [55, 56, 57, 45, 52, 53, 54, 43, 49, 50, 51, 48, 44]; -const SCAN_NUM_TAB: [c_uchar; 13] = [8, 9, 10, 53, 5, 6, 7, 27, 2, 3, 4, 11, 51]; - -// I think constants are more handy than enum for these... -// Keyboard controller commands -pub const KC_CMD_SET_LED: u8 = 0xed; -pub const KC_CMD_SET_SPEED: u8 = 0xf3; - -// CPU reset .. (reboot) -pub const KC_CPU_RESET: u8 = 0xfe; - -// Status register bits -pub const KC_SR_OUTB: u8 = 0x01; -pub const KC_SR_INPB: u8 = 0x02; -pub const KC_SR_AUXB: u8 = 0x20; - -// Keyboard Controller LED bits -pub const KC_LED_CAPS_LOCK: u8 = 4; -pub const KC_LED_NUM_LOCK: u8 = 2; -pub const KC_LED_SCROLL_LOCK: u8 = 1; - -// ACK -pub const KC_REPLY_ACK: u8 = 0xfa; - -// some stuffs for decoding -pub const BREAK_BIT: u8 = 0x80; -pub const PREFIX1: u8 = 0xe0; -pub const PREFIX2: u8 = 0xe1; diff --git a/src/machine/key.rs b/src/machine/key.rs index 0a09781..04220a6 100644 --- a/src/machine/key.rs +++ b/src/machine/key.rs @@ -1,4 +1,3 @@ -use self::super::kbd_defs::*; use bitflags::bitflags; use core::convert; @@ -98,3 +97,54 @@ impl Key { } } } + +use core::ffi::c_uchar; + +// bit masks for modifier keys +pub enum MbitDefs { + Shift = 0b00000001, + AltLeft = 0b00000010, + AltRight = 0b00000100, + CtrlLeft = 0b00001000, + CtrlRight = 0b00010000, + CapsLock = 0b00100000, + NumLock = 0b01000000, + ScrollLock = 0b10000000, +} + +// scan codes of a few specific keys +pub enum Scan { + F1 = 0x3b, + Del = 0x53, + Up = 72, + Down = 80, + Left = 75, + Right = 77, + Div = 8, +} + +// Decoding tables ... this shit is so ugly, thanks to rust's strong typing system!!! +// Also, this is a german layout keyboard +// oh btw, the code translation is done by ChatGPT if it's wrong complain to the AI! +const NORMAL_TAB: [c_uchar; 89] = [ + 0, 0, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 225, 39, 8, 0, 113, 119, 101, 114, 116, 122, 117, + 105, 111, 112, 129, 43, 10, 0, 97, 115, 100, 102, 103, 104, 106, 107, 108, 148, 132, 94, 0, 35, + 121, 120, 99, 118, 98, 110, 109, 44, 46, 45, 0, 42, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 45, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, +]; + +const SHIFT_TAB: [c_uchar; 89] = [ + 0, 0, 33, 34, 21, 36, 37, 38, 47, 40, 41, 61, 63, 96, 0, 0, 81, 87, 69, 82, 84, 90, 85, 73, 79, + 80, 154, 42, 0, 0, 65, 83, 68, 70, 71, 72, 74, 75, 76, 153, 142, 248, 0, 39, 89, 88, 67, 86, + 66, 78, 77, 59, 58, 95, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, +]; + +const ALT_TAB: [c_uchar; 89] = [ + 0, 0, 0, 253, 0, 0, 0, 0, 123, 91, 93, 125, 92, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 126, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 0, 0, +]; + +const ASC_NUM_TAB: [c_uchar; 13] = [55, 56, 57, 45, 52, 53, 54, 43, 49, 50, 51, 48, 44]; +const SCAN_NUM_TAB: [c_uchar; 13] = [8, 9, 10, 53, 5, 6, 7, 27, 2, 3, 4, 11, 51]; diff --git a/src/machine/keyctrl.rs b/src/machine/keyctrl.rs index 43f92d1..246ac02 100644 --- a/src/machine/keyctrl.rs +++ b/src/machine/keyctrl.rs @@ -1,6 +1,17 @@ -use self::super::kbd_defs::*; use self::super::key::*; use crate::machine::device_io::*; +use bitflags::bitflags; +use core::cmp; +use core::cmp::{Eq, PartialEq}; +use num_enum::{IntoPrimitive, TryFromPrimitive}; + +// Driver for the PS/2 keybard/mouse controller +// beyound OOStuBS: I'm gonna write full driver for it. + +// TODO figure out how to abstract the "interrupt control" layer. +// Keyboard controller should not be arch dependent +#[cfg(target_arch = "x86_64")] +use crate::arch::x86_64::interrupt::{pic_8259, pic_8259::PicDeviceInt as PD}; // this is the driver for keyboard controller not to confuse with the keyboard module. // The later is an abstraction @@ -19,34 +30,177 @@ use crate::machine::device_io::*; pub struct KeyboardController { code: u8, prefix: u8, - gather: Key, - leds: u8, + leds: Led, + current: Option<Key>, + last: Option<Key>, + gather: Option<Key>, + cport: IOPort, + dport: IOPort, +} + +pub enum KeyDelay { + L0 = 0, + L1 = 1, + L2 = 2, + L3 = 3, +} + +// x86 and arm has different interrupt controller +#[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 toggle_keyboard_int(enable: bool) { + if enable { + Self::enable_keyboard_int() + } else { + Self::disable_keyboard_int() + } + } + + #[inline(always)] + fn is_int_masked() -> bool { + pic_8259::is_masked(PD::KEYBOARD) + } } impl KeyboardController { - const CTRL_PORT:u16 = 0x64; - const DATA_PORT:u16 = 0x60; pub fn new() -> Self { Self { code: 0, - prefix: 9, - gather: Key::new(), - leds: 0, + prefix: 0, + leds: Led::NONE, + last: None, + current: None, + gather: None, + cport: IOPort::new(Defs::CTRL), + dport: IOPort::new(Defs::DATA), } } - pub fn key_hit(&mut self) -> Key { + pub fn fetch_key(&mut self) -> Key { todo!(); - // for debugging only - let mut invalid: Key = Key::new(); - invalid.set_raw(0xff); + // this should be called by the interrupt handler. + // 1. read raw keycode from data port + // 2. try to decode and put the result into self.gather. + // TODO consider move the decoding into the epilogue. + } - let status = inb(Self::CTRL_PORT); - return Key::new(); - // TODO here + // key decoding is stateful, this can't be implemented into Key struct. + pub fn decode_key(&mut self) -> bool { + // try to decode the raw 'code' into self.gather + // return true upon success + // this is a transcription of the C code.... Improve later. + // OOStuBS: The keys that were added in MF II keyboards -- compared to the older AT + // keyboard -- always send one of two possible prefix bytes first. + let done = false; + if self.code == Defs::PREFIX1 || self.code == Defs::PREFIX2 { + self.prefix = self.code; + return false; + } + + // OOStuBS: Releasing a key is actually only interesting in this implementation + // for the "modifier" keys SHIFT, CTRL and ALT. For the other keys, we + // can ignore the break code. + // ; A Key's break code is identical to its make code with break_bit set + + false } - pub fn reboot(&mut self) { + // block until status.outb becomes 1 + // return false on invalid SR. + // these wait_ functions are unsafe. If used inproperly this becomes a deadloop + // TODO support software timeout + unsafe fn wait_write(&self) { + loop { + let sr = StatusReg::from_bits_truncate(self.cport.inb()); + if sr.contains(StatusReg::OUTB) { + break; + } + } + } + + // block until status.inb becomes 0 + unsafe fn wait_read(&self) { + loop { + let sr = StatusReg::from_bits_truncate(self.cport.inb()); + if !sr.contains(StatusReg::INB) { + break; + } + } + } + + pub fn set_repeat_rate_delay(rate: u8, delay: KeyDelay) { + let rate = cmp::min(rate, 31); + let delay = delay as u8; + let is_masked = Self::is_int_masked(); + // idsable keyboard interrupt + // TODO should have a timeout + Self::disable_keyboard_int(); + + Self::toggle_keyboard_int(is_masked); + } + + pub fn reboot(&mut self) { todo!(); } } + +// I think constants are more handy than enum for these... +// Keyboard controller commands + +enum Cmd { + // these commands are sent through DATA port + SetLed = 0xed, + ScanCode = 0xf0, // Get or set current scancode set + SetSpeed = 0xf3, +} + +bitflags! { +pub struct Led:u8 { + const NONE = 0; + const SCROLL_LOCK = 1<<0; + const NUM_LOCk = 1<<1; + const CAPS_LOCK = 1<<2; +} +} + +bitflags! { +pub struct StatusReg:u8 { + const NONE = 0; + const OUTB = 1 << 0; // output buffer full (can read) + const INB = 1 << 1; // input buffer full (don't write yet) + const SYS = 1 << 2; // System flag, self test success + const CMD_DATA = 1 << 3; // 0: last write to input buffer was data (0x60) + // 1: last write to input buffer was command (0x64) + const NOT_LOCKED = 1 << 4; // Keyboard Lock. 1: not locked 0: locked + const AUXB = 1 << 5; // AUXB: aux output buffer full. + // on AT, 1: TIMEOUT + // on PS/2, 0: keyboard 1: mouse + const TIMEOUT = 1 << 6; // 0: OK 1: Timeout. + const PARITY_ERR = 1 << 7; +} +} + +enum Msg { + ACK = 0xfa, +} + +pub 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 = 0x80; + pub const PREFIX1: u8 = 0xe0; + pub const PREFIX2: u8 = 0xe1; +} diff --git a/src/machine/mod.rs b/src/machine/mod.rs index a9cf4cb..78fa73e 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -1,10 +1,9 @@ pub mod cgascr; +pub mod device_io; pub mod interrupt; -mod kbd_defs; pub mod key; pub mod keyctrl; pub mod mem; pub mod plugbox; -pub mod device_io; // TODO: this module *should* be arch independent. |
