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#if defined(CONFIG_MEDIA_CONTROLLER)
 115        struct media_entity *entity = &sd->entity;
 116#endif
 117        int err;
 118
 119        /* Check for valid input */
 120        if (!v4l2_dev || !sd || sd->v4l2_dev || !sd->name[0])
 121                return -EINVAL;
 122
 123        /*
 124         * The reason to acquire the module here is to avoid unloading
 125         * a module of sub-device which is registered to a media
 126         * device. To make it possible to unload modules for media
 127         * devices that also register sub-devices, do not
 128         * try_module_get() such sub-device owners.
 129         */
 130        sd->owner_v4l2_dev = v4l2_dev->dev && v4l2_dev->dev->driver &&
 131                sd->owner == v4l2_dev->dev->driver->owner;
 132
 133        if (!sd->owner_v4l2_dev && !try_module_get(sd->owner))
 134                return -ENODEV;
 135
 136        sd->v4l2_dev = v4l2_dev;
 137        /* This just returns 0 if either of the two args is NULL */
 138        err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler,
 139                                    NULL, true);
 140        if (err)
 141                goto error_module;
 142
 143#if defined(CONFIG_MEDIA_CONTROLLER)
 144        /* Register the entity. */
 145        if (v4l2_dev->mdev) {
 146                err = media_device_register_entity(v4l2_dev->mdev, entity);
 147                if (err < 0)
 148                        goto error_module;
 149        }
 150#endif
 151
 152        if (sd->internal_ops && sd->internal_ops->registered) {
 153                err = sd->internal_ops->registered(sd);
 154                if (err)
 155                        goto error_unregister;
 156        }
 157
 158        spin_lock(&v4l2_dev->lock);
 159        list_add_tail(&sd->list, &v4l2_dev->subdevs);
 160        spin_unlock(&v4l2_dev->lock);
 161
 162        return 0;
 163
 164error_unregister:
 165#if defined(CONFIG_MEDIA_CONTROLLER)
 166        media_device_unregister_entity(entity);
 167#endif
 168error_module:
 169        if (!sd->owner_v4l2_dev)
 170                module_put(sd->owner);
 171        sd->v4l2_dev = NULL;
 172        return err;
 173}
 174EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
 175
 176static void v4l2_subdev_release(struct v4l2_subdev *sd)
 177{
 178        struct module *owner = !sd->owner_v4l2_dev ? sd->owner : NULL;
 179
 180        if (sd->internal_ops && sd->internal_ops->release)
 181                sd->internal_ops->release(sd);
 182        module_put(owner);
 183}
 184
 185static void v4l2_device_release_subdev_node(struct video_device *vdev)
 186{
 187        v4l2_subdev_release(video_get_drvdata(vdev));
 188        kfree(vdev);
 189}
 190
 191int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
 192{
 193        struct video_device *vdev;
 194        struct v4l2_subdev *sd;
 195        int err;
 196
 197        /* Register a device node for every subdev marked with the
 198         * V4L2_SUBDEV_FL_HAS_DEVNODE flag.
 199         */
 200        list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
 201                if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
 202                        continue;
 203
 204                if (sd->devnode)
 205                        continue;
 206
 207                vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
 208                if (!vdev) {
 209                        err = -ENOMEM;
 210                        goto clean_up;
 211                }
 212
 213                video_set_drvdata(vdev, sd);
 214                strscpy(vdev->name, sd->name, sizeof(vdev->name));
 215                vdev->dev_parent = sd->dev;
 216                vdev->v4l2_dev = v4l2_dev;
 217                vdev->fops = &v4l2_subdev_fops;
 218                vdev->release = v4l2_device_release_subdev_node;
 219                vdev->ctrl_handler = sd->ctrl_handler;
 220                err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
 221                                              sd->owner);
 222                if (err < 0) {
 223                        kfree(vdev);
 224                        goto clean_up;
 225                }
 226                sd->devnode = vdev;
 227#if defined(CONFIG_MEDIA_CONTROLLER)
 228                sd->entity.info.dev.major = VIDEO_MAJOR;
 229                sd->entity.info.dev.minor = vdev->minor;
 230
 231                /* Interface is created by __video_register_device() */
 232                if (vdev->v4l2_dev->mdev) {
 233                        struct media_link *link;
 234
 235                        link = media_create_intf_link(&sd->entity,
 236                                                      &vdev->intf_devnode->intf,
 237                                                      MEDIA_LNK_FL_ENABLED |
 238                                                      MEDIA_LNK_FL_IMMUTABLE);
 239                        if (!link) {
 240                                err = -ENOMEM;
 241                                goto clean_up;
 242                        }
 243                }
 244#endif
 245        }
 246        return 0;
 247
 248clean_up:
 249        list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
 250                if (!sd->devnode)
 251                        break;
 252                video_unregister_device(sd->devnode);
 253        }
 254
 255        return err;
 256}
 257EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes);
 258
 259void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
 260{
 261        struct v4l2_device *v4l2_dev;
 262
 263        /* return if it isn't registered */
 264        if (sd == NULL || sd->v4l2_dev == NULL)
 265                return;
 266
 267        v4l2_dev = sd->v4l2_dev;
 268
 269        spin_lock(&v4l2_dev->lock);
 270        list_del(&sd->list);
 271        spin_unlock(&v4l2_dev->lock);
 272
 273        if (sd->internal_ops && sd->internal_ops->unregistered)
 274                sd->internal_ops->unregistered(sd);
 275        sd->v4l2_dev = NULL;
 276
 277#if defined(CONFIG_MEDIA_CONTROLLER)
 278        if (v4l2_dev->mdev) {
 279                /*
 280                 * No need to explicitly remove links, as both pads and
 281                 * links are removed by the function below, in the right order
 282                 */
 283                media_device_unregister_entity(&sd->entity);
 284        }
 285#endif
 286        if (sd->devnode)
 287                video_unregister_device(sd->devnode);
 288        else
 289                v4l2_subdev_release(sd);
 290}
 291EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);
 292