1use crate::drivers::bus::virtio::VirtioHal;
2use crate::sync::{Condvar, UPIntrFreeCell};
3use crate::task::schedule;
4use alloc::collections::VecDeque;
5use alloc::sync::Arc;
6use core::any::Any;
7use virtio_drivers::{VirtIOHeader, VirtIOInput};
8
9const VIRTIO5: usize = 0x10005000;
10const VIRTIO6: usize = 0x10006000;
11
12struct VirtIOInputInner {
13 virtio_input: VirtIOInput<'static, VirtioHal>,
14 events: VecDeque<u64>,
15}
16
17struct VirtIOInputWrapper {
18 inner: UPIntrFreeCell<VirtIOInputInner>,
19 condvar: Condvar,
20}
21
22pub trait InputDevice: Send + Sync + Any {
23 fn read_event(&self) -> u64;
24 fn handle_irq(&self);
25 fn is_empty(&self) -> bool;
26}
27
28lazy_static::lazy_static!(
29 pub static ref KEYBOARD_DEVICE: Arc<dyn InputDevice> = Arc::new(VirtIOInputWrapper::new(VIRTIO5));
30 pub static ref MOUSE_DEVICE: Arc<dyn InputDevice> = Arc::new(VirtIOInputWrapper::new(VIRTIO6));
31);
32
33impl VirtIOInputWrapper {
34 pub fn new(addr: usize) -> Self {
35 let inner = VirtIOInputInner {
36 virtio_input: unsafe {
37 VirtIOInput::<VirtioHal>::new(&mut *(addr as *mut VirtIOHeader)).unwrap()
38 },
39 events: VecDeque::new(),
40 };
41 Self {
42 inner: unsafe { UPIntrFreeCell::new(inner) },
43 condvar: Condvar::new(),
44 }
45 }
46}
47
48impl InputDevice for VirtIOInputWrapper {
49 fn is_empty(&self) -> bool {
50 self.inner.exclusive_access().events.is_empty()
51 }
52
53 fn read_event(&self) -> u64 {
54 loop {
55 let mut inner = self.inner.exclusive_access();
56 if let Some(event) = inner.events.pop_front() {
57 return event;
58 } else {
59 let task_cx_ptr = self.condvar.wait_no_sched();
60 drop(inner);
61 schedule(task_cx_ptr);
62 }
63 }
64 }
65
66 fn handle_irq(&self) {
67 let mut count = 0;
68 let mut result = 0;
69 self.inner.exclusive_session(|inner| {
70 inner.virtio_input.ack_interrupt();
71 while let Some(event) = inner.virtio_input.pop_pending_event() {
72 count += 1;
73 result = (event.event_type as u64) << 48
74 | (event.code as u64) << 32
75 | (event.value) as u64;
76 inner.events.push_back(result);
77 }
78 });
79 if count > 0 {
80 self.condvar.signal();
81 };
82 }
83}