From 9ff9cf4718b828c6c5c211bc599ec1f794d03b50 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Sun, 28 May 2017 16:05:28 -0400 Subject: [PATCH] Initial port to nix --- Cargo.toml | 3 +- src/lib.rs | 77 ++++++++----------- src/raw.rs | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 248 insertions(+), 49 deletions(-) create mode 100644 src/raw.rs diff --git a/Cargo.toml b/Cargo.toml index 53c97a3..7403309 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,12 +8,11 @@ repository = "https://github.com/cmr/evdev" documentation = "https://docs.rs/evdev" [dependencies] -ioctl = "0.3.3" bitflags = "0.8.2" -errno = "0.2.3" libc = "0.2.22" fixedbitset = "0.1.6" num = "0.1.37" +nix = "0.8.1" [features] unstable = [] diff --git a/src/lib.rs b/src/lib.rs index 14737d8..0bf52fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,12 +36,14 @@ #[macro_use] extern crate bitflags; -extern crate ioctl; +#[macro_use] +extern crate nix; extern crate libc; -extern crate errno; extern crate fixedbitset; extern crate num; +pub mod raw; + use std::os::unix::io::*; use std::os::unix::ffi::*; use std::path::Path; @@ -50,41 +52,22 @@ use std::mem::size_of; use fixedbitset::FixedBitSet; use num::traits::WrappingSub; +use nix::Error; + pub use Key::*; pub use FFEffect::*; pub use Synchronization::*; +use raw::*; + #[link(name = "rt")] extern { fn clock_gettime(clkid: libc::c_int, res: *mut libc::timespec); } -#[derive(Debug)] -pub enum Error { - NulError(std::ffi::NulError), - LibcError(errno::Errno), - IoctlError(&'static str, errno::Errno), -} - -impl From for Error { - fn from(e: std::ffi::NulError) -> Error { - Error::NulError(e) - } -} - -impl From for Error { - fn from(e: errno::Errno) -> Error { - Error::LibcError(e) - } -} - macro_rules! do_ioctl { ($name:ident($($arg:expr),+)) => {{ - let rc = unsafe { ::ioctl::$name($($arg,)+) }; - if rc < 0 { - return Err(Error::IoctlError(stringify!($name), errno::errno())) - } - rc + unsafe { ::raw::$name($($arg,)+) }? }} } @@ -399,7 +382,7 @@ pub struct DeviceState { pub timestamp: libc::timeval, /// Set = key pressed pub key_vals: FixedBitSet, - pub abs_vals: Vec, + pub abs_vals: Vec, /// Set = switch enabled (closed) pub switch_vals: FixedBitSet, /// Set = LED lit @@ -412,7 +395,7 @@ pub struct Device { name: CString, phys: Option, uniq: Option, - id: ioctl::input_id, + id: input_id, props: Props, driver_version: (u8, u8, u8), key_bits: FixedBitSet, @@ -425,7 +408,7 @@ pub struct Device { ff_stat: FFStatus, rep: Repeat, snd: Sound, - pending_events: Vec, + pending_events: Vec, clock: libc::c_int, // pending_events[last_seen..] is the events that have occurred since the last sync. last_seen: usize, @@ -644,7 +627,7 @@ impl Device { &self.uniq } - pub fn input_id(&self) -> ioctl::input_id { + pub fn input_id(&self) -> input_id { self.id } @@ -695,14 +678,14 @@ impl Device { pub fn open(path: &AsRef) -> Result { let cstr = match CString::new(path.as_ref().as_os_str().as_bytes()) { Ok(s) => s, - Err(e) => return Err(Error::NulError(e)) + Err(e) => return Err(Error::InvalidPath), }; // FIXME: only need for writing is for setting LED values. re-evaluate always using RDWR // later. let fd = Fd(unsafe { libc::open(cstr.as_ptr(), libc::O_NONBLOCK | libc::O_RDWR | libc::O_CLOEXEC, 0) }); if *fd == -1 { std::mem::forget(fd); - return Err(Error::LibcError(errno::errno())) + return Err(Error::from_errno(::nix::Errno::last())); } let mut dev = Device { @@ -747,13 +730,13 @@ impl Device { unsafe { vec.set_len(dev_len as usize - 1) }; dev.name = CString::new(vec.clone()).unwrap(); - let phys_len = unsafe { ioctl::eviocgphys(*fd, vec.as_mut_ptr(), 255) }; + let phys_len = unsafe { eviocgphys(*fd, vec.as_mut_ptr(), 255) }?; if phys_len > 0 { unsafe { vec.set_len(phys_len as usize - 1) }; dev.phys = Some(CString::new(vec.clone()).unwrap()); } - let uniq_len = unsafe { ioctl::eviocguniq(*fd, vec.as_mut_ptr(), 255) }; + let uniq_len = unsafe { eviocguniq(*fd, vec.as_mut_ptr(), 255) }?; if uniq_len > 0 { unsafe { vec.set_len(uniq_len as usize - 1) }; dev.uniq = Some(CString::new(vec.clone()).unwrap()); @@ -783,7 +766,7 @@ impl Device { do_ioctl!(eviocgbit(*fd, ABSOLUTE.number(), 0x3f, &mut bits64 as *mut u64 as *mut u8)); println!("abs bits: {:b}", bits64); dev.abs = AbsoluteAxis::from_bits(bits64).expect("evdev: unexpected abs bits! report a bug"); - dev.state.abs_vals = vec![ioctl::input_absinfo::default(); 0x3f]; + dev.state.abs_vals = vec![input_absinfo::default(); 0x3f]; } if dev.ty.contains(SWITCH) { @@ -882,7 +865,7 @@ impl Device { for key_idx in 0..self.key_bits.len() { if self.key_bits.contains(key_idx) { if old_state.key_vals[key_idx] != self.state.key_vals[key_idx] { - self.pending_events.push(ioctl::input_event { + self.pending_events.push(raw::input_event { time: time, _type: KEY.number(), code: key_idx as u16, @@ -897,7 +880,7 @@ impl Device { let abs = 1 << idx; if self.abs.bits() & abs != 0 { if old_state.abs_vals[idx as usize] != self.state.abs_vals[idx as usize] { - self.pending_events.push(ioctl::input_event { + self.pending_events.push(raw::input_event { time: time, _type: ABSOLUTE.number(), code: idx as u16, @@ -912,7 +895,7 @@ impl Device { let sw = 1 << idx; if sw < SW_MAX.bits() && self.switch.bits() & sw == 1 { if old_state.switch_vals[idx as usize] != self.state.switch_vals[idx as usize] { - self.pending_events.push(ioctl::input_event { + self.pending_events.push(raw::input_event { time: time, _type: SWITCH.number(), code: idx as u16, @@ -927,7 +910,7 @@ impl Device { let led = 1 << idx; if led < LED_MAX.bits() && self.led.bits() & led == 1 { if old_state.led_vals[idx as usize] != self.state.led_vals[idx as usize] { - self.pending_events.push(ioctl::input_event { + self.pending_events.push(raw::input_event { time: time, _type: LED.number(), code: idx as u16, @@ -938,7 +921,7 @@ impl Device { } } - self.pending_events.push(ioctl::input_event { + self.pending_events.push(raw::input_event { time: time, _type: SYNCHRONIZATION.number(), code: SYN_REPORT as u16, @@ -956,18 +939,18 @@ impl Device { libc::read(self.fd, buf.as_mut_ptr() .offset(pre_len as isize) as *mut libc::c_void, - (size_of::() * (buf.capacity() - pre_len)) as libc::size_t) + (size_of::() * (buf.capacity() - pre_len)) as libc::size_t) }; if sz == -1 { - let errno = errno::errno(); - if errno != errno::Errno(libc::EAGAIN) { - return Err(Error::LibcError(errno)); + let errno = ::nix::Errno::last(); + if errno != ::nix::Errno::EAGAIN { + return Err(Error::from_errno(errno)); } else { break; } } else { unsafe { - buf.set_len(pre_len + (sz as usize / size_of::())); + buf.set_len(pre_len + (sz as usize / size_of::())); } } } @@ -1010,10 +993,10 @@ impl<'a> Drop for RawEvents<'a> { } impl<'a> Iterator for RawEvents<'a> { - type Item = ioctl::input_event; + type Item = raw::input_event; #[inline(always)] - fn next(&mut self) -> Option { + fn next(&mut self) -> Option { self.0.pending_events.pop() } } diff --git a/src/raw.rs b/src/raw.rs new file mode 100644 index 0000000..d2b0f16 --- /dev/null +++ b/src/raw.rs @@ -0,0 +1,217 @@ +ioctl!(read eviocgeffects with b'E', 0x84; ::libc::c_int); +ioctl!(read eviocgid with b'E', 0x02; /*struct*/ input_id); +ioctl!(read eviocgkeycode with b'E', 0x04; [::libc::c_uint; 2]); +ioctl!(read eviocgrep with b'E', 0x03; [::libc::c_uint; 2]); +ioctl!(read eviocgversion with b'E', 0x01; ::libc::c_int); +ioctl!(write eviocrmff with b'E', 0x81; ::libc::c_int); +// ioctl!(read eviocgkeycode_v2 with b'E', 0x04; /*struct*/ input_keymap_entry); +// TODO #define EVIOCSFF _IOC ( _IOC_WRITE , 'E' , 0x80 , sizeof ( struct ff_effect ) ) +ioctl!(write eviocskeycode with b'E', 0x04; [::libc::c_uint; 2]); +// ioctl!(write eviocskeycode_v2 with b'E', 0x04; /*struct*/ input_keymap_entry); +ioctl!(write eviocsrep with b'E', 0x03; [::libc::c_uint; 2]); + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct input_event { + pub time: ::libc::timeval, + pub _type: u16, + pub code: u16, + pub value: i32, +} +impl ::std::default::Default for input_event { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +impl ::std::fmt::Debug for input_event { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "input_event {{ time: {{ tv_sec: {}, tv_usec: {} }}, _type: {}, code: {}, value: {}", + self.time.tv_sec, self.time.tv_usec, self._type, self.code, self.value) + } +} + +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct input_id { + pub bustype: u16, + pub vendor: u16, + pub product: u16, + pub version: u16, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct ff_effect { + pub _type: u16, + pub id: i16, + pub direction: u16, + pub trigger: ff_trigger, + pub replay: ff_replay, + pub u: Union_Unnamed16, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct Union_Unnamed16 { + pub _bindgen_data_: [u64; 4usize], +} +impl Union_Unnamed16 { + pub unsafe fn constant(&mut self) -> *mut ff_constant_effect { + let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); + ::std::mem::transmute(raw.offset(0)) + } + pub unsafe fn ramp(&mut self) -> *mut ff_ramp_effect { + let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); + ::std::mem::transmute(raw.offset(0)) + } + pub unsafe fn periodic(&mut self) -> *mut ff_periodic_effect { + let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); + ::std::mem::transmute(raw.offset(0)) + } + pub unsafe fn condition(&mut self) + -> *mut [ff_condition_effect; 2usize] { + let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); + ::std::mem::transmute(raw.offset(0)) + } + pub unsafe fn rumble(&mut self) -> *mut ff_rumble_effect { + let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); + ::std::mem::transmute(raw.offset(0)) + } +} +impl ::std::default::Default for Union_Unnamed16 { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)] +pub struct input_absinfo { + pub value: i32, + pub minimum: i32, + pub maximum: i32, + pub fuzz: i32, + pub flat: i32, + pub resolution: i32, +} +impl ::std::default::Default for input_absinfo { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct input_keymap_entry { + pub flags: u8, + pub len: u8, + pub index: u16, + pub keycode: u32, + pub scancode: [u8; 32usize], +} +impl ::std::default::Default for input_keymap_entry { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct ff_replay { + pub length: u16, + pub delay: u16, +} +impl ::std::default::Default for ff_replay { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct ff_trigger { + pub button: u16, + pub interval: u16, +} +impl ::std::default::Default for ff_trigger { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct ff_envelope { + pub attack_length: u16, + pub attack_level: u16, + pub fade_length: u16, + pub fade_level: u16, +} +impl ::std::default::Default for ff_envelope { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct ff_constant_effect { + pub level: i16, + pub envelope: ff_envelope, +} +impl ::std::default::Default for ff_constant_effect { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct ff_ramp_effect { + pub start_level: i16, + pub end_level: i16, + pub envelope: ff_envelope, +} +impl ::std::default::Default for ff_ramp_effect { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct ff_condition_effect { + pub right_saturation: u16, + pub left_saturation: u16, + pub right_coeff: i16, + pub left_coeff: i16, + pub deadband: u16, + pub center: i16, +} +impl ::std::default::Default for ff_condition_effect { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone, Debug)] +#[allow(raw_pointer_derive)] +pub struct ff_periodic_effect { + pub waveform: u16, + pub period: u16, + pub magnitude: i16, + pub offset: i16, + pub phase: u16, + pub envelope: ff_envelope, + pub custom_len: u32, + pub custom_data: *mut i16, +} +impl ::std::default::Default for ff_periodic_effect { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct ff_rumble_effect { + pub strong_magnitude: u16, + pub weak_magnitude: u16, +} +impl ::std::default::Default for ff_rumble_effect { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} + +ioctl!(read buf eviocgname with b'E', 0x06; u8); +ioctl!(read buf eviocgphys with b'E', 0x07; u8); +ioctl!(read buf eviocguniq with b'E', 0x08; u8); +ioctl!(read buf eviocgprop with b'E', 0x09; u8); +ioctl!(read buf eviocgmtslots with b'E', 0x0a; u8); +ioctl!(read buf eviocgkey with b'E', 0x18; u8); +ioctl!(read buf eviocgled with b'E', 0x19; u8); +ioctl!(read buf eviocgsnd with b'E', 0x1a; u8); +ioctl!(read buf eviocgsw with b'E', 0x1b; u8); + +ioctl!(write eviocsff with b'E', 0x80; ff_effect); +ioctl!(write eviocgrab with b'E', 0x90; ::libc::c_int); +ioctl!(write eviocrevoke with b'E', 0x91; ::libc::c_int); +ioctl!(write eviocsclockid with b'E', 0xa0; ::libc::c_int); + +pub unsafe fn eviocgbit(fd: ::libc::c_int, ev: u32, len: ::libc::c_int, buf: *mut u8) -> ::nix::Result { + convert_ioctl_res!(::nix::sys::ioctl::ioctl(fd, ior!(b'E', 0x20 + ev, len) as ::libc::c_ulong, buf)) +} + +pub unsafe fn eviocgabs(fd: ::libc::c_int, abs: u32, buf: *mut input_absinfo) -> ::nix::Result { + convert_ioctl_res!(::nix::sys::ioctl::ioctl(fd, ior!(b'E', 0x40 + abs, ::std::mem::size_of::()) as ::libc::c_ulong, buf)) +} +