You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
115 lines
2.9 KiB
115 lines
2.9 KiB
/* |
|
* Copyright 2023 Google LLC |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#define DT_DRV_COMPAT zephyr_native_linux_evdev |
|
|
|
#include <cmdline.h> |
|
#include <nsi_host_trampolines.h> |
|
#include <posix_native_task.h> |
|
#include <zephyr/device.h> |
|
#include <zephyr/input/input.h> |
|
#include <zephyr/kernel.h> |
|
#include <zephyr/logging/log.h> |
|
#include <zephyr/sys/util.h> |
|
|
|
#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);
|
|
|