Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/virtio/input/evdev.rs
5394 views
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
5
use std::collections::BTreeMap;
6
use std::os::raw::c_uint;
7
use std::ptr::null;
8
9
use base::ioctl_ior_nr;
10
use base::ioctl_iow_nr;
11
use base::ioctl_with_mut_ref;
12
use base::ioctl_with_ptr;
13
use base::ioctl_with_ref;
14
use base::AsRawDescriptor;
15
use data_model::Le32;
16
use linux_input_sys::constants::*;
17
18
use super::virtio_input_absinfo;
19
use super::virtio_input_bitmap;
20
use super::virtio_input_device_ids;
21
use super::InputError;
22
use super::Result;
23
24
const EVDEV: c_uint = 69;
25
26
#[repr(C)]
27
#[derive(Copy, Clone)]
28
struct evdev_buffer {
29
buffer: [std::os::raw::c_uchar; 128],
30
}
31
32
impl 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)]
48
struct evdev_id {
49
bustype: u16,
50
vendor: u16,
51
product: u16,
52
version: u16,
53
}
54
55
impl 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)]
68
struct 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
79
impl 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
92
impl 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
103
ioctl_ior_nr!(EVIOCGID, EVDEV, 0x02, evdev_id);
104
ioctl_ior_nr!(EVIOCGNAME, EVDEV, 0x06, evdev_buffer);
105
ioctl_ior_nr!(EVIOCGUNIQ, EVDEV, 0x08, evdev_buffer);
106
ioctl_ior_nr!(EVIOCGPROP, EVDEV, 0x09, evdev_buffer);
107
ioctl_ior_nr!(EVIOCGBIT, EVDEV, 0x20 + evt, evdev_buffer, evt);
108
ioctl_ior_nr!(EVIOCGABS, EVDEV, 0x40 + abs, evdev_abs_info, abs);
109
ioctl_iow_nr!(EVIOCGRAB, EVDEV, 0x90, u32);
110
111
fn errno() -> base::Error {
112
base::Error::last()
113
}
114
115
fn 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).
124
pub 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).
144
pub 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).
159
pub 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).
174
pub 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).
190
pub 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).
229
pub 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.
251
pub 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
265
pub 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
}
278
279