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@kernel.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 48 static dev_t media_dev_t; 49 50 /* 51 * Active devices 52 */ 53 static DEFINE_MUTEX(media_devnode_lock); 54 static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES); 55 56 /* Called when the last user of the media device exits. */ 57 static 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 74 static struct bus_type media_bus_type = { 75 .name = MEDIA_NAME, 76 }; 77 78 static 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 90 static 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 102 static __poll_t 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 EPOLLERR | EPOLLHUP; 109 if (!devnode->fops->poll) 110 return DEFAULT_POLLMASK; 111 return devnode->fops->poll(filp, poll); 112 } 113 114 static 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 130 static 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 139 static 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 */ 150 static 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 */ 188 static 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 205 static 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 219 int __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 kobject_set_name(&devnode->cdev.kobj, "media%d", devnode->minor); 255 256 /* Part 3: Add the media and char device */ 257 ret = cdev_device_add(&devnode->cdev, &devnode->dev); 258 if (ret < 0) { 259 pr_err("%s: cdev_device_add failed\n", __func__); 260 goto cdev_add_error; 261 } 262 263 /* Part 4: Activate this minor. The char device can now be used. */ 264 set_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); 265 266 return 0; 267 268 cdev_add_error: 269 mutex_lock(&media_devnode_lock); 270 clear_bit(devnode->minor, media_devnode_nums); 271 devnode->media_dev = NULL; 272 mutex_unlock(&media_devnode_lock); 273 274 put_device(&devnode->dev); 275 return ret; 276 } 277 278 void media_devnode_unregister_prepare(struct media_devnode *devnode) 279 { 280 /* Check if devnode was ever registered at all */ 281 if (!media_devnode_is_registered(devnode)) 282 return; 283 284 mutex_lock(&media_devnode_lock); 285 clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); 286 mutex_unlock(&media_devnode_lock); 287 } 288 289 void media_devnode_unregister(struct media_devnode *devnode) 290 { 291 mutex_lock(&media_devnode_lock); 292 /* Delete the cdev on this minor as well */ 293 cdev_device_del(&devnode->cdev, &devnode->dev); 294 devnode->media_dev = NULL; 295 mutex_unlock(&media_devnode_lock); 296 297 put_device(&devnode->dev); 298 } 299 300 /* 301 * Initialise media for linux 302 */ 303 static int __init media_devnode_init(void) 304 { 305 int ret; 306 307 pr_info("Linux media interface: v0.10\n"); 308 ret = alloc_chrdev_region(&media_dev_t, 0, MEDIA_NUM_DEVICES, 309 MEDIA_NAME); 310 if (ret < 0) { 311 pr_warn("unable to allocate major\n"); 312 return ret; 313 } 314 315 ret = bus_register(&media_bus_type); 316 if (ret < 0) { 317 unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES); 318 pr_warn("bus_register failed\n"); 319 return -EIO; 320 } 321 322 return 0; 323 } 324 325 static void __exit media_devnode_exit(void) 326 { 327 bus_unregister(&media_bus_type); 328 unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES); 329 } 330 331 subsys_initcall(media_devnode_init); 332 module_exit(media_devnode_exit) 333 334 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); 335 MODULE_DESCRIPTION("Device node registration for media drivers"); 336 MODULE_LICENSE("GPL"); 337