1use crate::input_device::InputDeviceInfoHandle;
6use crossbeam::queue::SegQueue;
7use fuchsia_inspect::Inspector;
8use futures::FutureExt;
9use starnix_core::fileops_impl_nonseekable;
10use starnix_core::mm::{MemoryAccessor, MemoryAccessorExt};
11use starnix_core::task::{CurrentTask, EventHandler, WaitCanceler, WaitQueue, Waiter};
12use starnix_core::vfs::buffers::{InputBuffer, OutputBuffer};
13use starnix_core::vfs::{FileObject, FileOps, fileops_impl_noop_sync};
14use starnix_logging::{log_info, track_stub};
15use starnix_sync::{InputFileInputFileLock, LockDepMutex};
16use starnix_syscalls::{SUCCESS, SyscallArg, SyscallResult};
17use starnix_types::time::duration_from_timeval;
18use starnix_uapi::errors::Errno;
19use starnix_uapi::open_flags::OpenFlags;
20use starnix_uapi::user_address::{ArchSpecific, MultiArchUserRef, UserAddress, UserRef};
21use starnix_uapi::vfs::FdEvents;
22use starnix_uapi::{
23 ABS_CNT, ABS_MT_POSITION_X, ABS_MT_POSITION_Y, ABS_MT_SLOT, ABS_MT_TRACKING_ID, BTN_EXTRA,
24 BTN_LEFT, BTN_MIDDLE, BTN_MISC, BTN_RIGHT, BTN_SIDE, BTN_TOUCH, EV_CNT, FF_CNT, INPUT_PROP_CNT,
25 INPUT_PROP_DIRECT, INPUT_PROP_POINTER, KEY_CNT, KEY_DOWN, KEY_LEFT, KEY_OK, KEY_POWER,
26 KEY_RIGHT, KEY_SLEEP, KEY_UP, KEY_VOLUMEDOWN, KEY_VOLUMEUP, LED_CNT, MSC_CNT, REL_CNT,
27 REL_HWHEEL, REL_WHEEL, REL_X, REL_Y, SW_CNT, errno, error, uapi,
28};
29use std::sync::atomic::{AtomicBool, AtomicI64, AtomicU64, Ordering};
30use std::sync::{Arc, Weak};
31use zerocopy::IntoBytes as _; uapi::check_arch_independent_layout! {
34 input_id {}
35 input_absinfo {}
36}
37
38type InputEventPtr = MultiArchUserRef<uapi::input_event, uapi::arch32::input_event>;
39
40pub struct InputFileStatus {
41 pub fidl_events_received_count: AtomicU64,
51
52 pub fidl_events_ignored_count: AtomicU64,
54
55 pub fidl_events_unexpected_count: AtomicU64,
59
60 pub fidl_events_converted_count: AtomicU64,
62
63 pub uapi_events_generated_count: AtomicU64,
65
66 pub last_generated_uapi_event_timestamp_ns: AtomicI64,
68
69 pub uapi_events_read_count: AtomicU64,
71
72 pub last_read_uapi_event_timestamp_ns: AtomicI64,
74
75 pub fd_read_count: AtomicU64,
77
78 pub fd_notify_count: AtomicU64,
80
81 pub opened_without_nonblock: AtomicBool,
83
84 pub open_timestamp_ns: AtomicI64,
86
87 pub closed: AtomicBool,
89
90 pub close_timestamp_ns: AtomicI64,
92
93 pub input_file: LockDepMutex<Weak<InputFile>, InputFileInputFileLock>,
95}
96
97impl InputFileStatus {
98 fn new(node: &fuchsia_inspect::Node) -> Arc<Self> {
99 let status = Arc::new(Self {
100 fidl_events_received_count: AtomicU64::new(0),
101 fidl_events_ignored_count: AtomicU64::new(0),
102 fidl_events_unexpected_count: AtomicU64::new(0),
103 fidl_events_converted_count: AtomicU64::new(0),
104 uapi_events_generated_count: AtomicU64::new(0),
105 last_generated_uapi_event_timestamp_ns: AtomicI64::new(0),
106 uapi_events_read_count: AtomicU64::new(0),
107 last_read_uapi_event_timestamp_ns: AtomicI64::new(0),
108 fd_read_count: AtomicU64::new(0),
109 fd_notify_count: AtomicU64::new(0),
110 opened_without_nonblock: AtomicBool::new(false),
111 open_timestamp_ns: AtomicI64::new(0),
112 closed: AtomicBool::new(false),
113 close_timestamp_ns: AtomicI64::new(0),
114 input_file: Default::default(),
115 });
116
117 let cloned_status = status.clone();
118 node.record_lazy_values("status", move || {
119 let cloned_cloned_status = cloned_status.clone();
120 async move {
121 let is_dropped = cloned_cloned_status.input_file.lock().upgrade().is_none();
122 if is_dropped && !cloned_cloned_status.closed.load(Ordering::Relaxed) {
123 cloned_cloned_status.closed.store(true, Ordering::Relaxed);
124 }
125
126 let inspector = Inspector::default();
127 let root = inspector.root();
128 root.record_uint(
129 "fd_read_count",
130 cloned_cloned_status.fd_read_count.load(Ordering::Relaxed),
131 );
132 root.record_uint(
133 "fd_notify_count",
134 cloned_cloned_status.fd_notify_count.load(Ordering::Relaxed),
135 );
136 root.record_bool(
137 "opened_without_nonblock",
138 cloned_cloned_status.opened_without_nonblock.load(Ordering::Relaxed),
139 );
140 root.record_int(
141 "open_timestamp_ns",
142 cloned_cloned_status.open_timestamp_ns.load(Ordering::Relaxed),
143 );
144 root.record_bool("closed", cloned_cloned_status.closed.load(Ordering::Relaxed));
145 root.record_int(
146 "close_timestamp_ns",
147 cloned_cloned_status.close_timestamp_ns.load(Ordering::Relaxed),
148 );
149 root.record_uint(
150 "fidl_events_received_count",
151 cloned_cloned_status.fidl_events_received_count.load(Ordering::Relaxed),
152 );
153 root.record_uint(
154 "fidl_events_ignored_count",
155 cloned_cloned_status.fidl_events_ignored_count.load(Ordering::Relaxed),
156 );
157 root.record_uint(
158 "fidl_events_unexpected_count",
159 cloned_cloned_status.fidl_events_unexpected_count.load(Ordering::Relaxed),
160 );
161 root.record_uint(
162 "fidl_events_converted_count",
163 cloned_cloned_status.fidl_events_converted_count.load(Ordering::Relaxed),
164 );
165 root.record_uint(
166 "uapi_events_generated_count",
167 cloned_cloned_status.uapi_events_generated_count.load(Ordering::Relaxed),
168 );
169 root.record_int(
170 "last_generated_uapi_event_timestamp_ns",
171 cloned_cloned_status
172 .last_generated_uapi_event_timestamp_ns
173 .load(Ordering::Relaxed),
174 );
175 root.record_uint(
176 "uapi_events_read_count",
177 cloned_cloned_status.uapi_events_read_count.load(Ordering::Relaxed),
178 );
179 root.record_int(
180 "last_read_uapi_event_timestamp_ns",
181 cloned_cloned_status.last_read_uapi_event_timestamp_ns.load(Ordering::Relaxed),
182 );
183 Ok(inspector)
184 }
185 .boxed()
186 });
187
188 status
189 }
190
191 pub fn count_received_events(&self, count: u64) {
192 self.fidl_events_received_count.fetch_add(count, Ordering::Relaxed);
193 }
194
195 pub fn count_ignored_events(&self, count: u64) {
196 self.fidl_events_ignored_count.fetch_add(count, Ordering::Relaxed);
197 }
198
199 pub fn count_unexpected_events(&self, count: u64) {
200 self.fidl_events_unexpected_count.fetch_add(count, Ordering::Relaxed);
201 }
202
203 pub fn count_converted_events(&self, count: u64) {
204 self.fidl_events_converted_count.fetch_add(count, Ordering::Relaxed);
205 }
206
207 pub fn count_generated_events(&self, count: u64, event_time_ns: i64) {
208 self.uapi_events_generated_count.fetch_add(count, Ordering::Relaxed);
209 self.last_generated_uapi_event_timestamp_ns.store(event_time_ns, Ordering::Relaxed);
210 }
211
212 pub fn count_read_events(&self, count: u64, event_time_ns: i64) {
213 self.uapi_events_read_count.fetch_add(count, Ordering::Relaxed);
214 self.last_read_uapi_event_timestamp_ns.store(event_time_ns, Ordering::Relaxed);
215 }
216
217 pub fn count_fd_read_calls(&self) {
218 self.fd_read_count.fetch_add(1, Ordering::Relaxed);
219 }
220
221 pub fn count_fd_notify_calls(&self) {
222 self.fd_notify_count.fetch_add(1, Ordering::Relaxed);
223 }
224
225 pub fn set_opened_without_nonblock(&self) {
226 self.opened_without_nonblock.store(true, Ordering::Relaxed);
227 }
228
229 pub fn set_open_timestamp(&self, timestamp: i64) {
230 self.open_timestamp_ns.store(timestamp, Ordering::Relaxed);
231 }
232
233 pub fn set_closed(&self) {
234 self.closed.store(true, Ordering::Relaxed);
235 }
236
237 pub fn set_closed_timestamp(&self, timestamp: i64) {
238 self.close_timestamp_ns.store(timestamp, Ordering::Relaxed);
239 }
240}
241
242pub struct InputFile {
243 driver_version: u32,
244 info: InputDeviceInfoHandle,
245 supported_event_types: BitSet<{ min_bytes(EV_CNT) }>,
246 supported_keys: BitSet<{ min_bytes(KEY_CNT) }>,
247 supported_position_attributes: BitSet<{ min_bytes(ABS_CNT) }>, supported_motion_attributes: BitSet<{ min_bytes(REL_CNT) }>, supported_switches: BitSet<{ min_bytes(SW_CNT) }>,
250 supported_leds: BitSet<{ min_bytes(LED_CNT) }>,
251 supported_haptics: BitSet<{ min_bytes(FF_CNT) }>, supported_misc_features: BitSet<{ min_bytes(MSC_CNT) }>,
253 properties: BitSet<{ min_bytes(INPUT_PROP_CNT) }>,
254 mt_slot_axis_info: uapi::input_absinfo,
255 mt_tracking_id_axis_info: uapi::input_absinfo,
256 x_axis_info: uapi::input_absinfo,
257 y_axis_info: uapi::input_absinfo,
258 events: SegQueue<LinuxEventWithTraceId>,
259 waiters: WaitQueue,
260 pub inspect_status: Option<Arc<InputFileStatus>>,
263}
264
265pub struct LinuxEventWithTraceId {
266 pub event: uapi::input_event,
267 pub trace_id: Option<fuchsia_trace::Id>,
268}
269
270impl LinuxEventWithTraceId {
271 pub fn new(event: uapi::input_event) -> Self {
272 match event.type_ as u32 {
273 uapi::EV_SYN => {
274 let trace_id = fuchsia_trace::Id::new();
275 fuchsia_trace::duration!("input", "linux_event_create");
276 fuchsia_trace::flow_begin!("input", "linux_event", trace_id);
277 LinuxEventWithTraceId { event: event, trace_id: Some(trace_id) }
278 }
279 _ => LinuxEventWithTraceId { event: event, trace_id: None },
282 }
283 }
284}
285
286const fn min_bytes(n_bits: u32) -> usize {
288 ((n_bits as usize) + 7) / 8
289}
290
291fn keyboard_properties() -> BitSet<{ min_bytes(INPUT_PROP_CNT) }> {
293 let mut attrs = BitSet::new();
294 attrs.set(INPUT_PROP_DIRECT);
295 attrs
296}
297
298fn touch_key_attributes() -> BitSet<{ min_bytes(KEY_CNT) }> {
300 let mut attrs = BitSet::new();
301 attrs.set(BTN_TOUCH);
302 attrs.set(BTN_MISC); attrs.set(KEY_SLEEP);
304 attrs.set(KEY_UP);
305 attrs.set(KEY_LEFT);
306 attrs.set(KEY_RIGHT);
307 attrs.set(KEY_DOWN);
308
309 attrs
310}
311
312fn touch_position_attributes() -> BitSet<{ min_bytes(ABS_CNT) }> {
314 let mut attrs = BitSet::new();
315 attrs.set(ABS_MT_SLOT);
316 attrs.set(ABS_MT_TRACKING_ID);
317 attrs.set(ABS_MT_POSITION_X);
318 attrs.set(ABS_MT_POSITION_Y);
319 attrs
320}
321
322fn touch_properties() -> BitSet<{ min_bytes(INPUT_PROP_CNT) }> {
324 let mut attrs = BitSet::new();
325 attrs.set(INPUT_PROP_DIRECT);
326 attrs
327}
328
329fn keyboard_key_attributes() -> BitSet<{ min_bytes(KEY_CNT) }> {
331 let mut attrs = BitSet::new();
332 for keycode in starnix_modules_input_event_conversion::keymap::KEY_MAP.all_linux_keycodes() {
333 if keycode >= BTN_MISC && keycode < KEY_OK {
338 continue;
339 }
340 if (keycode as usize) < KEY_CNT as usize {
341 attrs.set(keycode);
342 }
343 }
344 attrs.set(BTN_MISC);
345 attrs.set(KEY_POWER);
346 attrs.set(KEY_VOLUMEUP);
347 attrs.set(KEY_VOLUMEDOWN);
348 attrs
349}
350
351fn keyboard_position_attributes() -> BitSet<{ min_bytes(ABS_CNT) }> {
353 BitSet::new()
354}
355
356fn mouse_key_attributes() -> BitSet<{ min_bytes(KEY_CNT) }> {
358 let mut attrs = BitSet::new();
359 attrs.set(BTN_LEFT);
363 attrs.set(BTN_RIGHT);
364 attrs.set(BTN_MIDDLE);
365 attrs.set(BTN_SIDE);
366 attrs.set(BTN_EXTRA);
367 attrs
368}
369
370fn mouse_motion_attributes() -> BitSet<{ min_bytes(REL_CNT) }> {
372 let mut attrs = BitSet::new();
373 attrs.set(REL_X);
374 attrs.set(REL_Y);
375 attrs.set(REL_WHEEL);
376 attrs.set(REL_HWHEEL);
377 attrs
378}
379
380fn mouse_properties() -> BitSet<{ min_bytes(INPUT_PROP_CNT) }> {
382 let mut attrs = BitSet::new();
383 attrs.set(INPUT_PROP_POINTER);
386 attrs
387}
388
389impl InputFile {
390 const DRIVER_VERSION: u32 = 0;
396
397 pub fn new_touch(
405 info: InputDeviceInfoHandle,
406 width: i32,
407 height: i32,
408 node: &fuchsia_inspect::Node,
409 ) -> Self {
410 Self {
414 driver_version: Self::DRIVER_VERSION,
415 info,
416 supported_event_types: BitSet::list([uapi::EV_ABS]),
417 supported_keys: touch_key_attributes(),
418 supported_position_attributes: touch_position_attributes(),
419 supported_motion_attributes: BitSet::new(), supported_switches: BitSet::new(), supported_leds: BitSet::new(), supported_haptics: BitSet::new(), supported_misc_features: BitSet::new(), properties: touch_properties(),
425 mt_slot_axis_info: uapi::input_absinfo {
426 minimum: 0,
427 maximum: 10,
428 ..uapi::input_absinfo::default()
429 },
430 mt_tracking_id_axis_info: uapi::input_absinfo {
431 minimum: 0,
432 maximum: i32::MAX,
433 ..uapi::input_absinfo::default()
434 },
435 x_axis_info: uapi::input_absinfo {
436 minimum: 0,
437 maximum: i32::from(width),
438 ..uapi::input_absinfo::default()
441 },
442 y_axis_info: uapi::input_absinfo {
443 minimum: 0,
444 maximum: i32::from(height),
445 ..uapi::input_absinfo::default()
448 },
449 events: SegQueue::new(),
450 waiters: WaitQueue::default(),
451 inspect_status: Some(InputFileStatus::new(node)),
452 }
453 }
454
455 pub fn new_keyboard(info: InputDeviceInfoHandle, node: &fuchsia_inspect::Node) -> Self {
461 Self {
462 driver_version: Self::DRIVER_VERSION,
463 info,
464 supported_event_types: BitSet::list([uapi::EV_KEY]),
465 supported_keys: keyboard_key_attributes(),
466 supported_position_attributes: keyboard_position_attributes(),
467 supported_motion_attributes: BitSet::new(), supported_switches: BitSet::new(), supported_leds: BitSet::new(), supported_haptics: BitSet::new(), supported_misc_features: BitSet::new(), properties: keyboard_properties(),
473 mt_slot_axis_info: uapi::input_absinfo::default(),
474 mt_tracking_id_axis_info: uapi::input_absinfo::default(),
475 x_axis_info: uapi::input_absinfo::default(),
476 y_axis_info: uapi::input_absinfo::default(),
477 events: SegQueue::new(),
478 waiters: WaitQueue::default(),
479 inspect_status: Some(InputFileStatus::new(node)),
480 }
481 }
482
483 pub fn new_mouse(info: InputDeviceInfoHandle, node: &fuchsia_inspect::Node) -> Self {
489 Self {
490 driver_version: Self::DRIVER_VERSION,
491 info,
492 supported_event_types: BitSet::list([uapi::EV_KEY, uapi::EV_REL]),
496 supported_keys: mouse_key_attributes(),
497 supported_position_attributes: BitSet::new(), supported_motion_attributes: mouse_motion_attributes(),
499 supported_switches: BitSet::new(), supported_leds: BitSet::new(), supported_haptics: BitSet::new(), supported_misc_features: BitSet::new(), properties: mouse_properties(),
504 mt_slot_axis_info: uapi::input_absinfo::default(),
505 mt_tracking_id_axis_info: uapi::input_absinfo::default(),
506 x_axis_info: uapi::input_absinfo::default(),
507 y_axis_info: uapi::input_absinfo::default(),
508 events: SegQueue::new(),
509 waiters: WaitQueue::default(),
510 inspect_status: Some(InputFileStatus::new(node)),
511 }
512 }
513
514 pub fn init_inspect_status(self: &Arc<Self>) {
515 if let Some(inspect) = &self.inspect_status {
516 *inspect.input_file.lock() = Arc::downgrade(self);
517 }
518 }
519
520 pub fn add_events(&self, events: Vec<uapi::input_event>) {
521 if events.is_empty() {
522 return;
523 }
524 if let Some(inspect) = &self.inspect_status {
525 inspect.count_fd_notify_calls();
526 }
527 for event in events {
528 self.events.push(LinuxEventWithTraceId::new(event));
529 }
530 self.waiters.notify_fd_events(FdEvents::POLLIN);
531 }
532
533 pub fn read_events(&self, limit: usize) -> Vec<LinuxEventWithTraceId> {
534 if let Some(inspect) = &self.inspect_status {
535 inspect.count_fd_read_calls();
536 }
537 let mut events = vec![];
538 for _ in 0..limit {
539 if let Some(event) = self.events.pop() {
540 events.push(event);
541 } else {
542 break;
543 }
544 }
545 events
549 }
550}
551
552pub(crate) const EVIOC_VAR_LEN_MASK: u32 = !(uapi::_IOC_SIZEMASK << uapi::_IOC_SIZESHIFT);
556
557pub(crate) const EVIOCGNAME_BASE: u32 = uapi::EVIOCGNAME_0 & EVIOC_VAR_LEN_MASK;
558pub(crate) const EVIOCGPHYS_BASE: u32 = uapi::EVIOCGPHYS_0 & EVIOC_VAR_LEN_MASK;
559pub(crate) const EVIOCGUNIQ_BASE: u32 = uapi::EVIOCGUNIQ_0 & EVIOC_VAR_LEN_MASK;
560pub(crate) const EVIOCGKEY_BASE: u32 = uapi::EVIOCGKEY_0 & EVIOC_VAR_LEN_MASK;
561pub(crate) const EVIOCGLED_BASE: u32 = uapi::EVIOCGLED_0 & EVIOC_VAR_LEN_MASK;
562pub(crate) const EVIOCGSND_BASE: u32 = uapi::EVIOCGSND_0 & EVIOC_VAR_LEN_MASK;
563pub(crate) const EVIOCGSW_BASE: u32 = uapi::EVIOCGSW_0 & EVIOC_VAR_LEN_MASK;
564pub(crate) const EVIOCGPROP_BASE: u32 = uapi::EVIOCGPROP & EVIOC_VAR_LEN_MASK;
565pub(crate) const EVIOCGBIT_0_BASE: u32 = uapi::EVIOCGBIT_0 & EVIOC_VAR_LEN_MASK;
566pub(crate) const EVIOCGBIT_EV_KEY_BASE: u32 = uapi::EVIOCGBIT_EV_KEY & EVIOC_VAR_LEN_MASK;
567pub(crate) const EVIOCGBIT_EV_ABS_BASE: u32 = uapi::EVIOCGBIT_EV_ABS & EVIOC_VAR_LEN_MASK;
568pub(crate) const EVIOCGBIT_EV_REL_BASE: u32 = uapi::EVIOCGBIT_EV_REL & EVIOC_VAR_LEN_MASK;
569pub(crate) const EVIOCGBIT_EV_SW_BASE: u32 = uapi::EVIOCGBIT_EV_SW & EVIOC_VAR_LEN_MASK;
570pub(crate) const EVIOCGBIT_EV_LED_BASE: u32 = uapi::EVIOCGBIT_EV_LED & EVIOC_VAR_LEN_MASK;
571pub(crate) const EVIOCGBIT_EV_FF_BASE: u32 = uapi::EVIOCGBIT_EV_FF & EVIOC_VAR_LEN_MASK;
572pub(crate) const EVIOCGBIT_EV_MSC_BASE: u32 = uapi::EVIOCGBIT_EV_MSC & EVIOC_VAR_LEN_MASK;
573pub(crate) const EVIOCGBIT_EV_SND_BASE: u32 = uapi::EVIOCGBIT_EV_SND & EVIOC_VAR_LEN_MASK;
574
575impl FileOps for InputFile {
576 fileops_impl_nonseekable!();
577 fileops_impl_noop_sync!();
578
579 fn open(&self, file: &FileObject, _current_task: &CurrentTask) -> Result<(), Errno> {
580 if let Some(inspect) = &self.inspect_status {
581 inspect.set_open_timestamp(zx::MonotonicInstant::get().into_nanos());
582 if (file.flags() & OpenFlags::NONBLOCK) != OpenFlags::NONBLOCK {
583 inspect.set_opened_without_nonblock();
584 }
585 }
586 Ok(())
587 }
588
589 fn close(
590 self: Box<Self>,
591 _file: &starnix_core::vfs::FileObjectState,
592 _current_task: &CurrentTask,
593 ) {
594 if let Some(inspect) = &self.inspect_status {
595 inspect.set_closed();
596 inspect.set_closed_timestamp(zx::MonotonicInstant::get().into_nanos());
597 }
598 }
599
600 fn ioctl(
601 &self,
602 _file: &FileObject,
603 current_task: &CurrentTask,
604 request: u32,
605 arg: SyscallArg,
606 ) -> Result<SyscallResult, Errno> {
607 let user_addr = UserAddress::from(arg);
608 match request {
609 uapi::EVIOCGVERSION => {
610 current_task.write_object(UserRef::new(user_addr), &self.driver_version)?;
611 Ok(SUCCESS)
612 }
613 uapi::EVIOCGID => {
614 let input_id = self.info.lock().input_id;
615 current_task.write_object(UserRef::new(user_addr), &input_id)?;
616 Ok(SUCCESS)
617 }
618 uapi::EVIOCGABS_MT_SLOT => {
619 current_task.write_object(UserRef::new(user_addr), &self.mt_slot_axis_info)?;
620 Ok(SUCCESS)
621 }
622 uapi::EVIOCGABS_MT_TRACKING_ID => {
623 current_task
624 .write_object(UserRef::new(user_addr), &self.mt_tracking_id_axis_info)?;
625 Ok(SUCCESS)
626 }
627 uapi::EVIOCGABS_MT_POSITION_X => {
628 current_task.write_object(UserRef::new(user_addr), &self.x_axis_info)?;
629 Ok(SUCCESS)
630 }
631 uapi::EVIOCGABS_MT_POSITION_Y => {
632 current_task.write_object(UserRef::new(user_addr), &self.y_axis_info)?;
633 Ok(SUCCESS)
634 }
635 uapi::EVIOCGRAB => {
636 track_stub!(TODO("https://fxbug.dev/322873200"), "EVIOCGRAB");
638 Ok(SUCCESS)
639 }
640
641 request_with_params => {
642 let buffer_bytes_count =
644 ((request_with_params >> uapi::_IOC_SIZESHIFT) & uapi::_IOC_SIZEMASK) as usize;
645
646 let dir = (request_with_params >> uapi::_IOC_DIRSHIFT) & uapi::_IOC_DIRMASK;
647 let ioc_type = (request_with_params >> uapi::_IOC_TYPESHIFT) & uapi::_IOC_TYPEMASK;
648
649 if dir != uapi::_IOC_READ || ioc_type != (b'E' as u32) {
651 track_stub!(
652 TODO("https://fxbug.dev/322873200"),
653 "input ioctl invalid type or dir",
654 request_with_params
655 );
656 return error!(EINVAL);
657 }
658
659 let write_bits = |bits: &[u8]| -> Result<SyscallResult, Errno> {
663 if buffer_bytes_count == 0 {
664 return Ok(SUCCESS);
665 }
666 if current_task.zero(user_addr, buffer_bytes_count)? != buffer_bytes_count {
668 return error!(EFAULT);
669 }
670 let to_copy = std::cmp::min(bits.len(), buffer_bytes_count);
671 current_task.write_memory(user_addr, &bits[..to_copy])?;
672 Ok(SUCCESS)
673 };
674
675 let write_string = |bytes: &[u8]| -> Result<SyscallResult, Errno> {
678 if buffer_bytes_count == 0 {
679 return Ok(SUCCESS);
680 }
681 if current_task.zero(user_addr, buffer_bytes_count)? != buffer_bytes_count {
683 return error!(EFAULT);
684 }
685 let to_copy = std::cmp::min(bytes.len(), buffer_bytes_count.saturating_sub(1));
686 current_task.write_memory(user_addr, &bytes[..to_copy])?;
687 Ok((to_copy + 1).into())
690 };
691
692 match request_with_params & EVIOC_VAR_LEN_MASK {
693 EVIOCGBIT_0_BASE => write_bits(&self.supported_event_types.bytes),
694 EVIOCGBIT_EV_KEY_BASE => write_bits(&self.supported_keys.bytes),
695 EVIOCGBIT_EV_ABS_BASE => write_bits(&self.supported_position_attributes.bytes),
696 EVIOCGBIT_EV_REL_BASE => write_bits(&self.supported_motion_attributes.bytes),
697 EVIOCGBIT_EV_SW_BASE => write_bits(&self.supported_switches.bytes),
698 EVIOCGBIT_EV_LED_BASE => write_bits(&self.supported_leds.bytes),
699 EVIOCGBIT_EV_FF_BASE => write_bits(&self.supported_haptics.bytes),
700 EVIOCGBIT_EV_MSC_BASE => write_bits(&self.supported_misc_features.bytes),
701 EVIOCGBIT_EV_SND_BASE => write_bits(&[]),
702 EVIOCGPROP_BASE => write_bits(&self.properties.bytes),
703 EVIOCGNAME_BASE => {
704 let name = self.info.lock().name.clone();
705 write_string(name.as_bytes())
706 }
707 EVIOCGPHYS_BASE => {
708 let phys = format!("starnix/{}", self.info.lock().name);
709 write_string(phys.as_bytes())
710 }
711 EVIOCGUNIQ_BASE => {
712 error!(ENOENT)
715 }
716 EVIOCGKEY_BASE | EVIOCGLED_BASE | EVIOCGSND_BASE | EVIOCGSW_BASE => {
717 track_stub!(
733 TODO("https://fxbug.dev/322873200"),
734 "evdev current-state query",
735 request_with_params
736 );
737 write_bits(&[])
738 }
739 _ => {
740 track_stub!(
741 TODO("https://fxbug.dev/322873200"),
742 "input ioctl",
743 request_with_params
744 );
745 error!(EINVAL)
746 }
747 }
748 }
749 }
750 }
751
752 fn read(
753 &self,
754 _file: &FileObject,
755 current_task: &CurrentTask,
756 offset: usize,
757 data: &mut dyn OutputBuffer,
758 ) -> Result<usize, Errno> {
759 fuchsia_trace::duration!("input", "InputFile::read");
760 debug_assert!(offset == 0);
761 let input_event_size = InputEventPtr::size_of_object_for(current_task);
762
763 let limit = data.available() / input_event_size;
766 let events = self.read_events(limit);
767 if events.is_empty() {
768 log_info!("read() returning EAGAIN");
770 return error!(EAGAIN);
771 }
772
773 let last_event_timeval = events.last().expect("events is nonempty").event.time;
774 let last_event_time_ns = duration_from_timeval::<zx::MonotonicTimeline>(last_event_timeval)
775 .unwrap()
776 .into_nanos();
777 self.inspect_status
778 .clone()
779 .map(|status| status.count_read_events(events.len() as u64, last_event_time_ns));
780
781 for event in &events {
782 if let Some(trace_id) = event.trace_id {
783 fuchsia_trace::duration!("input", "linux_event_read");
784 fuchsia_trace::flow_end!("input", "linux_event", trace_id);
785 }
786 }
787
788 if current_task.is_arch32() {
789 let events: Result<Vec<uapi::arch32::input_event>, _> =
790 events.iter().map(|e| uapi::arch32::input_event::try_from(e.event)).collect();
791 let events = events.map_err(|_| errno!(EINVAL))?;
792 data.write_all(events.as_bytes())
793 } else {
794 let events: Vec<uapi::input_event> = events.iter().map(|e| e.event).collect();
795 data.write_all(events.as_bytes())
796 }
797 }
798
799 fn write(
800 &self,
801 _file: &FileObject,
802 _current_task: &CurrentTask,
803 offset: usize,
804 _data: &mut dyn InputBuffer,
805 ) -> Result<usize, Errno> {
806 debug_assert!(offset == 0);
807 track_stub!(TODO("https://fxbug.dev/322874385"), "write() on input device");
808 error!(EOPNOTSUPP)
809 }
810
811 fn wait_async(
812 &self,
813 _file: &FileObject,
814 _current_task: &CurrentTask,
815 waiter: &Waiter,
816 events: FdEvents,
817 handler: EventHandler,
818 ) -> Option<WaitCanceler> {
819 Some(self.waiters.wait_async_fd_events(waiter, events, handler))
820 }
821
822 fn query_events(
823 &self,
824 _file: &FileObject,
825 _current_task: &CurrentTask,
826 ) -> Result<FdEvents, Errno> {
827 Ok(if self.events.is_empty() { FdEvents::empty() } else { FdEvents::POLLIN })
828 }
829}
830
831pub struct ArcInputFile(pub Arc<InputFile>);
832
833impl FileOps for ArcInputFile {
834 fileops_impl_nonseekable!();
835 fileops_impl_noop_sync!();
836
837 fn open(&self, file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
838 self.0.as_ref().open(file, current_task)
839 }
840
841 fn close(
842 self: Box<Self>,
843 _file: &starnix_core::vfs::FileObjectState,
844 _current_task: &CurrentTask,
845 ) {
846 let arc_file = *self;
847 if let Some(inspect) = &arc_file.0.inspect_status {
848 inspect.set_closed();
849 inspect.set_closed_timestamp(zx::MonotonicInstant::get().into_nanos());
850 }
851 }
852
853 fn ioctl(
854 &self,
855 file: &FileObject,
856 current_task: &CurrentTask,
857 request: u32,
858 arg: SyscallArg,
859 ) -> Result<SyscallResult, Errno> {
860 self.0.as_ref().ioctl(file, current_task, request, arg)
861 }
862
863 fn read(
864 &self,
865 file: &FileObject,
866 current_task: &CurrentTask,
867 offset: usize,
868 data: &mut dyn OutputBuffer,
869 ) -> Result<usize, Errno> {
870 self.0.as_ref().read(file, current_task, offset, data)
871 }
872
873 fn write(
874 &self,
875 file: &FileObject,
876 current_task: &CurrentTask,
877 offset: usize,
878 data: &mut dyn InputBuffer,
879 ) -> Result<usize, Errno> {
880 self.0.as_ref().write(file, current_task, offset, data)
881 }
882
883 fn wait_async(
884 &self,
885 file: &FileObject,
886 current_task: &CurrentTask,
887 waiter: &Waiter,
888 events: FdEvents,
889 handler: EventHandler,
890 ) -> Option<WaitCanceler> {
891 self.0.as_ref().wait_async(file, current_task, waiter, events, handler)
892 }
893
894 fn query_events(
895 &self,
896 file: &FileObject,
897 current_task: &CurrentTask,
898 ) -> Result<FdEvents, Errno> {
899 self.0.as_ref().query_events(file, current_task)
900 }
901}
902
903pub struct BitSet<const NUM_BYTES: usize> {
904 bytes: [u8; NUM_BYTES],
905}
906
907impl<const NUM_BYTES: usize> BitSet<{ NUM_BYTES }> {
908 pub const fn new() -> Self {
909 Self { bytes: [0; NUM_BYTES] }
910 }
911
912 pub const fn list<const N: usize>(bits: [u32; N]) -> Self {
913 let mut bitset = Self::new();
914 let mut i = 0;
915 while i < bits.len() {
916 bitset.set(bits[i]);
917 i += 1;
918 }
919 bitset
920 }
921
922 pub const fn set(&mut self, bitnum: u32) {
923 let bitnum = bitnum as usize;
924 let byte = bitnum / 8;
925 let bit = bitnum % 8;
926 self.bytes[byte] |= 1 << bit;
927 }
928
929 #[cfg(test)]
930 pub fn get(&self, bitnum: u32) -> bool {
931 let bitnum = bitnum as usize;
932 let byte = bitnum / 8;
933 let bit = bitnum % 8;
934 (self.bytes[byte] & (1 << bit)) != 0
935 }
936}
937
938#[cfg(test)]
939mod tests {
940 use super::*;
941 use crate::input_device::InputDeviceInfo;
942 use std::sync::atomic::Ordering;
943
944 #[test]
945 fn test_keyboard_input_file_attributes() {
946 let inspector = fuchsia_inspect::Inspector::default();
947 let node = inspector.root();
948 let keyboard_file = InputFile::new_keyboard(
949 InputDeviceInfo::new(
950 uapi::input_id { bustype: 0, vendor: 0, product: 0, version: 0 },
951 "keyboard_test".to_string(),
952 ),
953 node,
954 );
955
956 assert!(keyboard_file.supported_event_types.get(uapi::EV_KEY));
958 assert!(!keyboard_file.supported_event_types.get(uapi::EV_REL));
959 assert!(!keyboard_file.supported_event_types.get(uapi::EV_ABS));
960
961 assert!(keyboard_file.supported_keys.get(uapi::KEY_A));
963 assert!(keyboard_file.supported_keys.get(uapi::KEY_Z));
964 assert!(keyboard_file.supported_keys.get(uapi::KEY_1));
965 assert!(keyboard_file.supported_keys.get(uapi::KEY_ENTER));
966 assert!(keyboard_file.supported_keys.get(uapi::KEY_SPACE));
967 assert!(keyboard_file.supported_keys.get(uapi::KEY_ESC));
968 assert!(keyboard_file.supported_keys.get(uapi::KEY_TAB));
969 assert!(keyboard_file.supported_keys.get(uapi::KEY_BACKSPACE));
970 assert!(keyboard_file.supported_keys.get(uapi::KEY_LEFTSHIFT));
971 assert!(keyboard_file.supported_keys.get(uapi::KEY_LEFTCTRL));
972 assert!(keyboard_file.supported_keys.get(uapi::KEY_LEFTALT));
973 assert!(keyboard_file.supported_keys.get(uapi::KEY_POWER));
974 assert!(keyboard_file.supported_keys.get(uapi::KEY_VOLUMEUP));
975 assert!(keyboard_file.supported_keys.get(uapi::KEY_VOLUMEDOWN));
976 assert!(keyboard_file.supported_keys.get(uapi::BTN_MISC));
977
978 assert!(keyboard_file.properties.get(uapi::INPUT_PROP_DIRECT));
980 assert!(!keyboard_file.properties.get(uapi::INPUT_PROP_POINTER));
981 }
982
983 #[test]
984 fn test_read_events_no_notify_when_buffer_full() {
985 let inspector = fuchsia_inspect::Inspector::default();
986 let node = inspector.root();
987 let input_file = InputFile::new_touch(
988 InputDeviceInfo::new(
989 uapi::input_id { bustype: 0, vendor: 0, product: 0, version: 0 },
990 "touch_test".to_string(),
991 ),
992 100,
993 100,
994 node,
995 );
996
997 let event1 = uapi::input_event {
999 type_: uapi::EV_KEY as u16,
1000 code: 1,
1001 value: 1,
1002 ..Default::default()
1003 };
1004 let event2 = uapi::input_event {
1005 type_: uapi::EV_KEY as u16,
1006 code: 2,
1007 value: 1,
1008 ..Default::default()
1009 };
1010 input_file.add_events(vec![event1, event2]);
1011
1012 let notify_count =
1014 input_file.inspect_status.as_ref().unwrap().fd_notify_count.load(Ordering::Relaxed);
1015 assert_eq!(notify_count, 1);
1016
1017 let events = input_file.read_events(1);
1019 assert_eq!(events.len(), 1);
1020
1021 let notify_count =
1023 input_file.inspect_status.as_ref().unwrap().fd_notify_count.load(Ordering::Relaxed);
1024 assert_eq!(notify_count, 1);
1025 }
1026
1027 #[test]
1028 fn test_bitset_set_and_get() {
1029 let mut bitset = BitSet::<4>::new();
1030 assert!(!bitset.get(0));
1031 assert!(!bitset.get(15));
1032 assert!(!bitset.get(31));
1033
1034 bitset.set(0);
1035 bitset.set(15);
1036 bitset.set(31);
1037
1038 assert!(bitset.get(0));
1039 assert!(bitset.get(15));
1040 assert!(bitset.get(31));
1041 assert!(!bitset.get(1));
1042 assert!(!bitset.get(14));
1043 assert!(!bitset.get(30));
1044 }
1045
1046 #[test]
1047 fn test_mouse_capabilities() {
1048 let inspector = fuchsia_inspect::Inspector::default();
1049 let node = inspector.root();
1050 let mouse_file = InputFile::new_mouse(
1051 InputDeviceInfo::new(
1052 uapi::input_id { bustype: 0, vendor: 0, product: 0, version: 0 },
1053 "mouse_test".to_string(),
1054 ),
1055 node,
1056 );
1057
1058 assert!(mouse_file.supported_event_types.get(uapi::EV_KEY));
1060 assert!(mouse_file.supported_event_types.get(uapi::EV_REL));
1061 assert!(!mouse_file.supported_event_types.get(uapi::EV_ABS));
1062
1063 assert!(mouse_file.supported_keys.get(BTN_LEFT));
1065 assert!(mouse_file.supported_keys.get(BTN_RIGHT));
1066 assert!(mouse_file.supported_keys.get(BTN_MIDDLE));
1067 assert!(mouse_file.supported_keys.get(BTN_SIDE));
1068 assert!(mouse_file.supported_keys.get(BTN_EXTRA));
1069 assert!(!mouse_file.supported_keys.get(BTN_TOUCH));
1070
1071 assert!(mouse_file.supported_motion_attributes.get(REL_X));
1073 assert!(mouse_file.supported_motion_attributes.get(REL_Y));
1074 assert!(mouse_file.supported_motion_attributes.get(REL_WHEEL));
1075 assert!(mouse_file.supported_motion_attributes.get(REL_HWHEEL));
1076
1077 assert!(mouse_file.properties.get(INPUT_PROP_POINTER));
1079 assert!(!mouse_file.properties.get(INPUT_PROP_DIRECT));
1080 }
1081}