1use fuchsia_inspect::Inspector;
6use futures::FutureExt;
7use starnix_core::fileops_impl_nonseekable;
8use starnix_core::mm::{MemoryAccessor, MemoryAccessorExt};
9use starnix_core::task::{CurrentTask, EventHandler, WaitCanceler, WaitQueue, Waiter};
10use starnix_core::vfs::buffers::{InputBuffer, OutputBuffer};
11use starnix_core::vfs::{FileObject, FileOps, fileops_impl_noop_sync};
12use starnix_logging::{log_info, trace_duration, trace_flow_begin, trace_flow_end, track_stub};
13use starnix_sync::{FileOpsCore, Locked, Mutex, Unlocked};
14use starnix_syscalls::{SUCCESS, SyscallArg, SyscallResult};
15use starnix_types::time::duration_from_timeval;
16use starnix_uapi::errors::Errno;
17use starnix_uapi::open_flags::OpenFlags;
18use starnix_uapi::user_address::{ArchSpecific, MultiArchUserRef, UserAddress, UserRef};
19use starnix_uapi::vfs::FdEvents;
20use starnix_uapi::{
21 ABS_CNT, ABS_MT_POSITION_X, ABS_MT_POSITION_Y, ABS_MT_SLOT, ABS_MT_TRACKING_ID, BTN_MISC,
22 BTN_TOUCH, EV_CNT, FF_CNT, INPUT_PROP_CNT, INPUT_PROP_DIRECT, KEY_CNT, KEY_DOWN, KEY_LEFT,
23 KEY_POWER, KEY_RIGHT, KEY_SLEEP, KEY_UP, KEY_VOLUMEDOWN, LED_CNT, MSC_CNT, REL_CNT, REL_WHEEL,
24 SW_CNT, errno, error, uapi,
25};
26use std::collections::VecDeque;
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 inner: Mutex<InputFileMutableState>,
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::random();
276 trace_duration!("input", "linux_event_create");
277 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
287struct InputFileMutableState {
289 pub(super) events: VecDeque<LinuxEventWithTraceId>,
290}
291
292const fn min_bytes(n_bits: u32) -> usize {
294 ((n_bits as usize) + 7) / 8
295}
296
297fn keyboard_properties() -> BitSet<{ min_bytes(INPUT_PROP_CNT) }> {
299 let mut attrs = BitSet::new();
300 attrs.set(INPUT_PROP_DIRECT);
301 attrs
302}
303
304fn touch_key_attributes() -> BitSet<{ min_bytes(KEY_CNT) }> {
306 let mut attrs = BitSet::new();
307 attrs.set(BTN_TOUCH);
308 attrs.set(BTN_MISC); attrs.set(KEY_SLEEP);
310 attrs.set(KEY_UP);
311 attrs.set(KEY_LEFT);
312 attrs.set(KEY_RIGHT);
313 attrs.set(KEY_DOWN);
314
315 attrs
316}
317
318fn touch_position_attributes() -> BitSet<{ min_bytes(ABS_CNT) }> {
320 let mut attrs = BitSet::new();
321 attrs.set(ABS_MT_SLOT);
322 attrs.set(ABS_MT_TRACKING_ID);
323 attrs.set(ABS_MT_POSITION_X);
324 attrs.set(ABS_MT_POSITION_Y);
325 attrs
326}
327
328fn touch_properties() -> BitSet<{ min_bytes(INPUT_PROP_CNT) }> {
330 let mut attrs = BitSet::new();
331 attrs.set(INPUT_PROP_DIRECT);
332 attrs
333}
334
335fn keyboard_key_attributes() -> BitSet<{ min_bytes(KEY_CNT) }> {
337 let mut attrs = BitSet::new();
338 attrs.set(BTN_MISC);
339 attrs.set(KEY_POWER);
340 attrs.set(KEY_VOLUMEDOWN);
341 attrs
342}
343
344fn keyboard_position_attributes() -> BitSet<{ min_bytes(ABS_CNT) }> {
346 BitSet::new()
347}
348
349fn mouse_wheel_attributes() -> BitSet<{ min_bytes(REL_CNT) }> {
350 let mut attrs = BitSet::new();
351 attrs.set(REL_WHEEL);
352 attrs
353}
354
355fn get_device_name(name: &str, input_id: &uapi::input_id) -> String {
359 format!("{}_{:04x}_{:04x}_v{}", name, input_id.vendor, input_id.product, input_id.version)
360}
361
362impl InputFile {
363 const DRIVER_VERSION: u32 = 0;
369
370 pub fn new_touch(
378 input_id: uapi::input_id,
379 width: i32,
380 height: i32,
381 node: &fuchsia_inspect::Node,
382 ) -> Self {
383 let device_name = get_device_name("starnix_touch", &input_id);
384 Self {
388 driver_version: Self::DRIVER_VERSION,
389 input_id,
390 supported_event_types: BitSet::list([uapi::EV_ABS]),
391 supported_keys: touch_key_attributes(),
392 supported_position_attributes: touch_position_attributes(),
393 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(),
399 mt_slot_axis_info: uapi::input_absinfo {
400 minimum: 0,
401 maximum: 10,
402 ..uapi::input_absinfo::default()
403 },
404 mt_tracking_id_axis_info: uapi::input_absinfo {
405 minimum: 0,
406 maximum: i32::MAX,
407 ..uapi::input_absinfo::default()
408 },
409 x_axis_info: uapi::input_absinfo {
410 minimum: 0,
411 maximum: i32::from(width),
412 ..uapi::input_absinfo::default()
415 },
416 y_axis_info: uapi::input_absinfo {
417 minimum: 0,
418 maximum: i32::from(height),
419 ..uapi::input_absinfo::default()
422 },
423 inner: Mutex::new(InputFileMutableState { events: VecDeque::new() }),
424 waiters: WaitQueue::default(),
425 inspect_status: Some(InputFileStatus::new(node)),
426 device_name,
427 }
428 }
429
430 pub fn new_keyboard(input_id: uapi::input_id, node: &fuchsia_inspect::Node) -> Self {
436 let device_name = get_device_name("starnix_buttons", &input_id);
437 Self {
438 driver_version: Self::DRIVER_VERSION,
439 input_id,
440 supported_event_types: BitSet::list([uapi::EV_KEY]),
441 supported_keys: keyboard_key_attributes(),
442 supported_position_attributes: keyboard_position_attributes(),
443 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(),
449 mt_slot_axis_info: uapi::input_absinfo::default(),
450 mt_tracking_id_axis_info: uapi::input_absinfo::default(),
451 x_axis_info: uapi::input_absinfo::default(),
452 y_axis_info: uapi::input_absinfo::default(),
453 inner: Mutex::new(InputFileMutableState { events: VecDeque::new() }),
454 waiters: WaitQueue::default(),
455 inspect_status: Some(InputFileStatus::new(node)),
456 device_name,
457 }
458 }
459
460 pub fn new_mouse(input_id: uapi::input_id, node: &fuchsia_inspect::Node) -> Self {
466 let device_name = get_device_name("starnix_mouse", &input_id);
467 Self {
468 driver_version: Self::DRIVER_VERSION,
469 input_id,
470 supported_event_types: BitSet::list([uapi::EV_REL]),
471 supported_keys: BitSet::new(), supported_position_attributes: BitSet::new(), supported_motion_attributes: mouse_wheel_attributes(),
474 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(),
480 mt_tracking_id_axis_info: uapi::input_absinfo::default(),
481 x_axis_info: uapi::input_absinfo::default(),
482 y_axis_info: uapi::input_absinfo::default(),
483 inner: Mutex::new(InputFileMutableState { events: VecDeque::new() }),
484 waiters: WaitQueue::default(),
485 inspect_status: Some(InputFileStatus::new(node)),
486 device_name,
487 }
488 }
489
490 pub fn init_inspect_status(self: &Arc<Self>) {
491 if let Some(inspect) = &self.inspect_status {
492 *inspect.input_file.lock() = Arc::downgrade(self);
493 }
494 }
495
496 pub fn add_events(&self, events: Vec<uapi::input_event>) {
497 if events.is_empty() {
498 return;
499 }
500 if let Some(inspect) = &self.inspect_status {
501 inspect.count_fd_notify_calls();
502 }
503 {
504 let mut inner = self.inner.lock();
505 inner.events.extend(events.into_iter().map(LinuxEventWithTraceId::new));
506 }
507 self.waiters.notify_fd_events(FdEvents::POLLIN);
508 }
509
510 pub fn read_events(&self, limit: usize) -> Vec<LinuxEventWithTraceId> {
511 if let Some(inspect) = &self.inspect_status {
512 inspect.count_fd_read_calls();
513 }
514 let (events, should_notify) = {
515 let mut inner = self.inner.lock();
516 let num_events = inner.events.len();
517 let limit = std::cmp::min(limit, num_events);
518 let should_notify = num_events > limit;
519 if should_notify {
520 log_info!(
521 "There was only space in the given buffer to read {} of the {} queued events. Sending a notification to prompt another read.",
522 limit,
523 num_events
524 );
525 }
526 let events = inner.events.drain(..limit).collect();
527 (events, should_notify)
528 };
529 if should_notify {
530 if let Some(inspect) = &self.inspect_status {
531 inspect.count_fd_notify_calls();
532 }
533 self.waiters.notify_fd_events(FdEvents::POLLIN);
534 }
535 events
536 }
537}
538
539const EVIOCGNAME_MASK: u32 = 0b11_00_0000_0000_0000_1111_1111_1111_1111;
542
543impl FileOps for InputFile {
544 fileops_impl_nonseekable!();
545 fileops_impl_noop_sync!();
546
547 fn open(
548 &self,
549 _locked: &mut Locked<FileOpsCore>,
550 file: &FileObject,
551 _current_task: &CurrentTask,
552 ) -> Result<(), Errno> {
553 if let Some(inspect) = &self.inspect_status {
554 inspect.set_open_timestamp(zx::MonotonicInstant::get().into_nanos());
555 if (file.flags() & OpenFlags::NONBLOCK) != OpenFlags::NONBLOCK {
556 inspect.set_opened_without_nonblock();
557 }
558 }
559 Ok(())
560 }
561
562 fn close(
563 self: Box<Self>,
564 _locked: &mut Locked<FileOpsCore>,
565 _file: &starnix_core::vfs::FileObjectState,
566 _current_task: &CurrentTask,
567 ) {
568 if let Some(inspect) = &self.inspect_status {
569 inspect.set_closed();
570 inspect.set_closed_timestamp(zx::MonotonicInstant::get().into_nanos());
571 }
572 }
573
574 fn ioctl(
575 &self,
576 _locked: &mut Locked<Unlocked>,
577 _file: &FileObject,
578 current_task: &CurrentTask,
579 request: u32,
580 arg: SyscallArg,
581 ) -> Result<SyscallResult, Errno> {
582 let user_addr = UserAddress::from(arg);
583 match request {
584 uapi::EVIOCGVERSION => {
585 current_task.write_object(UserRef::new(user_addr), &self.driver_version)?;
586 Ok(SUCCESS)
587 }
588 uapi::EVIOCGID => {
589 current_task.write_object(UserRef::new(user_addr), &self.input_id)?;
590 Ok(SUCCESS)
591 }
592 uapi::EVIOCGBIT_0 => {
593 current_task
594 .write_object(UserRef::new(user_addr), &self.supported_event_types.bytes)?;
595 Ok(SUCCESS)
596 }
597 uapi::EVIOCGBIT_EV_KEY => {
598 current_task.write_object(UserRef::new(user_addr), &self.supported_keys.bytes)?;
599 Ok(SUCCESS)
600 }
601 uapi::EVIOCGBIT_EV_ABS => {
602 current_task.write_object(
603 UserRef::new(user_addr),
604 &self.supported_position_attributes.bytes,
605 )?;
606 Ok(SUCCESS)
607 }
608 uapi::EVIOCGBIT_EV_REL => {
609 current_task.write_object(
610 UserRef::new(user_addr),
611 &self.supported_motion_attributes.bytes,
612 )?;
613 Ok(SUCCESS)
614 }
615 uapi::EVIOCGBIT_EV_SW => {
616 current_task
617 .write_object(UserRef::new(user_addr), &self.supported_switches.bytes)?;
618 Ok(SUCCESS)
619 }
620 uapi::EVIOCGBIT_EV_LED => {
621 current_task.write_object(UserRef::new(user_addr), &self.supported_leds.bytes)?;
622 Ok(SUCCESS)
623 }
624 uapi::EVIOCGBIT_EV_FF => {
625 current_task
626 .write_object(UserRef::new(user_addr), &self.supported_haptics.bytes)?;
627 Ok(SUCCESS)
628 }
629 uapi::EVIOCGBIT_EV_MSC => {
630 current_task
631 .write_object(UserRef::new(user_addr), &self.supported_misc_features.bytes)?;
632 Ok(SUCCESS)
633 }
634 uapi::EVIOCGPROP => {
635 current_task.write_object(UserRef::new(user_addr), &self.properties.bytes)?;
636 Ok(SUCCESS)
637 }
638 uapi::EVIOCGABS_MT_SLOT => {
639 current_task.write_object(UserRef::new(user_addr), &self.mt_slot_axis_info)?;
640 Ok(SUCCESS)
641 }
642 uapi::EVIOCGABS_MT_TRACKING_ID => {
643 current_task
644 .write_object(UserRef::new(user_addr), &self.mt_tracking_id_axis_info)?;
645 Ok(SUCCESS)
646 }
647 uapi::EVIOCGABS_MT_POSITION_X => {
648 current_task.write_object(UserRef::new(user_addr), &self.x_axis_info)?;
649 Ok(SUCCESS)
650 }
651 uapi::EVIOCGABS_MT_POSITION_Y => {
652 current_task.write_object(UserRef::new(user_addr), &self.y_axis_info)?;
653 Ok(SUCCESS)
654 }
655
656 request_with_params => {
657 match request_with_params & EVIOCGNAME_MASK {
660 uapi::EVIOCGNAME_0 => {
661 let device_name = &self.device_name;
673
674 let buffer_bytes_count =
679 ((request_with_params >> 16) & ((1 << 14) - 1)) as usize;
680
681 current_task.zero(user_addr, buffer_bytes_count)?;
684 let device_name_as_bytes = device_name.as_bytes();
685
686 let to_copy_bytes_count =
690 std::cmp::min(device_name_as_bytes.len(), buffer_bytes_count - 1);
691 current_task.write_memory(
692 user_addr,
693 &device_name_as_bytes[..to_copy_bytes_count],
694 )?;
695 Ok((to_copy_bytes_count + 1).into())
698 }
699 _ => {
700 track_stub!(
701 TODO("https://fxbug.dev/322873200"),
702 "input ioctl",
703 request_with_params
704 );
705 error!(EOPNOTSUPP)
706 }
707 }
708 }
709 }
710 }
711
712 fn read(
713 &self,
714 _locked: &mut Locked<FileOpsCore>,
715 _file: &FileObject,
716 current_task: &CurrentTask,
717 offset: usize,
718 data: &mut dyn OutputBuffer,
719 ) -> Result<usize, Errno> {
720 trace_duration!("input", "InputFile::read");
721 debug_assert!(offset == 0);
722 let input_event_size = InputEventPtr::size_of_object_for(current_task);
723
724 let limit = data.available() / input_event_size;
727 let events = self.read_events(limit);
728 if events.is_empty() {
729 log_info!("read() returning EAGAIN");
731 return error!(EAGAIN);
732 }
733
734 let last_event_timeval = events.last().expect("events is nonempty").event.time;
735 let last_event_time_ns = duration_from_timeval::<zx::MonotonicTimeline>(last_event_timeval)
736 .unwrap()
737 .into_nanos();
738 self.inspect_status
739 .clone()
740 .map(|status| status.count_read_events(events.len() as u64, last_event_time_ns));
741
742 for event in &events {
743 if let Some(trace_id) = event.trace_id {
744 trace_duration!("input", "linux_event_read");
745 trace_flow_end!("input", "linux_event", trace_id);
746 }
747 }
748
749 if current_task.is_arch32() {
750 let events: Result<Vec<uapi::arch32::input_event>, _> =
751 events.iter().map(|e| uapi::arch32::input_event::try_from(e.event)).collect();
752 let events = events.map_err(|_| errno!(EINVAL))?;
753 data.write_all(events.as_bytes())
754 } else {
755 let events: Vec<uapi::input_event> = events.iter().map(|e| e.event).collect();
756 data.write_all(events.as_bytes())
757 }
758 }
759
760 fn write(
761 &self,
762 _locked: &mut Locked<FileOpsCore>,
763 _file: &FileObject,
764 _current_task: &CurrentTask,
765 offset: usize,
766 _data: &mut dyn InputBuffer,
767 ) -> Result<usize, Errno> {
768 debug_assert!(offset == 0);
769 track_stub!(TODO("https://fxbug.dev/322874385"), "write() on input device");
770 error!(EOPNOTSUPP)
771 }
772
773 fn wait_async(
774 &self,
775 _locked: &mut Locked<FileOpsCore>,
776 _file: &FileObject,
777 _current_task: &CurrentTask,
778 waiter: &Waiter,
779 events: FdEvents,
780 handler: EventHandler,
781 ) -> Option<WaitCanceler> {
782 Some(self.waiters.wait_async_fd_events(waiter, events, handler))
783 }
784
785 fn query_events(
786 &self,
787 _locked: &mut Locked<FileOpsCore>,
788 _file: &FileObject,
789 _current_task: &CurrentTask,
790 ) -> Result<FdEvents, Errno> {
791 Ok(if self.inner.lock().events.is_empty() { FdEvents::empty() } else { FdEvents::POLLIN })
792 }
793}
794
795pub struct ArcInputFile(pub Arc<InputFile>);
796
797impl FileOps for ArcInputFile {
798 fileops_impl_nonseekable!();
799 fileops_impl_noop_sync!();
800
801 fn open(
802 &self,
803 locked: &mut Locked<FileOpsCore>,
804 file: &FileObject,
805 current_task: &CurrentTask,
806 ) -> Result<(), Errno> {
807 self.0.as_ref().open(locked, file, current_task)
808 }
809
810 fn close(
811 self: Box<Self>,
812 _locked: &mut Locked<FileOpsCore>,
813 _file: &starnix_core::vfs::FileObjectState,
814 _current_task: &CurrentTask,
815 ) {
816 let arc_file = *self;
817 if let Some(inspect) = &arc_file.0.inspect_status {
818 inspect.set_closed();
819 inspect.set_closed_timestamp(zx::MonotonicInstant::get().into_nanos());
820 }
821 }
822
823 fn ioctl(
824 &self,
825 locked: &mut Locked<Unlocked>,
826 file: &FileObject,
827 current_task: &CurrentTask,
828 request: u32,
829 arg: SyscallArg,
830 ) -> Result<SyscallResult, Errno> {
831 self.0.as_ref().ioctl(locked, file, current_task, request, arg)
832 }
833
834 fn read(
835 &self,
836 locked: &mut Locked<FileOpsCore>,
837 file: &FileObject,
838 current_task: &CurrentTask,
839 offset: usize,
840 data: &mut dyn OutputBuffer,
841 ) -> Result<usize, Errno> {
842 self.0.as_ref().read(locked, file, current_task, offset, data)
843 }
844
845 fn write(
846 &self,
847 locked: &mut Locked<FileOpsCore>,
848 file: &FileObject,
849 current_task: &CurrentTask,
850 offset: usize,
851 data: &mut dyn InputBuffer,
852 ) -> Result<usize, Errno> {
853 self.0.as_ref().write(locked, file, current_task, offset, data)
854 }
855
856 fn wait_async(
857 &self,
858 locked: &mut Locked<FileOpsCore>,
859 file: &FileObject,
860 current_task: &CurrentTask,
861 waiter: &Waiter,
862 events: FdEvents,
863 handler: EventHandler,
864 ) -> Option<WaitCanceler> {
865 self.0.as_ref().wait_async(locked, file, current_task, waiter, events, handler)
866 }
867
868 fn query_events(
869 &self,
870 locked: &mut Locked<FileOpsCore>,
871 file: &FileObject,
872 current_task: &CurrentTask,
873 ) -> Result<FdEvents, Errno> {
874 self.0.as_ref().query_events(locked, file, current_task)
875 }
876}
877
878pub struct BitSet<const NUM_BYTES: usize> {
879 bytes: [u8; NUM_BYTES],
880}
881
882impl<const NUM_BYTES: usize> BitSet<{ NUM_BYTES }> {
883 pub const fn new() -> Self {
884 Self { bytes: [0; NUM_BYTES] }
885 }
886
887 pub const fn list<const N: usize>(bits: [u32; N]) -> Self {
888 let mut bitset = Self::new();
889 let mut i = 0;
890 while i < bits.len() {
891 bitset.set(bits[i]);
892 i += 1;
893 }
894 bitset
895 }
896
897 pub const fn set(&mut self, bitnum: u32) {
898 let bitnum = bitnum as usize;
899 let byte = bitnum / 8;
900 let bit = bitnum % 8;
901 self.bytes[byte] |= 1 << bit;
902 }
903}