devices/virtio/input/
evdev.rs

1// Copyright 2019 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::collections::BTreeMap;
6use std::os::raw::c_uint;
7use std::ptr::null;
8
9use base::ioctl_ior_nr;
10use base::ioctl_iow_nr;
11use base::ioctl_with_mut_ref;
12use base::ioctl_with_ptr;
13use base::ioctl_with_ref;
14use base::AsRawDescriptor;
15use data_model::Le32;
16use linux_input_sys::constants::*;
17
18use super::virtio_input_absinfo;
19use super::virtio_input_bitmap;
20use super::virtio_input_device_ids;
21use super::InputError;
22use super::Result;
23
24const EVDEV: c_uint = 69;
25
26#[repr(C)]
27#[derive(Copy, Clone)]
28struct evdev_buffer {
29    buffer: [std::os::raw::c_uchar; 128],
30}
31
32impl evdev_buffer {
33    fn new() -> evdev_buffer {
34        evdev_buffer { buffer: [0u8; 128] }
35    }
36
37    fn get(&self, bit: usize) -> bool {
38        let idx = bit / 8;
39        let inner_bit = bit % 8;
40        self.buffer
41            .get(idx)
42            .is_some_and(|val| val & (1u8 << inner_bit) != 0)
43    }
44}
45
46#[repr(C)]
47#[derive(Copy, Clone)]
48struct evdev_id {
49    bustype: u16,
50    vendor: u16,
51    product: u16,
52    version: u16,
53}
54
55impl evdev_id {
56    fn new() -> evdev_id {
57        evdev_id {
58            bustype: 0,
59            vendor: 0,
60            product: 0,
61            version: 0,
62        }
63    }
64}
65
66#[repr(C)]
67#[derive(Copy, Clone)]
68struct evdev_abs_info {
69    // These should technically by signed ints, but Le32 is only compatible with u32 and we only
70    // forward the bytes but don't care about its actual values.
71    value: u32,
72    minimum: u32,
73    maximum: u32,
74    fuzz: u32,
75    flat: u32,
76    resolution: u32,
77}
78
79impl evdev_abs_info {
80    fn new() -> evdev_abs_info {
81        evdev_abs_info {
82            value: 0,
83            minimum: 0,
84            maximum: 0,
85            fuzz: 0,
86            flat: 0,
87            resolution: 0,
88        }
89    }
90}
91
92impl From<evdev_abs_info> for virtio_input_absinfo {
93    fn from(other: evdev_abs_info) -> Self {
94        virtio_input_absinfo {
95            min: Le32::from(other.minimum),
96            max: Le32::from(other.maximum),
97            fuzz: Le32::from(other.fuzz),
98            flat: Le32::from(other.flat),
99        }
100    }
101}
102
103ioctl_ior_nr!(EVIOCGID, EVDEV, 0x02, evdev_id);
104ioctl_ior_nr!(EVIOCGNAME, EVDEV, 0x06, evdev_buffer);
105ioctl_ior_nr!(EVIOCGUNIQ, EVDEV, 0x08, evdev_buffer);
106ioctl_ior_nr!(EVIOCGPROP, EVDEV, 0x09, evdev_buffer);
107ioctl_ior_nr!(EVIOCGBIT, EVDEV, 0x20 + evt, evdev_buffer, evt);
108ioctl_ior_nr!(EVIOCGABS, EVDEV, 0x40 + abs, evdev_abs_info, abs);
109ioctl_iow_nr!(EVIOCGRAB, EVDEV, 0x90, u32);
110
111fn errno() -> base::Error {
112    base::Error::last()
113}
114
115fn string_from_bytes_with_nul(buffer: &[u8], mut len: usize) -> Result<String> {
116    // Trim NUL byte.
117    if len > 0 && buffer[len] == 0 {
118        len -= 1;
119    }
120    String::from_utf8(buffer[0..len].to_vec()).map_err(InputError::InvalidString)
121}
122
123/// Gets id information from an event device (see EVIOCGID ioctl for details).
124pub fn device_ids<T: AsRawDescriptor>(descriptor: &T) -> Result<virtio_input_device_ids> {
125    let mut dev_id = evdev_id::new();
126    let len = {
127        // SAFETY:
128        // Safe because the kernel won't write more than size of evdev_id and we check the return
129        // value
130        unsafe { ioctl_with_mut_ref(descriptor, EVIOCGID, &mut dev_id) }
131    };
132    if len < 0 {
133        return Err(InputError::EvdevIdError(errno()));
134    }
135    Ok(virtio_input_device_ids::new(
136        dev_id.bustype,
137        dev_id.vendor,
138        dev_id.product,
139        dev_id.version,
140    ))
141}
142
143/// Gets the name of an event device (see EVIOCGNAME ioctl for details).
144pub fn name<T: AsRawDescriptor>(descriptor: &T) -> Result<String> {
145    let mut name = evdev_buffer::new();
146    let len = {
147        // SAFETY:
148        // Safe because the kernel won't write more than size of evdev_buffer and we check the
149        // return value
150        unsafe { ioctl_with_mut_ref(descriptor, EVIOCGNAME, &mut name) }
151    };
152    if len < 0 {
153        return Err(InputError::EvdevNameError(errno()));
154    }
155    string_from_bytes_with_nul(&name.buffer, len as usize)
156}
157
158/// Gets the unique (serial) name of an event device (see EVIOCGUNIQ ioctl for details).
159pub fn serial_name<T: AsRawDescriptor>(descriptor: &T) -> Result<String> {
160    let mut uniq = evdev_buffer::new();
161    let len = {
162        // SAFETY:
163        // Safe because the kernel won't write more than size of evdev_buffer and we check the
164        // return value
165        unsafe { ioctl_with_mut_ref(descriptor, EVIOCGUNIQ, &mut uniq) }
166    };
167    if len < 0 {
168        return Err(InputError::EvdevSerialError(errno()));
169    }
170    string_from_bytes_with_nul(&uniq.buffer, len as usize)
171}
172
173/// Gets the properties of an event device (see EVIOCGPROP ioctl for details).
174pub fn properties<T: AsRawDescriptor>(descriptor: &T) -> Result<virtio_input_bitmap> {
175    let mut props = evdev_buffer::new();
176    let len = {
177        // SAFETY:
178        // Safe because the kernel won't write more than size of evdev_buffer and we check the
179        // return value
180        unsafe { ioctl_with_mut_ref(descriptor, EVIOCGPROP, &mut props) }
181    };
182    if len < 0 {
183        return Err(InputError::EvdevPropertiesError(errno()));
184    }
185    Ok(virtio_input_bitmap::new(props.buffer))
186}
187
188/// Gets the event types supported by an event device as well as the event codes supported for each
189/// type (see EVIOCGBIT ioctl for details).
190pub fn supported_events<T: AsRawDescriptor>(
191    descriptor: &T,
192) -> Result<BTreeMap<u16, virtio_input_bitmap>> {
193    let mut evts: BTreeMap<u16, virtio_input_bitmap> = BTreeMap::new();
194
195    let mut evt_types = evdev_buffer::new();
196    let len = {
197        // SAFETY:
198        // Safe because the kernel won't write more than size of evdev_buffer and we check the
199        // return value
200        unsafe { ioctl_with_mut_ref(descriptor, EVIOCGBIT(0), &mut evt_types) }
201    };
202    if len < 0 {
203        return Err(InputError::EvdevEventTypesError(errno()));
204    }
205
206    // no need to ask for zero (EV_SYN) since it's always supported and treated as a special case
207    for ev in 1..EV_MAX {
208        if ev == EV_REP || !evt_types.get(ev as usize) {
209            // Event type not supported, skip it.
210            continue;
211        }
212        // Create a new zero-filled buffer every time to avoid carry-overs.
213        let mut evt_codes = evdev_buffer::new();
214        let len = {
215            // SAFETY:
216            // Safe because the kernel won't write more than size of evdev_buffer and we check the
217            // return value
218            unsafe { ioctl_with_mut_ref(descriptor, EVIOCGBIT(ev as c_uint), &mut evt_codes) }
219        };
220        if len < 0 {
221            return Err(InputError::EvdevEventTypesError(errno()));
222        }
223        evts.insert(ev, virtio_input_bitmap::new(evt_codes.buffer));
224    }
225    Ok(evts)
226}
227
228/// Gets the absolute axes of an event device (see EVIOCGABS ioctl for details).
229pub fn abs_info<T: AsRawDescriptor>(descriptor: &T) -> BTreeMap<u16, virtio_input_absinfo> {
230    let mut map: BTreeMap<u16, virtio_input_absinfo> = BTreeMap::new();
231
232    for abs in 0..ABS_MAX {
233        // Create a new one, zero-ed out every time to avoid carry-overs.
234        let mut abs_info = evdev_abs_info::new();
235        let ret = {
236            // SAFETY:
237            // Safe because the kernel won't write more than size of evdev_buffer and we check the
238            // return value
239            unsafe { ioctl_with_mut_ref(descriptor, EVIOCGABS(abs as c_uint), &mut abs_info) }
240        };
241        if ret == 0 {
242            map.insert(abs, virtio_input_absinfo::from(abs_info));
243        }
244    }
245    map
246}
247
248/// Grabs an event device (see EVIOCGGRAB ioctl for details). After this function succeeds the given
249/// descriptor has exclusive access to the device, effectively making it unusable for any other
250/// process in the host.
251pub fn grab_evdev<T: AsRawDescriptor>(descriptor: &mut T) -> Result<()> {
252    let val: u32 = 1;
253    let ret = {
254        // SAFETY:
255        // Safe because the kernel only read the value of the ptr and we check the return value
256        unsafe { ioctl_with_ref(descriptor, EVIOCGRAB, &val) }
257    };
258    if ret == 0 {
259        Ok(())
260    } else {
261        Err(InputError::EvdevGrabError(errno()))
262    }
263}
264
265pub fn ungrab_evdev<T: AsRawDescriptor>(descriptor: &mut T) -> Result<()> {
266    let ret = {
267        // SAFETY:
268        // Safe because the kernel only reads the value of the ptr (doesn't dereference) and
269        // we check the return value
270        unsafe { ioctl_with_ptr(descriptor, EVIOCGRAB, null::<u32>()) }
271    };
272    if ret == 0 {
273        Ok(())
274    } else {
275        Err(InputError::EvdevGrabError(errno()))
276    }
277}