summaryrefslogtreecommitdiff
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
parent357c9b7b5a61ce2062cbfcb37d9dba8d17ff3d6d (diff)
[dm][input] support input #11031
-rwxr-xr-xcomponents/drivers/Kconfig1
-rw-r--r--components/drivers/include/dt-bindings/input/event-codes.h360
-rw-r--r--components/drivers/include/rtdevice.h7
-rw-r--r--components/drivers/input/Kconfig36
-rw-r--r--components/drivers/input/SConscript32
-rw-r--r--components/drivers/input/input.c405
-rw-r--r--components/drivers/input/input_power.c130
-rw-r--r--components/drivers/input/input_touch.c453
-rw-r--r--components/drivers/input/input_uapi.c399
-rw-r--r--components/drivers/input/joystick/Kconfig7
-rw-r--r--components/drivers/input/joystick/SConscript15
-rw-r--r--components/drivers/input/keyboard/Kconfig13
-rw-r--r--components/drivers/input/keyboard/SConscript18
-rw-r--r--components/drivers/input/keyboard/keys-gpio.c163
-rw-r--r--components/drivers/input/misc/Kconfig12
-rw-r--r--components/drivers/input/misc/SConscript18
-rw-r--r--components/drivers/input/misc/button-e3x0.c115
-rw-r--r--components/drivers/input/touchscreen/Kconfig8
-rw-r--r--components/drivers/input/touchscreen/SConscript15
19 files changed, 2207 insertions, 0 deletions
diff --git a/components/drivers/Kconfig b/components/drivers/Kconfig
index 3ffa4c3f83..d45f2166bf 100755
--- a/components/drivers/Kconfig
+++ b/components/drivers/Kconfig
@@ -22,6 +22,7 @@ rsource "graphic/Kconfig"
rsource "hwcrypto/Kconfig"
rsource "wlan/Kconfig"
rsource "led/Kconfig"
+rsource "input/Kconfig"
rsource "mailbox/Kconfig"
rsource "phye/Kconfig"
rsource "ata/Kconfig"
diff --git a/components/drivers/include/dt-bindings/input/event-codes.h b/components/drivers/include/dt-bindings/input/event-codes.h
new file mode 100644
index 0000000000..e05b911c45
--- /dev/null
+++ b/components/drivers/include/dt-bindings/input/event-codes.h
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef __DT_BINDINGS_INPUT_EVENT_CODES_H__
+#define __DT_BINDINGS_INPUT_EVENT_CODES_H__
+
+/*
+ * Event types
+ */
+
+#define EV_SYN 0
+#define EV_KEY 1
+#define EV_REL 2
+#define EV_ABS 3
+#define EV_MSC 4
+#define EV_SW 5
+#define EV_LED 17
+#define EV_SND 18
+#define EV_REP 20
+#define EV_FF 21
+#define EV_PWR 22
+#define EV_FF_STATUS 23
+#define EV_MAX 31
+#define EV_CNT (EV_MAX + 1)
+
+/*
+ * Synchronization events.
+ */
+
+#define SYN_REPORT 0
+#define SYN_CONFIG 1
+#define SYN_MT_REPORT 2
+#define SYN_DROPPED 3
+#define SYN_MAX 15
+#define SYN_CNT (SYN_MAX + 1)
+
+/*
+ * Keys and buttons
+ */
+
+#define KEY_RESERVED 0 /* Reserved, do not use */
+#define KEY_ESC 1 /* Escape Key */
+#define KEY_1 2 /* 1 Key */
+#define KEY_2 3 /* 2 Key */
+#define KEY_3 4 /* 3 Key */
+#define KEY_4 5 /* 4 Key */
+#define KEY_5 6 /* 5 Key */
+#define KEY_6 7 /* 6 Key */
+#define KEY_7 8 /* 7 Key */
+#define KEY_8 9 /* 8 Key */
+#define KEY_9 10 /* 9 Key */
+#define KEY_0 11 /* 0 Key */
+#define KEY_MINUS 12 /* Minus Key */
+#define KEY_EQUAL 13 /* Equal Key */
+#define KEY_BACKSPACE 14 /* Backspace Key */
+#define KEY_TAB 15 /* Tab Key*/
+#define KEY_Q 16 /* Q Key */
+#define KEY_W 17 /* W Key */
+#define KEY_E 18 /* E Key */
+#define KEY_R 19 /* R Key */
+#define KEY_T 20 /* T Key */
+#define KEY_Y 21 /* Y Key */
+#define KEY_U 22 /* U Key */
+#define KEY_I 23 /* I Key */
+#define KEY_O 24 /* O Key */
+#define KEY_P 25 /* P Key */
+#define KEY_LEFTBRACE 26 /* Left Brace Key */
+#define KEY_RIGHTBRACE 27 /* Right Brace Key */
+#define KEY_ENTER 28 /* Enter Key */
+#define KEY_LEFTCTRL 29 /* Left Ctrl Key */
+#define KEY_A 30 /* A Key */
+#define KEY_S 31 /* S Key */
+#define KEY_D 32 /* D Key */
+#define KEY_F 33 /* F Key */
+#define KEY_G 34 /* G Key */
+#define KEY_H 35 /* H Key */
+#define KEY_J 36 /* J Key */
+#define KEY_K 37 /* K Key */
+#define KEY_L 38 /* L Key */
+#define KEY_SEMICOLON 39 /* Semicolon Key */
+#define KEY_APOSTROPHE 40 /* Apostrophe Key */
+#define KEY_GRAVE 41 /* Grave (backtick) Key */
+#define KEY_LEFTSHIFT 42 /* Left Shift Key */
+#define KEY_BACKSLASH 43 /* Backslash Key */
+#define KEY_Z 44 /* Z Key */
+#define KEY_X 45 /* X Key */
+#define KEY_C 46 /* C Key */
+#define KEY_V 47 /* V Key */
+#define KEY_B 48 /* B Key */
+#define KEY_N 49 /* N Key */
+#define KEY_M 50 /* M Key */
+#define KEY_COMMA 51 /* Comma Key */
+#define KEY_DOT 52 /* Dot Key */
+#define KEY_SLASH 53 /* Slash Key */
+#define KEY_RIGHTSHIFT 54 /* Right Shift Key */
+#define KEY_KPASTERISK 55 /* Keypad Asterisk Key */
+#define KEY_LEFTALT 56 /* Left Alt Key */
+#define KEY_SPACE 57 /* Space Key */
+#define KEY_CAPSLOCK 58 /* Caps Lock Key */
+#define KEY_F1 59 /* F1 Key */
+#define KEY_F2 60 /* F2 Key */
+#define KEY_F3 61 /* F3 Key */
+#define KEY_F4 62 /* F4 Key */
+#define KEY_F5 63 /* F5 Key */
+#define KEY_F6 64 /* F6 Key */
+#define KEY_F7 65 /* F7 Key */
+#define KEY_F8 66 /* F8 Key */
+#define KEY_F9 67 /* F9 Key */
+#define KEY_F10 68 /* F10 Key */
+#define KEY_NUMLOCK 69 /* Num Lock Key */
+#define KEY_SCROLLLOCK 70 /* Scroll Lock Key */
+#define KEY_KP7 71 /* Keypad 7 Key */
+#define KEY_KP8 72 /* Keypad 8 Key */
+#define KEY_KP9 73 /* Keypad 9 Key */
+#define KEY_KPMINUS 74 /* Keypad Minus Key */
+#define KEY_KP4 75 /* Keypad 4 Key */
+#define KEY_KP5 76 /* Keypad 5 Key */
+#define KEY_KP6 77 /* Keypad 6 Key */
+#define KEY_KPPLUS 78 /* Keypad Plus Key */
+#define KEY_KP1 79 /* Keypad 1 Key */
+#define KEY_KP2 80 /* Keypad 2 Key */
+#define KEY_KP3 81 /* Keypad 3 Key */
+#define KEY_KP0 82 /* Keypad 0 Key */
+#define KEY_KPDOT 83 /* Keypad Dot Key */
+#define KEY_F11 87 /* F11 Key */
+#define KEY_F12 88 /* F12 Key */
+#define KEY_KPENTER 96 /* Keypad Enter Key */
+#define KEY_RIGHTCTRL 97 /* Right Ctrl Key */
+#define KEY_KPSLASH 98 /* Keypad Slash Key */
+#define KEY_SYSRQ 99 /* SysReq Key */
+#define KEY_RIGHTALT 100 /* Right Alt Key */
+#define KEY_HOME 102 /* Home Key */
+#define KEY_UP 103 /* Up Key */
+#define KEY_PAGEUP 104 /* Page UpKey */
+#define KEY_LEFT 105 /* Left Key */
+#define KEY_RIGHT 106 /* Right Key */
+#define KEY_END 107 /* End Key */
+#define KEY_DOWN 108 /* Down Key */
+#define KEY_PAGEDOWN 109 /* Page Down Key */
+#define KEY_INSERT 110 /* Insert Key */
+#define KEY_DELETE 111 /* Delete Key */
+#define KEY_MUTE 113 /* Mute Key */
+#define KEY_VOLUMEDOWN 114 /* Volume Down Key */
+#define KEY_VOLUMEUP 115 /* Volume Up Key */
+#define KEY_POWER 116 /* Power Key */
+#define KEY_KPEQUAL 117 /* Keypad Equal Key */
+#define KEY_KPPLUSMINUS 118 /* Keypad Plus Key */
+#define KEY_PAUSE 119 /* Pause Key */
+#define KEY_SCALE 120 /* Scale Key */
+#define KEY_KPCOMMA 121 /* Keypad Comma Key */
+#define KEY_LEFTMETA 125 /* Left Meta Key */
+#define KEY_RIGHTMETA 126 /* Right Meta Key */
+#define KEY_COMPOSE 127 /* Compose Key */
+#define KEY_STOP 128 /* AC Stop */
+#define KEY_MENU 139 /* Menu Key */
+#define KEY_SETUP 141
+#define KEY_SLEEP 142 /* System Sleep Key */
+#define KEY_WAKEUP 143 /* System Wake Up Key */
+#define KEY_COFFEE 152 /* Screen Saver Key */
+#define KEY_BACK 158 /* Back Key */
+#define KEY_FORWARD 159 /* Forward Key */
+#define KEY_PLAYPAUSE 164
+#define KEY_RECORD 167
+#define KEY_REWIND 168
+#define KEY_EXIT 174 /* AC Exit */
+#define KEY_F13 183 /* F13 Key */
+#define KEY_F14 184 /* F14 Key */
+#define KEY_F15 185 /* F15 Key */
+#define KEY_F16 186 /* F16 Key */
+#define KEY_F17 187 /* F17 Key */
+#define KEY_F18 188 /* F18 Key */
+#define KEY_F19 189 /* F19 Key */
+#define KEY_F20 190 /* F20 Key */
+#define KEY_F21 191 /* F21 Key */
+#define KEY_F22 192 /* F22 Key */
+#define KEY_F23 193 /* F23 Key */
+#define KEY_F24 194 /* F24 Key */
+#define KEY_PLAY 207 /* Play Key */
+#define KEY_FASTFORWARD 208 /* Fast Forward Key */
+#define KEY_PRINT 210 /* Print Key */
+#define KEY_CONNECT 218 /* Connect Key */
+#define KEY_CANCEL 223 /* AC Cancel */
+#define KEY_BRIGHTNESSDOWN 224 /* Brightness Down Key */
+#define KEY_BRIGHTNESSUP 225 /* Brightneess Up Key */
+#define KEY_MEDIA 226 /* Media toggle */
+#define KEY_BLUETOOTH 237 /* Bluetooth Key */
+#define KEY_WLAN 238 /* Wireless LAN Key */
+#define KEY_UWB 239 /* Ultra-Wideband Key */
+#define KEY_SELECT 353
+#define KEY_CLEAR 355
+#define KEY_INFO 358 /* AL OEM Features/Tips/Tutorial */
+#define KEY_PROGRAM 362 /* Media Select Program Guide */
+#define KEY_CALENDAR 397
+#define KEY_RED 398
+#define KEY_GREEN 399
+#define KEY_YELLOW 400
+#define KEY_BLUE 401
+#define KEY_CHANNELUP 402 /* Channel Increment */
+#define KEY_CHANNELDOWN 403 /* Channel Decrement */
+#define KEY_RESTART 408 /* Restart Key */
+
+#define BTN_MISC 256
+#define BTN_0 256
+#define BTN_1 257
+#define BTN_2 258
+#define BTN_3 259
+#define BTN_4 260
+#define BTN_5 261
+#define BTN_6 262
+#define BTN_7 263
+#define BTN_8 264
+#define BTN_9 265
+
+#define BTN_MOUSE 272
+#define BTN_LEFT 272
+#define BTN_RIGHT 273
+#define BTN_MIDDLE 274
+#define BTN_SIDE 275
+#define BTN_EXTRA 276
+#define BTN_FORWARD 277
+#define BTN_BACK 278
+#define BTN_TASK 279
+
+#define BTN_JOYSTICK 288
+#define BTN_TRIGGER 288
+#define BTN_THUMB 289
+#define BTN_THUMB2 290
+#define BTN_TOP 291
+#define BTN_TOP2 292
+#define BTN_PINKIE 293
+#define BTN_BASE 294
+#define BTN_BASE2 295
+#define BTN_BASE3 296
+#define BTN_BASE4 297
+#define BTN_BASE5 298
+#define BTN_BASE6 299
+#define BTN_DEAD 303
+
+#define BTN_GAMEPAD 304
+#define BTN_SOUTH 304
+#define BTN_A BTN_SOUTH
+#define BTN_EAST 305
+#define BTN_B BTN_EAST
+#define BTN_C 306
+#define BTN_NORTH 307
+#define BTN_X BTN_NORTH
+#define BTN_WEST 308
+#define BTN_Y BTN_WEST
+#define BTN_Z 309
+#define BTN_TL 310
+#define BTN_TR 311
+#define BTN_TL2 312
+#define BTN_TR2 313
+#define BTN_SELECT 314
+#define BTN_START 315
+#define BTN_MODE 316
+#define BTN_THUMBL 317
+#define BTN_THUMBR 318
+
+#define BTN_DIGI 320
+#define BTN_TOOL_PEN 320
+#define BTN_TOOL_RUBBER 321
+#define BTN_TOOL_BRUSH 322
+#define BTN_TOOL_PENCIL 323
+#define BTN_TOOL_AIRBRUSH 324
+#define BTN_TOOL_FINGER 325
+#define BTN_TOOL_MOUSE 326
+#define BTN_TOOL_LENS 327
+#define BTN_TOOL_QUINTTAP 328 /* Five fingers on trackpad */
+#define BTN_STYLUS3 329
+#define BTN_TOUCH 330
+#define BTN_STYLUS 331
+#define BTN_STYLUS2 332
+#define BTN_TOOL_DOUBLETAP 333
+#define BTN_TOOL_TRIPLETAP 334
+#define BTN_TOOL_QUADTAP 335 /* Four fingers on trackpad */
+
+#define KEY_MAX 767
+#define KEY_CNT (KEY_MAX + 1)
+
+#define BTN_TOUCH 330
+
+/*
+ * Relative axes
+ */
+
+#define REL_X 0
+#define REL_Y 1
+#define REL_Z 2
+#define REL_RX 3
+#define REL_RY 4
+#define REL_RZ 5
+#define REL_HWHEEL 6
+#define REL_DIAL 7
+#define REL_WHEEL 8
+#define REL_MISC 9
+#define REL_RESERVED 10
+#define REL_WHEEL_HI_RES 11
+#define REL_HWHEEL_HI_RES 12
+#define REL_MAX 15
+#define REL_CNT (REL_MAX + 1)
+
+/*
+ * Absolute axes
+ */
+
+#define ABS_X 0
+#define ABS_Y 1
+#define ABS_Z 2
+#define ABS_RX 3
+#define ABS_RY 4
+#define ABS_RZ 5
+#define ABS_THROTTLE 6
+#define ABS_RUDDER 7
+#define ABS_WHEEL 8
+#define ABS_GAS 9
+#define ABS_BRAKE 10
+#define ABS_HAT0X 16
+#define ABS_HAT0Y 17
+#define ABS_HAT1X 18
+#define ABS_HAT1Y 19
+#define ABS_HAT2X 20
+#define ABS_HAT2Y 21
+#define ABS_HAT3X 22
+#define ABS_HAT3Y 23
+#define ABS_PRESSURE 24
+#define ABS_DISTANCE 25
+#define ABS_TILT_X 26
+#define ABS_TILT_Y 27
+#define ABS_TOOL_WIDTH 28
+
+#define ABS_VOLUME 32
+#define ABS_PROFILE 33
+
+#define ABS_MISC 40
+#define ABS_RESERVED 46
+
+#define ABS_MT_SLOT 47 /* MT slot being modified */
+#define ABS_MT_TOUCH_MAJOR 48 /* Major axis of touching ellipse */
+#define ABS_MT_TOUCH_MINOR 49 /* Minor axis (omit if circular) */
+#define ABS_MT_WIDTH_MAJOR 50 /* Major axis of approaching ellipse */
+#define ABS_MT_WIDTH_MINOR 51 /* Minor axis (omit if circular) */
+#define ABS_MT_ORIENTATION 52 /* Ellipse orientation */
+#define ABS_MT_POSITION_X 53 /* Center X touch position */
+#define ABS_MT_POSITION_Y 54 /* Center Y touch position */
+#define ABS_MT_TOOL_TYPE 55 /* Type of touching device */
+#define ABS_MT_BLOB_ID 56 /* Group a set of packets as a blob */
+#define ABS_MT_TRACKING_ID 57 /* Unique ID of initiated contact */
+#define ABS_MT_PRESSURE 58 /* Pressure on contact area */
+#define ABS_MT_DISTANCE 59 /* Contact hover distance */
+#define ABS_MT_TOOL_X 60 /* Center X tool position */
+#define ABS_MT_TOOL_Y 61 /* Center Y tool position */
+
+#define ABS_MAX 63
+#define ABS_CNT (ABS_MAX + 1)
+
+#endif /* __DT_BINDINGS_INPUT_EVENT_CODES_H__ */
diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h
index fbed6c829d..9f427c49c4 100644
--- a/components/drivers/include/rtdevice.h
+++ b/components/drivers/include/rtdevice.h
@@ -53,7 +53,14 @@ extern "C" {
#ifdef RT_USING_LED
#include "drivers/led.h"
+#endif /* RT_USING_LED */
+
+#ifdef RT_USING_INPUT
+#include "drivers/input.h"
+#ifdef RT_INPUT_UAPI
+#include "drivers/input_uapi.h"
#endif
+#endif /* RT_USING_INPUT */
#ifdef RT_USING_MBOX
#include "drivers/mailbox.h"
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 = &cap;
+ 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 = &cap;
+
+ 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')