Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ categories = ["os", "no-std", "hardware-support"]
axdriver_base = { path = "axdriver_base", version = "0.1" }
axdriver_block = { path = "axdriver_block", version = "0.1" }
axdriver_display = { path = "axdriver_display", version = "0.1" }
axdriver_input = { path = "axdriver_input", version = "0.1" }
axdriver_net = { path = "axdriver_net", version = "0.1" }
axdriver_pci = { path = "axdriver_pci", version = "0.1" }
axdriver_virtio = { path = "axdriver_virtio", version = "0.1" }
Expand Down
2 changes: 2 additions & 0 deletions axdriver_base/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ pub enum DeviceType {
Net,
/// Graphic display device (e.g., GPU)
Display,
/// Input device (e.g., keyboard, mouse).
Input,
}

/// The error type for device operation failures.
Expand Down
16 changes: 16 additions & 0 deletions axdriver_input/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "axdriver_input"
edition.workspace = true
description = "Common traits and types for input device drivers"
documentation = "https://arceos-org.github.io/axdriver_crates/axdriver_input"
keywords = ["arceos", "driver", "input"]
version.workspace = true
authors = ["mivik <[email protected]>"]
license.workspace = true
homepage.workspace = true
repository.workspace = true
categories.workspace = true

[dependencies]
axdriver_base = { workspace = true }
strum = { version = "0.27.2", default-features = false, features = ["derive"] }
101 changes: 101 additions & 0 deletions axdriver_input/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//! Common traits and types for input device drivers.

#![no_std]

#[doc(no_inline)]
pub use axdriver_base::{BaseDriverOps, DevError, DevResult, DeviceType};
use strum::FromRepr;

#[repr(u8)]
#[derive(Debug, Clone, Copy, Eq, PartialEq, FromRepr)]
pub enum EventType {
Synchronization = 0x00,
Key = 0x01,
Relative = 0x02,
Absolute = 0x03,
Misc = 0x04,
Switch = 0x05,
Led = 0x11,
Sound = 0x12,
ForceFeedback = 0x15,
}

impl EventType {
Copy link

Copilot AI Dec 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The MAX constant is set to 0x1f (31), but the largest EventType enum variant is ForceFeedback = 0x15 (21). This inconsistency could lead to incorrect behavior when code relies on this constant to represent the maximum event type value. Consider either setting MAX to 0x15 to match the actual maximum enum value, or adding a comment explaining why MAX is 0x1f if it represents a protocol-defined maximum rather than the enum's maximum value.

Suggested change
impl EventType {
impl EventType {
/// Protocol-defined maximum event type value (matches Linux `EV_MAX` = 0x1f),
/// which may be larger than the largest `EventType` variant.

Copilot uses AI. Check for mistakes.
pub const MAX: u8 = 0x1f;
pub const COUNT: u8 = Self::MAX + 1;

pub const fn bits_count(&self) -> usize {
match self {
EventType::Synchronization => 0x10,
EventType::Key => 0x300,
EventType::Relative => 0x10,
EventType::Absolute => 0x40,
EventType::Misc => 0x08,
EventType::Switch => 0x12,
EventType::Led => 0x10,
EventType::Sound => 0x08,
EventType::ForceFeedback => 0x80,
}
}
}

/// An input event, as defined by the Linux input subsystem.
#[repr(C)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Event {
pub event_type: u16,
pub code: u16,
pub value: u32,
}

#[repr(C)]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct InputDeviceId {
/// The bustype identifier.
pub bus_type: u16,
/// The vendor identifier.
pub vendor: u16,
/// The product identifier.
pub product: u16,
/// The version identifier.
pub version: u16,
}

#[repr(C)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct AbsInfo {
/// The minimum value for the axis.
pub min: u32,
/// The maximum value for the axis.
pub max: u32,
/// The fuzz value used to filter noise from the event stream.
pub fuzz: u32,
/// The size of the dead zone; values less than this will be reported as 0.
pub flat: u32,
/// The resolution for values reported for the axis.
pub res: u32,
}

/// Operations that require an input device driver to implement.
pub trait InputDriverOps: BaseDriverOps {
/// Returns the device ID of the input device.
fn device_id(&self) -> InputDeviceId;

/// Returns the physical location of the input device.
fn physical_location(&self) -> &str;

/// Returns a unique ID of the input device.
fn unique_id(&self) -> &str;

/// Fetches the bitmap of supported event codes for the specified event
/// type.
///
/// Returns true if the event type is supported and the bitmap is written to
/// `out`.
fn get_event_bits(&mut self, ty: EventType, out: &mut [u8]) -> DevResult<bool>;

/// Reads an input event from the device.
///
/// If no events are available, `Err(DevError::Again)` is returned.
fn read_event(&mut self) -> DevResult<Event>;
}
2 changes: 2 additions & 0 deletions axdriver_virtio/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ categories.workspace = true
alloc = ["virtio-drivers/alloc"]
block = ["axdriver_block"]
gpu = ["alloc", "axdriver_display"]
input = ["alloc", "axdriver_input"]
net = ["alloc", "axdriver_net"]

[dependencies]
axdriver_base = { workspace = true }
axdriver_block = { workspace = true, optional = true }
axdriver_display = { workspace = true, optional = true }
axdriver_input = { workspace = true, optional = true }
axdriver_net = { workspace = true, optional = true }
log = { workspace = true }
virtio-drivers = { version = "0.7.4", default-features = false }
88 changes: 88 additions & 0 deletions axdriver_virtio/src/input.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use alloc::{borrow::ToOwned, string::String};

use axdriver_base::{BaseDriverOps, DevError, DevResult, DeviceType};
use axdriver_input::{Event, EventType, InputDeviceId, InputDriverOps};
use virtio_drivers::{
Hal,
device::input::{InputConfigSelect, VirtIOInput as InnerDev},
transport::Transport,
};

use crate::as_dev_err;

/// The VirtIO Input device driver.
pub struct VirtIoInputDev<H: Hal, T: Transport> {
inner: InnerDev<H, T>,
device_id: InputDeviceId,
name: String,
}

unsafe impl<H: Hal, T: Transport> Send for VirtIoInputDev<H, T> {}
unsafe impl<H: Hal, T: Transport> Sync for VirtIoInputDev<H, T> {}

impl<H: Hal, T: Transport> VirtIoInputDev<H, T> {
/// Creates a new driver instance and initializes the device, or returns
/// an error if any step fails.
pub fn try_new(transport: T) -> DevResult<Self> {
let mut virtio = InnerDev::new(transport).map_err(as_dev_err)?;
let name = virtio.name().unwrap_or_else(|_| "<unknown>".to_owned());
let device_id = virtio.ids().map_err(as_dev_err)?;
let device_id = InputDeviceId {
bus_type: device_id.bustype,
vendor: device_id.vendor,
product: device_id.product,
version: device_id.version,
};

Ok(Self {
inner: virtio,
device_id,
name,
})
}
}

impl<H: Hal, T: Transport> BaseDriverOps for VirtIoInputDev<H, T> {
fn device_name(&self) -> &str {
&self.name
}

fn device_type(&self) -> DeviceType {
DeviceType::Input
}
}

impl<H: Hal, T: Transport> InputDriverOps for VirtIoInputDev<H, T> {
fn device_id(&self) -> InputDeviceId {
self.device_id
}

fn physical_location(&self) -> &str {
// TODO: unique physical location
"virtio0/input0"
}

fn unique_id(&self) -> &str {
// TODO: unique ID
"virtio"
}
Comment on lines +60 to +68
Copy link

Copilot AI Dec 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hard-coded strings "virtio0/input0" and "virtio" mean that all VirtIO input devices will report the same physical location and unique ID, making them indistinguishable from each other. This violates the intended purpose of these methods, which is to provide unique identification for each device instance. Consider generating unique identifiers, perhaps by incorporating the device's bus address or a counter into these strings.

Copilot uses AI. Check for mistakes.

fn get_event_bits(&mut self, ty: EventType, out: &mut [u8]) -> DevResult<bool> {
let read = self
.inner
.query_config_select(InputConfigSelect::EvBits, ty as u8, out);
Ok(read != 0)
}

fn read_event(&mut self) -> DevResult<Event> {
self.inner.ack_interrupt();
self.inner
.pop_pending_event()
.map(|e| Event {
event_type: e.event_type,
code: e.code,
value: e.value,
})
.ok_or(DevError::Again)
}
}
6 changes: 6 additions & 0 deletions axdriver_virtio/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ mod blk;
#[cfg(feature = "gpu")]
mod gpu;

#[cfg(feature = "input")]
mod input;
#[cfg(feature = "input")]
pub use self::input::VirtIoInputDev;

#[cfg(feature = "net")]
mod net;

Expand Down Expand Up @@ -84,6 +89,7 @@ const fn as_dev_type(t: VirtIoDevType) -> Option<DeviceType> {
Block => Some(DeviceType::Block),
Network => Some(DeviceType::Net),
GPU => Some(DeviceType::Display),
Input => Some(DeviceType::Input),
_ => None,
}
}
Expand Down