summaryrefslogtreecommitdiff
path: root/components/drivers/input/input.c
diff options
context:
space:
mode:
authorGUI <[email protected]>2025-12-10 16:58:10 +0800
committerGitHub <[email protected]>2025-12-10 16:58:10 +0800
commit3ff3fc39485c725cd93053805d25125353dd53e9 (patch)
tree708ac806078173a5bb47d56278f3dc8edbc865b9 /components/drivers/input/input.c
parent357c9b7b5a61ce2062cbfcb37d9dba8d17ff3d6d (diff)
[dm][input] support input #11031
Diffstat (limited to 'components/drivers/input/input.c')
-rw-r--r--components/drivers/input/input.c405
1 files changed, 405 insertions, 0 deletions
diff --git a/components/drivers/input/input.c b/components/drivers/input/input.c
new file mode 100644
index 0000000000..deec1fb594
--- /dev/null
+++ b/components/drivers/input/input.c
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-3-08 GuEe-GUI the first version
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define DBG_TAG "rtdm.input"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+static RT_DEFINE_SPINLOCK(input_device_lock);
+static rt_list_t input_device_nodes = RT_LIST_OBJECT_INIT(input_device_nodes);
+
+static struct rt_dm_ida input_ida = RT_DM_IDA_INIT(INPUT);
+
+#ifdef RT_INPUT_TOUCHSCREEN
+extern void input_touch_register(struct rt_input_device *idev);
+extern void input_touch_unregister(struct rt_input_device *idev);
+#endif
+
+#ifdef RT_INPUT_UAPI
+extern void input_uapi_init(struct rt_input_device *idev);
+extern void input_uapi_finit(struct rt_input_device *idev);
+extern void input_uapi_event(struct rt_input_device *idev, struct rt_input_event *event);
+#endif
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops _input_ops =
+{
+};
+#endif
+
+rt_err_t rt_input_device_register(struct rt_input_device *idev)
+{
+ rt_err_t err;
+ int device_id;
+ const char *dev_name;
+
+ if (!idev)
+ {
+ return -RT_EINVAL;
+ }
+
+ if ((device_id = rt_dm_ida_alloc(&input_ida)) < 0)
+ {
+ err = -RT_EFULL;
+ goto _remove_config;
+ }
+
+ rt_dm_dev_set_name(&idev->parent, "input%u", device_id);
+ dev_name = rt_dm_dev_get_name(&idev->parent);
+
+ rt_list_init(&idev->list);
+ rt_list_init(&idev->handler_nodes);
+ rt_spin_lock_init(&idev->lock);
+
+ /* Just make a search interface */
+ idev->parent.type = RT_Device_Class_Char;
+#ifdef RT_USING_DEVICE_OPS
+ idev->parent.ops = idev->parent.ops ? : &_input_ops;
+#endif
+ idev->parent.master_id = input_ida.master_id;
+ idev->parent.device_id = device_id;
+
+ if ((err = rt_device_register(&idev->parent, dev_name, RT_DEVICE_FLAG_DEACTIVATE)))
+ {
+ goto _fail;
+ }
+
+#ifdef RT_INPUT_UAPI
+ input_uapi_init(idev);
+#endif
+
+ rt_spin_lock(&input_device_lock);
+ rt_list_insert_before(&input_device_nodes, &idev->list);
+ rt_spin_unlock(&input_device_lock);
+
+#ifdef RT_INPUT_TOUCHSCREEN
+ /* MUST be registered after the list is inserted */
+ input_touch_register(idev);
+#endif
+
+ if (idev->poller)
+ {
+ rt_timer_start(&idev->poller->timer);
+ }
+
+ return RT_EOK;
+
+_fail:
+ rt_dm_ida_free(&input_ida, device_id);
+
+_remove_config:
+ rt_input_remove_config(idev);
+
+ return err;
+}
+
+rt_err_t rt_input_device_unregister(struct rt_input_device *idev)
+{
+ const char *dev_name;
+
+ if (!idev)
+ {
+ return -RT_EINVAL;
+ }
+
+ dev_name = rt_dm_dev_get_name(&idev->parent);
+
+ if (idev->parent.ref_count)
+ {
+ LOG_E("%s: there is %u user", dev_name, idev->parent.ref_count);
+ return -RT_EINVAL;
+ }
+
+#ifdef RT_INPUT_UAPI
+ input_uapi_finit(idev);
+#endif
+#ifdef RT_INPUT_TOUCHSCREEN
+ input_touch_unregister(idev);
+#endif
+ rt_input_remove_config(idev);
+
+ rt_dm_ida_free(&input_ida, idev->parent.device_id);
+
+ rt_device_unregister(&idev->parent);
+
+ rt_spin_lock(&input_device_lock);
+ rt_list_remove(&idev->list);
+ rt_spin_unlock(&input_device_lock);
+
+ return RT_EOK;
+}
+
+rt_err_t rt_input_set_capability(struct rt_input_device *idev,
+ rt_uint16_t type, rt_uint16_t code)
+{
+ if (!idev)
+ {
+ return -RT_EINVAL;
+ }
+
+ switch (type)
+ {
+ case EV_KEY:
+ rt_bitmap_set_bit(idev->key_map, code);
+ break;
+
+ case EV_REL:
+ rt_bitmap_set_bit(idev->rel_map, code);
+ break;
+
+ case EV_ABS:
+ if (!idev->absinfo)
+ {
+ idev->absinfo = rt_calloc(ABS_CNT, sizeof(*idev->absinfo));
+
+ if (!idev->absinfo)
+ {
+ return -RT_ENOMEM;
+ }
+ }
+ rt_bitmap_set_bit(idev->abs_map, code);
+ break;
+
+ case EV_MSC:
+ case EV_SW:
+ case EV_LED:
+ case EV_SND:
+ case EV_REP:
+ case EV_FF:
+ case EV_PWR:
+ case EV_FF_STATUS:
+ return -RT_ENOSYS;
+
+ default:
+ return -RT_EINVAL;
+ }
+
+ rt_bitmap_set_bit(idev->cap, type);
+
+ return RT_EOK;
+}
+
+rt_err_t rt_input_set_absinfo(struct rt_input_device *idev, rt_uint32_t axis,
+ rt_int32_t min, rt_int32_t max, rt_int32_t fuzz, rt_int32_t flat)
+{
+ struct rt_input_absinfo *absinfo;
+
+ if (!idev || !idev->absinfo)
+ {
+ return -RT_EINVAL;
+ }
+
+ rt_bitmap_set_bit(idev->abs_map, axis);
+
+ absinfo = &idev->absinfo[axis];
+ absinfo->minimum = min;
+ absinfo->maximum = max;
+ absinfo->fuzz = fuzz;
+ absinfo->flat = flat;
+
+ return RT_EOK;
+}
+
+static void input_poll(void *param)
+{
+ struct rt_input_device *idev = param;
+
+ idev->poller->poll(idev);
+}
+
+rt_err_t rt_input_setup_polling(struct rt_input_device *idev,
+ void (*poll)(struct rt_input_device *idev))
+{
+ const char *dev_name;
+
+ if (!idev || !poll)
+ {
+ return -RT_EINVAL;
+ }
+
+ dev_name = rt_dm_dev_get_name(&idev->parent);
+
+ idev->poller = rt_malloc(sizeof(*idev->poller));
+
+ if (!idev->poller)
+ {
+ return -RT_ENOMEM;
+ }
+
+ idev->poller->poll = poll;
+
+ rt_timer_init(&idev->poller->timer, dev_name, input_poll, idev,
+ rt_tick_from_millisecond(RT_INPUT_POLL_INTERVAL_DEFAULT),
+ RT_TIMER_FLAG_PERIODIC);
+
+ return RT_EOK;
+}
+
+void rt_input_remove_config(struct rt_input_device *idev)
+{
+ if (!idev)
+ {
+ return;
+ }
+
+ if (idev->poller)
+ {
+ rt_timer_stop(&idev->poller->timer);
+ rt_timer_detach(&idev->poller->timer);
+
+ rt_free(idev->poller);
+ idev->poller = RT_NULL;
+ }
+
+ if (idev->absinfo)
+ {
+ rt_free(idev->absinfo);
+ idev->absinfo = RT_NULL;
+ }
+
+#ifdef RT_INPUT_TOUCHSCREEN
+ if (idev->touch)
+ {
+ rt_free(idev->touch);
+ idev->touch = RT_NULL;
+ }
+#endif /* RT_INPUT_TOUCHSCREEN */
+}
+
+rt_err_t rt_input_set_poll_interval(struct rt_input_device *idev,
+ rt_uint32_t interval_ms)
+{
+ rt_tick_t tick;
+
+ if (!idev || !idev->poller)
+ {
+ return -RT_EINVAL;
+ }
+
+ tick = rt_tick_from_millisecond(interval_ms);
+
+ return rt_timer_control(&idev->poller->timer, RT_TIMER_CTRL_SET_TIME, &tick);
+}
+
+rt_err_t rt_input_trigger(struct rt_input_device *idev,
+ rt_uint16_t type, rt_uint16_t code, rt_int32_t value)
+{
+ RT_ASSERT(idev != RT_NULL);
+
+ if (idev->trigger)
+ {
+ return idev->trigger(idev, type, code, value);
+ }
+
+ return -RT_ENOSYS;
+}
+
+void rt_input_event(struct rt_input_device *idev,
+ rt_uint16_t type, rt_uint16_t code, rt_int32_t value)
+{
+ struct rt_input_event event;
+ struct rt_input_handler *handler, *handler_next;
+
+ RT_ASSERT(idev != RT_NULL);
+ RT_ASSERT(type < EV_MAX);
+
+ event.tick = rt_tick_get();
+ event.type = type;
+ event.code = code;
+ event.value = value;
+
+ rt_spin_lock(&idev->lock);
+
+#ifdef RT_INPUT_UAPI
+ input_uapi_event(idev, &event);
+#endif
+
+ rt_list_for_each_entry_safe(handler, handler_next, &idev->handler_nodes, list)
+ {
+ if (handler->callback(handler, &event))
+ {
+ break;
+ }
+ }
+
+ rt_spin_unlock(&idev->lock);
+}
+
+rt_err_t rt_input_add_handler(struct rt_input_handler *handler)
+{
+ struct rt_input_device *idev = RT_NULL, *idev_tmp;
+
+ if (!handler || !handler->callback)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (!handler->idev && !handler->identify)
+ {
+ return -RT_EINVAL;
+ }
+
+ rt_spin_lock(&input_device_lock);
+
+ rt_list_for_each_entry(idev_tmp, &input_device_nodes, list)
+ {
+ if (handler->idev)
+ {
+ if (handler->idev == idev_tmp)
+ {
+ idev = idev_tmp;
+ break;
+ }
+ }
+ else if (handler->identify(handler, idev_tmp))
+ {
+ idev = idev_tmp;
+ break;
+ }
+ }
+
+ rt_spin_unlock(&input_device_lock);
+
+ if (!idev)
+ {
+ return -RT_ENOSYS;
+ }
+
+ handler->idev = idev;
+ rt_list_init(&handler->list);
+
+ rt_spin_lock(&idev->lock);
+ rt_list_insert_before(&idev->handler_nodes, &handler->list);
+ rt_spin_unlock(&idev->lock);
+
+ return RT_EOK;
+}
+
+rt_err_t rt_input_del_handler(struct rt_input_handler *handler)
+{
+ struct rt_input_device *idev;
+
+ if (!handler)
+ {
+ return -RT_EINVAL;
+ }
+
+ idev = handler->idev;
+
+ rt_spin_lock(&idev->lock);
+ rt_list_remove(&handler->list);
+ rt_spin_unlock(&idev->lock);
+
+ return RT_EOK;
+}