linux/drivers/media/media-devnode.c
<<
>>
Prefs
   1/*
   2 * Media device node
   3 *
   4 * Copyright (C) 2010 Nokia Corporation
   5 *
   6 * Based on drivers/media/video/v4l2_dev.c code authored by
   7 *      Mauro Carvalho Chehab <mchehab@infradead.org> (version 2)
   8 *      Alan Cox, <alan@lxorguk.ukuu.org.uk> (version 1)
   9 *
  10 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
  11 *           Sakari Ailus <sakari.ailus@iki.fi>
  12 *
  13 * This program is free software; you can redistribute it and/or modify
  14 * it under the terms of the GNU General Public License version 2 as
  15 * published by the Free Software Foundation.
  16 *
  17 * This program is distributed in the hope that it will be useful,
  18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20 * GNU General Public License for more details.
  21 *
  22 * --
  23 *
  24 * Generic media device node infrastructure to register and unregister
  25 * character devices using a dynamic major number and proper reference
  26 * counting.
  27 */
  28
  29#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  30
  31#include <linux/errno.h>
  32#include <linux/init.h>
  33#include <linux/module.h>
  34#include <linux/kernel.h>
  35#include <linux/kmod.h>
  36#include <linux/slab.h>
  37#include <linux/mm.h>
  38#include <linux/string.h>
  39#include <linux/types.h>
  40#include <linux/uaccess.h>
  41
  42#include <media/media-devnode.h>
  43#include <media/media-device.h>
  44
  45#define MEDIA_NUM_DEVICES       256
  46#define MEDIA_NAME              "media"
  47
  48static dev_t media_dev_t;
  49
  50/*
  51 *      Active devices
  52 */
  53static DEFINE_MUTEX(media_devnode_lock);
  54static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES);
  55
  56/* Called when the last user of the media device exits. */
  57static void media_devnode_release(struct device *cd)
  58{
  59        struct media_devnode *devnode = to_media_devnode(cd);
  60
  61        mutex_lock(&media_devnode_lock);
  62        /* Mark device node number as free */
  63        clear_bit(devnode->minor, media_devnode_nums);
  64        mutex_unlock(&media_devnode_lock);
  65
  66        /* Release media_devnode and perform other cleanups as needed. */
  67        if (devnode->release)
  68                devnode->release(devnode);
  69
  70        kfree(devnode);
  71        pr_debug("%s: Media Devnode Deallocated\n", __func__);
  72}
  73
  74static struct bus_type media_bus_type = {
  75        .name = MEDIA_NAME,
  76};
  77
  78static ssize_t media_read(struct file *filp, char __user *buf,
  79                size_t sz, loff_t *off)
  80{
  81        struct media_devnode *devnode = media_devnode_data(filp);
  82
  83        if (!devnode->fops->read)
  84                return -EINVAL;
  85        if (!media_devnode_is_registered(devnode))
  86                return -EIO;
  87        return devnode->fops->read(filp, buf, sz, off);
  88}
  89
  90static ssize_t media_write(struct file *filp, const char __user *buf,
  91                size_t sz, loff_t *off)
  92{
  93        struct media_devnode *devnode = media_devnode_data(filp);
  94
  95        if (!devnode->fops->write)
  96                return -EINVAL;
  97        if (!media_devnode_is_registered(devnode))
  98                return -EIO;
  99        return devnode->fops->write(filp, buf, sz, off);
 100}
 101
 102static unsigned int media_poll(struct file *filp,
 103                               struct poll_table_struct *poll)
 104{
 105        struct media_devnode *devnode = media_devnode_data(filp);
 106
 107        if (!media_devnode_is_registered(devnode))
 108                return POLLERR | POLLHUP;
 109        if (!devnode->fops->poll)
 110                return DEFAULT_POLLMASK;
 111        return devnode->fops->poll(filp, poll);
 112}
 113
 114static long
 115__media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg,
 116              long (*ioctl_func)(struct file *filp, unsigned int cmd,
 117                                 unsigned long arg))
 118{
 119        struct media_devnode *devnode = media_devnode_data(filp);
 120
 121        if (!ioctl_func)
 122                return -ENOTTY;
 123
 124        if (!media_devnode_is_registered(devnode))
 125                return -EIO;
 126
 127        return ioctl_func(filp, cmd, arg);
 128}
 129
 130static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 131{
 132        struct media_devnode *devnode = media_devnode_data(filp);
 133
 134        return __media_ioctl(filp, cmd, arg, devnode->fops->ioctl);
 135}
 136
 137#ifdef CONFIG_COMPAT
 138
 139static long media_compat_ioctl(struct file *filp, unsigned int cmd,
 140                               unsigned long arg)
 141{
 142        struct media_devnode *devnode = media_devnode_data(filp);
 143
 144        return __media_ioctl(filp, cmd, arg, devnode->fops->compat_ioctl);
 145}
 146
 147#endif /* CONFIG_COMPAT */
 148
 149/* Override for the open function */
 150static int media_open(struct inode *inode, struct file *filp)
 151{
 152        struct media_devnode *devnode;
 153        int ret;
 154
 155        /* Check if the media device is available. This needs to be done with
 156         * the media_devnode_lock held to prevent an open/unregister race:
 157         * without the lock, the device could be unregistered and freed between
 158         * the media_devnode_is_registered() and get_device() calls, leading to
 159         * a crash.
 160         */
 161        mutex_lock(&media_devnode_lock);
 162        devnode = container_of(inode->i_cdev, struct media_devnode, cdev);
 163        /* return ENXIO if the media device has been removed
 164           already or if it is not registered anymore. */
 165        if (!media_devnode_is_registered(devnode)) {
 166                mutex_unlock(&media_devnode_lock);
 167                return -ENXIO;
 168        }
 169        /* and increase the device refcount */
 170        get_device(&devnode->dev);
 171        mutex_unlock(&media_devnode_lock);
 172
 173        filp->private_data = devnode;
 174
 175        if (devnode->fops->open) {
 176                ret = devnode->fops->open(filp);
 177                if (ret) {
 178                        put_device(&devnode->dev);
 179                        filp->private_data = NULL;
 180                        return ret;
 181                }
 182        }
 183
 184        return 0;
 185}
 186
 187/* Override for the release function */
 188static int media_release(struct inode *inode, struct file *filp)
 189{
 190        struct media_devnode *devnode = media_devnode_data(filp);
 191
 192        if (devnode->fops->release)
 193                devnode->fops->release(filp);
 194
 195        filp->private_data = NULL;
 196
 197        /* decrease the refcount unconditionally since the release()
 198           return value is ignored. */
 199        put_device(&devnode->dev);
 200
 201        pr_debug("%s: Media Release\n", __func__);
 202        return 0;
 203}
 204
 205static const struct file_operations media_devnode_fops = {
 206        .owner = THIS_MODULE,
 207        .read = media_read,
 208        .write = media_write,
 209        .open = media_open,
 210        .unlocked_ioctl = media_ioctl,
 211#ifdef CONFIG_COMPAT
 212        .compat_ioctl = media_compat_ioctl,
 213#endif /* CONFIG_COMPAT */
 214        .release = media_release,
 215        .poll = media_poll,
 216        .llseek = no_llseek,
 217};
 218
 219int __must_check media_devnode_register(struct media_device *mdev,
 220                                        struct media_devnode *devnode,
 221                                        struct module *owner)
 222{
 223        int minor;
 224        int ret;
 225
 226        /* Part 1: Find a free minor number */
 227        mutex_lock(&media_devnode_lock);
 228        minor = find_next_zero_bit(media_devnode_nums, MEDIA_NUM_DEVICES, 0);
 229        if (minor == MEDIA_NUM_DEVICES) {
 230                mutex_unlock(&media_devnode_lock);
 231                pr_err("could not get a free minor\n");
 232                kfree(devnode);
 233                return -ENFILE;
 234        }
 235
 236        set_bit(minor, media_devnode_nums);
 237        mutex_unlock(&media_devnode_lock);
 238
 239        devnode->minor = minor;
 240        devnode->media_dev = mdev;
 241
 242        /* Part 1: Initialize dev now to use dev.kobj for cdev.kobj.parent */
 243        devnode->dev.bus = &media_bus_type;
 244        devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor);
 245        devnode->dev.release = media_devnode_release;
 246        if (devnode->parent)
 247                devnode->dev.parent = devnode->parent;
 248        dev_set_name(&devnode->dev, "media%d", devnode->minor);
 249        device_initialize(&devnode->dev);
 250
 251        /* Part 2: Initialize the character device */
 252        cdev_init(&devnode->cdev, &media_devnode_fops);
 253        devnode->cdev.owner = owner;
 254
 255        /* Part 3: Add the media and char device */
 256        ret = cdev_device_add(&devnode->cdev, &devnode->dev);
 257        if (ret < 0) {
 258                pr_err("%s: cdev_device_add failed\n", __func__);
 259                goto cdev_add_error;
 260        }
 261
 262        /* Part 4: Activate this minor. The char device can now be used. */
 263        set_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
 264
 265        return 0;
 266
 267cdev_add_error:
 268        mutex_lock(&media_devnode_lock);
 269        clear_bit(devnode->minor, media_devnode_nums);
 270        devnode->media_dev = NULL;
 271        mutex_unlock(&media_devnode_lock);
 272
 273        put_device(&devnode->dev);
 274        return ret;
 275}
 276
 277void media_devnode_unregister_prepare(struct media_devnode *devnode)
 278{
 279        /* Check if devnode was ever registered at all */
 280        if (!media_devnode_is_registered(devnode))
 281                return;
 282
 283        mutex_lock(&media_devnode_lock);
 284        clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
 285        mutex_unlock(&media_devnode_lock);
 286}
 287
 288void media_devnode_unregister(struct media_devnode *devnode)
 289{
 290        mutex_lock(&media_devnode_lock);
 291        /* Delete the cdev on this minor as well */
 292        cdev_device_del(&devnode->cdev, &devnode->dev);
 293        mutex_unlock(&media_devnode_lock);
 294        devnode->media_dev = NULL;
 295        put_device(&devnode->dev);
 296}
 297
 298/*
 299 *      Initialise media for linux
 300 */
 301static int __init media_devnode_init(void)
 302{
 303        int ret;
 304
 305        pr_info("Linux media interface: v0.10\n");
 306        ret = alloc_chrdev_region(&media_dev_t, 0, MEDIA_NUM_DEVICES,
 307                                  MEDIA_NAME);
 308        if (ret < 0) {
 309                pr_warn("unable to allocate major\n");
 310                return ret;
 311        }
 312
 313        ret = bus_register(&media_bus_type);
 314        if (ret < 0) {
 315                unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
 316                pr_warn("bus_register failed\n");
 317                return -EIO;
 318        }
 319
 320        return 0;
 321}
 322
 323static void __exit media_devnode_exit(void)
 324{
 325        bus_unregister(&media_bus_type);
 326        unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
 327}
 328
 329subsys_initcall(media_devnode_init);
 330module_exit(media_devnode_exit)
 331
 332MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
 333MODULE_DESCRIPTION("Device node registration for media drivers");
 334MODULE_LICENSE("GPL");
 335