⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

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}