summary refs log tree commit diff
path: root/devices/src/virtio/input/mod.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 /devices/src/virtio/input/mod.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 'devices/src/virtio/input/mod.rs')
-rw-r--r--devices/src/virtio/input/mod.rs702
1 files changed, 702 insertions, 0 deletions
diff --git a/devices/src/virtio/input/mod.rs b/devices/src/virtio/input/mod.rs
new file mode 100644
index 0000000..82c15c0
--- /dev/null
+++ b/devices/src/virtio/input/mod.rs
@@ -0,0 +1,702 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#[allow(dead_code)]
+mod constants;
+mod defaults;
+mod evdev;
+mod event_source;
+
+use self::constants::*;
+
+use std::os::unix::io::{AsRawFd, RawFd};
+
+use data_model::{DataInit, Le16, Le32};
+use sys_util::{EventFd, GuestMemory, PollContext, PollToken};
+
+use self::event_source::{input_event, EvdevEventSource, EventSource, SocketEventSource};
+use super::{Queue, VirtioDevice, INTERRUPT_STATUS_USED_RING, TYPE_INPUT};
+use std::cmp::min;
+use std::collections::BTreeMap;
+use std::io::Read;
+use std::io::Write;
+use std::mem::size_of;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::Arc;
+use std::thread;
+
+const EVENT_QUEUE_SIZE: u16 = 64;
+const STATUS_QUEUE_SIZE: u16 = 64;
+const QUEUE_SIZES: &'static [u16] = &[EVENT_QUEUE_SIZE, STATUS_QUEUE_SIZE];
+
+#[derive(Debug)]
+pub enum InputError {
+    /// Failed to write events to the source
+    EventsWriteError(sys_util::GuestMemoryError),
+    /// Failed to read events from the source
+    EventsReadError(std::io::Error),
+    // Failed to get name of event device
+    EvdevIdError(sys_util::Error),
+    // Failed to get name of event device
+    EvdevNameError(sys_util::Error),
+    // Failed to get serial name of event device
+    EvdevSerialError(sys_util::Error),
+    // Failed to get properties of event device
+    EvdevPropertiesError(sys_util::Error),
+    // Failed to get event types supported by device
+    EvdevEventTypesError(sys_util::Error),
+    // Failed to get axis information of event device
+    EvdevAbsInfoError(sys_util::Error),
+    // Failed to grab event device
+    EvdevGrabError(sys_util::Error),
+}
+pub type Result<T> = std::result::Result<T, InputError>;
+
+#[derive(Copy, Clone, Default, Debug)]
+#[repr(C)]
+pub struct virtio_input_device_ids {
+    bustype: Le16,
+    vendor: Le16,
+    product: Le16,
+    version: Le16,
+}
+
+// Safe because it only has data and has no implicit padding.
+unsafe impl DataInit for virtio_input_device_ids {}
+
+impl virtio_input_device_ids {
+    fn new(bustype: u16, product: u16, vendor: u16, version: u16) -> virtio_input_device_ids {
+        virtio_input_device_ids {
+            bustype: Le16::from(bustype),
+            vendor: Le16::from(vendor),
+            product: Le16::from(product),
+            version: Le16::from(version),
+        }
+    }
+}
+
+#[derive(Copy, Clone, Default, Debug)]
+#[repr(C)]
+pub struct virtio_input_absinfo {
+    min: Le32,
+    max: Le32,
+    fuzz: Le32,
+    flat: Le32,
+}
+
+// Safe because it only has data and has no implicit padding.
+unsafe impl DataInit for virtio_input_absinfo {}
+
+impl virtio_input_absinfo {
+    fn new(min: u32, max: u32, fuzz: u32, flat: u32) -> virtio_input_absinfo {
+        virtio_input_absinfo {
+            min: Le32::from(min),
+            max: Le32::from(max),
+            fuzz: Le32::from(fuzz),
+            flat: Le32::from(flat),
+        }
+    }
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+struct virtio_input_config {
+    select: u8,
+    subsel: u8,
+    size: u8,
+    reserved: [u8; 5],
+    payload: [u8; 128],
+}
+
+// Safe because it only has data and has no implicit padding.
+unsafe impl DataInit for virtio_input_config {}
+
+impl virtio_input_config {
+    fn new() -> virtio_input_config {
+        virtio_input_config {
+            select: 0,
+            subsel: 0,
+            size: 0,
+            reserved: [0u8; 5],
+            payload: [0u8; 128],
+        }
+    }
+
+    fn set_payload_slice(&mut self, slice: &[u8]) {
+        let bytes_written = match (&mut self.payload[..]).write(slice) {
+            Ok(x) => x,
+            Err(_) => {
+                // This won't happen because write is guaranteed to succeed with slices
+                unreachable!();
+            }
+        };
+        self.size = bytes_written as u8;
+        if bytes_written < slice.len() {
+            // This shouldn't happen since everywhere this function is called the size is guaranteed
+            // to be at most 128 bytes (the size of the payload)
+            warn!("Slice is too long to fit in payload");
+        }
+    }
+
+    fn set_payload_bitmap(&mut self, bitmap: &virtio_input_bitmap) {
+        self.size = bitmap.min_size();
+        self.payload.copy_from_slice(&bitmap.bitmap);
+    }
+
+    fn set_absinfo(&mut self, absinfo: &virtio_input_absinfo) {
+        self.set_payload_slice(absinfo.as_slice());
+    }
+
+    fn set_device_ids(&mut self, device_ids: &virtio_input_device_ids) {
+        self.set_payload_slice(device_ids.as_slice());
+    }
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct virtio_input_bitmap {
+    bitmap: [u8; 128],
+}
+
+impl virtio_input_bitmap {
+    fn new(bitmap: [u8; 128]) -> virtio_input_bitmap {
+        virtio_input_bitmap { bitmap }
+    }
+
+    fn len(&self) -> usize {
+        self.bitmap.len()
+    }
+
+    // Creates a bitmap from an array of bit indices
+    fn from_bits(set_indices: &[u16]) -> virtio_input_bitmap {
+        let mut ret = virtio_input_bitmap { bitmap: [0u8; 128] };
+        for idx in set_indices {
+            let byte_pos = (idx / 8) as usize;
+            let bit_byte = 1u8 << (idx % 8);
+            if byte_pos < ret.len() {
+                ret.bitmap[byte_pos] |= bit_byte;
+            } else {
+                // This would only happen if new event codes (or types, or ABS_*, etc) are defined to be
+                // larger than or equal to 1024, in which case a new version of the virtio input
+                // protocol needs to be defined.
+                // There is nothing we can do about this error except log it.
+                error!("Attempted to set an out of bounds bit: {}", idx);
+            }
+        }
+        ret
+    }
+
+    // Returns the length of the minimum array that can hold all set bits in the map
+    fn min_size(&self) -> u8 {
+        self.bitmap
+            .iter()
+            .rposition(|v| *v != 0)
+            .map_or(0, |i| i + 1) as u8
+    }
+}
+
+pub struct VirtioInputConfig {
+    select: u8,
+    subsel: u8,
+    device_ids: virtio_input_device_ids,
+    name: Vec<u8>,
+    serial_name: Vec<u8>,
+    properties: virtio_input_bitmap,
+    supported_events: BTreeMap<u16, virtio_input_bitmap>,
+    axis_info: BTreeMap<u16, virtio_input_absinfo>,
+}
+
+impl VirtioInputConfig {
+    const CONFIG_MEM_SIZE: usize = size_of::<virtio_input_config>();
+
+    fn new(
+        device_ids: virtio_input_device_ids,
+        name: Vec<u8>,
+        serial_name: Vec<u8>,
+        properties: virtio_input_bitmap,
+        supported_events: BTreeMap<u16, virtio_input_bitmap>,
+        axis_info: BTreeMap<u16, virtio_input_absinfo>,
+    ) -> VirtioInputConfig {
+        VirtioInputConfig {
+            select: 0,
+            subsel: 0,
+            device_ids,
+            name,
+            serial_name,
+            properties,
+            supported_events,
+            axis_info,
+        }
+    }
+
+    fn from_evdev<T: AsRawFd>(source: &T) -> Result<VirtioInputConfig> {
+        Ok(VirtioInputConfig::new(
+            evdev::device_ids(source)?,
+            evdev::name(source)?,
+            evdev::serial_name(source)?,
+            evdev::properties(source)?,
+            evdev::supported_events(source)?,
+            evdev::abs_info(source),
+        ))
+    }
+
+    fn validate_read_offsets(&self, offset: usize, len: usize) -> bool {
+        if offset + len > VirtioInputConfig::CONFIG_MEM_SIZE {
+            error!(
+                "Attempt to read from invalid config range: [{}..{}], valid ranges in [0..{}]",
+                offset,
+                offset + len,
+                VirtioInputConfig::CONFIG_MEM_SIZE
+            );
+            return false;
+        }
+        true
+    }
+
+    fn build_config_memory(&self) -> virtio_input_config {
+        let mut cfg = virtio_input_config::new();
+        cfg.select = self.select;
+        cfg.subsel = self.subsel;
+        match self.select {
+            VIRTIO_INPUT_CFG_ID_NAME => {
+                cfg.set_payload_slice(&self.name);
+            }
+            VIRTIO_INPUT_CFG_ID_SERIAL => {
+                cfg.set_payload_slice(&self.serial_name);
+            }
+            VIRTIO_INPUT_CFG_PROP_BITS => {
+                cfg.set_payload_bitmap(&self.properties);
+            }
+            VIRTIO_INPUT_CFG_EV_BITS => {
+                let ev_type = self.subsel as u16;
+                // zero is a special case: return all supported event types (just like EVIOCGBIT)
+                if ev_type == 0 {
+                    let events_bm = virtio_input_bitmap::from_bits(
+                        &self.supported_events.keys().cloned().collect::<Vec<u16>>(),
+                    );
+                    cfg.set_payload_bitmap(&events_bm);
+                } else if let Some(supported_codes) = self.supported_events.get(&ev_type) {
+                    cfg.set_payload_bitmap(&supported_codes);
+                }
+            }
+            VIRTIO_INPUT_CFG_ABS_INFO => {
+                let abs_axis = self.subsel as u16;
+                if let Some(absinfo) = self.axis_info.get(&abs_axis) {
+                    cfg.set_absinfo(absinfo);
+                } // else all zeroes in the payload
+            }
+            VIRTIO_INPUT_CFG_ID_DEVIDS => {
+                cfg.set_device_ids(&self.device_ids);
+            }
+            _ => {
+                warn!("Unsuported virtio input config selection: {}", self.select);
+            }
+        }
+        cfg
+    }
+
+    fn read(&self, offset: usize, data: &mut [u8]) {
+        let data_len = data.len();
+        if self.validate_read_offsets(offset, data_len) {
+            let config = self.build_config_memory();
+            data.clone_from_slice(&config.as_slice()[offset..offset + data_len]);
+        }
+    }
+
+    fn validate_write_offsets(&self, offset: usize, len: usize) -> bool {
+        const MAX_WRITABLE_BYTES: usize = 2;
+        if offset + len > MAX_WRITABLE_BYTES {
+            error!(
+                "Attempt to write to invalid config range: [{}..{}], valid ranges in [0..{}]",
+                offset,
+                offset + len,
+                MAX_WRITABLE_BYTES
+            );
+            return false;
+        }
+        true
+    }
+
+    fn write(&mut self, offset: usize, data: &[u8]) {
+        let len = data.len();
+        if self.validate_write_offsets(offset, len) {
+            let mut selectors: [u8; 2] = [self.select, self.subsel];
+            selectors[offset..offset + len].clone_from_slice(&data);
+            self.select = selectors[0];
+            self.subsel = selectors[1];
+        }
+    }
+}
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C)]
+struct virtio_input_event {
+    type_: Le16,
+    code: Le16,
+    value: Le32,
+}
+
+// Safe because it only has data and has no implicit padding.
+unsafe impl DataInit for virtio_input_event {}
+
+impl virtio_input_event {
+    const EVENT_SIZE: usize = size_of::<virtio_input_event>();
+    fn new(type_: u16, code: u16, value: u32) -> virtio_input_event {
+        virtio_input_event {
+            type_: Le16::from(type_),
+            code: Le16::from(code),
+            value: Le32::from(value),
+        }
+    }
+
+    fn from_input_event(other: &input_event) -> virtio_input_event {
+        virtio_input_event {
+            type_: Le16::from(other.type_),
+            code: Le16::from(other.code),
+            value: Le32::from(other.value),
+        }
+    }
+}
+
+struct Worker<T: EventSource> {
+    event_source: T,
+    event_queue: Queue,
+    status_queue: Queue,
+    guest_memory: GuestMemory,
+    interrupt_status: Arc<AtomicUsize>,
+    interrupt_evt: EventFd,
+    interrupt_resample_evt: EventFd,
+}
+
+impl<T: EventSource> Worker<T> {
+    fn signal_used_queue(&self) {
+        self.interrupt_status
+            .fetch_or(INTERRUPT_STATUS_USED_RING as usize, Ordering::SeqCst);
+        self.interrupt_evt.write(1).unwrap();
+    }
+
+    // Send events from the source to the guest
+    fn send_events(&mut self) -> bool {
+        let queue = &mut self.event_queue;
+
+        let mut used_desc_heads = [(0, 0); EVENT_QUEUE_SIZE as usize];
+        let mut used_count = 0;
+
+        // Only consume from the queue iterator if we know we have events to send
+        while self.event_source.available_events_count() > 0 {
+            let mut queue_iter = queue.iter(&self.guest_memory);
+            match queue_iter.next() {
+                None => {
+                    break;
+                }
+                Some(avail_desc) => {
+                    if !avail_desc.is_write_only() {
+                        panic!("Received a read only descriptor on event queue");
+                    }
+                    let avail_events_size =
+                        self.event_source.available_events_count() * virtio_input_event::EVENT_SIZE;
+                    let len = min(avail_desc.len as usize, avail_events_size);
+                    if let Err(e) = self.guest_memory.read_to_memory(
+                        avail_desc.addr,
+                        &mut self.event_source,
+                        len,
+                    ) {
+                        // Read is guaranteed to succeed here, so the only possible failure would be
+                        // writing outside the guest memory region, which would mean the address and
+                        // length given in the queue descriptor are wrong.
+                        panic!("failed reading events into guest memory: {:?}", e);
+                    }
+                    used_desc_heads[used_count] = (avail_desc.index, len as u32);
+                    used_count += 1;
+                }
+            }
+        }
+        for &(desc_index, len) in &used_desc_heads[..used_count] {
+            queue.add_used(&self.guest_memory, desc_index, len);
+        }
+
+        used_count > 0
+    }
+
+    fn process_status_queue(&mut self) -> Result<bool> {
+        let queue = &mut self.status_queue;
+
+        let mut used_desc_heads = [(0, 0); EVENT_QUEUE_SIZE as usize];
+        let mut used_count = 0;
+        for avail_desc in queue.iter(&self.guest_memory) {
+            if !avail_desc.is_read_only() {
+                panic!("Received a writable descriptor on status queue");
+            }
+            let len = avail_desc.len as usize;
+            if len % virtio_input_event::EVENT_SIZE != 0 {
+                warn!(
+                    "Ignoring buffer of unexpected size on status queue: {:0}",
+                    len
+                );
+            } else {
+                self.guest_memory
+                    .write_from_memory(avail_desc.addr, &mut self.event_source, len)
+                    .map_err(|e| InputError::EventsWriteError(e))?;
+            }
+
+            used_desc_heads[used_count] = (avail_desc.index, len);
+            used_count += 1;
+        }
+
+        for &(desc_index, len) in &used_desc_heads[..used_count] {
+            queue.add_used(&self.guest_memory, desc_index, len as u32);
+        }
+        Ok(used_count > 0)
+    }
+
+    fn run(
+        &mut self,
+        event_queue_evt_fd: EventFd,
+        status_queue_evt_fd: EventFd,
+        kill_evt: EventFd,
+    ) {
+        if let Err(e) = self.event_source.init() {
+            error!("failed initializing event source: {:?}", e);
+            return;
+        }
+
+        #[derive(PollToken)]
+        enum Token {
+            EventQAvailable,
+            StatusQAvailable,
+            InputEventsAvailable,
+            InterruptResample,
+            Kill,
+        }
+        let poll_ctx: PollContext<Token> = match PollContext::new()
+            .and_then(|pc| {
+                pc.add(&event_queue_evt_fd, Token::EventQAvailable)
+                    .and(Ok(pc))
+            })
+            .and_then(|pc| {
+                pc.add(&status_queue_evt_fd, Token::StatusQAvailable)
+                    .and(Ok(pc))
+            })
+            .and_then(|pc| {
+                pc.add(&self.event_source, Token::InputEventsAvailable)
+                    .and(Ok(pc))
+            })
+            .and_then(|pc| {
+                pc.add(&self.interrupt_resample_evt, Token::InterruptResample)
+                    .and(Ok(pc))
+            })
+            .and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc)))
+        {
+            Ok(poll_ctx) => poll_ctx,
+            Err(e) => {
+                error!("failed creating PollContext: {:?}", e);
+                return;
+            }
+        };
+
+        'poll: loop {
+            let poll_events = match poll_ctx.wait() {
+                Ok(poll_events) => poll_events,
+                Err(e) => {
+                    error!("failed polling for events: {:?}", e);
+                    break;
+                }
+            };
+
+            let mut needs_interrupt = false;
+            for poll_event in poll_events.iter_readable() {
+                match poll_event.token() {
+                    Token::EventQAvailable => {
+                        if let Err(e) = event_queue_evt_fd.read() {
+                            error!("failed reading event queue EventFd: {:?}", e);
+                            break 'poll;
+                        }
+                        needs_interrupt |= self.send_events();
+                    }
+                    Token::StatusQAvailable => {
+                        if let Err(e) = status_queue_evt_fd.read() {
+                            error!("failed reading status queue EventFd: {:?}", e);
+                            break 'poll;
+                        }
+                        match self.process_status_queue() {
+                            Ok(b) => needs_interrupt |= b,
+                            Err(e) => error!("failed processing status events: {:?}", e),
+                        }
+                    }
+                    Token::InputEventsAvailable => match self.event_source.receive_events() {
+                        Err(e) => error!("error receiving events: {:?}", e),
+                        Ok(_cnt) => needs_interrupt |= self.send_events(),
+                    },
+                    Token::InterruptResample => {
+                        let _ = self.interrupt_resample_evt.read();
+                        if self.interrupt_status.load(Ordering::SeqCst) != 0 {
+                            self.interrupt_evt.write(1).unwrap();
+                        }
+                    }
+                    Token::Kill => {
+                        let _ = kill_evt.read();
+                        break 'poll;
+                    }
+                }
+            }
+            if needs_interrupt {
+                self.signal_used_queue();
+            }
+        }
+
+        if let Err(e) = self.event_source.finalize() {
+            error!("failed finalizing event source: {:?}", e);
+            return;
+        }
+    }
+}
+
+/// Virtio input device
+
+pub struct Input<T: EventSource> {
+    kill_evt: Option<EventFd>,
+    config: VirtioInputConfig,
+    source: Option<T>,
+}
+
+impl<T: EventSource> Drop for Input<T> {
+    fn drop(&mut self) {
+        if let Some(kill_evt) = self.kill_evt.take() {
+            // Ignore the result because there is nothing we can do about it.
+            let _ = kill_evt.write(1);
+        }
+    }
+}
+
+impl<T> VirtioDevice for Input<T>
+where
+    T: 'static + EventSource + Send,
+{
+    fn keep_fds(&self) -> Vec<RawFd> {
+        if let Some(ref source) = self.source {
+            return vec![source.as_raw_fd()];
+        }
+        Vec::new()
+    }
+
+    fn device_type(&self) -> u32 {
+        TYPE_INPUT
+    }
+
+    fn queue_max_sizes(&self) -> &[u16] {
+        QUEUE_SIZES
+    }
+
+    fn read_config(&self, offset: u64, data: &mut [u8]) {
+        self.config.read(offset as usize, data);
+    }
+
+    fn write_config(&mut self, offset: u64, data: &[u8]) {
+        self.config.write(offset as usize, data);
+    }
+
+    fn activate(
+        &mut self,
+        mem: GuestMemory,
+        interrupt_evt: EventFd,
+        interrupt_resample_evt: EventFd,
+        status: Arc<AtomicUsize>,
+        mut queues: Vec<Queue>,
+        mut queue_evts: Vec<EventFd>,
+    ) {
+        if queues.len() != 2 || queue_evts.len() != 2 {
+            return;
+        }
+
+        let (self_kill_evt, kill_evt) = match EventFd::new().and_then(|e| Ok((e.try_clone()?, e))) {
+            Ok(v) => v,
+            Err(e) => {
+                error!("failed to create kill EventFd pair: {:?}", e);
+                return;
+            }
+        };
+        self.kill_evt = Some(self_kill_evt);
+
+        // Status is queue 1, event is queue 0
+        let status_queue = queues.remove(1);
+        let status_queue_evt_fd = queue_evts.remove(1);
+
+        let event_queue = queues.remove(0);
+        let event_queue_evt_fd = queue_evts.remove(0);
+
+        if let Some(source) = self.source.take() {
+            let worker_result = thread::Builder::new()
+                .name(String::from("virtio_input"))
+                .spawn(move || {
+                    let mut worker = Worker {
+                        event_source: source,
+                        event_queue,
+                        status_queue,
+                        guest_memory: mem,
+                        interrupt_status: status,
+                        interrupt_evt,
+                        interrupt_resample_evt,
+                    };
+                    worker.run(event_queue_evt_fd, status_queue_evt_fd, kill_evt);
+                });
+
+            if let Err(e) = worker_result {
+                error!("failed to spawn virtio_input worker: {}", e);
+                return;
+            }
+        } else {
+            error!("tried to activate device without a source for events");
+            return;
+        }
+    }
+}
+
+/// Creates a new virtio input device from an event device node
+pub fn new_evdev<T>(source: T) -> Result<Input<EvdevEventSource<T>>>
+where
+    T: Read + Write + AsRawFd,
+{
+    Ok(Input {
+        kill_evt: None,
+        config: VirtioInputConfig::from_evdev(&source)?,
+        source: Some(EvdevEventSource::new(source)),
+    })
+}
+
+/// Creates a new virtio trackpad device which supports (single) touch, primary and secondary
+/// buttons as well as X and Y axis.
+pub fn new_trackpad<T>(source: T, width: u32, height: u32) -> Result<Input<SocketEventSource<T>>>
+where
+    T: Read + Write + AsRawFd,
+{
+    Ok(Input {
+        kill_evt: None,
+        config: defaults::new_trackpad_config(width, height),
+        source: Some(SocketEventSource::new(source)),
+    })
+}
+
+/// Creates a new virtio mouse which supports primary, secondary, wheel and REL events.
+pub fn new_mouse<T>(source: T) -> Result<Input<SocketEventSource<T>>>
+where
+    T: Read + Write + AsRawFd,
+{
+    Ok(Input {
+        kill_evt: None,
+        config: defaults::new_mouse_config(),
+        source: Some(SocketEventSource::new(source)),
+    })
+}
+
+/// Creates a new virtio keyboard, which supports the same events as an en-us physical keyboard.
+pub fn new_keyboard<T>(source: T) -> Result<Input<SocketEventSource<T>>>
+where
+    T: Read + Write + AsRawFd,
+{
+    Ok(Input {
+        kill_evt: None,
+        config: defaults::new_keyboard_config(),
+        source: Some(SocketEventSource::new(source)),
+    })
+}