1use crossbeam::queue::SegQueue;
6use fuchsia_inspect::Inspector;
7use futures::FutureExt;
8use starnix_core::fileops_impl_nonseekable;
9use starnix_core::mm::{MemoryAccessor, MemoryAccessorExt};
10use starnix_core::task::{CurrentTask, EventHandler, WaitCanceler, WaitQueue, Waiter};
11use starnix_core::vfs::buffers::{InputBuffer, OutputBuffer};
12use starnix_core::vfs::{FileObject, FileOps, fileops_impl_noop_sync};
13use starnix_logging::{log_info, track_stub};
14use starnix_sync::{InputFileInputFileLock, LockDepMutex};
15use starnix_syscalls::{SUCCESS, SyscallArg, SyscallResult};
16use starnix_types::time::duration_from_timeval;
17use starnix_uapi::errors::Errno;
18use starnix_uapi::open_flags::OpenFlags;
19use starnix_uapi::user_address::{ArchSpecific, MultiArchUserRef, UserAddress, UserRef};
20use starnix_uapi::vfs::FdEvents;
21use starnix_uapi::{
22 ABS_CNT, ABS_MT_POSITION_X, ABS_MT_POSITION_Y, ABS_MT_SLOT, ABS_MT_TRACKING_ID, BTN_MISC,
23 BTN_TOUCH, EV_CNT, FF_CNT, INPUT_PROP_CNT, INPUT_PROP_DIRECT, KEY_CNT, KEY_DOWN, KEY_LEFT,
24 KEY_POWER, KEY_RIGHT, KEY_SLEEP, KEY_UP, KEY_VOLUMEDOWN, KEY_VOLUMEUP, LED_CNT, MSC_CNT,
25 REL_CNT, REL_WHEEL, SW_CNT, errno, error, uapi,
26};
27use std::sync::atomic::{AtomicBool, AtomicI64, AtomicU64, Ordering};
28use std::sync::{Arc, Weak};
29use zerocopy::IntoBytes as _; uapi::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 pub fidl_events_received_count: AtomicU64,
49
50 pub fidl_events_ignored_count: AtomicU64,
52
53 pub fidl_events_unexpected_count: AtomicU64,
57
58 pub fidl_events_converted_count: AtomicU64,
60
61 pub uapi_events_generated_count: AtomicU64,
63
64 pub last_generated_uapi_event_timestamp_ns: AtomicI64,
66
67 pub uapi_events_read_count: AtomicU64,
69
70 pub last_read_uapi_event_timestamp_ns: AtomicI64,
72
73 pub fd_read_count: AtomicU64,
75
76 pub fd_notify_count: AtomicU64,
78
79 pub opened_without_nonblock: AtomicBool,
81
82 pub open_timestamp_ns: AtomicI64,
84
85 pub closed: AtomicBool,
87
88 pub close_timestamp_ns: AtomicI64,
90
91 pub input_file: LockDepMutex<Weak<InputFile>, InputFileInputFileLock>,
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: Default::default(),
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) }>, supported_motion_attributes: BitSet<{ min_bytes(REL_CNT) }>, supported_switches: BitSet<{ min_bytes(SW_CNT) }>,
248 supported_leds: BitSet<{ min_bytes(LED_CNT) }>,
249 supported_haptics: BitSet<{ min_bytes(FF_CNT) }>, 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 events: SegQueue<LinuxEventWithTraceId>,
257 waiters: WaitQueue,
258 pub inspect_status: Option<Arc<InputFileStatus>>,
261
262 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::new();
276 fuchsia_trace::duration!("input", "linux_event_create");
277 fuchsia_trace::flow_begin!("input", "linux_event", trace_id);
278 LinuxEventWithTraceId { event: event, trace_id: Some(trace_id) }
279 }
280 _ => LinuxEventWithTraceId { event: event, trace_id: None },
283 }
284 }
285}
286
287const fn min_bytes(n_bits: u32) -> usize {
289 ((n_bits as usize) + 7) / 8
290}
291
292fn keyboard_properties() -> BitSet<{ min_bytes(INPUT_PROP_CNT) }> {
294 let mut attrs = BitSet::new();
295 attrs.set(INPUT_PROP_DIRECT);
296 attrs
297}
298
299fn touch_key_attributes() -> BitSet<{ min_bytes(KEY_CNT) }> {
301 let mut attrs = BitSet::new();
302 attrs.set(BTN_TOUCH);
303 attrs.set(BTN_MISC); attrs.set(KEY_SLEEP);
305 attrs.set(KEY_UP);
306 attrs.set(KEY_LEFT);
307 attrs.set(KEY_RIGHT);
308 attrs.set(KEY_DOWN);
309
310 attrs
311}
312
313fn touch_position_attributes() -> BitSet<{ min_bytes(ABS_CNT) }> {
315 let mut attrs = BitSet::new();
316 attrs.set(ABS_MT_SLOT);
317 attrs.set(ABS_MT_TRACKING_ID);
318 attrs.set(ABS_MT_POSITION_X);
319 attrs.set(ABS_MT_POSITION_Y);
320 attrs
321}
322
323fn touch_properties() -> BitSet<{ min_bytes(INPUT_PROP_CNT) }> {
325 let mut attrs = BitSet::new();
326 attrs.set(INPUT_PROP_DIRECT);
327 attrs
328}
329
330fn keyboard_key_attributes() -> BitSet<{ min_bytes(KEY_CNT) }> {
332 let mut attrs = BitSet::new();
333 attrs.set(BTN_MISC);
334 attrs.set(KEY_POWER);
335 attrs.set(KEY_VOLUMEUP);
336 attrs.set(KEY_VOLUMEDOWN);
337 attrs
338}
339
340fn keyboard_position_attributes() -> BitSet<{ min_bytes(ABS_CNT) }> {
342 BitSet::new()
343}
344
345fn mouse_wheel_attributes() -> BitSet<{ min_bytes(REL_CNT) }> {
346 let mut attrs = BitSet::new();
347 attrs.set(REL_WHEEL);
348 attrs
349}
350
351fn get_device_name(name: &str, input_id: &uapi::input_id) -> String {
355 format!("{}_{:04x}_{:04x}_v{}", name, input_id.vendor, input_id.product, input_id.version)
356}
357
358impl InputFile {
359 const DRIVER_VERSION: u32 = 0;
365
366 pub fn new_touch(
374 input_id: uapi::input_id,
375 width: i32,
376 height: i32,
377 node: &fuchsia_inspect::Node,
378 ) -> Self {
379 let device_name = get_device_name("starnix_touch", &input_id);
380 Self {
384 driver_version: Self::DRIVER_VERSION,
385 input_id,
386 supported_event_types: BitSet::list([uapi::EV_ABS]),
387 supported_keys: touch_key_attributes(),
388 supported_position_attributes: touch_position_attributes(),
389 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(),
395 mt_slot_axis_info: uapi::input_absinfo {
396 minimum: 0,
397 maximum: 10,
398 ..uapi::input_absinfo::default()
399 },
400 mt_tracking_id_axis_info: uapi::input_absinfo {
401 minimum: 0,
402 maximum: i32::MAX,
403 ..uapi::input_absinfo::default()
404 },
405 x_axis_info: uapi::input_absinfo {
406 minimum: 0,
407 maximum: i32::from(width),
408 ..uapi::input_absinfo::default()
411 },
412 y_axis_info: uapi::input_absinfo {
413 minimum: 0,
414 maximum: i32::from(height),
415 ..uapi::input_absinfo::default()
418 },
419 events: SegQueue::new(),
420 waiters: WaitQueue::default(),
421 inspect_status: Some(InputFileStatus::new(node)),
422 device_name,
423 }
424 }
425
426 pub fn new_keyboard(input_id: uapi::input_id, node: &fuchsia_inspect::Node) -> Self {
432 let device_name = get_device_name("starnix_buttons", &input_id);
433 Self {
434 driver_version: Self::DRIVER_VERSION,
435 input_id,
436 supported_event_types: BitSet::list([uapi::EV_KEY]),
437 supported_keys: keyboard_key_attributes(),
438 supported_position_attributes: keyboard_position_attributes(),
439 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(),
445 mt_slot_axis_info: uapi::input_absinfo::default(),
446 mt_tracking_id_axis_info: uapi::input_absinfo::default(),
447 x_axis_info: uapi::input_absinfo::default(),
448 y_axis_info: uapi::input_absinfo::default(),
449 events: SegQueue::new(),
450 waiters: WaitQueue::default(),
451 inspect_status: Some(InputFileStatus::new(node)),
452 device_name,
453 }
454 }
455
456 pub fn new_mouse(input_id: uapi::input_id, node: &fuchsia_inspect::Node) -> Self {
462 let device_name = get_device_name("starnix_mouse", &input_id);
463 Self {
464 driver_version: Self::DRIVER_VERSION,
465 input_id,
466 supported_event_types: BitSet::list([uapi::EV_REL]),
467 supported_keys: BitSet::new(), supported_position_attributes: BitSet::new(), supported_motion_attributes: mouse_wheel_attributes(),
470 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(),
476 mt_tracking_id_axis_info: uapi::input_absinfo::default(),
477 x_axis_info: uapi::input_absinfo::default(),
478 y_axis_info: uapi::input_absinfo::default(),
479 events: SegQueue::new(),
480 waiters: WaitQueue::default(),
481 inspect_status: Some(InputFileStatus::new(node)),
482 device_name,
483 }
484 }
485
486 pub fn init_inspect_status(self: &Arc<Self>) {
487 if let Some(inspect) = &self.inspect_status {
488 *inspect.input_file.lock() = Arc::downgrade(self);
489 }
490 }
491
492 pub fn add_events(&self, events: Vec<uapi::input_event>) {
493 if events.is_empty() {
494 return;
495 }
496 if let Some(inspect) = &self.inspect_status {
497 inspect.count_fd_notify_calls();
498 }
499 for event in events {
500 self.events.push(LinuxEventWithTraceId::new(event));
501 }
502 self.waiters.notify_fd_events(FdEvents::POLLIN);
503 }
504
505 pub fn read_events(&self, limit: usize) -> Vec<LinuxEventWithTraceId> {
506 if let Some(inspect) = &self.inspect_status {
507 inspect.count_fd_read_calls();
508 }
509 let mut events = vec![];
510 for _ in 0..limit {
511 if let Some(event) = self.events.pop() {
512 events.push(event);
513 } else {
514 break;
515 }
516 }
517 events
521 }
522}
523
524const EVIOCGNAME_MASK: u32 = 0b11_00_0000_0000_0000_1111_1111_1111_1111;
527
528impl FileOps for InputFile {
529 fileops_impl_nonseekable!();
530 fileops_impl_noop_sync!();
531
532 fn open(&self, file: &FileObject, _current_task: &CurrentTask) -> Result<(), Errno> {
533 if let Some(inspect) = &self.inspect_status {
534 inspect.set_open_timestamp(zx::MonotonicInstant::get().into_nanos());
535 if (file.flags() & OpenFlags::NONBLOCK) != OpenFlags::NONBLOCK {
536 inspect.set_opened_without_nonblock();
537 }
538 }
539 Ok(())
540 }
541
542 fn close(
543 self: Box<Self>,
544 _file: &starnix_core::vfs::FileObjectState,
545 _current_task: &CurrentTask,
546 ) {
547 if let Some(inspect) = &self.inspect_status {
548 inspect.set_closed();
549 inspect.set_closed_timestamp(zx::MonotonicInstant::get().into_nanos());
550 }
551 }
552
553 fn ioctl(
554 &self,
555 _file: &FileObject,
556 current_task: &CurrentTask,
557 request: u32,
558 arg: SyscallArg,
559 ) -> Result<SyscallResult, Errno> {
560 let user_addr = UserAddress::from(arg);
561 match request {
562 uapi::EVIOCGVERSION => {
563 current_task.write_object(UserRef::new(user_addr), &self.driver_version)?;
564 Ok(SUCCESS)
565 }
566 uapi::EVIOCGID => {
567 current_task.write_object(UserRef::new(user_addr), &self.input_id)?;
568 Ok(SUCCESS)
569 }
570 uapi::EVIOCGBIT_0 => {
571 current_task
572 .write_object(UserRef::new(user_addr), &self.supported_event_types.bytes)?;
573 Ok(SUCCESS)
574 }
575 uapi::EVIOCGBIT_EV_KEY => {
576 current_task.write_object(UserRef::new(user_addr), &self.supported_keys.bytes)?;
577 Ok(SUCCESS)
578 }
579 uapi::EVIOCGBIT_EV_ABS => {
580 current_task.write_object(
581 UserRef::new(user_addr),
582 &self.supported_position_attributes.bytes,
583 )?;
584 Ok(SUCCESS)
585 }
586 uapi::EVIOCGBIT_EV_REL => {
587 current_task.write_object(
588 UserRef::new(user_addr),
589 &self.supported_motion_attributes.bytes,
590 )?;
591 Ok(SUCCESS)
592 }
593 uapi::EVIOCGBIT_EV_SW => {
594 current_task
595 .write_object(UserRef::new(user_addr), &self.supported_switches.bytes)?;
596 Ok(SUCCESS)
597 }
598 uapi::EVIOCGBIT_EV_LED => {
599 current_task.write_object(UserRef::new(user_addr), &self.supported_leds.bytes)?;
600 Ok(SUCCESS)
601 }
602 uapi::EVIOCGBIT_EV_FF => {
603 current_task
604 .write_object(UserRef::new(user_addr), &self.supported_haptics.bytes)?;
605 Ok(SUCCESS)
606 }
607 uapi::EVIOCGBIT_EV_MSC => {
608 current_task
609 .write_object(UserRef::new(user_addr), &self.supported_misc_features.bytes)?;
610 Ok(SUCCESS)
611 }
612 uapi::EVIOCGPROP => {
613 current_task.write_object(UserRef::new(user_addr), &self.properties.bytes)?;
614 Ok(SUCCESS)
615 }
616 uapi::EVIOCGABS_MT_SLOT => {
617 current_task.write_object(UserRef::new(user_addr), &self.mt_slot_axis_info)?;
618 Ok(SUCCESS)
619 }
620 uapi::EVIOCGABS_MT_TRACKING_ID => {
621 current_task
622 .write_object(UserRef::new(user_addr), &self.mt_tracking_id_axis_info)?;
623 Ok(SUCCESS)
624 }
625 uapi::EVIOCGABS_MT_POSITION_X => {
626 current_task.write_object(UserRef::new(user_addr), &self.x_axis_info)?;
627 Ok(SUCCESS)
628 }
629 uapi::EVIOCGABS_MT_POSITION_Y => {
630 current_task.write_object(UserRef::new(user_addr), &self.y_axis_info)?;
631 Ok(SUCCESS)
632 }
633
634 request_with_params => {
635 match request_with_params & EVIOCGNAME_MASK {
638 uapi::EVIOCGNAME_0 => {
639 let device_name = &self.device_name;
651
652 let buffer_bytes_count =
657 ((request_with_params >> 16) & ((1 << 14) - 1)) as usize;
658
659 current_task.zero(user_addr, buffer_bytes_count)?;
662 let device_name_as_bytes = device_name.as_bytes();
663
664 let to_copy_bytes_count =
668 std::cmp::min(device_name_as_bytes.len(), buffer_bytes_count - 1);
669 current_task.write_memory(
670 user_addr,
671 &device_name_as_bytes[..to_copy_bytes_count],
672 )?;
673 Ok((to_copy_bytes_count + 1).into())
676 }
677 _ => {
678 track_stub!(
679 TODO("https://fxbug.dev/322873200"),
680 "input ioctl",
681 request_with_params
682 );
683 error!(EOPNOTSUPP)
684 }
685 }
686 }
687 }
688 }
689
690 fn read(
691 &self,
692 _file: &FileObject,
693 current_task: &CurrentTask,
694 offset: usize,
695 data: &mut dyn OutputBuffer,
696 ) -> Result<usize, Errno> {
697 fuchsia_trace::duration!("input", "InputFile::read");
698 debug_assert!(offset == 0);
699 let input_event_size = InputEventPtr::size_of_object_for(current_task);
700
701 let limit = data.available() / input_event_size;
704 let events = self.read_events(limit);
705 if events.is_empty() {
706 log_info!("read() returning EAGAIN");
708 return error!(EAGAIN);
709 }
710
711 let last_event_timeval = events.last().expect("events is nonempty").event.time;
712 let last_event_time_ns = duration_from_timeval::<zx::MonotonicTimeline>(last_event_timeval)
713 .unwrap()
714 .into_nanos();
715 self.inspect_status
716 .clone()
717 .map(|status| status.count_read_events(events.len() as u64, last_event_time_ns));
718
719 for event in &events {
720 if let Some(trace_id) = event.trace_id {
721 fuchsia_trace::duration!("input", "linux_event_read");
722 fuchsia_trace::flow_end!("input", "linux_event", trace_id);
723 }
724 }
725
726 if current_task.is_arch32() {
727 let events: Result<Vec<uapi::arch32::input_event>, _> =
728 events.iter().map(|e| uapi::arch32::input_event::try_from(e.event)).collect();
729 let events = events.map_err(|_| errno!(EINVAL))?;
730 data.write_all(events.as_bytes())
731 } else {
732 let events: Vec<uapi::input_event> = events.iter().map(|e| e.event).collect();
733 data.write_all(events.as_bytes())
734 }
735 }
736
737 fn write(
738 &self,
739 _file: &FileObject,
740 _current_task: &CurrentTask,
741 offset: usize,
742 _data: &mut dyn InputBuffer,
743 ) -> Result<usize, Errno> {
744 debug_assert!(offset == 0);
745 track_stub!(TODO("https://fxbug.dev/322874385"), "write() on input device");
746 error!(EOPNOTSUPP)
747 }
748
749 fn wait_async(
750 &self,
751 _file: &FileObject,
752 _current_task: &CurrentTask,
753 waiter: &Waiter,
754 events: FdEvents,
755 handler: EventHandler,
756 ) -> Option<WaitCanceler> {
757 Some(self.waiters.wait_async_fd_events(waiter, events, handler))
758 }
759
760 fn query_events(
761 &self,
762 _file: &FileObject,
763 _current_task: &CurrentTask,
764 ) -> Result<FdEvents, Errno> {
765 Ok(if self.events.is_empty() { FdEvents::empty() } else { FdEvents::POLLIN })
766 }
767}
768
769pub struct ArcInputFile(pub Arc<InputFile>);
770
771impl FileOps for ArcInputFile {
772 fileops_impl_nonseekable!();
773 fileops_impl_noop_sync!();
774
775 fn open(&self, file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
776 self.0.as_ref().open(file, current_task)
777 }
778
779 fn close(
780 self: Box<Self>,
781 _file: &starnix_core::vfs::FileObjectState,
782 _current_task: &CurrentTask,
783 ) {
784 let arc_file = *self;
785 if let Some(inspect) = &arc_file.0.inspect_status {
786 inspect.set_closed();
787 inspect.set_closed_timestamp(zx::MonotonicInstant::get().into_nanos());
788 }
789 }
790
791 fn ioctl(
792 &self,
793 file: &FileObject,
794 current_task: &CurrentTask,
795 request: u32,
796 arg: SyscallArg,
797 ) -> Result<SyscallResult, Errno> {
798 self.0.as_ref().ioctl(file, current_task, request, arg)
799 }
800
801 fn read(
802 &self,
803 file: &FileObject,
804 current_task: &CurrentTask,
805 offset: usize,
806 data: &mut dyn OutputBuffer,
807 ) -> Result<usize, Errno> {
808 self.0.as_ref().read(file, current_task, offset, data)
809 }
810
811 fn write(
812 &self,
813 file: &FileObject,
814 current_task: &CurrentTask,
815 offset: usize,
816 data: &mut dyn InputBuffer,
817 ) -> Result<usize, Errno> {
818 self.0.as_ref().write(file, current_task, offset, data)
819 }
820
821 fn wait_async(
822 &self,
823 file: &FileObject,
824 current_task: &CurrentTask,
825 waiter: &Waiter,
826 events: FdEvents,
827 handler: EventHandler,
828 ) -> Option<WaitCanceler> {
829 self.0.as_ref().wait_async(file, current_task, waiter, events, handler)
830 }
831
832 fn query_events(
833 &self,
834 file: &FileObject,
835 current_task: &CurrentTask,
836 ) -> Result<FdEvents, Errno> {
837 self.0.as_ref().query_events(file, current_task)
838 }
839}
840
841pub struct BitSet<const NUM_BYTES: usize> {
842 bytes: [u8; NUM_BYTES],
843}
844
845impl<const NUM_BYTES: usize> BitSet<{ NUM_BYTES }> {
846 pub const fn new() -> Self {
847 Self { bytes: [0; NUM_BYTES] }
848 }
849
850 pub const fn list<const N: usize>(bits: [u32; N]) -> Self {
851 let mut bitset = Self::new();
852 let mut i = 0;
853 while i < bits.len() {
854 bitset.set(bits[i]);
855 i += 1;
856 }
857 bitset
858 }
859
860 pub const fn set(&mut self, bitnum: u32) {
861 let bitnum = bitnum as usize;
862 let byte = bitnum / 8;
863 let bit = bitnum % 8;
864 self.bytes[byte] |= 1 << bit;
865 }
866}
867
868#[cfg(test)]
869mod tests {
870 use super::*;
871 use std::sync::atomic::Ordering;
872
873 #[test]
874 fn test_read_events_no_notify_when_buffer_full() {
875 let inspector = fuchsia_inspect::Inspector::default();
876 let node = inspector.root();
877 let input_file = InputFile::new_touch(
878 uapi::input_id { bustype: 0, vendor: 0, product: 0, version: 0 },
879 100,
880 100,
881 node,
882 );
883
884 let event1 = uapi::input_event {
886 type_: uapi::EV_KEY as u16,
887 code: 1,
888 value: 1,
889 ..Default::default()
890 };
891 let event2 = uapi::input_event {
892 type_: uapi::EV_KEY as u16,
893 code: 2,
894 value: 1,
895 ..Default::default()
896 };
897 input_file.add_events(vec![event1, event2]);
898
899 let notify_count =
901 input_file.inspect_status.as_ref().unwrap().fd_notify_count.load(Ordering::Relaxed);
902 assert_eq!(notify_count, 1);
903
904 let events = input_file.read_events(1);
906 assert_eq!(events.len(), 1);
907
908 let notify_count =
910 input_file.inspect_status.as_ref().unwrap().fd_notify_count.load(Ordering::Relaxed);
911 assert_eq!(notify_count, 1);
912 }
913}