root/drivers/media/v4l2-core/v4l2-device.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. v4l2_device_register
  2. v4l2_device_release
  3. v4l2_device_put
  4. v4l2_device_set_name
  5. v4l2_device_disconnect
  6. v4l2_device_unregister
  7. v4l2_device_register_subdev
  8. v4l2_subdev_release
  9. v4l2_device_release_subdev_node
  10. v4l2_device_register_subdev_nodes
  11. v4l2_device_unregister_subdev

   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 
  17 int 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 }
  43 EXPORT_SYMBOL_GPL(v4l2_device_register);
  44 
  45 static 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 
  54 int v4l2_device_put(struct v4l2_device *v4l2_dev)
  55 {
  56         return kref_put(&v4l2_dev->ref, v4l2_device_release);
  57 }
  58 EXPORT_SYMBOL_GPL(v4l2_device_put);
  59 
  60 int 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 }
  74 EXPORT_SYMBOL_GPL(v4l2_device_set_name);
  75 
  76 void 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 }
  86 EXPORT_SYMBOL_GPL(v4l2_device_disconnect);
  87 
  88 void 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 }
 109 EXPORT_SYMBOL_GPL(v4l2_device_unregister);
 110 
 111 int 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 
 164 error_unregister:
 165 #if defined(CONFIG_MEDIA_CONTROLLER)
 166         media_device_unregister_entity(entity);
 167 #endif
 168 error_module:
 169         if (!sd->owner_v4l2_dev)
 170                 module_put(sd->owner);
 171         sd->v4l2_dev = NULL;
 172         return err;
 173 }
 174 EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
 175 
 176 static 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         sd->devnode = NULL;
 183         module_put(owner);
 184 }
 185 
 186 static void v4l2_device_release_subdev_node(struct video_device *vdev)
 187 {
 188         v4l2_subdev_release(video_get_drvdata(vdev));
 189         kfree(vdev);
 190 }
 191 
 192 int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
 193 {
 194         struct video_device *vdev;
 195         struct v4l2_subdev *sd;
 196         int err;
 197 
 198         /* Register a device node for every subdev marked with the
 199          * V4L2_SUBDEV_FL_HAS_DEVNODE flag.
 200          */
 201         list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
 202                 if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
 203                         continue;
 204 
 205                 if (sd->devnode)
 206                         continue;
 207 
 208                 vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
 209                 if (!vdev) {
 210                         err = -ENOMEM;
 211                         goto clean_up;
 212                 }
 213 
 214                 video_set_drvdata(vdev, sd);
 215                 strscpy(vdev->name, sd->name, sizeof(vdev->name));
 216                 vdev->dev_parent = sd->dev;
 217                 vdev->v4l2_dev = v4l2_dev;
 218                 vdev->fops = &v4l2_subdev_fops;
 219                 vdev->release = v4l2_device_release_subdev_node;
 220                 vdev->ctrl_handler = sd->ctrl_handler;
 221                 err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
 222                                               sd->owner);
 223                 if (err < 0) {
 224                         kfree(vdev);
 225                         goto clean_up;
 226                 }
 227                 sd->devnode = vdev;
 228 #if defined(CONFIG_MEDIA_CONTROLLER)
 229                 sd->entity.info.dev.major = VIDEO_MAJOR;
 230                 sd->entity.info.dev.minor = vdev->minor;
 231 
 232                 /* Interface is created by __video_register_device() */
 233                 if (vdev->v4l2_dev->mdev) {
 234                         struct media_link *link;
 235 
 236                         link = media_create_intf_link(&sd->entity,
 237                                                       &vdev->intf_devnode->intf,
 238                                                       MEDIA_LNK_FL_ENABLED |
 239                                                       MEDIA_LNK_FL_IMMUTABLE);
 240                         if (!link) {
 241                                 err = -ENOMEM;
 242                                 goto clean_up;
 243                         }
 244                 }
 245 #endif
 246         }
 247         return 0;
 248 
 249 clean_up:
 250         list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
 251                 if (!sd->devnode)
 252                         break;
 253                 video_unregister_device(sd->devnode);
 254         }
 255 
 256         return err;
 257 }
 258 EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes);
 259 
 260 void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
 261 {
 262         struct v4l2_device *v4l2_dev;
 263 
 264         /* return if it isn't registered */
 265         if (sd == NULL || sd->v4l2_dev == NULL)
 266                 return;
 267 
 268         v4l2_dev = sd->v4l2_dev;
 269 
 270         spin_lock(&v4l2_dev->lock);
 271         list_del(&sd->list);
 272         spin_unlock(&v4l2_dev->lock);
 273 
 274         if (sd->internal_ops && sd->internal_ops->unregistered)
 275                 sd->internal_ops->unregistered(sd);
 276         sd->v4l2_dev = NULL;
 277 
 278 #if defined(CONFIG_MEDIA_CONTROLLER)
 279         if (v4l2_dev->mdev) {
 280                 /*
 281                  * No need to explicitly remove links, as both pads and
 282                  * links are removed by the function below, in the right order
 283                  */
 284                 media_device_unregister_entity(&sd->entity);
 285         }
 286 #endif
 287         if (sd->devnode)
 288                 video_unregister_device(sd->devnode);
 289         else
 290                 v4l2_subdev_release(sd);
 291 }
 292 EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);

/* [<][>][^][v][top][bottom][index][help] */