devices/virtio/input/
mod.rs

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)]
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    // 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
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                // 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
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// virtio_input_config_select is the prefix of virtio_input_config consisting of only the writable
228// fields (select and subsel), which multiplex the rest of the (read-only) config data.
229#[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    // Creates a bitmap from an array of bit indices
256    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                // This would only happen if new event codes (or types, or ABS_*, etc) are defined
265                // to be larger than or equal to 1024, in which case a new version
266                // of the virtio input protocol needs to be defined.
267                // There is nothing we can do about this error except log it.
268                error!("Attempted to set an out of bounds bit: {}", idx);
269            }
270        }
271        ret
272    }
273
274    // Returns the length of the minimum array that can hold all set bits in the map
275    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                // zero is a special case: return all supported event types (just like EVIOCGBIT)
340                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                } // else all zeroes in the payload
354            }
355            VIRTIO_INPUT_CFG_ID_DEVIDS => {
356                cfg.set_device_ids(&self.device_ids);
357            }
358            VIRTIO_INPUT_CFG_UNSET => {
359                // Per the virtio spec at https://docs.oasis-open.org/virtio/virtio/v1.1/cs01/virtio-v1.1-cs01.html#x1-3390008,
360                // there is no action required of us when this is set. It's unclear whether we
361                // should be zeroing the virtio_input_config, but empirically we know that the
362                // existing behavior of doing nothing works with the Linux virtio-input frontend.
363            }
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    // Fills a virtqueue with events from the source.  Returns the number of bytes written.
381    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    // Send events from the source to the guest
399    fn send_events(&mut self) -> bool {
400        let mut needs_interrupt = false;
401
402        // Only consume from the queue iterator if we know we have events to send
403        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    // Sends events from the guest to the source.
430    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 error! and early return anywhere in function
454    #[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
544/// Virtio input device
545pub 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/// Snapshot of [Input]'s state.
556#[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
710/// Creates a new virtio input device from an event device node
711pub 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
722/// Creates a new virtio touch device which supports single touch only.
723pub 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
741/// Creates a new virtio touch device which supports multi touch.
742pub 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
760/// Creates a new virtio trackpad device which supports (single) touch, primary and secondary
761/// buttons as well as X and Y axis.
762pub 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
780/// Creates a new virtio trackpad device which supports multi touch, primary and secondary
781/// buttons as well as X and Y axis.
782pub 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
800/// Creates a new virtio mouse which supports primary, secondary, wheel and REL events.
801pub 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
816/// Creates a new virtio keyboard, which supports the same events as an en-us physical keyboard.
817pub 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
832/// Creates a new virtio device for switches.
833pub 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
848/// Creates a new virtio device for rotary.
849pub 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
864/// Creates a new custom virtio input device
865pub 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
929// Read and parse input event config file to input device bitmaps. If parsing is successful, this
930// function returns a CustomInputConfig. The field in CustomInputConfig are corresponding to the
931// same field in struct VirtioInputConfig.
932fn 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    // Read the json file to String
936    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    // Parse the string into a JSON object
945    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    // Parse the supported events
949    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        // Create a sample JSON file for testing
1041        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        // Call the function and assert the result
1082        let result = parse_input_config_file(&path, 0);
1083        assert!(result.is_ok());
1084
1085        let supported_event = result.unwrap().supported_events;
1086        // EV_KEY type
1087        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        // EV_REP type
1093        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        // EV_LED type
1099        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 the example custom keyboard config file
1107    // (tests/data/input/example_custom_keyboard_config.json) provides the same supported events as
1108    // default keyboard's supported events.
1109    #[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        // Create a sample JSON file for testing
1126        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        // Call the function and assert the result
1203        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        // EV_KEY type
1212        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        // EV_ABS type
1219        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 the example custom touchscreen config file
1276    // (tests/data/input/example_custom_multitouchscreen_config.json) provides the same
1277    // configuration as the default multi touch screen.
1278    #[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}