diff options
| author | Paulo Alcantara <pc@manguebit.org> | 2026-09-26 19:20:30 -0300 |
|---|---|---|
| committer | Paulo Alcantara <pc@manguebit.org> | 2026-09-30 14:24:12 -0300 |
| commit | dd05add7b2b6004c5fa3a1f276f56d8668f86b65 (patch) | |
| tree | 23efdcaa0b8031f6ac6f57b6734d18d6c1adc6f2 /Documentation/input/uinput.rst | |
| download | linux-stable-dd05add7b2b6004c5fa3a1f276f56d8668f86b65.tar.gz linux-stable-dd05add7b2b6004c5fa3a1f276f56d8668f86b65.zip | |
netfs: zero the tail of a short DIO/unbuffered readgrafted
The buffered read collector zero-fills the tail of a short read that
stops below the inode's i_size (netfs_clear_unread()), so a read that
races an extending write still returns the expected number of bytes.
The non-buffered collector path does no such thing: it just records
how much was transferred.
Add the same zero-fill for the non-buffered case, gated on
NETFS_SREQ_CLEAR_TAIL: a subreq's source sets that flag when a short
result from it is known to be safe to treat as a hole, as opposed to
NETFS_SREQ_HIT_EOF, which means the read genuinely ran off the end of
the file and should be reported short as-is. Only CLEAR_TAIL should
zero-fill here; a real EOF must stay a real short read.
No source currently sets CLEAR_TAIL on an unbuffered/DIO subrequest,
so this is inert on its own -- a following change teaches cifs to set
it in the one case that needs it.
Fixes: e2d46f2ec332 ("netfs: Change the read result collector to only use one work item")
Reviewed-by: David Howells <dhowells@redhat.com>
Reviewed-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
Cc: Christian Brauner <brauner@kernel.org>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Ronnie Sahlberg <ronniesahlberg@gmail.com>
Cc: Shyam Prasad N <sprasad@microsoft.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: Bharath SM <bharathsm@microsoft.com>
Cc: stable@vger.kernel.org
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; + } + |
