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 pub fd_read_count: AtomicU64,
74
75 pub fd_notify_count: AtomicU64,
77}
78
79impl InputFileStatus {
80 fn new(node: &fuchsia_inspect::Node) -> Arc<Self> {
81 let status = Arc::new(Self {
82 fidl_events_received_count: AtomicU64::new(0),
83 fidl_events_ignored_count: AtomicU64::new(0),
84 fidl_events_unexpected_count: AtomicU64::new(0),
85 fidl_events_converted_count: AtomicU64::new(0),
86 uapi_events_generated_count: AtomicU64::new(0),
87 last_generated_uapi_event_timestamp_ns: AtomicI64::new(0),
88 uapi_events_read_count: AtomicU64::new(0),
89 last_read_uapi_event_timestamp_ns: AtomicI64::new(0),
90 fd_read_count: AtomicU64::new(0),
91 fd_notify_count: AtomicU64::new(0),
92 });
93
94 let weak_status = Arc::downgrade(&status);
95 node.record_lazy_values("status", move || {
96 let status = weak_status.upgrade();
97 async move {
98 let inspector = Inspector::default();
99 if let Some(status) = status {
100 let root = inspector.root();
101 root.record_uint("fd_read_count", status.fd_read_count.load(Ordering::Relaxed));
102 root.record_uint(
103 "fd_notify_count",
104 status.fd_notify_count.load(Ordering::Relaxed),
105 );
106 root.record_uint(
107 "fidl_events_received_count",
108 status.fidl_events_received_count.load(Ordering::Relaxed),
109 );
110 root.record_uint(
111 "fidl_events_ignored_count",
112 status.fidl_events_ignored_count.load(Ordering::Relaxed),
113 );
114 root.record_uint(
115 "fidl_events_unexpected_count",
116 status.fidl_events_unexpected_count.load(Ordering::Relaxed),
117 );
118 root.record_uint(
119 "fidl_events_converted_count",
120 status.fidl_events_converted_count.load(Ordering::Relaxed),
121 );
122 root.record_uint(
123 "uapi_events_generated_count",
124 status.uapi_events_generated_count.load(Ordering::Relaxed),
125 );
126 root.record_int(
127 "last_generated_uapi_event_timestamp_ns",
128 status.last_generated_uapi_event_timestamp_ns.load(Ordering::Relaxed),
129 );
130 root.record_uint(
131 "uapi_events_read_count",
132 status.uapi_events_read_count.load(Ordering::Relaxed),
133 );
134 root.record_int(
135 "last_read_uapi_event_timestamp_ns",
136 status.last_read_uapi_event_timestamp_ns.load(Ordering::Relaxed),
137 );
138 }
139 Ok(inspector)
140 }
141 .boxed()
142 });
143
144 status
145 }
146
147 pub fn count_received_events(&self, count: u64) {
148 self.fidl_events_received_count.fetch_add(count, Ordering::Relaxed);
149 }
150
151 pub fn count_ignored_events(&self, count: u64) {
152 self.fidl_events_ignored_count.fetch_add(count, Ordering::Relaxed);
153 }
154
155 pub fn count_unexpected_events(&self, count: u64) {
156 self.fidl_events_unexpected_count.fetch_add(count, Ordering::Relaxed);
157 }
158
159 pub fn count_converted_events(&self, count: u64) {
160 self.fidl_events_converted_count.fetch_add(count, Ordering::Relaxed);
161 }
162
163 pub fn count_generated_events(&self, count: u64, event_time_ns: i64) {
164 self.uapi_events_generated_count.fetch_add(count, Ordering::Relaxed);
165 self.last_generated_uapi_event_timestamp_ns.store(event_time_ns, Ordering::Relaxed);
166 }
167
168 pub fn count_read_events(&self, count: u64, event_time_ns: i64) {
169 self.uapi_events_read_count.fetch_add(count, Ordering::Relaxed);
170 self.last_read_uapi_event_timestamp_ns.store(event_time_ns, Ordering::Relaxed);
171 }
172
173 pub fn count_fd_read_calls(&self) {
174 self.fd_read_count.fetch_add(1, Ordering::Relaxed);
175 }
176
177 pub fn count_fd_notify_calls(&self) {
178 self.fd_notify_count.fetch_add(1, Ordering::Relaxed);
179 }
180}
181
182pub struct InputFile {
183 driver_version: u32,
184 input_id: uapi::input_id,
185 supported_event_types: BitSet<{ min_bytes(EV_CNT) }>,
186 supported_keys: BitSet<{ min_bytes(KEY_CNT) }>,
187 supported_position_attributes: BitSet<{ min_bytes(ABS_CNT) }>, supported_motion_attributes: BitSet<{ min_bytes(REL_CNT) }>, supported_switches: BitSet<{ min_bytes(SW_CNT) }>,
190 supported_leds: BitSet<{ min_bytes(LED_CNT) }>,
191 supported_haptics: BitSet<{ min_bytes(FF_CNT) }>, supported_misc_features: BitSet<{ min_bytes(MSC_CNT) }>,
193 properties: BitSet<{ min_bytes(INPUT_PROP_CNT) }>,
194 mt_slot_axis_info: uapi::input_absinfo,
195 mt_tracking_id_axis_info: uapi::input_absinfo,
196 x_axis_info: uapi::input_absinfo,
197 y_axis_info: uapi::input_absinfo,
198 inner: Mutex<InputFileMutableState>,
199 waiters: WaitQueue,
200 pub inspect_status: Option<Arc<InputFileStatus>>,
203
204 device_name: String,
206}
207
208pub struct LinuxEventWithTraceId {
209 pub event: uapi::input_event,
210 pub trace_id: Option<fuchsia_trace::Id>,
211}
212
213impl LinuxEventWithTraceId {
214 pub fn new(event: uapi::input_event) -> Self {
215 match event.type_ as u32 {
216 uapi::EV_SYN => {
217 let trace_id = fuchsia_trace::Id::random();
218 trace_duration!("input", "linux_event_create");
219 trace_flow_begin!("input", "linux_event", trace_id);
220 LinuxEventWithTraceId { event: event, trace_id: Some(trace_id) }
221 }
222 _ => LinuxEventWithTraceId { event: event, trace_id: None },
225 }
226 }
227}
228
229struct InputFileMutableState {
231 pub(super) events: VecDeque<LinuxEventWithTraceId>,
232}
233
234const fn min_bytes(n_bits: u32) -> usize {
236 ((n_bits as usize) + 7) / 8
237}
238
239fn keyboard_properties() -> BitSet<{ min_bytes(INPUT_PROP_CNT) }> {
241 let mut attrs = BitSet::new();
242 attrs.set(INPUT_PROP_DIRECT);
243 attrs
244}
245
246fn touch_key_attributes() -> BitSet<{ min_bytes(KEY_CNT) }> {
248 let mut attrs = BitSet::new();
249 attrs.set(BTN_TOUCH);
250 attrs.set(BTN_MISC); attrs.set(KEY_SLEEP);
252 attrs.set(KEY_UP);
253 attrs.set(KEY_LEFT);
254 attrs.set(KEY_RIGHT);
255 attrs.set(KEY_DOWN);
256
257 attrs
258}
259
260fn touch_position_attributes() -> BitSet<{ min_bytes(ABS_CNT) }> {
262 let mut attrs = BitSet::new();
263 attrs.set(ABS_MT_SLOT);
264 attrs.set(ABS_MT_TRACKING_ID);
265 attrs.set(ABS_MT_POSITION_X);
266 attrs.set(ABS_MT_POSITION_Y);
267 attrs
268}
269
270fn touch_properties() -> BitSet<{ min_bytes(INPUT_PROP_CNT) }> {
272 let mut attrs = BitSet::new();
273 attrs.set(INPUT_PROP_DIRECT);
274 attrs
275}
276
277fn keyboard_key_attributes() -> BitSet<{ min_bytes(KEY_CNT) }> {
279 let mut attrs = BitSet::new();
280 attrs.set(BTN_MISC);
281 attrs.set(KEY_POWER);
282 attrs.set(KEY_VOLUMEDOWN);
283 attrs
284}
285
286fn keyboard_position_attributes() -> BitSet<{ min_bytes(ABS_CNT) }> {
288 BitSet::new()
289}
290
291fn mouse_wheel_attributes() -> BitSet<{ min_bytes(REL_CNT) }> {
292 let mut attrs = BitSet::new();
293 attrs.set(REL_WHEEL);
294 attrs
295}
296
297fn get_device_name(name: &str, input_id: &uapi::input_id) -> String {
301 format!("{}_{:04x}_{:04x}_v{}", name, input_id.vendor, input_id.product, input_id.version)
302}
303
304impl InputFile {
305 const DRIVER_VERSION: u32 = 0;
311
312 pub fn new_touch(
320 input_id: uapi::input_id,
321 width: i32,
322 height: i32,
323 node: Option<&fuchsia_inspect::Node>,
324 ) -> Self {
325 let device_name = get_device_name("starnix_touch", &input_id);
326 Self {
330 driver_version: Self::DRIVER_VERSION,
331 input_id,
332 supported_event_types: BitSet::list([uapi::EV_ABS]),
333 supported_keys: touch_key_attributes(),
334 supported_position_attributes: touch_position_attributes(),
335 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(),
341 mt_slot_axis_info: uapi::input_absinfo {
342 minimum: 0,
343 maximum: 10,
344 ..uapi::input_absinfo::default()
345 },
346 mt_tracking_id_axis_info: uapi::input_absinfo {
347 minimum: 0,
348 maximum: i32::MAX,
349 ..uapi::input_absinfo::default()
350 },
351 x_axis_info: uapi::input_absinfo {
352 minimum: 0,
353 maximum: i32::from(width),
354 ..uapi::input_absinfo::default()
357 },
358 y_axis_info: uapi::input_absinfo {
359 minimum: 0,
360 maximum: i32::from(height),
361 ..uapi::input_absinfo::default()
364 },
365 inner: Mutex::new(InputFileMutableState { events: VecDeque::new() }),
366 waiters: WaitQueue::default(),
367 inspect_status: node.map(|n| InputFileStatus::new(n)),
368 device_name,
369 }
370 }
371
372 pub fn new_keyboard(input_id: uapi::input_id, node: Option<&fuchsia_inspect::Node>) -> Self {
378 let device_name = get_device_name("starnix_buttons", &input_id);
379 Self {
380 driver_version: Self::DRIVER_VERSION,
381 input_id,
382 supported_event_types: BitSet::list([uapi::EV_KEY]),
383 supported_keys: keyboard_key_attributes(),
384 supported_position_attributes: keyboard_position_attributes(),
385 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(),
391 mt_slot_axis_info: uapi::input_absinfo::default(),
392 mt_tracking_id_axis_info: uapi::input_absinfo::default(),
393 x_axis_info: uapi::input_absinfo::default(),
394 y_axis_info: uapi::input_absinfo::default(),
395 inner: Mutex::new(InputFileMutableState { events: VecDeque::new() }),
396 waiters: WaitQueue::default(),
397 inspect_status: node.map(|n| InputFileStatus::new(n)),
398 device_name,
399 }
400 }
401
402 pub fn new_mouse(input_id: uapi::input_id, node: Option<&fuchsia_inspect::Node>) -> Self {
408 let device_name = get_device_name("starnix_mouse", &input_id);
409 Self {
410 driver_version: Self::DRIVER_VERSION,
411 input_id,
412 supported_event_types: BitSet::list([uapi::EV_REL]),
413 supported_keys: BitSet::new(), supported_position_attributes: BitSet::new(), supported_motion_attributes: mouse_wheel_attributes(),
416 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(),
422 mt_tracking_id_axis_info: uapi::input_absinfo::default(),
423 x_axis_info: uapi::input_absinfo::default(),
424 y_axis_info: uapi::input_absinfo::default(),
425 inner: Mutex::new(InputFileMutableState { events: VecDeque::new() }),
426 waiters: WaitQueue::default(),
427 inspect_status: node.map(|n| InputFileStatus::new(n)),
428 device_name,
429 }
430 }
431
432 pub fn add_events(&self, events: Vec<uapi::input_event>) {
433 if events.is_empty() {
434 return;
435 }
436 if let Some(inspect) = &self.inspect_status {
437 inspect.count_fd_notify_calls();
438 }
439 {
440 let mut inner = self.inner.lock();
441 inner.events.extend(events.into_iter().map(LinuxEventWithTraceId::new));
442 }
443 self.waiters.notify_fd_events(FdEvents::POLLIN);
444 }
445
446 pub fn read_events(&self, limit: usize) -> Vec<LinuxEventWithTraceId> {
447 if let Some(inspect) = &self.inspect_status {
448 inspect.count_fd_read_calls();
449 }
450 let (events, should_notify) = {
451 let mut inner = self.inner.lock();
452 let num_events = inner.events.len();
453 let limit = std::cmp::min(limit, num_events);
454 let should_notify = num_events > limit;
455 if should_notify {
456 log_info!(
457 "There was only space in the given buffer to read {} of the {} queued events. Sending a notification to prompt another read.",
458 limit,
459 num_events
460 );
461 }
462 let events = inner.events.drain(..limit).collect();
463 (events, should_notify)
464 };
465 if should_notify {
466 if let Some(inspect) = &self.inspect_status {
467 inspect.count_fd_notify_calls();
468 }
469 self.waiters.notify_fd_events(FdEvents::POLLIN);
470 }
471 events
472 }
473}
474
475const EVIOCGNAME_MASK: u32 = 0b11_00_0000_0000_0000_1111_1111_1111_1111;
478
479impl CloseFreeSafe for InputFile {}
481impl FileOps for InputFile {
482 fileops_impl_nonseekable!();
483 fileops_impl_noop_sync!();
484
485 fn ioctl(
486 &self,
487 _locked: &mut Locked<Unlocked>,
488 _file: &FileObject,
489 current_task: &CurrentTask,
490 request: u32,
491 arg: SyscallArg,
492 ) -> Result<SyscallResult, Errno> {
493 let user_addr = UserAddress::from(arg);
494 match request {
495 uapi::EVIOCGVERSION => {
496 current_task.write_object(UserRef::new(user_addr), &self.driver_version)?;
497 Ok(SUCCESS)
498 }
499 uapi::EVIOCGID => {
500 current_task.write_object(UserRef::new(user_addr), &self.input_id)?;
501 Ok(SUCCESS)
502 }
503 uapi::EVIOCGBIT_0 => {
504 current_task
505 .write_object(UserRef::new(user_addr), &self.supported_event_types.bytes)?;
506 Ok(SUCCESS)
507 }
508 uapi::EVIOCGBIT_EV_KEY => {
509 current_task.write_object(UserRef::new(user_addr), &self.supported_keys.bytes)?;
510 Ok(SUCCESS)
511 }
512 uapi::EVIOCGBIT_EV_ABS => {
513 current_task.write_object(
514 UserRef::new(user_addr),
515 &self.supported_position_attributes.bytes,
516 )?;
517 Ok(SUCCESS)
518 }
519 uapi::EVIOCGBIT_EV_REL => {
520 current_task.write_object(
521 UserRef::new(user_addr),
522 &self.supported_motion_attributes.bytes,
523 )?;
524 Ok(SUCCESS)
525 }
526 uapi::EVIOCGBIT_EV_SW => {
527 current_task
528 .write_object(UserRef::new(user_addr), &self.supported_switches.bytes)?;
529 Ok(SUCCESS)
530 }
531 uapi::EVIOCGBIT_EV_LED => {
532 current_task.write_object(UserRef::new(user_addr), &self.supported_leds.bytes)?;
533 Ok(SUCCESS)
534 }
535 uapi::EVIOCGBIT_EV_FF => {
536 current_task
537 .write_object(UserRef::new(user_addr), &self.supported_haptics.bytes)?;
538 Ok(SUCCESS)
539 }
540 uapi::EVIOCGBIT_EV_MSC => {
541 current_task
542 .write_object(UserRef::new(user_addr), &self.supported_misc_features.bytes)?;
543 Ok(SUCCESS)
544 }
545 uapi::EVIOCGPROP => {
546 current_task.write_object(UserRef::new(user_addr), &self.properties.bytes)?;
547 Ok(SUCCESS)
548 }
549 uapi::EVIOCGABS_MT_SLOT => {
550 current_task.write_object(UserRef::new(user_addr), &self.mt_slot_axis_info)?;
551 Ok(SUCCESS)
552 }
553 uapi::EVIOCGABS_MT_TRACKING_ID => {
554 current_task
555 .write_object(UserRef::new(user_addr), &self.mt_tracking_id_axis_info)?;
556 Ok(SUCCESS)
557 }
558 uapi::EVIOCGABS_MT_POSITION_X => {
559 current_task.write_object(UserRef::new(user_addr), &self.x_axis_info)?;
560 Ok(SUCCESS)
561 }
562 uapi::EVIOCGABS_MT_POSITION_Y => {
563 current_task.write_object(UserRef::new(user_addr), &self.y_axis_info)?;
564 Ok(SUCCESS)
565 }
566
567 request_with_params => {
568 match request_with_params & EVIOCGNAME_MASK {
571 uapi::EVIOCGNAME_0 => {
572 let device_name = &self.device_name;
584
585 let buffer_bytes_count =
590 ((request_with_params >> 16) & ((1 << 14) - 1)) as usize;
591
592 current_task.zero(user_addr, buffer_bytes_count)?;
595 let device_name_as_bytes = device_name.as_bytes();
596
597 let to_copy_bytes_count =
601 std::cmp::min(device_name_as_bytes.len(), buffer_bytes_count - 1);
602 current_task.write_memory(
603 user_addr,
604 &device_name_as_bytes[..to_copy_bytes_count],
605 )?;
606 Ok((to_copy_bytes_count + 1).into())
609 }
610 _ => {
611 track_stub!(
612 TODO("https://fxbug.dev/322873200"),
613 "input ioctl",
614 request_with_params
615 );
616 error!(EOPNOTSUPP)
617 }
618 }
619 }
620 }
621 }
622
623 fn read(
624 &self,
625 _locked: &mut Locked<FileOpsCore>,
626 _file: &FileObject,
627 current_task: &CurrentTask,
628 offset: usize,
629 data: &mut dyn OutputBuffer,
630 ) -> Result<usize, Errno> {
631 trace_duration!("input", "InputFile::read");
632 debug_assert!(offset == 0);
633 let input_event_size = InputEventPtr::size_of_object_for(current_task);
634
635 let limit = data.available() / input_event_size;
638 let events = self.read_events(limit);
639 if events.is_empty() {
640 log_info!("read() returning EAGAIN");
642 return error!(EAGAIN);
643 }
644
645 let last_event_timeval = events.last().expect("events is nonempty").event.time;
646 let last_event_time_ns = duration_from_timeval::<zx::MonotonicTimeline>(last_event_timeval)
647 .unwrap()
648 .into_nanos();
649 self.inspect_status
650 .clone()
651 .map(|status| status.count_read_events(events.len() as u64, last_event_time_ns));
652
653 for event in &events {
654 if let Some(trace_id) = event.trace_id {
655 trace_duration!("input", "linux_event_read");
656 trace_flow_end!("input", "linux_event", trace_id);
657 }
658 }
659
660 if current_task.is_arch32() {
661 let events: Result<Vec<uapi::arch32::input_event>, _> =
662 events.iter().map(|e| uapi::arch32::input_event::try_from(e.event)).collect();
663 let events = events.map_err(|_| errno!(EINVAL))?;
664 data.write_all(events.as_bytes())
665 } else {
666 let events: Vec<uapi::input_event> = events.iter().map(|e| e.event).collect();
667 data.write_all(events.as_bytes())
668 }
669 }
670
671 fn write(
672 &self,
673 _locked: &mut Locked<FileOpsCore>,
674 _file: &FileObject,
675 _current_task: &CurrentTask,
676 offset: usize,
677 _data: &mut dyn InputBuffer,
678 ) -> Result<usize, Errno> {
679 debug_assert!(offset == 0);
680 track_stub!(TODO("https://fxbug.dev/322874385"), "write() on input device");
681 error!(EOPNOTSUPP)
682 }
683
684 fn wait_async(
685 &self,
686 _locked: &mut Locked<FileOpsCore>,
687 _file: &FileObject,
688 _current_task: &CurrentTask,
689 waiter: &Waiter,
690 events: FdEvents,
691 handler: EventHandler,
692 ) -> Option<WaitCanceler> {
693 Some(self.waiters.wait_async_fd_events(waiter, events, handler))
694 }
695
696 fn query_events(
697 &self,
698 _locked: &mut Locked<FileOpsCore>,
699 _file: &FileObject,
700 _current_task: &CurrentTask,
701 ) -> Result<FdEvents, Errno> {
702 Ok(if self.inner.lock().events.is_empty() { FdEvents::empty() } else { FdEvents::POLLIN })
703 }
704}
705
706pub struct BitSet<const NUM_BYTES: usize> {
707 bytes: [u8; NUM_BYTES],
708}
709
710impl<const NUM_BYTES: usize> BitSet<{ NUM_BYTES }> {
711 pub const fn new() -> Self {
712 Self { bytes: [0; NUM_BYTES] }
713 }
714
715 pub const fn list<const N: usize>(bits: [u32; N]) -> Self {
716 let mut bitset = Self::new();
717 let mut i = 0;
718 while i < bits.len() {
719 bitset.set(bits[i]);
720 i += 1;
721 }
722 bitset
723 }
724
725 pub const fn set(&mut self, bitnum: u32) {
726 let bitnum = bitnum as usize;
727 let byte = bitnum / 8;
728 let bit = bitnum % 8;
729 self.bytes[byte] |= 1 << bit;
730 }
731}