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, VolatileReadable, WriteOnly}; 8 use crate::Error; 9 use alloc::{boxed::Box, string::String}; 10 use core::cmp::min; 11 use core::mem::size_of; 12 use core::ptr::{addr_of, NonNull}; 13 use zerocopy::{AsBytes, FromBytes, FromZeroes}; 14 15 /// Virtual human interface devices such as keyboards, mice and tablets. 16 /// 17 /// An instance of the virtio device represents one such input device. 18 /// Device behavior mirrors that of the evdev layer in Linux, 19 /// making pass-through implementations on top of evdev easy. 20 pub struct VirtIOInput<H: Hal, T: Transport> { 21 transport: T, 22 event_queue: VirtQueue<H, QUEUE_SIZE>, 23 status_queue: VirtQueue<H, QUEUE_SIZE>, 24 event_buf: Box<[InputEvent; 32]>, 25 config: NonNull<Config>, 26 } 27 28 impl<H: Hal, T: Transport> VirtIOInput<H, T> { 29 /// Create a new VirtIO-Input driver. new(mut transport: T) -> Result<Self, Error>30 pub fn new(mut transport: T) -> Result<Self, Error> { 31 let mut event_buf = Box::new([InputEvent::default(); QUEUE_SIZE]); 32 33 let negotiated_features = transport.begin_init(SUPPORTED_FEATURES); 34 35 let config = transport.config_space::<Config>()?; 36 37 let mut event_queue = VirtQueue::new( 38 &mut transport, 39 QUEUE_EVENT, 40 negotiated_features.contains(Feature::RING_INDIRECT_DESC), 41 negotiated_features.contains(Feature::RING_EVENT_IDX), 42 )?; 43 let status_queue = VirtQueue::new( 44 &mut transport, 45 QUEUE_STATUS, 46 negotiated_features.contains(Feature::RING_INDIRECT_DESC), 47 negotiated_features.contains(Feature::RING_EVENT_IDX), 48 )?; 49 for (i, event) in event_buf.as_mut().iter_mut().enumerate() { 50 // Safe because the buffer lasts as long as the queue. 51 let token = unsafe { event_queue.add(&[], &mut [event.as_bytes_mut()])? }; 52 assert_eq!(token, i as u16); 53 } 54 if event_queue.should_notify() { 55 transport.notify(QUEUE_EVENT); 56 } 57 58 transport.finish_init(); 59 60 Ok(VirtIOInput { 61 transport, 62 event_queue, 63 status_queue, 64 event_buf, 65 config, 66 }) 67 } 68 69 /// Acknowledge interrupt and process events. ack_interrupt(&mut self) -> bool70 pub fn ack_interrupt(&mut self) -> bool { 71 self.transport.ack_interrupt() 72 } 73 74 /// Pop the pending event. pop_pending_event(&mut self) -> Option<InputEvent>75 pub fn pop_pending_event(&mut self) -> Option<InputEvent> { 76 if let Some(token) = self.event_queue.peek_used() { 77 let event = &mut self.event_buf[token as usize]; 78 // Safe because we are passing the same buffer as we passed to `VirtQueue::add` and it 79 // is still valid. 80 unsafe { 81 self.event_queue 82 .pop_used(token, &[], &mut [event.as_bytes_mut()]) 83 .ok()?; 84 } 85 let event_saved = *event; 86 // requeue 87 // Safe because buffer lasts as long as the queue. 88 if let Ok(new_token) = unsafe { self.event_queue.add(&[], &mut [event.as_bytes_mut()]) } 89 { 90 // This only works because nothing happen between `pop_used` and `add` that affects 91 // the list of free descriptors in the queue, so `add` reuses the descriptor which 92 // was just freed by `pop_used`. 93 assert_eq!(new_token, token); 94 if self.event_queue.should_notify() { 95 self.transport.notify(QUEUE_EVENT); 96 } 97 return Some(event_saved); 98 } 99 } 100 None 101 } 102 103 /// Query a specific piece of information by `select` and `subsel`, and write 104 /// result to `out`, return the result size. query_config_select( &mut self, select: InputConfigSelect, subsel: u8, out: &mut [u8], ) -> u8105 pub fn query_config_select( 106 &mut self, 107 select: InputConfigSelect, 108 subsel: u8, 109 out: &mut [u8], 110 ) -> u8 { 111 let size; 112 // Safe because config points to a valid MMIO region for the config space. 113 unsafe { 114 volwrite!(self.config, select, select as u8); 115 volwrite!(self.config, subsel, subsel); 116 size = volread!(self.config, size); 117 let size_to_copy = min(usize::from(size), out.len()); 118 for (i, out_item) in out.iter_mut().take(size_to_copy).enumerate() { 119 *out_item = addr_of!((*self.config.as_ptr()).data[i]).vread(); 120 } 121 } 122 size 123 } 124 125 /// Queries a specific piece of information by `select` and `subsel`, allocates a sufficiently 126 /// large byte buffer for it, and returns it. query_config_select_alloc( &mut self, select: InputConfigSelect, subsel: u8, ) -> Result<Box<[u8]>, Error>127 fn query_config_select_alloc( 128 &mut self, 129 select: InputConfigSelect, 130 subsel: u8, 131 ) -> Result<Box<[u8]>, Error> { 132 // Safe because config points to a valid MMIO region for the config space. 133 unsafe { 134 volwrite!(self.config, select, select as u8); 135 volwrite!(self.config, subsel, subsel); 136 let size = usize::from(volread!(self.config, size)); 137 if size > CONFIG_DATA_MAX_LENGTH { 138 return Err(Error::IoError); 139 } 140 let mut buf = u8::new_box_slice_zeroed(size); 141 for i in 0..size { 142 buf[i] = addr_of!((*self.config.as_ptr()).data[i]).vread(); 143 } 144 Ok(buf) 145 } 146 } 147 148 /// Queries a specific piece of information by `select` and `subsel` into a newly-allocated 149 /// buffer, and tries to convert it to a string. 150 /// 151 /// Returns an error if it is not valid UTF-8. query_config_string( &mut self, select: InputConfigSelect, subsel: u8, ) -> Result<String, Error>152 fn query_config_string( 153 &mut self, 154 select: InputConfigSelect, 155 subsel: u8, 156 ) -> Result<String, Error> { 157 Ok(String::from_utf8( 158 self.query_config_select_alloc(select, subsel)?.into(), 159 )?) 160 } 161 162 /// Queries and returns the name of the device, or an error if it is not valid UTF-8. name(&mut self) -> Result<String, Error>163 pub fn name(&mut self) -> Result<String, Error> { 164 self.query_config_string(InputConfigSelect::IdName, 0) 165 } 166 167 /// Queries and returns the serial number of the device, or an error if it is not valid UTF-8. serial_number(&mut self) -> Result<String, Error>168 pub fn serial_number(&mut self) -> Result<String, Error> { 169 self.query_config_string(InputConfigSelect::IdSerial, 0) 170 } 171 172 /// Queries and returns the ID information of the device. ids(&mut self) -> Result<DevIDs, Error>173 pub fn ids(&mut self) -> Result<DevIDs, Error> { 174 let mut ids = DevIDs::default(); 175 let size = self.query_config_select(InputConfigSelect::IdDevids, 0, ids.as_bytes_mut()); 176 if usize::from(size) == size_of::<DevIDs>() { 177 Ok(ids) 178 } else { 179 Err(Error::IoError) 180 } 181 } 182 183 /// Queries and returns the input properties of the device. prop_bits(&mut self) -> Result<Box<[u8]>, Error>184 pub fn prop_bits(&mut self) -> Result<Box<[u8]>, Error> { 185 self.query_config_select_alloc(InputConfigSelect::PropBits, 0) 186 } 187 188 /// Queries and returns a bitmap of supported event codes for the given event type. 189 /// 190 /// If the event type is not supported an empty slice will be returned. ev_bits(&mut self, event_type: u8) -> Result<Box<[u8]>, Error>191 pub fn ev_bits(&mut self, event_type: u8) -> Result<Box<[u8]>, Error> { 192 self.query_config_select_alloc(InputConfigSelect::EvBits, event_type) 193 } 194 195 /// Queries and returns information about the given axis of the device. abs_info(&mut self, axis: u8) -> Result<AbsInfo, Error>196 pub fn abs_info(&mut self, axis: u8) -> Result<AbsInfo, Error> { 197 let mut info = AbsInfo::default(); 198 let size = self.query_config_select(InputConfigSelect::AbsInfo, axis, info.as_bytes_mut()); 199 if usize::from(size) == size_of::<AbsInfo>() { 200 Ok(info) 201 } else { 202 Err(Error::IoError) 203 } 204 } 205 } 206 207 // SAFETY: The config space can be accessed from any thread. 208 unsafe impl<H: Hal, T: Transport + Send> Send for VirtIOInput<H, T> where 209 VirtQueue<H, QUEUE_SIZE>: Send 210 { 211 } 212 213 // SAFETY: An '&VirtIOInput` can't do anything, all methods take `&mut self`. 214 unsafe impl<H: Hal, T: Transport + Sync> Sync for VirtIOInput<H, T> where 215 VirtQueue<H, QUEUE_SIZE>: Sync 216 { 217 } 218 219 impl<H: Hal, T: Transport> Drop for VirtIOInput<H, T> { drop(&mut self)220 fn drop(&mut self) { 221 // Clear any pointers pointing to DMA regions, so the device doesn't try to access them 222 // after they have been freed. 223 self.transport.queue_unset(QUEUE_EVENT); 224 self.transport.queue_unset(QUEUE_STATUS); 225 } 226 } 227 228 const CONFIG_DATA_MAX_LENGTH: usize = 128; 229 230 /// Select value used for [`VirtIOInput::query_config_select()`]. 231 #[repr(u8)] 232 #[derive(Debug, Clone, Copy)] 233 pub enum InputConfigSelect { 234 /// Returns the name of the device, in u.string. subsel is zero. 235 IdName = 0x01, 236 /// Returns the serial number of the device, in u.string. subsel is zero. 237 IdSerial = 0x02, 238 /// Returns ID information of the device, in u.ids. subsel is zero. 239 IdDevids = 0x03, 240 /// Returns input properties of the device, in u.bitmap. subsel is zero. 241 /// Individual bits in the bitmap correspond to INPUT_PROP_* constants used 242 /// by the underlying evdev implementation. 243 PropBits = 0x10, 244 /// subsel specifies the event type using EV_* constants in the underlying 245 /// evdev implementation. If size is non-zero the event type is supported 246 /// and a bitmap of supported event codes is returned in u.bitmap. Individual 247 /// bits in the bitmap correspond to implementation-defined input event codes, 248 /// for example keys or pointing device axes. 249 EvBits = 0x11, 250 /// subsel specifies the absolute axis using ABS_* constants in the underlying 251 /// evdev implementation. Information about the axis will be returned in u.abs. 252 AbsInfo = 0x12, 253 } 254 255 #[repr(C)] 256 struct Config { 257 select: WriteOnly<u8>, 258 subsel: WriteOnly<u8>, 259 size: ReadOnly<u8>, 260 _reserved: [ReadOnly<u8>; 5], 261 data: [ReadOnly<u8>; CONFIG_DATA_MAX_LENGTH], 262 } 263 264 /// Information about an axis of an input device, typically a joystick. 265 #[repr(C)] 266 #[derive(AsBytes, Clone, Debug, Default, Eq, PartialEq, FromBytes, FromZeroes)] 267 pub struct AbsInfo { 268 /// The minimum value for the axis. 269 pub min: u32, 270 /// The maximum value for the axis. 271 pub max: u32, 272 /// The fuzz value used to filter noise from the event stream. 273 pub fuzz: u32, 274 /// The size of the dead zone; values less than this will be reported as 0. 275 pub flat: u32, 276 /// The resolution for values reported for the axis. 277 pub res: u32, 278 } 279 280 /// The identifiers of a VirtIO input device. 281 #[repr(C)] 282 #[derive(AsBytes, Clone, Debug, Default, Eq, PartialEq, FromBytes, FromZeroes)] 283 pub struct DevIDs { 284 /// The bustype identifier. 285 pub bustype: u16, 286 /// The vendor identifier. 287 pub vendor: u16, 288 /// The product identifier. 289 pub product: u16, 290 /// The version identifier. 291 pub version: u16, 292 } 293 294 /// Both queues use the same `virtio_input_event` struct. `type`, `code` and `value` 295 /// are filled according to the Linux input layer (evdev) interface. 296 #[repr(C)] 297 #[derive(AsBytes, Clone, Copy, Debug, Default, FromBytes, FromZeroes)] 298 pub struct InputEvent { 299 /// Event type. 300 pub event_type: u16, 301 /// Event code. 302 pub code: u16, 303 /// Event value. 304 pub value: u32, 305 } 306 307 const QUEUE_EVENT: u16 = 0; 308 const QUEUE_STATUS: u16 = 1; 309 const SUPPORTED_FEATURES: Feature = Feature::RING_EVENT_IDX.union(Feature::RING_INDIRECT_DESC); 310 311 // a parameter that can change 312 const QUEUE_SIZE: usize = 32; 313 314 #[cfg(test)] 315 mod tests { 316 use super::*; 317 use crate::{ 318 hal::fake::FakeHal, 319 transport::{ 320 fake::{FakeTransport, QueueStatus, State}, 321 DeviceType, 322 }, 323 }; 324 use alloc::{sync::Arc, vec}; 325 use core::convert::TryInto; 326 use std::sync::Mutex; 327 328 #[test] config()329 fn config() { 330 const DEFAULT_DATA: ReadOnly<u8> = ReadOnly::new(0); 331 let mut config_space = Config { 332 select: WriteOnly::default(), 333 subsel: WriteOnly::default(), 334 size: ReadOnly::new(0), 335 _reserved: Default::default(), 336 data: [DEFAULT_DATA; 128], 337 }; 338 let state = Arc::new(Mutex::new(State { 339 queues: vec![QueueStatus::default(), QueueStatus::default()], 340 ..Default::default() 341 })); 342 let transport = FakeTransport { 343 device_type: DeviceType::Block, 344 max_queue_size: QUEUE_SIZE.try_into().unwrap(), 345 device_features: 0, 346 config_space: NonNull::from(&mut config_space), 347 state: state.clone(), 348 }; 349 let mut input = VirtIOInput::<FakeHal, FakeTransport<Config>>::new(transport).unwrap(); 350 351 set_data(&mut config_space, "Test input device".as_bytes()); 352 assert_eq!(input.name().unwrap(), "Test input device"); 353 assert_eq!(config_space.select.0, InputConfigSelect::IdName as u8); 354 assert_eq!(config_space.subsel.0, 0); 355 356 set_data(&mut config_space, "Serial number".as_bytes()); 357 assert_eq!(input.serial_number().unwrap(), "Serial number"); 358 assert_eq!(config_space.select.0, InputConfigSelect::IdSerial as u8); 359 assert_eq!(config_space.subsel.0, 0); 360 361 let ids = DevIDs { 362 bustype: 0x4242, 363 product: 0x0067, 364 vendor: 0x1234, 365 version: 0x4321, 366 }; 367 set_data(&mut config_space, ids.as_bytes()); 368 assert_eq!(input.ids().unwrap(), ids); 369 assert_eq!(config_space.select.0, InputConfigSelect::IdDevids as u8); 370 assert_eq!(config_space.subsel.0, 0); 371 372 set_data(&mut config_space, &[0x12, 0x34, 0x56]); 373 assert_eq!(input.prop_bits().unwrap().as_ref(), &[0x12, 0x34, 0x56]); 374 assert_eq!(config_space.select.0, InputConfigSelect::PropBits as u8); 375 assert_eq!(config_space.subsel.0, 0); 376 377 set_data(&mut config_space, &[0x42, 0x66]); 378 assert_eq!(input.ev_bits(3).unwrap().as_ref(), &[0x42, 0x66]); 379 assert_eq!(config_space.select.0, InputConfigSelect::EvBits as u8); 380 assert_eq!(config_space.subsel.0, 3); 381 382 let abs_info = AbsInfo { 383 min: 12, 384 max: 1234, 385 fuzz: 4, 386 flat: 10, 387 res: 2, 388 }; 389 set_data(&mut config_space, abs_info.as_bytes()); 390 assert_eq!(input.abs_info(5).unwrap(), abs_info); 391 assert_eq!(config_space.select.0, InputConfigSelect::AbsInfo as u8); 392 assert_eq!(config_space.subsel.0, 5); 393 } 394 set_data(config_space: &mut Config, value: &[u8])395 fn set_data(config_space: &mut Config, value: &[u8]) { 396 config_space.size.0 = value.len().try_into().unwrap(); 397 for (i, &byte) in value.into_iter().enumerate() { 398 config_space.data[i].0 = byte; 399 } 400 } 401 } 402