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,
}