Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Media device node
0004  *
0005  * Copyright (C) 2010 Nokia Corporation
0006  *
0007  * Based on drivers/media/video/v4l2_dev.c code authored by
0008  *  Mauro Carvalho Chehab <mchehab@kernel.org> (version 2)
0009  *  Alan Cox, <alan@lxorguk.ukuu.org.uk> (version 1)
0010  *
0011  * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
0012  *       Sakari Ailus <sakari.ailus@iki.fi>
0013  *
0014  * --
0015  *
0016  * Generic media device node infrastructure to register and unregister
0017  * character devices using a dynamic major number and proper reference
0018  * counting.
0019  */
0020 
0021 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0022 
0023 #include <linux/errno.h>
0024 #include <linux/init.h>
0025 #include <linux/module.h>
0026 #include <linux/kernel.h>
0027 #include <linux/kmod.h>
0028 #include <linux/slab.h>
0029 #include <linux/mm.h>
0030 #include <linux/string.h>
0031 #include <linux/types.h>
0032 #include <linux/uaccess.h>
0033 
0034 #include <media/media-devnode.h>
0035 #include <media/media-device.h>
0036 
0037 #define MEDIA_NUM_DEVICES   256
0038 #define MEDIA_NAME      "media"
0039 
0040 static dev_t media_dev_t;
0041 
0042 /*
0043  *  Active devices
0044  */
0045 static DEFINE_MUTEX(media_devnode_lock);
0046 static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES);
0047 
0048 /* Called when the last user of the media device exits. */
0049 static void media_devnode_release(struct device *cd)
0050 {
0051     struct media_devnode *devnode = to_media_devnode(cd);
0052 
0053     mutex_lock(&media_devnode_lock);
0054     /* Mark device node number as free */
0055     clear_bit(devnode->minor, media_devnode_nums);
0056     mutex_unlock(&media_devnode_lock);
0057 
0058     /* Release media_devnode and perform other cleanups as needed. */
0059     if (devnode->release)
0060         devnode->release(devnode);
0061 
0062     kfree(devnode);
0063     pr_debug("%s: Media Devnode Deallocated\n", __func__);
0064 }
0065 
0066 static struct bus_type media_bus_type = {
0067     .name = MEDIA_NAME,
0068 };
0069 
0070 static ssize_t media_read(struct file *filp, char __user *buf,
0071         size_t sz, loff_t *off)
0072 {
0073     struct media_devnode *devnode = media_devnode_data(filp);
0074 
0075     if (!devnode->fops->read)
0076         return -EINVAL;
0077     if (!media_devnode_is_registered(devnode))
0078         return -EIO;
0079     return devnode->fops->read(filp, buf, sz, off);
0080 }
0081 
0082 static ssize_t media_write(struct file *filp, const char __user *buf,
0083         size_t sz, loff_t *off)
0084 {
0085     struct media_devnode *devnode = media_devnode_data(filp);
0086 
0087     if (!devnode->fops->write)
0088         return -EINVAL;
0089     if (!media_devnode_is_registered(devnode))
0090         return -EIO;
0091     return devnode->fops->write(filp, buf, sz, off);
0092 }
0093 
0094 static __poll_t media_poll(struct file *filp,
0095                    struct poll_table_struct *poll)
0096 {
0097     struct media_devnode *devnode = media_devnode_data(filp);
0098 
0099     if (!media_devnode_is_registered(devnode))
0100         return EPOLLERR | EPOLLHUP;
0101     if (!devnode->fops->poll)
0102         return DEFAULT_POLLMASK;
0103     return devnode->fops->poll(filp, poll);
0104 }
0105 
0106 static long
0107 __media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg,
0108           long (*ioctl_func)(struct file *filp, unsigned int cmd,
0109                  unsigned long arg))
0110 {
0111     struct media_devnode *devnode = media_devnode_data(filp);
0112 
0113     if (!ioctl_func)
0114         return -ENOTTY;
0115 
0116     if (!media_devnode_is_registered(devnode))
0117         return -EIO;
0118 
0119     return ioctl_func(filp, cmd, arg);
0120 }
0121 
0122 static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
0123 {
0124     struct media_devnode *devnode = media_devnode_data(filp);
0125 
0126     return __media_ioctl(filp, cmd, arg, devnode->fops->ioctl);
0127 }
0128 
0129 #ifdef CONFIG_COMPAT
0130 
0131 static long media_compat_ioctl(struct file *filp, unsigned int cmd,
0132                    unsigned long arg)
0133 {
0134     struct media_devnode *devnode = media_devnode_data(filp);
0135 
0136     return __media_ioctl(filp, cmd, arg, devnode->fops->compat_ioctl);
0137 }
0138 
0139 #endif /* CONFIG_COMPAT */
0140 
0141 /* Override for the open function */
0142 static int media_open(struct inode *inode, struct file *filp)
0143 {
0144     struct media_devnode *devnode;
0145     int ret;
0146 
0147     /* Check if the media device is available. This needs to be done with
0148      * the media_devnode_lock held to prevent an open/unregister race:
0149      * without the lock, the device could be unregistered and freed between
0150      * the media_devnode_is_registered() and get_device() calls, leading to
0151      * a crash.
0152      */
0153     mutex_lock(&media_devnode_lock);
0154     devnode = container_of(inode->i_cdev, struct media_devnode, cdev);
0155     /* return ENXIO if the media device has been removed
0156        already or if it is not registered anymore. */
0157     if (!media_devnode_is_registered(devnode)) {
0158         mutex_unlock(&media_devnode_lock);
0159         return -ENXIO;
0160     }
0161     /* and increase the device refcount */
0162     get_device(&devnode->dev);
0163     mutex_unlock(&media_devnode_lock);
0164 
0165     filp->private_data = devnode;
0166 
0167     if (devnode->fops->open) {
0168         ret = devnode->fops->open(filp);
0169         if (ret) {
0170             put_device(&devnode->dev);
0171             filp->private_data = NULL;
0172             return ret;
0173         }
0174     }
0175 
0176     return 0;
0177 }
0178 
0179 /* Override for the release function */
0180 static int media_release(struct inode *inode, struct file *filp)
0181 {
0182     struct media_devnode *devnode = media_devnode_data(filp);
0183 
0184     if (devnode->fops->release)
0185         devnode->fops->release(filp);
0186 
0187     filp->private_data = NULL;
0188 
0189     /* decrease the refcount unconditionally since the release()
0190        return value is ignored. */
0191     put_device(&devnode->dev);
0192 
0193     pr_debug("%s: Media Release\n", __func__);
0194     return 0;
0195 }
0196 
0197 static const struct file_operations media_devnode_fops = {
0198     .owner = THIS_MODULE,
0199     .read = media_read,
0200     .write = media_write,
0201     .open = media_open,
0202     .unlocked_ioctl = media_ioctl,
0203 #ifdef CONFIG_COMPAT
0204     .compat_ioctl = media_compat_ioctl,
0205 #endif /* CONFIG_COMPAT */
0206     .release = media_release,
0207     .poll = media_poll,
0208     .llseek = no_llseek,
0209 };
0210 
0211 int __must_check media_devnode_register(struct media_device *mdev,
0212                     struct media_devnode *devnode,
0213                     struct module *owner)
0214 {
0215     int minor;
0216     int ret;
0217 
0218     /* Part 1: Find a free minor number */
0219     mutex_lock(&media_devnode_lock);
0220     minor = find_first_zero_bit(media_devnode_nums, MEDIA_NUM_DEVICES);
0221     if (minor == MEDIA_NUM_DEVICES) {
0222         mutex_unlock(&media_devnode_lock);
0223         pr_err("could not get a free minor\n");
0224         kfree(devnode);
0225         return -ENFILE;
0226     }
0227 
0228     set_bit(minor, media_devnode_nums);
0229     mutex_unlock(&media_devnode_lock);
0230 
0231     devnode->minor = minor;
0232     devnode->media_dev = mdev;
0233 
0234     /* Part 1: Initialize dev now to use dev.kobj for cdev.kobj.parent */
0235     devnode->dev.bus = &media_bus_type;
0236     devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor);
0237     devnode->dev.release = media_devnode_release;
0238     if (devnode->parent)
0239         devnode->dev.parent = devnode->parent;
0240     dev_set_name(&devnode->dev, "media%d", devnode->minor);
0241     device_initialize(&devnode->dev);
0242 
0243     /* Part 2: Initialize the character device */
0244     cdev_init(&devnode->cdev, &media_devnode_fops);
0245     devnode->cdev.owner = owner;
0246     kobject_set_name(&devnode->cdev.kobj, "media%d", devnode->minor);
0247 
0248     /* Part 3: Add the media and char device */
0249     ret = cdev_device_add(&devnode->cdev, &devnode->dev);
0250     if (ret < 0) {
0251         pr_err("%s: cdev_device_add failed\n", __func__);
0252         goto cdev_add_error;
0253     }
0254 
0255     /* Part 4: Activate this minor. The char device can now be used. */
0256     set_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
0257 
0258     return 0;
0259 
0260 cdev_add_error:
0261     mutex_lock(&media_devnode_lock);
0262     clear_bit(devnode->minor, media_devnode_nums);
0263     devnode->media_dev = NULL;
0264     mutex_unlock(&media_devnode_lock);
0265 
0266     put_device(&devnode->dev);
0267     return ret;
0268 }
0269 
0270 void media_devnode_unregister_prepare(struct media_devnode *devnode)
0271 {
0272     /* Check if devnode was ever registered at all */
0273     if (!media_devnode_is_registered(devnode))
0274         return;
0275 
0276     mutex_lock(&media_devnode_lock);
0277     clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
0278     mutex_unlock(&media_devnode_lock);
0279 }
0280 
0281 void media_devnode_unregister(struct media_devnode *devnode)
0282 {
0283     mutex_lock(&media_devnode_lock);
0284     /* Delete the cdev on this minor as well */
0285     cdev_device_del(&devnode->cdev, &devnode->dev);
0286     devnode->media_dev = NULL;
0287     mutex_unlock(&media_devnode_lock);
0288 
0289     put_device(&devnode->dev);
0290 }
0291 
0292 /*
0293  *  Initialise media for linux
0294  */
0295 static int __init media_devnode_init(void)
0296 {
0297     int ret;
0298 
0299     pr_info("Linux media interface: v0.10\n");
0300     ret = alloc_chrdev_region(&media_dev_t, 0, MEDIA_NUM_DEVICES,
0301                   MEDIA_NAME);
0302     if (ret < 0) {
0303         pr_warn("unable to allocate major\n");
0304         return ret;
0305     }
0306 
0307     ret = bus_register(&media_bus_type);
0308     if (ret < 0) {
0309         unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
0310         pr_warn("bus_register failed\n");
0311         return -EIO;
0312     }
0313 
0314     return 0;
0315 }
0316 
0317 static void __exit media_devnode_exit(void)
0318 {
0319     bus_unregister(&media_bus_type);
0320     unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
0321 }
0322 
0323 subsys_initcall(media_devnode_init);
0324 module_exit(media_devnode_exit)
0325 
0326 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
0327 MODULE_DESCRIPTION("Device node registration for media drivers");
0328 MODULE_LICENSE("GPL");