1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
//! Abstractions for the keyboard driver.
use bitfield_struct::bitfield;
use pc_keyboard::layouts::Us104Key;
use pc_keyboard::{DecodedKey, HandleControl, KeyEvent, ScancodeSet1};
use crate::arch::io::Port;
/// Access status (read) and command (write) registers.
const CTRL: Port<u8> = Port::new(0x64);
/// Access PS/2 device keyboard output (read) and input (write) buffers.
const DATA: Port<u8> = Port::new(0x60);
/// Keyboard driver, that initializes the keyboard and parses keycodes.
pub struct Keyboard {
/// Keyboard layout. You choose another layout, like DE.
inner: pc_keyboard::Keyboard<Us104Key, ScancodeSet1>,
}
impl Keyboard {
/// Constructs the keyboard driver
pub const fn new() -> Keyboard {
Keyboard {
inner: pc_keyboard::Keyboard::new(
ScancodeSet1::new(),
Us104Key,
HandleControl::MapLettersToUnicode,
),
}
}
/// Initialize the keyboar controller
pub fn init(&mut self) {
self.set_repeat_rate(0, 0);
}
/// Configure the repeat rate of the keyboard
pub fn set_repeat_rate(&mut self, speed: u8, delay: u8) {
if speed <= 31 && delay <= 3 {
self.send_cmd(0xf3, delay << 4 | speed);
}
}
/// Check if a key has been pressed
pub fn key_hit(&mut self) -> Option<char> {
let event = self.key_event()?;
match self.inner.process_keyevent(event)? {
DecodedKey::RawKey(_) => None,
DecodedKey::Unicode(c) => Some(c),
}
}
fn key_event(&mut self) -> Option<KeyEvent> {
let status = unsafe { Status(CTRL.read()) };
if status.has_output() {
let scan = unsafe { DATA.read() };
if !status.is_mouse() {
return self.inner.add_byte(scan).ok()?;
}
}
None
}
/// Send a command or data to a connected PS/2 device
fn send_cmd(&mut self, cmd: u8, data: u8) {
unsafe {
while Status(CTRL.read()).input_pending() {}
CTRL.write(cmd);
CTRL.write(data);
}
}
}
/// Flags in the PS/2 controller status register
#[bitfield(u8)]
struct Status {
/// Output buffer non-empty?
has_output: bool,
/// Is input buffer full?
input_pending: bool,
/// Set on soft reset, cleared on power up
system_flag: bool,
/// Is command Byte? (otherwise data)
is_command: bool,
__: bool,
/// Mouse output has data
is_mouse: bool,
timeout_err: bool,
parity_err: bool,
}