1 //! Driver for VirtIO input devices. 2 3 use super::common::Feature; 4 use crate::hal::Hal; 5 use crate::queue::VirtQueue; 6 use crate::transport::Transport; 7 use crate::volatile::{volread, volwrite, ReadOnly, WriteOnly}; 8 use crate::Result; 9 use alloc::boxed::Box; 10 use core::ptr::NonNull; 11 use zerocopy::{AsBytes, FromBytes, FromZeroes}; 12 13 /// Virtual human interface devices such as keyboards, mice and tablets. 14 /// 15 /// An instance of the virtio device represents one such input device. 16 /// Device behavior mirrors that of the evdev layer in Linux, 17 /// making pass-through implementations on top of evdev easy. 18 pub struct VirtIOInput<H: Hal, T: Transport> { 19 transport: T, 20 event_queue: VirtQueue<H, QUEUE_SIZE>, 21 status_queue: VirtQueue<H, QUEUE_SIZE>, 22 event_buf: Box<[InputEvent; 32]>, 23 config: NonNull<Config>, 24 } 25 26 impl<H: Hal, T: Transport> VirtIOInput<H, T> { 27 /// Create a new VirtIO-Input driver. new(mut transport: T) -> Result<Self>28 pub fn new(mut transport: T) -> Result<Self> { 29 let mut event_buf = Box::new([InputEvent::default(); QUEUE_SIZE]); 30 31 let negotiated_features = transport.begin_init(SUPPORTED_FEATURES); 32 33 let config = transport.config_space::<Config>()?; 34 35 let mut event_queue = VirtQueue::new( 36 &mut transport, 37 QUEUE_EVENT, 38 negotiated_features.contains(Feature::RING_INDIRECT_DESC), 39 negotiated_features.contains(Feature::RING_EVENT_IDX), 40 )?; 41 let status_queue = VirtQueue::new( 42 &mut transport, 43 QUEUE_STATUS, 44 negotiated_features.contains(Feature::RING_INDIRECT_DESC), 45 negotiated_features.contains(Feature::RING_EVENT_IDX), 46 )?; 47 for (i, event) in event_buf.as_mut().iter_mut().enumerate() { 48 // Safe because the buffer lasts as long as the queue. 49 let token = unsafe { event_queue.add(&[], &mut [event.as_bytes_mut()])? }; 50 assert_eq!(token, i as u16); 51 } 52 if event_queue.should_notify() { 53 transport.notify(QUEUE_EVENT); 54 } 55 56 transport.finish_init(); 57 58 Ok(VirtIOInput { 59 transport, 60 event_queue, 61 status_queue, 62 event_buf, 63 config, 64 }) 65 } 66 67 /// Acknowledge interrupt and process events. ack_interrupt(&mut self) -> bool68 pub fn ack_interrupt(&mut self) -> bool { 69 self.transport.ack_interrupt() 70 } 71 72 /// Pop the pending event. pop_pending_event(&mut self) -> Option<InputEvent>73 pub fn pop_pending_event(&mut self) -> Option<InputEvent> { 74 if let Some(token) = self.event_queue.peek_used() { 75 let event = &mut self.event_buf[token as usize]; 76 // Safe because we are passing the same buffer as we passed to `VirtQueue::add` and it 77 // is still valid. 78 unsafe { 79 self.event_queue 80 .pop_used(token, &[], &mut [event.as_bytes_mut()]) 81 .ok()?; 82 } 83 let event_saved = *event; 84 // requeue 85 // Safe because buffer lasts as long as the queue. 86 if let Ok(new_token) = unsafe { self.event_queue.add(&[], &mut [event.as_bytes_mut()]) } 87 { 88 // This only works because nothing happen between `pop_used` and `add` that affects 89 // the list of free descriptors in the queue, so `add` reuses the descriptor which 90 // was just freed by `pop_used`. 91 assert_eq!(new_token, token); 92 if self.event_queue.should_notify() { 93 self.transport.notify(QUEUE_EVENT); 94 } 95 return Some(event_saved); 96 } 97 } 98 None 99 } 100 101 /// Query a specific piece of information by `select` and `subsel`, and write 102 /// result to `out`, return the result size. query_config_select( &mut self, select: InputConfigSelect, subsel: u8, out: &mut [u8], ) -> u8103 pub fn query_config_select( 104 &mut self, 105 select: InputConfigSelect, 106 subsel: u8, 107 out: &mut [u8], 108 ) -> u8 { 109 let size; 110 let data; 111 // Safe because config points to a valid MMIO region for the config space. 112 unsafe { 113 volwrite!(self.config, select, select as u8); 114 volwrite!(self.config, subsel, subsel); 115 size = volread!(self.config, size); 116 data = volread!(self.config, data); 117 } 118 out[..size as usize].copy_from_slice(&data[..size as usize]); 119 size 120 } 121 } 122 123 // SAFETY: The config space can be accessed from any thread. 124 unsafe impl<H: Hal, T: Transport + Send> Send for VirtIOInput<H, T> where 125 VirtQueue<H, QUEUE_SIZE>: Send 126 { 127 } 128 129 // SAFETY: An '&VirtIOInput` can't do anything, all methods take `&mut self`. 130 unsafe impl<H: Hal, T: Transport + Sync> Sync for VirtIOInput<H, T> where 131 VirtQueue<H, QUEUE_SIZE>: Sync 132 { 133 } 134 135 impl<H: Hal, T: Transport> Drop for VirtIOInput<H, T> { drop(&mut self)136 fn drop(&mut self) { 137 // Clear any pointers pointing to DMA regions, so the device doesn't try to access them 138 // after they have been freed. 139 self.transport.queue_unset(QUEUE_EVENT); 140 self.transport.queue_unset(QUEUE_STATUS); 141 } 142 } 143 144 /// Select value used for [`VirtIOInput::query_config_select()`]. 145 #[repr(u8)] 146 #[derive(Debug, Clone, Copy)] 147 pub enum InputConfigSelect { 148 /// Returns the name of the device, in u.string. subsel is zero. 149 IdName = 0x01, 150 /// Returns the serial number of the device, in u.string. subsel is zero. 151 IdSerial = 0x02, 152 /// Returns ID information of the device, in u.ids. subsel is zero. 153 IdDevids = 0x03, 154 /// Returns input properties of the device, in u.bitmap. subsel is zero. 155 /// Individual bits in the bitmap correspond to INPUT_PROP_* constants used 156 /// by the underlying evdev implementation. 157 PropBits = 0x10, 158 /// subsel specifies the event type using EV_* constants in the underlying 159 /// evdev implementation. If size is non-zero the event type is supported 160 /// and a bitmap of supported event codes is returned in u.bitmap. Individual 161 /// bits in the bitmap correspond to implementation-defined input event codes, 162 /// for example keys or pointing device axes. 163 EvBits = 0x11, 164 /// subsel specifies the absolute axis using ABS_* constants in the underlying 165 /// evdev implementation. Information about the axis will be returned in u.abs. 166 AbsInfo = 0x12, 167 } 168 169 #[repr(C)] 170 struct Config { 171 select: WriteOnly<u8>, 172 subsel: WriteOnly<u8>, 173 size: ReadOnly<u8>, 174 _reversed: [ReadOnly<u8>; 5], 175 data: ReadOnly<[u8; 128]>, 176 } 177 178 #[repr(C)] 179 #[derive(Debug)] 180 struct AbsInfo { 181 min: u32, 182 max: u32, 183 fuzz: u32, 184 flat: u32, 185 res: u32, 186 } 187 188 #[repr(C)] 189 #[derive(Debug)] 190 struct DevIDs { 191 bustype: u16, 192 vendor: u16, 193 product: u16, 194 version: u16, 195 } 196 197 /// Both queues use the same `virtio_input_event` struct. `type`, `code` and `value` 198 /// are filled according to the Linux input layer (evdev) interface. 199 #[repr(C)] 200 #[derive(AsBytes, Clone, Copy, Debug, Default, FromBytes, FromZeroes)] 201 pub struct InputEvent { 202 /// Event type. 203 pub event_type: u16, 204 /// Event code. 205 pub code: u16, 206 /// Event value. 207 pub value: u32, 208 } 209 210 const QUEUE_EVENT: u16 = 0; 211 const QUEUE_STATUS: u16 = 1; 212 const SUPPORTED_FEATURES: Feature = Feature::RING_EVENT_IDX.union(Feature::RING_INDIRECT_DESC); 213 214 // a parameter that can change 215 const QUEUE_SIZE: usize = 32; 216