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

Linux 6.18.37 · Driver API

V4L2 device instance

v4l2_device 등록, media 연동, hotplug disconnect, 순회와 refcount를 설명하는 전문 번역입니다.

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

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

1. 요약·해설

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

요약과 해설

v4l2-device.rst:1-146

`v4l2_device`는 한 장치 instance의 상위 container입니다. Hotplug 시 부모 연결 해제와 sub-device unregister를 분리하고, 모든 node reference가 반환된 뒤 release callback에서 최종 정리합니다.

문서 구성
원문 줄내용
1-48등록·이름·media 연동
49-69Unregister와 disconnect
70-103Driver instance 순회
104-118Atomic instance 번호
119-142Hotplug refcount
143-146`v4l2-device.h` kernel-doc

2. 영어 원문 전체

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

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 V4L2 device instance
4 --------------------
5
6 Each device instance is represented by a struct v4l2_device.
7 Very simple devices can just allocate this struct, but most of the time you
8 would embed this struct inside a larger struct.
9
10 You must register the device instance by calling:
11
12 :c:func:`v4l2_device_register <v4l2_device_register>`
13 (dev, :c:type:`v4l2_dev <v4l2_device>`).
14
15 Registration will initialize the :c:type:`v4l2_device` struct. If the
16 dev->driver_data field is ``NULL``, it will be linked to
17 :c:type:`v4l2_dev <v4l2_device>` argument.
18
19 Drivers that want integration with the media device framework need to set
20 dev->driver_data manually to point to the driver-specific device structure
21 that embed the struct v4l2_device instance. This is achieved by a
22 ``dev_set_drvdata()`` call before registering the V4L2 device instance.
23 They must also set the struct v4l2_device mdev field to point to a
24 properly initialized and registered :c:type:`media_device` instance.
25
26 If :c:type:`v4l2_dev <v4l2_device>`\ ->name is empty then it will be set to a
27 value derived from dev (driver name followed by the bus_id, to be precise).
28 If you set it up before calling :c:func:`v4l2_device_register` then it will
29 be untouched. If dev is ``NULL``, then you **must** setup
30 :c:type:`v4l2_dev <v4l2_device>`\ ->name before calling
31 :c:func:`v4l2_device_register`.
32
33 You can use :c:func:`v4l2_device_set_name` to set the name based on a driver
34 name and a driver-global atomic_t instance. This will generate names like
35 ``ivtv0``, ``ivtv1``, etc. If the name ends with a digit, then it will insert
36 a dash: ``cx18-0``, ``cx18-1``, etc. This function returns the instance number.
37
38 The first ``dev`` argument is normally the ``struct device`` pointer of a
39 ``pci_dev``, ``usb_interface`` or ``platform_device``. It is rare for dev to
40 be ``NULL``, but it happens with ISA devices or when one device creates
41 multiple PCI devices, thus making it impossible to associate
42 :c:type:`v4l2_dev <v4l2_device>` with a particular parent.
43
44 You can also supply a ``notify()`` callback that can be called by sub-devices
45 to notify you of events. Whether you need to set this depends on the
46 sub-device. Any notifications a sub-device supports must be defined in a header
47 in ``include/media/subdevice.h``.
48
49 V4L2 devices are unregistered by calling:
50
51 :c:func:`v4l2_device_unregister`
52 (:c:type:`v4l2_dev <v4l2_device>`).
53
54 If the dev->driver_data field points to :c:type:`v4l2_dev <v4l2_device>`,
55 it will be reset to ``NULL``. Unregistering will also automatically unregister
56 all subdevs from the device.
57
58 If you have a hotpluggable device (e.g. a USB device), then when a disconnect
59 happens the parent device becomes invalid. Since :c:type:`v4l2_device` has a
60 pointer to that parent device it has to be cleared as well to mark that the
61 parent is gone. To do this call:
62
63 :c:func:`v4l2_device_disconnect`
64 (:c:type:`v4l2_dev <v4l2_device>`).
65
66 This does *not* unregister the subdevs, so you still need to call the
67 :c:func:`v4l2_device_unregister` function for that. If your driver is not
68 hotpluggable, then there is no need to call :c:func:`v4l2_device_disconnect`.
69
70 Sometimes you need to iterate over all devices registered by a specific
71 driver. This is usually the case if multiple device drivers use the same
72 hardware. E.g. the ivtvfb driver is a framebuffer driver that uses the ivtv
73 hardware. The same is true for alsa drivers for example.
74
75 You can iterate over all registered devices as follows:
76
77 .. code-block:: c
78
79 static int callback(struct device *dev, void *p)
80 {
81 struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
82
83 /* test if this device was inited */
84 if (v4l2_dev == NULL)
85 return 0;
86 ...
87 return 0;
88 }
89
90 int iterate(void *p)
91 {
92 struct device_driver *drv;
93 int err;
94
95 /* Find driver 'ivtv' on the PCI bus.
96 pci_bus_type is a global. For USB buses use usb_bus_type. */
97 drv = driver_find("ivtv", &pci_bus_type);
98 /* iterate over all ivtv device instances */
99 err = driver_for_each_device(drv, NULL, p, callback);
100 put_driver(drv);
101 return err;
102 }
103
104 Sometimes you need to keep a running counter of the device instance. This is
105 commonly used to map a device instance to an index of a module option array.
106
107 The recommended approach is as follows:
108
109 .. code-block:: c
110
111 static atomic_t drv_instance = ATOMIC_INIT(0);
112
113 static int drv_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
114 {
115 ...
116 state->instance = atomic_inc_return(&drv_instance) - 1;
117 }
118
119 If you have multiple device nodes then it can be difficult to know when it is
120 safe to unregister :c:type:`v4l2_device` for hotpluggable devices. For this
121 purpose :c:type:`v4l2_device` has refcounting support. The refcount is
122 increased whenever :c:func:`video_register_device` is called and it is
123 decreased whenever that device node is released. When the refcount reaches
124 zero, then the :c:type:`v4l2_device` release() callback is called. You can
125 do your final cleanup there.
126
127 If other device nodes (e.g. ALSA) are created, then you can increase and
128 decrease the refcount manually as well by calling:
129
130 :c:func:`v4l2_device_get`
131 (:c:type:`v4l2_dev <v4l2_device>`).
132
133 or:
134
135 :c:func:`v4l2_device_put`
136 (:c:type:`v4l2_dev <v4l2_device>`).
137
138 Since the initial refcount is 1 you also need to call
139 :c:func:`v4l2_device_put` in the ``disconnect()`` callback (for USB devices)
140 or in the ``remove()`` callback (for e.g. PCI devices), otherwise the refcount
141 will never reach 0.
142
143 v4l2_device functions and data structures
144 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
145
146 .. kernel-doc:: include/media/v4l2-device.h
147

3. 한국어 전문 번역

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

V4L2 device instance 등록

1-48

각 V4L2 장치 instance는 `struct v4l2_device`로 표현합니다. 매우 단순한 장치는 구조체를 직접 할당할 수 있지만, 보통은 더 큰 driver 전용 구조체 안에 포함합니다.

`v4l2_device_register(dev, v4l2_dev)`를 호출해 instance를 등록합니다. 등록 과정은 `v4l2_device`를 초기화하며, `dev->driver_data`가 `NULL`이면 전달된 `v4l2_dev`와 연결합니다.

Media device framework와 통합하는 driver는 `v4l2_device`를 포함한 driver 전용 구조체를 가리키도록 `dev->driver_data`를 직접 설정해야 합니다. V4L2 instance 등록 전에 `dev_set_drvdata()`를 호출하고, `v4l2_device.mdev`도 초기화·등록된 `media_device`를 가리키게 해야 합니다.

`v4l2_dev->name`이 비어 있으면 driver 이름과 bus ID를 바탕으로 이름이 생성됩니다. 등록 전에 이름을 설정하면 유지됩니다. `dev`가 `NULL`이면 등록 전에 이름을 반드시 설정해야 합니다.

`v4l2_device_set_name()`은 driver 이름과 driver 전역 `atomic_t`로 `ivtv0`, `ivtv1` 같은 이름을 만듭니다. 이름이 숫자로 끝나면 `cx18-0`, `cx18-1`처럼 dash를 넣으며 instance 번호를 반환합니다.

첫 번째 `dev` 인자는 보통 `pci_dev`, `usb_interface`, `platform_device`의 `struct device` pointer입니다. ISA 장치나 하나의 장치가 여러 PCI 장치를 만드는 경우처럼 특정 부모와 연결할 수 없을 때만 드물게 `NULL`을 사용합니다.

Sub-device가 event를 알릴 수 있도록 선택적인 `notify()` callback을 제공할 수도 있습니다. 필요한지는 sub-device에 따라 다르며, 지원 notification은 `include/media/subdevice.h`에 정의되어야 합니다.

v4l2_device 등록 준비
일반 장치`struct device``v4l2_device_register()`
Media 통합`dev_set_drvdata()``mdev` 설정등록
부모 없음`name` 사전 설정등록

부모 연결과 media 통합 여부에 따라 등록 전 field를 준비합니다.

.. SPDX-License-Identifier: GPL-2.0

V4L2 device instance
--------------------

Each device instance is represented by a struct v4l2_device.
Very simple devices can just allocate this struct, but most of the time you
would embed this struct inside a larger struct.

You must register the device instance by calling:

        :c:func:`v4l2_device_register <v4l2_device_register>`
        (dev, :c:type:`v4l2_dev <v4l2_device>`).

Registration will initialize the :c:type:`v4l2_device` struct. If the
dev->driver_data field is ``NULL``, it will be linked to
:c:type:`v4l2_dev <v4l2_device>` argument.

Drivers that want integration with the media device framework need to set
dev->driver_data manually to point to the driver-specific device structure
that embed the struct v4l2_device instance. This is achieved by a
``dev_set_drvdata()`` call before registering the V4L2 device instance.
They must also set the struct v4l2_device mdev field to point to a
properly initialized and registered :c:type:`media_device` instance.

If :c:type:`v4l2_dev <v4l2_device>`\ ->name is empty then it will be set to a
value derived from dev (driver name followed by the bus_id, to be precise).
If you set it up before  calling :c:func:`v4l2_device_register` then it will
be untouched. If dev is ``NULL``, then you **must** setup
:c:type:`v4l2_dev <v4l2_device>`\ ->name before calling
:c:func:`v4l2_device_register`.

You can use :c:func:`v4l2_device_set_name` to set the name based on a driver
name and a driver-global atomic_t instance. This will generate names like
``ivtv0``, ``ivtv1``, etc. If the name ends with a digit, then it will insert
a dash: ``cx18-0``, ``cx18-1``, etc. This function returns the instance number.

The first ``dev`` argument is normally the ``struct device`` pointer of a
``pci_dev``, ``usb_interface`` or ``platform_device``. It is rare for dev to
be ``NULL``, but it happens with ISA devices or when one device creates
multiple PCI devices, thus making it impossible to associate
:c:type:`v4l2_dev <v4l2_device>` with a particular parent.

You can also supply a ``notify()`` callback that can be called by sub-devices
to notify you of events. Whether you need to set this depends on the
sub-device. Any notifications a sub-device supports must be defined in a header
in ``include/media/subdevice.h``.

Unregister와 hotplug disconnect

49-69

V4L2 장치는 `v4l2_device_unregister(v4l2_dev)`로 등록 해제합니다. `dev->driver_data`가 해당 `v4l2_dev`를 가리켰다면 `NULL`로 되돌리고, 장치의 모든 sub-device도 자동으로 unregister합니다.

USB처럼 hotplug 가능한 장치는 disconnect 시 부모 device가 무효가 됩니다. `v4l2_device` 안의 부모 pointer도 지워 부모가 사라졌음을 표시해야 하며, 이를 위해 `v4l2_device_disconnect(v4l2_dev)`를 호출합니다.

`v4l2_device_disconnect()`는 sub-device를 unregister하지 않습니다. 따라서 이후 `v4l2_device_unregister()`도 호출해야 합니다. Hotplug가 아닌 driver에는 disconnect 호출이 필요 없습니다.

Hotplug 제거 순서
Hotplug event`v4l2_device_disconnect()`부모 pointer 제거
그 다음`v4l2_device_unregister()`Sub-device unregister

Disconnect는 부모 연결만 끊고 unregister가 sub-device 정리를 담당합니다.

V4L2 devices are unregistered by calling:

        :c:func:`v4l2_device_unregister`
        (:c:type:`v4l2_dev <v4l2_device>`).

If the dev->driver_data field points to :c:type:`v4l2_dev <v4l2_device>`,
it will be reset to ``NULL``. Unregistering will also automatically unregister
all subdevs from the device.

If you have a hotpluggable device (e.g. a USB device), then when a disconnect
happens the parent device becomes invalid. Since :c:type:`v4l2_device` has a
pointer to that parent device it has to be cleared as well to mark that the
parent is gone. To do this call:

        :c:func:`v4l2_device_disconnect`
        (:c:type:`v4l2_dev <v4l2_device>`).

This does *not* unregister the subdevs, so you still need to call the
:c:func:`v4l2_device_unregister` function for that. If your driver is not
hotpluggable, then there is no need to call :c:func:`v4l2_device_disconnect`.

등록 장치 순회

70-103

여러 device driver가 같은 hardware를 사용할 때 특정 driver가 등록한 모든 장치를 순회해야 할 수 있습니다. 예를 들어 framebuffer driver인 ivtvfb와 ALSA driver는 각각 ivtv hardware를 공유합니다.

예제 callback은 `dev_get_drvdata(dev)`로 `v4l2_device`를 얻고, 초기화되지 않아 `NULL`이면 건너뜁니다.

순회 함수는 `driver_find("ivtv", &pci_bus_type)`로 PCI bus의 ivtv driver를 찾고 `driver_for_each_device()`로 모든 instance에 callback을 실행합니다. USB bus라면 `usb_bus_type`을 사용합니다. 완료 후 `put_driver()`로 driver reference를 반환합니다.

Driver instance 순회
`driver_find()``device_driver`
`driver_for_each_device()``dev_get_drvdata()`각 `v4l2_device` 처리
`put_driver()`Reference 반환

Driver reference를 얻고 각 장치 callback을 실행한 뒤 reference를 반환합니다.

Sometimes you need to iterate over all devices registered by a specific
driver. This is usually the case if multiple device drivers use the same
hardware. E.g. the ivtvfb driver is a framebuffer driver that uses the ivtv
hardware. The same is true for alsa drivers for example.

You can iterate over all registered devices as follows:

.. code-block:: c

        static int callback(struct device *dev, void *p)
        {
                struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);

                /* test if this device was inited */
                if (v4l2_dev == NULL)
                        return 0;
                ...
                return 0;
        }

        int iterate(void *p)
        {
                struct device_driver *drv;
                int err;

                /* Find driver 'ivtv' on the PCI bus.
                pci_bus_type is a global. For USB buses use usb_bus_type. */
                drv = driver_find("ivtv", &pci_bus_type);
                /* iterate over all ivtv device instances */
                err = driver_for_each_device(drv, NULL, p, callback);
                put_driver(drv);
                return err;
        }

장치 instance 번호

104-118

장치 instance를 module option 배열 index에 대응시키기 위해 실행 중인 instance counter가 필요한 경우가 많습니다.

권장 방식은 driver 전역 `atomic_t`를 `ATOMIC_INIT(0)`으로 초기화하고 probe에서 `atomic_inc_return(&drv_instance) - 1`을 저장하는 것입니다. 첫 instance는 0부터 시작하며 동시 probe에도 안전합니다.

Instance 번호 할당
`ATOMIC_INIT(0)``atomic_inc_return()``- 1``state->instance`

Atomic counter를 증가시킨 반환값에서 1을 빼 0 기반 번호를 얻습니다.

Sometimes you need to keep a running counter of the device instance. This is
commonly used to map a device instance to an index of a module option array.

The recommended approach is as follows:

.. code-block:: c

        static atomic_t drv_instance = ATOMIC_INIT(0);

        static int drv_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
        {
                ...
                state->instance = atomic_inc_return(&drv_instance) - 1;
        }

Hotplug reference counting

119-142

여러 device node를 가진 hotplug 장치는 언제 `v4l2_device`를 안전하게 unregister할 수 있는지 판단하기 어렵습니다. 이를 위해 `v4l2_device`는 reference counting을 지원합니다.

`video_register_device()`가 호출될 때 refcount가 증가하고 해당 node가 release될 때 감소합니다. Refcount가 0이 되면 `v4l2_device`의 `release()` callback이 호출되므로 최종 정리를 그곳에서 수행할 수 있습니다.

ALSA 같은 다른 장치 node도 만들었다면 `v4l2_device_get()`과 `v4l2_device_put()`으로 refcount를 직접 늘리고 줄일 수 있습니다.

초기 refcount가 1이므로 USB 장치는 `disconnect()` callback에서, PCI 같은 장치는 `remove()` callback에서 `v4l2_device_put()`을 호출해야 합니다. 이 호출을 빠뜨리면 refcount가 0에 도달하지 않습니다.

v4l2_device refcount
초기 reference1
`video_register_device()`증가Node release감소
기타 node`v4l2_device_get()``v4l2_device_put()`
Disconnect·remove초기 `v4l2_device_put()`0`release()`

모든 node와 초기 reference가 반환되어야 최종 release가 실행됩니다.

If you have multiple device nodes then it can be difficult to know when it is
safe to unregister :c:type:`v4l2_device` for hotpluggable devices. For this
purpose :c:type:`v4l2_device` has refcounting support. The refcount is
increased whenever :c:func:`video_register_device` is called and it is
decreased whenever that device node is released. When the refcount reaches
zero, then the :c:type:`v4l2_device` release() callback is called. You can
do your final cleanup there.

If other device nodes (e.g. ALSA) are created, then you can increase and
decrease the refcount manually as well by calling:

        :c:func:`v4l2_device_get`
        (:c:type:`v4l2_dev <v4l2_device>`).

or:

        :c:func:`v4l2_device_put`
        (:c:type:`v4l2_dev <v4l2_device>`).

Since the initial refcount is 1 you also need to call
:c:func:`v4l2_device_put` in the ``disconnect()`` callback (for USB devices)
or in the ``remove()`` callback (for e.g. PCI devices), otherwise the refcount
will never reach 0.

v4l2_device 함수와 자료구조

143-146

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

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

v4l2_device functions and data structures
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

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