diff --git a/components/drivers/Kconfig b/components/drivers/Kconfig index 3ffa4c3f83b..d45f2166bfb 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 00000000000..e05b911c45c --- /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 7007441c6bc..280e74c2f39 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 00000000000..707a7500d9c --- /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 00000000000..a1a02c70245 --- /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 00000000000..deec1fb5944 --- /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 +#include +#include + +#define DBG_TAG "rtdm.input" +#define DBG_LVL DBG_INFO +#include + +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 00000000000..11bf7b86aa1 --- /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 +#include +#include + +#define DBG_TAG "input.power" +#define DBG_LVL DBG_INFO +#include + +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 00000000000..c5537b0122b --- /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 +#include +#include + +#define DBG_TAG "input.touch" +#define DBG_LVL DBG_INFO +#include + +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 00000000000..c1ce87efb57 --- /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 +#include +#include + +#include +#include +#include +#include + +#define DBG_TAG "input.uapi" +#define DBG_LVL DBG_INFO +#include + +#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 00000000000..d218d1d16bb --- /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 00000000000..1b68c7eb656 --- /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 00000000000..6cce9d514b5 --- /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 00000000000..67c4713e795 --- /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 00000000000..5de974bf4a3 --- /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 +#include + +#define DBG_TAG "input.keyboard.gpio" +#define DBG_LVL DBG_INFO +#include + +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 00000000000..0928bc3f420 --- /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 00000000000..6b80c70aca1 --- /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 00000000000..2c09a540168 --- /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 +#include +#include + +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 00000000000..63ce6d96657 --- /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 00000000000..1465692553a --- /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')