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