virtio_drivers/device/
input.rs

1//! Driver for VirtIO input devices.
2
3use super::common::Feature;
4use crate::hal::Hal;
5use crate::queue::VirtQueue;
6use crate::transport::Transport;
7use crate::volatile::{volread, volwrite, ReadOnly, VolatileReadable, WriteOnly};
8use crate::Error;
9use alloc::{boxed::Box, string::String};
10use core::cmp::min;
11use core::mem::size_of;
12use core::ptr::{addr_of, NonNull};
13use zerocopy::{AsBytes, FromBytes, FromZeroes};
14
15/// Virtual human interface devices such as keyboards, mice and tablets.
16///
17/// An instance of the virtio device represents one such input device.
18/// Device behavior mirrors that of the evdev layer in Linux,
19/// making pass-through implementations on top of evdev easy.
20pub struct VirtIOInput<H: Hal, T: Transport> {
21    transport: T,
22    event_queue: VirtQueue<H, QUEUE_SIZE>,
23    status_queue: VirtQueue<H, QUEUE_SIZE>,
24    event_buf: Box<[InputEvent; 32]>,
25    config: NonNull<Config>,
26}
27
28impl<H: Hal, T: Transport> VirtIOInput<H, T> {
29    /// Create a new VirtIO-Input driver.
30    pub fn new(mut transport: T) -> Result<Self, Error> {
31        let mut event_buf = Box::new([InputEvent::default(); QUEUE_SIZE]);
32
33        let negotiated_features = transport.begin_init(SUPPORTED_FEATURES);
34
35        let config = transport.config_space::<Config>()?;
36
37        let mut event_queue = VirtQueue::new(
38            &mut transport,
39            QUEUE_EVENT,
40            negotiated_features.contains(Feature::RING_INDIRECT_DESC),
41            negotiated_features.contains(Feature::RING_EVENT_IDX),
42        )?;
43        let status_queue = VirtQueue::new(
44            &mut transport,
45            QUEUE_STATUS,
46            negotiated_features.contains(Feature::RING_INDIRECT_DESC),
47            negotiated_features.contains(Feature::RING_EVENT_IDX),
48        )?;
49        for (i, event) in event_buf.as_mut().iter_mut().enumerate() {
50            // Safe because the buffer lasts as long as the queue.
51            let token = unsafe { event_queue.add(&[], &mut [event.as_bytes_mut()])? };
52            assert_eq!(token, i as u16);
53        }
54        if event_queue.should_notify() {
55            transport.notify(QUEUE_EVENT);
56        }
57
58        transport.finish_init();
59
60        Ok(VirtIOInput {
61            transport,
62            event_queue,
63            status_queue,
64            event_buf,
65            config,
66        })
67    }
68
69    /// Acknowledge interrupt and process events.
70    pub fn ack_interrupt(&mut self) -> bool {
71        self.transport.ack_interrupt()
72    }
73
74    /// Pop the pending event.
75    pub fn pop_pending_event(&mut self) -> Option<InputEvent> {
76        if let Some(token) = self.event_queue.peek_used() {
77            let event = &mut self.event_buf[token as usize];
78            // Safe because we are passing the same buffer as we passed to `VirtQueue::add` and it
79            // is still valid.
80            unsafe {
81                self.event_queue
82                    .pop_used(token, &[], &mut [event.as_bytes_mut()])
83                    .ok()?;
84            }
85            let event_saved = *event;
86            // requeue
87            // Safe because buffer lasts as long as the queue.
88            if let Ok(new_token) = unsafe { self.event_queue.add(&[], &mut [event.as_bytes_mut()]) }
89            {
90                // This only works because nothing happen between `pop_used` and `add` that affects
91                // the list of free descriptors in the queue, so `add` reuses the descriptor which
92                // was just freed by `pop_used`.
93                assert_eq!(new_token, token);
94                if self.event_queue.should_notify() {
95                    self.transport.notify(QUEUE_EVENT);
96                }
97                return Some(event_saved);
98            }
99        }
100        None
101    }
102
103    /// Query a specific piece of information by `select` and `subsel`, and write
104    /// result to `out`, return the result size.
105    pub fn query_config_select(
106        &mut self,
107        select: InputConfigSelect,
108        subsel: u8,
109        out: &mut [u8],
110    ) -> u8 {
111        let size;
112        // Safe because config points to a valid MMIO region for the config space.
113        unsafe {
114            volwrite!(self.config, select, select as u8);
115            volwrite!(self.config, subsel, subsel);
116            size = volread!(self.config, size);
117            let size_to_copy = min(usize::from(size), out.len());
118            for (i, out_item) in out.iter_mut().take(size_to_copy).enumerate() {
119                *out_item = addr_of!((*self.config.as_ptr()).data[i]).vread();
120            }
121        }
122        size
123    }
124
125    /// Queries a specific piece of information by `select` and `subsel`, allocates a sufficiently
126    /// large byte buffer for it, and returns it.
127    fn query_config_select_alloc(
128        &mut self,
129        select: InputConfigSelect,
130        subsel: u8,
131    ) -> Result<Box<[u8]>, Error> {
132        // Safe because config points to a valid MMIO region for the config space.
133        unsafe {
134            volwrite!(self.config, select, select as u8);
135            volwrite!(self.config, subsel, subsel);
136            let size = usize::from(volread!(self.config, size));
137            if size > CONFIG_DATA_MAX_LENGTH {
138                return Err(Error::IoError);
139            }
140            let mut buf = u8::new_box_slice_zeroed(size);
141            for i in 0..size {
142                buf[i] = addr_of!((*self.config.as_ptr()).data[i]).vread();
143            }
144            Ok(buf)
145        }
146    }
147
148    /// Queries a specific piece of information by `select` and `subsel` into a newly-allocated
149    /// buffer, and tries to convert it to a string.
150    ///
151    /// Returns an error if it is not valid UTF-8.
152    fn query_config_string(
153        &mut self,
154        select: InputConfigSelect,
155        subsel: u8,
156    ) -> Result<String, Error> {
157        Ok(String::from_utf8(
158            self.query_config_select_alloc(select, subsel)?.into(),
159        )?)
160    }
161
162    /// Queries and returns the name of the device, or an error if it is not valid UTF-8.
163    pub fn name(&mut self) -> Result<String, Error> {
164        self.query_config_string(InputConfigSelect::IdName, 0)
165    }
166
167    /// Queries and returns the serial number of the device, or an error if it is not valid UTF-8.
168    pub fn serial_number(&mut self) -> Result<String, Error> {
169        self.query_config_string(InputConfigSelect::IdSerial, 0)
170    }
171
172    /// Queries and returns the ID information of the device.
173    pub fn ids(&mut self) -> Result<DevIDs, Error> {
174        let mut ids = DevIDs::default();
175        let size = self.query_config_select(InputConfigSelect::IdDevids, 0, ids.as_bytes_mut());
176        if usize::from(size) == size_of::<DevIDs>() {
177            Ok(ids)
178        } else {
179            Err(Error::IoError)
180        }
181    }
182
183    /// Queries and returns the input properties of the device.
184    pub fn prop_bits(&mut self) -> Result<Box<[u8]>, Error> {
185        self.query_config_select_alloc(InputConfigSelect::PropBits, 0)
186    }
187
188    /// Queries and returns a bitmap of supported event codes for the given event type.
189    ///
190    /// If the event type is not supported an empty slice will be returned.
191    pub fn ev_bits(&mut self, event_type: u8) -> Result<Box<[u8]>, Error> {
192        self.query_config_select_alloc(InputConfigSelect::EvBits, event_type)
193    }
194
195    /// Queries and returns information about the given axis of the device.
196    pub fn abs_info(&mut self, axis: u8) -> Result<AbsInfo, Error> {
197        let mut info = AbsInfo::default();
198        let size = self.query_config_select(InputConfigSelect::AbsInfo, axis, info.as_bytes_mut());
199        if usize::from(size) == size_of::<AbsInfo>() {
200            Ok(info)
201        } else {
202            Err(Error::IoError)
203        }
204    }
205}
206
207// SAFETY: The config space can be accessed from any thread.
208unsafe impl<H: Hal, T: Transport + Send> Send for VirtIOInput<H, T> where
209    VirtQueue<H, QUEUE_SIZE>: Send
210{
211}
212
213// SAFETY: An '&VirtIOInput` can't do anything, all methods take `&mut self`.
214unsafe impl<H: Hal, T: Transport + Sync> Sync for VirtIOInput<H, T> where
215    VirtQueue<H, QUEUE_SIZE>: Sync
216{
217}
218
219impl<H: Hal, T: Transport> Drop for VirtIOInput<H, T> {
220    fn drop(&mut self) {
221        // Clear any pointers pointing to DMA regions, so the device doesn't try to access them
222        // after they have been freed.
223        self.transport.queue_unset(QUEUE_EVENT);
224        self.transport.queue_unset(QUEUE_STATUS);
225    }
226}
227
228const CONFIG_DATA_MAX_LENGTH: usize = 128;
229
230/// Select value used for [`VirtIOInput::query_config_select()`].
231#[repr(u8)]
232#[derive(Debug, Clone, Copy)]
233pub enum InputConfigSelect {
234    /// Returns the name of the device, in u.string. subsel is zero.
235    IdName = 0x01,
236    /// Returns the serial number of the device, in u.string. subsel is zero.
237    IdSerial = 0x02,
238    /// Returns ID information of the device, in u.ids. subsel is zero.
239    IdDevids = 0x03,
240    /// Returns input properties of the device, in u.bitmap. subsel is zero.
241    /// Individual bits in the bitmap correspond to INPUT_PROP_* constants used
242    /// by the underlying evdev implementation.
243    PropBits = 0x10,
244    /// subsel specifies the event type using EV_* constants in the underlying
245    /// evdev implementation. If size is non-zero the event type is supported
246    /// and a bitmap of supported event codes is returned in u.bitmap. Individual
247    /// bits in the bitmap correspond to implementation-defined input event codes,
248    /// for example keys or pointing device axes.
249    EvBits = 0x11,
250    /// subsel specifies the absolute axis using ABS_* constants in the underlying
251    /// evdev implementation. Information about the axis will be returned in u.abs.
252    AbsInfo = 0x12,
253}
254
255#[repr(C)]
256struct Config {
257    select: WriteOnly<u8>,
258    subsel: WriteOnly<u8>,
259    size: ReadOnly<u8>,
260    _reserved: [ReadOnly<u8>; 5],
261    data: [ReadOnly<u8>; CONFIG_DATA_MAX_LENGTH],
262}
263
264/// Information about an axis of an input device, typically a joystick.
265#[repr(C)]
266#[derive(AsBytes, Clone, Debug, Default, Eq, PartialEq, FromBytes, FromZeroes)]
267pub struct AbsInfo {
268    /// The minimum value for the axis.
269    pub min: u32,
270    /// The maximum value for the axis.
271    pub max: u32,
272    /// The fuzz value used to filter noise from the event stream.
273    pub fuzz: u32,
274    /// The size of the dead zone; values less than this will be reported as 0.
275    pub flat: u32,
276    /// The resolution for values reported for the axis.
277    pub res: u32,
278}
279
280/// The identifiers of a VirtIO input device.
281#[repr(C)]
282#[derive(AsBytes, Clone, Debug, Default, Eq, PartialEq, FromBytes, FromZeroes)]
283pub struct DevIDs {
284    /// The bustype identifier.
285    pub bustype: u16,
286    /// The vendor identifier.
287    pub vendor: u16,
288    /// The product identifier.
289    pub product: u16,
290    /// The version identifier.
291    pub version: u16,
292}
293
294/// Both queues use the same `virtio_input_event` struct. `type`, `code` and `value`
295/// are filled according to the Linux input layer (evdev) interface.
296#[repr(C)]
297#[derive(AsBytes, Clone, Copy, Debug, Default, FromBytes, FromZeroes)]
298pub struct InputEvent {
299    /// Event type.
300    pub event_type: u16,
301    /// Event code.
302    pub code: u16,
303    /// Event value.
304    pub value: u32,
305}
306
307const QUEUE_EVENT: u16 = 0;
308const QUEUE_STATUS: u16 = 1;
309const SUPPORTED_FEATURES: Feature = Feature::RING_EVENT_IDX.union(Feature::RING_INDIRECT_DESC);
310
311// a parameter that can change
312const QUEUE_SIZE: usize = 32;
313
314#[cfg(test)]
315mod tests {
316    use super::*;
317    use crate::{
318        hal::fake::FakeHal,
319        transport::{
320            fake::{FakeTransport, QueueStatus, State},
321            DeviceType,
322        },
323    };
324    use alloc::{sync::Arc, vec};
325    use core::convert::TryInto;
326    use std::sync::Mutex;
327
328    #[test]
329    fn config() {
330        const DEFAULT_DATA: ReadOnly<u8> = ReadOnly::new(0);
331        let mut config_space = Config {
332            select: WriteOnly::default(),
333            subsel: WriteOnly::default(),
334            size: ReadOnly::new(0),
335            _reserved: Default::default(),
336            data: [DEFAULT_DATA; 128],
337        };
338        let state = Arc::new(Mutex::new(State {
339            queues: vec![QueueStatus::default(), QueueStatus::default()],
340            ..Default::default()
341        }));
342        let transport = FakeTransport {
343            device_type: DeviceType::Block,
344            max_queue_size: QUEUE_SIZE.try_into().unwrap(),
345            device_features: 0,
346            config_space: NonNull::from(&mut config_space),
347            state: state.clone(),
348        };
349        let mut input = VirtIOInput::<FakeHal, FakeTransport<Config>>::new(transport).unwrap();
350
351        set_data(&mut config_space, "Test input device".as_bytes());
352        assert_eq!(input.name().unwrap(), "Test input device");
353        assert_eq!(config_space.select.0, InputConfigSelect::IdName as u8);
354        assert_eq!(config_space.subsel.0, 0);
355
356        set_data(&mut config_space, "Serial number".as_bytes());
357        assert_eq!(input.serial_number().unwrap(), "Serial number");
358        assert_eq!(config_space.select.0, InputConfigSelect::IdSerial as u8);
359        assert_eq!(config_space.subsel.0, 0);
360
361        let ids = DevIDs {
362            bustype: 0x4242,
363            product: 0x0067,
364            vendor: 0x1234,
365            version: 0x4321,
366        };
367        set_data(&mut config_space, ids.as_bytes());
368        assert_eq!(input.ids().unwrap(), ids);
369        assert_eq!(config_space.select.0, InputConfigSelect::IdDevids as u8);
370        assert_eq!(config_space.subsel.0, 0);
371
372        set_data(&mut config_space, &[0x12, 0x34, 0x56]);
373        assert_eq!(input.prop_bits().unwrap().as_ref(), &[0x12, 0x34, 0x56]);
374        assert_eq!(config_space.select.0, InputConfigSelect::PropBits as u8);
375        assert_eq!(config_space.subsel.0, 0);
376
377        set_data(&mut config_space, &[0x42, 0x66]);
378        assert_eq!(input.ev_bits(3).unwrap().as_ref(), &[0x42, 0x66]);
379        assert_eq!(config_space.select.0, InputConfigSelect::EvBits as u8);
380        assert_eq!(config_space.subsel.0, 3);
381
382        let abs_info = AbsInfo {
383            min: 12,
384            max: 1234,
385            fuzz: 4,
386            flat: 10,
387            res: 2,
388        };
389        set_data(&mut config_space, abs_info.as_bytes());
390        assert_eq!(input.abs_info(5).unwrap(), abs_info);
391        assert_eq!(config_space.select.0, InputConfigSelect::AbsInfo as u8);
392        assert_eq!(config_space.subsel.0, 5);
393    }
394
395    fn set_data(config_space: &mut Config, value: &[u8]) {
396        config_space.size.0 = value.len().try_into().unwrap();
397        for (i, &byte) in value.into_iter().enumerate() {
398            config_space.data[i].0 = byte;
399        }
400    }
401}