1use crossbeam::queue::SegQueue;
6use fuchsia_inspect::Inspector;
7use futures::FutureExt;
8use starnix_core::fileops_impl_nonseekable;
9use starnix_core::mm::{MemoryAccessor, MemoryAccessorExt};
10use starnix_core::task::{CurrentTask, EventHandler, WaitCanceler, WaitQueue, Waiter};
11use starnix_core::vfs::buffers::{InputBuffer, OutputBuffer};
12use starnix_core::vfs::{FileObject, FileOps, fileops_impl_noop_sync};
13use starnix_logging::{log_info, track_stub};
14use starnix_sync::{FileOpsCore, Locked, Mutex, Unlocked};
15use starnix_syscalls::{SUCCESS, SyscallArg, SyscallResult};
16use starnix_types::time::duration_from_timeval;
17use starnix_uapi::errors::Errno;
18use starnix_uapi::open_flags::OpenFlags;
19use starnix_uapi::user_address::{ArchSpecific, MultiArchUserRef, UserAddress, UserRef};
20use starnix_uapi::vfs::FdEvents;
21use starnix_uapi::{
22 ABS_CNT, ABS_MT_POSITION_X, ABS_MT_POSITION_Y, ABS_MT_SLOT, ABS_MT_TRACKING_ID, BTN_MISC,
23 BTN_TOUCH, EV_CNT, FF_CNT, INPUT_PROP_CNT, INPUT_PROP_DIRECT, KEY_CNT, KEY_DOWN, KEY_LEFT,
24 KEY_POWER, KEY_RIGHT, KEY_SLEEP, KEY_UP, KEY_VOLUMEDOWN, LED_CNT, MSC_CNT, REL_CNT, REL_WHEEL,
25 SW_CNT, errno, error, uapi,
26};
27use std::sync::atomic::{AtomicBool, AtomicI64, AtomicU64, Ordering};
28use std::sync::{Arc, Weak};
29use zerocopy::IntoBytes as _; uapi::check_arch_independent_layout! {
32 input_id {}
33 input_absinfo {}
34}
35
36type InputEventPtr = MultiArchUserRef<uapi::input_event, uapi::arch32::input_event>;
37
38pub struct InputFileStatus {
39 pub fidl_events_received_count: AtomicU64,
49
50 pub fidl_events_ignored_count: AtomicU64,
52
53 pub fidl_events_unexpected_count: AtomicU64,
57
58 pub fidl_events_converted_count: AtomicU64,
60
61 pub uapi_events_generated_count: AtomicU64,
63
64 pub last_generated_uapi_event_timestamp_ns: AtomicI64,
66
67 pub uapi_events_read_count: AtomicU64,
69
70 pub last_read_uapi_event_timestamp_ns: AtomicI64,
72
73 pub fd_read_count: AtomicU64,
75
76 pub fd_notify_count: AtomicU64,
78
79 pub opened_without_nonblock: AtomicBool,
81
82 pub open_timestamp_ns: AtomicI64,
84
85 pub closed: AtomicBool,
87
88 pub close_timestamp_ns: AtomicI64,
90
91 pub input_file: Mutex<Weak<InputFile>>,
93}
94
95impl InputFileStatus {
96 fn new(node: &fuchsia_inspect::Node) -> Arc<Self> {
97 let status = Arc::new(Self {
98 fidl_events_received_count: AtomicU64::new(0),
99 fidl_events_ignored_count: AtomicU64::new(0),
100 fidl_events_unexpected_count: AtomicU64::new(0),
101 fidl_events_converted_count: AtomicU64::new(0),
102 uapi_events_generated_count: AtomicU64::new(0),
103 last_generated_uapi_event_timestamp_ns: AtomicI64::new(0),
104 uapi_events_read_count: AtomicU64::new(0),
105 last_read_uapi_event_timestamp_ns: AtomicI64::new(0),
106 fd_read_count: AtomicU64::new(0),
107 fd_notify_count: AtomicU64::new(0),
108 opened_without_nonblock: AtomicBool::new(false),
109 open_timestamp_ns: AtomicI64::new(0),
110 closed: AtomicBool::new(false),
111 close_timestamp_ns: AtomicI64::new(0),
112 input_file: Mutex::new(Weak::new()),
113 });
114
115 let cloned_status = status.clone();
116 node.record_lazy_values("status", move || {
117 let cloned_cloned_status = cloned_status.clone();
118 async move {
119 let is_dropped = cloned_cloned_status.input_file.lock().upgrade().is_none();
120 if is_dropped && !cloned_cloned_status.closed.load(Ordering::Relaxed) {
121 cloned_cloned_status.closed.store(true, Ordering::Relaxed);
122 }
123
124 let inspector = Inspector::default();
125 let root = inspector.root();
126 root.record_uint(
127 "fd_read_count",
128 cloned_cloned_status.fd_read_count.load(Ordering::Relaxed),
129 );
130 root.record_uint(
131 "fd_notify_count",
132 cloned_cloned_status.fd_notify_count.load(Ordering::Relaxed),
133 );
134 root.record_bool(
135 "opened_without_nonblock",
136 cloned_cloned_status.opened_without_nonblock.load(Ordering::Relaxed),
137 );
138 root.record_int(
139 "open_timestamp_ns",
140 cloned_cloned_status.open_timestamp_ns.load(Ordering::Relaxed),
141 );
142 root.record_bool("closed", cloned_cloned_status.closed.load(Ordering::Relaxed));
143 root.record_int(
144 "close_timestamp_ns",
145 cloned_cloned_status.close_timestamp_ns.load(Ordering::Relaxed),
146 );
147 root.record_uint(
148 "fidl_events_received_count",
149 cloned_cloned_status.fidl_events_received_count.load(Ordering::Relaxed),
150 );
151 root.record_uint(
152 "fidl_events_ignored_count",
153 cloned_cloned_status.fidl_events_ignored_count.load(Ordering::Relaxed),
154 );
155 root.record_uint(
156 "fidl_events_unexpected_count",
157 cloned_cloned_status.fidl_events_unexpected_count.load(Ordering::Relaxed),
158 );
159 root.record_uint(
160 "fidl_events_converted_count",
161 cloned_cloned_status.fidl_events_converted_count.load(Ordering::Relaxed),
162 );
163 root.record_uint(
164 "uapi_events_generated_count",
165 cloned_cloned_status.uapi_events_generated_count.load(Ordering::Relaxed),
166 );
167 root.record_int(
168 "last_generated_uapi_event_timestamp_ns",
169 cloned_cloned_status
170 .last_generated_uapi_event_timestamp_ns
171 .load(Ordering::Relaxed),
172 );
173 root.record_uint(
174 "uapi_events_read_count",
175 cloned_cloned_status.uapi_events_read_count.load(Ordering::Relaxed),
176 );
177 root.record_int(
178 "last_read_uapi_event_timestamp_ns",
179 cloned_cloned_status.last_read_uapi_event_timestamp_ns.load(Ordering::Relaxed),
180 );
181 Ok(inspector)
182 }
183 .boxed()
184 });
185
186 status
187 }
188
189 pub fn count_received_events(&self, count: u64) {
190 self.fidl_events_received_count.fetch_add(count, Ordering::Relaxed);
191 }
192
193 pub fn count_ignored_events(&self, count: u64) {
194 self.fidl_events_ignored_count.fetch_add(count, Ordering::Relaxed);
195 }
196
197 pub fn count_unexpected_events(&self, count: u64) {
198 self.fidl_events_unexpected_count.fetch_add(count, Ordering::Relaxed);
199 }
200
201 pub fn count_converted_events(&self, count: u64) {
202 self.fidl_events_converted_count.fetch_add(count, Ordering::Relaxed);
203 }
204
205 pub fn count_generated_events(&self, count: u64, event_time_ns: i64) {
206 self.uapi_events_generated_count.fetch_add(count, Ordering::Relaxed);
207 self.last_generated_uapi_event_timestamp_ns.store(event_time_ns, Ordering::Relaxed);
208 }
209
210 pub fn count_read_events(&self, count: u64, event_time_ns: i64) {
211 self.uapi_events_read_count.fetch_add(count, Ordering::Relaxed);
212 self.last_read_uapi_event_timestamp_ns.store(event_time_ns, Ordering::Relaxed);
213 }
214
215 pub fn count_fd_read_calls(&self) {
216 self.fd_read_count.fetch_add(1, Ordering::Relaxed);
217 }
218
219 pub fn count_fd_notify_calls(&self) {
220 self.fd_notify_count.fetch_add(1, Ordering::Relaxed);
221 }
222
223 pub fn set_opened_without_nonblock(&self) {
224 self.opened_without_nonblock.store(true, Ordering::Relaxed);
225 }
226
227 pub fn set_open_timestamp(&self, timestamp: i64) {
228 self.open_timestamp_ns.store(timestamp, Ordering::Relaxed);
229 }
230
231 pub fn set_closed(&self) {
232 self.closed.store(true, Ordering::Relaxed);
233 }
234
235 pub fn set_closed_timestamp(&self, timestamp: i64) {
236 self.close_timestamp_ns.store(timestamp, Ordering::Relaxed);
237 }
238}
239
240pub struct InputFile {
241 driver_version: u32,
242 input_id: uapi::input_id,
243 supported_event_types: BitSet<{ min_bytes(EV_CNT) }>,
244 supported_keys: BitSet<{ min_bytes(KEY_CNT) }>,
245 supported_position_attributes: BitSet<{ min_bytes(ABS_CNT) }>, supported_motion_attributes: BitSet<{ min_bytes(REL_CNT) }>, supported_switches: BitSet<{ min_bytes(SW_CNT) }>,
248 supported_leds: BitSet<{ min_bytes(LED_CNT) }>,
249 supported_haptics: BitSet<{ min_bytes(FF_CNT) }>, supported_misc_features: BitSet<{ min_bytes(MSC_CNT) }>,
251 properties: BitSet<{ min_bytes(INPUT_PROP_CNT) }>,
252 mt_slot_axis_info: uapi::input_absinfo,
253 mt_tracking_id_axis_info: uapi::input_absinfo,
254 x_axis_info: uapi::input_absinfo,
255 y_axis_info: uapi::input_absinfo,
256 events: SegQueue<LinuxEventWithTraceId>,
257 waiters: WaitQueue,
258 pub inspect_status: Option<Arc<InputFileStatus>>,
261
262 device_name: String,
264}
265
266pub struct LinuxEventWithTraceId {
267 pub event: uapi::input_event,
268 pub trace_id: Option<fuchsia_trace::Id>,
269}
270
271impl LinuxEventWithTraceId {
272 pub fn new(event: uapi::input_event) -> Self {
273 match event.type_ as u32 {
274 uapi::EV_SYN => {
275 let trace_id = fuchsia_trace::Id::new();
276 fuchsia_trace::duration!("input", "linux_event_create");
277 fuchsia_trace::flow_begin!("input", "linux_event", trace_id);
278 LinuxEventWithTraceId { event: event, trace_id: Some(trace_id) }
279 }
280 _ => LinuxEventWithTraceId { event: event, trace_id: None },
283 }
284 }
285}
286
287const fn min_bytes(n_bits: u32) -> usize {
289 ((n_bits as usize) + 7) / 8
290}
291
292fn keyboard_properties() -> BitSet<{ min_bytes(INPUT_PROP_CNT) }> {
294 let mut attrs = BitSet::new();
295 attrs.set(INPUT_PROP_DIRECT);
296 attrs
297}
298
299fn touch_key_attributes() -> BitSet<{ min_bytes(KEY_CNT) }> {
301 let mut attrs = BitSet::new();
302 attrs.set(BTN_TOUCH);
303 attrs.set(BTN_MISC); attrs.set(KEY_SLEEP);
305 attrs.set(KEY_UP);
306 attrs.set(KEY_LEFT);
307 attrs.set(KEY_RIGHT);
308 attrs.set(KEY_DOWN);
309
310 attrs
311}
312
313fn touch_position_attributes() -> BitSet<{ min_bytes(ABS_CNT) }> {
315 let mut attrs = BitSet::new();
316 attrs.set(ABS_MT_SLOT);
317 attrs.set(ABS_MT_TRACKING_ID);
318 attrs.set(ABS_MT_POSITION_X);
319 attrs.set(ABS_MT_POSITION_Y);
320 attrs
321}
322
323fn touch_properties() -> BitSet<{ min_bytes(INPUT_PROP_CNT) }> {
325 let mut attrs = BitSet::new();
326 attrs.set(INPUT_PROP_DIRECT);
327 attrs
328}
329
330fn keyboard_key_attributes() -> BitSet<{ min_bytes(KEY_CNT) }> {
332 let mut attrs = BitSet::new();
333 attrs.set(BTN_MISC);
334 attrs.set(KEY_POWER);
335 attrs.set(KEY_VOLUMEDOWN);
336 attrs
337}
338
339fn keyboard_position_attributes() -> BitSet<{ min_bytes(ABS_CNT) }> {
341 BitSet::new()
342}
343
344fn mouse_wheel_attributes() -> BitSet<{ min_bytes(REL_CNT) }> {
345 let mut attrs = BitSet::new();
346 attrs.set(REL_WHEEL);
347 attrs
348}
349
350fn get_device_name(name: &str, input_id: &uapi::input_id) -> String {
354 format!("{}_{:04x}_{:04x}_v{}", name, input_id.vendor, input_id.product, input_id.version)
355}
356
357impl InputFile {
358 const DRIVER_VERSION: u32 = 0;
364
365 pub fn new_touch(
373 input_id: uapi::input_id,
374 width: i32,
375 height: i32,
376 node: &fuchsia_inspect::Node,
377 ) -> Self {
378 let device_name = get_device_name("starnix_touch", &input_id);
379 Self {
383 driver_version: Self::DRIVER_VERSION,
384 input_id,
385 supported_event_types: BitSet::list([uapi::EV_ABS]),
386 supported_keys: touch_key_attributes(),
387 supported_position_attributes: touch_position_attributes(),
388 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(),
394 mt_slot_axis_info: uapi::input_absinfo {
395 minimum: 0,
396 maximum: 10,
397 ..uapi::input_absinfo::default()
398 },
399 mt_tracking_id_axis_info: uapi::input_absinfo {
400 minimum: 0,
401 maximum: i32::MAX,
402 ..uapi::input_absinfo::default()
403 },
404 x_axis_info: uapi::input_absinfo {
405 minimum: 0,
406 maximum: i32::from(width),
407 ..uapi::input_absinfo::default()
410 },
411 y_axis_info: uapi::input_absinfo {
412 minimum: 0,
413 maximum: i32::from(height),
414 ..uapi::input_absinfo::default()
417 },
418 events: SegQueue::new(),
419 waiters: WaitQueue::default(),
420 inspect_status: Some(InputFileStatus::new(node)),
421 device_name,
422 }
423 }
424
425 pub fn new_keyboard(input_id: uapi::input_id, node: &fuchsia_inspect::Node) -> Self {
431 let device_name = get_device_name("starnix_buttons", &input_id);
432 Self {
433 driver_version: Self::DRIVER_VERSION,
434 input_id,
435 supported_event_types: BitSet::list([uapi::EV_KEY]),
436 supported_keys: keyboard_key_attributes(),
437 supported_position_attributes: keyboard_position_attributes(),
438 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(),
444 mt_slot_axis_info: uapi::input_absinfo::default(),
445 mt_tracking_id_axis_info: uapi::input_absinfo::default(),
446 x_axis_info: uapi::input_absinfo::default(),
447 y_axis_info: uapi::input_absinfo::default(),
448 events: SegQueue::new(),
449 waiters: WaitQueue::default(),
450 inspect_status: Some(InputFileStatus::new(node)),
451 device_name,
452 }
453 }
454
455 pub fn new_mouse(input_id: uapi::input_id, node: &fuchsia_inspect::Node) -> Self {
461 let device_name = get_device_name("starnix_mouse", &input_id);
462 Self {
463 driver_version: Self::DRIVER_VERSION,
464 input_id,
465 supported_event_types: BitSet::list([uapi::EV_REL]),
466 supported_keys: BitSet::new(), supported_position_attributes: BitSet::new(), supported_motion_attributes: mouse_wheel_attributes(),
469 supported_switches: BitSet::new(), supported_leds: BitSet::new(), supported_haptics: BitSet::new(), supported_misc_features: BitSet::new(), properties: BitSet::new(), mt_slot_axis_info: uapi::input_absinfo::default(),
475 mt_tracking_id_axis_info: uapi::input_absinfo::default(),
476 x_axis_info: uapi::input_absinfo::default(),
477 y_axis_info: uapi::input_absinfo::default(),
478 events: SegQueue::new(),
479 waiters: WaitQueue::default(),
480 inspect_status: Some(InputFileStatus::new(node)),
481 device_name,
482 }
483 }
484
485 pub fn init_inspect_status(self: &Arc<Self>) {
486 if let Some(inspect) = &self.inspect_status {
487 *inspect.input_file.lock() = Arc::downgrade(self);
488 }
489 }
490
491 pub fn add_events(&self, events: Vec<uapi::input_event>) {
492 if events.is_empty() {
493 return;
494 }
495 if let Some(inspect) = &self.inspect_status {
496 inspect.count_fd_notify_calls();
497 }
498 for event in events {
499 self.events.push(LinuxEventWithTraceId::new(event));
500 }
501 self.waiters.notify_fd_events(FdEvents::POLLIN);
502 }
503
504 pub fn read_events(&self, limit: usize) -> Vec<LinuxEventWithTraceId> {
505 if let Some(inspect) = &self.inspect_status {
506 inspect.count_fd_read_calls();
507 }
508 let mut events = vec![];
509 for _ in 0..limit {
510 if let Some(event) = self.events.pop() {
511 events.push(event);
512 } else {
513 break;
514 }
515 }
516 events
520 }
521}
522
523const EVIOCGNAME_MASK: u32 = 0b11_00_0000_0000_0000_1111_1111_1111_1111;
526
527impl FileOps for InputFile {
528 fileops_impl_nonseekable!();
529 fileops_impl_noop_sync!();
530
531 fn open(
532 &self,
533 _locked: &mut Locked<FileOpsCore>,
534 file: &FileObject,
535 _current_task: &CurrentTask,
536 ) -> Result<(), Errno> {
537 if let Some(inspect) = &self.inspect_status {
538 inspect.set_open_timestamp(zx::MonotonicInstant::get().into_nanos());
539 if (file.flags() & OpenFlags::NONBLOCK) != OpenFlags::NONBLOCK {
540 inspect.set_opened_without_nonblock();
541 }
542 }
543 Ok(())
544 }
545
546 fn close(
547 self: Box<Self>,
548 _locked: &mut Locked<FileOpsCore>,
549 _file: &starnix_core::vfs::FileObjectState,
550 _current_task: &CurrentTask,
551 ) {
552 if let Some(inspect) = &self.inspect_status {
553 inspect.set_closed();
554 inspect.set_closed_timestamp(zx::MonotonicInstant::get().into_nanos());
555 }
556 }
557
558 fn ioctl(
559 &self,
560 _locked: &mut Locked<Unlocked>,
561 _file: &FileObject,
562 current_task: &CurrentTask,
563 request: u32,
564 arg: SyscallArg,
565 ) -> Result<SyscallResult, Errno> {
566 let user_addr = UserAddress::from(arg);
567 match request {
568 uapi::EVIOCGVERSION => {
569 current_task.write_object(UserRef::new(user_addr), &self.driver_version)?;
570 Ok(SUCCESS)
571 }
572 uapi::EVIOCGID => {
573 current_task.write_object(UserRef::new(user_addr), &self.input_id)?;
574 Ok(SUCCESS)
575 }
576 uapi::EVIOCGBIT_0 => {
577 current_task
578 .write_object(UserRef::new(user_addr), &self.supported_event_types.bytes)?;
579 Ok(SUCCESS)
580 }
581 uapi::EVIOCGBIT_EV_KEY => {
582 current_task.write_object(UserRef::new(user_addr), &self.supported_keys.bytes)?;
583 Ok(SUCCESS)
584 }
585 uapi::EVIOCGBIT_EV_ABS => {
586 current_task.write_object(
587 UserRef::new(user_addr),
588 &self.supported_position_attributes.bytes,
589 )?;
590 Ok(SUCCESS)
591 }
592 uapi::EVIOCGBIT_EV_REL => {
593 current_task.write_object(
594 UserRef::new(user_addr),
595 &self.supported_motion_attributes.bytes,
596 )?;
597 Ok(SUCCESS)
598 }
599 uapi::EVIOCGBIT_EV_SW => {
600 current_task
601 .write_object(UserRef::new(user_addr), &self.supported_switches.bytes)?;
602 Ok(SUCCESS)
603 }
604 uapi::EVIOCGBIT_EV_LED => {
605 current_task.write_object(UserRef::new(user_addr), &self.supported_leds.bytes)?;
606 Ok(SUCCESS)
607 }
608 uapi::EVIOCGBIT_EV_FF => {
609 current_task
610 .write_object(UserRef::new(user_addr), &self.supported_haptics.bytes)?;
611 Ok(SUCCESS)
612 }
613 uapi::EVIOCGBIT_EV_MSC => {
614 current_task
615 .write_object(UserRef::new(user_addr), &self.supported_misc_features.bytes)?;
616 Ok(SUCCESS)
617 }
618 uapi::EVIOCGPROP => {
619 current_task.write_object(UserRef::new(user_addr), &self.properties.bytes)?;
620 Ok(SUCCESS)
621 }
622 uapi::EVIOCGABS_MT_SLOT => {
623 current_task.write_object(UserRef::new(user_addr), &self.mt_slot_axis_info)?;
624 Ok(SUCCESS)
625 }
626 uapi::EVIOCGABS_MT_TRACKING_ID => {
627 current_task
628 .write_object(UserRef::new(user_addr), &self.mt_tracking_id_axis_info)?;
629 Ok(SUCCESS)
630 }
631 uapi::EVIOCGABS_MT_POSITION_X => {
632 current_task.write_object(UserRef::new(user_addr), &self.x_axis_info)?;
633 Ok(SUCCESS)
634 }
635 uapi::EVIOCGABS_MT_POSITION_Y => {
636 current_task.write_object(UserRef::new(user_addr), &self.y_axis_info)?;
637 Ok(SUCCESS)
638 }
639
640 request_with_params => {
641 match request_with_params & EVIOCGNAME_MASK {
644 uapi::EVIOCGNAME_0 => {
645 let device_name = &self.device_name;
657
658 let buffer_bytes_count =
663 ((request_with_params >> 16) & ((1 << 14) - 1)) as usize;
664
665 current_task.zero(user_addr, buffer_bytes_count)?;
668 let device_name_as_bytes = device_name.as_bytes();
669
670 let to_copy_bytes_count =
674 std::cmp::min(device_name_as_bytes.len(), buffer_bytes_count - 1);
675 current_task.write_memory(
676 user_addr,
677 &device_name_as_bytes[..to_copy_bytes_count],
678 )?;
679 Ok((to_copy_bytes_count + 1).into())
682 }
683 _ => {
684 track_stub!(
685 TODO("https://fxbug.dev/322873200"),
686 "input ioctl",
687 request_with_params
688 );
689 error!(EOPNOTSUPP)
690 }
691 }
692 }
693 }
694 }
695
696 fn read(
697 &self,
698 _locked: &mut Locked<FileOpsCore>,
699 _file: &FileObject,
700 current_task: &CurrentTask,
701 offset: usize,
702 data: &mut dyn OutputBuffer,
703 ) -> Result<usize, Errno> {
704 fuchsia_trace::duration!("input", "InputFile::read");
705 debug_assert!(offset == 0);
706 let input_event_size = InputEventPtr::size_of_object_for(current_task);
707
708 let limit = data.available() / input_event_size;
711 let events = self.read_events(limit);
712 if events.is_empty() {
713 log_info!("read() returning EAGAIN");
715 return error!(EAGAIN);
716 }
717
718 let last_event_timeval = events.last().expect("events is nonempty").event.time;
719 let last_event_time_ns = duration_from_timeval::<zx::MonotonicTimeline>(last_event_timeval)
720 .unwrap()
721 .into_nanos();
722 self.inspect_status
723 .clone()
724 .map(|status| status.count_read_events(events.len() as u64, last_event_time_ns));
725
726 for event in &events {
727 if let Some(trace_id) = event.trace_id {
728 fuchsia_trace::duration!("input", "linux_event_read");
729 fuchsia_trace::flow_end!("input", "linux_event", trace_id);
730 }
731 }
732
733 if current_task.is_arch32() {
734 let events: Result<Vec<uapi::arch32::input_event>, _> =
735 events.iter().map(|e| uapi::arch32::input_event::try_from(e.event)).collect();
736 let events = events.map_err(|_| errno!(EINVAL))?;
737 data.write_all(events.as_bytes())
738 } else {
739 let events: Vec<uapi::input_event> = events.iter().map(|e| e.event).collect();
740 data.write_all(events.as_bytes())
741 }
742 }
743
744 fn write(
745 &self,
746 _locked: &mut Locked<FileOpsCore>,
747 _file: &FileObject,
748 _current_task: &CurrentTask,
749 offset: usize,
750 _data: &mut dyn InputBuffer,
751 ) -> Result<usize, Errno> {
752 debug_assert!(offset == 0);
753 track_stub!(TODO("https://fxbug.dev/322874385"), "write() on input device");
754 error!(EOPNOTSUPP)
755 }
756
757 fn wait_async(
758 &self,
759 _locked: &mut Locked<FileOpsCore>,
760 _file: &FileObject,
761 _current_task: &CurrentTask,
762 waiter: &Waiter,
763 events: FdEvents,
764 handler: EventHandler,
765 ) -> Option<WaitCanceler> {
766 Some(self.waiters.wait_async_fd_events(waiter, events, handler))
767 }
768
769 fn query_events(
770 &self,
771 _locked: &mut Locked<FileOpsCore>,
772 _file: &FileObject,
773 _current_task: &CurrentTask,
774 ) -> Result<FdEvents, Errno> {
775 Ok(if self.events.is_empty() { FdEvents::empty() } else { FdEvents::POLLIN })
776 }
777}
778
779pub struct ArcInputFile(pub Arc<InputFile>);
780
781impl FileOps for ArcInputFile {
782 fileops_impl_nonseekable!();
783 fileops_impl_noop_sync!();
784
785 fn open(
786 &self,
787 locked: &mut Locked<FileOpsCore>,
788 file: &FileObject,
789 current_task: &CurrentTask,
790 ) -> Result<(), Errno> {
791 self.0.as_ref().open(locked, file, current_task)
792 }
793
794 fn close(
795 self: Box<Self>,
796 _locked: &mut Locked<FileOpsCore>,
797 _file: &starnix_core::vfs::FileObjectState,
798 _current_task: &CurrentTask,
799 ) {
800 let arc_file = *self;
801 if let Some(inspect) = &arc_file.0.inspect_status {
802 inspect.set_closed();
803 inspect.set_closed_timestamp(zx::MonotonicInstant::get().into_nanos());
804 }
805 }
806
807 fn ioctl(
808 &self,
809 locked: &mut Locked<Unlocked>,
810 file: &FileObject,
811 current_task: &CurrentTask,
812 request: u32,
813 arg: SyscallArg,
814 ) -> Result<SyscallResult, Errno> {
815 self.0.as_ref().ioctl(locked, file, current_task, request, arg)
816 }
817
818 fn read(
819 &self,
820 locked: &mut Locked<FileOpsCore>,
821 file: &FileObject,
822 current_task: &CurrentTask,
823 offset: usize,
824 data: &mut dyn OutputBuffer,
825 ) -> Result<usize, Errno> {
826 self.0.as_ref().read(locked, file, current_task, offset, data)
827 }
828
829 fn write(
830 &self,
831 locked: &mut Locked<FileOpsCore>,
832 file: &FileObject,
833 current_task: &CurrentTask,
834 offset: usize,
835 data: &mut dyn InputBuffer,
836 ) -> Result<usize, Errno> {
837 self.0.as_ref().write(locked, file, current_task, offset, data)
838 }
839
840 fn wait_async(
841 &self,
842 locked: &mut Locked<FileOpsCore>,
843 file: &FileObject,
844 current_task: &CurrentTask,
845 waiter: &Waiter,
846 events: FdEvents,
847 handler: EventHandler,
848 ) -> Option<WaitCanceler> {
849 self.0.as_ref().wait_async(locked, file, current_task, waiter, events, handler)
850 }
851
852 fn query_events(
853 &self,
854 locked: &mut Locked<FileOpsCore>,
855 file: &FileObject,
856 current_task: &CurrentTask,
857 ) -> Result<FdEvents, Errno> {
858 self.0.as_ref().query_events(locked, file, current_task)
859 }
860}
861
862pub struct BitSet<const NUM_BYTES: usize> {
863 bytes: [u8; NUM_BYTES],
864}
865
866impl<const NUM_BYTES: usize> BitSet<{ NUM_BYTES }> {
867 pub const fn new() -> Self {
868 Self { bytes: [0; NUM_BYTES] }
869 }
870
871 pub const fn list<const N: usize>(bits: [u32; N]) -> Self {
872 let mut bitset = Self::new();
873 let mut i = 0;
874 while i < bits.len() {
875 bitset.set(bits[i]);
876 i += 1;
877 }
878 bitset
879 }
880
881 pub const fn set(&mut self, bitnum: u32) {
882 let bitnum = bitnum as usize;
883 let byte = bitnum / 8;
884 let bit = bitnum % 8;
885 self.bytes[byte] |= 1 << bit;
886 }
887}
888
889#[cfg(test)]
890mod tests {
891 use super::*;
892 use std::sync::atomic::Ordering;
893
894 #[test]
895 fn test_read_events_no_notify_when_buffer_full() {
896 let inspector = fuchsia_inspect::Inspector::default();
897 let node = inspector.root();
898 let input_file = InputFile::new_touch(
899 uapi::input_id { bustype: 0, vendor: 0, product: 0, version: 0 },
900 100,
901 100,
902 node,
903 );
904
905 let event1 = uapi::input_event {
907 type_: uapi::EV_KEY as u16,
908 code: 1,
909 value: 1,
910 ..Default::default()
911 };
912 let event2 = uapi::input_event {
913 type_: uapi::EV_KEY as u16,
914 code: 2,
915 value: 1,
916 ..Default::default()
917 };
918 input_file.add_events(vec![event1, event2]);
919
920 let notify_count =
922 input_file.inspect_status.as_ref().unwrap().fd_notify_count.load(Ordering::Relaxed);
923 assert_eq!(notify_count, 1);
924
925 let events = input_file.read_events(1);
927 assert_eq!(events.len(), 1);
928
929 let notify_count =
931 input_file.inspect_status.as_ref().unwrap().fd_notify_count.load(Ordering::Relaxed);
932 assert_eq!(notify_count, 1);
933 }
934}