• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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