diff options
Diffstat (limited to 'Documentation/driver-api/media/v4l2-event.rst')
-rw-r--r-- | Documentation/driver-api/media/v4l2-event.rst | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/Documentation/driver-api/media/v4l2-event.rst b/Documentation/driver-api/media/v4l2-event.rst new file mode 100644 index 0000000000..52d4fbc5d8 --- /dev/null +++ b/Documentation/driver-api/media/v4l2-event.rst @@ -0,0 +1,181 @@ +.. 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/ti/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 + |