virtio-inputd: v6.0 single-producer evdev; bump 0.1.0->0.2.3
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
[package]
|
||||
name = "virtio-inputd"
|
||||
version = "0.2.0"
|
||||
version = "0.2.3"
|
||||
edition = "2024"
|
||||
description = "VirtIO input device driver for Red Bear OS (v6.0: writes Linux evdev events to /scheme/input/evdev). Handles QEMU virtio-input-host-pci, virtio-input-keyboard, virtio-input-mouse, virtio-input-tablet."
|
||||
description = "virtio-input daemon v6.0 2026: reads virtio-input PCI events and writes Linux evdev events to /scheme/input/evdev"
|
||||
|
||||
[[bin]]
|
||||
name = "virtio-inputd"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! virtio-inputd — VirtIO input device driver for Red Bear OS
|
||||
//! virtio-inputd v6.0 — VirtIO input device driver for Red Bear OS
|
||||
//!
|
||||
//! Handles the QEMU `virtio-input-*` paravirt input devices:
|
||||
//! Drives QEMU `virtio-input-*` paravirt input devices:
|
||||
//! - `-device virtio-input-host-pci` (host passthrough)
|
||||
//! - `-device virtio-input-keyboard`
|
||||
//! - `-device virtio-input-mouse`
|
||||
@@ -8,27 +8,21 @@
|
||||
//!
|
||||
//! ## Pipeline
|
||||
//!
|
||||
//! 1. PCI probe for `vendor=0x1AF4 device=0x1052` (legacy virtio-input) or
|
||||
//! `vendor=0x1AF4 device=0x1042+` (modern virtio 1.0, type=18). One daemon
|
||||
//! per device — pcid-spawner launches us.
|
||||
//! 2. Negotiate `VIRTIO_F_VERSION_1` (only feature we need).
|
||||
//! 3. Set up one event virtqueue and pre-fill the available ring with 8 KiB
|
||||
//! of DMA-allocated event buffers.
|
||||
//! 4. Wait for `used_idx` to advance via IRQ. Drain used buffers, decode
|
||||
//! virtio_input_event (type/code/value), translate to orbclient event,
|
||||
//! write to inputd via ProducerHandle.
|
||||
//! 5. Re-cycle drained buffers back to the avail ring and kick.
|
||||
//! 1. PCI probe for modern virtio-input (vendor=0x1AF4, device=0x1042+).
|
||||
//! pcid-spawner launches us with the PCI location as argument.
|
||||
//! 2. Negotiate `VIRTIO_F_VERSION_1`.
|
||||
//! 3. Set up one event virtqueue with 64 DMA-allocated event buffers.
|
||||
//! 4. Drain used buffers, decode `VirtioInputEvent`, write Linux evdev events
|
||||
//! to `/scheme/input/evdev` via `EvdevProducerHandle`.
|
||||
//! 5. Recycle drained buffers to the avail ring and kick.
|
||||
//!
|
||||
//! ## Event Translation
|
||||
//! ## Wire format
|
||||
//!
|
||||
//! virtio_input_event types map to orbclient events:
|
||||
//! - EV_KEY (1) → KeyEvent (key press / release via value 0/1)
|
||||
//! - EV_REL (2) → MouseRelativeEvent (dx, dy from REL_X, REL_Y)
|
||||
//! - EV_SYN (0) → dropped (inputd multiplexes itself)
|
||||
//! - EV_ABS / MSC / LED → dropped for now (Phase 5.2 expansion)
|
||||
//!
|
||||
//! Phase 5.2 (follow-up): add evdevd producer path in parallel with inputd.
|
||||
//! See local/docs/CONSOLE-TO-KDE-DESKTOP-PLAN.md §5.
|
||||
//! virtio-input sends `VirtioInputEvent { type: u8, code: u8, value: u32 }`.
|
||||
//! We translate to Linux evdev `EvdevEvent { event_type: u16, code: u16, value: i32 }`:
|
||||
//! - virtio `type` (u8) → evdev `event_type` (u16) — direct map, EV_SYN/EV_KEY/EV_REL/EV_ABS match
|
||||
//! - virtio `code` (u8) → evdev `code` (u16) — zero-extend
|
||||
//! - virtio `value` (u32) → evdev `value` (i32) — sign-extend for ABS, cast for others
|
||||
|
||||
#![forbid(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
@@ -39,9 +33,8 @@ use std::sync::atomic::{Ordering, fence};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use inputd::ProducerHandle;
|
||||
use inputd::{EvdevProducerHandle, EV_ABS, EV_KEY, EV_REL, EV_SYN};
|
||||
use log::{debug, error, info, warn};
|
||||
use orbclient::{Event, KeyEvent, MouseRelativeEvent, ScrollEvent};
|
||||
use redox_driver_sys::dma::DmaBuffer;
|
||||
use redox_driver_sys::pcid_client::PcidClient;
|
||||
use redox_driver_sys::pci::{PciDevice, PciDeviceInfo, PCI_CAP_ID_VNDR};
|
||||
@@ -50,117 +43,12 @@ mod virtio;
|
||||
use virtio::{
|
||||
QueueConfig, VirtioInputEvent, VirtioModernPciTransport, VIRTIO_INPUT_EVENT_SIZE,
|
||||
VIRTIO_INPUT_CFG_EV_BITS, VIRTIO_INPUT_CFG_ABS_INFO, VIRTIO_INPUT_CFG_ID_NAME,
|
||||
VIRTIO_INPUT_CFG_ID_SERIAL, VIRTIO_INPUT_CFG_ID_DEVIDS, VIRTIO_INPUT_CFG_PROP_BITS,
|
||||
VIRTIO_INPUT_CFG_ID_SERIAL,
|
||||
VIRTIO_F_VERSION_1,
|
||||
};
|
||||
|
||||
// Linux input-event-codes.h (subset we care about)
|
||||
const EV_SYN: u16 = 0x00;
|
||||
const EV_KEY: u16 = 0x01;
|
||||
const EV_REL: u16 = 0x02;
|
||||
const EV_ABS: u16 = 0x03;
|
||||
const EV_MSC: u16 = 0x04;
|
||||
const EV_SW: u16 = 0x05;
|
||||
const EV_LED: u16 = 0x11;
|
||||
const EV_SND: u16 = 0x12;
|
||||
const EV_REP: u16 = 0x14;
|
||||
|
||||
const SYN_REPORT: u16 = 0;
|
||||
const SYN_DROPPED: u16 = 3;
|
||||
|
||||
// REL_*
|
||||
const REL_X: u16 = 0x00;
|
||||
const REL_Y: u16 = 0x01;
|
||||
const REL_WHEEL: u16 = 0x08;
|
||||
const REL_HWHEEL: u16 = 0x06;
|
||||
|
||||
// KEY_*
|
||||
const KEY_ESC: u16 = 1;
|
||||
const KEY_1: u16 = 2;
|
||||
const KEY_0: u16 = 11;
|
||||
const KEY_Q: u16 = 16;
|
||||
const KEY_P: u16 = 25;
|
||||
const KEY_A: u16 = 30;
|
||||
const KEY_L: u16 = 38;
|
||||
const KEY_Z: u16 = 44;
|
||||
const KEY_M: u16 = 50;
|
||||
const KEY_F1: u16 = 59;
|
||||
const KEY_F12: u16 = 68;
|
||||
const KEY_LEFTCTRL: u16 = 29;
|
||||
const KEY_LEFTALT: u16 = 56;
|
||||
const KEY_LEFTSHIFT: u16 = 42;
|
||||
const KEY_RIGHTSHIFT: u16 = 54;
|
||||
const KEY_LEFTMETA: u16 = 91;
|
||||
const KEY_RIGHTMETA: u16 = 92;
|
||||
const KEY_KPENTER: u16 = 96;
|
||||
const KEY_KPSLASH: u16 = 95;
|
||||
const KEY_SPACE: u16 = 57;
|
||||
const KEY_CAPSLOCK: u16 = 58;
|
||||
const KEY_NUMLOCK: u16 = 69;
|
||||
const KEY_SCROLLLOCK: u16 = 70;
|
||||
const KEY_MINUS: u16 = 12;
|
||||
const KEY_EQUAL: u16 = 13;
|
||||
const KEY_TAB: u16 = 15;
|
||||
const KEY_ENTER: u16 = 28;
|
||||
const KEY_SEMICOLON: u16 = 39;
|
||||
const KEY_APOSTROPHE: u16 = 40;
|
||||
const KEY_GRAVE: u16 = 41;
|
||||
const KEY_BACKSLASH: u16 = 43;
|
||||
const KEY_COMMA: u16 = 51;
|
||||
const KEY_DOT: u16 = 52;
|
||||
const KEY_SLASH: u16 = 53;
|
||||
const KEY_LEFTBRACE: u16 = 26;
|
||||
const KEY_RIGHTBRACE: u16 = 27;
|
||||
const KEY_BACKSPACE: u16 = 14;
|
||||
const KEY_102ND: u16 = 86;
|
||||
const KEY_RO: u16 = 89;
|
||||
const KEY_KATAKANAHIRAGANA: u16 = 93;
|
||||
const KEY_HENKAN: u16 = 92;
|
||||
const KEY_MUHENKAN: u16 = 94;
|
||||
const KEY_KPJPCOMMA: u16 = 95;
|
||||
const KEY_KP7: u16 = 71;
|
||||
const KEY_KP8: u16 = 72;
|
||||
const KEY_KP9: u16 = 73;
|
||||
const KEY_KPMINUS: u16 = 74;
|
||||
const KEY_KP4: u16 = 75;
|
||||
const KEY_KP5: u16 = 76;
|
||||
const KEY_KP6: u16 = 77;
|
||||
const KEY_KPPLUS: u16 = 78;
|
||||
const KEY_KP1: u16 = 79;
|
||||
const KEY_KP2: u16 = 80;
|
||||
const KEY_KP3: u16 = 81;
|
||||
const KEY_KP0: u16 = 82;
|
||||
const KEY_KPDOT: u16 = 83;
|
||||
const KEY_KPASTERISK: u16 = 55;
|
||||
const KEY_KPEQUAL: u16 = 117;
|
||||
const KEY_F2: u16 = 60;
|
||||
const KEY_F3: u16 = 61;
|
||||
const KEY_F4: u16 = 62;
|
||||
const KEY_F5: u16 = 63;
|
||||
const KEY_F6: u16 = 64;
|
||||
const KEY_F7: u16 = 65;
|
||||
const KEY_F8: u16 = 66;
|
||||
const KEY_F9: u16 = 67;
|
||||
const KEY_F10: u16 = 68;
|
||||
const KEY_F11: u16 = 69;
|
||||
const KEY_PRINT: u16 = 70;
|
||||
const KEY_SCROLL: u16 = 70;
|
||||
const KEY_PAUSE: u16 = 119;
|
||||
const KEY_INSERT: u16 = 110;
|
||||
const KEY_HOME: u16 = 102;
|
||||
const KEY_PAGEUP: u16 = 104;
|
||||
const KEY_DELETE: u16 = 111;
|
||||
const KEY_END: u16 = 107;
|
||||
const KEY_PAGEDOWN: u16 = 109;
|
||||
const KEY_RIGHT: u16 = 106;
|
||||
const KEY_LEFT: u16 = 105;
|
||||
const KEY_DOWN: u16 = 108;
|
||||
const KEY_UP: u16 = 103;
|
||||
|
||||
const VIRTQ_DESC_F_NEXT: u16 = 1;
|
||||
const VIRTQ_DESC_F_WRITE: u16 = 2;
|
||||
const VIRTQ_DESC_F_AVAIL: u16 = 4;
|
||||
const VIRTQ_DESC_F_USED: u16 = 8;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DriverError {
|
||||
@@ -211,7 +99,7 @@ struct VirtqUsedElem {
|
||||
///
|
||||
/// virtio-input only needs to receive event buffers from the device, so this
|
||||
/// implementation pre-allocates a ring of `size` buffers at startup. Each
|
||||
/// buffer is exactly one `virtio_input_event` (8 bytes). Buffers are cycled
|
||||
/// buffer is exactly one `VirtioInputEvent` (8 bytes). Buffers are cycled
|
||||
/// back to the avail ring after the device has consumed them.
|
||||
struct InputEventQueue {
|
||||
index: u16,
|
||||
@@ -272,10 +160,6 @@ impl InputEventQueue {
|
||||
for i in 0..self.size {
|
||||
self.push_avail(i);
|
||||
}
|
||||
// The device reads avail_ring[avail_idx % size] to discover new buffers.
|
||||
// After writing all `size` ring slots, we MUST publish the new
|
||||
// avail_idx = size, or the device will not see any of them.
|
||||
// See virtio spec §2.8.6 "Publishing the used ring".
|
||||
fence(Ordering::Release);
|
||||
self.write_avail_idx(self.size);
|
||||
}
|
||||
@@ -322,8 +206,6 @@ impl InputEventQueue {
|
||||
fence(Ordering::SeqCst);
|
||||
let used_idx = self.read_used_idx();
|
||||
|
||||
// 64 is the maximum queue size we accept, so the stack array is
|
||||
// always large enough for a single drain cycle.
|
||||
let mut drained_ids: [u16; 64] = [0u16; 64];
|
||||
let mut drained_count: usize = 0;
|
||||
|
||||
@@ -363,103 +245,50 @@ impl InputEventQueue {
|
||||
}
|
||||
}
|
||||
|
||||
/// Map a Linux evdev keycode to the closest character (US QWERTY layout).
|
||||
/// Translate a virtio input event to evdev and write to the producer.
|
||||
///
|
||||
/// This is a very small subset — sufficient for QEMU virtio-input-keyboard
|
||||
/// to produce useful KeyEvent::character values. Real evdev has a complex
|
||||
/// keymap model; we accept the simplification that Phase 5.2 will replace
|
||||
/// with the evdevd keymap bridge.
|
||||
fn keycode_to_char(code: u16) -> char {
|
||||
match code {
|
||||
KEY_ESC => '\u{1B}',
|
||||
KEY_1 => '1',
|
||||
KEY_0 => '0',
|
||||
KEY_Q => 'q',
|
||||
KEY_P => 'p',
|
||||
KEY_A => 'a',
|
||||
KEY_L => 'l',
|
||||
KEY_Z => 'z',
|
||||
KEY_M => 'm',
|
||||
KEY_MINUS => '-',
|
||||
KEY_EQUAL => '=',
|
||||
KEY_TAB => '\t',
|
||||
KEY_SPACE => ' ',
|
||||
KEY_LEFTBRACE => '[',
|
||||
KEY_RIGHTBRACE => ']',
|
||||
KEY_BACKSLASH => '\\',
|
||||
KEY_SEMICOLON => ';',
|
||||
KEY_APOSTROPHE => '\'',
|
||||
KEY_GRAVE => '`',
|
||||
KEY_COMMA => ',',
|
||||
KEY_DOT => '.',
|
||||
KEY_SLASH => '/',
|
||||
KEY_ENTER => '\n',
|
||||
KEY_BACKSPACE => '\u{08}',
|
||||
KEY_KP0 => '0',
|
||||
KEY_KP1 => '1',
|
||||
KEY_KP2 => '2',
|
||||
KEY_KP3 => '3',
|
||||
KEY_KP4 => '4',
|
||||
KEY_KP5 => '5',
|
||||
KEY_KP6 => '6',
|
||||
KEY_KP7 => '7',
|
||||
KEY_KP8 => '8',
|
||||
KEY_KP9 => '9',
|
||||
KEY_KPMINUS => '-',
|
||||
KEY_KPPLUS => '+',
|
||||
KEY_KPDOT => '.',
|
||||
KEY_KPASTERISK => '*',
|
||||
KEY_KPSLASH => '/',
|
||||
KEY_KPENTER => '\n',
|
||||
KEY_KPEQUAL => '=',
|
||||
_ => '\0',
|
||||
}
|
||||
}
|
||||
/// virtio type (u8) → evdev event_type (u16): direct map, EV_SYN=0, EV_KEY=1, EV_REL=2, EV_ABS=3
|
||||
/// virtio code (u8) → evdev code (u16): zero-extend
|
||||
/// virtio value (u32) → evdev value (i32): cast (ABS sign-extends via i32)
|
||||
fn write_evdev_event(producer: &mut EvdevProducerHandle, ev: &VirtioInputEvent) {
|
||||
let event_type = ev.event_type as u16;
|
||||
let code = ev.code as u16;
|
||||
let value = ev.value as i32;
|
||||
|
||||
/// Translate a virtio_input_event into one or more orbclient events.
|
||||
///
|
||||
/// Multiple events are batched in the output vector so the caller can write
|
||||
/// them all in one syscall.
|
||||
fn translate_event(ev: &VirtioInputEvent) -> Vec<Event> {
|
||||
match ev.event_type {
|
||||
EV_SYN => Vec::new(),
|
||||
EV_KEY => {
|
||||
let pressed = ev.value != 0;
|
||||
let character = keycode_to_char(ev.code);
|
||||
vec![KeyEvent { character, scancode: ev.code as u8, pressed }.to_event()]
|
||||
}
|
||||
EV_REL => {
|
||||
// REL_WHEEL: value is delta in 120ths of a notch; orbclient uses
|
||||
// raw pixels. Clamp small positive/negative to +/-1.
|
||||
match ev.code {
|
||||
REL_X | REL_Y => {
|
||||
vec![MouseRelativeEvent {
|
||||
dx: if ev.code == REL_X { ev.value } else { 0 },
|
||||
dy: if ev.code == REL_Y { ev.value } else { 0 },
|
||||
}
|
||||
.to_event()]
|
||||
}
|
||||
REL_WHEEL | REL_HWHEEL => {
|
||||
let clicks = if ev.value == 0 {
|
||||
0
|
||||
} else if ev.value > 0 {
|
||||
1
|
||||
} else {
|
||||
-1
|
||||
};
|
||||
vec![ScrollEvent {
|
||||
x: if ev.code == REL_HWHEEL { clicks } else { 0 },
|
||||
y: if ev.code == REL_WHEEL { clicks } else { 0 },
|
||||
}
|
||||
.to_event()]
|
||||
}
|
||||
_ => Vec::new(),
|
||||
match event_type {
|
||||
EV_SYN => {
|
||||
if let Err(e) = producer.write_syn_report() {
|
||||
warn!("virtio-inputd: write_syn_report failed: {e}");
|
||||
}
|
||||
}
|
||||
// EV_ABS / EV_MSC / EV_LED / EV_REP / EV_SND / EV_SW are not yet
|
||||
// translated — Phase 5.2 expansion. For now they are dropped, which
|
||||
// is acceptable for QEMU keyboard + mouse + basic tablet.
|
||||
_ => Vec::new(),
|
||||
EV_KEY => {
|
||||
if let Err(e) = producer.write_key(code, value != 0) {
|
||||
warn!("virtio-inputd: write_key failed: {e}");
|
||||
}
|
||||
if let Err(e) = producer.write_syn_report() {
|
||||
warn!("virtio-inputd: write_syn_report (after key) failed: {e}");
|
||||
}
|
||||
}
|
||||
EV_REL => {
|
||||
if let Err(e) = producer.write_rel(code, value) {
|
||||
warn!("virtio-inputd: write_rel failed: {e}");
|
||||
}
|
||||
if let Err(e) = producer.write_syn_report() {
|
||||
warn!("virtio-inputd: write_syn_report (after rel) failed: {e}");
|
||||
}
|
||||
}
|
||||
EV_ABS => {
|
||||
if let Err(e) = producer.write_abs(code, value) {
|
||||
warn!("virtio-inputd: write_abs failed: {e}");
|
||||
}
|
||||
if let Err(e) = producer.write_syn_report() {
|
||||
warn!("virtio-inputd: write_syn_report (after abs) failed: {e}");
|
||||
}
|
||||
}
|
||||
// EV_MSC, EV_LED, EV_SND, EV_REP, EV_SW — dropped; not used by virtio-input devices
|
||||
_ => {
|
||||
debug!("virtio-inputd: dropped evdev event type={event_type} code={code} value={value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,11 +321,8 @@ fn virtio_input_probe(pci: &mut PciDevice) -> Result<bool> {
|
||||
let cap_id = pci.read_config_byte(offset as u64)?;
|
||||
let cap_next = pci.read_config_byte(offset as u64 + 1)?;
|
||||
if cap_id == PCI_CAP_ID_VNDR {
|
||||
// cap.cfg_type is at offset 3 of the capability.
|
||||
let cfg_type = pci.read_config_byte(offset as u64 + 3)?;
|
||||
if cfg_type == 4 {
|
||||
// cap.id is at offset 5 — for device_cfg, this is the
|
||||
// virtio device type.
|
||||
let dev_type = pci.read_config_byte(offset as u64 + 5)?;
|
||||
if dev_type == 18 {
|
||||
return Ok(true);
|
||||
@@ -509,15 +335,12 @@ fn virtio_input_probe(pci: &mut PciDevice) -> Result<bool> {
|
||||
}
|
||||
|
||||
fn run_device() -> Result<()> {
|
||||
// Connect to pcid via the env var it provides. If absent, we cannot run.
|
||||
if PcidClient::connect_default().is_none() {
|
||||
return Err(DriverError::Initialization(
|
||||
"virtio-inputd: not launched by pcid-spawner (PCID_CLIENT_CHANNEL unset)".into(),
|
||||
));
|
||||
}
|
||||
|
||||
// The pcid-spawner also passes the PCI location as a positional argument
|
||||
// before PCID_CLIENT_CHANNEL. Format: "segment:bus:device.function".
|
||||
let args: Vec<String> = env::args().skip(1).collect();
|
||||
let loc_str = args.first().ok_or_else(|| {
|
||||
DriverError::Initialization(
|
||||
@@ -565,10 +388,6 @@ fn run_device() -> Result<()> {
|
||||
let mut transport = VirtioModernPciTransport::new(&pci_info, &mut pci_device)?;
|
||||
transport.initialize_device(VIRTIO_F_VERSION_1)?;
|
||||
|
||||
// Wrap remaining init in a closure so any error resets the device
|
||||
// to a clean state. virtio 1.0 §2.1.6: a driver that fails to
|
||||
// complete initialization MUST reset the device so a future
|
||||
// attach (e.g. after driver-manager restart) starts cleanly.
|
||||
let init_result = (|| -> Result<()> {
|
||||
let num_queues = transport.num_queues();
|
||||
if num_queues < 1 {
|
||||
@@ -606,11 +425,9 @@ fn run_device() -> Result<()> {
|
||||
if transport.config_read_size() != 0 {
|
||||
let _ = transport.config_read_string(serial_buf.len(), &mut serial_buf);
|
||||
}
|
||||
let _ = std::str::from_utf8(&serial_buf[..]);
|
||||
|
||||
// Probe EV bits to log a summary
|
||||
let mut ev_bits = [0u8; 16];
|
||||
let mut abs_count = 0u8;
|
||||
for ev_type in 0u8..16u8 {
|
||||
transport.config_write_select(VIRTIO_INPUT_CFG_EV_BITS, ev_type);
|
||||
let size = transport.config_read_size() as usize;
|
||||
@@ -622,8 +439,8 @@ fn run_device() -> Result<()> {
|
||||
debug!("virtio-inputd: device supports EV type {ev_type}");
|
||||
}
|
||||
}
|
||||
// Probe ABS bits to count absolute axes. absinfo is 5*u32=20 bytes;
|
||||
// a non-zero size response indicates the axis is supported.
|
||||
// Probe ABS bits to count absolute axes.
|
||||
let mut abs_count = 0u8;
|
||||
for abs in 0u8..64u8 {
|
||||
transport.config_write_select(VIRTIO_INPUT_CFG_ABS_INFO, abs);
|
||||
if transport.config_read_size() >= 20 {
|
||||
@@ -638,12 +455,12 @@ fn run_device() -> Result<()> {
|
||||
device_name, event_qcfg.size, abs_count
|
||||
);
|
||||
|
||||
// Open the inputd producer handle for event delivery.
|
||||
let mut producer = match ProducerHandle::new() {
|
||||
// Open the v6.0 evdev producer handle for event delivery.
|
||||
let mut producer = match EvdevProducerHandle::new() {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
warn!("virtio-inputd: failed to open /scheme/input/producer: {e} — events will be dropped");
|
||||
return Err(DriverError::Io(format!("inputd producer unavailable: {e}")));
|
||||
warn!("virtio-inputd: failed to open /scheme/input/evdev: {e} — events will be dropped");
|
||||
return Err(DriverError::Io(format!("evdev producer unavailable: {e}")));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -662,10 +479,9 @@ fn run_device() -> Result<()> {
|
||||
fn run_event_loop(
|
||||
transport: &mut VirtioModernPciTransport,
|
||||
event_queue: &mut InputEventQueue,
|
||||
producer: &mut ProducerHandle,
|
||||
producer: &mut EvdevProducerHandle,
|
||||
) {
|
||||
let mut pending_events: Vec<VirtioInputEvent> = Vec::with_capacity(64);
|
||||
let mut translated: Vec<Event> = Vec::with_capacity(16);
|
||||
loop {
|
||||
if transport.device_in_error_state() {
|
||||
warn!("virtio-inputd: device entered FAILED or NEEDS_RESET state, exiting");
|
||||
@@ -675,15 +491,8 @@ fn run_event_loop(
|
||||
event_queue.drain(&mut pending_events);
|
||||
if !pending_events.is_empty() {
|
||||
for ev in &pending_events {
|
||||
translated.clear();
|
||||
translated.extend(translate_event(ev));
|
||||
for event in &translated {
|
||||
if let Err(e) = producer.write_event(*event) {
|
||||
warn!("virtio-inputd: write_event failed: {e}");
|
||||
}
|
||||
}
|
||||
write_evdev_event(producer, ev);
|
||||
}
|
||||
pending_events.clear();
|
||||
if let Err(e) = transport.notify_queue(event_queue.index, event_queue.notify_off) {
|
||||
warn!("virtio-inputd: notify_queue failed: {e}");
|
||||
}
|
||||
@@ -704,4 +513,4 @@ fn main() {
|
||||
error!("virtio-inputd: fatal: {e:?}");
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user