Documentation/driver-api/media/v4l2-event.rst GitHub 원문 ↗

Linux 6.18.37 · Driver API

V4L2 events

File handle별 V4L2 event 구독, ring buffer, overflow 병합과 poll 전달을 설명하는 전문 번역입니다.

Source pathDocumentation/driver-api/media/v4l2-event.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약과 해설

v4l2-event.rst:1-181

`v4l2_fh`의 subscription별 ring buffer는 event 종류를 격리하고, merge·replace callback은 overflow 때 최종 상태를 보존합니다.

문서 구성
원문 줄내용
1-44Event 식별과 ring buffer
45-89Overflow merge·replace와 queue
90-126Subscription callback
127-154구독 해제와 pending 검사
155-176poll 전달과 private event
177-181`v4l2-event.h` kernel-doc

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 V4L2 events
4 -----------
5
6 The V4L2 events provide a generic way to pass events to user space.
7 The driver must use :c:type:`v4l2_fh` to be able to support V4L2 events.
8
9 Events are subscribed per-filehandle. An event specification consists of a
10 ``type`` and is optionally associated with an object identified through the
11 ``id`` field. If unused, then the ``id`` is 0. So an event is uniquely
12 identified by the ``(type, id)`` tuple.
13
14 The :c:type:`v4l2_fh` struct has a list of subscribed events on its
15 ``subscribed`` field.
16
17 When the user subscribes to an event, a :c:type:`v4l2_subscribed_event`
18 struct is added to :c:type:`v4l2_fh`\ ``.subscribed``, one for every
19 subscribed event.
20
21 Each :c:type:`v4l2_subscribed_event` struct ends with a
22 :c:type:`v4l2_kevent` ringbuffer, with the size given by the caller
23 of :c:func:`v4l2_event_subscribe`. This ringbuffer is used to store any events
24 raised by the driver.
25
26 So every ``(type, ID)`` event tuple will have its own
27 :c:type:`v4l2_kevent` ringbuffer. This guarantees that if a driver is
28 generating lots of events of one type in a short time, then that will
29 not overwrite events of another type.
30
31 But if you get more events of one type than the size of the
32 :c:type:`v4l2_kevent` ringbuffer, then the oldest event will be dropped
33 and the new one added.
34
35 The :c:type:`v4l2_kevent` struct links into the ``available``
36 list of the :c:type:`v4l2_fh` struct so :ref:`VIDIOC_DQEVENT` will
37 know which event to dequeue first.
38
39 Finally, if the event subscription is associated with a particular object
40 such as a V4L2 control, then that object needs to know about that as well
41 so that an event can be raised by that object. So the ``node`` field can
42 be used to link the :c:type:`v4l2_subscribed_event` struct into a list of
43 such objects.
44
45 So to summarize:
46
47 - struct v4l2_fh has two lists: one of the ``subscribed`` events,
48 and one of the ``available`` events.
49
50 - struct v4l2_subscribed_event has a ringbuffer of raised
51 (pending) events of that particular type.
52
53 - If struct v4l2_subscribed_event is associated with a specific
54 object, then that object will have an internal list of
55 struct v4l2_subscribed_event so it knows who subscribed an
56 event to that object.
57
58 Furthermore, the internal struct v4l2_subscribed_event has
59 ``merge()`` and ``replace()`` callbacks which drivers can set. These
60 callbacks are called when a new event is raised and there is no more room.
61
62 The ``replace()`` callback allows you to replace the payload of the old event
63 with that of the new event, merging any relevant data from the old payload
64 into the new payload that replaces it. It is called when this event type has
65 a ringbuffer with size is one, i.e. only one event can be stored in the
66 ringbuffer.
67
68 The ``merge()`` callback allows you to merge the oldest event payload into
69 that of the second-oldest event payload. It is called when
70 the ringbuffer has size is greater than one.
71
72 This way no status information is lost, just the intermediate steps leading
73 up to that state.
74
75 A good example of these ``replace``/``merge`` callbacks is in v4l2-event.c:
76 ``ctrls_replace()`` and ``ctrls_merge()`` callbacks for the control event.
77
78 .. note::
79 these callbacks can be called from interrupt context, so they must
80 be fast.
81
82 In order to queue events to video device, drivers should call:
83
84 :c:func:`v4l2_event_queue <v4l2_event_queue>`
85 (:c:type:`vdev <video_device>`, :c:type:`ev <v4l2_event>`)
86
87 The driver's only responsibility is to fill in the type and the data fields.
88 The other fields will be filled in by V4L2.
89
90 Event subscription
91 ~~~~~~~~~~~~~~~~~~
92
93 Subscribing to an event is via:
94
95 :c:func:`v4l2_event_subscribe <v4l2_event_subscribe>`
96 (:c:type:`fh <v4l2_fh>`, :c:type:`sub <v4l2_event_subscription>` ,
97 elems, :c:type:`ops <v4l2_subscribed_event_ops>`)
98
99
100 This function is used to implement :c:type:`video_device`->
101 :c:type:`ioctl_ops <v4l2_ioctl_ops>`-> ``vidioc_subscribe_event``,
102 but the driver must check first if the driver is able to produce events
103 with specified event id, and then should call
104 :c:func:`v4l2_event_subscribe` to subscribe the event.
105
106 The elems argument is the size of the event queue for this event. If it is 0,
107 then the framework will fill in a default value (this depends on the event
108 type).
109
110 The ops argument allows the driver to specify a number of callbacks:
111
112 .. tabularcolumns:: |p{1.5cm}|p{16.0cm}|
113
114 ======== ==============================================================
115 Callback Description
116 ======== ==============================================================
117 add called when a new listener gets added (subscribing to the same
118 event twice will only cause this callback to get called once)
119 del called when a listener stops listening
120 replace replace event 'old' with event 'new'.
121 merge merge event 'old' into event 'new'.
122 ======== ==============================================================
123
124 All 4 callbacks are optional, if you don't want to specify any callbacks
125 the ops argument itself maybe ``NULL``.
126
127 Unsubscribing an event
128 ~~~~~~~~~~~~~~~~~~~~~~
129
130 Unsubscribing to an event is via:
131
132 :c:func:`v4l2_event_unsubscribe <v4l2_event_unsubscribe>`
133 (:c:type:`fh <v4l2_fh>`, :c:type:`sub <v4l2_event_subscription>`)
134
135 This function is used to implement :c:type:`video_device`->
136 :c:type:`ioctl_ops <v4l2_ioctl_ops>`-> ``vidioc_unsubscribe_event``.
137 A driver may call :c:func:`v4l2_event_unsubscribe` directly unless it
138 wants to be involved in unsubscription process.
139
140 The special type ``V4L2_EVENT_ALL`` may be used to unsubscribe all events. The
141 drivers may want to handle this in a special way.
142
143 Check if there's a pending event
144 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
145
146 Checking if there's a pending event is via:
147
148 :c:func:`v4l2_event_pending <v4l2_event_pending>`
149 (:c:type:`fh <v4l2_fh>`)
150
151
152 This function returns the number of pending events. Useful when implementing
153 poll.
154
155 How events work
156 ~~~~~~~~~~~~~~~
157
158 Events are delivered to user space through the poll system call. The driver
159 can use :c:type:`v4l2_fh`->wait (a wait_queue_head_t) as the argument for
160 ``poll_wait()``.
161
162 There are standard and private events. New standard events must use the
163 smallest available event type. The drivers must allocate their events from
164 their own class starting from class base. Class base is
165 ``V4L2_EVENT_PRIVATE_START`` + n * 1000 where n is the lowest available number.
166 The first event type in the class is reserved for future use, so the first
167 available event type is 'class base + 1'.
168
169 An example on how the V4L2 events may be used can be found in the OMAP
170 3 ISP driver (``drivers/media/platform/ti/omap3isp``).
171
172 A subdev can directly send an event to the :c:type:`v4l2_device` notify
173 function with ``V4L2_DEVICE_NOTIFY_EVENT``. This allows the bridge to map
174 the subdev that sends the event to the video node(s) associated with the
175 subdev that need to be informed about such an event.
176
177 V4L2 event functions and data structures
178 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
179
180 .. kernel-doc:: include/media/v4l2-event.h
181
182

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

V4L2 event 자료구조와 ring buffer

1-44

V4L2 event는 event를 userspace에 전달하는 일반적인 방법입니다. Driver가 V4L2 event를 지원하려면 `v4l2_fh`를 사용해야 합니다.

Event subscription은 file handle별로 관리합니다. Event 명세는 `type`과 선택적인 object `id`로 이루어지며, `id`를 사용하지 않으면 0입니다. 따라서 하나의 event는 `(type, id)` tuple로 고유하게 식별됩니다.

`v4l2_fh.subscribed`는 구독한 event 목록입니다. 사용자가 event를 구독할 때마다 해당 event를 나타내는 `v4l2_subscribed_event`가 이 목록에 추가됩니다.

각 `v4l2_subscribed_event` 끝에는 `v4l2_event_subscribe()` 호출자가 지정한 크기의 `v4l2_kevent` ring buffer가 있습니다. Driver가 발생시킨 event는 이 buffer에 저장됩니다.

각 `(type, id)` tuple은 독립 ring buffer를 가지므로 한 종류의 event가 짧은 시간에 많이 발생해도 다른 종류의 event를 덮어쓰지 않습니다. 같은 종류의 event가 ring buffer 크기를 넘으면 가장 오래된 event를 버리고 새 event를 추가합니다.

`v4l2_kevent`는 `v4l2_fh.available` 목록에도 연결되므로 `VIDIOC_DQEVENT`가 먼저 dequeue할 event를 알 수 있습니다.

Subscription이 V4L2 control 같은 특정 object와 연결되면 그 object도 구독자를 알아야 event를 발생시킬 수 있습니다. `node` field는 `v4l2_subscribed_event`를 해당 object의 내부 목록에 연결할 때 사용합니다.

Event subscription 구조
`v4l2_fh.subscribed``v4l2_subscribed_event`Tuple별 `v4l2_kevent` ring buffer
발생한 event`v4l2_fh.available``VIDIOC_DQEVENT`
특정 object`node`Object의 구독자 목록

File handle의 구독 목록과 이용 가능 목록, tuple별 ring buffer가 함께 동작합니다.

.. 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.

Event overflow 병합과 queue

45-89

요약하면 `v4l2_fh`에는 구독한 event의 `subscribed` 목록과 발생하여 대기 중인 event의 `available` 목록이 있습니다. `v4l2_subscribed_event`는 특정 종류의 pending event ring buffer를 가지며, 특정 object와 연결된 경우 object도 자신에게 등록된 subscription 목록을 가집니다.

내부 `v4l2_subscribed_event`에는 driver가 설정할 수 있는 `merge()`와 `replace()` callback도 있습니다. 새 event가 발생했지만 ring buffer에 빈 공간이 없을 때 호출됩니다.

Ring buffer 크기가 1이면 `replace()`가 기존 event payload를 새 payload로 바꾸면서 필요한 기존 상태를 새 payload에 병합합니다. 크기가 1보다 크면 `merge()`가 가장 오래된 event payload를 두 번째로 오래된 payload에 합칩니다.

이 방식은 최종 상태 정보는 잃지 않고 그 상태에 이르는 중간 단계만 압축합니다. Control event의 예는 `v4l2-event.c`의 `ctrls_replace()`와 `ctrls_merge()`입니다.

이 callback들은 interrupt context에서 호출될 수 있으므로 빨라야 합니다.

Video device에 event를 queue하려면 `v4l2_event_queue(vdev, ev)`를 호출합니다. Driver는 event의 type과 data field만 채우며 나머지 field는 V4L2가 채웁니다.

Ring buffer overflow 처리
조건Callback동작
크기 1`replace()`기존 payload를 새 payload로 교체하며 상태 병합
크기 1 초과`merge()`가장 오래된 payload를 다음 payload에 병합
공통 제약Interrupt context 가능빠르게 완료해야 함

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

90-126

Event 구독은 `v4l2_event_subscribe(fh, sub, elems, ops)`로 수행합니다. 이 함수는 `video_device->ioctl_ops->vidioc_subscribe_event`를 구현할 때 사용합니다.

Driver는 먼저 지정된 event ID의 event를 실제로 만들 수 있는지 검사한 뒤 `v4l2_event_subscribe()`를 호출해야 합니다.

`elems`는 이 event의 queue 크기입니다. 0이면 framework가 event 종류에 따른 기본값을 채웁니다.

`ops`는 네 가지 선택적 callback을 지정합니다. `add`는 새 listener가 추가될 때 호출되며 같은 event를 두 번 구독해도 한 번만 호출됩니다. `del`은 listener가 구독을 중지할 때 호출됩니다. `replace`는 old event를 new event로 교체하고 `merge`는 old event를 new event에 병합합니다.

네 callback은 모두 선택 사항이며 아무 callback도 필요 없으면 `ops` 자체를 `NULL`로 전달할 수 있습니다.

v4l2_subscribed_event_ops
Callback호출 시점과 역할
`add`새 listener 추가
`del`Listener 구독 종료
`replace`Old event를 new event로 교체
`merge`Old event를 new event에 병합

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``.

Event 구독 해제

127-142

Event 구독 해제는 `v4l2_event_unsubscribe(fh, sub)`로 수행하며 `video_device->ioctl_ops->vidioc_unsubscribe_event` 구현에 사용합니다.

Driver가 구독 해제 과정에 직접 관여할 필요가 없다면 `v4l2_event_unsubscribe()`를 그대로 호출할 수 있습니다.

특수 type `V4L2_EVENT_ALL`은 모든 event 구독을 해제합니다. Driver는 이 값을 별도 방식으로 처리할 수 있습니다.

구독 해제 경로
`vidioc_unsubscribe_event``v4l2_event_unsubscribe()`
`V4L2_EVENT_ALL`모든 event 구독 해제

단일 event 또는 모든 event subscription을 file handle에서 제거합니다.

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.

Pending event 확인

143-154

Pending event 수는 `v4l2_event_pending(fh)`으로 확인합니다.

이 함수가 반환하는 pending event 개수는 file operation의 poll을 구현할 때 유용합니다.

Pending event 검사
입력반환값주요 용도
`v4l2_fh`Pending event 개수poll 구현

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.

Event 전달과 private type

155-176

Event는 poll system call을 통해 userspace로 전달합니다. Driver는 `poll_wait()` 인자로 `v4l2_fh->wait`의 `wait_queue_head_t`를 사용할 수 있습니다.

Event에는 표준 event와 private event가 있습니다. 새 표준 event는 사용 가능한 가장 작은 event type을 사용해야 합니다.

Driver 전용 event는 driver 고유 class에서 할당합니다. Class base는 `V4L2_EVENT_PRIVATE_START + n * 1000`이며 `n`은 사용 가능한 가장 작은 번호입니다. Class의 첫 event type은 미래 사용을 위해 예약되므로 실제 첫 event는 `class base + 1`입니다.

V4L2 event 사용 예는 OMAP3 ISP driver인 `drivers/media/platform/ti/omap3isp`에서 볼 수 있습니다.

Sub-device는 `V4L2_DEVICE_NOTIFY_EVENT`와 함께 `v4l2_device`의 notify 함수에 event를 직접 보낼 수 있습니다. Bridge는 event를 보낸 sub-device를 연결된 video node에 대응시켜 통지가 필요한 node로 전달합니다.

Event 전달 경로
Video node event`v4l2_fh->wait``poll_wait()`Userspace
Sub-device event`V4L2_DEVICE_NOTIFY_EVENT`Bridge mapping관련 video node

Queue된 event는 poll로 userspace에 전달되거나 sub-device에서 bridge를 거쳐 관련 node에 매핑됩니다.

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 함수와 자료구조

177-181

`include/media/v4l2-event.h`의 kernel-doc에서 V4L2 event 함수와 자료구조의 상세 API를 제공합니다.

API 정의 위치
Header내용
`include/media/v4l2-event.h`V4L2 event 함수·자료구조

V4L2 event functions and data structures
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. kernel-doc:: include/media/v4l2-event.h