veridian_kernel/drivers/evdev.rs
1//! evdev device node support for VeridianOS
2//!
3//! Creates per-device event nodes (`/dev/input/event*`) that expose input
4//! events through the standard Linux evdev interface. User-space libinput
5//! reads from these nodes to receive keyboard, mouse, and other input events.
6//!
7//! Events originate from the unified [`input_event`] ring buffer and are
8//! routed to per-device queues based on event type (EV_KEY -> keyboard,
9//! EV_REL/BTN_* -> mouse).
10
11#![allow(dead_code)]
12
13use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
14
15use super::input_event::{self, InputEvent, EV_ABS, EV_KEY, EV_REL};
16
17// ---------------------------------------------------------------------------
18// evdev ioctl numbers (Linux-compatible)
19// ---------------------------------------------------------------------------
20
21/// EVIOCGVERSION -- get driver version
22pub(crate) const EVIOCGVERSION: u32 = 0x01;
23/// EVIOCGID -- get device ID
24pub(crate) const EVIOCGID: u32 = 0x02;
25/// EVIOCGNAME -- get device name
26pub(crate) const EVIOCGNAME: u32 = 0x06;
27/// EVIOCGPHYS -- get physical location
28pub(crate) const EVIOCGPHYS: u32 = 0x07;
29/// EVIOCGUNIQ -- get unique identifier
30pub(crate) const EVIOCGUNIQ: u32 = 0x08;
31/// EVIOCGBIT -- get event type bits
32pub(crate) const EVIOCGBIT: u32 = 0x20;
33/// EVIOCGABS -- get absolute axis info
34pub(crate) const EVIOCGABS: u32 = 0x40;
35/// EVIOCGRAB -- exclusive grab
36pub(crate) const EVIOCGRAB: u32 = 0x90;
37
38// ---------------------------------------------------------------------------
39// Device type enumeration
40// ---------------------------------------------------------------------------
41
42/// Type of input device
43#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44pub(crate) enum EvdevDeviceType {
45 /// Keyboard device (event0)
46 Keyboard,
47 /// Mouse / pointer device (event1)
48 Mouse,
49}
50
51// ---------------------------------------------------------------------------
52// Per-device event queue
53// ---------------------------------------------------------------------------
54
55const DEVICE_BUFFER_SIZE: usize = 128;
56
57/// Per-device event ring buffer
58struct DeviceEventBuffer {
59 buf: [InputEvent; DEVICE_BUFFER_SIZE],
60 head: AtomicUsize,
61 tail: AtomicUsize,
62}
63
64impl DeviceEventBuffer {
65 const fn new() -> Self {
66 Self {
67 buf: [InputEvent {
68 timestamp: 0,
69 event_type: 0,
70 code: 0,
71 value: 0,
72 }; DEVICE_BUFFER_SIZE],
73 head: AtomicUsize::new(0),
74 tail: AtomicUsize::new(0),
75 }
76 }
77
78 fn push(&mut self, event: InputEvent) {
79 let head = self.head.load(Ordering::Relaxed);
80 let next = (head + 1) & (DEVICE_BUFFER_SIZE - 1);
81 let tail = self.tail.load(Ordering::Acquire);
82 if next == tail {
83 return; // Buffer full, drop event
84 }
85 self.buf[head] = event;
86 self.head.store(next, Ordering::Release);
87 }
88
89 fn pop(&self) -> Option<InputEvent> {
90 let tail = self.tail.load(Ordering::Relaxed);
91 let head = self.head.load(Ordering::Acquire);
92 if tail == head {
93 return None;
94 }
95 let event = self.buf[tail];
96 self.tail
97 .store((tail + 1) & (DEVICE_BUFFER_SIZE - 1), Ordering::Release);
98 Some(event)
99 }
100
101 fn is_empty(&self) -> bool {
102 self.tail.load(Ordering::Relaxed) == self.head.load(Ordering::Acquire)
103 }
104}
105
106// SAFETY: DeviceEventBuffer uses atomic head/tail. Single producer
107// (route_events) and single consumer (read).
108unsafe impl Send for DeviceEventBuffer {}
109unsafe impl Sync for DeviceEventBuffer {}
110
111// ---------------------------------------------------------------------------
112// evdev device state
113// ---------------------------------------------------------------------------
114
115/// State for a single evdev device node
116pub(crate) struct EvdevDevice {
117 /// Device type
118 pub(crate) device_type: EvdevDeviceType,
119 /// Device name (for EVIOCGNAME)
120 pub(crate) name: [u8; 64],
121 pub(crate) name_len: usize,
122 /// Major device number
123 pub(crate) major: u32,
124 /// Minor device number
125 pub(crate) minor: u32,
126 /// Per-device event queue
127 buffer: DeviceEventBuffer,
128 /// Whether this device is exclusively grabbed
129 grabbed: AtomicBool,
130}
131
132impl EvdevDevice {
133 pub(crate) const fn new(
134 device_type: EvdevDeviceType,
135 name_bytes: &[u8; 64],
136 name_len: usize,
137 major: u32,
138 minor: u32,
139 ) -> Self {
140 Self {
141 device_type,
142 name: *name_bytes,
143 name_len,
144 major,
145 minor,
146 buffer: DeviceEventBuffer::new(),
147 grabbed: AtomicBool::new(false),
148 }
149 }
150
151 /// Push an event into this device's queue
152 pub(crate) fn push_event(&mut self, event: InputEvent) {
153 self.buffer.push(event);
154 }
155
156 /// Read the next event
157 pub(crate) fn read_event(&self) -> Option<InputEvent> {
158 self.buffer.pop()
159 }
160
161 /// Check if events are available
162 pub(crate) fn has_events(&self) -> bool {
163 !self.buffer.is_empty()
164 }
165
166 /// Read events into a byte buffer (returns bytes read)
167 pub(crate) fn read_into_buffer(&self, buffer: &mut [u8]) -> usize {
168 let event_size = core::mem::size_of::<InputEvent>();
169 let max_events = buffer.len() / event_size;
170 let mut bytes_read = 0;
171
172 for i in 0..max_events {
173 if let Some(event) = self.read_event() {
174 let offset = i * event_size;
175 // SAFETY: We checked bounds above (i < max_events, max_events = len /
176 // event_size)
177 unsafe {
178 core::ptr::copy_nonoverlapping(
179 &event as *const InputEvent as *const u8,
180 buffer.as_mut_ptr().add(offset),
181 event_size,
182 );
183 }
184 bytes_read += event_size;
185 } else {
186 break;
187 }
188 }
189
190 bytes_read
191 }
192
193 /// Handle an evdev ioctl
194 pub(crate) fn handle_ioctl(&self, cmd: u32, arg: *mut u8) -> Result<i32, i32> {
195 // Extract the evdev ioctl number from the request.
196 // Linux evdev ioctls are _IOC(dir, 'E', nr, size). We match on nr.
197 let nr = cmd & 0xFF;
198
199 match nr {
200 EVIOCGVERSION => {
201 if arg.is_null() {
202 return Err(-1);
203 }
204 // Return Linux evdev version 0x010001 (1.0.1)
205 // SAFETY: Caller validated arg pointer.
206 unsafe {
207 *(arg as *mut u32) = 0x010001;
208 }
209 Ok(0)
210 }
211 EVIOCGID => {
212 if arg.is_null() {
213 return Err(-1);
214 }
215 // Return a synthetic input_id struct
216 // struct input_id { u16 bustype, vendor, product, version }
217 // SAFETY: Caller validated arg pointer.
218 unsafe {
219 let id = arg as *mut u16;
220 id.write(0x19); // BUS_VIRTUAL
221 id.add(1).write(0x1AF4); // VirtIO vendor
222 id.add(2).write(match self.device_type {
223 EvdevDeviceType::Keyboard => 0x0001,
224 EvdevDeviceType::Mouse => 0x0002,
225 });
226 id.add(3).write(0x0001); // version
227 }
228 Ok(0)
229 }
230 _ if (EVIOCGNAME..EVIOCGBIT).contains(&nr) => {
231 // EVIOCGNAME -- return device name
232 if arg.is_null() {
233 return Err(-1);
234 }
235 let copy_len = self.name_len.min(63);
236 // SAFETY: Caller validated arg pointer; copy_len bounded.
237 unsafe {
238 core::ptr::copy_nonoverlapping(self.name.as_ptr(), arg, copy_len);
239 // Null-terminate
240 arg.add(copy_len).write(0);
241 }
242 Ok(copy_len as i32)
243 }
244 _ if (EVIOCGBIT..EVIOCGABS).contains(&nr) => {
245 // EVIOCGBIT -- return capability bitmask
246 if arg.is_null() {
247 return Err(-1);
248 }
249 let ev_type = nr - EVIOCGBIT;
250 self.fill_capability_bits(ev_type, arg);
251 Ok(0)
252 }
253 _ if (EVIOCGABS..EVIOCGRAB).contains(&nr) => {
254 // EVIOCGABS -- return absolute axis info
255 if arg.is_null() {
256 return Err(-1);
257 }
258 // struct input_absinfo { value, minimum, maximum, fuzz, flat, resolution }
259 // For now, return zeroed info (we only support relative mouse)
260 // SAFETY: Caller validated arg pointer.
261 unsafe {
262 core::ptr::write_bytes(arg, 0, 6 * 4); // 6 x i32
263 }
264 Ok(0)
265 }
266 EVIOCGRAB => {
267 if arg.is_null() {
268 return Err(-1);
269 }
270 // SAFETY: Caller validated arg pointer.
271 let grab_value = unsafe { *(arg as *const u32) };
272 if grab_value != 0 {
273 self.grabbed.store(true, Ordering::Release);
274 } else {
275 self.grabbed.store(false, Ordering::Release);
276 }
277 Ok(0)
278 }
279 _ => Err(-1), // Unsupported ioctl
280 }
281 }
282
283 /// Fill event capability bitmask
284 fn fill_capability_bits(&self, ev_type: u32, out: *mut u8) {
285 // Zero the output first (enough for 64 bytes of bitmap)
286 // SAFETY: out was validated by caller.
287 unsafe {
288 core::ptr::write_bytes(out, 0, 64);
289 }
290
291 match ev_type {
292 0 => {
293 // EV type bitmap: which event types this device supports
294 // SAFETY: out was validated by caller.
295 unsafe {
296 let bits = out;
297 match self.device_type {
298 EvdevDeviceType::Keyboard => {
299 // Supports EV_KEY (bit 1)
300 *bits = 0x02;
301 }
302 EvdevDeviceType::Mouse => {
303 // Supports EV_KEY (bit 1) + EV_REL (bit 2)
304 *bits = 0x06;
305 }
306 }
307 }
308 }
309 1 => {
310 // EV_KEY bitmap (which keys/buttons are supported)
311 // For keyboard: set bits 1-127 (most scancodes)
312 // For mouse: set BTN_LEFT (0x110), BTN_RIGHT (0x111), BTN_MIDDLE (0x112)
313 // SAFETY: out was validated by caller.
314 unsafe {
315 match self.device_type {
316 EvdevDeviceType::Keyboard => {
317 // Set key bits 1-127 (bytes 0-15)
318 for i in 0..16 {
319 *out.add(i) = 0xFF;
320 }
321 // Clear bit 0 (reserved)
322 *out &= 0xFE;
323 }
324 EvdevDeviceType::Mouse => {
325 // BTN_LEFT = 0x110, bit index = 0x110 / 8 = 34, bit = 0
326 // BTN_RIGHT = 0x111, byte 34, bit 1
327 // BTN_MIDDLE = 0x112, byte 34, bit 2
328 if 34 < 64 {
329 *out.add(34) = 0x07; // bits 0,1,2
330 }
331 }
332 }
333 }
334 }
335 2 => {
336 // EV_REL bitmap (which relative axes are supported)
337 if self.device_type == EvdevDeviceType::Mouse {
338 // REL_X (bit 0) + REL_Y (bit 1)
339 // SAFETY: out was validated by caller.
340 unsafe {
341 *out = 0x03;
342 }
343 }
344 }
345 _ => {} // Other event types: leave zeroed
346 }
347 }
348}
349
350// ---------------------------------------------------------------------------
351// Global evdev device table
352// ---------------------------------------------------------------------------
353
354/// Keyboard device name
355const KEYBOARD_NAME: &[u8] = b"VeridianOS PS/2 Keyboard";
356/// Mouse device name
357const MOUSE_NAME: &[u8] = b"VeridianOS PS/2 Mouse";
358
359/// Helper to create a fixed-size name buffer
360const fn make_name(src: &[u8]) -> ([u8; 64], usize) {
361 let mut buf = [0u8; 64];
362 let len = if src.len() > 63 { 63 } else { src.len() };
363 let mut i = 0;
364 while i < len {
365 buf[i] = src[i];
366 i += 1;
367 }
368 (buf, len)
369}
370
371const KEYBOARD_NAME_BUF: ([u8; 64], usize) = make_name(KEYBOARD_NAME);
372const MOUSE_NAME_BUF: ([u8; 64], usize) = make_name(MOUSE_NAME);
373
374static KEYBOARD_DEVICE: spin::Mutex<EvdevDevice> = spin::Mutex::new(EvdevDevice::new(
375 EvdevDeviceType::Keyboard,
376 &KEYBOARD_NAME_BUF.0,
377 KEYBOARD_NAME_BUF.1,
378 13,
379 64, // /dev/input/event0 = major 13, minor 64
380));
381
382static MOUSE_DEVICE: spin::Mutex<EvdevDevice> = spin::Mutex::new(EvdevDevice::new(
383 EvdevDeviceType::Mouse,
384 &MOUSE_NAME_BUF.0,
385 MOUSE_NAME_BUF.1,
386 13,
387 65, // /dev/input/event1 = major 13, minor 65
388));
389
390// ---------------------------------------------------------------------------
391// Public API
392// ---------------------------------------------------------------------------
393
394/// Route events from the global input queue to per-device queues.
395///
396/// Should be called periodically (e.g., after `input_event::poll_all()`).
397pub(crate) fn route_events() {
398 while let Some(event) = input_event::read_event() {
399 match event.event_type {
400 EV_KEY => {
401 // Keys with code >= 0x110 are mouse buttons
402 if event.code >= 0x110 && event.code <= 0x117 {
403 MOUSE_DEVICE.lock().push_event(event);
404 } else {
405 KEYBOARD_DEVICE.lock().push_event(event);
406 }
407 }
408 EV_REL => {
409 MOUSE_DEVICE.lock().push_event(event);
410 }
411 EV_ABS => {
412 MOUSE_DEVICE.lock().push_event(event);
413 }
414 _ => {
415 // Unknown event type -- route to keyboard as fallback
416 KEYBOARD_DEVICE.lock().push_event(event);
417 }
418 }
419 }
420}
421
422/// Read events from a specific device into a buffer.
423///
424/// `minor` selects the device (64 = keyboard, 65 = mouse).
425/// Returns number of bytes read.
426pub(crate) fn read_device(minor: u32, buffer: &mut [u8]) -> usize {
427 match minor {
428 64 => KEYBOARD_DEVICE.lock().read_into_buffer(buffer),
429 65 => MOUSE_DEVICE.lock().read_into_buffer(buffer),
430 _ => 0,
431 }
432}
433
434/// Handle an ioctl on an evdev device.
435///
436/// `minor` selects the device (64 = keyboard, 65 = mouse).
437pub(crate) fn handle_ioctl(minor: u32, cmd: u32, arg: *mut u8) -> Result<i32, i32> {
438 match minor {
439 64 => KEYBOARD_DEVICE.lock().handle_ioctl(cmd, arg),
440 65 => MOUSE_DEVICE.lock().handle_ioctl(cmd, arg),
441 _ => Err(-1),
442 }
443}
444
445/// Check if a device has pending events.
446pub(crate) fn has_events(minor: u32) -> bool {
447 match minor {
448 64 => KEYBOARD_DEVICE.lock().has_events(),
449 65 => MOUSE_DEVICE.lock().has_events(),
450 _ => false,
451 }
452}
453
454/// Get the device name for a given minor number.
455pub(crate) fn device_name(minor: u32) -> Option<&'static str> {
456 match minor {
457 64 => Some("event0"),
458 65 => Some("event1"),
459 _ => None,
460 }
461}
462
463// ---------------------------------------------------------------------------
464// Tests
465// ---------------------------------------------------------------------------
466
467#[cfg(test)]
468mod tests {
469 use super::*;
470
471 #[test]
472 fn test_device_buffer_push_pop() {
473 let mut buf = DeviceEventBuffer::new();
474 let event = InputEvent::key(0x1E, true); // 'A' key
475 buf.push(event);
476 assert!(!buf.is_empty());
477
478 let popped = buf.pop();
479 assert!(popped.is_some());
480 let popped = popped.unwrap();
481 assert_eq!(popped.code, 0x1E);
482 assert_eq!(popped.value, 1);
483 assert!(buf.is_empty());
484 }
485
486 #[test]
487 fn test_device_buffer_empty() {
488 let buf = DeviceEventBuffer::new();
489 assert!(buf.is_empty());
490 assert!(buf.pop().is_none());
491 }
492
493 #[test]
494 fn test_make_name() {
495 let (buf, len) = make_name(b"test device");
496 assert_eq!(len, 11);
497 assert_eq!(&buf[..len], b"test device");
498 assert_eq!(buf[len], 0);
499 }
500
501 #[test]
502 fn test_device_name_lookup() {
503 assert_eq!(device_name(64), Some("event0"));
504 assert_eq!(device_name(65), Some("event1"));
505 assert_eq!(device_name(66), None);
506 }
507}