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::{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 _; uapi::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 pub fidl_events_received_count: AtomicU64,
48
49 pub fidl_events_ignored_count: AtomicU64,
51
52 pub fidl_events_unexpected_count: AtomicU64,
56
57 pub fidl_events_converted_count: AtomicU64,
59
60 pub uapi_events_generated_count: AtomicU64,
62
63 pub last_generated_uapi_event_timestamp_ns: AtomicI64,
65
66 pub uapi_events_read_count: AtomicU64,
68
69 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) }>, supported_motion_attributes: BitSet<{ min_bytes(REL_CNT) }>, supported_switches: BitSet<{ min_bytes(SW_CNT) }>,
169 supported_leds: BitSet<{ min_bytes(LED_CNT) }>,
170 supported_haptics: BitSet<{ min_bytes(FF_CNT) }>, 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 pub inspect_status: Option<Arc<InputFileStatus>>,
181
182 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 _ => LinuxEventWithTraceId { event: event, trace_id: None },
203 }
204 }
205}
206
207pub struct InputFileMutableState {
209 pub events: VecDeque<LinuxEventWithTraceId>,
210 pub waiters: WaitQueue,
211}
212
213const fn min_bytes(n_bits: u32) -> usize {
215 ((n_bits as usize) + 7) / 8
216}
217
218fn keyboard_properties() -> BitSet<{ min_bytes(INPUT_PROP_CNT) }> {
220 let mut attrs = BitSet::new();
221 attrs.set(INPUT_PROP_DIRECT);
222 attrs
223}
224
225fn touch_key_attributes() -> BitSet<{ min_bytes(KEY_CNT) }> {
227 let mut attrs = BitSet::new();
228 attrs.set(BTN_TOUCH);
229 attrs.set(BTN_MISC); 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
239fn 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
249fn touch_properties() -> BitSet<{ min_bytes(INPUT_PROP_CNT) }> {
251 let mut attrs = BitSet::new();
252 attrs.set(INPUT_PROP_DIRECT);
253 attrs
254}
255
256fn 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
265fn 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
276fn 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 const DRIVER_VERSION: u32 = 0;
290
291 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 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(), supported_switches: BitSet::new(), supported_leds: BitSet::new(), supported_haptics: BitSet::new(), supported_misc_features: BitSet::new(), 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 ..uapi::input_absinfo::default()
336 },
337 y_axis_info: uapi::input_absinfo {
338 minimum: 0,
339 maximum: i32::from(height),
340 ..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 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(), supported_switches: BitSet::new(), supported_leds: BitSet::new(), supported_haptics: BitSet::new(), supported_misc_features: BitSet::new(), 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 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(), supported_position_attributes: BitSet::new(), supported_motion_attributes: mouse_wheel_attributes(),
399 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(),
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
418const EVIOCGNAME_MASK: u32 = 0b11_00_0000_0000_0000_1111_1111_1111_1111;
421
422impl 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 match request_with_params & EVIOCGNAME_MASK {
514 uapi::EVIOCGNAME_0 => {
515 let device_name = &self.device_name;
527
528 let buffer_bytes_count =
533 ((request_with_params >> 16) & ((1 << 14) - 1)) as usize;
534
535 current_task.zero(user_addr, buffer_bytes_count)?;
538 let device_name_as_bytes = device_name.as_bytes();
539
540 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 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 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 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}