Skip to main content

starnix_modules_input/
input_file.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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::{CloseFreeSafe, 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::user_address::{ArchSpecific, MultiArchUserRef, UserAddress, UserRef};
18use starnix_uapi::vfs::FdEvents;
19use starnix_uapi::{
20    ABS_CNT, ABS_MT_POSITION_X, ABS_MT_POSITION_Y, ABS_MT_SLOT, ABS_MT_TRACKING_ID, BTN_MISC,
21    BTN_TOUCH, EV_CNT, FF_CNT, INPUT_PROP_CNT, INPUT_PROP_DIRECT, KEY_CNT, KEY_DOWN, KEY_LEFT,
22    KEY_POWER, KEY_RIGHT, KEY_SLEEP, KEY_UP, KEY_VOLUMEDOWN, LED_CNT, MSC_CNT, REL_CNT, REL_WHEEL,
23    SW_CNT, errno, error, uapi,
24};
25use std::collections::VecDeque;
26use std::sync::Arc;
27use std::sync::atomic::{AtomicI64, AtomicU64, Ordering};
28use zerocopy::IntoBytes as _; // for `as_bytes()`
29
30uapi::check_arch_independent_layout! {
31    input_id {}
32    input_absinfo {}
33}
34
35type InputEventPtr = MultiArchUserRef<uapi::input_event, uapi::arch32::input_event>;
36
37pub struct InputFileStatus {
38    /// The number of FIDL events received by this file from Fuchsia input system.
39    ///
40    /// We expect:
41    /// fidl_events_received_count = fidl_events_ignored_count +
42    ///                              fidl_events_unexpected_count +
43    ///                              fidl_events_converted_count
44    /// otherwise starnix ignored events unexpectedly.
45    ///
46    /// fidl_events_unexpected_count should be 0, if not it hints issues from upstream of ui stack.
47    pub fidl_events_received_count: AtomicU64,
48
49    /// The number of FIDL events ignored to this module’s representation of TouchEvent.
50    pub fidl_events_ignored_count: AtomicU64,
51
52    /// The unexpected number of FIDL events reached to this module should be filtered out
53    /// earlier in the UI stack.
54    /// It maybe unexpected format or unexpected order.
55    pub fidl_events_unexpected_count: AtomicU64,
56
57    /// The number of FIDL events converted to this module’s representation of TouchEvent.
58    pub fidl_events_converted_count: AtomicU64,
59
60    /// The number of uapi::input_events generated from TouchEvents.
61    pub uapi_events_generated_count: AtomicU64,
62
63    /// The event time of the last generated uapi::input_event.
64    pub last_generated_uapi_event_timestamp_ns: AtomicI64,
65
66    /// The number of uapi::input_events read from this input file by external process.
67    pub uapi_events_read_count: AtomicU64,
68
69    /// The event time of the last uapi::input_event read by external process.
70    pub last_read_uapi_event_timestamp_ns: AtomicI64,
71}
72
73impl InputFileStatus {
74    fn new(node: &fuchsia_inspect::Node) -> Arc<Self> {
75        let status = Arc::new(Self {
76            fidl_events_received_count: AtomicU64::new(0),
77            fidl_events_ignored_count: AtomicU64::new(0),
78            fidl_events_unexpected_count: AtomicU64::new(0),
79            fidl_events_converted_count: AtomicU64::new(0),
80            uapi_events_generated_count: AtomicU64::new(0),
81            last_generated_uapi_event_timestamp_ns: AtomicI64::new(0),
82            uapi_events_read_count: AtomicU64::new(0),
83            last_read_uapi_event_timestamp_ns: AtomicI64::new(0),
84        });
85
86        let weak_status = Arc::downgrade(&status);
87        node.record_lazy_values("status", move || {
88            let status = weak_status.upgrade();
89            async move {
90                let inspector = Inspector::default();
91                if let Some(status) = status {
92                    let root = inspector.root();
93                    root.record_uint(
94                        "fidl_events_received_count",
95                        status.fidl_events_received_count.load(Ordering::Relaxed),
96                    );
97                    root.record_uint(
98                        "fidl_events_ignored_count",
99                        status.fidl_events_ignored_count.load(Ordering::Relaxed),
100                    );
101                    root.record_uint(
102                        "fidl_events_unexpected_count",
103                        status.fidl_events_unexpected_count.load(Ordering::Relaxed),
104                    );
105                    root.record_uint(
106                        "fidl_events_converted_count",
107                        status.fidl_events_converted_count.load(Ordering::Relaxed),
108                    );
109                    root.record_uint(
110                        "uapi_events_generated_count",
111                        status.uapi_events_generated_count.load(Ordering::Relaxed),
112                    );
113                    root.record_int(
114                        "last_generated_uapi_event_timestamp_ns",
115                        status.last_generated_uapi_event_timestamp_ns.load(Ordering::Relaxed),
116                    );
117                    root.record_uint(
118                        "uapi_events_read_count",
119                        status.uapi_events_read_count.load(Ordering::Relaxed),
120                    );
121                    root.record_int(
122                        "last_read_uapi_event_timestamp_ns",
123                        status.last_read_uapi_event_timestamp_ns.load(Ordering::Relaxed),
124                    );
125                }
126                Ok(inspector)
127            }
128            .boxed()
129        });
130
131        status
132    }
133
134    pub fn count_received_events(&self, count: u64) {
135        self.fidl_events_received_count.fetch_add(count, Ordering::Relaxed);
136    }
137
138    pub fn count_ignored_events(&self, count: u64) {
139        self.fidl_events_ignored_count.fetch_add(count, Ordering::Relaxed);
140    }
141
142    pub fn count_unexpected_events(&self, count: u64) {
143        self.fidl_events_unexpected_count.fetch_add(count, Ordering::Relaxed);
144    }
145
146    pub fn count_converted_events(&self, count: u64) {
147        self.fidl_events_converted_count.fetch_add(count, Ordering::Relaxed);
148    }
149
150    pub fn count_generated_events(&self, count: u64, event_time_ns: i64) {
151        self.uapi_events_generated_count.fetch_add(count, Ordering::Relaxed);
152        self.last_generated_uapi_event_timestamp_ns.store(event_time_ns, Ordering::Relaxed);
153    }
154
155    pub fn count_read_events(&self, count: u64, event_time_ns: i64) {
156        self.uapi_events_read_count.fetch_add(count, Ordering::Relaxed);
157        self.last_read_uapi_event_timestamp_ns.store(event_time_ns, Ordering::Relaxed);
158    }
159}
160
161pub struct InputFile {
162    driver_version: u32,
163    input_id: uapi::input_id,
164    supported_event_types: BitSet<{ min_bytes(EV_CNT) }>,
165    supported_keys: BitSet<{ min_bytes(KEY_CNT) }>,
166    supported_position_attributes: BitSet<{ min_bytes(ABS_CNT) }>, // ABSolute position
167    supported_motion_attributes: BitSet<{ min_bytes(REL_CNT) }>,   // RELative motion
168    supported_switches: BitSet<{ min_bytes(SW_CNT) }>,
169    supported_leds: BitSet<{ min_bytes(LED_CNT) }>,
170    supported_haptics: BitSet<{ min_bytes(FF_CNT) }>, // 'F'orce 'F'eedback
171    supported_misc_features: BitSet<{ min_bytes(MSC_CNT) }>,
172    properties: BitSet<{ min_bytes(INPUT_PROP_CNT) }>,
173    mt_slot_axis_info: uapi::input_absinfo,
174    mt_tracking_id_axis_info: uapi::input_absinfo,
175    x_axis_info: uapi::input_absinfo,
176    y_axis_info: uapi::input_absinfo,
177    pub inner: Mutex<InputFileMutableState>,
178    // InputFile will be initialized with an InputFileStatus that holds Inspect data
179    // `None` for Uinput InputFiles
180    pub inspect_status: Option<Arc<InputFileStatus>>,
181
182    // A descriptive device name. Should contain only alphanumerics and `_`.
183    device_name: String,
184}
185
186pub struct LinuxEventWithTraceId {
187    pub event: uapi::input_event,
188    pub trace_id: Option<fuchsia_trace::Id>,
189}
190
191impl LinuxEventWithTraceId {
192    pub fn new(event: uapi::input_event) -> Self {
193        match event.type_ as u32 {
194            uapi::EV_SYN => {
195                let trace_id = fuchsia_trace::Id::random();
196                trace_duration!("input", "linux_event_create");
197                trace_flow_begin!("input", "linux_event", trace_id);
198                LinuxEventWithTraceId { event: event, trace_id: Some(trace_id) }
199            }
200            // EV_SYN marks the end of a complete input event. Other event types are its properties,
201            // so they don't initiate a trace.
202            _ => LinuxEventWithTraceId { event: event, trace_id: None },
203        }
204    }
205}
206
207// Mutable state of `InputFile`
208pub struct InputFileMutableState {
209    pub events: VecDeque<LinuxEventWithTraceId>,
210    pub waiters: WaitQueue,
211}
212
213/// Returns the minimum number of bytes required to store `n_bits` bits.
214const fn min_bytes(n_bits: u32) -> usize {
215    ((n_bits as usize) + 7) / 8
216}
217
218/// Returns appropriate `INPUT_PROP`-erties for a keyboard device.
219fn keyboard_properties() -> BitSet<{ min_bytes(INPUT_PROP_CNT) }> {
220    let mut attrs = BitSet::new();
221    attrs.set(INPUT_PROP_DIRECT);
222    attrs
223}
224
225/// Returns appropriate `KEY`-board related flags for a touchscreen device.
226fn touch_key_attributes() -> BitSet<{ min_bytes(KEY_CNT) }> {
227    let mut attrs = BitSet::new();
228    attrs.set(BTN_TOUCH);
229    attrs.set(BTN_MISC); // Include BTN_MISC as a catchall key event.
230    attrs.set(KEY_SLEEP);
231    attrs.set(KEY_UP);
232    attrs.set(KEY_LEFT);
233    attrs.set(KEY_RIGHT);
234    attrs.set(KEY_DOWN);
235
236    attrs
237}
238
239/// Returns appropriate `ABS`-olute position related flags for a touchscreen device.
240fn touch_position_attributes() -> BitSet<{ min_bytes(ABS_CNT) }> {
241    let mut attrs = BitSet::new();
242    attrs.set(ABS_MT_SLOT);
243    attrs.set(ABS_MT_TRACKING_ID);
244    attrs.set(ABS_MT_POSITION_X);
245    attrs.set(ABS_MT_POSITION_Y);
246    attrs
247}
248
249/// Returns appropriate `INPUT_PROP`-erties for a touchscreen device.
250fn touch_properties() -> BitSet<{ min_bytes(INPUT_PROP_CNT) }> {
251    let mut attrs = BitSet::new();
252    attrs.set(INPUT_PROP_DIRECT);
253    attrs
254}
255
256/// Returns appropriate `KEY`-board related flags for a keyboard device.
257fn keyboard_key_attributes() -> BitSet<{ min_bytes(KEY_CNT) }> {
258    let mut attrs = BitSet::new();
259    attrs.set(BTN_MISC);
260    attrs.set(KEY_POWER);
261    attrs.set(KEY_VOLUMEDOWN);
262    attrs
263}
264
265/// Returns appropriate `ABS`-olute position related flags for a keyboard device.
266fn keyboard_position_attributes() -> BitSet<{ min_bytes(ABS_CNT) }> {
267    BitSet::new()
268}
269
270fn mouse_wheel_attributes() -> BitSet<{ min_bytes(REL_CNT) }> {
271    let mut attrs = BitSet::new();
272    attrs.set(REL_WHEEL);
273    attrs
274}
275
276/// Makes a device name string from a name and device ID details.
277///
278/// For practical reasons the device name should contain alphanumerics and `_`.
279fn get_device_name(name: &str, input_id: &uapi::input_id) -> String {
280    format!("{}_{:04x}_{:04x}_v{}", name, input_id.vendor, input_id.product, input_id.version)
281}
282
283impl InputFile {
284    // Per https://www.linuxjournal.com/article/6429, the driver version is 32-bits wide,
285    // and interpreted as:
286    // * [31-16]: version
287    // * [15-08]: minor
288    // * [07-00]: patch level
289    const DRIVER_VERSION: u32 = 0;
290
291    /// Creates an `InputFile` instance suitable for emulating a touchscreen.
292    ///
293    /// # Parameters
294    /// - `input_id`: device's bustype, vendor id, product id, and version.
295    /// - `width`: width of screen.
296    /// - `height`: height of screen.
297    /// - `inspect_status`: The inspect status for the parent device of "touch_input_file".
298    pub fn new_touch(
299        input_id: uapi::input_id,
300        width: i32,
301        height: i32,
302        node: Option<&fuchsia_inspect::Node>,
303    ) -> Self {
304        let device_name = get_device_name("starnix_touch", &input_id);
305        // Fuchsia scales the position reported by the touch sensor to fit view coordinates.
306        // Hence, the range of touch positions is exactly the same as the range of view
307        // coordinates.
308        Self {
309            driver_version: Self::DRIVER_VERSION,
310            input_id,
311            supported_event_types: BitSet::list([uapi::EV_ABS]),
312            supported_keys: touch_key_attributes(),
313            supported_position_attributes: touch_position_attributes(),
314            supported_motion_attributes: BitSet::new(), // None supported, not a mouse.
315            supported_switches: BitSet::new(),          // None supported
316            supported_leds: BitSet::new(),              // None supported
317            supported_haptics: BitSet::new(),           // None supported
318            supported_misc_features: BitSet::new(),     // None supported
319            properties: touch_properties(),
320            mt_slot_axis_info: uapi::input_absinfo {
321                minimum: 0,
322                maximum: 10,
323                ..uapi::input_absinfo::default()
324            },
325            mt_tracking_id_axis_info: uapi::input_absinfo {
326                minimum: 0,
327                maximum: i32::MAX,
328                ..uapi::input_absinfo::default()
329            },
330            x_axis_info: uapi::input_absinfo {
331                minimum: 0,
332                maximum: i32::from(width),
333                // TODO(https://fxbug.dev/42075436): `value` field should contain the most recent
334                // X position.
335                ..uapi::input_absinfo::default()
336            },
337            y_axis_info: uapi::input_absinfo {
338                minimum: 0,
339                maximum: i32::from(height),
340                // TODO(https://fxbug.dev/42075436): `value` field should contain the most recent
341                // Y position.
342                ..uapi::input_absinfo::default()
343            },
344            inner: Mutex::new(InputFileMutableState {
345                events: VecDeque::new(),
346                waiters: WaitQueue::default(),
347            }),
348            inspect_status: node.map(|n| InputFileStatus::new(n)),
349            device_name,
350        }
351    }
352
353    /// Creates an `InputFile` instance suitable for emulating a keyboard.
354    ///
355    /// # Parameters
356    /// - `input_id`: device's bustype, vendor id, product id, and version.
357    /// - `inspect_status`: The inspect status for the parent device of "keyboard_input_file".
358    pub fn new_keyboard(input_id: uapi::input_id, node: Option<&fuchsia_inspect::Node>) -> Self {
359        let device_name = get_device_name("starnix_buttons", &input_id);
360        Self {
361            driver_version: Self::DRIVER_VERSION,
362            input_id,
363            supported_event_types: BitSet::list([uapi::EV_KEY]),
364            supported_keys: keyboard_key_attributes(),
365            supported_position_attributes: keyboard_position_attributes(),
366            supported_motion_attributes: BitSet::new(), // None supported, not a mouse.
367            supported_switches: BitSet::new(),          // None supported
368            supported_leds: BitSet::new(),              // None supported
369            supported_haptics: BitSet::new(),           // None supported
370            supported_misc_features: BitSet::new(),     // None supported
371            properties: keyboard_properties(),
372            mt_slot_axis_info: uapi::input_absinfo::default(),
373            mt_tracking_id_axis_info: uapi::input_absinfo::default(),
374            x_axis_info: uapi::input_absinfo::default(),
375            y_axis_info: uapi::input_absinfo::default(),
376            inner: Mutex::new(InputFileMutableState {
377                events: VecDeque::new(),
378                waiters: WaitQueue::default(),
379            }),
380            inspect_status: node.map(|n| InputFileStatus::new(n)),
381            device_name,
382        }
383    }
384
385    /// Creates an `InputFile` instance suitable for emulating a mouse wheel.
386    ///
387    /// # Parameters
388    /// - `input_id`: device's bustype, vendor id, product id, and version.
389    /// - `inspect_status`: The inspect status for the parent device of "mouse_input_file".
390    pub fn new_mouse(input_id: uapi::input_id, node: Option<&fuchsia_inspect::Node>) -> Self {
391        let device_name = get_device_name("starnix_mouse", &input_id);
392        Self {
393            driver_version: Self::DRIVER_VERSION,
394            input_id,
395            supported_event_types: BitSet::list([uapi::EV_REL]),
396            supported_keys: BitSet::new(), // None supported, scroll only
397            supported_position_attributes: BitSet::new(), // None supported, scroll only
398            supported_motion_attributes: mouse_wheel_attributes(),
399            supported_switches: BitSet::new(), // None supported
400            supported_leds: BitSet::new(),     // None supported
401            supported_haptics: BitSet::new(),  // None supported
402            supported_misc_features: BitSet::new(), // None supported
403            properties: BitSet::new(),         // None supported, scroll only
404            mt_slot_axis_info: uapi::input_absinfo::default(),
405            mt_tracking_id_axis_info: uapi::input_absinfo::default(),
406            x_axis_info: uapi::input_absinfo::default(),
407            y_axis_info: uapi::input_absinfo::default(),
408            inner: Mutex::new(InputFileMutableState {
409                events: VecDeque::new(),
410                waiters: WaitQueue::default(),
411            }),
412            inspect_status: node.map(|n| InputFileStatus::new(n)),
413            device_name,
414        }
415    }
416}
417
418// The bit-mask that removes the variable parts of the EVIOCGNAME ioctl
419// request.
420const EVIOCGNAME_MASK: u32 = 0b11_00_0000_0000_0000_1111_1111_1111_1111;
421
422/// `InputFile` doesn't implement the `close` method.
423impl CloseFreeSafe for InputFile {}
424impl FileOps for InputFile {
425    fileops_impl_nonseekable!();
426    fileops_impl_noop_sync!();
427
428    fn ioctl(
429        &self,
430        _locked: &mut Locked<Unlocked>,
431        _file: &FileObject,
432        current_task: &CurrentTask,
433        request: u32,
434        arg: SyscallArg,
435    ) -> Result<SyscallResult, Errno> {
436        let user_addr = UserAddress::from(arg);
437        match request {
438            uapi::EVIOCGVERSION => {
439                current_task.write_object(UserRef::new(user_addr), &self.driver_version)?;
440                Ok(SUCCESS)
441            }
442            uapi::EVIOCGID => {
443                current_task.write_object(UserRef::new(user_addr), &self.input_id)?;
444                Ok(SUCCESS)
445            }
446            uapi::EVIOCGBIT_0 => {
447                current_task
448                    .write_object(UserRef::new(user_addr), &self.supported_event_types.bytes)?;
449                Ok(SUCCESS)
450            }
451            uapi::EVIOCGBIT_EV_KEY => {
452                current_task.write_object(UserRef::new(user_addr), &self.supported_keys.bytes)?;
453                Ok(SUCCESS)
454            }
455            uapi::EVIOCGBIT_EV_ABS => {
456                current_task.write_object(
457                    UserRef::new(user_addr),
458                    &self.supported_position_attributes.bytes,
459                )?;
460                Ok(SUCCESS)
461            }
462            uapi::EVIOCGBIT_EV_REL => {
463                current_task.write_object(
464                    UserRef::new(user_addr),
465                    &self.supported_motion_attributes.bytes,
466                )?;
467                Ok(SUCCESS)
468            }
469            uapi::EVIOCGBIT_EV_SW => {
470                current_task
471                    .write_object(UserRef::new(user_addr), &self.supported_switches.bytes)?;
472                Ok(SUCCESS)
473            }
474            uapi::EVIOCGBIT_EV_LED => {
475                current_task.write_object(UserRef::new(user_addr), &self.supported_leds.bytes)?;
476                Ok(SUCCESS)
477            }
478            uapi::EVIOCGBIT_EV_FF => {
479                current_task
480                    .write_object(UserRef::new(user_addr), &self.supported_haptics.bytes)?;
481                Ok(SUCCESS)
482            }
483            uapi::EVIOCGBIT_EV_MSC => {
484                current_task
485                    .write_object(UserRef::new(user_addr), &self.supported_misc_features.bytes)?;
486                Ok(SUCCESS)
487            }
488            uapi::EVIOCGPROP => {
489                current_task.write_object(UserRef::new(user_addr), &self.properties.bytes)?;
490                Ok(SUCCESS)
491            }
492            uapi::EVIOCGABS_MT_SLOT => {
493                current_task.write_object(UserRef::new(user_addr), &self.mt_slot_axis_info)?;
494                Ok(SUCCESS)
495            }
496            uapi::EVIOCGABS_MT_TRACKING_ID => {
497                current_task
498                    .write_object(UserRef::new(user_addr), &self.mt_tracking_id_axis_info)?;
499                Ok(SUCCESS)
500            }
501            uapi::EVIOCGABS_MT_POSITION_X => {
502                current_task.write_object(UserRef::new(user_addr), &self.x_axis_info)?;
503                Ok(SUCCESS)
504            }
505            uapi::EVIOCGABS_MT_POSITION_Y => {
506                current_task.write_object(UserRef::new(user_addr), &self.y_axis_info)?;
507                Ok(SUCCESS)
508            }
509
510            request_with_params => {
511                // Remove the variable part of the request with params, so
512                // we can identify it.
513                match request_with_params & EVIOCGNAME_MASK {
514                    uapi::EVIOCGNAME_0 => {
515                        // Request to report the device name.
516                        //
517                        // An EVIOCGNAME request comes with the response buffer size encoded in
518                        // bits 29..16 of the request's `u32` code.  This is in contrast to
519                        // most other ioctl request codes in this file, which are fully known
520                        // at compile time, so we need to decode it a bit differently from
521                        // other ioctl codes.
522                        //
523                        // See [here][hh] the macros that do this.
524                        //
525                        // [hh]: https://cs.opensource.google/fuchsia/fuchsia/+/main:third_party/android/platform/bionic/libc/kernel/uapi/linux/input.h;l=82;drc=0f0c18f695543b15b852f68f297744d03d642a26
526                        let device_name = &self.device_name;
527
528                        // The lowest 14 bits of the top 16 bits are the unsigned buffer
529                        // length in bytes.  While we don't use multibyte characters,
530                        // make sure that all sizes below are expressed in terms of
531                        // bytes, not characters.
532                        let buffer_bytes_count =
533                            ((request_with_params >> 16) & ((1 << 14) - 1)) as usize;
534
535                        // Zero out the entire user buffer in case the user reads too much.
536                        // Probably not needed, but I don't think it hurts.
537                        current_task.zero(user_addr, buffer_bytes_count)?;
538                        let device_name_as_bytes = device_name.as_bytes();
539
540                        // Copy all bytes from device name if the buffer is large enough.
541                        // If not, copy one less than the buffer size, to leave space
542                        // for the final NUL.
543                        let to_copy_bytes_count =
544                            std::cmp::min(device_name_as_bytes.len(), buffer_bytes_count - 1);
545                        current_task.write_memory(
546                            user_addr,
547                            &device_name_as_bytes[..to_copy_bytes_count],
548                        )?;
549                        // EVIOCGNAME ioctl returns the number of bytes written.
550                        // Do not forget the trailing NUL.
551                        Ok((to_copy_bytes_count + 1).into())
552                    }
553                    _ => {
554                        track_stub!(
555                            TODO("https://fxbug.dev/322873200"),
556                            "input ioctl",
557                            request_with_params
558                        );
559                        error!(EOPNOTSUPP)
560                    }
561                }
562            }
563        }
564    }
565
566    fn read(
567        &self,
568        _locked: &mut Locked<FileOpsCore>,
569        _file: &FileObject,
570        current_task: &CurrentTask,
571        offset: usize,
572        data: &mut dyn OutputBuffer,
573    ) -> Result<usize, Errno> {
574        trace_duration!("input", "InputFile::read");
575        debug_assert!(offset == 0);
576        let mut inner = self.inner.lock();
577        let num_events = inner.events.len();
578        if num_events == 0 {
579            // TODO(https://fxbug.dev/42075445): `EAGAIN` is only permitted if the file is opened
580            // with `O_NONBLOCK`. Figure out what to do if the file is opened without that flag.
581            log_info!("read() returning EAGAIN");
582            return error!(EAGAIN);
583        }
584
585        let input_event_size = InputEventPtr::size_of_object_for(current_task);
586
587        // The limit of the buffer is determined by taking the available bytes
588        // and using integer division on the size of uapi::input_event in bytes.
589        // This is how many events we can write at a time, up to the amount of
590        // events queued to be written.
591        let limit = std::cmp::min(data.available() / input_event_size, num_events);
592        if num_events > limit {
593            log_info!(
594                "There was only space in the given buffer to read {} of the {} queued events. Sending a notification to prompt another read.",
595                limit,
596                num_events
597            );
598            inner.waiters.notify_fd_events(FdEvents::POLLIN);
599        }
600        let events: Vec<LinuxEventWithTraceId> = inner.events.drain(..limit).collect::<Vec<_>>();
601        let last_event_timeval = events.last().expect("events is nonempty").event.time;
602        let last_event_time_ns = duration_from_timeval::<zx::MonotonicTimeline>(last_event_timeval)
603            .unwrap()
604            .into_nanos();
605        self.inspect_status
606            .clone()
607            .map(|status| status.count_read_events(events.len() as u64, last_event_time_ns));
608
609        for event in &events {
610            if let Some(trace_id) = event.trace_id {
611                trace_duration!("input", "linux_event_read");
612                trace_flow_end!("input", "linux_event", trace_id);
613            }
614        }
615
616        if current_task.is_arch32() {
617            let events: Result<Vec<uapi::arch32::input_event>, _> =
618                events.iter().map(|e| uapi::arch32::input_event::try_from(e.event)).collect();
619            let events = events.map_err(|_| errno!(EINVAL))?;
620            data.write_all(events.as_bytes())
621        } else {
622            let events: Vec<uapi::input_event> = events.iter().map(|e| e.event).collect();
623            data.write_all(events.as_bytes())
624        }
625    }
626
627    fn write(
628        &self,
629        _locked: &mut Locked<FileOpsCore>,
630        _file: &FileObject,
631        _current_task: &CurrentTask,
632        offset: usize,
633        _data: &mut dyn InputBuffer,
634    ) -> Result<usize, Errno> {
635        debug_assert!(offset == 0);
636        track_stub!(TODO("https://fxbug.dev/322874385"), "write() on input device");
637        error!(EOPNOTSUPP)
638    }
639
640    fn wait_async(
641        &self,
642        _locked: &mut Locked<FileOpsCore>,
643        _file: &FileObject,
644        _current_task: &CurrentTask,
645        waiter: &Waiter,
646        events: FdEvents,
647        handler: EventHandler,
648    ) -> Option<WaitCanceler> {
649        Some(self.inner.lock().waiters.wait_async_fd_events(waiter, events, handler))
650    }
651
652    fn query_events(
653        &self,
654        _locked: &mut Locked<FileOpsCore>,
655        _file: &FileObject,
656        _current_task: &CurrentTask,
657    ) -> Result<FdEvents, Errno> {
658        Ok(if self.inner.lock().events.is_empty() { FdEvents::empty() } else { FdEvents::POLLIN })
659    }
660}
661
662pub struct BitSet<const NUM_BYTES: usize> {
663    bytes: [u8; NUM_BYTES],
664}
665
666impl<const NUM_BYTES: usize> BitSet<{ NUM_BYTES }> {
667    pub const fn new() -> Self {
668        Self { bytes: [0; NUM_BYTES] }
669    }
670
671    pub const fn list<const N: usize>(bits: [u32; N]) -> Self {
672        let mut bitset = Self::new();
673        let mut i = 0;
674        while i < bits.len() {
675            bitset.set(bits[i]);
676            i += 1;
677        }
678        bitset
679    }
680
681    pub const fn set(&mut self, bitnum: u32) {
682        let bitnum = bitnum as usize;
683        let byte = bitnum / 8;
684        let bit = bitnum % 8;
685        self.bytes[byte] |= 1 << bit;
686    }
687}