summary refs log tree commit diff
path: root/src/main.rs
diff options
context:
space:
mode:
authorJorge E. Moreira <jemoreira@google.com>2019-01-14 18:44:49 -0800
committerchrome-bot <chrome-bot@chromium.org>2019-02-01 06:21:08 -0800
commitdffec507fba14da82b914c9c195df324360e9e28 (patch)
tree36906570c97e639a495beb38bb8ac1f8cd6043f2 /src/main.rs
parent5329be3634547fe383aff7981854484088e6a622 (diff)
downloadcrosvm-dffec507fba14da82b914c9c195df324360e9e28.tar
crosvm-dffec507fba14da82b914c9c195df324360e9e28.tar.gz
crosvm-dffec507fba14da82b914c9c195df324360e9e28.tar.bz2
crosvm-dffec507fba14da82b914c9c195df324360e9e28.tar.lz
crosvm-dffec507fba14da82b914c9c195df324360e9e28.tar.xz
crosvm-dffec507fba14da82b914c9c195df324360e9e28.tar.zst
crosvm-dffec507fba14da82b914c9c195df324360e9e28.zip
Adds Virtio-Input device simulation
This allows decoupling input from the wayland socket while using a
standard virtio device for it. The proposed virtio input spec can be
found at
https://www.kraxel.org/virtio/virtio-v1.0-cs03-virtio-input.pdf, it
has already been implemented in qemu and (guest) kernel support exists
since version 4.1.

This change adds the following options to crosvm:
--evdev: Grabs a host device and passes it through to the guest
--<device>: Creates a default configuration for <device>,
receives the input events from a unix socket. <device> can be
'keyboard', 'mouse' or 'trackpad'.

Bug=chromium:921271
Test=booted on x86 linux and manually tried virtio-input devices
Change-Id: I8455b72c53ea2f431009ee8140799b0797775e76
Reviewed-on: https://chromium-review.googlesource.com/1412355
Commit-Ready: Jorge Moreira Broche <jemoreira@google.com>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs76
1 files changed, 76 insertions, 0 deletions
diff --git a/src/main.rs b/src/main.rs
index 9392360..8e83621 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -72,6 +72,25 @@ struct BindMount {
     writable: bool,
 }
 
+const DEFAULT_TRACKPAD_WIDTH: u32 = 800;
+const DEFAULT_TRACKPAD_HEIGHT: u32 = 1280;
+
+struct TrackpadOption {
+    path: PathBuf,
+    width: u32,
+    height: u32,
+}
+
+impl TrackpadOption {
+    fn new(path: PathBuf) -> TrackpadOption {
+        TrackpadOption {
+            path,
+            width: DEFAULT_TRACKPAD_WIDTH,
+            height: DEFAULT_TRACKPAD_HEIGHT,
+        }
+    }
+}
+
 pub struct Config {
     vcpu_count: Option<u32>,
     memory: Option<usize>,
@@ -97,6 +116,10 @@ pub struct Config {
     gpu: bool,
     cras_audio: bool,
     null_audio: bool,
+    virtio_trackpad: Option<TrackpadOption>,
+    virtio_mouse: Option<PathBuf>,
+    virtio_keyboard: Option<PathBuf>,
+    virtio_input_evdevs: Vec<PathBuf>,
 }
 
 impl Default for Config {
@@ -126,6 +149,10 @@ impl Default for Config {
             seccomp_policy_dir: PathBuf::from(SECCOMP_POLICY_DIR),
             cras_audio: false,
             null_audio: false,
+            virtio_trackpad: None,
+            virtio_mouse: None,
+            virtio_keyboard: None,
+            virtio_input_evdevs: Vec::new(),
         }
     }
 }
@@ -492,6 +519,51 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument::
         "gpu" => {
             cfg.gpu = true;
         }
+        "trackpad" => {
+            if cfg.virtio_trackpad.is_some() {
+                return Err(argument::Error::TooManyArguments(
+                    "`trackpad` already given".to_owned(),
+                ));
+            }
+            let mut it = value.unwrap().split(":");
+
+            let mut trackpad_spec =
+                TrackpadOption::new(PathBuf::from(it.next().unwrap().to_owned()));
+            if let Some(width) = it.next() {
+                trackpad_spec.width = width.trim().parse().unwrap();
+            }
+            if let Some(height) = it.next() {
+                trackpad_spec.height = height.trim().parse().unwrap();
+            }
+
+            cfg.virtio_trackpad = Some(trackpad_spec);
+        }
+        "mouse" => {
+            if cfg.virtio_mouse.is_some() {
+                return Err(argument::Error::TooManyArguments(
+                    "`mouse` already given".to_owned(),
+                ));
+            }
+            cfg.virtio_mouse = Some(PathBuf::from(value.unwrap().to_owned()));
+        }
+        "keyboard" => {
+            if cfg.virtio_keyboard.is_some() {
+                return Err(argument::Error::TooManyArguments(
+                    "`keyboard` already given".to_owned(),
+                ));
+            }
+            cfg.virtio_keyboard = Some(PathBuf::from(value.unwrap().to_owned()));
+        }
+        "evdev" => {
+            let dev_path = PathBuf::from(value.unwrap());
+            if !dev_path.exists() {
+                return Err(argument::Error::InvalidValue {
+                    value: value.unwrap().to_owned(),
+                    expected: "this input device path does not exist",
+                });
+            }
+            cfg.virtio_input_evdevs.push(dev_path);
+        }
         "help" => return Err(argument::Error::PrintHelp),
         _ => unreachable!(),
     }
@@ -551,6 +623,10 @@ fn run_vm(args: std::env::Args) -> std::result::Result<(), ()> {
                           "File descriptor for configured tap device.  Mutually exclusive with `host_ip`, `netmask`, and `mac`."),
           #[cfg(feature = "gpu")]
           Argument::flag("gpu", "(EXPERIMENTAL) enable virtio-gpu device"),
+          Argument::value("evdev", "PATH", "Path to an event device node. The device will be grabbed (unusable from the host) and made available to the guest with the same configuration it shows on the host"),
+          Argument::value("trackpad", "PATH:WIDTH:HEIGHT", "Path to a socket from where to read trackpad input events and write status updates to, optionally followed by screen width and height (defaults to 800x1280)."),
+          Argument::value("mouse", "PATH", "Path to a socket from where to read mouse input events and write status updates to."),
+          Argument::value("keyboard", "PATH", "Path to a socket from where to read keyboard input events and write status updates to."),
           Argument::short_flag('h', "help", "Print help message.")];
 
     let mut cfg = Config::default();