Skip to main content

os/drivers/input/
mod.rs

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}