[dm][input] support input #11031

This commit is contained in:
GUI
2025-12-10 16:58:10 +08:00
committed by GitHub
parent 357c9b7b5a
commit 3ff3fc3948
19 changed files with 2207 additions and 0 deletions

View File

@@ -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"

View File

@@ -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__ */

View File

@@ -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"

View File

@@ -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

View File

@@ -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')

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1,7 @@
menuconfig RT_INPUT_JOYSTICK
bool "Joystick"
default n
if RT_INPUT_JOYSTICK
osource "$(SOC_DM_INPUT_JOYSTICK_DIR)/Kconfig"
endif

View File

@@ -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')

View File

@@ -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

View File

@@ -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')

View File

@@ -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);

View File

@@ -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

View File

@@ -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')

View File

@@ -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);

View File

@@ -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

View File

@@ -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')