1use fuchsia_inspect::{NumericProperty, Property};
6use starnix_core::fileops_impl_nonseekable;
7use starnix_core::mm::{MemoryAccessor, MemoryAccessorExt};
8use starnix_core::task::{CurrentTask, EventHandler, WaitCanceler, WaitQueue, Waiter};
9use starnix_core::vfs::buffers::{InputBuffer, OutputBuffer};
10use starnix_core::vfs::{CloseFreeSafe, FileObject, FileOps, fileops_impl_noop_sync};
11use starnix_logging::{log_info, trace_duration, trace_flow_begin, trace_flow_end, track_stub};
12use starnix_sync::{FileOpsCore, Locked, Mutex, Unlocked};
13use starnix_syscalls::{SUCCESS, SyscallArg, SyscallResult};
14use starnix_types::time::duration_from_timeval;
15use starnix_uapi::errors::Errno;
16use starnix_uapi::user_address::{ArchSpecific, MultiArchUserRef, UserAddress, UserRef};
17use starnix_uapi::vfs::FdEvents;
18use starnix_uapi::{
19 ABS_CNT, ABS_MT_POSITION_X, ABS_MT_POSITION_Y, ABS_MT_SLOT, ABS_MT_TRACKING_ID, BTN_MISC,
20 BTN_TOUCH, EV_CNT, FF_CNT, INPUT_PROP_CNT, INPUT_PROP_DIRECT, KEY_CNT, KEY_POWER, KEY_SLEEP,
21 KEY_VOLUMEDOWN, LED_CNT, MSC_CNT, REL_CNT, REL_WHEEL, SW_CNT, errno, error, uapi,
22};
23use std::collections::VecDeque;
24use std::sync::Arc;
25use zerocopy::IntoBytes as _; uapi::check_arch_independent_layout! {
28 input_id {}
29 input_absinfo {}
30}
31
32type InputEventPtr = MultiArchUserRef<uapi::input_event, uapi::arch32::input_event>;
33
34pub struct InputFileStatus {
35 pub fidl_events_received_count: fuchsia_inspect::UintProperty,
45
46 pub fidl_events_ignored_count: fuchsia_inspect::UintProperty,
48
49 pub fidl_events_unexpected_count: fuchsia_inspect::UintProperty,
53
54 pub fidl_events_converted_count: fuchsia_inspect::UintProperty,
56
57 pub uapi_events_generated_count: fuchsia_inspect::UintProperty,
59
60 pub last_generated_uapi_event_timestamp_ns: fuchsia_inspect::IntProperty,
62
63 pub uapi_events_read_count: fuchsia_inspect::UintProperty,
65
66 pub last_read_uapi_event_timestamp_ns: fuchsia_inspect::IntProperty,
68}
69
70impl InputFileStatus {
71 fn new(node: &fuchsia_inspect::Node) -> Self {
72 let fidl_events_received_count = node.create_uint("fidl_events_received_count", 0);
73 let fidl_events_ignored_count = node.create_uint("fidl_events_ignored_count", 0);
74 let fidl_events_unexpected_count = node.create_uint("fidl_events_unexpected_count", 0);
75 let fidl_events_converted_count = node.create_uint("fidl_events_converted_count", 0);
76 let uapi_events_generated_count = node.create_uint("uapi_events_generated_count", 0);
77 let last_generated_uapi_event_timestamp_ns =
78 node.create_int("last_generated_uapi_event_timestamp_ns", 0);
79 let uapi_events_read_count = node.create_uint("uapi_events_read_count", 0);
80 let last_read_uapi_event_timestamp_ns =
81 node.create_int("last_read_uapi_event_timestamp_ns", 0);
82 Self {
83 fidl_events_received_count,
84 fidl_events_ignored_count,
85 fidl_events_unexpected_count,
86 fidl_events_converted_count,
87 uapi_events_generated_count,
88 last_generated_uapi_event_timestamp_ns,
89 uapi_events_read_count,
90 last_read_uapi_event_timestamp_ns,
91 }
92 }
93
94 pub fn count_received_events(&self, count: u64) {
95 self.fidl_events_received_count.add(count);
96 }
97
98 pub fn count_ignored_events(&self, count: u64) {
99 self.fidl_events_ignored_count.add(count);
100 }
101
102 pub fn count_unexpected_events(&self, count: u64) {
103 self.fidl_events_unexpected_count.add(count);
104 }
105
106 pub fn count_converted_events(&self, count: u64) {
107 self.fidl_events_converted_count.add(count);
108 }
109
110 pub fn count_generated_events(&self, count: u64, event_time_ns: i64) {
111 self.uapi_events_generated_count.add(count);
112 self.last_generated_uapi_event_timestamp_ns.set(event_time_ns);
113 }
114
115 pub fn count_read_events(&self, count: u64, event_time_ns: i64) {
116 self.uapi_events_read_count.add(count);
117 self.last_read_uapi_event_timestamp_ns.set(event_time_ns);
118 }
119}
120
121pub struct InputFile {
122 driver_version: u32,
123 input_id: uapi::input_id,
124 supported_event_types: BitSet<{ min_bytes(EV_CNT) }>,
125 supported_keys: BitSet<{ min_bytes(KEY_CNT) }>,
126 supported_position_attributes: BitSet<{ min_bytes(ABS_CNT) }>, supported_motion_attributes: BitSet<{ min_bytes(REL_CNT) }>, supported_switches: BitSet<{ min_bytes(SW_CNT) }>,
129 supported_leds: BitSet<{ min_bytes(LED_CNT) }>,
130 supported_haptics: BitSet<{ min_bytes(FF_CNT) }>, supported_misc_features: BitSet<{ min_bytes(MSC_CNT) }>,
132 properties: BitSet<{ min_bytes(INPUT_PROP_CNT) }>,
133 mt_slot_axis_info: uapi::input_absinfo,
134 mt_tracking_id_axis_info: uapi::input_absinfo,
135 x_axis_info: uapi::input_absinfo,
136 y_axis_info: uapi::input_absinfo,
137 pub inner: Mutex<InputFileMutableState>,
138 pub inspect_status: Option<Arc<InputFileStatus>>,
141
142 device_name: String,
144}
145
146pub struct LinuxEventWithTraceId {
147 pub event: uapi::input_event,
148 pub trace_id: Option<fuchsia_trace::Id>,
149}
150
151impl LinuxEventWithTraceId {
152 pub fn new(event: uapi::input_event) -> Self {
153 match event.type_ as u32 {
154 uapi::EV_SYN => {
155 let trace_id = fuchsia_trace::Id::random();
156 trace_duration!("input", "linux_event_create");
157 trace_flow_begin!("input", "linux_event", trace_id);
158 LinuxEventWithTraceId { event: event, trace_id: Some(trace_id) }
159 }
160 _ => LinuxEventWithTraceId { event: event, trace_id: None },
163 }
164 }
165}
166
167pub struct InputFileMutableState {
169 pub events: VecDeque<LinuxEventWithTraceId>,
170 pub waiters: WaitQueue,
171}
172
173const fn min_bytes(n_bits: u32) -> usize {
175 ((n_bits as usize) + 7) / 8
176}
177
178fn keyboard_properties() -> BitSet<{ min_bytes(INPUT_PROP_CNT) }> {
180 let mut attrs = BitSet::new();
181 attrs.set(INPUT_PROP_DIRECT);
182 attrs
183}
184
185fn touch_key_attributes() -> BitSet<{ min_bytes(KEY_CNT) }> {
187 let mut attrs = BitSet::new();
188 attrs.set(BTN_TOUCH);
189 attrs.set(BTN_MISC); attrs.set(KEY_SLEEP);
191 attrs
192}
193
194fn touch_position_attributes() -> BitSet<{ min_bytes(ABS_CNT) }> {
196 let mut attrs = BitSet::new();
197 attrs.set(ABS_MT_SLOT);
198 attrs.set(ABS_MT_TRACKING_ID);
199 attrs.set(ABS_MT_POSITION_X);
200 attrs.set(ABS_MT_POSITION_Y);
201 attrs
202}
203
204fn touch_properties() -> BitSet<{ min_bytes(INPUT_PROP_CNT) }> {
206 let mut attrs = BitSet::new();
207 attrs.set(INPUT_PROP_DIRECT);
208 attrs
209}
210
211fn keyboard_key_attributes() -> BitSet<{ min_bytes(KEY_CNT) }> {
213 let mut attrs = BitSet::new();
214 attrs.set(BTN_MISC);
215 attrs.set(KEY_POWER);
216 attrs.set(KEY_VOLUMEDOWN);
217 attrs
218}
219
220fn keyboard_position_attributes() -> BitSet<{ min_bytes(ABS_CNT) }> {
222 BitSet::new()
223}
224
225fn mouse_wheel_attributes() -> BitSet<{ min_bytes(REL_CNT) }> {
226 let mut attrs = BitSet::new();
227 attrs.set(REL_WHEEL);
228 attrs
229}
230
231fn get_device_name(name: &str, input_id: &uapi::input_id) -> String {
235 format!("{}_{:04x}_{:04x}_v{}", name, input_id.vendor, input_id.product, input_id.version)
236}
237
238impl InputFile {
239 const DRIVER_VERSION: u32 = 0;
245
246 pub fn new_touch(
254 input_id: uapi::input_id,
255 width: i32,
256 height: i32,
257 node: Option<&fuchsia_inspect::Node>,
258 ) -> Self {
259 let device_name = get_device_name("starnix_touch", &input_id);
260 Self {
264 driver_version: Self::DRIVER_VERSION,
265 input_id,
266 supported_event_types: BitSet::list([uapi::EV_ABS]),
267 supported_keys: touch_key_attributes(),
268 supported_position_attributes: touch_position_attributes(),
269 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(),
275 mt_slot_axis_info: uapi::input_absinfo {
276 minimum: 0,
277 maximum: 10,
278 ..uapi::input_absinfo::default()
279 },
280 mt_tracking_id_axis_info: uapi::input_absinfo {
281 minimum: 0,
282 maximum: i32::MAX,
283 ..uapi::input_absinfo::default()
284 },
285 x_axis_info: uapi::input_absinfo {
286 minimum: 0,
287 maximum: i32::from(width),
288 ..uapi::input_absinfo::default()
291 },
292 y_axis_info: uapi::input_absinfo {
293 minimum: 0,
294 maximum: i32::from(height),
295 ..uapi::input_absinfo::default()
298 },
299 inner: Mutex::new(InputFileMutableState {
300 events: VecDeque::new(),
301 waiters: WaitQueue::default(),
302 }),
303 inspect_status: node.map(|n| Arc::new(InputFileStatus::new(n))),
304 device_name,
305 }
306 }
307
308 pub fn new_keyboard(input_id: uapi::input_id, node: Option<&fuchsia_inspect::Node>) -> Self {
314 let device_name = get_device_name("starnix_buttons", &input_id);
315 Self {
316 driver_version: Self::DRIVER_VERSION,
317 input_id,
318 supported_event_types: BitSet::list([uapi::EV_KEY]),
319 supported_keys: keyboard_key_attributes(),
320 supported_position_attributes: keyboard_position_attributes(),
321 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(),
327 mt_slot_axis_info: uapi::input_absinfo::default(),
328 mt_tracking_id_axis_info: uapi::input_absinfo::default(),
329 x_axis_info: uapi::input_absinfo::default(),
330 y_axis_info: uapi::input_absinfo::default(),
331 inner: Mutex::new(InputFileMutableState {
332 events: VecDeque::new(),
333 waiters: WaitQueue::default(),
334 }),
335 inspect_status: node.map(|n| Arc::new(InputFileStatus::new(n))),
336 device_name,
337 }
338 }
339
340 pub fn new_mouse(input_id: uapi::input_id, node: Option<&fuchsia_inspect::Node>) -> Self {
346 let device_name = get_device_name("starnix_mouse", &input_id);
347 Self {
348 driver_version: Self::DRIVER_VERSION,
349 input_id,
350 supported_event_types: BitSet::list([uapi::EV_REL]),
351 supported_keys: BitSet::new(), supported_position_attributes: BitSet::new(), supported_motion_attributes: mouse_wheel_attributes(),
354 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(),
360 mt_tracking_id_axis_info: uapi::input_absinfo::default(),
361 x_axis_info: uapi::input_absinfo::default(),
362 y_axis_info: uapi::input_absinfo::default(),
363 inner: Mutex::new(InputFileMutableState {
364 events: VecDeque::new(),
365 waiters: WaitQueue::default(),
366 }),
367 inspect_status: node.map(|n| Arc::new(InputFileStatus::new(n))),
368 device_name,
369 }
370 }
371}
372
373const EVIOCGNAME_MASK: u32 = 0b11_00_0000_0000_0000_1111_1111_1111_1111;
376
377impl CloseFreeSafe for InputFile {}
379impl FileOps for InputFile {
380 fileops_impl_nonseekable!();
381 fileops_impl_noop_sync!();
382
383 fn ioctl(
384 &self,
385 _locked: &mut Locked<Unlocked>,
386 _file: &FileObject,
387 current_task: &CurrentTask,
388 request: u32,
389 arg: SyscallArg,
390 ) -> Result<SyscallResult, Errno> {
391 let user_addr = UserAddress::from(arg);
392 match request {
393 uapi::EVIOCGVERSION => {
394 current_task.write_object(UserRef::new(user_addr), &self.driver_version)?;
395 Ok(SUCCESS)
396 }
397 uapi::EVIOCGID => {
398 current_task.write_object(UserRef::new(user_addr), &self.input_id)?;
399 Ok(SUCCESS)
400 }
401 uapi::EVIOCGBIT_0 => {
402 current_task
403 .write_object(UserRef::new(user_addr), &self.supported_event_types.bytes)?;
404 Ok(SUCCESS)
405 }
406 uapi::EVIOCGBIT_EV_KEY => {
407 current_task.write_object(UserRef::new(user_addr), &self.supported_keys.bytes)?;
408 Ok(SUCCESS)
409 }
410 uapi::EVIOCGBIT_EV_ABS => {
411 current_task.write_object(
412 UserRef::new(user_addr),
413 &self.supported_position_attributes.bytes,
414 )?;
415 Ok(SUCCESS)
416 }
417 uapi::EVIOCGBIT_EV_REL => {
418 current_task.write_object(
419 UserRef::new(user_addr),
420 &self.supported_motion_attributes.bytes,
421 )?;
422 Ok(SUCCESS)
423 }
424 uapi::EVIOCGBIT_EV_SW => {
425 current_task
426 .write_object(UserRef::new(user_addr), &self.supported_switches.bytes)?;
427 Ok(SUCCESS)
428 }
429 uapi::EVIOCGBIT_EV_LED => {
430 current_task.write_object(UserRef::new(user_addr), &self.supported_leds.bytes)?;
431 Ok(SUCCESS)
432 }
433 uapi::EVIOCGBIT_EV_FF => {
434 current_task
435 .write_object(UserRef::new(user_addr), &self.supported_haptics.bytes)?;
436 Ok(SUCCESS)
437 }
438 uapi::EVIOCGBIT_EV_MSC => {
439 current_task
440 .write_object(UserRef::new(user_addr), &self.supported_misc_features.bytes)?;
441 Ok(SUCCESS)
442 }
443 uapi::EVIOCGPROP => {
444 current_task.write_object(UserRef::new(user_addr), &self.properties.bytes)?;
445 Ok(SUCCESS)
446 }
447 uapi::EVIOCGABS_MT_SLOT => {
448 current_task.write_object(UserRef::new(user_addr), &self.mt_slot_axis_info)?;
449 Ok(SUCCESS)
450 }
451 uapi::EVIOCGABS_MT_TRACKING_ID => {
452 current_task
453 .write_object(UserRef::new(user_addr), &self.mt_tracking_id_axis_info)?;
454 Ok(SUCCESS)
455 }
456 uapi::EVIOCGABS_MT_POSITION_X => {
457 current_task.write_object(UserRef::new(user_addr), &self.x_axis_info)?;
458 Ok(SUCCESS)
459 }
460 uapi::EVIOCGABS_MT_POSITION_Y => {
461 current_task.write_object(UserRef::new(user_addr), &self.y_axis_info)?;
462 Ok(SUCCESS)
463 }
464
465 request_with_params => {
466 match request_with_params & EVIOCGNAME_MASK {
469 uapi::EVIOCGNAME_0 => {
470 let device_name = &self.device_name;
482
483 let buffer_bytes_count =
488 ((request_with_params >> 16) & ((1 << 14) - 1)) as usize;
489
490 current_task.zero(user_addr, buffer_bytes_count)?;
493 let device_name_as_bytes = device_name.as_bytes();
494
495 let to_copy_bytes_count =
499 std::cmp::min(device_name_as_bytes.len(), buffer_bytes_count - 1);
500 current_task.write_memory(
501 user_addr,
502 &device_name_as_bytes[..to_copy_bytes_count],
503 )?;
504 Ok((to_copy_bytes_count + 1).into())
507 }
508 _ => {
509 track_stub!(
510 TODO("https://fxbug.dev/322873200"),
511 "input ioctl",
512 request_with_params
513 );
514 error!(EOPNOTSUPP)
515 }
516 }
517 }
518 }
519 }
520
521 fn read(
522 &self,
523 _locked: &mut Locked<FileOpsCore>,
524 _file: &FileObject,
525 current_task: &CurrentTask,
526 offset: usize,
527 data: &mut dyn OutputBuffer,
528 ) -> Result<usize, Errno> {
529 trace_duration!("input", "InputFile::read");
530 debug_assert!(offset == 0);
531 let mut inner = self.inner.lock();
532 let num_events = inner.events.len();
533 if num_events == 0 {
534 log_info!("read() returning EAGAIN");
537 return error!(EAGAIN);
538 }
539
540 let input_event_size = InputEventPtr::size_of_object_for(current_task);
541
542 let limit = std::cmp::min(data.available() / input_event_size, num_events);
547 if num_events > limit {
548 log_info!(
549 "There was only space in the given buffer to read {} of the {} queued events. Sending a notification to prompt another read.",
550 limit,
551 num_events
552 );
553 inner.waiters.notify_fd_events(FdEvents::POLLIN);
554 }
555 let events: Vec<LinuxEventWithTraceId> = inner.events.drain(..limit).collect::<Vec<_>>();
556 let last_event_timeval = events.last().expect("events is nonempty").event.time;
557 let last_event_time_ns = duration_from_timeval::<zx::MonotonicTimeline>(last_event_timeval)
558 .unwrap()
559 .into_nanos();
560 self.inspect_status
561 .clone()
562 .map(|status| status.count_read_events(events.len() as u64, last_event_time_ns));
563
564 for event in &events {
565 if let Some(trace_id) = event.trace_id {
566 trace_duration!("input", "linux_event_read");
567 trace_flow_end!("input", "linux_event", trace_id);
568 }
569 }
570
571 if current_task.is_arch32() {
572 let events: Result<Vec<uapi::arch32::input_event>, _> =
573 events.iter().map(|e| uapi::arch32::input_event::try_from(e.event)).collect();
574 let events = events.map_err(|_| errno!(EINVAL))?;
575 data.write_all(events.as_bytes())
576 } else {
577 let events: Vec<uapi::input_event> = events.iter().map(|e| e.event).collect();
578 data.write_all(events.as_bytes())
579 }
580 }
581
582 fn write(
583 &self,
584 _locked: &mut Locked<FileOpsCore>,
585 _file: &FileObject,
586 _current_task: &CurrentTask,
587 offset: usize,
588 _data: &mut dyn InputBuffer,
589 ) -> Result<usize, Errno> {
590 debug_assert!(offset == 0);
591 track_stub!(TODO("https://fxbug.dev/322874385"), "write() on input device");
592 error!(EOPNOTSUPP)
593 }
594
595 fn wait_async(
596 &self,
597 _locked: &mut Locked<FileOpsCore>,
598 _file: &FileObject,
599 _current_task: &CurrentTask,
600 waiter: &Waiter,
601 events: FdEvents,
602 handler: EventHandler,
603 ) -> Option<WaitCanceler> {
604 Some(self.inner.lock().waiters.wait_async_fd_events(waiter, events, handler))
605 }
606
607 fn query_events(
608 &self,
609 _locked: &mut Locked<FileOpsCore>,
610 _file: &FileObject,
611 _current_task: &CurrentTask,
612 ) -> Result<FdEvents, Errno> {
613 Ok(if self.inner.lock().events.is_empty() { FdEvents::empty() } else { FdEvents::POLLIN })
614 }
615}
616
617pub struct BitSet<const NUM_BYTES: usize> {
618 bytes: [u8; NUM_BYTES],
619}
620
621impl<const NUM_BYTES: usize> BitSet<{ NUM_BYTES }> {
622 pub const fn new() -> Self {
623 Self { bytes: [0; NUM_BYTES] }
624 }
625
626 pub const fn list<const N: usize>(bits: [u32; N]) -> Self {
627 let mut bitset = Self::new();
628 let mut i = 0;
629 while i < bits.len() {
630 bitset.set(bits[i]);
631 i += 1;
632 }
633 bitset
634 }
635
636 pub const fn set(&mut self, bitnum: u32) {
637 let bitnum = bitnum as usize;
638 let byte = bitnum / 8;
639 let bit = bitnum % 8;
640 self.bytes[byte] |= 1 << bit;
641 }
642}