summary refs log tree commit diff
path: root/devices/src/virtio/input/event_source.rs
diff options
context:
space:
mode:
Diffstat (limited to 'devices/src/virtio/input/event_source.rs')
-rw-r--r--devices/src/virtio/input/event_source.rs134
1 files changed, 50 insertions, 84 deletions
diff --git a/devices/src/virtio/input/event_source.rs b/devices/src/virtio/input/event_source.rs
index d190e18..392c121 100644
--- a/devices/src/virtio/input/event_source.rs
+++ b/devices/src/virtio/input/event_source.rs
@@ -4,32 +4,15 @@
 
 use super::constants::*;
 use super::evdev::{grab_evdev, ungrab_evdev};
-use super::virtio_input_event;
 use super::InputError;
 use super::Result;
 use data_model::DataInit;
-use linux_input_sys::input_event;
+use linux_input_sys::{input_event, virtio_input_event, InputEventDecoder};
 use std::collections::VecDeque;
 use std::io::Read;
 use std::io::Write;
-use std::mem::size_of;
 use std::os::unix::io::{AsRawFd, RawFd};
-use sys_util::{error, warn};
-
-trait ConvertFromVirtioInputEvent {
-    fn from_virtio_input_event(other: &virtio_input_event) -> input_event;
-}
-
-impl ConvertFromVirtioInputEvent for input_event {
-    fn from_virtio_input_event(other: &virtio_input_event) -> input_event {
-        input_event {
-            timestamp_fields: [0, 0],
-            type_: other.type_.into(),
-            code: other.code.into(),
-            value: other.value.into(),
-        }
-    }
-}
+use sys_util::warn;
 
 /// Encapsulates a socket or device node into an abstract event source, providing a common
 /// interface.
@@ -58,21 +41,11 @@ pub trait EventSource: AsRawFd {
     fn send_event(&mut self, vio_evt: &virtio_input_event) -> Result<()>;
 }
 
-// Try to read 16 events at a time to match what the linux guest driver does.
-const READ_BUFFER_SIZE: usize = 16 * size_of::<input_event>();
-
-// The read buffer needs to be aligned to the alignment of input_event, which is aligned as u64
-#[repr(align(8))]
-pub struct ReadBuffer {
-    buffer: [u8; READ_BUFFER_SIZE],
-}
-
 /// Encapsulates implementation details common to all kinds of event sources.
 pub struct EventSourceImpl<T> {
     source: T,
     queue: VecDeque<virtio_input_event>,
-    read_buffer: ReadBuffer,
-    // The read index accounts for incomplete events read previously.
+    read_buffer: Vec<u8>,
     read_idx: usize,
 }
 
@@ -86,38 +59,19 @@ impl<T> EventSourceImpl<T>
 where
     T: Read + Write,
 {
-    // Receive events from the source and store them in a queue, unless they should be filtered out.
-    fn receive_events<F: Fn(&input_event) -> bool>(&mut self, event_filter: F) -> Result<usize> {
+    // Receive events from the source and store them in a queue.
+    fn receive_events<E: InputEventDecoder>(&mut self) -> Result<usize> {
         let read = self
             .source
-            .read(&mut self.read_buffer.buffer[self.read_idx..])
+            .read(&mut self.read_buffer[self.read_idx..])
             .map_err(InputError::EventsReadError)?;
         let buff_size = read + self.read_idx;
 
-        for evt_slice in self.read_buffer.buffer[..buff_size].chunks_exact(input_event::EVENT_SIZE)
-        {
-            let input_evt = match input_event::from_slice(evt_slice) {
-                Some(x) => x,
-                None => {
-                    // This shouldn't happen because all slices (even the last one) are guaranteed
-                    // to have the correct size and be properly aligned.
-                    error!(
-                        "Failed converting a slice of sice {} to input_event",
-                        evt_slice.len()
-                    );
-                    // Skipping the event here effectively means no events will be received, because
-                    // if from_slice fails once it will fail always.
-                    continue;
-                }
-            };
-            if !event_filter(&input_evt) {
-                continue;
-            }
-            let vio_evt = virtio_input_event::from_input_event(input_evt);
-            self.queue.push_back(vio_evt);
+        for evt_slice in self.read_buffer[..buff_size].chunks_exact(E::SIZE) {
+            self.queue.push_back(E::decode(evt_slice));
         }
 
-        let remainder = buff_size % input_event::EVENT_SIZE;
+        let remainder = buff_size % E::SIZE;
         // If there is an incomplete event at the end of the buffer, it needs to be moved to the
         // beginning and the next read operation must write right after it.
         if remainder != 0 {
@@ -125,13 +79,13 @@ where
             // The copy should only happen if there is at least one complete event in the buffer,
             // otherwise source and destination would be the same.
             if buff_size != remainder {
-                let (des, src) = self.read_buffer.buffer.split_at_mut(buff_size - remainder);
+                let (des, src) = self.read_buffer.split_at_mut(buff_size - remainder);
                 des[..remainder].copy_from_slice(&src[..remainder]);
             }
         }
         self.read_idx = remainder;
 
-        let received_events = buff_size / input_event::EVENT_SIZE;
+        let received_events = buff_size / E::SIZE;
 
         Ok(received_events)
     }
@@ -144,32 +98,42 @@ where
         self.queue.pop_front()
     }
 
-    fn send_event(&mut self, vio_evt: &virtio_input_event) -> Result<()> {
-        let evt = input_event::from_virtio_input_event(vio_evt);
+    fn send_event(&mut self, vio_evt: &virtio_input_event, encoding: EventType) -> Result<()> {
         // Miscellaneous events produced by the device are sent back to it by the kernel input
         // subsystem, but because these events are handled by the host kernel as well as the
         // guest the device would get them twice. Which would prompt the device to send the
         // event to the guest again entering an infinite loop.
-        if evt.type_ != EV_MSC {
+        if vio_evt.type_ != EV_MSC {
+            let evt;
+            let event_bytes = match encoding {
+                EventType::InputEvent => {
+                    evt = input_event::from_virtio_input_event(vio_evt);
+                    evt.as_slice()
+                }
+                EventType::VirtioInputEvent => vio_evt.as_slice(),
+            };
             self.source
-                .write_all(evt.as_slice())
+                .write_all(event_bytes)
                 .map_err(InputError::EventsWriteError)?;
         }
         Ok(())
     }
 
-    fn new(source: T) -> EventSourceImpl<T> {
+    fn new(source: T, capacity: usize) -> EventSourceImpl<T> {
         EventSourceImpl {
             source,
             queue: VecDeque::new(),
-            read_buffer: ReadBuffer {
-                buffer: [0u8; READ_BUFFER_SIZE],
-            },
+            read_buffer: vec![0; capacity],
             read_idx: 0,
         }
     }
 }
 
+enum EventType {
+    VirtioInputEvent,
+    InputEvent,
+}
+
 /// Encapsulates a (unix) socket as an event source.
 pub struct SocketEventSource<T> {
     evt_source_impl: EventSourceImpl<T>,
@@ -181,7 +145,7 @@ where
 {
     pub fn new(source: T) -> SocketEventSource<T> {
         SocketEventSource {
-            evt_source_impl: EventSourceImpl::new(source),
+            evt_source_impl: EventSourceImpl::new(source, 16 * virtio_input_event::SIZE),
         }
     }
 }
@@ -205,7 +169,7 @@ where
     }
 
     fn receive_events(&mut self) -> Result<usize> {
-        self.evt_source_impl.receive_events(|_evt| true)
+        self.evt_source_impl.receive_events::<virtio_input_event>()
     }
 
     fn available_events_count(&self) -> usize {
@@ -217,7 +181,8 @@ where
     }
 
     fn send_event(&mut self, vio_evt: &virtio_input_event) -> Result<()> {
-        self.evt_source_impl.send_event(vio_evt)
+        self.evt_source_impl
+            .send_event(vio_evt, EventType::VirtioInputEvent)
     }
 }
 
@@ -232,7 +197,7 @@ where
 {
     pub fn new(source: T) -> EvdevEventSource<T> {
         EvdevEventSource {
-            evt_source_impl: EventSourceImpl::new(source),
+            evt_source_impl: EventSourceImpl::new(source, 16 * input_event::SIZE),
         }
     }
 }
@@ -256,7 +221,7 @@ where
     }
 
     fn receive_events(&mut self) -> Result<usize> {
-        self.evt_source_impl.receive_events(|_evt| true)
+        self.evt_source_impl.receive_events::<input_event>()
     }
 
     fn available_events_count(&self) -> usize {
@@ -268,19 +233,20 @@ where
     }
 
     fn send_event(&mut self, vio_evt: &virtio_input_event) -> Result<()> {
-        self.evt_source_impl.send_event(vio_evt)
+        self.evt_source_impl
+            .send_event(vio_evt, EventType::InputEvent)
     }
 }
 
 #[cfg(test)]
 mod tests {
-    use crate::virtio::input::event_source::input_event;
-    use crate::virtio::input::event_source::EventSourceImpl;
-    use crate::virtio::input::virtio_input_event;
-    use data_model::{DataInit, Le16, Le32};
     use std::cmp::min;
-    use std::io::Read;
-    use std::io::Write;
+    use std::io::{Read, Write};
+
+    use data_model::{DataInit, Le16, Le32};
+    use linux_input_sys::InputEventDecoder;
+
+    use crate::virtio::input::event_source::{input_event, virtio_input_event, EventSourceImpl};
 
     struct SourceMock {
         events: Vec<u8>,
@@ -317,7 +283,7 @@ mod tests {
 
     #[test]
     fn empty_new() {
-        let mut source = EventSourceImpl::new(SourceMock::new(&vec![]));
+        let mut source = EventSourceImpl::new(SourceMock::new(&vec![]), 128);
         assert_eq!(
             source.available_events(),
             0,
@@ -332,9 +298,9 @@ mod tests {
 
     #[test]
     fn empty_receive() {
-        let mut source = EventSourceImpl::new(SourceMock::new(&vec![]));
+        let mut source = EventSourceImpl::new(SourceMock::new(&vec![]), 128);
         assert_eq!(
-            source.receive_events(|_| true).unwrap(),
+            source.receive_events::<input_event>().unwrap(),
             0,
             "zero events should be received"
         );
@@ -367,9 +333,9 @@ mod tests {
     #[test]
     fn partial_pop() {
         let evts = instantiate_input_events(4usize);
-        let mut source = EventSourceImpl::new(SourceMock::new(&evts));
+        let mut source = EventSourceImpl::new(SourceMock::new(&evts), input_event::SIZE * 4);
         assert_eq!(
-            source.receive_events(|_| true).unwrap(),
+            source.receive_events::<input_event>().unwrap(),
             evts.len(),
             "should receive all events"
         );
@@ -383,9 +349,9 @@ mod tests {
     fn total_pop() {
         const EVENT_COUNT: usize = 4;
         let evts = instantiate_input_events(EVENT_COUNT);
-        let mut source = EventSourceImpl::new(SourceMock::new(&evts));
+        let mut source = EventSourceImpl::new(SourceMock::new(&evts), input_event::SIZE * 4);
         assert_eq!(
-            source.receive_events(|_| true).unwrap(),
+            source.receive_events::<input_event>().unwrap(),
             evts.len(),
             "should receive all events"
         );