linux/drivers/media/v4l2-core/v4l2-device.c
<<
>>
Prefs
   1/*
   2    V4L2 device support.
   3
   4    Copyright (C) 2008  Hans Verkuil <hverkuil@xs4all.nl>
   5
   6    This program is free software; you can redistribute it and/or modify
   7    it under the terms of the GNU General Public License as published by
   8    the Free Software Foundation; either version 2 of the License, or
   9    (at your option) any later version.
  10
  11    This program is distributed in the hope that it will be useful,
  12    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14    GNU General Public License for more details.
  15
  16    You should have received a copy of the GNU General Public License
  17    along with this program; if not, write to the Free Software
  18    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19 */
  20
  21#include <linux/types.h>
  22#include <linux/ioctl.h>
  23#include <linux/module.h>
  24#include <linux/i2c.h>
  25#include <linux/slab.h>
  26#if defined(CONFIG_SPI)
  27#include <linux/spi/spi.h>
  28#endif
  29#include <linux/videodev2.h>
  30#include <media/v4l2-device.h>
  31#include <media/v4l2-ctrls.h>
  32
  33int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
  34{
  35        if (v4l2_dev == NULL)
  36                return -EINVAL;
  37
  38        INIT_LIST_HEAD(&v4l2_dev->subdevs);
  39        spin_lock_init(&v4l2_dev->lock);
  40        mutex_init(&v4l2_dev->ioctl_lock);
  41        v4l2_prio_init(&v4l2_dev->prio);
  42        kref_init(&v4l2_dev->ref);
  43        get_device(dev);
  44        v4l2_dev->dev = dev;
  45        if (dev == NULL) {
  46                /* If dev == NULL, then name must be filled in by the caller */
  47                WARN_ON(!v4l2_dev->name[0]);
  48                return 0;
  49        }
  50
  51        /* Set name to driver name + device name if it is empty. */
  52        if (!v4l2_dev->name[0])
  53                snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s",
  54                        dev->driver->name, dev_name(dev));
  55        if (!dev_get_drvdata(dev))
  56                dev_set_drvdata(dev, v4l2_dev);
  57        return 0;
  58}
  59EXPORT_SYMBOL_GPL(v4l2_device_register);
  60
  61static void v4l2_device_release(struct kref *ref)
  62{
  63        struct v4l2_device *v4l2_dev =
  64                container_of(ref, struct v4l2_device, ref);
  65
  66        if (v4l2_dev->release)
  67                v4l2_dev->release(v4l2_dev);
  68}
  69
  70int v4l2_device_put(struct v4l2_device *v4l2_dev)
  71{
  72        return kref_put(&v4l2_dev->ref, v4l2_device_release);
  73}
  74EXPORT_SYMBOL_GPL(v4l2_device_put);
  75
  76int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename,
  77                                                atomic_t *instance)
  78{
  79        int num = atomic_inc_return(instance) - 1;
  80        int len = strlen(basename);
  81
  82        if (basename[len - 1] >= '0' && basename[len - 1] <= '9')
  83                snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
  84                                "%s-%d", basename, num);
  85        else
  86                snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
  87                                "%s%d", basename, num);
  88        return num;
  89}
  90EXPORT_SYMBOL_GPL(v4l2_device_set_name);
  91
  92void v4l2_device_disconnect(struct v4l2_device *v4l2_dev)
  93{
  94        if (v4l2_dev->dev == NULL)
  95                return;
  96
  97        if (dev_get_drvdata(v4l2_dev->dev) == v4l2_dev)
  98                dev_set_drvdata(v4l2_dev->dev, NULL);
  99        put_device(v4l2_dev->dev);
 100        v4l2_dev->dev = NULL;
 101}
 102EXPORT_SYMBOL_GPL(v4l2_device_disconnect);
 103
 104void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
 105{
 106        struct v4l2_subdev *sd, *next;
 107
 108        if (v4l2_dev == NULL)
 109                return;
 110        v4l2_device_disconnect(v4l2_dev);
 111
 112        /* Unregister subdevs */
 113        list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list) {
 114                v4l2_device_unregister_subdev(sd);
 115#if IS_ENABLED(CONFIG_I2C)
 116                if (sd->flags & V4L2_SUBDEV_FL_IS_I2C) {
 117                        struct i2c_client *client = v4l2_get_subdevdata(sd);
 118
 119                        /* We need to unregister the i2c client explicitly.
 120                           We cannot rely on i2c_del_adapter to always
 121                           unregister clients for us, since if the i2c bus
 122                           is a platform bus, then it is never deleted. */
 123                        if (client)
 124                                i2c_unregister_device(client);
 125                        continue;
 126                }
 127#endif
 128#if defined(CONFIG_SPI)
 129                if (sd->flags & V4L2_SUBDEV_FL_IS_SPI) {
 130                        struct spi_device *spi = v4l2_get_subdevdata(sd);
 131
 132                        if (spi)
 133                                spi_unregister_device(spi);
 134                        continue;
 135                }
 136#endif
 137        }
 138}
 139EXPORT_SYMBOL_GPL(v4l2_device_unregister);
 140
 141int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
 142                                struct v4l2_subdev *sd)
 143{
 144#if defined(CONFIG_MEDIA_CONTROLLER)
 145        struct media_entity *entity = &sd->entity;
 146#endif
 147        int err;
 148
 149        /* Check for valid input */
 150        if (v4l2_dev == NULL || sd == NULL || !sd->name[0])
 151                return -EINVAL;
 152
 153        /* Warn if we apparently re-register a subdev */
 154        WARN_ON(sd->v4l2_dev != NULL);
 155
 156        if (!try_module_get(sd->owner))
 157                return -ENODEV;
 158
 159        sd->v4l2_dev = v4l2_dev;
 160        if (sd->internal_ops && sd->internal_ops->registered) {
 161                err = sd->internal_ops->registered(sd);
 162                if (err)
 163                        goto error_module;
 164        }
 165
 166        /* This just returns 0 if either of the two args is NULL */
 167        err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler, NULL);
 168        if (err)
 169                goto error_unregister;
 170
 171#if defined(CONFIG_MEDIA_CONTROLLER)
 172        /* Register the entity. */
 173        if (v4l2_dev->mdev) {
 174                err = media_device_register_entity(v4l2_dev->mdev, entity);
 175                if (err < 0)
 176                        goto error_unregister;
 177        }
 178#endif
 179
 180        spin_lock(&v4l2_dev->lock);
 181        list_add_tail(&sd->list, &v4l2_dev->subdevs);
 182        spin_unlock(&v4l2_dev->lock);
 183
 184        return 0;
 185
 186error_unregister:
 187        if (sd->internal_ops && sd->internal_ops->unregistered)
 188                sd->internal_ops->unregistered(sd);
 189error_module:
 190        module_put(sd->owner);
 191        sd->v4l2_dev = NULL;
 192        return err;
 193}
 194EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
 195
 196static void v4l2_device_release_subdev_node(struct video_device *vdev)
 197{
 198        struct v4l2_subdev *sd = video_get_drvdata(vdev);
 199        sd->devnode = NULL;
 200        kfree(vdev);
 201}
 202
 203int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
 204{
 205        struct video_device *vdev;
 206        struct v4l2_subdev *sd;
 207        int err;
 208
 209        /* Register a device node for every subdev marked with the
 210         * V4L2_SUBDEV_FL_HAS_DEVNODE flag.
 211         */
 212        list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
 213                if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
 214                        continue;
 215
 216                vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
 217                if (!vdev) {
 218                        err = -ENOMEM;
 219                        goto clean_up;
 220                }
 221
 222                video_set_drvdata(vdev, sd);
 223                strlcpy(vdev->name, sd->name, sizeof(vdev->name));
 224                vdev->v4l2_dev = v4l2_dev;
 225                vdev->fops = &v4l2_subdev_fops;
 226                vdev->release = v4l2_device_release_subdev_node;
 227                vdev->ctrl_handler = sd->ctrl_handler;
 228                err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
 229                                              sd->owner);
 230                if (err < 0) {
 231                        kfree(vdev);
 232                        goto clean_up;
 233                }
 234#if defined(CONFIG_MEDIA_CONTROLLER)
 235                sd->entity.info.v4l.major = VIDEO_MAJOR;
 236                sd->entity.info.v4l.minor = vdev->minor;
 237#endif
 238                sd->devnode = vdev;
 239        }
 240        return 0;
 241
 242clean_up:
 243        list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
 244                if (!sd->devnode)
 245                        break;
 246                video_unregister_device(sd->devnode);
 247        }
 248
 249        return err;
 250}
 251EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes);
 252
 253void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
 254{
 255        struct v4l2_device *v4l2_dev;
 256
 257        /* return if it isn't registered */
 258        if (sd == NULL || sd->v4l2_dev == NULL)
 259                return;
 260
 261        v4l2_dev = sd->v4l2_dev;
 262
 263        spin_lock(&v4l2_dev->lock);
 264        list_del(&sd->list);
 265        spin_unlock(&v4l2_dev->lock);
 266
 267        if (sd->internal_ops && sd->internal_ops->unregistered)
 268                sd->internal_ops->unregistered(sd);
 269        sd->v4l2_dev = NULL;
 270
 271#if defined(CONFIG_MEDIA_CONTROLLER)
 272        if (v4l2_dev->mdev)
 273                media_device_unregister_entity(&sd->entity);
 274#endif
 275        video_unregister_device(sd->devnode);
 276        module_put(sd->owner);
 277}
 278EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);
 279