linux/drivers/media/video/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/i2c.h>
  24#if defined(CONFIG_SPI)
  25#include <linux/spi/spi.h>
  26#endif
  27#include <linux/videodev2.h>
  28#include <media/v4l2-device.h>
  29#include <media/v4l2-ctrls.h>
  30
  31int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
  32{
  33        if (v4l2_dev == NULL)
  34                return -EINVAL;
  35
  36        INIT_LIST_HEAD(&v4l2_dev->subdevs);
  37        spin_lock_init(&v4l2_dev->lock);
  38        mutex_init(&v4l2_dev->ioctl_lock);
  39        v4l2_prio_init(&v4l2_dev->prio);
  40        kref_init(&v4l2_dev->ref);
  41        v4l2_dev->dev = dev;
  42        if (dev == NULL) {
  43                /* If dev == NULL, then name must be filled in by the caller */
  44                WARN_ON(!v4l2_dev->name[0]);
  45                return 0;
  46        }
  47
  48        /* Set name to driver name + device name if it is empty. */
  49        if (!v4l2_dev->name[0])
  50                snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s",
  51                        dev->driver->name, dev_name(dev));
  52        if (!dev_get_drvdata(dev))
  53                dev_set_drvdata(dev, v4l2_dev);
  54        return 0;
  55}
  56EXPORT_SYMBOL_GPL(v4l2_device_register);
  57
  58static void v4l2_device_release(struct kref *ref)
  59{
  60        struct v4l2_device *v4l2_dev =
  61                container_of(ref, struct v4l2_device, ref);
  62
  63        if (v4l2_dev->release)
  64                v4l2_dev->release(v4l2_dev);
  65}
  66
  67int v4l2_device_put(struct v4l2_device *v4l2_dev)
  68{
  69        return kref_put(&v4l2_dev->ref, v4l2_device_release);
  70}
  71EXPORT_SYMBOL_GPL(v4l2_device_put);
  72
  73int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename,
  74                                                atomic_t *instance)
  75{
  76        int num = atomic_inc_return(instance) - 1;
  77        int len = strlen(basename);
  78
  79        if (basename[len - 1] >= '0' && basename[len - 1] <= '9')
  80                snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
  81                                "%s-%d", basename, num);
  82        else
  83                snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
  84                                "%s%d", basename, num);
  85        return num;
  86}
  87EXPORT_SYMBOL_GPL(v4l2_device_set_name);
  88
  89void v4l2_device_disconnect(struct v4l2_device *v4l2_dev)
  90{
  91        if (v4l2_dev->dev == NULL)
  92                return;
  93
  94        if (dev_get_drvdata(v4l2_dev->dev) == v4l2_dev)
  95                dev_set_drvdata(v4l2_dev->dev, NULL);
  96        v4l2_dev->dev = NULL;
  97}
  98EXPORT_SYMBOL_GPL(v4l2_device_disconnect);
  99
 100void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
 101{
 102        struct v4l2_subdev *sd, *next;
 103
 104        if (v4l2_dev == NULL)
 105                return;
 106        v4l2_device_disconnect(v4l2_dev);
 107
 108        /* Unregister subdevs */
 109        list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list) {
 110                v4l2_device_unregister_subdev(sd);
 111#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
 112                if (sd->flags & V4L2_SUBDEV_FL_IS_I2C) {
 113                        struct i2c_client *client = v4l2_get_subdevdata(sd);
 114
 115                        /* We need to unregister the i2c client explicitly.
 116                           We cannot rely on i2c_del_adapter to always
 117                           unregister clients for us, since if the i2c bus
 118                           is a platform bus, then it is never deleted. */
 119                        if (client)
 120                                i2c_unregister_device(client);
 121                        continue;
 122                }
 123#endif
 124#if defined(CONFIG_SPI)
 125                if (sd->flags & V4L2_SUBDEV_FL_IS_SPI) {
 126                        struct spi_device *spi = v4l2_get_subdevdata(sd);
 127
 128                        if (spi)
 129                                spi_unregister_device(spi);
 130                        continue;
 131                }
 132#endif
 133        }
 134}
 135EXPORT_SYMBOL_GPL(v4l2_device_unregister);
 136
 137int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
 138                                struct v4l2_subdev *sd)
 139{
 140#if defined(CONFIG_MEDIA_CONTROLLER)
 141        struct media_entity *entity = &sd->entity;
 142#endif
 143        int err;
 144
 145        /* Check for valid input */
 146        if (v4l2_dev == NULL || sd == NULL || !sd->name[0])
 147                return -EINVAL;
 148
 149        /* Warn if we apparently re-register a subdev */
 150        WARN_ON(sd->v4l2_dev != NULL);
 151
 152        if (!try_module_get(sd->owner))
 153                return -ENODEV;
 154
 155        sd->v4l2_dev = v4l2_dev;
 156        if (sd->internal_ops && sd->internal_ops->registered) {
 157                err = sd->internal_ops->registered(sd);
 158                if (err) {
 159                        module_put(sd->owner);
 160                        return err;
 161                }
 162        }
 163
 164        /* This just returns 0 if either of the two args is NULL */
 165        err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler);
 166        if (err) {
 167                if (sd->internal_ops && sd->internal_ops->unregistered)
 168                        sd->internal_ops->unregistered(sd);
 169                module_put(sd->owner);
 170                return err;
 171        }
 172
 173#if defined(CONFIG_MEDIA_CONTROLLER)
 174        /* Register the entity. */
 175        if (v4l2_dev->mdev) {
 176                err = media_device_register_entity(v4l2_dev->mdev, entity);
 177                if (err < 0) {
 178                        if (sd->internal_ops && sd->internal_ops->unregistered)
 179                                sd->internal_ops->unregistered(sd);
 180                        module_put(sd->owner);
 181                        return err;
 182                }
 183        }
 184#endif
 185
 186        spin_lock(&v4l2_dev->lock);
 187        list_add_tail(&sd->list, &v4l2_dev->subdevs);
 188        spin_unlock(&v4l2_dev->lock);
 189
 190        return 0;
 191}
 192EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
 193
 194int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
 195{
 196        struct video_device *vdev;
 197        struct v4l2_subdev *sd;
 198        int err;
 199
 200        /* Register a device node for every subdev marked with the
 201         * V4L2_SUBDEV_FL_HAS_DEVNODE flag.
 202         */
 203        list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
 204                if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
 205                        continue;
 206
 207                vdev = &sd->devnode;
 208                strlcpy(vdev->name, sd->name, sizeof(vdev->name));
 209                vdev->v4l2_dev = v4l2_dev;
 210                vdev->fops = &v4l2_subdev_fops;
 211                vdev->release = video_device_release_empty;
 212                err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
 213                                              sd->owner);
 214                if (err < 0)
 215                        return err;
 216#if defined(CONFIG_MEDIA_CONTROLLER)
 217                sd->entity.v4l.major = VIDEO_MAJOR;
 218                sd->entity.v4l.minor = vdev->minor;
 219#endif
 220        }
 221        return 0;
 222}
 223EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes);
 224
 225void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
 226{
 227        struct v4l2_device *v4l2_dev;
 228
 229        /* return if it isn't registered */
 230        if (sd == NULL || sd->v4l2_dev == NULL)
 231                return;
 232
 233        v4l2_dev = sd->v4l2_dev;
 234
 235        spin_lock(&v4l2_dev->lock);
 236        list_del(&sd->list);
 237        spin_unlock(&v4l2_dev->lock);
 238
 239        if (sd->internal_ops && sd->internal_ops->unregistered)
 240                sd->internal_ops->unregistered(sd);
 241        sd->v4l2_dev = NULL;
 242
 243#if defined(CONFIG_MEDIA_CONTROLLER)
 244        if (v4l2_dev->mdev)
 245                media_device_unregister_entity(&sd->entity);
 246#endif
 247        video_unregister_device(&sd->devnode);
 248        module_put(sd->owner);
 249}
 250EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);
 251