diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib.rs | 4 | ||||
| -rw-r--r-- | src/machine/key.rs | 21 | ||||
| -rw-r--r-- | src/machine/keyctrl.rs | 116 |
3 files changed, 93 insertions, 48 deletions
@@ -14,6 +14,8 @@ use core::panic::PanicInfo; use machine::cgascr::CGAScreen; use machine::interrupt; +use crate::machine::key::Modifiers; + #[cfg(not(test))] #[panic_handler] fn panic(info: &PanicInfo) -> ! { @@ -40,7 +42,7 @@ pub extern "C" fn _entry() -> ! { println!("Bitmap starting from : {:p}", framemap.bm.as_ptr()); println!("Skip first {} bytes", framemap.skip_byte); - + use crate::machine::device_io::IOPort; loop { // let code = io::KBCTL_GLOBAL.lock().simple_read(); io::KBCTL_GLOBAL.lock().fetch_key(); diff --git a/src/machine/key.rs b/src/machine/key.rs index 8d4e5f9..48e98b2 100644 --- a/src/machine/key.rs +++ b/src/machine/key.rs @@ -21,18 +21,23 @@ impl convert::Into<u8> for Key { } } +// Technically the *Lock are special keys, instead of Modifiers +// but we don't need another type FWIW. +// Mask bits[2:0] to get the leds. bitflags! { #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub struct Modifiers:u8 { const NONE = 0; - const SHIFT = 1 << 0; - const ALT_LEFT = 1 << 1; - const ALT_RIGHT = 1 << 2; - const CTRL_LEFT = 1 << 3; - const CTRL_RIGHT = 1 << 4; - const CAPSLOCK = 1 << 5; - const NUMLOCK = 1 << 6; - const SCROLL_LOCK = 1 << 7; + // lock states + const SCROLL_LOCK = 1 << 0; + const NUMLOCK = 1 << 1; + const CAPSLOCK = 1 << 2; + // modifiers + const SHIFT = 1 << 3; + const ALT_LEFT = 1 << 4; + const ALT_RIGHT = 1 << 5; + const CTRL_LEFT = 1 << 6; + const CTRL_RIGHT = 1 << 7; } } diff --git a/src/machine/keyctrl.rs b/src/machine/keyctrl.rs index 9284534..349f4ff 100644 --- a/src/machine/keyctrl.rs +++ b/src/machine/keyctrl.rs @@ -1,4 +1,5 @@ use self::super::key::*; +use crate::io::*; use crate::machine::device_io::*; use bitflags::bitflags; use core::cmp; @@ -24,7 +25,6 @@ use super::key::Modifiers; // set_repeat_rate(int speed,int delay) pub struct KeyboardController { - leds: Led, keystate: KeyState, gather: Option<Key>, // if not collected timely it will be overwritten cport: IOPort, @@ -63,23 +63,14 @@ impl KeyState { } } - pub fn toggle_capslock(&mut self) { - self.modi.toggle(Modifiers::CAPSLOCK); - } - - pub fn toggle_numlock(&mut self) { - self.modi.toggle(Modifiers::NUMLOCK); - } - - pub fn toggle_scroll_lock(&mut self) { - self.modi.toggle(Modifiers::SCROLL_LOCK); + pub fn get_leds(&self) -> u8 { + return self.modi.bits() & 0b111; } } impl KeyboardController { pub fn new() -> Self { Self { - leds: Led::NONE, keystate: KeyState::new(), cport: IOPort::new(Defs::CTRL), dport: IOPort::new(Defs::DATA), @@ -87,24 +78,31 @@ impl KeyboardController { } } - // Led and lock state are toggled together, to prevent out-of-sync // TODO: rollback lock state if setting led fails fn toggle_lock(&mut self, lock: Modifiers) { - let led = match lock { - Modifiers::SCROLL_LOCK => Some(Led::SCROLL_LOCK), - Modifiers::CAPSLOCK => Some(Led::CAPS_LOCK), - Modifiers::NUMLOCK => Some(Led::NUM_LOCk), - _ => None, - }; - if let Some(led) = led { - self.keystate.modi.toggle(lock); - self.toggle_led(led); - } + self.keystate.modi.toggle(lock); + self.update_led(); } - - fn toggle_led(&mut self, led: Led) { - self.leds.toggle(led); - todo!("toggle keyboard led: "); + // in some corner cases, e.g. keyboard control I/O may fail, while the + // CAPSLOCK is set and the uppcase table is used for key decoding. So we + // never set the leds explicitly, instead we update the leds from the + // current keyboard state i.e. keystate.modi + fn update_led(&self) { + let leds = self.keystate.get_leds(); + // TODO perhaps disable interrupts here + // TODO set a timeout. The ACK reply may never come + // 1. write command + unsafe {self.__block_until_cmd_buffer_empty();} + self.dport.outb(Cmd::SetLed as u8); + // 2. wait for ack + let ack = unsafe { self.__block_for_ack() }; + if !ack { + return; + } + // 3. write leds + self.dport.outb(leds); + // 4. wait for ack: we will ignore this ack because there is nothing we + // can do if the ack doesn't arive } pub fn update_state(&mut self, code: u8) { @@ -124,7 +122,7 @@ impl KeyboardController { // the prefix should have been comsumed at this point so clear it self.keystate.prefix = Prefix::NONE; } - + // TODO: need a rewrite for the toggle_lock and toggle_led fn press_event(&mut self) -> bool { let mut should_decode_ascii = false; let code = self.keystate.scan.unwrap(); @@ -145,6 +143,17 @@ impl KeyboardController { } } 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; } @@ -233,13 +242,35 @@ impl KeyboardController { }); } - pub fn set_repeat_rate_delay() { + pub fn cycle_repeat_rate() { todo!(); } - pub fn reboot(&mut self) { + pub fn cycle_deley() { todo!(); } + + /// unsafe: this function could block forever as it doesn't emply + /// timeout. + /// wait until the next OUTB; return true if get an ACK message + unsafe fn __block_for_ack(&self) -> bool { + loop { + // if let Some(f) + let s = self.read_status().unwrap(); + if s.contains(StatusReg::OUTB) { + break; + } + } + let msg = self.cport.inb(); + return msg == Msg::ACK as u8; + } + + unsafe fn __block_until_cmd_buffer_empty(&self) { + loop { + let s = self.read_status().unwrap(); + if !s.contains(StatusReg::INB) {break;}; + } + } } // x86 and arm has different interrupt controller @@ -270,23 +301,30 @@ impl KeyboardController { } } +// for whatever reason the PS/2 keyboard controls the "shutdown"... +// TODO use a "target feature" for machine functions like this. +// TODO "reboot controler" needs better abstraction, maybe a trait. +impl KeyboardController { + pub unsafe fn reboot(&self) { + // what ever magic it is, tell BIOS this is an intentional reset and don't + // run memory test + println!("reboot..."); + *(0x472 as *mut u16) = 0x1234; + self.__block_until_cmd_buffer_empty(); + self.cport.outb(Cmd::CpuReset as u8); + } +} + enum Cmd { // these commands are sent through DATA port SetLed = 0xed, ScanCode = 0xf0, // Get or set current scancode set SetSpeed = 0xf3, + CpuReset = 0xfe, } bitflags! { -pub struct Led:u8 { - const NONE = 0; - const SCROLL_LOCK = 1<<0; - const NUM_LOCk = 1<<1; - const CAPS_LOCK = 1<<2; -} -} - -bitflags! { +#[derive(Debug)] pub struct StatusReg:u8 { const NONE = 0; const OUTB = 1 << 0; // output buffer full (can read) |
