rstubs/device/
keyboard.rs

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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//! Abstractions for the keyboard driver.

use arraydeque::{ArrayDeque, Wrapping};
use bitfield_struct::bitfield;
use pc_keyboard::layouts::Us104Key;
use pc_keyboard::{DecodedKey, HandleControl, KeyCode, KeyState, ScancodeSet1};

use crate::arch::io::Port;
use crate::threading::{Scheduler, Semaphore};

/// 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 PS2Controller {
    /// Keyboard layout. You choose another layout, like DE.
    inner: pc_keyboard::Keyboard<Us104Key, ScancodeSet1>,
    ctrl: bool,
    alt: bool,
}

impl PS2Controller {
    /// Constructs the keyboard driver
    pub const fn new() -> Self {
        Self {
            inner: pc_keyboard::Keyboard::new(
                ScancodeSet1::new(),
                Us104Key,
                HandleControl::MapLettersToUnicode,
            ),
            ctrl: false,
            alt: false,
        }
    }

    /// Initialize the keyboar controller
    pub fn init(&mut self) {
        self.set_repeat_rate(0, 0);

        // clear buffer
        while self.event().is_some() {}
    }

    /// 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);
        }
    }

    /// Read a key from the keyboard and parse it using the internal keyboard decoder.
    ///
    /// This function also reboots the system if ctrl+alt+del is pressed
    pub fn event(&mut self) -> Option<DecodedKey> {
        let status = unsafe { Status(CTRL.read()) };
        if status.has_output() {
            let scan = unsafe { DATA.read() };
            if !status.is_mouse() {
                let event = self.inner.add_byte(scan).ok()??;

                // Check for reboot shortcut
                if event.code == KeyCode::LControl {
                    self.ctrl = event.state == KeyState::Down;
                } else if event.code == KeyCode::LAlt {
                    self.alt = event.state == KeyState::Down;
                } else if event.code == KeyCode::Delete && self.ctrl && self.alt {
                    println!("Rebooting...");
                    self.reboot();
                }

                return self.inner.process_keyevent(event);
            }
        }
        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);
        }
    }

    /// Yes on x86 the keyboard can reboot the system
    pub fn reboot(&mut self) {
        self.send_cmd(0xfe, 0);
    }
}

/// Buffers key presses.
///
/// This has to be protected by the [Guard][crate::interrupts::guard::Guard].
pub struct KeyBuffer {
    sema: Semaphore,
    buf: ArrayDeque<char, 16, Wrapping>,
}

impl KeyBuffer {
    pub const fn new() -> Self {
        Self {
            sema: Semaphore::new(0),
            buf: ArrayDeque::new(),
        }
    }
    /// Push a key into the buffer
    pub fn push(&mut self, scheduler: &mut Scheduler, key: char) {
        self.buf.push_back(key);
        self.sema.signal(scheduler);
    }
    /// Wait for the next key press
    pub fn pop(&mut self, scheduler: &mut Scheduler) -> char {
        self.sema.wait(scheduler);
        self.buf.pop_front().unwrap()
    }
}

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