Wednesday, September 18, 2013

What is uinput?

uinput is the kernel interface to create evdev devices that, for most purposes, look the same as real devices. This goes so far that around 80% (well, I'm guessing. actually, make this 83.45%) of all testing I do now is with emulated devices only. There are a few bits that can't be emulated, a few things that are different, but generally I found uinput devices to be close enough to the real thing. As the evdev interface, the uinput interface requires you to handle a few structs and ioctls, not necessarily in an obvious way. libevdev wraps that for you.

Creating a device

The simplest way to create a uinput device is to duplicate an existing device.

The above code will create a device from a fd, duplicate that device as a uinput device and then post a x/y relative event through that uinput device. Because we opened the uinput device as LIBEVDEV_UINPUT_OPEN_MANAGED, libevdev will handle access to the /dev/uinput node.

Duplicating devices is useful, but a more likely use-case is to create a device from scratch:

This time we created a blank device, set a few bits and created a uinput device from that. The result should be a device that looks like a normal three-button mouse to most of the stack.

As you can see, because this time we opened /dev/uinput ourselves, we need to close it ourselves too. libevdev won't touch the fd unless it's in LIBEVDEV_UINPUT_OPEN_MANAGED mode. Note that you can only ever have one active uinput device per fd, and closing the fd will destroy the uinput device (but won't free the memory, you'll still have to call libevdev_uinput_destroy).

Accessing uinput devices

We just created a uinput device, but how do we actually use it? Well, as shown above events are just written to the device directly. But sometimes we have to create a device and re-open it through libevdev.

Voila. That's all there is to it to complete the circle. You can now use that device to create a uinput device again, and so on, and so forth.

A word of warning: the kernel does not (yet) provide an ioctl to get the device number from a newly created uinput device. libevdev has to guess what the device is going to be. In some cases, this guess may come up with the wrong device. This can happen if you create multiple uinput devices with the same name at the same time. So, don't do that. Either change the name, or delay creation so that the timestamp (one-second resolution!) differs for each device.

Changing a device

So you have a device but for some reason it doesn't exactly reflect what you actually need. This can happen for broken devices that export random axes, or it can happen if the software stack needs certain bits that the device doesn't actually provide. The code below is C-style pseudocode, don't expect to be able to directly take and compile it.

Simple enough - we've disabled ABS_RX, so we'll never get an event from this instance. Note that this is a local change only, so anyone else reading the device will still receive ABS_RX events. Likewise, we enabled ABS_PRESSURE so that future calls to libevdev_has_event_code will return true, including the axis range we've provided. This too is a local change only and won't affect anyone else. For obvious reasons, enabling a bit on the device doesn't actually make the device generate events of that type. Otherwise, the HW industry would be out of business quickly.

For local changes, libevdev provides setters for almost every field. I won't go into more details here, the API should be obvious enough so that e.g. changing the device name is straightforward.

Modifying the kernel device

A few calls can actually modify the kernel device, so that other readers of the device will see modified data.

This call would actually change the axis ranges on the device. A future reader of the device would thus see the new range. Note that the kernel won't enable the bits as you upload the new data, so you can't actually create new axes on the device, only modify existing ones.

This post describes how to read input events from the kernel through the new libevdev library.

What is libevdev?

libevdev is a wrapper library to access /dev/input/eventX devices and provide their events through a C API. It buffers the device and is essentially a read(2) on steriods. Instead of read(2) on the file descriptor, you'd call libevdev_next_event() to fetch the next event that is waiting on the fd. And the buffering allows a process to access device data easily.

Why use a library though? The kernel interface is relatively simple, but it has a few pitfalls. For one, device data is accessed through ioctl(2) and can cause weird bugs [1]. Second, not all events work in the same way. e.g. EVIOCGABS doesn't work the same for multi-touch axes, simply because the slot protocol has different semantics than the normal EV_ABS protocol. EV_REP has different handling as EV_ABS, EV_SYN is a special case anyway, etc. libevdev tries to avoid having to think about the differences and does sanity checks for the various calls.

Status of libevdev

libevdev is currently in version 0.4, and the current API is expected stable. That is, we don't foresee any changes unless we discover some severe bug. If that is the case, I will update the blog post here.

Example code

The code snippets below are in C-style pseudocode. You won't be able to just take them and compile them, but look at libevdev-events for a real tool that does almost everything described below.

Initializing a device

The first step to get a device is to open it. That is not actually handled by libevdev directly, rather it expects an already opened file descriptor. The reason is simple: reading /dev/input/event devices usually requires root and the process accessing the device may not have these permissions. In weston for example, the fd is passed from the suid weston-launch binary. Ok, enough talk, let's see some code:

Getting information about the device is done by simply calling the various getters. And checking the device for functionality is done by checking the various event codes we care about. Note that the above code checks for the EV_REL event type first, then for the actual axes bits. This is just for completeness, it is not necessary. Checking for an event code also checks for the event type so we can skip libevdev_has_event_type(). Both approaches are allowed of course, whichever makes you feel more comfortable about the code.

Finally, cleaning up: Because we don't handle the fd in libevdev, we just use it, you'll have to close that separately.

Ok, the gist of how to access a device should be clear. Let's move on to
reading events from the device

Reading events

In the standard case, we just want to get the next event and process it.

The error handling should be clear by now: negative errno means something
has gone wrong. Except -EAGAIN, wich indicates that there are no events
to read at the moment. A return value of LIBEVDEV_READ_STATUS_SYNC is special, it signals a
SYN_DROPPED event which I'll describe later.

A return value of LIBEVDEV_READ_STATUS_SUCCESS means success, so we know we have an event and we can
print it. libevdev provides some helper functions to print the string value of
an event type or code. The code above could, for example print something like
this:

We have an event!
2 (EV_REL) 0 (REL_X) value -1

As you can see, all this effort just to read the same thing off the kernel
device that you would've otherwise with a read(2) call. But wait! There's
more!

Event buffering

libevdev buffers events internally and always tries to read the maximum number
of events off the kernel device. So when you call libevdev_next_event,
libevdev may read 50 events off the fd (or whatever is available) and only
give you the first. On the next call, it will simply give you the second event of
those first 50, but try to read more again to keep the kernel buffer as empty
as possible.

Whenever you request an event, libevdev will update its internal state to
match the current device state so the client doesn't have to. So if you need
to keep track of button states, you can rely on libevdev:

If no button is pressed, then pressed before the next event is read, this
snippet would print "Button is up" and "Button is down". Fairly obvious, I
think.

Important to point out is that the device state is always the state as seen
by the client, i.e. if the client would keep track of the device state
based on the events libevdev hands to it, libevdev and the client would always
have the same state. Why is this important? libevdev reads multiple events off
the wire whenever a client calls libevdev_next_event, but these events
do not update the state of the device until passed to the client. So
again, since libevdev reflects the state as seen by the client, the client
doesn't need to keep track of the state itself. Winners all 'round.

SYN_DROPPED device syncing

A EV_SYN/SYN_DROPPED event is relatively recent (kernel 2.6.39). If a device
sends events faster than userspace can read it, eventually the kernel buffers
are full and the kernel drops events. When it does so, it sends a
EV_SYN/SYN_DROPPED event to notify userspace. The userspace process then needs
to stop what it's doing, re-sync the device (i.e. query all axis, key, LED,
etc. values), update the internal state accordingly and then it can start
reading events again.

libevdev handles all this for you.
In the example code above, you saw that a return value of LIBEVDEV_READ_STATUS_SYNC signals a
SYN_DROPPED event and we called handle_syn_dropped(). This function is
actually incredibly easy:

You notice there is almost no difference to the normal event loop. A
different read flag, and instead of an rc of 0, we're now expecting an rc of
LIBEVDEV_READ_STATUS_SYNC. libevdev will give us events that all reflect the state change since the
SYN_DROPPED so we can update the client accordingly. Once the device is fully
synced, libevdev_next_event returns -EAGAIN to indicate there
are no more events to sync. The client can go back to reading events normally
with LIBEVDEV_READ_FLAG_NORMAL.

This is a lot simpler than having to ioctl the device and calculating the
state manually.

The state handling is the same as described above. Even though libevdev
knows that there are e.g. a few button events waiting in the sync queue it
will not update the client-visible state until it passed the respective event
to you.

Finally: you don't have to sync the device after a SYN_DROPPED event. You
can chose to keep reading with LIBEVDEV_READ_FLAG_NORMAL as if nothing
happened. If you do so, libevdev will drop the sync event queue, update the
internal state to match the sync status and pass you the next real event. So
even if you didn't get that button down event because you dropped the sync,
libevdev_get_event_value(dev, EV_KEY, BTN_LEFT) will now return 1 to
reflect the state of the device. So libevdev's device state still matches what
the client would otherwise see (had it processed all events).

This is a base overview of how libevdev works. In the next post, I'll show how to manipulate the device.

[1] look the kernel source, drivers/input/evdev.c:handle_eviocgbit, supplying the wrong size was common enough to warrant a warning in the kernel.

Friday, September 13, 2013

git-branch-tools is my little repo for git scripts to make a few things easier. I first talked about it here. The repository is available on https://github.com/whot/git-branch-tools, the latest addition is git patch-set.
I used to create git patch sets with just git format-patch, but too often I found some minor change on the last review and had to re-generate it. So ended up with multiple patch files in the directory, or worse, a combination of old and new ones in danger of being sent by git send-email later. git-patch-set fixes this for me:

So my patches are in the $GIT_DIR/patches/ directory, named after the
current date + time and the refs used for the list. This makes them
identifiable and sortable (to some degree anyway). And, to make things
easier, $GIT_DIR/patches/latest is a symlink to the latest patch set, so usually the workflow is