Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/virtio/input/mod.rs
5394 views
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 {
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)]
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 {
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)]
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 {
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)]
231
struct virtio_input_config_select {
232
select: u8,
233
subsel: u8,
234
}
235
236
#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
237
#[repr(C)]
238
pub 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
246
impl 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)]
284
pub 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
293
impl 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
372
struct Worker<T: EventSource> {
373
event_source: T,
374
event_queue: Queue,
375
status_queue: Queue,
376
name: String,
377
}
378
379
impl<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
545
pub 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)]
557
struct InputSnapshot {
558
config_select: u8,
559
config_subsel: u8,
560
virtio_features: u64,
561
}
562
563
impl<T> VirtioDevice for Input<T>
564
where
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
690
impl<T> Input<T>
691
where
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
711
pub fn new_evdev<T>(source: T, virtio_features: u64) -> Result<Input<EvdevEventSource<T>>>
712
where
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.
723
pub 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>>>
731
where
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.
742
pub 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>>>
750
where
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.
762
pub 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>>>
770
where
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.
782
pub 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>>>
790
where
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.
801
pub fn new_mouse<T>(
802
idx: u32,
803
source: T,
804
virtio_features: u64,
805
) -> Result<Input<SocketEventSource<T>>>
806
where
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.
817
pub fn new_keyboard<T>(
818
idx: u32,
819
source: T,
820
virtio_features: u64,
821
) -> Result<Input<SocketEventSource<T>>>
822
where
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.
833
pub fn new_switches<T>(
834
idx: u32,
835
source: T,
836
virtio_features: u64,
837
) -> Result<Input<SocketEventSource<T>>>
838
where
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.
849
pub fn new_rotary<T>(
850
idx: u32,
851
source: T,
852
virtio_features: u64,
853
) -> Result<Input<SocketEventSource<T>>>
854
where
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
865
pub fn new_custom<T>(
866
idx: u32,
867
source: T,
868
input_config_path: PathBuf,
869
virtio_features: u64,
870
) -> Result<Input<SocketEventSource<T>>>
871
where
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)]
891
struct 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)]
902
struct InputConfigFileEvent {
903
event_type: String,
904
event_type_code: u16,
905
supported_events: BTreeMap<String, u16>,
906
}
907
908
#[derive(Debug, Deserialize)]
909
struct 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
921
struct 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.
932
fn 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
1006
fn 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)]
1020
mod 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
}
1297
1298