[PATCH libevdev 2/4] doc: Add documentation on how SYN_DROPPED is handled

Peter Hutterer peter.hutterer at who-t.net
Thu Mar 13 17:07:04 PDT 2014


On Thu, Mar 13, 2014 at 09:59:24AM -0400, Benjamin Tissoires wrote:
> On Tue, Mar 11, 2014 at 8:45 PM, Peter Hutterer
> <peter.hutterer at who-t.net> wrote:
> > This is getting a bit complex, so add some high-level documentation that we at
> > least know what we're trying to do.
> >
> > Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
> > ---
> 
> Well, besides the nitpicking at the beginning, I'm ok with that:
> Reviewed-by: Benjamin Tissoires <benjamin.tissoires at gmail.com>
> 
> In a more general comment, I think that either we should put part of
> this in the kernel at Documentation/input/event-codes.txt, or at least
> put a link on libevdev in this very same file.

Yeah, that sounds like a good idea. I think linking to libevdev is the
better solution here, otherwise we split the documentation and become
possibly outdated on one.
Also, libevdev focuses more on a userspace POV which is what most programs
would be interested in.

> Seeing that BSD is offering a GSoC for implemeting evdev in the input
> part of their kernel makes me wonder if they are going to use the
> exact same semantic for their evdev protocol

I've contacted Matthieu and told him about libevdev. The whole point of
evdev in BSD is to be compatible to linux so they'll have to use the same
semantics.

Thanks for the review, I've amended the event sequence as suggested.

Cheers,
   Peter

> ..
> 
> >  libevdev/libevdev.h | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++-
> >  1 file changed, 156 insertions(+), 2 deletions(-)
> >
> > diff --git a/libevdev/libevdev.h b/libevdev/libevdev.h
> > index 481e378..5dfe026 100644
> > --- a/libevdev/libevdev.h
> > +++ b/libevdev/libevdev.h
> > @@ -52,7 +52,8 @@ extern "C" {
> >   * has been received and that the state of the device is different to what is
> >   * to be expected. It then provides the delta between the previous state and
> >   * the actual state of the device as a set of events. See
> > - * libevdev_next_event() for more information.
> > + * libevdev_next_event() and @ref syn_dropped for more information on how
> > + * SYN_DROPPED is handled.
> >   *
> >   * Signal safety
> >   * =============
> > @@ -157,6 +158,157 @@ extern "C" {
> >   */
> >
> >  /**
> > + * @page syn_dropped SYN_DROPPED handling
> > + *
> > + * This page describes how libevdev handles SYN_DROPPED events.
> > + *
> > + * The kernel sends evdev events separated by an event of type EV_SYN and
> > + * code SYN_REPORT. Such an event marks the end of a frame of hardware
> > + * events. The number of events between SYN_REPORT events is arbitrary and
> > + * depends on the hardware. And example event sequence may look like this:
> > + * @code
> > +   EV_ABS   ABS_X        9
> > +   EV_ABS   ABS_Y        8
> > +   EV_SYN   SYN_REPORT   0
> > +   ------------------------
> > +   EV_ABS   ABS_X        10
> > +   EV_ABS   ABS_Y        10
> > +   EV_KEY   BTN_TOUCH    1
> > +   EV_SYN   SYN_REPORT   0
> > +   ------------------------
> > +   EV_ABS   ABS_X        11
> > +   EV_SYN   SYN_REPORT   0
> > + * @endcode
> > + *
> > + * Events are handed to the client buffer as they appear, the kernel adjusts
> > + * the buffer size to handle at least one full event. In the normal case,
> > + * the client reads the event and the kernel can place the next event in the
> > + * buffer. If the client is not fast enough, the kernel places an event of
> > + * type EV_SYN and code SYN_DROPPED into the buffer, effectively notifying
> > + * the client that some events were lost. The above example event sequence
> > + * may look like this (note the missing ABS_Y event):
> > + * @code
> > +   EV_ABS   ABS_X        9
> > +   EV_ABS   ABS_Y        8
> > +   EV_SYN   SYN_REPORT   0
> > +   ------------------------
> > +   EV_ABS   ABS_X        10
> > +   EV_SYN   SYN_DROPPED  0
> > +   EV_KEY   BTN_TOUCH    1
> > +   EV_SYN   SYN_REPORT   0
> > +   ------------------------
> > +   EV_ABS   ABS_X        11
> > +   EV_SYN   SYN_REPORT   0
> > + * @endcode
> 
> <mode bikeshedding on>
> 
> This event sequence looks like the kernel just replaced ABS_Y by
> SYN_DROPPED. IMO, it would be more convincing if we have at least 1
> event repeated before and after the SYN_DROPPED.
> 
> how about:
> 
> + * @code
> +   EV_ABS   ABS_X        9
> +   EV_ABS   ABS_Y        8
> +   EV_SYN   SYN_REPORT   0
> +   ------------------------
> +   EV_ABS   ABS_X        10
> +   EV_ABS   ABS_Y        9
> +   EV_SYN   SYN_DROPPED  0
> +   EV_ABS   ABS_Y        15
> +   EV_SYN   SYN_REPORT   0
> +   ------------------------
> +   EV_ABS   ABS_X        11
> +   EV_KEY   BTN_TOUCH    0
> +   EV_SYN   SYN_REPORT   0
> + * @endcode
> 
> here:
> - ABS_Y is sent twice in the second report where SYN_DROPPED is here
> - BTN_TOUCH is set to 0 while it's previous state was (or could be) 0,
> so we missed this too.
> 
> <mode bikeshedding off>
> 
> Cheers,
> Benjamin
> 
> > + *
> > + * A SYN_DROPPED event may be recieved at any time in the event sequence.
> > + * When a SYN_DROPPED event is received, the client must:
> > + * * discard all events since the last SYN_REPORT
> > + * * discard all events until including the next SYN_REPORT
> > + * These event are part of incomplete event frames.
> > + *
> > + * The handling of the device after a SYN_DROPPED depends on the available
> > + * event codes. For all event codes of type EV_REL, no handling is
> > + * necessary, there is no state attached. For all event codes of type
> > + * EV_KEY, EV_SW, EV_LED and EV_SND, the matching @ref ioctls retrieve the
> > + * current state. The caller must then compare the last-known state to the
> > + * retrieved state and handle the deltas accordingly.
> > + * libevdev simplifies this approach: if the state of the device has
> > + * changed, libevdev generates an event for each code with the new value and
> > + * passes it to the caller during libevdev_next_event() if
> > + * LIBEVDEV_READ_FLAG_SYNC is set.
> > + *
> > + * For events of type EV_ABS and an event code less than ABS_MT_SLOT, the
> > + * handling of state changes is as described above. For events between
> > + * ABS_MT_SLOT and ABS_MAX, the event handling differs.
> > + * Slots are the vehicles to transport information for multiple simultaneous
> > + * touchpoints on a device. Slots are re-used once a touchpoint has ended.
> > + * The kernel sends an ABS_MT_SLOT event whenever the current slot
> > + * changes; any event in the above axis range applies only to the currently
> > + * active slot.
> > + * Thus, an event sequence from a slot-capable device may look like this:
> > + * @code
> > +   EV_ABS   ABS_MT_POSITION_Y   10
> > +   EV_ABS   ABS_MT_SLOT         1
> > +   EV_ABS   ABS_MT_POSITION_X   100
> > +   EV_ABS   ABS_MT_POSITION_Y   80
> > +   EV_SYN   SYN_REPORT          0
> > + * @endcode
> > + * Note the lack of ABS_MT_SLOT: the first ABS_MT_POSITION_Y applies to
> > + * a slot opened previously, and is the only axis that changed for that
> > + * slot. The touchpoint in slot 1 now has position 100/80.
> > + * The kernel does not provide events if a value does not change, and does
> > + * not send ABS_MT_SLOT events if the slot does not change, or none of the
> > + * values within a slot changes. A client must thus keep the state for each
> > + * slot.
> > + *
> > + * If a SYN_DROPPED is received,  the client must sync all slots
> > + * individually and update its internal state. libevdev simplifies this by
> > + * generating multiple events:
> > + * * for each slot on the device, libevdev generates an
> > + *   ABS_MT_SLOT event with the value set to the slot number
> > + * * for each event code between ABS_MT_SLOT + 1 and ABS_MAX that changed
> > + *   state for this slot, libevdev generates an event for the new state
> > + * * libevdev sends a final ABS_MT_SLOT event for the current slot as
> > + *   seen by the kernel
> > + * * libevdev terminates this sequence with an EV_SYN SYN_REPORT event
> > + *
> > + * An example event sequence for such a sync may look like this:
> > + * @code
> > +   EV_ABS   ABS_MT_SLOT         0
> > +   EV_ABS   ABS_MT_POSITION_Y   10
> > +   EV_ABS   ABS_MT_SLOT         1
> > +   EV_ABS   ABS_MT_POSITION_X   100
> > +   EV_ABS   ABS_MT_POSITION_Y   80
> > +   EV_ABS   ABS_MT_SLOT         2
> > +   EV_ABS   ABS_MT_POSITION_Y   8
> > +   EV_ABS   ABS_MT_PRESSURE     12
> > +   EV_ABS   ABS_MT_SLOT         1
> > +   EV_SYN   SYN_REPORT          0
> > + * @endcode
> > + * Note the terminating ABS_MT_SLOT event, this indicates that the kernel
> > + * currently has slot 1 active.
> > + *
> > + * The event code ABS_MT_TRACKING_ID is used to denote the start and end of
> > + * a touch point within a slot. An ABS_MT_TRACKING_ID of zero or greater
> > + * denotes the start of a touchpoint, an ABS_MT_TRACKING_ID of -1 denotes
> > + * the end of a touchpoint within this slot. During SYN_DROPPED, a touch
> > + * point may have ended and re-started within a slot - a client must check
> > + * the ABS_MT_TRACKING_ID. libevdev simplifies this by emulating extra
> > + * events if the ABS_MT_TRACKING_ID has changed:
> > + * * if the ABS_MT_TRACKING_ID was valid and is -1, libevdev enqueues an
> > + *   ABS_MT_TRACKING_ID event with value -1.
> > + * * if the ABS_MT_TRACKING_ID was -1 and is now a valid ID, libevdev
> > + *   enqueues an ABS_MT_TRACKING_ID event with the current value.
> > + * * if the ABS_MT_TRACKING_ID was a valid ID and is now a different valid
> > + *   ID, libevev enqueues an ABS_MT_TRACKING_ID event with value -1 and
> > + *   another ABS_MT_TRACKING_ID event with the new value.
> > + * An example event sequence for such a sync may look like this:
> > + * @code
> > +   EV_ABS   ABS_MT_SLOT         0
> > +   EV_ABS   ABS_MT_TRACKING_ID  -1
> > +   EV_ABS   ABS_MT_SLOT         2
> > +   EV_ABS   ABS_MT_TRACKING_ID  -1
> > +   EV_SYN   SYN_REPORT          0
> > +   ------------------------
> > +   EV_ABS   ABS_MT_SLOT         1
> > +   EV_ABS   ABS_MT_POSITION_X   100
> > +   EV_ABS   ABS_MT_POSITION_Y   80
> > +   EV_ABS   ABS_MT_SLOT         2
> > +   EV_ABS   ABS_MT_TRACKING_ID  45
> > +   EV_ABS   ABS_MT_POSITION_Y   8
> > +   EV_ABS   ABS_MT_PRESSURE     12
> > +   EV_ABS   ABS_MT_SLOT         1
> > +   EV_SYN   SYN_REPORT          0
> > + * @endcode
> > + * Note how the touchpoint in slot 0 was terminated, the touchpoint in slot
> > + * 2 was terminated and then started with a new ABS_MT_TRACKING_ID. The touchpoint
> > + * in slot 1 maintained the same ABS_MT_TRACKING_ID and only updated the
> > + * coordinates. Slot 1 is the currently active slot.
> > + *
> > + */
> > +
> > +/**
> >   * @page testing libevdev-internal test suite
> >   *
> >   * libevdev's internal test suite uses the
> > @@ -698,7 +850,9 @@ enum libevdev_read_status {
> >   * @ref LIBEVDEV_READ_FLAG_SYNC flag set, to get the set of events that make up the
> >   * device state delta. This function returns @ref LIBEVDEV_READ_STATUS_SYNC for
> >   * each event part of that delta, until it returns -EAGAIN once all events
> > - * have been synced.
> > + * have been synced. For more details on what libevdev does to sync after a
> > + * SYN_DROPPED event, see @ref syn_dropped.
> > + *
> >   * @note The implementation of libevdev limits the maximum number of slots
> >   * that can be synched. If your device exceeds the number of slots
> >   * (currently 60), slot indices equal and above this maximum are ignored and
> > --
> > 1.8.5.3
> >
> > _______________________________________________
> > Input-tools mailing list
> > Input-tools at lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/input-tools


More information about the Input-tools mailing list