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::{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 _; // for `as_bytes()`
30
31uapi::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    /// The number of FIDL events received by this file from Fuchsia input system.
40    ///
41    /// We expect:
42    /// fidl_events_received_count = fidl_events_ignored_count +
43    ///                              fidl_events_unexpected_count +
44    ///                              fidl_events_converted_count
45    /// otherwise starnix ignored events unexpectedly.
46    ///
47    /// fidl_events_unexpected_count should be 0, if not it hints issues from upstream of ui stack.
48    pub fidl_events_received_count: AtomicU64,
49
50    /// The number of FIDL events ignored to this module’s representation of TouchEvent.
51    pub fidl_events_ignored_count: AtomicU64,
52
53    /// The unexpected number of FIDL events reached to this module should be filtered out
54    /// earlier in the UI stack.
55    /// It maybe unexpected format or unexpected order.
56    pub fidl_events_unexpected_count: AtomicU64,
57
58    /// The number of FIDL events converted to this module’s representation of TouchEvent.
59    pub fidl_events_converted_count: AtomicU64,
60
61    /// The number of uapi::input_events generated from TouchEvents.
62    pub uapi_events_generated_count: AtomicU64,
63
64    /// The event time of the last generated uapi::input_event.
65    pub last_generated_uapi_event_timestamp_ns: AtomicI64,
66
67    /// The number of uapi::input_events read from this input file by external process.
68    pub uapi_events_read_count: AtomicU64,
69
70    /// The event time of the last uapi::input_event read by external process.
71    pub last_read_uapi_event_timestamp_ns: AtomicI64,
72
73    /// Number of read calls.
74    pub fd_read_count: AtomicU64,
75
76    /// Number of notify calls.
77    pub fd_notify_count: AtomicU64,
78
79    /// Whether the file was opened without the NONBLOCK flag.
80    pub opened_without_nonblock: AtomicBool,
81
82    /// The timestamp when the file was opened.
83    pub open_timestamp_ns: AtomicI64,
84
85    /// Whether the file was closed (dropped).
86    pub closed: AtomicBool,
87
88    /// The timestamp when the file was closed.
89    pub close_timestamp_ns: AtomicI64,
90
91    /// The weak pointer to the InputFile.
92    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) }>, // ABSolute position
246    supported_motion_attributes: BitSet<{ min_bytes(REL_CNT) }>,   // RELative motion
247    supported_switches: BitSet<{ min_bytes(SW_CNT) }>,
248    supported_leds: BitSet<{ min_bytes(LED_CNT) }>,
249    supported_haptics: BitSet<{ min_bytes(FF_CNT) }>, // 'F'orce 'F'eedback
250    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    // InputFile will be initialized with an InputFileStatus that holds Inspect data
259    // `None` for Uinput InputFiles
260    pub inspect_status: Option<Arc<InputFileStatus>>,
261
262    // A descriptive device name. Should contain only alphanumerics and `_`.
263    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            // EV_SYN marks the end of a complete input event. Other event types are its properties,
281            // so they don't initiate a trace.
282            _ => LinuxEventWithTraceId { event: event, trace_id: None },
283        }
284    }
285}
286
287// Mutable state of `InputFile`
288struct InputFileMutableState {
289    pub(super) events: VecDeque<LinuxEventWithTraceId>,
290}
291
292/// Returns the minimum number of bytes required to store `n_bits` bits.
293const fn min_bytes(n_bits: u32) -> usize {
294    ((n_bits as usize) + 7) / 8
295}
296
297/// Returns appropriate `INPUT_PROP`-erties for a keyboard device.
298fn keyboard_properties() -> BitSet<{ min_bytes(INPUT_PROP_CNT) }> {
299    let mut attrs = BitSet::new();
300    attrs.set(INPUT_PROP_DIRECT);
301    attrs
302}
303
304/// Returns appropriate `KEY`-board related flags for a touchscreen device.
305fn touch_key_attributes() -> BitSet<{ min_bytes(KEY_CNT) }> {
306    let mut attrs = BitSet::new();
307    attrs.set(BTN_TOUCH);
308    attrs.set(BTN_MISC); // Include BTN_MISC as a catchall key event.
309    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
318/// Returns appropriate `ABS`-olute position related flags for a touchscreen device.
319fn 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
328/// Returns appropriate `INPUT_PROP`-erties for a touchscreen device.
329fn touch_properties() -> BitSet<{ min_bytes(INPUT_PROP_CNT) }> {
330    let mut attrs = BitSet::new();
331    attrs.set(INPUT_PROP_DIRECT);
332    attrs
333}
334
335/// Returns appropriate `KEY`-board related flags for a keyboard device.
336fn 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
344/// Returns appropriate `ABS`-olute position related flags for a keyboard device.
345fn 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
355/// Makes a device name string from a name and device ID details.
356///
357/// For practical reasons the device name should contain alphanumerics and `_`.
358fn 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    // Per https://www.linuxjournal.com/article/6429, the driver version is 32-bits wide,
364    // and interpreted as:
365    // * [31-16]: version
366    // * [15-08]: minor
367    // * [07-00]: patch level
368    const DRIVER_VERSION: u32 = 0;
369
370    /// Creates an `InputFile` instance suitable for emulating a touchscreen.
371    ///
372    /// # Parameters
373    /// - `input_id`: device's bustype, vendor id, product id, and version.
374    /// - `width`: width of screen.
375    /// - `height`: height of screen.
376    /// - `inspect_status`: The inspect status for the parent device of "touch_input_file".
377    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        // Fuchsia scales the position reported by the touch sensor to fit view coordinates.
385        // Hence, the range of touch positions is exactly the same as the range of view
386        // coordinates.
387        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(), // None supported, not a mouse.
394            supported_switches: BitSet::new(),          // None supported
395            supported_leds: BitSet::new(),              // None supported
396            supported_haptics: BitSet::new(),           // None supported
397            supported_misc_features: BitSet::new(),     // None supported
398            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                // TODO(https://fxbug.dev/42075436): `value` field should contain the most recent
413                // X position.
414                ..uapi::input_absinfo::default()
415            },
416            y_axis_info: uapi::input_absinfo {
417                minimum: 0,
418                maximum: i32::from(height),
419                // TODO(https://fxbug.dev/42075436): `value` field should contain the most recent
420                // Y position.
421                ..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    /// Creates an `InputFile` instance suitable for emulating a keyboard.
431    ///
432    /// # Parameters
433    /// - `input_id`: device's bustype, vendor id, product id, and version.
434    /// - `inspect_status`: The inspect status for the parent device of "keyboard_input_file".
435    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(), // None supported, not a mouse.
444            supported_switches: BitSet::new(),          // None supported
445            supported_leds: BitSet::new(),              // None supported
446            supported_haptics: BitSet::new(),           // None supported
447            supported_misc_features: BitSet::new(),     // None supported
448            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    /// Creates an `InputFile` instance suitable for emulating a mouse wheel.
461    ///
462    /// # Parameters
463    /// - `input_id`: device's bustype, vendor id, product id, and version.
464    /// - `inspect_status`: The inspect status for the parent device of "mouse_input_file".
465    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(), // None supported, scroll only
472            supported_position_attributes: BitSet::new(), // None supported, scroll only
473            supported_motion_attributes: mouse_wheel_attributes(),
474            supported_switches: BitSet::new(), // None supported
475            supported_leds: BitSet::new(),     // None supported
476            supported_haptics: BitSet::new(),  // None supported
477            supported_misc_features: BitSet::new(), // None supported
478            properties: BitSet::new(),         // None supported, scroll only
479            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
539// The bit-mask that removes the variable parts of the EVIOCGNAME ioctl
540// request.
541const 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                // Remove the variable part of the request with params, so
658                // we can identify it.
659                match request_with_params & EVIOCGNAME_MASK {
660                    uapi::EVIOCGNAME_0 => {
661                        // Request to report the device name.
662                        //
663                        // An EVIOCGNAME request comes with the response buffer size encoded in
664                        // bits 29..16 of the request's `u32` code.  This is in contrast to
665                        // most other ioctl request codes in this file, which are fully known
666                        // at compile time, so we need to decode it a bit differently from
667                        // other ioctl codes.
668                        //
669                        // See [here][hh] the macros that do this.
670                        //
671                        // [hh]: https://cs.opensource.google/fuchsia/fuchsia/+/main:third_party/android/platform/bionic/libc/kernel/uapi/linux/input.h;l=82;drc=0f0c18f695543b15b852f68f297744d03d642a26
672                        let device_name = &self.device_name;
673
674                        // The lowest 14 bits of the top 16 bits are the unsigned buffer
675                        // length in bytes.  While we don't use multibyte characters,
676                        // make sure that all sizes below are expressed in terms of
677                        // bytes, not characters.
678                        let buffer_bytes_count =
679                            ((request_with_params >> 16) & ((1 << 14) - 1)) as usize;
680
681                        // Zero out the entire user buffer in case the user reads too much.
682                        // Probably not needed, but I don't think it hurts.
683                        current_task.zero(user_addr, buffer_bytes_count)?;
684                        let device_name_as_bytes = device_name.as_bytes();
685
686                        // Copy all bytes from device name if the buffer is large enough.
687                        // If not, copy one less than the buffer size, to leave space
688                        // for the final NUL.
689                        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                        // EVIOCGNAME ioctl returns the number of bytes written.
696                        // Do not forget the trailing NUL.
697                        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        // The limit of the buffer is determined by taking the available bytes
725        // and using integer division on the size of uapi::input_event in bytes.
726        let limit = data.available() / input_event_size;
727        let events = self.read_events(limit);
728        if events.is_empty() {
729            // TODO: b/498956542 - ensure this is the correct behavior for input files
730            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}