RT-Thread RTOS
An open source embedded real-time operating system
Input userspace API (UAPI)

Input event UAPI (<tt>RT_INPUT_UAPI</tt>)

**input_uapi.c** exposes each **rt_input_device** as a Linux-compatible character device for POSIX userspace (Smart / LWP + DFS). IOCTLs and **struct input_event** are defined in **drivers/input_uapi.h** (aligned with **include/uapi/linux/input.h**).

DM overview and driver binding: Input device model (DM). In-kernel reporters and handlers: Input subsystem.

Sources: **components/drivers/input/input_uapi.c**, **components/drivers/include/drivers/input_uapi.h**.


Kconfig

Option Default Role
**RT_INPUT_UAPI** y if **RT_USING_SMART**, else n Build **input_uapi.c**, attach **dfs_file_ops** in **input_uapi_init**
**RT_INPUT_UAPI_EVENT_MAX** 128 Ring buffer slots (**struct input_event** per device)
**RT_UAPI_FAKE_BLOCK** y **O_NONBLOCK** empty **read** returns synthetic **SYN_REPORT** instead of **-EAGAIN**

Dependencies: **RT_USING_INPUT**, **RT_USING_KTIME**, **RT_USING_POSIX_DEVIO**.


Architecture

rt_input_report_* → rt_input_sync
→ rt_input_event (input.c)
→ input_uapi_event (if ref_count > 0)
ring buffer + ktime timestamp
SYN_REPORT → sync_count++, wake wait_queue
→ read() / poll(POLLIN) on /dev/inputN
Hook When
**input_uapi_init** **rt_input_device_register** — allocates **struct input_uapi**, sets **idev->parent.fops**
**input_uapi_event** Every **rt_input_event** while UAPI enabled
**input_uapi_finit** **rt_input_device_unregister** — free UAPI state

Registered device names are **input0**, **input1**, … (**rt_dm_ida** in **input.c**). Open via devfs:

int fd = open("/dev/input0", O_RDONLY);
int open(const char *file, int flags,...)
Definition: dfs_posix.c:48

**input_uapi_event** returns without queuing when **idev->parent.ref_count == 0** — userspace must **open** the node before events appear.


Event format

Kernel handler path UAPI queue
Struct **struct rt_input_event** (drivers/input.h) **struct input_event** (input_uapi.h)
Time **rt_tick_t tick** **struct timeval** from **rt_ktime_boottime_get_us**
Codes **dt-bindings/input/event-codes.h** Same

**struct input_absinfo** returned by **EVIOCGABS** matches **struct rt_input_absinfo** (**RT_ASSERT** on layout in **input_uapi_init**).


Ring buffer and framing

**struct input_uapi** holds:

  • Atomic **read_idx**, **write_idx**, **sync_count**
  • **events[RT_INPUT_UAPI_EVENT_MAX]**
  • Optional **grabbed_file** for **EVIOCGRAB**

On each kernel event copy, **write_idx** advances. When **type == EV_SYN** and **code == SYN_REPORT**, **sync_count** increments and **rt_wqueue_wakeup** runs.

**read** drains events until the user buffer is full or a **SYN_REPORT** completes one frame; each consumed frame decrements **sync_count**.

Overflow: if the next write would overwrite unread data, the event is dropped (warning log). Raise **RT_INPUT_UAPI_EVENT_MAX** for high-rate touch streams.


<tt>read()</tt> / <tt>poll()</tt> / <tt>write()</tt>

Behavior Detail
Min size **count != 0** and **count < sizeof(struct input_event)** → **-EINVAL**
**count == 0** Allowed (availability check after wait)
Blocking Waits on **idev->parent.wait_queue** until **sync_count > 0**
**O_NONBLOCK** Empty queue → **-EAGAIN**, or fake **SYN_REPORT** if **RT_UAPI_FAKE_BLOCK**
**poll** **POLLIN** when **sync_count > 0** (**O_RDONLY** / **O_RDWR** only)
**write** **-ENOSYS**

Grab: if another **dfs_file** holds **EVIOCGRAB**, **read** returns **-EAGAIN**.


<tt>ioctl()</tt> (implemented)

IOCTL Purpose
**EVIOCGVERSION** **EV_VERSION** (0x010001)
**EVIOCGID** Virtual ID: bustype **0x06**, vendor **0x5354**, product **0x4556**, version **RT_VER_NUM >> 16**
**EVIOCGNAME(len)** Device name (**inputN**)
**EVIOCGPROP(len)** Property bitmap (direct-touch bit when buffer large enough)
**EVIOCGBIT(ev, len)** Type bitmap (**ev==0**) or **EV_KEY/EV_REL/EV_ABS** maps
**EVIOCGABS(abs)** Axis **struct input_absinfo**
**EVIOCGRAB** Exclusive grab; non-zero **args** grabs; second grabber **-EBUSY**

**EVIOCSABS**, force-feedback, and other Linux input IOCTLs → **-EINVAL**.


Userspace example

#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
#include <drivers/input_uapi.h>
void listen_input0(void)
{
struct input_event ev[64];
struct pollfd pfd = { .fd = open("/dev/input0", O_RDONLY), .events = POLLIN };
for (;;)
{
if (poll(&pfd, 1, -1) <= 0)
continue;
ssize_t n = read(pfd.fd, ev, sizeof(ev));
if (n <= 0)
continue;
for (int i = 0; i < n / (int)sizeof(struct input_event); ++i)
{
/* ev[i].type, ev[i].code, ev[i].value */
}
}
}
ssize_t read(int fd, void *buf, size_t len)
Definition: dfs_posix.c:325

Use **rt_input_add_handler** in kernel; use UAPI when a POSIX process (e.g. **evtest**) reads the same event stream.


Pitfalls

Issue Mitigation
No events before open **ref_count** gate in **input_uapi_event**
Unregister with open fd **rt_input_device_unregister** checks **ref_count** — close fds first
Grab conflicts Release with **EVIOCGRAB** and zero argument
Touch bursts Increase **RT_INPUT_UAPI_EVENT_MAX** or read faster
**RT_UAPI_FAKE_BLOCK** Disable for strict **-EAGAIN** on empty non-blocking reads

See also