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 * You should have received a copy of the GNU General Public License
  23 * along with this program; if not, write to the Free Software
  24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  25 *
  26 * --
  27 *
  28 * Generic media device node infrastructure to register and unregister
  29 * character devices using a dynamic major number and proper reference
  30 * counting.
  31 */
  32
  33#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  34
  35#include <linux/errno.h>
  36#include <linux/init.h>
  37#include <linux/module.h>
  38#include <linux/kernel.h>
  39#include <linux/kmod.h>
  40#include <linux/slab.h>
  41#include <linux/mm.h>
  42#include <linux/string.h>
  43#include <linux/types.h>
  44#include <linux/uaccess.h>
  45
  46#include <media/media-devnode.h>
  47
  48#define MEDIA_NUM_DEVICES       256
  49#define MEDIA_NAME              "media"
  50
  51static dev_t media_dev_t;
  52
  53/*
  54 *      Active devices
  55 */
  56static DEFINE_MUTEX(media_devnode_lock);
  57static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES);
  58
  59/* Called when the last user of the media device exits. */
  60static void media_devnode_release(struct device *cd)
  61{
  62        struct media_devnode *mdev = to_media_devnode(cd);
  63
  64        mutex_lock(&media_devnode_lock);
  65
  66        /* Delete the cdev on this minor as well */
  67        cdev_del(&mdev->cdev);
  68
  69        /* Mark device node number as free */
  70        clear_bit(mdev->minor, media_devnode_nums);
  71
  72        mutex_unlock(&media_devnode_lock);
  73
  74        /* Release media_devnode and perform other cleanups as needed. */
  75        if (mdev->release)
  76                mdev->release(mdev);
  77}
  78
  79static struct bus_type media_bus_type = {
  80        .name = MEDIA_NAME,
  81};
  82
  83static ssize_t media_read(struct file *filp, char __user *buf,
  84                size_t sz, loff_t *off)
  85{
  86        struct media_devnode *mdev = media_devnode_data(filp);
  87
  88        if (!mdev->fops->read)
  89                return -EINVAL;
  90        if (!media_devnode_is_registered(mdev))
  91                return -EIO;
  92        return mdev->fops->read(filp, buf, sz, off);
  93}
  94
  95static ssize_t media_write(struct file *filp, const char __user *buf,
  96                size_t sz, loff_t *off)
  97{
  98        struct media_devnode *mdev = media_devnode_data(filp);
  99
 100        if (!mdev->fops->write)
 101                return -EINVAL;
 102        if (!media_devnode_is_registered(mdev))
 103                return -EIO;
 104        return mdev->fops->write(filp, buf, sz, off);
 105}
 106
 107static unsigned int media_poll(struct file *filp,
 108                               struct poll_table_struct *poll)
 109{
 110        struct media_devnode *mdev = media_devnode_data(filp);
 111
 112        if (!media_devnode_is_registered(mdev))
 113                return POLLERR | POLLHUP;
 114        if (!mdev->fops->poll)
 115                return DEFAULT_POLLMASK;
 116        return mdev->fops->poll(filp, poll);
 117}
 118
 119static long
 120__media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg,
 121              long (*ioctl_func)(struct file *filp, unsigned int cmd,
 122                                 unsigned long arg))
 123{
 124        struct media_devnode *mdev = media_devnode_data(filp);
 125
 126        if (!ioctl_func)
 127                return -ENOTTY;
 128
 129        if (!media_devnode_is_registered(mdev))
 130                return -EIO;
 131
 132        return ioctl_func(filp, cmd, arg);
 133}
 134
 135static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 136{
 137        struct media_devnode *mdev = media_devnode_data(filp);
 138
 139        return __media_ioctl(filp, cmd, arg, mdev->fops->ioctl);
 140}
 141
 142#ifdef CONFIG_COMPAT
 143
 144static long media_compat_ioctl(struct file *filp, unsigned int cmd,
 145                               unsigned long arg)
 146{
 147        struct media_devnode *mdev = media_devnode_data(filp);
 148
 149        return __media_ioctl(filp, cmd, arg, mdev->fops->compat_ioctl);
 150}
 151
 152#endif /* CONFIG_COMPAT */
 153
 154/* Override for the open function */
 155static int media_open(struct inode *inode, struct file *filp)
 156{
 157        struct media_devnode *mdev;
 158        int ret;
 159
 160        /* Check if the media device is available. This needs to be done with
 161         * the media_devnode_lock held to prevent an open/unregister race:
 162         * without the lock, the device could be unregistered and freed between
 163         * the media_devnode_is_registered() and get_device() calls, leading to
 164         * a crash.
 165         */
 166        mutex_lock(&media_devnode_lock);
 167        mdev = container_of(inode->i_cdev, struct media_devnode, cdev);
 168        /* return ENXIO if the media device has been removed
 169           already or if it is not registered anymore. */
 170        if (!media_devnode_is_registered(mdev)) {
 171                mutex_unlock(&media_devnode_lock);
 172                return -ENXIO;
 173        }
 174        /* and increase the device refcount */
 175        get_device(&mdev->dev);
 176        mutex_unlock(&media_devnode_lock);
 177
 178        filp->private_data = mdev;
 179
 180        if (mdev->fops->open) {
 181                ret = mdev->fops->open(filp);
 182                if (ret) {
 183                        put_device(&mdev->dev);
 184                        return ret;
 185                }
 186        }
 187
 188        return 0;
 189}
 190
 191/* Override for the release function */
 192static int media_release(struct inode *inode, struct file *filp)
 193{
 194        struct media_devnode *mdev = media_devnode_data(filp);
 195        int ret = 0;
 196
 197        if (mdev->fops->release)
 198                mdev->fops->release(filp);
 199
 200        /* decrease the refcount unconditionally since the release()
 201           return value is ignored. */
 202        put_device(&mdev->dev);
 203        filp->private_data = NULL;
 204        return ret;
 205}
 206
 207static const struct file_operations media_devnode_fops = {
 208        .owner = THIS_MODULE,
 209        .read = media_read,
 210        .write = media_write,
 211        .open = media_open,
 212        .unlocked_ioctl = media_ioctl,
 213#ifdef CONFIG_COMPAT
 214        .compat_ioctl = media_compat_ioctl,
 215#endif /* CONFIG_COMPAT */
 216        .release = media_release,
 217        .poll = media_poll,
 218        .llseek = no_llseek,
 219};
 220
 221/**
 222 * media_devnode_register - register a media device node
 223 * @mdev: media device node structure we want to register
 224 *
 225 * The registration code assigns minor numbers and registers the new device node
 226 * with the kernel. An error is returned if no free minor number can be found,
 227 * or if the registration of the device node fails.
 228 *
 229 * Zero is returned on success.
 230 *
 231 * Note that if the media_devnode_register call fails, the release() callback of
 232 * the media_devnode structure is *not* called, so the caller is responsible for
 233 * freeing any data.
 234 */
 235int __must_check media_devnode_register(struct media_devnode *mdev)
 236{
 237        int minor;
 238        int ret;
 239
 240        /* Part 1: Find a free minor number */
 241        mutex_lock(&media_devnode_lock);
 242        minor = find_next_zero_bit(media_devnode_nums, MEDIA_NUM_DEVICES, 0);
 243        if (minor == MEDIA_NUM_DEVICES) {
 244                mutex_unlock(&media_devnode_lock);
 245                pr_err("could not get a free minor\n");
 246                return -ENFILE;
 247        }
 248
 249        set_bit(minor, media_devnode_nums);
 250        mutex_unlock(&media_devnode_lock);
 251
 252        mdev->minor = minor;
 253
 254        /* Part 2: Initialize and register the character device */
 255        cdev_init(&mdev->cdev, &media_devnode_fops);
 256        mdev->cdev.owner = mdev->fops->owner;
 257
 258        ret = cdev_add(&mdev->cdev, MKDEV(MAJOR(media_dev_t), mdev->minor), 1);
 259        if (ret < 0) {
 260                pr_err("%s: cdev_add failed\n", __func__);
 261                goto error;
 262        }
 263
 264        /* Part 3: Register the media device */
 265        mdev->dev.bus = &media_bus_type;
 266        mdev->dev.devt = MKDEV(MAJOR(media_dev_t), mdev->minor);
 267        mdev->dev.release = media_devnode_release;
 268        if (mdev->parent)
 269                mdev->dev.parent = mdev->parent;
 270        dev_set_name(&mdev->dev, "media%d", mdev->minor);
 271        ret = device_register(&mdev->dev);
 272        if (ret < 0) {
 273                pr_err("%s: device_register failed\n", __func__);
 274                goto error;
 275        }
 276
 277        /* Part 4: Activate this minor. The char device can now be used. */
 278        set_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
 279
 280        return 0;
 281
 282error:
 283        cdev_del(&mdev->cdev);
 284        clear_bit(mdev->minor, media_devnode_nums);
 285        return ret;
 286}
 287
 288/**
 289 * media_devnode_unregister - unregister a media device node
 290 * @mdev: the device node to unregister
 291 *
 292 * This unregisters the passed device. Future open calls will be met with
 293 * errors.
 294 *
 295 * This function can safely be called if the device node has never been
 296 * registered or has already been unregistered.
 297 */
 298void media_devnode_unregister(struct media_devnode *mdev)
 299{
 300        /* Check if mdev was ever registered at all */
 301        if (!media_devnode_is_registered(mdev))
 302                return;
 303
 304        mutex_lock(&media_devnode_lock);
 305        clear_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
 306        mutex_unlock(&media_devnode_lock);
 307        device_unregister(&mdev->dev);
 308}
 309
 310/*
 311 *      Initialise media for linux
 312 */
 313static int __init media_devnode_init(void)
 314{
 315        int ret;
 316
 317        pr_info("Linux media interface: v0.10\n");
 318        ret = alloc_chrdev_region(&media_dev_t, 0, MEDIA_NUM_DEVICES,
 319                                  MEDIA_NAME);
 320        if (ret < 0) {
 321                pr_warn("unable to allocate major\n");
 322                return ret;
 323        }
 324
 325        ret = bus_register(&media_bus_type);
 326        if (ret < 0) {
 327                unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
 328                pr_warn("bus_register failed\n");
 329                return -EIO;
 330        }
 331
 332        return 0;
 333}
 334
 335static void __exit media_devnode_exit(void)
 336{
 337        bus_unregister(&media_bus_type);
 338        unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
 339}
 340
 341subsys_initcall(media_devnode_init);
 342module_exit(media_devnode_exit)
 343
 344MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
 345MODULE_DESCRIPTION("Device node registration for media drivers");
 346MODULE_LICENSE("GPL");
 347
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.