diff options
| author | Paul E. McKenney <paulmck@kernel.org> | 2026-08-14 15:43:51 -0700 |
|---|---|---|
| committer | Paul E. McKenney <paulmck@kernel.org> | 2026-08-14 15:43:51 -0700 |
| commit | 9cc63f8bcd560c760d0b12e15bba8f81c86237cf (patch) | |
| tree | 3b5269b1bcf6714171754946367c51e0590f64da /Documentation/input/uinput.rst | |
| download | linux-stable-9cc63f8bcd560c760d0b12e15bba8f81c86237cf.tar.gz linux-stable-9cc63f8bcd560c760d0b12e15bba8f81c86237cf.zip | |
Merge branches 'expcb.2026.07.24a', 'misc.2026.07.30a', 'rcu-tasks.2026.07.30a', 'srcu.2026.08.11a' and 'torture.2026.08.14a' into HEADgrafted
Changes:
Make expedited grace periods expedite normal RCU callbacks
Miscellaneous fixes:
* Improve diagnostic output with character task states.
* Mark accesses to inform KCSAN of concurrency design.
* Move from kmalloc() to kmalloc_obj().
* Documentation updates.
* Improve handling of RCU deferred quiescent states.
* Clean up unused function arguments and structure fields.
* Reduce show_rcu_gp_kthreads() stack space.
Tasks RCU updates:
* Clean up after SRCU re-implementation of Tasks Trace RCU.
* Mark accesses to inform KCSAN of concurrency design.
* Add ->lazy_timer status to diagnostic output.
* Remove an unnecessary memory barrier.
* Fix a data race, courtesy of KCSAN.
* Documentation updates.
* Convert cond_resched_tasks_rcu_qs() from macro to static inline
function.
SRCU updates:
* Add Rust helpers for SRCU.
* Avoid losing queued work at cleanup_srcu_struct() time.
Torture-test updates:
* Preparation work for immediate RCU priority deboosting.
* Test RCU readers from real interrupt handlers (as opposed to softirq).
* Simplify code through use of cpumask_next_wrap().
* Improve diagnostic output with character task states.
* Add rcutorture.nwriters parameter to allow lightweight stall testing,
and rcutorture.stall_only to make doing so easier.
* Test an RCU Tasks Trace grace period implying an RCU grace period.
* Make RCU Tasks Trace torturing track reader batches.
* Fix a data race, courtesy of KCSAN.
* Plug a shuffle_tmp_mask memory leak on kthread spawn failure.
Diffstat (limited to 'Documentation/input/uinput.rst')
| -rw-r--r-- | Documentation/input/uinput.rst | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/Documentation/input/uinput.rst b/Documentation/input/uinput.rst new file mode 100644 index 000000000..30fe80e32 --- /dev/null +++ b/Documentation/input/uinput.rst @@ -0,0 +1,245 @@ +============= +uinput module +============= + +Introduction +============ + +uinput is a kernel module that makes it possible to emulate input devices +from userspace. By writing to /dev/uinput (or /dev/input/uinput) device, a +process can create a virtual input device with specific capabilities. Once +this virtual device is created, the process can send events through it, +that will be delivered to userspace and in-kernel consumers. + +Interface +========= + +:: + + linux/uinput.h + +The uinput header defines ioctls to create, set up, and destroy virtual +devices. + +libevdev +======== + +libevdev is a wrapper library for evdev devices that provides interfaces to +create uinput devices and send events. libevdev is less error-prone than +accessing uinput directly, and should be considered for new software. + +For examples and more information about libevdev: +https://www.freedesktop.org/software/libevdev/doc/latest/ + +Examples +======== + +Keyboard events +--------------- + +This first example shows how to create a new virtual device, and how to +send a key event. All default imports and error handlers were removed for +the sake of simplicity. + +.. code-block:: c + + #include <linux/uinput.h> + + void emit(int fd, int type, int code, int val) + { + struct input_event ie; + + ie.type = type; + ie.code = code; + ie.value = val; + /* timestamp values below are ignored */ + ie.time.tv_sec = 0; + ie.time.tv_usec = 0; + + write(fd, &ie, sizeof(ie)); + } + + int main(void) + { + struct uinput_setup usetup; + + int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); + + + /* + * The ioctls below will enable the device that is about to be + * created, to pass key events, in this case the space key. + */ + ioctl(fd, UI_SET_EVBIT, EV_KEY); + ioctl(fd, UI_SET_KEYBIT, KEY_SPACE); + + memset(&usetup, 0, sizeof(usetup)); + usetup.id.bustype = BUS_USB; + usetup.id.vendor = 0x1234; /* sample vendor */ + usetup.id.product = 0x5678; /* sample product */ + strcpy(usetup.name, "Example device"); + + ioctl(fd, UI_DEV_SETUP, &usetup); + ioctl(fd, UI_DEV_CREATE); + + /* + * On UI_DEV_CREATE the kernel will create the device node for this + * device. We are inserting a pause here so that userspace has time + * to detect, initialize the new device, and can start listening to + * the event, otherwise it will not notice the event we are about + * to send. This pause is only needed in our example code! + */ + sleep(1); + + /* Key press, report the event, send key release, and report again */ + emit(fd, EV_KEY, KEY_SPACE, 1); + emit(fd, EV_SYN, SYN_REPORT, 0); + emit(fd, EV_KEY, KEY_SPACE, 0); + emit(fd, EV_SYN, SYN_REPORT, 0); + + /* + * Give userspace some time to read the events before we destroy the + * device with UI_DEV_DESTROY. + */ + sleep(1); + + ioctl(fd, UI_DEV_DESTROY); + close(fd); + + return 0; + } + +Mouse movements +--------------- + +This example shows how to create a virtual device that behaves like a physical +mouse. + +.. code-block:: c + + #include <linux/uinput.h> + + /* emit function is identical to of the first example */ + + int main(void) + { + struct uinput_setup usetup; + int i = 50; + + int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); + + /* enable mouse button left and relative events */ + ioctl(fd, UI_SET_EVBIT, EV_KEY); + ioctl(fd, UI_SET_KEYBIT, BTN_LEFT); + + ioctl(fd, UI_SET_EVBIT, EV_REL); + ioctl(fd, UI_SET_RELBIT, REL_X); + ioctl(fd, UI_SET_RELBIT, REL_Y); + + memset(&usetup, 0, sizeof(usetup)); + usetup.id.bustype = BUS_USB; + usetup.id.vendor = 0x1234; /* sample vendor */ + usetup.id.product = 0x5678; /* sample product */ + strcpy(usetup.name, "Example device"); + + ioctl(fd, UI_DEV_SETUP, &usetup); + ioctl(fd, UI_DEV_CREATE); + + /* + * On UI_DEV_CREATE the kernel will create the device node for this + * device. We are inserting a pause here so that userspace has time + * to detect, initialize the new device, and can start listening to + * the event, otherwise it will not notice the event we are about + * to send. This pause is only needed in our example code! + */ + sleep(1); + + /* Move the mouse diagonally, 5 units per axis */ + while (i--) { + emit(fd, EV_REL, REL_X, 5); + emit(fd, EV_REL, REL_Y, 5); + emit(fd, EV_SYN, SYN_REPORT, 0); + usleep(15000); + } + + /* + * Give userspace some time to read the events before we destroy the + * device with UI_DEV_DESTROY. + */ + sleep(1); + + ioctl(fd, UI_DEV_DESTROY); + close(fd); + + return 0; + } + + +uinput old interface +-------------------- + +Before uinput version 5, there wasn't a dedicated ioctl to set up a virtual +device. Programs supporting older versions of uinput interface need to fill +a uinput_user_dev structure and write it to the uinput file descriptor to +configure the new uinput device. New code should not use the old interface +but interact with uinput via ioctl calls, or use libevdev. + +.. code-block:: c + + #include <linux/uinput.h> + + /* emit function is identical to of the first example */ + + int main(void) + { + struct uinput_user_dev uud; + int version, rc, fd; + + fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); + rc = ioctl(fd, UI_GET_VERSION, &version); + + if (rc == 0 && version >= 5) { + /* use UI_DEV_SETUP */ + return 0; + } + + /* + * The ioctls below will enable the device that is about to be + * created, to pass key events, in this case the space key. + */ + ioctl(fd, UI_SET_EVBIT, EV_KEY); + ioctl(fd, UI_SET_KEYBIT, KEY_SPACE); + + memset(&uud, 0, sizeof(uud)); + snprintf(uud.name, UINPUT_MAX_NAME_SIZE, "uinput old interface"); + write(fd, &uud, sizeof(uud)); + + ioctl(fd, UI_DEV_CREATE); + + /* + * On UI_DEV_CREATE the kernel will create the device node for this + * device. We are inserting a pause here so that userspace has time + * to detect, initialize the new device, and can start listening to + * the event, otherwise it will not notice the event we are about + * to send. This pause is only needed in our example code! + */ + sleep(1); + + /* Key press, report the event, send key release, and report again */ + emit(fd, EV_KEY, KEY_SPACE, 1); + emit(fd, EV_SYN, SYN_REPORT, 0); + emit(fd, EV_KEY, KEY_SPACE, 0); + emit(fd, EV_SYN, SYN_REPORT, 0); + + /* + * Give userspace some time to read the events before we destroy the + * device with UI_DEV_DESTROY. + */ + sleep(1); + + ioctl(fd, UI_DEV_DESTROY); + + close(fd); + return 0; + } + |
