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