mycelium_kernel/drivers/
ps2_keyboard.rs1use maitake::sync::WaitQueue;
2use mycelium_util::{fmt, sync::blocking::Mutex};
3use pc_keyboard::{layouts, Keyboard};
4pub use pc_keyboard::{DecodedKey, KeyCode};
5
6pub struct Ps2Keyboard {
7 buf: thingbuf::StaticThingBuf<Option<DecodedKey>, 128>,
10 kbd: Mutex<Keyboard<layouts::Us104Key, pc_keyboard::ScancodeSet1>>,
17 waiters: WaitQueue,
18}
19
20static PS2_KEYBOARD: Ps2Keyboard = Ps2Keyboard {
21 buf: thingbuf::StaticThingBuf::new(),
22 kbd: Mutex::new(
23 Keyboard::<layouts::Us104Key, pc_keyboard::ScancodeSet1>::new(
24 pc_keyboard::HandleControl::MapLettersToUnicode,
25 ),
26 ),
27 waiters: WaitQueue::new(),
28};
29
30pub async fn next_key() -> DecodedKey {
31 if let Some(key) = PS2_KEYBOARD.buf.pop() {
32 return key.expect("no one should push `None`s to the buffer, this is a bug");
33 }
34
35 PS2_KEYBOARD
36 .waiters
37 .wait()
38 .await
39 .expect("PS/2 keyboard waiters should never be closed, this is a bug");
40 PS2_KEYBOARD
41 .buf
42 .pop()
43 .expect("we just got woken up, there should be a key in the buffer")
44 .expect("no one should push `None`s to the buffer, this is a bug")
45}
46
47pub(crate) fn handle_scancode(scancode: u8) {
48 PS2_KEYBOARD
49 .kbd
50 .try_with_lock(|kbd| {
51 match kbd.add_byte(scancode) {
52 Err(error) => {
53 tracing::warn!(
54 ?error,
55 scancode = fmt::hex(&scancode),
56 "error decoding scancode, ignoring it!"
57 );
58 }
59 Ok(None) => {}
61 Ok(Some(event)) => {
63 if let Some(decoded_key) = kbd.process_keyevent(event) {
64 if let Err(decoded_key) = PS2_KEYBOARD.buf.push(Some(decoded_key)) {
66 tracing::warn!(
67 ?decoded_key,
68 "keyboard buffer full, dropping key event!"
69 )
70 }
71 PS2_KEYBOARD.waiters.wake_all();
72 }
73 }
74 };
75 })
76 .expect("handle_scancode should only be called in an ISR!");
77}