summaryrefslogtreecommitdiffstats
path: root/Documentation/driver-api/media/v4l2-device.rst
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:49:45 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:49:45 +0000
commit2c3c1048746a4622d8c89a29670120dc8fab93c4 (patch)
tree848558de17fb3008cdf4d861b01ac7781903ce39 /Documentation/driver-api/media/v4l2-device.rst
parentInitial commit. (diff)
downloadlinux-upstream.tar.xz
linux-upstream.zip
Adding upstream version 6.1.76.upstream/6.1.76upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'Documentation/driver-api/media/v4l2-device.rst')
-rw-r--r--Documentation/driver-api/media/v4l2-device.rst146
1 files changed, 146 insertions, 0 deletions
diff --git a/Documentation/driver-api/media/v4l2-device.rst b/Documentation/driver-api/media/v4l2-device.rst
new file mode 100644
index 000000000..7bd9c45f5
--- /dev/null
+++ b/Documentation/driver-api/media/v4l2-device.rst
@@ -0,0 +1,146 @@
+.. 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``.
+
+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`.
+
+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;
+ }
+
+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;
+ }
+
+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 functions and data structures
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. kernel-doc:: include/media/v4l2-device.h