mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
181 lines
6.8 KiB
181 lines
6.8 KiB
.. SPDX-License-Identifier: GPL-2.0 |
|
|
|
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 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. |
|
|
|
The :c:type:`v4l2_fh` struct has a list of subscribed events on its |
|
``subscribed`` field. |
|
|
|
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 v4l2_fh has two lists: one of the ``subscribed`` events, |
|
and one of the ``available`` events. |
|
|
|
- struct v4l2_subscribed_event has a ringbuffer of raised |
|
(pending) events of that particular type. |
|
|
|
- If struct v4l2_subscribed_event is associated with a specific |
|
object, then that object will have an internal list of |
|
struct v4l2_subscribed_event so it knows who subscribed an |
|
event to that object. |
|
|
|
Furthermore, the internal struct 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 |
|
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. |
|
|
|
A good example of these ``replace``/``merge`` callbacks is in v4l2-event.c: |
|
``ctrls_replace()`` and ``ctrls_merge()`` callbacks for the control event. |
|
|
|
.. note:: |
|
these callbacks can be called from interrupt context, so they must |
|
be fast. |
|
|
|
In order to queue events to video device, drivers should call: |
|
|
|
:c:func:`v4l2_event_queue <v4l2_event_queue>` |
|
(:c:type:`vdev <video_device>`, :c:type:`ev <v4l2_event>`) |
|
|
|
The driver's only responsibility is to fill in the type and the data fields. |
|
The other fields will be filled in by V4L2. |
|
|
|
Event subscription |
|
~~~~~~~~~~~~~~~~~~ |
|
|
|
Subscribing to an event is via: |
|
|
|
:c:func:`v4l2_event_subscribe <v4l2_event_subscribe>` |
|
(:c:type:`fh <v4l2_fh>`, :c:type:`sub <v4l2_event_subscription>` , |
|
elems, :c:type:`ops <v4l2_subscribed_event_ops>`) |
|
|
|
|
|
This function is used to implement :c:type:`video_device`-> |
|
:c:type:`ioctl_ops <v4l2_ioctl_ops>`-> ``vidioc_subscribe_event``, |
|
but the driver must check first if the driver is able to produce events |
|
with specified event id, and then should call |
|
:c:func:`v4l2_event_subscribe` to subscribe the event. |
|
|
|
The elems argument is the size of the event queue for this event. If it is 0, |
|
then the framework will fill in a default value (this depends on the event |
|
type). |
|
|
|
The ops argument allows the driver to specify a number of callbacks: |
|
|
|
.. tabularcolumns:: |p{1.5cm}|p{16.0cm}| |
|
|
|
======== ============================================================== |
|
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) |
|
del called when a listener stops listening |
|
replace replace event 'old' with event 'new'. |
|
merge merge event 'old' into event 'new'. |
|
======== ============================================================== |
|
|
|
All 4 callbacks are optional, if you don't want to specify any callbacks |
|
the ops argument itself maybe ``NULL``. |
|
|
|
Unsubscribing an event |
|
~~~~~~~~~~~~~~~~~~~~~~ |
|
|
|
Unsubscribing to an event is via: |
|
|
|
:c:func:`v4l2_event_unsubscribe <v4l2_event_unsubscribe>` |
|
(:c:type:`fh <v4l2_fh>`, :c:type:`sub <v4l2_event_subscription>`) |
|
|
|
This function is used to implement :c:type:`video_device`-> |
|
:c:type:`ioctl_ops <v4l2_ioctl_ops>`-> ``vidioc_unsubscribe_event``. |
|
A driver may call :c:func:`v4l2_event_unsubscribe` directly unless it |
|
wants to be involved in unsubscription process. |
|
|
|
The special type ``V4L2_EVENT_ALL`` may be used to unsubscribe all events. The |
|
drivers may want to handle this in a special way. |
|
|
|
Check if there's a pending event |
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
|
|
Checking if there's a pending event is via: |
|
|
|
:c:func:`v4l2_event_pending <v4l2_event_pending>` |
|
(:c:type:`fh <v4l2_fh>`) |
|
|
|
|
|
This function returns the number of pending events. Useful when implementing |
|
poll. |
|
|
|
How events work |
|
~~~~~~~~~~~~~~~ |
|
|
|
Events are delivered to user space through the poll system call. The driver |
|
can use :c:type:`v4l2_fh`->wait (a wait_queue_head_t) as the argument for |
|
``poll_wait()``. |
|
|
|
There are standard and private events. New standard events must use the |
|
smallest available event type. The drivers must allocate their events from |
|
their own class starting from class base. Class base is |
|
``V4L2_EVENT_PRIVATE_START`` + n * 1000 where n is the lowest available number. |
|
The first event type in the class is reserved for future use, so the first |
|
available event type is 'class base + 1'. |
|
|
|
An example on how the V4L2 events may be used can be found in the OMAP |
|
3 ISP driver (``drivers/media/platform/omap3isp``). |
|
|
|
A subdev can directly send an event to the :c:type:`v4l2_device` notify |
|
function with ``V4L2_DEVICE_NOTIFY_EVENT``. This allows the bridge to map |
|
the subdev that sends the event to the video node(s) associated with the |
|
subdev that need to be informed about such an event. |
|
|
|
V4L2 event functions and data structures |
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
|
|
|
.. kernel-doc:: include/media/v4l2-event.h |
|
|
|
|