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