linux/drivers/media/v4l2-core/v4l2-device.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3    V4L2 device support.
   4
   5    Copyright (C) 2008  Hans Verkuil <hverkuil@xs4all.nl>
   6
   7 */
   8
   9#include <linux/types.h>
  10#include <linux/ioctl.h>
  11#include <linux/module.h>
  12#include <linux/slab.h>
  13#include <linux/videodev2.h>
  14#include <media/v4l2-device.h>
  15#include <media/v4l2-ctrls.h>
  16
  17int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
  18{
  19        if (v4l2_dev == NULL)
  20                return -EINVAL;
  21
  22        INIT_LIST_HEAD(&v4l2_dev->subdevs);
  23        spin_lock_init(&v4l2_dev->lock);
  24        v4l2_prio_init(&v4l2_dev->prio);
  25        kref_init(&v4l2_dev->ref);
  26        get_device(dev);
  27        v4l2_dev->dev = dev;
  28        if (dev == NULL) {
  29                /* If dev == NULL, then name must be filled in by the caller */
  30                if (WARN_ON(!v4l2_dev->name[0]))
  31                        return -EINVAL;
  32                return 0;
  33        }
  34
  35        /* Set name to driver name + device name if it is empty. */
  36        if (!v4l2_dev->name[0])
  37                snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s",
  38                        dev->driver->name, dev_name(dev));
  39        if (!dev_get_drvdata(dev))
  40                dev_set_drvdata(dev, v4l2_dev);
  41        return 0;
  42}
  43EXPORT_SYMBOL_GPL(v4l2_device_register);
  44
  45static void v4l2_device_release(struct kref *ref)
  46{
  47        struct v4l2_device *v4l2_dev =
  48                container_of(ref, struct v4l2_device, ref);
  49
  50        if (v4l2_dev->release)
  51                v4l2_dev->release(v4l2_dev);
  52}
  53
  54int v4l2_device_put(struct v4l2_device *v4l2_dev)
  55{
  56        return kref_put(&v4l2_dev->ref, v4l2_device_release);
  57}
  58EXPORT_SYMBOL_GPL(v4l2_device_put);
  59
  60int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename,
  61                                                atomic_t *instance)
  62{
  63        int num = atomic_inc_return(instance) - 1;
  64        int len = strlen(basename);
  65
  66        if (basename[len - 1] >= '0' && basename[len - 1] <= '9')
  67                snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
  68                                "%s-%d", basename, num);
  69        else
  70                snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
  71                                "%s%d", basename, num);
  72        return num;
  73}
  74EXPORT_SYMBOL_GPL(v4l2_device_set_name);
  75
  76void v4l2_device_disconnect(struct v4l2_device *v4l2_dev)
  77{
  78        if (v4l2_dev->dev == NULL)
  79                return;
  80
  81        if (dev_get_drvdata(v4l2_dev->dev) == v4l2_dev)
  82                dev_set_drvdata(v4l2_dev->dev, NULL);
  83        put_device(v4l2_dev->dev);
  84        v4l2_dev->dev = NULL;
  85}
  86EXPORT_SYMBOL_GPL(v4l2_device_disconnect);
  87
  88void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
  89{
  90        struct v4l2_subdev *sd, *next;
  91
  92        /* Just return if v4l2_dev is NULL or if it was already
  93         * unregistered before. */
  94        if (v4l2_dev == NULL || !v4l2_dev->name[0])
  95                return;
  96        v4l2_device_disconnect(v4l2_dev);
  97
  98        /* Unregister subdevs */
  99        list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list) {
 100                v4l2_device_unregister_subdev(sd);
 101                if (sd->flags & V4L2_SUBDEV_FL_IS_I2C)
 102                        v4l2_i2c_subdev_unregister(sd);
 103                else if (sd->flags & V4L2_SUBDEV_FL_IS_SPI)
 104                        v4l2_spi_subdev_unregister(sd);
 105        }
 106        /* Mark as unregistered, thus preventing duplicate unregistrations */
 107        v4l2_dev->name[0] = '\0';
 108}
 109EXPORT_SYMBOL_GPL(v4l2_device_unregister);
 110
 111int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
 112                                struct v4l2_subdev *sd)
 113{
 114        int err;
 115
 116        /* Check for valid input */
 117        if (!v4l2_dev || !sd || sd->v4l2_dev || !sd->name[0])
 118                return -EINVAL;
 119
 120        /*
 121         * The reason to acquire the module here is to avoid unloading
 122         * a module of sub-device which is registered to a media
 123         * device. To make it possible to unload modules for media
 124         * devices that also register sub-devices, do not
 125         * try_module_get() such sub-device owners.
 126         */
 127        sd->owner_v4l2_dev = v4l2_dev->dev && v4l2_dev->dev->driver &&
 128                sd->owner == v4l2_dev->dev->driver->owner;
 129
 130        if (!sd->owner_v4l2_dev && !try_module_get(sd->owner))
 131                return -ENODEV;
 132
 133        sd->v4l2_dev = v4l2_dev;
 134        /* This just returns 0 if either of the two args is NULL */
 135        err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler,
 136                                    NULL, true);
 137        if (err)
 138                goto error_module;
 139
 140#if defined(CONFIG_MEDIA_CONTROLLER)
 141        /* Register the entity. */
 142        if (v4l2_dev->mdev) {
 143                err = media_device_register_entity(v4l2_dev->mdev, &sd->entity);
 144                if (err < 0)
 145                        goto error_module;
 146        }
 147#endif
 148
 149        if (sd->internal_ops && sd->internal_ops->registered) {
 150                err = sd->internal_ops->registered(sd);
 151                if (err)
 152                        goto error_unregister;
 153        }
 154
 155        spin_lock(&v4l2_dev->lock);
 156        list_add_tail(&sd->list, &v4l2_dev->subdevs);
 157        spin_unlock(&v4l2_dev->lock);
 158
 159        return 0;
 160
 161error_unregister:
 162#if defined(CONFIG_MEDIA_CONTROLLER)
 163        media_device_unregister_entity(&sd->entity);
 164#endif
 165error_module:
 166        if (!sd->owner_v4l2_dev)
 167                module_put(sd->owner);
 168        sd->v4l2_dev = NULL;
 169        return err;
 170}
 171EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
 172
 173static void v4l2_subdev_release(struct v4l2_subdev *sd)
 174{
 175        struct module *owner = !sd->owner_v4l2_dev ? sd->owner : NULL;
 176
 177        if (sd->internal_ops && sd->internal_ops->release)
 178                sd->internal_ops->release(sd);
 179        sd->devnode = NULL;
 180        module_put(owner);
 181}
 182
 183static void v4l2_device_release_subdev_node(struct video_device *vdev)
 184{
 185        v4l2_subdev_release(video_get_drvdata(vdev));
 186        kfree(vdev);
 187}
 188
 189int __v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev,
 190                                        bool read_only)
 191{
 192        struct video_device *vdev;
 193        struct v4l2_subdev *sd;
 194        int err;
 195
 196        /* Register a device node for every subdev marked with the
 197         * V4L2_SUBDEV_FL_HAS_DEVNODE flag.
 198         */
 199        list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
 200                if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
 201                        continue;
 202
 203                if (sd->devnode)
 204                        continue;
 205
 206                vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
 207                if (!vdev) {
 208                        err = -ENOMEM;
 209                        goto clean_up;
 210                }
 211
 212                video_set_drvdata(vdev, sd);
 213                strscpy(vdev->name, sd->name, sizeof(vdev->name));
 214                vdev->dev_parent = sd->dev;
 215                vdev->v4l2_dev = v4l2_dev;
 216                vdev->fops = &v4l2_subdev_fops;
 217                vdev->release = v4l2_device_release_subdev_node;
 218                vdev->ctrl_handler = sd->ctrl_handler;
 219                if (read_only)
 220                        set_bit(V4L2_FL_SUBDEV_RO_DEVNODE, &vdev->flags);
 221                sd->devnode = vdev;
 222                err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
 223                                              sd->owner);
 224                if (err < 0) {
 225                        sd->devnode = NULL;
 226                        kfree(vdev);
 227                        goto clean_up;
 228                }
 229#if defined(CONFIG_MEDIA_CONTROLLER)
 230                sd->entity.info.dev.major = VIDEO_MAJOR;
 231                sd->entity.info.dev.minor = vdev->minor;
 232
 233                /* Interface is created by __video_register_device() */
 234                if (vdev->v4l2_dev->mdev) {
 235                        struct media_link *link;
 236
 237                        link = media_create_intf_link(&sd->entity,
 238                                                      &vdev->intf_devnode->intf,
 239                                                      MEDIA_LNK_FL_ENABLED |
 240                                                      MEDIA_LNK_FL_IMMUTABLE);
 241                        if (!link) {
 242                                err = -ENOMEM;
 243                                goto clean_up;
 244                        }
 245                }
 246#endif
 247        }
 248        return 0;
 249
 250clean_up:
 251        list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
 252                if (!sd->devnode)
 253                        break;
 254                video_unregister_device(sd->devnode);
 255        }
 256
 257        return err;
 258}
 259EXPORT_SYMBOL_GPL(__v4l2_device_register_subdev_nodes);
 260
 261void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
 262{
 263        struct v4l2_device *v4l2_dev;
 264
 265        /* return if it isn't registered */
 266        if (sd == NULL || sd->v4l2_dev == NULL)
 267                return;
 268
 269        v4l2_dev = sd->v4l2_dev;
 270
 271        spin_lock(&v4l2_dev->lock);
 272        list_del(&sd->list);
 273        spin_unlock(&v4l2_dev->lock);
 274
 275        if (sd->internal_ops && sd->internal_ops->unregistered)
 276                sd->internal_ops->unregistered(sd);
 277        sd->v4l2_dev = NULL;
 278
 279#if defined(CONFIG_MEDIA_CONTROLLER)
 280        if (v4l2_dev->mdev) {
 281                /*
 282                 * No need to explicitly remove links, as both pads and
 283                 * links are removed by the function below, in the right order
 284                 */
 285                media_device_unregister_entity(&sd->entity);
 286        }
 287#endif
 288        if (sd->devnode)
 289                video_unregister_device(sd->devnode);
 290        else
 291                v4l2_subdev_release(sd);
 292}
 293EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);
 294