rt-thread/documentation/6.components/device-driver/input/uapi.md

5.9 KiB
Executable File

@page page_device_input_uapi Input userspace API (UAPI)

Input event UAPI (RT_INPUT_UAPI)

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: @ref page_device_input_dm. In-kernel reporters and handlers: @ref page_device_input.

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

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.


read() / poll() / write()

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.


ioctl() (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 */
        }
    }
}

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

  • @ref page_device_input_dm
  • @ref page_device_input
  • components/drivers/include/drivers/input_uapi.h
  • components/drivers/input/Kconfig