diff options
Diffstat (limited to 'components/drivers/input')
| -rw-r--r-- | components/drivers/input/Kconfig | 36 | ||||
| -rw-r--r-- | components/drivers/input/SConscript | 32 | ||||
| -rw-r--r-- | components/drivers/input/input.c | 405 | ||||
| -rw-r--r-- | components/drivers/input/input_power.c | 130 | ||||
| -rw-r--r-- | components/drivers/input/input_touch.c | 453 | ||||
| -rw-r--r-- | components/drivers/input/input_uapi.c | 399 | ||||
| -rw-r--r-- | components/drivers/input/joystick/Kconfig | 7 | ||||
| -rw-r--r-- | components/drivers/input/joystick/SConscript | 15 | ||||
| -rw-r--r-- | components/drivers/input/keyboard/Kconfig | 13 | ||||
| -rw-r--r-- | components/drivers/input/keyboard/SConscript | 18 | ||||
| -rw-r--r-- | components/drivers/input/keyboard/keys-gpio.c | 163 | ||||
| -rw-r--r-- | components/drivers/input/misc/Kconfig | 12 | ||||
| -rw-r--r-- | components/drivers/input/misc/SConscript | 18 | ||||
| -rw-r--r-- | components/drivers/input/misc/button-e3x0.c | 115 | ||||
| -rw-r--r-- | components/drivers/input/touchscreen/Kconfig | 8 | ||||
| -rw-r--r-- | components/drivers/input/touchscreen/SConscript | 15 |
16 files changed, 1839 insertions, 0 deletions
diff --git a/components/drivers/input/Kconfig b/components/drivers/input/Kconfig new file mode 100644 index 0000000000..707a7500d9 --- /dev/null +++ b/components/drivers/input/Kconfig @@ -0,0 +1,36 @@ +menuconfig RT_USING_INPUT + bool "Using Input device drivers" + depends on RT_USING_DM + select RT_USING_ADT + select RT_USING_ADT_BITMAP + default n + +config RT_INPUT_POWER + bool "Input event power" + depends on RT_USING_INPUT + default y + +config RT_INPUT_UAPI + bool "Input event Unix API" + depends on RT_USING_INPUT + depends on RT_USING_KTIME + depends on RT_USING_POSIX_DEVIO + default n + default y if RT_USING_SMART + +config RT_INPUT_UAPI_EVENT_MAX + int "Events storage max" + depends on RT_INPUT_UAPI + default 128 + +config RT_UAPI_FAKE_BLOCK + bool "Events fake when block" + depends on RT_INPUT_UAPI + default y + +if RT_USING_INPUT + rsource "joystick/Kconfig" + rsource "keyboard/Kconfig" + rsource "misc/Kconfig" + rsource "touchscreen/Kconfig" +endif diff --git a/components/drivers/input/SConscript b/components/drivers/input/SConscript new file mode 100644 index 0000000000..a1a02c7024 --- /dev/null +++ b/components/drivers/input/SConscript @@ -0,0 +1,32 @@ +from building import * + +group = [] +objs = [] + +if not GetDepend(['RT_USING_INPUT']): + Return('group') + +cwd = GetCurrentDir() +list = os.listdir(cwd) +CPPPATH = [cwd + '/../include'] + +src = ['input.c'] + +if GetDepend(['RT_INPUT_POWER']): + src += ['input_power.c'] + +if GetDepend(['RT_INPUT_TOUCHSCREEN']): + src += ['input_touch.c'] + +if GetDepend(['RT_INPUT_UAPI']): + src += ['input_uapi.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) +objs = objs + group + +Return('objs') 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; +} diff --git a/components/drivers/input/input_power.c b/components/drivers/input/input_power.c new file mode 100644 index 0000000000..11bf7b86aa --- /dev/null +++ b/components/drivers/input/input_power.c @@ -0,0 +1,130 @@ +/* + * 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 "input.power" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> + +struct input_event_cap +{ + rt_uint16_t code; + rt_int32_t value; + rt_int32_t current; +}; + +static rt_bool_t power_input_identify(struct rt_input_handler *handler, + struct rt_input_device *idev) +{ + struct input_event_cap *cap = handler->priv; + + if (rt_bitmap_test_bit(idev->key_map, cap->code)) + { + if (cap->value == cap->current) + { + return RT_TRUE; + } + + ++cap->current; + } + + return RT_FALSE; +} + +static rt_bool_t power_input_callback(struct rt_input_handler *handler, + struct rt_input_event *ev) +{ + if (ev->code == KEY_POWER) + { + if (ev->value == 0) + { + rt_hw_cpu_shutdown(); + } + + return RT_TRUE; + } + else if (ev->code == KEY_RESTART) + { + if (ev->value == 0) + { + rt_hw_cpu_reset(); + } + + return RT_TRUE; + } + + return RT_FALSE; +} + +static rt_bool_t power_test_cap(struct rt_input_handler *handler, + struct rt_input_device *idev) +{ + struct input_event_cap *cap = handler->priv; + + if (rt_bitmap_test_bit(idev->key_map, cap->code)) + { + ++cap->value; + } + + return RT_FALSE; +} + +static void power_handler_install(rt_uint16_t code) +{ + rt_uint32_t idev_count; + struct input_event_cap cap; + struct rt_input_handler tmp_handler, *handlers; + + cap.code = code; + cap.value = 0; + tmp_handler.idev = RT_NULL; + tmp_handler.identify = &power_test_cap; + tmp_handler.callback = &power_input_callback; + tmp_handler.priv = ∩ + rt_input_add_handler(&tmp_handler); /* Just test */ + + if (!(idev_count = cap.value)) + { + return; + } + + handlers = rt_calloc(idev_count, sizeof(*handlers)); + + if (!handlers) + { + LOG_E("No memory to install power handler"); + return; + } + + for (int i = 0; i < idev_count; ++i, ++handlers) + { + cap.value = i; + cap.current = 0; + + handlers->identify = &power_input_identify; + handlers->callback = &power_input_callback; + handlers->priv = ∩ + + rt_input_add_handler(handlers); + handlers->priv = RT_NULL; + } +} + +static int input_event_power_init(void) +{ + power_handler_install(KEY_POWER); + power_handler_install(KEY_RESTART); + + return 0; +} +INIT_ENV_EXPORT(input_event_power_init); diff --git a/components/drivers/input/input_touch.c b/components/drivers/input/input_touch.c new file mode 100644 index 0000000000..c5537b0122 --- /dev/null +++ b/components/drivers/input/input_touch.c @@ -0,0 +1,453 @@ +/* + * 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 "input.touch" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> + +struct input_touch_device +{ + struct rt_touch_device parent; + struct rt_input_handler handler; + + rt_bool_t enabled; + rt_uint16_t slot; + rt_uint16_t down; + struct rt_touch_data points[]; +}; + +struct input_touch_properties +{ + rt_uint32_t max_x; + rt_uint32_t max_y; + rt_bool_t invert_x; + rt_bool_t invert_y; + rt_bool_t swap_x_y; + + rt_uint16_t track_id; + rt_uint32_t num_slots; + struct input_touch_device *touch_dev; +}; + +static rt_size_t input_touch_readpoint(struct rt_touch_device *touch, + void *buf, rt_size_t touch_num) +{ + struct input_touch_device *touch_dev; + + touch_dev = rt_container_of(touch, struct input_touch_device, parent); + + rt_memcpy(buf, &touch_dev->points[touch_dev->slot], sizeof(struct rt_touch_data)); + + return 1; +} + +static rt_err_t input_touch_control(struct rt_touch_device *touch, int cmd, void *arg) +{ + rt_err_t err = RT_EOK; + struct input_touch_device *touch_dev; + + if (!arg) + { + return -RT_EINVAL; + } + + touch_dev = rt_container_of(touch, struct input_touch_device, parent); + + switch (cmd) + { + case RT_TOUCH_CTRL_GET_ID: + *(int *)arg = 0; + break; + + case RT_TOUCH_CTRL_GET_INFO: + rt_memcpy(arg, &touch_dev->parent.info, sizeof(touch_dev->parent.info)); + break; + + case RT_TOUCH_CTRL_SET_X_RANGE: + touch_dev->parent.info.range_x = *(rt_uint16_t *)arg; + break; + + case RT_TOUCH_CTRL_SET_Y_RANGE: + touch_dev->parent.info.range_y = *(rt_uint16_t *)arg; + break; + + case RT_TOUCH_CTRL_SET_X_TO_Y: + break; + + case RT_TOUCH_CTRL_DISABLE_INT: + case RT_TOUCH_CTRL_POWER_OFF: + touch_dev->enabled = RT_FALSE; + break; + + case RT_TOUCH_CTRL_ENABLE_INT: + case RT_TOUCH_CTRL_POWER_ON: + touch_dev->enabled = RT_TRUE; + break; + + case RT_TOUCH_CTRL_GET_STATUS: + *(int *)arg = touch_dev->enabled; + break; + + default: + err = -RT_ENOSYS; + break; + } + + return err; +} + +const static struct rt_touch_ops input_touch_ops = +{ + .touch_readpoint = input_touch_readpoint, + .touch_control = input_touch_control, +}; + +static rt_bool_t input_touch_cb(struct rt_input_handler *handler, + struct rt_input_event *ev) +{ + struct input_touch_device *touch_dev; + + touch_dev = rt_container_of(handler, struct input_touch_device, handler); + + if (touch_dev->enabled) + { + struct rt_touch_data *point = &touch_dev->points[touch_dev->slot]; + + if (ev->type == EV_ABS) + { + struct rt_input_device *idev = handler->idev; + struct rt_input_absinfo *absinfo = &idev->absinfo[touch_dev->slot]; + + switch (ev->code) + { + case ABS_MT_SLOT: + touch_dev->slot = ev->value; + break; + + case ABS_MT_TRACKING_ID: + point->timestamp = ev->tick; + + if (ev->value == (typeof(ev->code))-1) + { + point->event = RT_TOUCH_EVENT_UP; + + touch_dev->down = 0; + rt_hw_touch_isr(&touch_dev->parent); + + break; + } + + point->track_id = ev->value; + point->event = touch_dev->down ? RT_TOUCH_EVENT_MOVE : RT_TOUCH_EVENT_DOWN; + + ++touch_dev->down; + break; + + case ABS_MT_POSITION_X: + case ABS_X: + point->x_coordinate = (ev->value * touch_dev->parent.info.range_x) / + (absinfo->maximum - absinfo->minimum); + break; + + case ABS_MT_POSITION_Y: + case ABS_Y: + point->y_coordinate = (ev->value * touch_dev->parent.info.range_y) / + (absinfo->maximum - absinfo->minimum); + break; + } + } + else if (ev->type == EV_SYN && ev->code == SYN_REPORT && ev->value == 0) + { + rt_hw_touch_isr(&touch_dev->parent); + } + } + + return RT_FALSE; +} + +void input_touch_register(struct rt_input_device *idev) +{ + const char *dev_name; + struct rt_touch_device *tdev; + struct input_touch_device *touch_dev; + struct input_touch_properties *prop = idev->touch; + + /* Only register rt_touch_device */ + if (!prop || !prop->touch_dev) + { + return; + } + touch_dev = prop->touch_dev; + tdev = &touch_dev->parent; + + tdev->ops = &input_touch_ops; + + rt_dm_dev_set_name_auto(&tdev->parent, "touch"); + dev_name = rt_dm_dev_get_name(&tdev->parent); + + rt_hw_touch_register(tdev, dev_name, RT_DEVICE_FLAG_INT_RX, prop); + + touch_dev->enabled = RT_TRUE; + touch_dev->handler.idev = idev; + touch_dev->handler.callback = &input_touch_cb; + rt_input_add_handler(&touch_dev->handler); +} + +void input_touch_unregister(struct rt_input_device *idev) +{ + struct rt_touch_device *tdev; + struct input_touch_device *touch_dev; + struct input_touch_properties *prop = idev->touch; + + if (!prop) + { + return; + } + + if (prop->touch_dev) + { + goto _end; + } + + touch_dev = prop->touch_dev; + tdev = &touch_dev->parent; + + rt_input_del_handler(&touch_dev->handler); + rt_device_unregister(&tdev->parent); + +_end: + rt_free(idev->touch); + idev->touch = RT_NULL; +} + +static void input_touch_parse(struct rt_input_device *idev, + rt_bool_t multitouch, struct input_touch_properties *prop) +{ + rt_bool_t present = RT_TRUE; + rt_uint32_t axis, axis_x, axis_y; + rt_uint32_t minimum, maximum, fuzz; + struct rt_device *dev = &idev->parent; + struct rt_input_absinfo *absinfo = idev->absinfo; + + axis_x = multitouch ? ABS_MT_POSITION_X : ABS_X; + axis_y = multitouch ? ABS_MT_POSITION_Y : ABS_Y; + + if ((present = rt_dm_dev_prop_read_u32(dev, "touchscreen-min-x", &minimum))) + { + minimum = absinfo[axis_x].minimum; + } + + if ((present |= rt_dm_dev_prop_read_u32(dev, "touchscreen-size-x", &maximum))) + { + maximum = absinfo[axis_x].maximum + 1; + } + + if ((present |= rt_dm_dev_prop_read_u32(dev, "touchscreen-fuzz-x", &fuzz))) + { + fuzz = absinfo[axis_x].fuzz; + } + + if (present) + { + rt_input_set_absinfo(idev, axis_x, minimum, maximum - 1, fuzz, 0); + } + + if ((present = rt_dm_dev_prop_read_u32(dev, "touchscreen-min-y", &minimum))) + { + minimum = absinfo[axis_y].minimum; + } + + if ((present |= rt_dm_dev_prop_read_u32(dev, "touchscreen-size-y", &maximum))) + { + maximum = absinfo[axis_y].maximum + 1; + } + + if ((present |= rt_dm_dev_prop_read_u32(dev, "touchscreen-fuzz-y", &fuzz))) + { + fuzz = absinfo[axis_y].fuzz; + } + + if (present) + { + rt_input_set_absinfo(idev, axis_y, minimum, maximum - 1, fuzz, 0); + } + + axis = multitouch ? ABS_MT_PRESSURE : ABS_PRESSURE; + + if ((present = rt_dm_dev_prop_read_u32(dev, "touchscreen-max-pressure", &maximum))) + { + maximum = absinfo[axis].maximum; + } + + if ((present |= rt_dm_dev_prop_read_u32(dev, "touchscreen-fuzz-pressure", &fuzz))) + { + fuzz = absinfo[axis].fuzz; + } + + if (present) + { + rt_input_set_absinfo(idev, axis, 0, maximum, fuzz, 0); + } + + prop->max_x = absinfo[axis_x].maximum; + prop->max_y = absinfo[axis_y].maximum; + + prop->invert_x = rt_dm_dev_prop_read_bool(dev, "touchscreen-inverted-x"); + + if (prop->invert_x) + { + absinfo[axis_x].maximum -= absinfo[axis_x].minimum; + absinfo[axis_x].minimum = 0; + } + + prop->invert_y = rt_dm_dev_prop_read_bool(dev, "touchscreen-inverted-y"); + + if (prop->invert_y) + { + absinfo[axis_y].maximum -= absinfo[axis_y].minimum; + absinfo[axis_y].minimum = 0; + } + + prop->swap_x_y = rt_dm_dev_prop_read_bool(dev, "touchscreen-swapped-x-y"); + + if (prop->swap_x_y) + { + struct rt_input_absinfo swap_absinfo; + + rt_memcpy(&swap_absinfo, &idev->absinfo[axis_x], sizeof(swap_absinfo)); + rt_memcpy(&idev->absinfo[axis_x], &idev->absinfo[axis_y], sizeof(swap_absinfo)); + rt_memcpy(&idev->absinfo[axis_y], &swap_absinfo, sizeof(swap_absinfo)); + } +} + +rt_err_t rt_input_setup_touch(struct rt_input_device *idev, + rt_uint32_t num_slots, struct rt_touch_info *info) +{ + rt_size_t alloc_size; + rt_bool_t multitouch; + struct input_touch_device *touch_dev; + struct input_touch_properties *prop; + + if (!idev || idev->touch) + { + return -RT_EINVAL; + } + + multitouch = !!num_slots; + alloc_size = sizeof(*prop); + + if (info) + { + alloc_size += sizeof(*touch_dev); + alloc_size += sizeof(*touch_dev->points) * rt_max_t(rt_uint32_t, num_slots, 1); + } + + if (!(prop = rt_calloc(1, alloc_size))) + { + return -RT_ENOMEM; + } + idev->touch = prop; + + if ((prop->num_slots = num_slots)) + { + rt_input_set_absinfo(idev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0); + rt_input_set_absinfo(idev, ABS_MT_TRACKING_ID, 0, RT_UINT16_MAX, 0, 0); + } + + input_touch_parse(idev, multitouch, prop); + + if (info) + { + rt_size_t points_nr = rt_max_t(rt_uint32_t, num_slots, 1); + + touch_dev = (void *)prop + sizeof(*prop); + prop->touch_dev = touch_dev; + + for (int i = 0; i < points_nr; ++i) + { + touch_dev->points[i].width = 1; + } + + rt_memcpy(&touch_dev->parent.info, info, sizeof(*info)); + + info = &touch_dev->parent.info; + info->point_num = info->point_num ? : prop->num_slots; + info->range_x = info->range_x ? : prop->max_x; + info->range_y = info->range_y ? : prop->max_y; + } + + return RT_EOK; +} + +rt_err_t rt_input_parse_touch_position(struct rt_input_device *idev, + rt_uint32_t *out_x, rt_uint32_t *out_y) +{ + struct input_touch_properties *prop; + + RT_ASSERT(idev != RT_NULL); + RT_ASSERT(out_x != RT_NULL); + RT_ASSERT(out_y != RT_NULL); + + prop = idev->touch; + + if (prop->invert_x) + { + *out_x = prop->max_x - *out_x; + } + + if (prop->invert_y) + { + *out_y = prop->max_y - *out_y; + } + + if (prop->swap_x_y) + { + *out_x ^= *out_y; + *out_y ^= *out_x; + *out_x ^= *out_y; + } + + return RT_EOK; +} + +rt_bool_t rt_input_report_touch_inactive(struct rt_input_device *idev, + rt_bool_t active) +{ + struct input_touch_properties *prop; + + RT_ASSERT(idev != RT_NULL); + + prop = idev->touch; + + if (!active) + { + rt_input_event(idev, EV_ABS, ABS_MT_TRACKING_ID, -1); + + return RT_FALSE; + } + + rt_input_event(idev, EV_ABS, ABS_MT_TRACKING_ID, prop->track_id++); + + return RT_TRUE; +} + +void rt_input_report_touch_position(struct rt_input_device *idev, + rt_uint32_t x, rt_uint32_t y, rt_bool_t multitouch) +{ + RT_ASSERT(idev != RT_NULL); + + rt_input_parse_touch_position(idev, &x, &y); + rt_input_report_abs(idev, multitouch ? ABS_MT_POSITION_X : ABS_X, x); + rt_input_report_abs(idev, multitouch ? ABS_MT_POSITION_Y : ABS_Y, y); +} diff --git a/components/drivers/input/input_uapi.c b/components/drivers/input/input_uapi.c new file mode 100644 index 0000000000..c1ce87efb5 --- /dev/null +++ b/components/drivers/input/input_uapi.c @@ -0,0 +1,399 @@ +/* + * 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> + +#include <poll.h> +#include <errno.h> +#include <ktime.h> +#include <dfs_file.h> + +#define DBG_TAG "input.uapi" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> + +#define _IOC_NRBITS 8 +#define _IOC_TYPEBITS 8 +#ifndef _IOC_SIZEBITS +#define _IOC_SIZEBITS 14 +#endif +#ifndef _IOC_DIRBITS +#define _IOC_DIRBITS 2 +#endif + +#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS) - 1) + +#define _IOC_NRSHIFT 0 +#define _IOC_TYPESHIFT (_IOC_NRSHIFT + _IOC_NRBITS) +#define _IOC_SIZESHIFT (_IOC_TYPESHIFT + _IOC_TYPEBITS) +#define _IOC_DIRSHIFT (_IOC_SIZESHIFT + _IOC_SIZEBITS) + +#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & 0xFF) +#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & 0xFF) +#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & 0x3FFF) +#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & 0x3) + +#ifndef _IOC_READ +#define _IOC_READ 2U +#endif +#ifndef _IOC +#define _IOC(dir, type, nr, size) \ +( \ + ((dir) << _IOC_DIRSHIFT) | \ + ((type) << _IOC_TYPESHIFT) | \ + ((nr) << _IOC_NRSHIFT) | \ + ((size) << _IOC_SIZESHIFT) \ +) +#endif + +struct input_uapi +{ + struct dfs_file *grabbed_file; + + rt_atomic_t write_idx; + rt_atomic_t read_idx; + rt_atomic_t sync_count; + struct input_event events[RT_INPUT_UAPI_EVENT_MAX]; +}; + +static int input_uapi_fops_open(struct dfs_file *file) +{ + struct rt_input_device *idev = file->vnode->data; + + rt_device_open(&idev->parent, RT_DEVICE_OFLAG_RDWR); + + return 0; +} + +static int input_uapi_fops_close(struct dfs_file *file) +{ + struct rt_input_device *idev = file->vnode->data; + struct input_uapi *uapi = idev->uapi; + + rt_device_close(&idev->parent); + + if (uapi->grabbed_file == file) + { + rt_spin_lock(&idev->lock); + uapi->grabbed_file = RT_NULL; + rt_spin_unlock(&idev->lock); + } + + return 0; +} + +static int input_uapi_fops_ioctl(struct dfs_file *file, int cmd, void *args) +{ + unsigned int size; + struct rt_input_device *idev = file->vnode->data; + struct input_uapi *uapi = idev->uapi; + + switch (cmd) + { + case EVIOCGVERSION: + { + int version = EV_VERSION; + + rt_memcpy(args, &version, sizeof(int)); + return 0; + } + + case EVIOCGID: + { + static struct input_id virtual_id = + { + .bustype = 0x06, /* BUS_VIRTUAL */ + .vendor = 0x5354, /* "RT" */ + .product = 0x4556, /* "EV" */ + .version = RT_VER_NUM >> 16, + }; + + rt_memcpy(args, &virtual_id, sizeof(virtual_id)); + return 0; + } + + case EVIOCGRAB: + rt_spin_lock(&idev->lock); + + if (uapi->grabbed_file && uapi->grabbed_file != file) + { + rt_spin_unlock(&idev->lock); + return -EBUSY; + } + + uapi->grabbed_file = args ? file : RT_NULL; + rt_spin_unlock(&idev->lock); + + return 0; + } + + size = _IOC_SIZE(cmd); + + switch (((cmd) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT))) + { + case EVIOCGNAME(0): + rt_strncpy(args, idev->parent.parent.name, rt_min_t(unsigned int, size, RT_NAME_MAX)); + return 0; + + case EVIOCGPROP(0): + { + rt_bitmap_t *bitmap = args; + const int input_prop_direct = 0x1; + + rt_memset(bitmap, 0, size); + + if (size >= sizeof(rt_bitmap_t)) + { + bitmap[RT_BIT_WORD(input_prop_direct)] |= RT_BIT_MASK(input_prop_direct); + } + return 0; + } + } + + if (_IOC_TYPE(cmd) != 'E') + { + return -EINVAL; + } + + if (_IOC_DIR(cmd) == _IOC_READ) + { + if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) + { + rt_size_t bit_len; + rt_bitmap_t *bitmap; + + switch (_IOC_NR(cmd) & EV_MAX) + { + case 0: bitmap = idev->cap; bit_len = EV_MAX; break; + case EV_KEY: bitmap = idev->key_map; bit_len = KEY_MAX; break; + case EV_REL: bitmap = idev->rel_map; bit_len = REL_MAX; break; + case EV_ABS: bitmap = idev->abs_map; bit_len = ABS_MAX; break; + default: + return -EINVAL; + } + + size = rt_min_t(rt_size_t, size, ((bit_len + 8) / 8)); + rt_memcpy(args, bitmap, size); + + return 0; + } + + if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) + { + rt_size_t max; + + if (!idev->absinfo) + { + return -EINVAL; + } + + max = _IOC_NR(cmd) & ABS_MAX; + + rt_memcpy(args, &idev->absinfo[max], rt_min_t(rt_size_t, size, sizeof(struct input_absinfo))); + + return 0; + } + } + + return -EINVAL; +} + +static ssize_t input_uapi_fops_read(struct dfs_file *file, void *buf, size_t count, off_t *pos) +{ + int err; + size_t read = 0; + struct input_event *event = buf; + struct rt_input_device *idev = file->vnode->data; + struct input_uapi *uapi = idev->uapi; + + rt_spin_lock(&idev->lock); + + if (uapi->grabbed_file && uapi->grabbed_file != file) + { + rt_spin_unlock(&idev->lock); + return -EAGAIN; + } + + rt_spin_unlock(&idev->lock); + + if (count != 0 && count < sizeof(struct input_event)) + { + return -EINVAL; + } + + for (;;) + { + if (!rt_atomic_load(&uapi->sync_count) && (file->flags & O_NONBLOCK)) + { + #ifdef RT_UAPI_FAKE_BLOCK + static struct input_event fake_event = + { + .type = EV_SYN, + .code = SYN_REPORT, + }; + + rt_memcpy(event, &fake_event, sizeof(struct input_event)); + read += sizeof(struct input_event); + + return read; + #else + return -EAGAIN; + #endif + } + + /* No IO is done but we check for error conditions */ + if (count == 0) + { + break; + } + + while (read + sizeof(struct input_event) <= count && rt_atomic_load(&uapi->sync_count)) + { + rt_ubase_t r_idx = rt_atomic_load(&uapi->read_idx); + + rt_memcpy(event, &uapi->events[r_idx], sizeof(struct input_event)); + + rt_atomic_store(&uapi->read_idx, (r_idx + 1) % RT_ARRAY_SIZE(uapi->events)); + + if (event->type == EV_SYN && event->code == SYN_REPORT) + { + rt_atomic_sub(&uapi->sync_count, 1); + } + + ++event; + read += sizeof(struct input_event); + } + + if (read) + { + break; + } + + if (!(file->flags & O_NONBLOCK)) + { + err = rt_wqueue_wait_interruptible(&idev->parent.wait_queue, 0, RT_WAITING_FOREVER); + + if (err) + { + return err; + } + } + } + + return read; +} + +static ssize_t input_uapi_fops_write(struct dfs_file *file, const void *buf, size_t count, off_t *pos) +{ + return -ENOSYS; +} + +static int input_uapi_fops_poll(struct dfs_file *file, struct rt_pollreq *req) +{ + /* Only support POLLIN */ + int mask = 0, flags = file->flags & O_ACCMODE; + struct rt_input_device *idev = file->vnode->data; + struct input_uapi *uapi = idev->uapi; + + if (flags == O_RDONLY || flags == O_RDWR) + { + rt_poll_add(&idev->parent.wait_queue, req); + + if (rt_atomic_load(&uapi->sync_count)) + { + mask |= POLLIN; + } + } + + return mask; +} + +static const struct dfs_file_ops input_uapi_fops = +{ + .open = input_uapi_fops_open, + .close = input_uapi_fops_close, + .ioctl = input_uapi_fops_ioctl, + .read = input_uapi_fops_read, + .write = input_uapi_fops_write, + .lseek = generic_dfs_lseek, + .poll = input_uapi_fops_poll, +}; + +void input_uapi_init(struct rt_input_device *idev) +{ + struct input_uapi *uapi = rt_calloc(1, sizeof(struct input_uapi)); + + if (!uapi) + { + LOG_W("%s: No memory to create UAPI", rt_dm_dev_get_name(&idev->parent)); + return; + } + + idev->uapi = uapi; + idev->parent.fops = &input_uapi_fops; + + RT_ASSERT(sizeof(struct input_absinfo) == sizeof(struct rt_input_absinfo)); + RT_ASSERT(rt_offsetof(struct input_absinfo, value) == rt_offsetof(struct rt_input_absinfo, value)); + RT_ASSERT(rt_offsetof(struct input_absinfo, minimum) == rt_offsetof(struct rt_input_absinfo, minimum)); + RT_ASSERT(rt_offsetof(struct input_absinfo, maximum) == rt_offsetof(struct rt_input_absinfo, maximum)); + RT_ASSERT(rt_offsetof(struct input_absinfo, fuzz) == rt_offsetof(struct rt_input_absinfo, fuzz)); + RT_ASSERT(rt_offsetof(struct input_absinfo, flat) == rt_offsetof(struct rt_input_absinfo, flat)); + RT_ASSERT(rt_offsetof(struct input_absinfo, resolution) == rt_offsetof(struct rt_input_absinfo, resolution)); +} + +void input_uapi_finit(struct rt_input_device *idev) +{ + if (idev->uapi) + { + rt_free(idev->uapi); + idev->uapi = RT_NULL; + idev->parent.fops = RT_NULL; + } +} + +void input_uapi_event(struct rt_input_device *idev, struct rt_input_event *event) +{ + rt_ubase_t w_idx, next; + struct input_event *uapi_event; + struct input_uapi *uapi = idev->uapi; + + if (!idev->parent.ref_count) + { + return; + } + + w_idx = rt_atomic_load(&uapi->write_idx); + next = (w_idx + 1) % RT_ARRAY_SIZE(uapi->events); + + if (next == rt_atomic_load(&uapi->read_idx)) + { + LOG_W("%s: Event (type: %d code: %d value: %d) dropped", + rt_dm_dev_get_name(&idev->parent), + event->type, event->code, event->value); + return; + } + + uapi_event = &uapi->events[w_idx]; + + rt_ktime_boottime_get_us(&uapi_event->time); + uapi_event->type = event->type; + uapi_event->code = event->code; + uapi_event->value = event->value; + + rt_atomic_store(&uapi->write_idx, next); + + if (event->type == EV_SYN && event->code == SYN_REPORT) + { + rt_atomic_add(&uapi->sync_count, 1); + rt_wqueue_wakeup(&idev->parent.wait_queue, (void *)(rt_ubase_t)POLLIN); + } +} diff --git a/components/drivers/input/joystick/Kconfig b/components/drivers/input/joystick/Kconfig new file mode 100644 index 0000000000..d218d1d16b --- /dev/null +++ b/components/drivers/input/joystick/Kconfig @@ -0,0 +1,7 @@ +menuconfig RT_INPUT_JOYSTICK + bool "Joystick" + default n + +if RT_INPUT_JOYSTICK + osource "$(SOC_DM_INPUT_JOYSTICK_DIR)/Kconfig" +endif diff --git a/components/drivers/input/joystick/SConscript b/components/drivers/input/joystick/SConscript new file mode 100644 index 0000000000..1b68c7eb65 --- /dev/null +++ b/components/drivers/input/joystick/SConscript @@ -0,0 +1,15 @@ +from building import * + +group = [] + +if not GetDepend(['RT_INPUT_JOYSTICK']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../../include'] + +src = [] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/input/keyboard/Kconfig b/components/drivers/input/keyboard/Kconfig new file mode 100644 index 0000000000..6cce9d514b --- /dev/null +++ b/components/drivers/input/keyboard/Kconfig @@ -0,0 +1,13 @@ +menuconfig RT_INPUT_KEYBOARD + bool "Keyboards" + default n + +config RT_INPUT_KEYBOARD_GPIO + bool "GPIO" + depends on RT_INPUT_KEYBOARD + depends on RT_USING_OFW + default n + +if RT_INPUT_KEYBOARD + osource "$(SOC_DM_INPUT_KEYBOARD_DIR)/Kconfig" +endif diff --git a/components/drivers/input/keyboard/SConscript b/components/drivers/input/keyboard/SConscript new file mode 100644 index 0000000000..67c4713e79 --- /dev/null +++ b/components/drivers/input/keyboard/SConscript @@ -0,0 +1,18 @@ +from building import * + +group = [] + +if not GetDepend(['RT_INPUT_KEYBOARD']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../../include'] + +src = [] + +if GetDepend(['RT_INPUT_KEYBOARD_GPIO']): + src += ['keys-gpio.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/input/keyboard/keys-gpio.c b/components/drivers/input/keyboard/keys-gpio.c new file mode 100644 index 0000000000..5de974bf4a --- /dev/null +++ b/components/drivers/input/keyboard/keys-gpio.c @@ -0,0 +1,163 @@ +/* + * 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 <rtthread.h> +#include <rtdevice.h> + +#define DBG_TAG "input.keyboard.gpio" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> + +struct gpio_key +{ + struct rt_input_device parent; + + rt_base_t pin; + rt_uint8_t mode; + rt_uint32_t code; +}; + +static void gpio_key_event(void *data) +{ + struct gpio_key *gkey = data; + + rt_input_report_key(&gkey->parent, gkey->code, 1); + rt_input_sync(&gkey->parent); + + rt_input_report_key(&gkey->parent, gkey->code, 0); + rt_input_sync(&gkey->parent); +} + +static rt_err_t ofw_append_gpio_key(struct rt_ofw_node *np) +{ + rt_err_t err = RT_EOK; + rt_uint32_t debounce; + const char *propname; + struct gpio_key *gkey = rt_calloc(1, sizeof(*gkey)); + + if (!gkey) + { + return -RT_ENOMEM; + } + + gkey->pin = rt_ofw_get_named_pin(np, RT_NULL, 0, &gkey->mode, RT_NULL); + + if (gkey->pin < 0) + { + err = gkey->pin; + + goto _fail; + } + + if ((propname = rt_ofw_get_prop_fuzzy_name(np, ",code$")) && + !rt_ofw_prop_read_u32(np, propname, &gkey->code)) + { + rt_input_set_capability(&gkey->parent, EV_KEY, gkey->code); + + if (!(err = rt_input_device_register(&gkey->parent))) + { + err = rt_pin_attach_irq(gkey->pin, gkey->mode, gpio_key_event, gkey); + + if (err) + { + rt_input_device_unregister(&gkey->parent); + goto _fail; + } + + rt_pin_irq_enable(gkey->pin, RT_TRUE); + } + } + + if (err) + { + goto _fail; + } + + if (!rt_ofw_prop_read_u32(np, "debounce-interval", &debounce)) + { + rt_pin_debounce(gkey->pin, debounce); + } + + rt_ofw_data(np) = gkey; + + return RT_EOK; + +_fail: + rt_free(gkey); + + return err; +} + +static rt_err_t gpio_key_probe(struct rt_platform_device *pdev) +{ + rt_err_t err = RT_EOK; + struct rt_ofw_node *key_np, *np = pdev->parent.ofw_node; + + rt_ofw_foreach_available_child_node(np, key_np) + { + err = ofw_append_gpio_key(key_np); + + if (err == -RT_ENOMEM) + { + rt_ofw_node_put(key_np); + + return err; + } + else if (err) + { + LOG_E("%s: create KEY fail", rt_ofw_node_full_name(key_np)); + continue; + } + } + + return err; +} + +static rt_err_t gpio_key_remove(struct rt_platform_device *pdev) +{ + struct rt_ofw_node *key_np, *np = pdev->parent.ofw_node; + + rt_ofw_foreach_available_child_node(np, key_np) + { + struct gpio_key *gkey = rt_ofw_data(key_np); + + if (!gkey) + { + continue; + } + + rt_ofw_data(key_np) = RT_NULL; + + rt_pin_irq_enable(gkey->pin, RT_FALSE); + rt_pin_detach_irq(gkey->pin); + + rt_input_device_unregister(&gkey->parent); + + rt_free(gkey); + } + + return RT_EOK; +} + +static const struct rt_ofw_node_id gpio_key_ofw_ids[] = +{ + { .compatible = "gpio-keys" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver gpio_key_driver = +{ + .name = "gpio-keys", + .ids = gpio_key_ofw_ids, + + .probe = gpio_key_probe, + .remove = gpio_key_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(gpio_key_driver); diff --git a/components/drivers/input/misc/Kconfig b/components/drivers/input/misc/Kconfig new file mode 100644 index 0000000000..0928bc3f42 --- /dev/null +++ b/components/drivers/input/misc/Kconfig @@ -0,0 +1,12 @@ +menuconfig RT_INPUT_MISC + bool "Misc" + default n + +config RT_INPUT_MISC_BUTTON_E3X0 + bool "NI Ettus Research USRP E3xx Button support" + depends on RT_INPUT_MISC + default n + +if RT_INPUT_MISC + osource "$(SOC_DM_INPUT_MISC_DIR)/Kconfig" +endif diff --git a/components/drivers/input/misc/SConscript b/components/drivers/input/misc/SConscript new file mode 100644 index 0000000000..6b80c70aca --- /dev/null +++ b/components/drivers/input/misc/SConscript @@ -0,0 +1,18 @@ +from building import * + +group = [] + +if not GetDepend(['RT_INPUT_MISC']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../../include'] + +src = [] + +if GetDepend(['RT_INPUT_MISC_BUTTON_E3X0']): + src += ['button-e3x0.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/input/misc/button-e3x0.c b/components/drivers/input/misc/button-e3x0.c new file mode 100644 index 0000000000..2c09a54016 --- /dev/null +++ b/components/drivers/input/misc/button-e3x0.c @@ -0,0 +1,115 @@ +/* + * 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> + +struct e3x0_button +{ + struct rt_input_device parent; + + int press_irq, release_irq; +}; + +static void e3x0_button_press_isr(int irqno, void *param) +{ + struct e3x0_button *btn = param; + + rt_input_report_key(&btn->parent, KEY_POWER, 1); + rt_input_sync(&btn->parent); +} + +static void e3x0_button_release_isr(int irqno, void *param) +{ + struct e3x0_button *btn = param; + + rt_input_report_key(&btn->parent, KEY_POWER, 0); + rt_input_sync(&btn->parent); +} + +static rt_err_t e3x0_button_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct e3x0_button *btn = rt_calloc(1, sizeof(*btn)); + + if (!btn) + { + return -RT_ENOMEM; + } + + if ((btn->press_irq = rt_dm_dev_get_irq_by_name(dev, "press")) < 0) + { + err = btn->press_irq; + goto _fail; + } + + if ((btn->release_irq = rt_dm_dev_get_irq_by_name(dev, "release")) < 0) + { + err = btn->release_irq; + goto _fail; + } + + rt_input_set_capability(&btn->parent, EV_KEY, KEY_POWER); + + if ((err = rt_input_device_register(&btn->parent))) + { + goto _fail; + } + + dev->user_data = btn; + + rt_hw_interrupt_install(btn->press_irq, e3x0_button_press_isr, btn, "button-e3x0-press"); + rt_hw_interrupt_umask(btn->press_irq); + + rt_hw_interrupt_install(btn->release_irq, e3x0_button_release_isr, btn, "button-e3x0-release"); + rt_hw_interrupt_umask(btn->release_irq); + + return RT_EOK; + +_fail: + rt_free(btn); + + return err; +} + +static rt_err_t e3x0_button_remove(struct rt_platform_device *pdev) +{ + struct e3x0_button *btn = pdev->parent.user_data; + + rt_hw_interrupt_mask(btn->press_irq); + rt_pic_detach_irq(btn->press_irq, btn); + + rt_hw_interrupt_mask(btn->release_irq); + rt_pic_detach_irq(btn->release_irq, btn); + + rt_input_device_unregister(&btn->parent); + + rt_free(btn); + + return RT_EOK; +} + +static const struct rt_ofw_node_id e3x0_button_ofw_ids[] = +{ + { .compatible = "ettus,e3x0-button" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver e3x0_button_driver = +{ + .name = "e3x0-button", + .ids = e3x0_button_ofw_ids, + + .probe = e3x0_button_probe, + .remove = e3x0_button_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(e3x0_button_driver); diff --git a/components/drivers/input/touchscreen/Kconfig b/components/drivers/input/touchscreen/Kconfig new file mode 100644 index 0000000000..63ce6d9665 --- /dev/null +++ b/components/drivers/input/touchscreen/Kconfig @@ -0,0 +1,8 @@ +menuconfig RT_INPUT_TOUCHSCREEN + bool "Touchscreens" + select RT_USING_TOUCH + default n + +if RT_INPUT_TOUCHSCREEN + osource "$(SOC_DM_INPUT_TOUCHSCREEN_DIR)/Kconfig" +endif diff --git a/components/drivers/input/touchscreen/SConscript b/components/drivers/input/touchscreen/SConscript new file mode 100644 index 0000000000..1465692553 --- /dev/null +++ b/components/drivers/input/touchscreen/SConscript @@ -0,0 +1,15 @@ +from building import * + +group = [] + +if not GetDepend(['RT_INPUT_TOUCHSCREEN']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../../include'] + +src = [] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') |
