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