use alloc::{format, sync::Arc};
use core::{
any::Any,
sync::atomic::{AtomicU32, Ordering},
task::Context,
time::Duration,
};
static EVENT_DEVICE_COUNT: AtomicU32 = AtomicU32::new(0);
pub fn input_device_count() -> u32 {
EVENT_DEVICE_COUNT.load(Ordering::Acquire)
}
#[allow(unused_imports)]
use ax_driver::prelude::{
AbsInfo, AxInputDevice, BaseDriverOps, DevError, Event, EventType, InputDeviceId,
InputDriverOps,
};
use ax_errno::{AxError, AxResult};
use ax_hal::time::wall_time;
use ax_sync::Mutex;
use axfs_ng_vfs::{DeviceId, NodeFlags, NodeType, VfsResult};
use axpoll::{IoEvents, Pollable};
use bitmaps::Bitmap;
use linux_raw_sys::{
general::{__kernel_old_time_t, __kernel_suseconds_t},
ioctl::{EVIOCGID, EVIOCGRAB, EVIOCGVERSION},
};
use zerocopy::{FromBytes, Immutable, IntoBytes};
use crate::{
mm::UserPtr,
pseudofs::{Device, DeviceOps, DirMapping, SimpleFs},
};
const KEY_CNT: usize = EventType::Key.bits_count();
struct Inner {
device: AxInputDevice,
read_ahead: Option<(Duration, Event)>,
key_state: Bitmap<KEY_CNT>,
}
impl Inner {
fn has_event(&mut self) -> bool {
if self.read_ahead.is_none() {
match self.device.read_event() {
Ok(event) => {
if event.event_type == EventType::Key as u16 {
if event.value == 0 {
self.key_state.set(event.code as usize, false);
} else if event.value == 1 {
self.key_state.set(event.code as usize, true);
}
}
self.read_ahead = Some((wall_time(), event));
}
Err(DevError::Again) => {}
Err(err) => {
warn!("Failed to read event: {err:?}");
}
}
}
self.read_ahead.is_some()
}
}
const INPUT_PROP_CNT: usize = 0x20;
const INPUT_PROP_POINTER: usize = 0x00;
const INPUT_PROP_DIRECT: usize = 0x01;
#[repr(C)]
#[derive(Default, Clone, Copy, FromBytes, IntoBytes, Immutable)]
struct InputAbsInfo {
value: i32,
minimum: i32,
maximum: i32,
fuzz: i32,
flat: i32,
resolution: i32,
}
const ABS_MAX: usize = 0x40;
pub struct EventDev {
inner: Mutex<Inner>,
ev_bits: Bitmap<{ EventType::COUNT as usize }>,
prop_bits: [u8; INPUT_PROP_CNT.div_ceil(8)],
abs_bits: [u8; ABS_MAX.div_ceil(8)],
}
impl EventDev {
pub fn new(mut device: AxInputDevice) -> Self {
let mut ev_bits = Bitmap::new();
for i in 0..EventType::COUNT {
let Some(ty) = EventType::from_repr(i) else {
continue;
};
if device
.get_event_bits(ty, &mut [])
.is_ok_and(|success| success)
{
ev_bits.set(i as usize, true);
}
}
let mut prop_bits = [0u8; INPUT_PROP_CNT.div_ceil(8)];
let prop_bits_reliable = match device.get_prop_bits(&mut prop_bits) {
Ok(_) => true,
Err(err) => {
warn!("Failed to get input property bits: {err:?}");
false
}
};
let is_touchscreen = prop_bits[INPUT_PROP_DIRECT / 8] & (1 << (INPUT_PROP_DIRECT % 8)) != 0;
let has_axes =
ev_bits.get(EventType::Relative as usize) || ev_bits.get(EventType::Absolute as usize);
if prop_bits_reliable && has_axes && !is_touchscreen {
prop_bits[INPUT_PROP_POINTER / 8] |= 1 << (INPUT_PROP_POINTER % 8);
}
let mut abs_bits = [0u8; ABS_MAX.div_ceil(8)];
if ev_bits.get(EventType::Absolute as usize) {
let _ = device.get_event_bits(EventType::Absolute, &mut abs_bits);
}
Self {
inner: Mutex::new(Inner {
device,
read_ahead: None,
key_state: Bitmap::new(),
}),
ev_bits,
prop_bits,
abs_bits,
}
}
fn axis_supported(&self, axis: u8) -> bool {
let bit = axis as usize;
if bit >= ABS_MAX {
return false;
}
self.abs_bits[bit / 8] & (1 << (bit % 8)) != 0
}
fn get_event_bits(&self, arg: usize, size: usize, ty: u8) -> AxResult<usize> {
let bits = UserPtr::<u8>::from(arg).get_as_mut_slice(size)?;
if ty == 0 {
Ok(copy_bytes(self.ev_bits.as_bytes(), bits))
} else {
let ty = EventType::from_repr(ty).ok_or(AxError::InvalidInput)?;
match self.inner.lock().device.get_event_bits(ty, bits) {
Ok(true) => {}
Ok(false) => {
debug!("No events for {ty:?}");
}
Err(err) => {
warn!("Failed to get event bits: {err:?}");
}
}
Ok(bits.len().min(ty.bits_count().div_ceil(8)))
}
}
}
fn copy_bytes(src: &[u8], dst: &mut [u8]) -> usize {
let len = src.len().min(dst.len());
dst[..len].copy_from_slice(&src[..len]);
len
}
fn return_str(arg: usize, size: usize, s: &str) -> AxResult<usize> {
let slice = UserPtr::<u8>::from(arg).get_as_mut_slice(size)?;
Ok(copy_bytes(s.as_bytes(), slice))
}
fn dev_error_to_ax_error(err: DevError) -> AxError {
match err {
DevError::AlreadyExists => AxError::AlreadyExists,
DevError::Again => AxError::WouldBlock,
DevError::BadState => AxError::BadState,
DevError::InvalidParam | DevError::Unsupported => AxError::InvalidInput,
DevError::Io => AxError::Io,
DevError::NoMemory => AxError::NoMemory,
DevError::ResourceBusy => AxError::ResourceBusy,
}
}
fn return_zero_bits(arg: usize, size: usize, bits: usize) -> AxResult<usize> {
let slice = UserPtr::<u8>::from(arg).get_as_mut_slice(size)?;
let len = bits.div_ceil(8).min(slice.len());
slice[..len].fill(0);
Ok(len)
}
#[repr(C)]
#[derive(FromBytes, IntoBytes, Immutable)]
pub struct KernelTimeval {
pub tv_sec: __kernel_old_time_t,
pub tv_usec: __kernel_suseconds_t,
}
#[repr(C)]
#[derive(FromBytes, IntoBytes, Immutable)]
struct InputEvent {
time: KernelTimeval,
event_type: u16,
code: u16,
value: i32,
}
#[unsafe(no_mangle)]
#[inline(never)]
pub extern "C" fn ongkey() {
core::hint::black_box(());
}
impl DeviceOps for EventDev {
fn read_at(&self, buf: &mut [u8], _offset: u64) -> VfsResult<usize> {
if buf.is_empty() {
return Ok(0);
}
if buf.len() < size_of::<InputEvent>() {
return Err(AxError::InvalidInput);
}
let mut read = 0;
let mut inner = self.inner.lock();
for out in buf.chunks_exact_mut(size_of::<InputEvent>()) {
if !inner.has_event() {
break;
}
let Some((time, event)) = inner.read_ahead.take() else {
break;
};
let input_event = InputEvent {
time: KernelTimeval {
tv_sec: time.as_secs() as _,
tv_usec: time.subsec_micros() as _,
},
event_type: event.event_type,
code: event.code,
value: event.value as _,
};
out.copy_from_slice(input_event.as_bytes());
read += out.len();
}
if read == 0 {
Err(AxError::WouldBlock)
} else {
Ok(read)
}
}
fn write_at(&self, _buf: &[u8], _offset: u64) -> VfsResult<usize> {
Err(AxError::InvalidInput)
}
fn flags(&self) -> NodeFlags {
NodeFlags::NON_CACHEABLE | NodeFlags::STREAM
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_pollable(&self) -> Option<&dyn Pollable> {
Some(self)
}
fn ioctl(&self, cmd: u32, arg: usize) -> VfsResult<usize> {
match cmd {
EVIOCGVERSION => {
*UserPtr::<u32>::from(arg).get_as_mut()? = 0x10001;
Ok(0)
}
EVIOCGID => {
*UserPtr::<InputDeviceId>::from(arg).get_as_mut()? =
self.inner.lock().device.device_id();
Ok(0)
}
EVIOCGRAB => Ok(0),
other => {
let mut tmp = other;
let nr = (tmp & 0xff) as u8;
tmp >>= 8;
let ty = (tmp & 0xff) as u8;
tmp >>= 8;
let size = (tmp & 0x3fff) as usize;
tmp >>= 14;
let dir = tmp & 0x3;
if ty != b'E' {
warn!("unknown ioctl for evdev: {cmd} {arg}");
return Err(AxError::InvalidInput);
}
match dir {
1 => return Err(AxError::InvalidInput),
2 => {
#[allow(clippy::single_match)]
match nr {
0x06 => {
return return_str(
arg,
size,
self.inner.lock().device.device_name(),
);
}
0x07 => {
return return_str(
arg,
size,
self.inner.lock().device.physical_location(),
);
}
0x08 => {
return return_str(arg, size, self.inner.lock().device.unique_id());
}
0x09 => {
let slice = UserPtr::<u8>::from(arg).get_as_mut_slice(size)?;
return Ok(copy_bytes(&self.prop_bits, slice));
}
0x18 => {
let bits = UserPtr::<u8>::from(arg).get_as_mut_slice(size)?;
return Ok(copy_bytes(
self.inner.lock().key_state.as_bytes(),
bits,
));
}
0x19 => {
return return_zero_bits(arg, size, EventType::Led.bits_count());
}
0x1a => {
return return_zero_bits(arg, size, EventType::Sound.bits_count());
}
0x1b => {
return return_zero_bits(arg, size, EventType::Switch.bits_count());
}
_ => {}
}
if nr & !EventType::MAX == EventType::COUNT {
return self.get_event_bits(arg, size, nr & EventType::MAX);
}
const ABS_CNT: u8 = 0x40;
if nr & !(ABS_CNT - 1) == ABS_CNT {
if size < size_of::<InputAbsInfo>() {
return Err(AxError::InvalidInput);
}
let axis = nr & (ABS_CNT - 1);
if !self.axis_supported(axis) {
return Err(AxError::InvalidInput);
}
let info = match self.inner.lock().device.get_abs_info(axis) {
Ok(info) => info,
Err(err) => return Err(dev_error_to_ax_error(err)),
};
let abs = InputAbsInfo {
value: 0,
minimum: info.min as i32,
maximum: info.max as i32,
fuzz: info.fuzz as i32,
flat: info.flat as i32,
resolution: info.res as i32,
};
let bytes = abs.as_bytes();
let slice = UserPtr::<u8>::from(arg).get_as_mut_slice(size)?;
slice[..bytes.len()].copy_from_slice(bytes);
return Ok(bytes.len());
}
return Err(AxError::InvalidInput);
}
_ => {}
}
Err(AxError::InvalidInput)
}
}
}
}
impl Pollable for EventDev {
fn poll(&self) -> IoEvents {
let mut events = IoEvents::empty();
events.set(IoEvents::IN, self.inner.lock().has_event());
events
}
fn register(&self, context: &mut Context<'_>, events: IoEvents) {
if events.contains(IoEvents::IN) {
context.waker().wake_by_ref();
}
}
}
pub fn input_devices(fs: Arc<SimpleFs>) -> DirMapping {
let mut inputs = DirMapping::new();
let mut mice_alias: Option<Arc<EventDev>> = None;
let mut input_id: u32 = 0;
let input_devices = ax_input::take_inputs();
for mut device in input_devices.into_iter() {
let mut keys = [0; 0x300usize.div_ceil(8)];
assert!(device.get_event_bits(EventType::Key, &mut keys).unwrap());
const BTN_MOUSE: usize = 0x110;
let is_mouse = keys[BTN_MOUSE / 8] & (1 << (BTN_MOUSE % 8)) != 0;
let event_dev = Arc::new(EventDev::new(device));
let dev = Device::new(
fs.clone(),
NodeType::CharacterDevice,
DeviceId::new(13, 64 + input_id),
event_dev.clone(),
);
inputs.add(format!("event{input_id}"), dev);
input_id += 1;
if is_mouse && mice_alias.is_none() {
mice_alias = Some(event_dev);
}
}
if let Some(event_dev) = mice_alias {
inputs.add(
"mice",
Device::new(
fs,
NodeType::CharacterDevice,
DeviceId::new(13, 63),
event_dev,
),
);
}
EVENT_DEVICE_COUNT.store(input_id, Ordering::Release);
inputs
}