1use crate::uinput::vfs::{CloseFreeSafe, NamespaceNode};
6use crate::{InputEventsRelayHandle, InputFile, OpenedFiles};
7use bit_vec::BitVec;
8use fidl_fuchsia_ui_test_input::{
9 self as futinput, CoordinateUnit, DisplayDimensions, KeyboardSimulateKeyEventRequest,
10 RegistryRegisterKeyboardAndGetDeviceInfoRequest,
11 RegistryRegisterTouchScreenAndGetDeviceInfoRequest,
12};
13use fuchsia_inspect;
14use starnix_core::device::kobject::{Device, DeviceMetadata};
15use starnix_core::device::{DeviceMode, DeviceOps};
16use starnix_core::fileops_impl_seekless;
17use starnix_core::mm::MemoryAccessorExt;
18use starnix_core::task::CurrentTask;
19use starnix_core::vfs::{
20 self, FileObject, FileOps, FsString, default_ioctl, fileops_impl_noop_sync,
21};
22use starnix_logging::log_warn;
23use starnix_modules_input_event_conversion::key_linux_to_fuchsia::LinuxKeyboardEventParser;
24use starnix_modules_input_event_conversion::touch_linux_to_fuchsia::LinuxTouchEventParser;
25use starnix_sync::{FileOpsCore, LockEqualOrBefore, Locked, Mutex, Unlocked};
26use starnix_syscalls::{SUCCESS, SyscallArg, SyscallResult};
27use starnix_uapi::device_id::INPUT_MAJOR;
28use starnix_uapi::errors::Errno;
29use starnix_uapi::open_flags::OpenFlags;
30use starnix_uapi::user_address::{MultiArchUserRef, UserRef};
31use starnix_uapi::{device_id, errno, error, uapi};
32use std::sync::Arc;
33use std::sync::atomic::{AtomicI32, Ordering};
34
35const UINPUT_VERSION: u32 = 5;
38
39type InputEventPtr = MultiArchUserRef<uapi::input_event, uapi::arch32::input_event>;
40
41#[derive(Clone)]
42enum DeviceId {
43 Keyboard,
44 Touchscreen(i32, i32),
45}
46
47pub fn register_uinput_device(
48 locked: &mut Locked<Unlocked>,
49 system_task: &CurrentTask,
50 input_event_relay_handle: Arc<InputEventsRelayHandle>,
51) -> Result<(), Errno> {
52 let kernel = system_task.kernel();
53 let registry = &kernel.device_registry;
54 let misc_class = registry.objects.misc_class();
55 let inspect_node = Arc::new(kernel.inspect_node.create_child("uinput"));
56 let device = UinputDevice::new(input_event_relay_handle, inspect_node);
57 registry.register_device(
58 locked,
59 system_task,
60 "uinput".into(),
61 DeviceMetadata::new("uinput".into(), device_id::DeviceId::UINPUT, DeviceMode::Char),
62 misc_class,
63 device,
64 )?;
65 Ok(())
66}
67
68fn add_and_register_input_device<L>(
69 locked: &mut Locked<L>,
70 system_task: &CurrentTask,
71 dev_ops: impl DeviceOps,
72 device_id: u32,
73) -> Result<Device, Errno>
74where
75 L: LockEqualOrBefore<FileOpsCore>,
76{
77 let kernel = system_task.kernel();
78 let registry = &kernel.device_registry;
79
80 let input_class = registry.objects.input_class();
81
82 registry.register_device(
83 locked,
84 system_task,
85 FsString::from(format!("event{}", device_id)).as_ref(),
86 DeviceMetadata::new(
87 format!("input/event{}", device_id).into(),
88 starnix_uapi::device_id::DeviceId::new(INPUT_MAJOR, device_id),
89 DeviceMode::Char,
90 ),
91 input_class,
92 dev_ops,
93 )
94}
95
96#[derive(Clone)]
97struct UinputDevice {
98 input_event_relay: Arc<InputEventsRelayHandle>,
99 inspect_node: Arc<fuchsia_inspect::Node>,
100}
101
102impl UinputDevice {
103 pub fn new(
104 input_event_relay: Arc<InputEventsRelayHandle>,
105 inspect_node: Arc<fuchsia_inspect::Node>,
106 ) -> Self {
107 Self { input_event_relay, inspect_node }
108 }
109}
110
111impl DeviceOps for UinputDevice {
112 fn open(
113 &self,
114 _locked: &mut Locked<FileOpsCore>,
115 _current_task: &CurrentTask,
116 _id: device_id::DeviceId,
117 _node: &NamespaceNode,
118 _flags: OpenFlags,
119 ) -> Result<Box<dyn FileOps>, Errno> {
120 Ok(Box::new(UinputDeviceFile::new(
121 self.input_event_relay.clone(),
122 self.inspect_node.clone(),
123 )))
124 }
125}
126
127enum CreatedDevice {
128 None,
129 Keyboard(futinput::KeyboardSynchronousProxy, LinuxKeyboardEventParser),
130 Touchscreen(futinput::TouchScreenSynchronousProxy, Box<LinuxTouchEventParser>),
132}
133
134struct Range {
135 min: i32,
136 max: i32,
137}
138struct UinputDeviceMutableState {
139 enabled_evbits: BitVec,
140 input_id: Option<uapi::input_id>,
141 created_device: CreatedDevice,
142 k_device: Option<Device>,
143 device_id: Option<u32>,
144 x_range: Option<Range>,
145 y_range: Option<Range>,
146}
147
148impl UinputDeviceMutableState {
149 fn get_id_and_device_type(&self) -> Option<(uapi::input_id, DeviceId)> {
150 let input_id = match self.input_id {
151 Some(input_id) => input_id,
152 None => return None,
153 };
154 let device_type = match self.enabled_evbits.clone().get(uapi::EV_ABS as usize) {
158 Some(true) => {
159 let mut touchscreen_width = 1000;
161 let mut touchscreen_height = 1000;
162
163 if self.x_range.is_some() && self.y_range.is_some() {
164 let x_range = self.x_range.as_ref().unwrap();
165 let y_range = self.y_range.as_ref().unwrap();
166 touchscreen_width = x_range.max - x_range.min;
167 touchscreen_height = y_range.max - y_range.min;
168 }
169 DeviceId::Touchscreen(touchscreen_width, touchscreen_height)
170 }
171 Some(false) | None => DeviceId::Keyboard,
172 };
173
174 Some((input_id, device_type))
175 }
176}
177
178struct UinputDeviceFile {
179 input_event_relay: Arc<InputEventsRelayHandle>,
180 inner: Mutex<UinputDeviceMutableState>,
181 inspect_node: Arc<fuchsia_inspect::Node>,
182}
183
184impl UinputDeviceFile {
185 pub fn new(
186 input_event_relay: Arc<InputEventsRelayHandle>,
187 inspect_node: Arc<fuchsia_inspect::Node>,
188 ) -> Self {
189 Self {
190 input_event_relay,
191 inner: Mutex::new(UinputDeviceMutableState {
192 enabled_evbits: BitVec::from_elem(uapi::EV_CNT as usize, false),
193 input_id: None,
194 created_device: CreatedDevice::None,
195 k_device: None,
196 device_id: None,
197 x_range: None,
198 y_range: None,
199 }),
200 inspect_node,
201 }
202 }
203
204 fn ui_set_evbit(&self, arg: SyscallArg) -> Result<SyscallResult, Errno> {
207 let evbit: u32 = arg.into();
208 match evbit {
209 uapi::EV_KEY | uapi::EV_ABS => {
210 self.inner.lock().enabled_evbits.set(evbit as usize, true);
211 Ok(SUCCESS)
212 }
213 _ => {
214 log_warn!("UI_SET_EVBIT with unsupported evbit {}", evbit);
215 error!(EPERM)
216 }
217 }
218 }
219
220 fn ui_abs_setup(
223 &self,
224 current_task: &CurrentTask,
225 abs_setup: UserRef<starnix_uapi::uinput_abs_setup>,
226 ) -> Result<SyscallResult, Errno> {
227 let setup: starnix_uapi::uinput_abs_setup = current_task.read_object(abs_setup)?;
228 let code: u32 = setup.code.into();
229 match code {
230 uapi::ABS_MT_POSITION_X => {
231 self.inner.lock().x_range =
232 Some(Range { min: setup.absinfo.minimum, max: setup.absinfo.maximum });
233 }
234 uapi::ABS_MT_POSITION_Y => {
235 self.inner.lock().y_range =
236 Some(Range { min: setup.absinfo.minimum, max: setup.absinfo.maximum });
237 }
238 _ => {
239 log_warn!("UI_ABS_SETUP ignore event code {}", setup.code);
240 }
241 }
242 Ok(SUCCESS)
243 }
244
245 fn ui_get_version(
249 &self,
250 current_task: &CurrentTask,
251 user_version: UserRef<u32>,
252 ) -> Result<SyscallResult, Errno> {
253 let response: u32 = UINPUT_VERSION;
254 current_task.write_object(user_version, &response)?;
255 Ok(SUCCESS)
256 }
257
258 fn ui_dev_setup(
261 &self,
262 current_task: &CurrentTask,
263 user_uinput_setup: UserRef<uapi::uinput_setup>,
264 ) -> Result<SyscallResult, Errno> {
265 let uinput_setup = current_task.read_object(user_uinput_setup)?;
266 self.inner.lock().input_id = Some(uinput_setup.id);
267 Ok(SUCCESS)
268 }
269
270 fn ui_dev_create<L>(
271 &self,
272 locked: &mut Locked<L>,
273 current_task: &CurrentTask,
274 ) -> Result<SyscallResult, Errno>
275 where
276 L: LockEqualOrBefore<FileOpsCore>,
277 {
278 let registry = match fuchsia_component::client::connect_to_protocol_sync::<
280 futinput::RegistryMarker,
281 >() {
282 Ok(proxy) => Some(proxy),
283 Err(_) => {
284 log_warn!("Could not connect to fuchsia.ui.test.input/Registry");
285 None
286 }
287 };
288 self.ui_dev_create_inner(locked, current_task, registry)
289 }
290
291 fn ui_dev_create_inner<L>(
294 &self,
295 locked: &mut Locked<L>,
296 current_task: &CurrentTask,
297 registry: Option<futinput::RegistrySynchronousProxy>,
299 ) -> Result<SyscallResult, Errno>
300 where
301 L: LockEqualOrBefore<FileOpsCore>,
302 {
303 match registry {
304 Some(proxy) => {
305 let mut inner = self.inner.lock();
306 let (input_id, device_type) = match inner.get_id_and_device_type() {
307 Some((id, dev)) => (id, dev),
308 None => return error!(EINVAL),
309 };
310
311 let open_files: OpenedFiles = Default::default();
312
313 let (registered_device_id, inspect_status) = match device_type {
314 DeviceId::Keyboard => {
315 let (key_client, key_server) =
316 fidl::endpoints::create_sync_proxy::<futinput::KeyboardMarker>();
317 inner.created_device =
318 CreatedDevice::Keyboard(key_client, LinuxKeyboardEventParser::create());
319
320 let register_res = proxy.register_keyboard_and_get_device_info(
322 RegistryRegisterKeyboardAndGetDeviceInfoRequest {
323 device: Some(key_server),
324 ..Default::default()
325 },
326 zx::MonotonicInstant::INFINITE,
327 );
328
329 match register_res {
330 Ok(resp) => match resp.device_id {
331 Some(device_id) => {
332 inner.device_id = Some(device_id);
333 let node = self
334 .inspect_node
335 .create_child(format!("uinput_device_{}", device_id));
336 let inspect_status = crate::InputDeviceStatus::new(node);
337 self.input_event_relay.add_keyboard_device(
338 device_id,
339 open_files.clone(),
340 Some(inspect_status.clone()),
341 );
342 (device_id, inspect_status)
343 }
344 None => {
345 log_warn!(
346 "register_keyboard_and_get_device_info response does not include a device_id"
347 );
348 return error!(EPERM);
349 }
350 },
351 Err(e) => {
352 log_warn!(
353 "Uinput could not register Keyboard device to Registry: {:?}",
354 e
355 );
356 return error!(EPERM);
357 }
358 }
359 }
360 DeviceId::Touchscreen(_width, _height) => {
361 let (touch_client, touch_server) =
362 fidl::endpoints::create_sync_proxy::<futinput::TouchScreenMarker>();
363 inner.created_device = CreatedDevice::Touchscreen(
364 touch_client,
365 Box::new(LinuxTouchEventParser::create()),
366 );
367
368 let mut request = RegistryRegisterTouchScreenAndGetDeviceInfoRequest {
369 device: Some(touch_server),
370 coordinate_unit: Some(CoordinateUnit::PhysicalPixels),
371 ..Default::default()
372 };
373
374 if inner.x_range.is_some() && inner.y_range.is_some() {
375 request.coordinate_unit = Some(CoordinateUnit::RegisteredDimensions);
376 let x_range = inner.x_range.as_ref().unwrap();
377 let y_range = inner.y_range.as_ref().unwrap();
378 request.display_dimensions = Some(DisplayDimensions {
379 min_x: x_range.min.into(),
380 max_x: x_range.max.into(),
381 min_y: y_range.min.into(),
382 max_y: y_range.max.into(),
383 });
384 }
385
386 let register_res = proxy.register_touch_screen_and_get_device_info(
388 request,
389 zx::Instant::INFINITE,
390 );
391
392 match register_res {
393 Ok(resp) => match resp.device_id {
394 Some(device_id) => {
395 inner.device_id = Some(device_id);
396 let node = self
397 .inspect_node
398 .create_child(format!("uinput_device_{}", device_id));
399 let inspect_status = crate::InputDeviceStatus::new(node);
400 self.input_event_relay.add_touch_device(
401 device_id,
402 open_files.clone(),
403 Some(inspect_status.clone()),
404 );
405 (device_id, inspect_status)
406 }
407 None => {
408 log_warn!(
409 "register_touch_screen_and_get_device_info response does not include a device_id"
410 );
411 return error!(EPERM);
412 }
413 },
414 Err(e) => {
415 log_warn!(
416 "Uinput could not register Keyboard device to Registry: {:?}",
417 e
418 );
419 return error!(EPERM);
420 }
421 }
422 }
423 };
424
425 let device = add_and_register_input_device(
426 locked,
427 current_task,
428 VirtualDevice { input_id, devt: device_type, open_files, inspect_status },
429 registered_device_id,
430 )?;
431 inner.k_device = Some(device);
432
433 new_device();
434
435 Ok(SUCCESS)
436 }
437 None => {
438 log_warn!("No Registry available for Uinput.");
439 error!(EPERM)
440 }
441 }
442 }
443
444 fn ui_dev_destroy<L>(
445 &self,
446 locked: &mut Locked<L>,
447 current_task: &CurrentTask,
448 ) -> Result<SyscallResult, Errno>
449 where
450 L: LockEqualOrBefore<FileOpsCore>,
451 {
452 let mut inner = self.inner.lock();
453 match inner.device_id {
454 Some(device_id) => {
455 self.input_event_relay.remove_device(device_id);
456 }
457 None => {
458 }
461 }
462
463 match inner.k_device.clone() {
464 Some(device) => {
465 let kernel = current_task.kernel();
466 kernel.device_registry.remove_device(locked, current_task, device);
467 }
468 None => {
469 log_warn!("UI_DEV_DESTROY kHandle not found");
470 return error!(EPERM);
471 }
472 }
473 inner.k_device = None;
474 inner.created_device = CreatedDevice::None;
475
476 destroy_device();
477
478 Ok(SUCCESS)
479 }
480}
481
482static COUNT_OF_UINPUT_DEVICE: AtomicI32 = AtomicI32::new(0);
484
485fn new_device() {
486 let _ = COUNT_OF_UINPUT_DEVICE.fetch_add(1, Ordering::SeqCst);
487}
488
489fn destroy_device() {
490 let _ = COUNT_OF_UINPUT_DEVICE.fetch_sub(1, Ordering::SeqCst);
491}
492
493pub fn uinput_running() -> bool {
494 COUNT_OF_UINPUT_DEVICE.load(Ordering::SeqCst) > 0
495}
496
497impl CloseFreeSafe for UinputDeviceFile {}
499impl FileOps for UinputDeviceFile {
500 fileops_impl_seekless!();
501 fileops_impl_noop_sync!();
502
503 fn ioctl(
504 &self,
505 locked: &mut Locked<Unlocked>,
506 file: &FileObject,
507 current_task: &CurrentTask,
508 request: u32,
509 arg: SyscallArg,
510 ) -> Result<SyscallResult, Errno> {
511 match request {
512 uapi::UI_GET_VERSION => self.ui_get_version(current_task, arg.into()),
513 uapi::UI_SET_EVBIT => self.ui_set_evbit(arg),
514 uapi::UI_ABS_SETUP => self.ui_abs_setup(current_task, arg.into()),
515 uapi::UI_SET_KEYBIT
519 | uapi::UI_SET_ABSBIT
520 | uapi::UI_SET_PHYS
521 | uapi::UI_SET_PROPBIT => Ok(SUCCESS),
522 uapi::UI_DEV_SETUP => self.ui_dev_setup(current_task, arg.into()),
523 uapi::UI_DEV_CREATE => self.ui_dev_create(locked, current_task),
524 uapi::UI_DEV_DESTROY => self.ui_dev_destroy(locked, current_task),
525 _ => {
528 log_warn!("receive unknown ioctl request: {:?}", request);
529 default_ioctl(file, locked, current_task, request, arg)
530 }
531 }
532 }
533
534 fn write(
535 &self,
536 _locked: &mut Locked<FileOpsCore>,
537 _file: &vfs::FileObject,
538 current_task: &starnix_core::task::CurrentTask,
539 _offset: usize,
540 data: &mut dyn vfs::buffers::InputBuffer,
541 ) -> Result<usize, Errno> {
542 let content = data.read_all()?;
543 let event =
544 InputEventPtr::read_from_prefix(current_task, &content).map_err(|_| errno!(EINVAL))?;
545 let mut inner = self.inner.lock();
546
547 match &mut inner.created_device {
548 CreatedDevice::Keyboard(proxy, parser) => {
549 let input_report = parser.handle(event);
550 match input_report {
551 Ok(Some(report)) => {
552 if let Some(keyboard_report) = report.keyboard {
553 let res = proxy.simulate_key_event(
554 &KeyboardSimulateKeyEventRequest {
555 report: Some(keyboard_report),
556 ..Default::default()
557 },
558 zx::MonotonicInstant::INFINITE,
559 );
560 if res.is_err() {
561 return error!(EIO);
562 }
563 }
564 }
565 Ok(None) => (),
566 Err(e) => return Err(e),
567 }
568 }
569 CreatedDevice::Touchscreen(proxy, parser) => {
570 let input_report = parser.handle(event);
571 match input_report {
572 Ok(Some(report)) => {
573 if let Some(touch_report) = report.touch {
574 let res = proxy.simulate_touch_event(
575 &touch_report,
576 zx::MonotonicInstant::INFINITE,
577 );
578 if res.is_err() {
579 return error!(EIO);
580 }
581 }
582 }
583 Ok(None) => (),
584 Err(e) => return Err(e),
585 }
586 }
587 CreatedDevice::None => return error!(EINVAL),
588 }
589
590 Ok(content.len())
591 }
592
593 fn read(
594 &self,
595 _locked: &mut Locked<FileOpsCore>,
596 _file: &vfs::FileObject,
597 _current_task: &starnix_core::task::CurrentTask,
598 _offset: usize,
599 _data: &mut dyn vfs::buffers::OutputBuffer,
600 ) -> Result<usize, Errno> {
601 log_warn!("uinput FD does not support read().");
602 error!(EINVAL)
603 }
604}
605
606#[derive(Clone)]
607pub struct VirtualDevice {
608 input_id: uapi::input_id,
609 devt: DeviceId,
610 open_files: OpenedFiles,
611 inspect_status: Arc<crate::InputDeviceStatus>,
612}
613
614impl DeviceOps for VirtualDevice {
615 fn open(
616 &self,
617 _locked: &mut Locked<FileOpsCore>,
618 _current_task: &CurrentTask,
619 _id: device_id::DeviceId,
620 _node: &NamespaceNode,
621 _flags: OpenFlags,
622 ) -> Result<Box<dyn FileOps>, Errno> {
623 let mut file_nodes = self.inspect_status.file_nodes.lock();
624 let child_node =
625 self.inspect_status.node.create_child(format!("file_{}", file_nodes.len()));
626 let input_file = match &self.devt {
627 DeviceId::Keyboard => Arc::new(InputFile::new_keyboard(self.input_id, &child_node)),
628 DeviceId::Touchscreen(width, height) => Arc::new(InputFile::new_touch(
629 self.input_id,
630 width.clone(),
631 height.clone(),
632 &child_node,
633 )),
634 };
635
636 file_nodes.push(child_node);
637 input_file.init_inspect_status();
638 self.open_files.lock().push(Arc::downgrade(&input_file));
639
640 Ok(Box::new(crate::input_file::ArcInputFile(input_file)))
641 }
642}
643
644#[cfg(test)]
645mod test {
646 use super::*;
647 use crate::{EventProxyMode, start_input_relays_for_test};
648 use starnix_core::task::Kernel;
649 #[allow(deprecated, reason = "pre-existing usage")]
650 use starnix_core::testing::{AutoReleasableTask, create_kernel_task_and_unlocked};
651 use starnix_core::vfs::FileHandle;
652 use std::sync::Arc;
653 use test_case::test_case;
654
655 async fn new_kernel_objects() -> (
656 Arc<UinputDeviceFile>,
657 Arc<Kernel>,
658 AutoReleasableTask,
659 FileHandle,
660 &'static mut Locked<Unlocked>,
661 ) {
662 #[allow(deprecated, reason = "pre-existing usage")]
663 let (kernel, current_task, locked) = create_kernel_task_and_unlocked();
664 let (input_relay_handle, _, _, _, _, _, _, _, _, _, _, _) =
665 start_input_relays_for_test(locked, ¤t_task, EventProxyMode::None).await;
666 let inspector = fuchsia_inspect::Inspector::default();
667 let dev = Arc::new(UinputDeviceFile::new(
668 input_relay_handle,
669 Arc::new(inspector.root().create_child("uinput")),
670 ));
671
672 let root_namespace_node = current_task
673 .lookup_path_from_root(locked, ".".into())
674 .expect("failed to get namespace node for root");
675
676 let file_object = FileObject::new(
677 locked,
678 ¤t_task,
679 Box::new(dev.clone()),
680 root_namespace_node,
683 OpenFlags::empty(),
684 )
685 .expect("FileObject::new failed");
686 (dev, kernel, current_task, file_object, locked)
687 }
688
689 #[test_case(uapi::EV_KEY, vec![uapi::EV_KEY as usize] => Ok(SUCCESS))]
690 #[test_case(uapi::EV_ABS, vec![uapi::EV_ABS as usize] => Ok(SUCCESS))]
691 #[test_case(uapi::EV_REL, vec![] => error!(EPERM))]
692 #[::fuchsia::test]
693 async fn ui_set_evbit(bit: u32, expected_evbits: Vec<usize>) -> Result<SyscallResult, Errno> {
694 let (dev, _kernel, current_task, file_object, locked) = new_kernel_objects().await;
695 let locked = locked.cast_locked::<Unlocked>();
696 let r = dev.ioctl(
697 locked,
698 &file_object,
699 ¤t_task,
700 uapi::UI_SET_EVBIT,
701 SyscallArg::from(bit as u64),
702 );
703 for expected_evbit in expected_evbits {
704 assert!(dev.inner.lock().enabled_evbits.get(expected_evbit).unwrap());
705 }
706 r
707 }
708
709 #[::fuchsia::test]
710 async fn ui_set_evbit_call_multi() {
711 let (dev, _kernel, current_task, file_object, locked) = new_kernel_objects().await;
712 let locked = locked.cast_locked::<Unlocked>();
713 let r = dev.ioctl(
714 locked,
715 &file_object,
716 ¤t_task,
717 uapi::UI_SET_EVBIT,
718 SyscallArg::from(uapi::EV_KEY as u64),
719 );
720 assert_eq!(r, Ok(SUCCESS));
721 let r = dev.ioctl(
722 locked,
723 &file_object,
724 ¤t_task,
725 uapi::UI_SET_EVBIT,
726 SyscallArg::from(uapi::EV_ABS as u64),
727 );
728 assert_eq!(r, Ok(SUCCESS));
729 assert!(dev.inner.lock().enabled_evbits.get(uapi::EV_KEY as usize).unwrap());
730 assert!(dev.inner.lock().enabled_evbits.get(uapi::EV_ABS as usize).unwrap());
731 }
732
733 #[::fuchsia::test]
734 async fn ui_set_keybit() {
735 let (dev, _kernel, current_task, file_object, locked) = new_kernel_objects().await;
736 let locked = locked.cast_locked::<Unlocked>();
737 let r = dev.ioctl(
738 locked,
739 &file_object,
740 ¤t_task,
741 uapi::UI_SET_KEYBIT,
742 SyscallArg::from(uapi::BTN_TOUCH as u64),
743 );
744 assert_eq!(r, Ok(SUCCESS));
745
746 let r = dev.ioctl(
748 locked,
749 &file_object,
750 ¤t_task,
751 uapi::UI_SET_KEYBIT,
752 SyscallArg::from(uapi::KEY_SPACE as u64),
753 );
754 assert_eq!(r, Ok(SUCCESS));
755 }
756
757 #[::fuchsia::test]
758 async fn ui_set_absbit() {
759 let (dev, _kernel, current_task, file_object, locked) = new_kernel_objects().await;
760 let locked = locked.cast_locked::<Unlocked>();
761 let r = dev.ioctl(
762 locked,
763 &file_object,
764 ¤t_task,
765 uapi::UI_SET_ABSBIT,
766 SyscallArg::from(uapi::ABS_MT_SLOT as u64),
767 );
768 assert_eq!(r, Ok(SUCCESS));
769
770 let r = dev.ioctl(
772 locked,
773 &file_object,
774 ¤t_task,
775 uapi::UI_SET_ABSBIT,
776 SyscallArg::from(uapi::ABS_MT_TOUCH_MAJOR as u64),
777 );
778 assert_eq!(r, Ok(SUCCESS));
779 }
780
781 #[::fuchsia::test]
782 async fn ui_set_propbit() {
783 let (dev, _kernel, current_task, file_object, locked) = new_kernel_objects().await;
784 let locked = locked.cast_locked::<Unlocked>();
785 let r = dev.ioctl(
786 locked,
787 &file_object,
788 ¤t_task,
789 uapi::UI_SET_PROPBIT,
790 SyscallArg::from(uapi::INPUT_PROP_DIRECT as u64),
791 );
792 assert_eq!(r, Ok(SUCCESS));
793
794 let r = dev.ioctl(
796 locked,
797 &file_object,
798 ¤t_task,
799 uapi::UI_SET_PROPBIT,
800 SyscallArg::from(uapi::INPUT_PROP_DIRECT as u64),
801 );
802 assert_eq!(r, Ok(SUCCESS));
803 }
804}