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