1 // Copyright 2019 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #[allow(dead_code)]
6 mod defaults;
7 mod evdev;
8 mod event_source;
9
10 use std::collections::BTreeMap;
11 use std::fs;
12 use std::io::Read;
13 use std::io::Write;
14 use std::path::PathBuf;
15
16 use anyhow::anyhow;
17 use anyhow::bail;
18 use anyhow::Context;
19 use base::custom_serde::deserialize_seq_to_arr;
20 use base::custom_serde::serialize_arr;
21 use base::error;
22 use base::info;
23 use base::warn;
24 use base::AsRawDescriptor;
25 use base::Event;
26 use base::EventToken;
27 use base::RawDescriptor;
28 use base::WaitContext;
29 use base::WorkerThread;
30 use data_model::Le16;
31 use data_model::Le32;
32 use linux_input_sys::constants::*;
33 use linux_input_sys::virtio_input_event;
34 use linux_input_sys::InputEventDecoder;
35 use remain::sorted;
36 use serde::Deserialize;
37 use serde::Serialize;
38 use snapshot::AnySnapshot;
39 use thiserror::Error;
40 use vm_memory::GuestMemory;
41 use zerocopy::FromBytes;
42 use zerocopy::Immutable;
43 use zerocopy::IntoBytes;
44 use zerocopy::KnownLayout;
45
46 use self::event_source::EvdevEventSource;
47 use self::event_source::EventSource;
48 use self::event_source::SocketEventSource;
49 use super::copy_config;
50 use super::DescriptorChain;
51 use super::DeviceType;
52 use super::Interrupt;
53 use super::Queue;
54 use super::VirtioDevice;
55
56 const EVENT_QUEUE_SIZE: u16 = 64;
57 const STATUS_QUEUE_SIZE: u16 = 64;
58 const QUEUE_SIZES: &[u16] = &[EVENT_QUEUE_SIZE, STATUS_QUEUE_SIZE];
59
60 #[sorted]
61 #[derive(Error, Debug)]
62 pub enum InputError {
63 // Failed to get axis information of event device
64 #[error("failed to get axis information of event device: {0}")]
65 EvdevAbsInfoError(base::Error),
66 // Failed to get event types supported by device
67 #[error("failed to get event types supported by device: {0}")]
68 EvdevEventTypesError(base::Error),
69 // Failed to grab event device
70 #[error("failed to grab event device: {0}")]
71 EvdevGrabError(base::Error),
72 // Failed to get name of event device
73 #[error("failed to get id of event device: {0}")]
74 EvdevIdError(base::Error),
75 // Failed to get name of event device
76 #[error("failed to get name of event device: {0}")]
77 EvdevNameError(base::Error),
78 // Failed to get properties of event device
79 #[error("failed to get properties of event device: {0}")]
80 EvdevPropertiesError(base::Error),
81 // Failed to get serial name of event device
82 #[error("failed to get serial name of event device: {0}")]
83 EvdevSerialError(base::Error),
84 /// Failed to read events from the source
85 #[error("failed to read events from the source: {0}")]
86 EventsReadError(std::io::Error),
87 /// Failed to write events to the source
88 #[error("failed to write events to the source: {0}")]
89 EventsWriteError(std::io::Error),
90 // Detected error on guest side
91 #[error("detected error on guest side: {0}")]
92 GuestError(String),
93 // Invalid UTF-8 string
94 #[error("invalid UTF-8 string: {0}")]
95 InvalidString(std::string::FromUtf8Error),
96 // Failed to parse event config file
97 #[error("failed to parse event config file: {0}")]
98 ParseEventConfigError(String),
99 // Error while reading from virtqueue
100 #[error("failed to read from virtqueue: {0}")]
101 ReadQueue(std::io::Error),
102 // Error while writing to virtqueue
103 #[error("failed to write to virtqueue: {0}")]
104 WriteQueue(std::io::Error),
105 }
106
107 pub type Result<T> = std::result::Result<T, InputError>;
108
109 #[derive(
110 Copy,
111 Clone,
112 Default,
113 Debug,
114 FromBytes,
115 Immutable,
116 IntoBytes,
117 KnownLayout,
118 Serialize,
119 Deserialize,
120 )]
121 #[repr(C)]
122 pub struct virtio_input_device_ids {
123 bustype: Le16,
124 vendor: Le16,
125 product: Le16,
126 version: Le16,
127 }
128
129 impl virtio_input_device_ids {
new(bustype: u16, product: u16, vendor: u16, version: u16) -> virtio_input_device_ids130 fn new(bustype: u16, product: u16, vendor: u16, version: u16) -> virtio_input_device_ids {
131 virtio_input_device_ids {
132 bustype: Le16::from(bustype),
133 vendor: Le16::from(vendor),
134 product: Le16::from(product),
135 version: Le16::from(version),
136 }
137 }
138 }
139
140 #[derive(
141 Copy,
142 Clone,
143 Default,
144 Debug,
145 FromBytes,
146 Immutable,
147 IntoBytes,
148 KnownLayout,
149 PartialEq,
150 Serialize,
151 Deserialize,
152 )]
153 #[repr(C)]
154 pub struct virtio_input_absinfo {
155 min: Le32,
156 max: Le32,
157 fuzz: Le32,
158 flat: Le32,
159 }
160
161 impl virtio_input_absinfo {
new(min: u32, max: u32, fuzz: u32, flat: u32) -> virtio_input_absinfo162 fn new(min: u32, max: u32, fuzz: u32, flat: u32) -> virtio_input_absinfo {
163 virtio_input_absinfo {
164 min: Le32::from(min),
165 max: Le32::from(max),
166 fuzz: Le32::from(fuzz),
167 flat: Le32::from(flat),
168 }
169 }
170 }
171
172 #[derive(Copy, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
173 #[repr(C)]
174 struct virtio_input_config {
175 select: u8,
176 subsel: u8,
177 size: u8,
178 reserved: [u8; 5],
179 payload: [u8; 128],
180 }
181
182 impl virtio_input_config {
new() -> virtio_input_config183 fn new() -> virtio_input_config {
184 virtio_input_config {
185 select: 0,
186 subsel: 0,
187 size: 0,
188 reserved: [0u8; 5],
189 payload: [0u8; 128],
190 }
191 }
192
set_payload_slice(&mut self, slice: &[u8])193 fn set_payload_slice(&mut self, slice: &[u8]) {
194 let bytes_written = match (&mut self.payload[..]).write(slice) {
195 Ok(x) => x,
196 Err(_) => {
197 // This won't happen because write is guaranteed to succeed with slices
198 unreachable!();
199 }
200 };
201 self.size = bytes_written as u8;
202 if bytes_written < slice.len() {
203 // This shouldn't happen since everywhere this function is called the size is guaranteed
204 // to be at most 128 bytes (the size of the payload)
205 warn!("Slice is too long to fit in payload");
206 }
207 }
208
set_payload_str(&mut self, s: &str)209 fn set_payload_str(&mut self, s: &str) {
210 self.set_payload_slice(s.as_bytes());
211 }
212
set_payload_bitmap(&mut self, bitmap: &virtio_input_bitmap)213 fn set_payload_bitmap(&mut self, bitmap: &virtio_input_bitmap) {
214 self.size = bitmap.min_size();
215 self.payload.copy_from_slice(&bitmap.bitmap);
216 }
217
set_absinfo(&mut self, absinfo: &virtio_input_absinfo)218 fn set_absinfo(&mut self, absinfo: &virtio_input_absinfo) {
219 self.set_payload_slice(absinfo.as_bytes());
220 }
221
set_device_ids(&mut self, device_ids: &virtio_input_device_ids)222 fn set_device_ids(&mut self, device_ids: &virtio_input_device_ids) {
223 self.set_payload_slice(device_ids.as_bytes());
224 }
225 }
226
227 #[derive(Copy, Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
228 #[repr(C)]
229 pub struct virtio_input_bitmap {
230 #[serde(
231 serialize_with = "serialize_arr",
232 deserialize_with = "deserialize_seq_to_arr"
233 )]
234 bitmap: [u8; 128],
235 }
236
237 impl virtio_input_bitmap {
new(bitmap: [u8; 128]) -> virtio_input_bitmap238 fn new(bitmap: [u8; 128]) -> virtio_input_bitmap {
239 virtio_input_bitmap { bitmap }
240 }
241
len(&self) -> usize242 fn len(&self) -> usize {
243 self.bitmap.len()
244 }
245
246 // Creates a bitmap from an array of bit indices
from_bits(set_indices: &[u16]) -> virtio_input_bitmap247 fn from_bits(set_indices: &[u16]) -> virtio_input_bitmap {
248 let mut ret = virtio_input_bitmap { bitmap: [0u8; 128] };
249 for idx in set_indices {
250 let byte_pos = (idx / 8) as usize;
251 let bit_byte = 1u8 << (idx % 8);
252 if byte_pos < ret.len() {
253 ret.bitmap[byte_pos] |= bit_byte;
254 } else {
255 // This would only happen if new event codes (or types, or ABS_*, etc) are defined
256 // to be larger than or equal to 1024, in which case a new version
257 // of the virtio input protocol needs to be defined.
258 // There is nothing we can do about this error except log it.
259 error!("Attempted to set an out of bounds bit: {}", idx);
260 }
261 }
262 ret
263 }
264
265 // Returns the length of the minimum array that can hold all set bits in the map
min_size(&self) -> u8266 fn min_size(&self) -> u8 {
267 self.bitmap
268 .iter()
269 .rposition(|v| *v != 0)
270 .map_or(0, |i| i + 1) as u8
271 }
272 }
273
274 #[derive(Debug, Serialize, Deserialize, Clone)]
275 pub struct VirtioInputConfig {
276 select: u8,
277 subsel: u8,
278 device_ids: virtio_input_device_ids,
279 name: String,
280 serial_name: String,
281 properties: virtio_input_bitmap,
282 supported_events: BTreeMap<u16, virtio_input_bitmap>,
283 axis_info: BTreeMap<u16, virtio_input_absinfo>,
284 }
285
286 impl VirtioInputConfig {
new( device_ids: virtio_input_device_ids, name: String, serial_name: String, properties: virtio_input_bitmap, supported_events: BTreeMap<u16, virtio_input_bitmap>, axis_info: BTreeMap<u16, virtio_input_absinfo>, ) -> VirtioInputConfig287 fn new(
288 device_ids: virtio_input_device_ids,
289 name: String,
290 serial_name: String,
291 properties: virtio_input_bitmap,
292 supported_events: BTreeMap<u16, virtio_input_bitmap>,
293 axis_info: BTreeMap<u16, virtio_input_absinfo>,
294 ) -> VirtioInputConfig {
295 VirtioInputConfig {
296 select: 0,
297 subsel: 0,
298 device_ids,
299 name,
300 serial_name,
301 properties,
302 supported_events,
303 axis_info,
304 }
305 }
306
from_evdev<T: AsRawDescriptor>(source: &T) -> Result<VirtioInputConfig>307 fn from_evdev<T: AsRawDescriptor>(source: &T) -> Result<VirtioInputConfig> {
308 Ok(VirtioInputConfig::new(
309 evdev::device_ids(source)?,
310 evdev::name(source)?,
311 evdev::serial_name(source)?,
312 evdev::properties(source)?,
313 evdev::supported_events(source)?,
314 evdev::abs_info(source),
315 ))
316 }
317
build_config_memory(&self) -> virtio_input_config318 fn build_config_memory(&self) -> virtio_input_config {
319 let mut cfg = virtio_input_config::new();
320 cfg.select = self.select;
321 cfg.subsel = self.subsel;
322 match self.select {
323 VIRTIO_INPUT_CFG_ID_NAME => {
324 cfg.set_payload_str(&self.name);
325 }
326 VIRTIO_INPUT_CFG_ID_SERIAL => {
327 cfg.set_payload_str(&self.serial_name);
328 }
329 VIRTIO_INPUT_CFG_PROP_BITS => {
330 cfg.set_payload_bitmap(&self.properties);
331 }
332 VIRTIO_INPUT_CFG_EV_BITS => {
333 let ev_type = self.subsel as u16;
334 // zero is a special case: return all supported event types (just like EVIOCGBIT)
335 if ev_type == 0 {
336 let events_bm = virtio_input_bitmap::from_bits(
337 &self.supported_events.keys().cloned().collect::<Vec<u16>>(),
338 );
339 cfg.set_payload_bitmap(&events_bm);
340 } else if let Some(supported_codes) = self.supported_events.get(&ev_type) {
341 cfg.set_payload_bitmap(supported_codes);
342 }
343 }
344 VIRTIO_INPUT_CFG_ABS_INFO => {
345 let abs_axis = self.subsel as u16;
346 if let Some(absinfo) = self.axis_info.get(&abs_axis) {
347 cfg.set_absinfo(absinfo);
348 } // else all zeroes in the payload
349 }
350 VIRTIO_INPUT_CFG_ID_DEVIDS => {
351 cfg.set_device_ids(&self.device_ids);
352 }
353 VIRTIO_INPUT_CFG_UNSET => {
354 // Per the virtio spec at https://docs.oasis-open.org/virtio/virtio/v1.1/cs01/virtio-v1.1-cs01.html#x1-3390008,
355 // there is no action required of us when this is set. It's unclear whether we
356 // should be zeroing the virtio_input_config, but empirically we know that the
357 // existing behavior of doing nothing works with the Linux virtio-input frontend.
358 }
359 _ => {
360 warn!("Unsuported virtio input config selection: {}", self.select);
361 }
362 }
363 cfg
364 }
365
read(&self, offset: usize, data: &mut [u8])366 fn read(&self, offset: usize, data: &mut [u8]) {
367 copy_config(
368 data,
369 0,
370 self.build_config_memory().as_bytes(),
371 offset as u64,
372 );
373 }
374
write(&mut self, offset: usize, data: &[u8])375 fn write(&mut self, offset: usize, data: &[u8]) {
376 let mut config = self.build_config_memory();
377 copy_config(config.as_mut_bytes(), offset as u64, data, 0);
378 self.select = config.select;
379 self.subsel = config.subsel;
380 }
381 }
382
383 struct Worker<T: EventSource> {
384 event_source: T,
385 event_queue: Queue,
386 status_queue: Queue,
387 name: String,
388 }
389
390 impl<T: EventSource> Worker<T> {
391 // Fills a virtqueue with events from the source. Returns the number of bytes written.
fill_event_virtqueue( event_source: &mut T, avail_desc: &mut DescriptorChain, ) -> Result<usize>392 fn fill_event_virtqueue(
393 event_source: &mut T,
394 avail_desc: &mut DescriptorChain,
395 ) -> Result<usize> {
396 let writer = &mut avail_desc.writer;
397
398 while writer.available_bytes() >= virtio_input_event::SIZE {
399 if let Some(evt) = event_source.pop_available_event() {
400 writer.write_obj(evt).map_err(InputError::WriteQueue)?;
401 } else {
402 break;
403 }
404 }
405
406 Ok(writer.bytes_written())
407 }
408
409 // Send events from the source to the guest
send_events(&mut self) -> bool410 fn send_events(&mut self) -> bool {
411 let mut needs_interrupt = false;
412
413 // Only consume from the queue iterator if we know we have events to send
414 while self.event_source.available_events_count() > 0 {
415 match self.event_queue.pop() {
416 None => {
417 break;
418 }
419 Some(mut avail_desc) => {
420 let bytes_written =
421 match Worker::fill_event_virtqueue(&mut self.event_source, &mut avail_desc)
422 {
423 Ok(count) => count,
424 Err(e) => {
425 error!("Input: failed to send events to guest: {}", e);
426 break;
427 }
428 };
429
430 self.event_queue.add_used(avail_desc, bytes_written as u32);
431 needs_interrupt = true;
432 }
433 }
434 }
435
436 needs_interrupt
437 }
438
439 // Sends events from the guest to the source. Returns the number of bytes read.
read_event_virtqueue( avail_desc: &mut DescriptorChain, event_source: &mut T, ) -> Result<usize>440 fn read_event_virtqueue(
441 avail_desc: &mut DescriptorChain,
442 event_source: &mut T,
443 ) -> Result<usize> {
444 let reader = &mut avail_desc.reader;
445 while reader.available_bytes() >= virtio_input_event::SIZE {
446 let evt: virtio_input_event = reader.read_obj().map_err(InputError::ReadQueue)?;
447 event_source.send_event(&evt)?;
448 }
449
450 Ok(reader.bytes_read())
451 }
452
process_status_queue(&mut self) -> Result<bool>453 fn process_status_queue(&mut self) -> Result<bool> {
454 let mut needs_interrupt = false;
455 while let Some(mut avail_desc) = self.status_queue.pop() {
456 let bytes_read =
457 match Worker::read_event_virtqueue(&mut avail_desc, &mut self.event_source) {
458 Ok(count) => count,
459 Err(e) => {
460 error!("Input: failed to read events from virtqueue: {}", e);
461 return Err(e);
462 }
463 };
464
465 self.status_queue.add_used(avail_desc, bytes_read as u32);
466 needs_interrupt = true;
467 }
468
469 Ok(needs_interrupt)
470 }
471
472 // Allow error! and early return anywhere in function
473 #[allow(clippy::needless_return)]
run(&mut self, kill_evt: Event)474 fn run(&mut self, kill_evt: Event) {
475 if let Err(e) = self.event_source.init() {
476 error!("failed initializing event source: {}", e);
477 return;
478 }
479
480 #[derive(EventToken)]
481 enum Token {
482 EventQAvailable,
483 StatusQAvailable,
484 InputEventsAvailable,
485 Kill,
486 }
487 let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
488 (self.event_queue.event(), Token::EventQAvailable),
489 (self.status_queue.event(), Token::StatusQAvailable),
490 (&self.event_source, Token::InputEventsAvailable),
491 (&kill_evt, Token::Kill),
492 ]) {
493 Ok(wait_ctx) => wait_ctx,
494 Err(e) => {
495 error!("failed creating WaitContext: {}", e);
496 return;
497 }
498 };
499
500 'wait: loop {
501 let wait_events = match wait_ctx.wait() {
502 Ok(wait_events) => wait_events,
503 Err(e) => {
504 error!("failed polling for events: {}", e);
505 break;
506 }
507 };
508
509 let mut eventq_needs_interrupt = false;
510 let mut statusq_needs_interrupt = false;
511 for wait_event in wait_events.iter().filter(|e| e.is_readable) {
512 match wait_event.token {
513 Token::EventQAvailable => {
514 if let Err(e) = self.event_queue.event().wait() {
515 error!("failed reading event queue Event: {}", e);
516 break 'wait;
517 }
518 eventq_needs_interrupt |= self.send_events();
519 }
520 Token::StatusQAvailable => {
521 if let Err(e) = self.status_queue.event().wait() {
522 error!("failed reading status queue Event: {}", e);
523 break 'wait;
524 }
525 match self.process_status_queue() {
526 Ok(b) => statusq_needs_interrupt |= b,
527 Err(e) => error!("failed processing status events: {}", e),
528 }
529 }
530 Token::InputEventsAvailable => match self.event_source.receive_events() {
531 Err(e) => error!("error receiving events: {}", e),
532 Ok(_cnt) => eventq_needs_interrupt |= self.send_events(),
533 },
534 Token::Kill => {
535 let _ = kill_evt.wait();
536 break 'wait;
537 }
538 }
539 }
540
541 for event in wait_events.iter().filter(|e| e.is_hungup) {
542 if let Token::InputEventsAvailable = event.token {
543 warn!("input event source for '{}' disconnected", self.name);
544 let _ = wait_ctx.delete(&self.event_source);
545 }
546 }
547
548 if eventq_needs_interrupt {
549 self.event_queue.trigger_interrupt();
550 }
551 if statusq_needs_interrupt {
552 self.status_queue.trigger_interrupt();
553 }
554 }
555
556 if let Err(e) = self.event_source.finalize() {
557 error!("failed finalizing event source: {}", e);
558 return;
559 }
560 }
561 }
562
563 /// Virtio input device
564 pub struct Input<T: EventSource + Send + 'static> {
565 worker_thread: Option<WorkerThread<Worker<T>>>,
566 config: VirtioInputConfig,
567 source: Option<T>,
568 virtio_features: u64,
569 }
570
571 /// Snapshot of [Input]'s state.
572 #[derive(Serialize, Deserialize)]
573 struct InputSnapshot {
574 config: VirtioInputConfig,
575 virtio_features: u64,
576 }
577
578 impl<T> VirtioDevice for Input<T>
579 where
580 T: 'static + EventSource + Send,
581 {
keep_rds(&self) -> Vec<RawDescriptor>582 fn keep_rds(&self) -> Vec<RawDescriptor> {
583 if let Some(source) = &self.source {
584 return vec![source.as_raw_descriptor()];
585 }
586 Vec::new()
587 }
588
device_type(&self) -> DeviceType589 fn device_type(&self) -> DeviceType {
590 DeviceType::Input
591 }
592
queue_max_sizes(&self) -> &[u16]593 fn queue_max_sizes(&self) -> &[u16] {
594 QUEUE_SIZES
595 }
596
read_config(&self, offset: u64, data: &mut [u8])597 fn read_config(&self, offset: u64, data: &mut [u8]) {
598 self.config.read(offset as usize, data);
599 }
600
write_config(&mut self, offset: u64, data: &[u8])601 fn write_config(&mut self, offset: u64, data: &[u8]) {
602 self.config.write(offset as usize, data);
603 }
604
features(&self) -> u64605 fn features(&self) -> u64 {
606 self.virtio_features
607 }
608
activate( &mut self, _mem: GuestMemory, _interrupt: Interrupt, mut queues: BTreeMap<usize, Queue>, ) -> anyhow::Result<()>609 fn activate(
610 &mut self,
611 _mem: GuestMemory,
612 _interrupt: Interrupt,
613 mut queues: BTreeMap<usize, Queue>,
614 ) -> anyhow::Result<()> {
615 if queues.len() != 2 {
616 return Err(anyhow!("expected 2 queues, got {}", queues.len()));
617 }
618 let event_queue = queues.remove(&0).unwrap();
619 let status_queue = queues.remove(&1).unwrap();
620
621 let name = self.config.name.clone();
622 let source = self
623 .source
624 .take()
625 .context("tried to activate device without a source for events")?;
626 self.worker_thread = Some(WorkerThread::start("v_input", move |kill_evt| {
627 let mut worker = Worker {
628 event_source: source,
629 event_queue,
630 status_queue,
631 name,
632 };
633 worker.run(kill_evt);
634 worker
635 }));
636
637 Ok(())
638 }
639
reset(&mut self) -> anyhow::Result<()>640 fn reset(&mut self) -> anyhow::Result<()> {
641 if let Some(worker_thread) = self.worker_thread.take() {
642 let worker = worker_thread.stop();
643 self.source = Some(worker.event_source);
644 }
645 Ok(())
646 }
647
virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>>648 fn virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>> {
649 if let Some(worker_thread) = self.worker_thread.take() {
650 let worker = worker_thread.stop();
651 self.source = Some(worker.event_source);
652 let queues = BTreeMap::from([(0, worker.event_queue), (1, worker.status_queue)]);
653 Ok(Some(queues))
654 } else {
655 Ok(None)
656 }
657 }
658
virtio_wake( &mut self, queues_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>, ) -> anyhow::Result<()>659 fn virtio_wake(
660 &mut self,
661 queues_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>,
662 ) -> anyhow::Result<()> {
663 if let Some((mem, interrupt, queues)) = queues_state {
664 self.activate(mem, interrupt, queues)?;
665 }
666 Ok(())
667 }
668
virtio_snapshot(&mut self) -> anyhow::Result<AnySnapshot>669 fn virtio_snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
670 AnySnapshot::to_any(InputSnapshot {
671 virtio_features: self.virtio_features,
672 config: self.config.clone(),
673 })
674 .context("failed to serialize InputSnapshot")
675 }
676
virtio_restore(&mut self, data: AnySnapshot) -> anyhow::Result<()>677 fn virtio_restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
678 let snap: InputSnapshot = AnySnapshot::from_any(data).context("error deserializing")?;
679 if snap.virtio_features != self.virtio_features {
680 bail!(
681 "expected virtio_features to match, but they did not. Live: {:?}, snapshot {:?}",
682 self.virtio_features,
683 snap.virtio_features,
684 );
685 }
686 self.config = snap.config;
687 Ok(())
688 }
689 }
690
691 /// Creates a new virtio input device from an event device node
new_evdev<T>(source: T, virtio_features: u64) -> Result<Input<EvdevEventSource<T>>> where T: Read + Write + AsRawDescriptor + Send + 'static,692 pub fn new_evdev<T>(source: T, virtio_features: u64) -> Result<Input<EvdevEventSource<T>>>
693 where
694 T: Read + Write + AsRawDescriptor + Send + 'static,
695 {
696 Ok(Input {
697 worker_thread: None,
698 config: VirtioInputConfig::from_evdev(&source)?,
699 source: Some(EvdevEventSource::new(source)),
700 virtio_features,
701 })
702 }
703
704 /// Creates a new virtio touch device which supports single touch only.
new_single_touch<T>( idx: u32, source: T, width: u32, height: u32, name: Option<&str>, virtio_features: u64, ) -> Result<Input<SocketEventSource<T>>> where T: Read + Write + AsRawDescriptor + Send + 'static,705 pub fn new_single_touch<T>(
706 idx: u32,
707 source: T,
708 width: u32,
709 height: u32,
710 name: Option<&str>,
711 virtio_features: u64,
712 ) -> Result<Input<SocketEventSource<T>>>
713 where
714 T: Read + Write + AsRawDescriptor + Send + 'static,
715 {
716 Ok(Input {
717 worker_thread: None,
718 config: defaults::new_single_touch_config(idx, width, height, name),
719 source: Some(SocketEventSource::new(source)),
720 virtio_features,
721 })
722 }
723
724 /// Creates a new virtio touch device which supports multi touch.
new_multi_touch<T>( idx: u32, source: T, width: u32, height: u32, name: Option<&str>, virtio_features: u64, ) -> Result<Input<SocketEventSource<T>>> where T: Read + Write + AsRawDescriptor + Send + 'static,725 pub fn new_multi_touch<T>(
726 idx: u32,
727 source: T,
728 width: u32,
729 height: u32,
730 name: Option<&str>,
731 virtio_features: u64,
732 ) -> Result<Input<SocketEventSource<T>>>
733 where
734 T: Read + Write + AsRawDescriptor + Send + 'static,
735 {
736 Ok(Input {
737 worker_thread: None,
738 config: defaults::new_multi_touch_config(idx, width, height, name),
739 source: Some(SocketEventSource::new(source)),
740 virtio_features,
741 })
742 }
743
744 /// Creates a new virtio trackpad device which supports (single) touch, primary and secondary
745 /// buttons as well as X and Y axis.
new_trackpad<T>( idx: u32, source: T, width: u32, height: u32, name: Option<&str>, virtio_features: u64, ) -> Result<Input<SocketEventSource<T>>> where T: Read + Write + AsRawDescriptor + Send + 'static,746 pub fn new_trackpad<T>(
747 idx: u32,
748 source: T,
749 width: u32,
750 height: u32,
751 name: Option<&str>,
752 virtio_features: u64,
753 ) -> Result<Input<SocketEventSource<T>>>
754 where
755 T: Read + Write + AsRawDescriptor + Send + 'static,
756 {
757 Ok(Input {
758 worker_thread: None,
759 config: defaults::new_trackpad_config(idx, width, height, name),
760 source: Some(SocketEventSource::new(source)),
761 virtio_features,
762 })
763 }
764
765 /// Creates a new virtio trackpad device which supports multi touch, primary and secondary
766 /// buttons as well as X and Y axis.
new_multitouch_trackpad<T>( idx: u32, source: T, width: u32, height: u32, name: Option<&str>, virtio_features: u64, ) -> Result<Input<SocketEventSource<T>>> where T: Read + Write + AsRawDescriptor + Send + 'static,767 pub fn new_multitouch_trackpad<T>(
768 idx: u32,
769 source: T,
770 width: u32,
771 height: u32,
772 name: Option<&str>,
773 virtio_features: u64,
774 ) -> Result<Input<SocketEventSource<T>>>
775 where
776 T: Read + Write + AsRawDescriptor + Send + 'static,
777 {
778 Ok(Input {
779 worker_thread: None,
780 config: defaults::new_multitouch_trackpad_config(idx, width, height, name),
781 source: Some(SocketEventSource::new(source)),
782 virtio_features,
783 })
784 }
785
786 /// Creates a new virtio mouse which supports primary, secondary, wheel and REL events.
new_mouse<T>( idx: u32, source: T, virtio_features: u64, ) -> Result<Input<SocketEventSource<T>>> where T: Read + Write + AsRawDescriptor + Send + 'static,787 pub fn new_mouse<T>(
788 idx: u32,
789 source: T,
790 virtio_features: u64,
791 ) -> Result<Input<SocketEventSource<T>>>
792 where
793 T: Read + Write + AsRawDescriptor + Send + 'static,
794 {
795 Ok(Input {
796 worker_thread: None,
797 config: defaults::new_mouse_config(idx),
798 source: Some(SocketEventSource::new(source)),
799 virtio_features,
800 })
801 }
802
803 /// Creates a new virtio keyboard, which supports the same events as an en-us physical keyboard.
new_keyboard<T>( idx: u32, source: T, virtio_features: u64, ) -> Result<Input<SocketEventSource<T>>> where T: Read + Write + AsRawDescriptor + Send + 'static,804 pub fn new_keyboard<T>(
805 idx: u32,
806 source: T,
807 virtio_features: u64,
808 ) -> Result<Input<SocketEventSource<T>>>
809 where
810 T: Read + Write + AsRawDescriptor + Send + 'static,
811 {
812 Ok(Input {
813 worker_thread: None,
814 config: defaults::new_keyboard_config(idx),
815 source: Some(SocketEventSource::new(source)),
816 virtio_features,
817 })
818 }
819
820 /// Creates a new virtio device for switches.
new_switches<T>( idx: u32, source: T, virtio_features: u64, ) -> Result<Input<SocketEventSource<T>>> where T: Read + Write + AsRawDescriptor + Send + 'static,821 pub fn new_switches<T>(
822 idx: u32,
823 source: T,
824 virtio_features: u64,
825 ) -> Result<Input<SocketEventSource<T>>>
826 where
827 T: Read + Write + AsRawDescriptor + Send + 'static,
828 {
829 Ok(Input {
830 worker_thread: None,
831 config: defaults::new_switches_config(idx),
832 source: Some(SocketEventSource::new(source)),
833 virtio_features,
834 })
835 }
836
837 /// Creates a new virtio device for rotary.
new_rotary<T>( idx: u32, source: T, virtio_features: u64, ) -> Result<Input<SocketEventSource<T>>> where T: Read + Write + AsRawDescriptor + Send + 'static,838 pub fn new_rotary<T>(
839 idx: u32,
840 source: T,
841 virtio_features: u64,
842 ) -> Result<Input<SocketEventSource<T>>>
843 where
844 T: Read + Write + AsRawDescriptor + Send + 'static,
845 {
846 Ok(Input {
847 worker_thread: None,
848 config: defaults::new_rotary_config(idx),
849 source: Some(SocketEventSource::new(source)),
850 virtio_features,
851 })
852 }
853
854 /// Creates a new custom virtio input device
new_custom<T>( idx: u32, source: T, input_config_path: PathBuf, virtio_features: u64, ) -> Result<Input<SocketEventSource<T>>> where T: Read + Write + AsRawDescriptor + Send + 'static,855 pub fn new_custom<T>(
856 idx: u32,
857 source: T,
858 input_config_path: PathBuf,
859 virtio_features: u64,
860 ) -> Result<Input<SocketEventSource<T>>>
861 where
862 T: Read + Write + AsRawDescriptor + Send + 'static,
863 {
864 let config = parse_input_config_file(&input_config_path, idx)?;
865
866 Ok(Input {
867 worker_thread: None,
868 config: defaults::new_custom_config(
869 idx,
870 &config.name,
871 &config.serial_name,
872 config.properties,
873 config.supported_events,
874 config.axis_info,
875 ),
876 source: Some(SocketEventSource::new(source)),
877 virtio_features,
878 })
879 }
880
881 #[derive(Debug, Deserialize)]
882 struct InputConfigFile {
883 name: Option<String>,
884 serial_name: Option<String>,
885 #[serde(default)]
886 properties: BTreeMap<String, u16>,
887 events: Vec<InputConfigFileEvent>,
888 #[serde(default)]
889 axis_info: Vec<InputConfigFileAbsInfo>,
890 }
891
892 #[derive(Debug, Deserialize)]
893 struct InputConfigFileEvent {
894 event_type: String,
895 event_type_code: u16,
896 supported_events: BTreeMap<String, u16>,
897 }
898
899 #[derive(Debug, Deserialize)]
900 struct InputConfigFileAbsInfo {
901 #[allow(dead_code)]
902 axis: String,
903 axis_code: u16,
904 min: u32,
905 max: u32,
906 #[serde(default)]
907 fuzz: u32,
908 #[serde(default)]
909 flat: u32,
910 }
911
912 struct CustomInputConfig {
913 name: String,
914 serial_name: String,
915 properties: virtio_input_bitmap,
916 supported_events: BTreeMap<u16, virtio_input_bitmap>,
917 axis_info: BTreeMap<u16, virtio_input_absinfo>,
918 }
919
920 // Read and parse input event config file to input device bitmaps. If parsing is successful, this
921 // function returns a CustomInputConfig. The field in CustomInputConfig are corresponding to the
922 // same field in struct VirtioInputConfig.
parse_input_config_file(config_path: &PathBuf, device_idx: u32) -> Result<CustomInputConfig>923 fn parse_input_config_file(config_path: &PathBuf, device_idx: u32) -> Result<CustomInputConfig> {
924 let mut supported_events: BTreeMap<u16, virtio_input_bitmap> = BTreeMap::new();
925
926 // Read the json file to String
927 let contents = fs::read_to_string(config_path).map_err(|e| {
928 InputError::ParseEventConfigError(format!(
929 "Failed to read input event config from {}: {}",
930 config_path.display(),
931 e
932 ))
933 })?;
934
935 // Parse the string into a JSON object
936 let config_file: InputConfigFile = serde_json::from_str(contents.as_str()).map_err(|e| {
937 InputError::ParseEventConfigError(format!("Failed to parse json string: {}", e))
938 })?;
939 // Parse the supported events
940 for event in config_file.events {
941 let bitmap = bitmap_from_map(&event.supported_events).map_err(|e| {
942 InputError::ParseEventConfigError(format!(
943 "The config file's {} event can't be parsed: {:?}",
944 config_path.display(),
945 e
946 ))
947 })?;
948 if supported_events
949 .insert(event.event_type_code, bitmap)
950 .is_some()
951 {
952 return Err(InputError::ParseEventConfigError(format!(
953 "The {} event has been repeatedly defined by {}",
954 event.event_type,
955 config_path.display()
956 )));
957 }
958 info!(
959 "{} event is defined by {} for input device id {}",
960 event.event_type,
961 config_path.display(),
962 device_idx
963 );
964 }
965
966 let properties = bitmap_from_map(&config_file.properties).map_err(|e| {
967 InputError::ParseEventConfigError(format!("Unable to parse device properties: {:?}", e))
968 })?;
969
970 let axis_info: BTreeMap<u16, virtio_input_absinfo> = config_file
971 .axis_info
972 .iter()
973 .map(|a| {
974 (
975 a.axis_code,
976 virtio_input_absinfo::new(a.min, a.max, a.fuzz, a.flat),
977 )
978 })
979 .collect();
980
981 let name = config_file
982 .name
983 .unwrap_or_else(|| "Crosvm Virtio Custom".to_string());
984 let serial_name = config_file
985 .serial_name
986 .unwrap_or_else(|| "virtio-custom".to_string());
987
988 Ok(CustomInputConfig {
989 name,
990 serial_name,
991 properties,
992 supported_events,
993 axis_info,
994 })
995 }
996
bitmap_from_map(map: &BTreeMap<String, u16>) -> Result<virtio_input_bitmap>997 fn bitmap_from_map(map: &BTreeMap<String, u16>) -> Result<virtio_input_bitmap> {
998 let mut bitmap_idx: Vec<u16> = Vec::new();
999 for (key, &value) in map {
1000 if value >= 1024 {
1001 return Err(InputError::ParseEventConfigError(format!(
1002 "Value exceeds bitmap bounds: {} ({})",
1003 value, key
1004 )));
1005 }
1006 bitmap_idx.push(value);
1007 }
1008 Ok(virtio_input_bitmap::from_bits(&bitmap_idx))
1009 }
1010
1011 #[cfg(test)]
1012 mod tests {
1013 use defaults::new_keyboard_config;
1014 use defaults::new_multi_touch_config;
1015 use linux_input_sys::constants::ABS_MT_POSITION_X;
1016 use linux_input_sys::constants::ABS_MT_POSITION_Y;
1017 use linux_input_sys::constants::ABS_MT_SLOT;
1018 use linux_input_sys::constants::ABS_MT_TRACKING_ID;
1019 use linux_input_sys::constants::ABS_X;
1020 use linux_input_sys::constants::ABS_Y;
1021 use linux_input_sys::constants::BTN_TOUCH;
1022 use linux_input_sys::constants::EV_ABS;
1023 use linux_input_sys::constants::EV_KEY;
1024 use linux_input_sys::constants::EV_LED;
1025 use linux_input_sys::constants::EV_REP;
1026 use linux_input_sys::constants::INPUT_PROP_DIRECT;
1027 use tempfile::TempDir;
1028
1029 use super::*;
1030 #[test]
parse_keyboard_like_input_config_file_success()1031 fn parse_keyboard_like_input_config_file_success() {
1032 // Create a sample JSON file for testing
1033 let temp_file = TempDir::new().unwrap();
1034 let path = temp_file.path().join("test.json");
1035 let test_json = r#"
1036 {
1037 "name": "Virtio Custom Test",
1038 "serial_name": "virtio-custom-test",
1039 "events": [
1040 {
1041 "event_type": "EV_KEY",
1042 "event_type_code": 1,
1043 "supported_events": {
1044 "KEY_ESC": 1,
1045 "KEY_1": 2,
1046 "KEY_2": 3,
1047 "KEY_A": 30,
1048 "KEY_B": 48,
1049 "KEY_SPACE": 57
1050 }
1051 },
1052 {
1053 "event_type": "EV_REP",
1054 "event_type_code": 20,
1055 "supported_events": {
1056 "REP_DELAY": 0,
1057 "REP_PERIOD": 1
1058 }
1059 },
1060 {
1061 "event_type": "EV_LED",
1062 "event_type_code": 17,
1063 "supported_events": {
1064 "LED_NUML": 0,
1065 "LED_CAPSL": 1,
1066 "LED_SCROLLL": 2
1067 }
1068 }
1069 ]
1070 }"#;
1071 fs::write(&path, test_json).expect("Unable to write test file");
1072
1073 // Call the function and assert the result
1074 let result = parse_input_config_file(&path, 0);
1075 assert!(result.is_ok());
1076
1077 let supported_event = result.unwrap().supported_events;
1078 // EV_KEY type
1079 let ev_key_events = supported_event.get(&EV_KEY);
1080 assert!(ev_key_events.is_some());
1081 let ev_key_bitmap = ev_key_events.unwrap();
1082 let expected_ev_key_bitmap = &virtio_input_bitmap::from_bits(&[1, 2, 3, 30, 48, 57]);
1083 assert_eq!(ev_key_bitmap, expected_ev_key_bitmap);
1084 // EV_REP type
1085 let ev_rep_events = supported_event.get(&EV_REP);
1086 assert!(ev_rep_events.is_some());
1087 let ev_rep_bitmap = ev_rep_events.unwrap();
1088 let expected_ev_rep_bitmap = &virtio_input_bitmap::from_bits(&[0, 1]);
1089 assert_eq!(ev_rep_bitmap, expected_ev_rep_bitmap);
1090 // EV_LED type
1091 let ev_led_events = supported_event.get(&EV_LED);
1092 assert!(ev_led_events.is_some());
1093 let ev_led_bitmap = ev_led_events.unwrap();
1094 let expected_ev_led_bitmap = &virtio_input_bitmap::from_bits(&[0, 1, 2]);
1095 assert_eq!(ev_led_bitmap, expected_ev_led_bitmap);
1096 }
1097
1098 // Test the example custom keyboard config file
1099 // (tests/data/input/example_custom_keyboard_config.json) provides the same supported events as
1100 // default keyboard's supported events.
1101 #[test]
example_custom_keyboard_config_file_events_eq_default_keyboard_events()1102 fn example_custom_keyboard_config_file_events_eq_default_keyboard_events() {
1103 let temp_file = TempDir::new().unwrap();
1104 let path = temp_file.path().join("test.json");
1105 let test_json =
1106 include_str!("../../../tests/data/input/example_custom_keyboard_config.json");
1107 fs::write(&path, test_json).expect("Unable to write test file");
1108
1109 let keyboard_supported_events = new_keyboard_config(0).supported_events;
1110 let custom_supported_events = parse_input_config_file(&path, 0).unwrap().supported_events;
1111
1112 assert_eq!(keyboard_supported_events, custom_supported_events);
1113 }
1114
1115 #[test]
parse_touchscreen_like_input_config_file_success()1116 fn parse_touchscreen_like_input_config_file_success() {
1117 // Create a sample JSON file for testing
1118 let temp_file = TempDir::new().unwrap();
1119 let path = temp_file.path().join("touchscreen.json");
1120 let test_json = r#"
1121 {
1122 "name": "Virtio Custom Test",
1123 "serial_name": "virtio-custom-test",
1124 "properties": {"INPUT_PROP_DIRECT": 1},
1125 "events": [
1126 {
1127 "event_type": "EV_KEY",
1128 "event_type_code": 1,
1129 "supported_events": {
1130 "BTN_TOUCH": 330
1131 }
1132 }, {
1133 "event_type": "EV_ABS",
1134 "event_type_code": 3,
1135 "supported_events": {
1136 "ABS_MT_SLOT": 47,
1137 "ABS_MT_TRACKING_ID": 57,
1138 "ABS_MT_POSITION_X": 53,
1139 "ABS_MT_POSITION_Y": 54,
1140 "ABS_X": 0,
1141 "ABS_Y": 1
1142 }
1143 }
1144 ],
1145 "axis_info": [
1146 {
1147 "axis": "ABS_MT_SLOT",
1148 "axis_code": 47,
1149 "min": 0,
1150 "max": 10,
1151 "fuzz": 0,
1152 "flat": 0
1153 }, {
1154 "axis": "ABS_MT_TRACKING_ID",
1155 "axis_code": 57,
1156 "min": 0,
1157 "max": 10,
1158 "fuzz": 0,
1159 "flat": 0
1160 }, {
1161 "axis": "ABS_MT_POSITION_X",
1162 "axis_code": 53,
1163 "min": 0,
1164 "max": 720,
1165 "fuzz": 0,
1166 "flat": 0
1167 }, {
1168 "axis": "ABS_MT_POSITION_Y",
1169 "axis_code": 54,
1170 "min": 0,
1171 "max": 1280,
1172 "fuzz": 0,
1173 "flat": 0
1174 }, {
1175 "axis": "ABS_X",
1176 "axis_code": 0,
1177 "min": 0,
1178 "max": 720,
1179 "fuzz": 0,
1180 "flat": 0
1181 }, {
1182 "axis": "ABS_Y",
1183 "axis_code": 1,
1184 "min": 0,
1185 "max": 1280,
1186 "fuzz": 0,
1187 "flat": 0
1188 }
1189 ]
1190 }"#;
1191
1192 fs::write(&path, test_json).expect("Unable to write test file");
1193
1194 // Call the function and assert the result
1195 let config = parse_input_config_file(&path, 0).expect("failed to parse config");
1196
1197 let properties = &config.properties;
1198 let expected_properties = virtio_input_bitmap::from_bits(&[INPUT_PROP_DIRECT]);
1199 assert_eq!(properties, &expected_properties);
1200
1201 let supported_events = &config.supported_events;
1202
1203 // EV_KEY type
1204 let ev_key_events = supported_events.get(&EV_KEY);
1205 assert!(ev_key_events.is_some());
1206 let ev_key_bitmap = ev_key_events.unwrap();
1207 let expected_ev_key_bitmap = virtio_input_bitmap::from_bits(&[BTN_TOUCH]);
1208 assert_eq!(ev_key_bitmap, &expected_ev_key_bitmap);
1209
1210 // EV_ABS type
1211 let ev_abs_events = supported_events.get(&EV_ABS);
1212 assert!(ev_abs_events.is_some());
1213 let ev_abs_bitmap = ev_abs_events.unwrap();
1214 let expected_ev_abs_bitmap = virtio_input_bitmap::from_bits(&[
1215 ABS_MT_SLOT,
1216 ABS_MT_TRACKING_ID,
1217 ABS_MT_POSITION_X,
1218 ABS_MT_POSITION_Y,
1219 ABS_X,
1220 ABS_Y,
1221 ]);
1222 assert_eq!(ev_abs_bitmap, &expected_ev_abs_bitmap);
1223
1224 let axis_info = &config.axis_info;
1225 let slot_opt = axis_info.get(&ABS_MT_SLOT);
1226 assert!(slot_opt.is_some());
1227 let slot_info = slot_opt.unwrap();
1228 let expected_slot_info = virtio_input_absinfo::new(0, 10, 0, 0);
1229 assert_eq!(slot_info, &expected_slot_info);
1230
1231 let axis_info = &config.axis_info;
1232 let tracking_id_opt = axis_info.get(&ABS_MT_TRACKING_ID);
1233 assert!(tracking_id_opt.is_some());
1234 let tracking_id_info = tracking_id_opt.unwrap();
1235 let expected_tracking_id_info = virtio_input_absinfo::new(0, 10, 0, 0);
1236 assert_eq!(tracking_id_info, &expected_tracking_id_info);
1237
1238 let axis_info = &config.axis_info;
1239 let position_x_opt = axis_info.get(&ABS_MT_POSITION_X);
1240 assert!(position_x_opt.is_some());
1241 let position_x_info = position_x_opt.unwrap();
1242 let expected_position_x_info = virtio_input_absinfo::new(0, 720, 0, 0);
1243 assert_eq!(position_x_info, &expected_position_x_info);
1244
1245 let axis_info = &config.axis_info;
1246 let position_y_opt = axis_info.get(&ABS_MT_POSITION_Y);
1247 assert!(position_y_opt.is_some());
1248 let position_y_info = position_y_opt.unwrap();
1249 let expected_position_y_info = virtio_input_absinfo::new(0, 1280, 0, 0);
1250 assert_eq!(position_y_info, &expected_position_y_info);
1251
1252 let axis_info = &config.axis_info;
1253 let x_opt = axis_info.get(&ABS_X);
1254 assert!(x_opt.is_some());
1255 let x_info = x_opt.unwrap();
1256 let expected_x_info = virtio_input_absinfo::new(0, 720, 0, 0);
1257 assert_eq!(x_info, &expected_x_info);
1258
1259 let axis_info = &config.axis_info;
1260 let y_opt = axis_info.get(&ABS_Y);
1261 assert!(y_opt.is_some());
1262 let y_info = y_opt.unwrap();
1263 let expected_y_info = virtio_input_absinfo::new(0, 1280, 0, 0);
1264 assert_eq!(y_info, &expected_y_info);
1265 }
1266
1267 // Test the example custom touchscreen config file
1268 // (tests/data/input/example_custom_multitouchscreen_config.json) provides the same
1269 // configuration as the default multi touch screen.
1270 #[test]
example_custom_touchscreen_config_file_events_eq_default_multitouchscreen_events()1271 fn example_custom_touchscreen_config_file_events_eq_default_multitouchscreen_events() {
1272 let temp_file = TempDir::new().unwrap();
1273 let path = temp_file.path().join("test.json");
1274 let test_json =
1275 include_str!("../../../tests/data/input/example_custom_multitouchscreen_config.json");
1276 fs::write(&path, test_json).expect("Unable to write test file");
1277
1278 let default_config = new_multi_touch_config(0, 720, 1280, None);
1279 let custom_config = parse_input_config_file(&path, 0).expect("Failed to parse JSON file");
1280
1281 assert_eq!(
1282 default_config.supported_events,
1283 custom_config.supported_events
1284 );
1285 assert_eq!(default_config.properties, custom_config.properties);
1286 assert_eq!(default_config.axis_info, custom_config.axis_info);
1287 }
1288 }
1289