media: v4l2-event.rst: improve events description

Both v4l2-event.rst and v4l2-event.h have an overview of
events, but there are some inconsistencies there:

- at v4l2-event, the event's ring buffer is called kevent. Its
  name is, instead, v4l2_kevent;

- Some things are mentioned on both places (with different words),
  others are either on one of the files.

In order to cleanup this mess, put everything at v4l2-event.rst
and improve it to be a little more coherent and to have cross
references.

Acked-by: Sakari Ailus <[email protected]>
Signed-off-by: Mauro Carvalho Chehab <[email protected]>
This commit is contained in:
Mauro Carvalho Chehab 2017-09-22 13:35:45 -04:00
commit 66f1e6078e
2 changed files with 54 additions and 47 deletions

View file

@ -5,27 +5,68 @@ V4L2 events
The V4L2 events provide a generic way to pass events to user space.
The driver must use :c:type:`v4l2_fh` to be able to support V4L2 events.
Events are defined by a type and an optional ID. The ID may refer to a V4L2
object such as a control ID. If unused, then the ID is 0.
Events are subscribed per-filehandle. An event specification consists of a
``type`` and is optionally associated with an object identified through the
``id`` field. If unused, then the ``id`` is 0. So an event is uniquely
identified by the ``(type, id)`` tuple.
When the user subscribes to an event the driver will allocate a number of
kevent structs for that event. So every (type, ID) event tuple will have
its own set of kevent structs. This guarantees that if a driver is generating
lots of events of one type in a short time, then that will not overwrite
events of another type.
The :c:type:`v4l2_fh` struct has a list of subscribed events on its
``subscribed`` field.
But if you get more events of one type than the number of kevents that were
reserved, then the oldest event will be dropped and the new one added.
When the user subscribes to an event, a :c:type:`v4l2_subscribed_event`
struct is added to :c:type:`v4l2_fh`\ ``.subscribed``, one for every
subscribed event.
Each :c:type:`v4l2_subscribed_event` struct ends with a
:c:type:`v4l2_kevent` ringbuffer, with the size given by the caller
of :c:func:`v4l2_event_subscribe`. This ringbuffer is used to store any events
raised by the driver.
So every ``(type, ID)`` event tuple will have its own
:c:type:`v4l2_kevent` ringbuffer. This guarantees that if a driver is
generating lots of events of one type in a short time, then that will
not overwrite events of another type.
But if you get more events of one type than the size of the
:c:type:`v4l2_kevent` ringbuffer, then the oldest event will be dropped
and the new one added.
The :c:type:`v4l2_kevent` struct links into the ``available``
list of the :c:type:`v4l2_fh` struct so :ref:`VIDIOC_DQEVENT` will
know which event to dequeue first.
Finally, if the event subscription is associated with a particular object
such as a V4L2 control, then that object needs to know about that as well
so that an event can be raised by that object. So the ``node`` field can
be used to link the :c:type:`v4l2_subscribed_event` struct into a list of
such objects.
So to summarize:
- struct :c:type:`v4l2_fh` has two lists: one of the ``subscribed`` events,
and one of the ``available`` events.
- struct :c:type:`v4l2_subscribed_event` has a ringbuffer of raised
(pending) events of that particular type.
- If struct :c:type:`v4l2_subscribed_event` is associated with a specific
object, then that object will have an internal list of
struct :c:type:`v4l2_subscribed_event` so it knows who subscribed an
event to that object.
Furthermore, the internal struct :c:type:`v4l2_subscribed_event` has
``merge()`` and ``replace()`` callbacks which drivers can set. These
callbacks are called when a new event is raised and there is no more room.
The ``replace()`` callback allows you to replace the payload of the old event
with that of the new event, merging any relevant data from the old payload
into the new payload that replaces it. It is called when this event type has
only one kevent struct allocated. The ``merge()`` callback allows you to merge
the oldest event payload into that of the second-oldest event payload. It is
called when there are two or more kevent structs allocated.
a ringbuffer with size is one, i.e. only one event can be stored in the
ringbuffer.
The ``merge()`` callback allows you to merge the oldest event payload into
that of the second-oldest event payload. It is called when
the ringbuffer has size is greater than one.
This way no status information is lost, just the intermediate steps leading
up to that state.
@ -73,7 +114,7 @@ The ops argument allows the driver to specify a number of callbacks:
Callback Description
======== ==============================================================
add called when a new listener gets added (subscribing to the same
event twice will only cause this callback to get called once)
event twice will only cause this callback to get called once)
del called when a listener stops listening
replace replace event 'old' with event 'new'.
merge merge event 'old' into event 'new'.