/* * Copyright 2023 Google LLC * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT zephyr_native_linux_evdev #include #include #include #include #include #include #include #include #include "linux_evdev_bottom.h" LOG_MODULE_REGISTER(linux_evdev, CONFIG_INPUT_LOG_LEVEL); static int linux_evdev_fd = -1; static const char *linux_evdev_path; static struct k_thread linux_evdev_thread; static K_KERNEL_STACK_DEFINE(linux_evdev_thread_stack, CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE); static void linux_evdev_options(void) { static struct args_struct_t linux_evdev_options[] = { { .is_mandatory = true, .option = "evdev", .name = "path", .type = 's', .dest = (void *)&linux_evdev_path, .descript = "Path of the evdev device to use", }, ARG_TABLE_ENDMARKER, }; native_add_command_line_opts(linux_evdev_options); } static void linux_evdev_check_arg(void) { if (linux_evdev_path == NULL) { posix_print_error_and_exit( "Error: evdev device missing.\n" "Please specify an evdev device with the --evdev " "argument when using CONFIG_NATIVE_LINUX_EVDEV=y\n"); } } static void linux_evdev_cleanup(void) { if (linux_evdev_fd >= 0) { nsi_host_close(linux_evdev_fd); } } NATIVE_TASK(linux_evdev_options, PRE_BOOT_1, 10); NATIVE_TASK(linux_evdev_check_arg, PRE_BOOT_2, 10); NATIVE_TASK(linux_evdev_cleanup, ON_EXIT, 10); static void linux_evdev_thread_fn(void *p1, void *p2, void *p3) { const struct device *dev = p1; uint16_t type; uint16_t code; int32_t value; int ret; while (true) { ret = linux_evdev_read(linux_evdev_fd, &type, &code, &value); if (ret == NATIVE_LINUX_EVDEV_NO_DATA) { /* Let other threads run. */ k_sleep(K_MSEC(CONFIG_NATIVE_LINUX_THREAD_SLEEP_MS)); continue; } else if (ret < 0) { return; } LOG_DBG("evdev event: type=%d code=%d val=%d", type, code, value); if (type == 0) { /* EV_SYN */ input_report(dev, 0, 0, 0, true, K_FOREVER); } else if (type == INPUT_EV_KEY && value == 2) { /* nothing, ignore key repeats */ } else { input_report(dev, type, code, value, false, K_FOREVER); } } } static int linux_evdev_init(const struct device *dev) { linux_evdev_fd = linux_evdev_open(linux_evdev_path); k_thread_create(&linux_evdev_thread, linux_evdev_thread_stack, K_KERNEL_STACK_SIZEOF(linux_evdev_thread_stack), linux_evdev_thread_fn, (void *)dev, NULL, NULL, CONFIG_NATIVE_LINUX_EVDEV_THREAD_PRIORITY, 0, K_NO_WAIT); k_thread_name_set(&linux_evdev_thread, dev->name); return 0; } BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "Only one zephyr,native-linux-evdev compatible node is supported"); DEVICE_DT_INST_DEFINE(0, linux_evdev_init, NULL, NULL, NULL, POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL);