Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.26-rc8 451 lines 11 kB view raw
1/* 2 * dvbdev.c 3 * 4 * Copyright (C) 2000 Ralph Metzler <ralph@convergence.de> 5 * & Marcus Metzler <marcus@convergence.de> 6 * for convergence integrated media GmbH 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public License 10 * as published by the Free Software Foundation; either version 2.1 11 * of the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 21 * 22 */ 23 24#include <linux/types.h> 25#include <linux/errno.h> 26#include <linux/string.h> 27#include <linux/module.h> 28#include <linux/kernel.h> 29#include <linux/init.h> 30#include <linux/slab.h> 31#include <linux/device.h> 32#include <linux/fs.h> 33#include <linux/cdev.h> 34#include <linux/mutex.h> 35#include "dvbdev.h" 36 37static int dvbdev_debug; 38 39module_param(dvbdev_debug, int, 0644); 40MODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off)."); 41 42#define dprintk if (dvbdev_debug) printk 43 44static LIST_HEAD(dvb_adapter_list); 45static DEFINE_MUTEX(dvbdev_register_lock); 46 47static const char * const dnames[] = { 48 "video", "audio", "sec", "frontend", "demux", "dvr", "ca", 49 "net", "osd" 50}; 51 52#define DVB_MAX_IDS 4 53#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type) 54#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64) 55 56static struct class *dvb_class; 57 58static struct dvb_device* dvbdev_find_device (int minor) 59{ 60 struct dvb_adapter *adap; 61 62 list_for_each_entry(adap, &dvb_adapter_list, list_head) { 63 struct dvb_device *dev; 64 list_for_each_entry(dev, &adap->device_list, list_head) 65 if (nums2minor(adap->num, dev->type, dev->id) == minor) 66 return dev; 67 } 68 69 return NULL; 70} 71 72 73static int dvb_device_open(struct inode *inode, struct file *file) 74{ 75 struct dvb_device *dvbdev; 76 77 dvbdev = dvbdev_find_device (iminor(inode)); 78 79 if (dvbdev && dvbdev->fops) { 80 int err = 0; 81 const struct file_operations *old_fops; 82 83 file->private_data = dvbdev; 84 old_fops = file->f_op; 85 file->f_op = fops_get(dvbdev->fops); 86 if(file->f_op->open) 87 err = file->f_op->open(inode,file); 88 if (err) { 89 fops_put(file->f_op); 90 file->f_op = fops_get(old_fops); 91 } 92 fops_put(old_fops); 93 return err; 94 } 95 return -ENODEV; 96} 97 98 99static const struct file_operations dvb_device_fops = 100{ 101 .owner = THIS_MODULE, 102 .open = dvb_device_open, 103}; 104 105static struct cdev dvb_device_cdev; 106 107int dvb_generic_open(struct inode *inode, struct file *file) 108{ 109 struct dvb_device *dvbdev = file->private_data; 110 111 if (!dvbdev) 112 return -ENODEV; 113 114 if (!dvbdev->users) 115 return -EBUSY; 116 117 if ((file->f_flags & O_ACCMODE) == O_RDONLY) { 118 if (!dvbdev->readers) 119 return -EBUSY; 120 dvbdev->readers--; 121 } else { 122 if (!dvbdev->writers) 123 return -EBUSY; 124 dvbdev->writers--; 125 } 126 127 dvbdev->users--; 128 return 0; 129} 130EXPORT_SYMBOL(dvb_generic_open); 131 132 133int dvb_generic_release(struct inode *inode, struct file *file) 134{ 135 struct dvb_device *dvbdev = file->private_data; 136 137 if (!dvbdev) 138 return -ENODEV; 139 140 if ((file->f_flags & O_ACCMODE) == O_RDONLY) { 141 dvbdev->readers++; 142 } else { 143 dvbdev->writers++; 144 } 145 146 dvbdev->users++; 147 return 0; 148} 149EXPORT_SYMBOL(dvb_generic_release); 150 151 152int dvb_generic_ioctl(struct inode *inode, struct file *file, 153 unsigned int cmd, unsigned long arg) 154{ 155 struct dvb_device *dvbdev = file->private_data; 156 157 if (!dvbdev) 158 return -ENODEV; 159 160 if (!dvbdev->kernel_ioctl) 161 return -EINVAL; 162 163 return dvb_usercopy (inode, file, cmd, arg, dvbdev->kernel_ioctl); 164} 165EXPORT_SYMBOL(dvb_generic_ioctl); 166 167 168static int dvbdev_get_free_id (struct dvb_adapter *adap, int type) 169{ 170 u32 id = 0; 171 172 while (id < DVB_MAX_IDS) { 173 struct dvb_device *dev; 174 list_for_each_entry(dev, &adap->device_list, list_head) 175 if (dev->type == type && dev->id == id) 176 goto skip; 177 return id; 178skip: 179 id++; 180 } 181 return -ENFILE; 182} 183 184 185int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, 186 const struct dvb_device *template, void *priv, int type) 187{ 188 struct dvb_device *dvbdev; 189 struct file_operations *dvbdevfops; 190 struct device *clsdev; 191 int id; 192 193 mutex_lock(&dvbdev_register_lock); 194 195 if ((id = dvbdev_get_free_id (adap, type)) < 0){ 196 mutex_unlock(&dvbdev_register_lock); 197 *pdvbdev = NULL; 198 printk(KERN_ERR "%s: couldn't find free device id\n", __func__); 199 return -ENFILE; 200 } 201 202 *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL); 203 204 if (!dvbdev){ 205 mutex_unlock(&dvbdev_register_lock); 206 return -ENOMEM; 207 } 208 209 dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL); 210 211 if (!dvbdevfops){ 212 kfree (dvbdev); 213 mutex_unlock(&dvbdev_register_lock); 214 return -ENOMEM; 215 } 216 217 memcpy(dvbdev, template, sizeof(struct dvb_device)); 218 dvbdev->type = type; 219 dvbdev->id = id; 220 dvbdev->adapter = adap; 221 dvbdev->priv = priv; 222 dvbdev->fops = dvbdevfops; 223 init_waitqueue_head (&dvbdev->wait_queue); 224 225 memcpy(dvbdev->fops, template->fops, sizeof(struct file_operations)); 226 dvbdev->fops->owner = adap->module; 227 228 list_add_tail (&dvbdev->list_head, &adap->device_list); 229 230 mutex_unlock(&dvbdev_register_lock); 231 232 clsdev = device_create(dvb_class, adap->device, 233 MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), 234 "dvb%d.%s%d", adap->num, dnames[type], id); 235 if (IS_ERR(clsdev)) { 236 printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n", 237 __func__, adap->num, dnames[type], id, PTR_ERR(clsdev)); 238 return PTR_ERR(clsdev); 239 } 240 241 dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", 242 adap->num, dnames[type], id, nums2minor(adap->num, type, id), 243 nums2minor(adap->num, type, id)); 244 245 return 0; 246} 247EXPORT_SYMBOL(dvb_register_device); 248 249 250void dvb_unregister_device(struct dvb_device *dvbdev) 251{ 252 if (!dvbdev) 253 return; 254 255 device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num, 256 dvbdev->type, dvbdev->id))); 257 258 list_del (&dvbdev->list_head); 259 kfree (dvbdev->fops); 260 kfree (dvbdev); 261} 262EXPORT_SYMBOL(dvb_unregister_device); 263 264static int dvbdev_check_free_adapter_num(int num) 265{ 266 struct list_head *entry; 267 list_for_each(entry, &dvb_adapter_list) { 268 struct dvb_adapter *adap; 269 adap = list_entry(entry, struct dvb_adapter, list_head); 270 if (adap->num == num) 271 return 0; 272 } 273 return 1; 274} 275 276static int dvbdev_get_free_adapter_num (void) 277{ 278 int num = 0; 279 280 while (num < DVB_MAX_ADAPTERS) { 281 if (dvbdev_check_free_adapter_num(num)) 282 return num; 283 num++; 284 } 285 286 return -ENFILE; 287} 288 289 290int dvb_register_adapter(struct dvb_adapter *adap, const char *name, 291 struct module *module, struct device *device, 292 short *adapter_nums) 293{ 294 int i, num; 295 296 mutex_lock(&dvbdev_register_lock); 297 298 for (i = 0; i < DVB_MAX_ADAPTERS; ++i) { 299 num = adapter_nums[i]; 300 if (num >= 0 && num < DVB_MAX_ADAPTERS) { 301 /* use the one the driver asked for */ 302 if (dvbdev_check_free_adapter_num(num)) 303 break; 304 } else { 305 num = dvbdev_get_free_adapter_num(); 306 break; 307 } 308 num = -1; 309 } 310 311 if (num < 0) { 312 mutex_unlock(&dvbdev_register_lock); 313 return -ENFILE; 314 } 315 316 memset (adap, 0, sizeof(struct dvb_adapter)); 317 INIT_LIST_HEAD (&adap->device_list); 318 319 printk(KERN_INFO "DVB: registering new adapter (%s)\n", name); 320 321 adap->num = num; 322 adap->name = name; 323 adap->module = module; 324 adap->device = device; 325 326 list_add_tail (&adap->list_head, &dvb_adapter_list); 327 328 mutex_unlock(&dvbdev_register_lock); 329 330 return num; 331} 332EXPORT_SYMBOL(dvb_register_adapter); 333 334 335int dvb_unregister_adapter(struct dvb_adapter *adap) 336{ 337 mutex_lock(&dvbdev_register_lock); 338 list_del (&adap->list_head); 339 mutex_unlock(&dvbdev_register_lock); 340 return 0; 341} 342EXPORT_SYMBOL(dvb_unregister_adapter); 343 344/* if the miracle happens and "generic_usercopy()" is included into 345 the kernel, then this can vanish. please don't make the mistake and 346 define this as video_usercopy(). this will introduce a dependecy 347 to the v4l "videodev.o" module, which is unnecessary for some 348 cards (ie. the budget dvb-cards don't need the v4l module...) */ 349int dvb_usercopy(struct inode *inode, struct file *file, 350 unsigned int cmd, unsigned long arg, 351 int (*func)(struct inode *inode, struct file *file, 352 unsigned int cmd, void *arg)) 353{ 354 char sbuf[128]; 355 void *mbuf = NULL; 356 void *parg = NULL; 357 int err = -EINVAL; 358 359 /* Copy arguments into temp kernel buffer */ 360 switch (_IOC_DIR(cmd)) { 361 case _IOC_NONE: 362 /* 363 * For this command, the pointer is actually an integer 364 * argument. 365 */ 366 parg = (void *) arg; 367 break; 368 case _IOC_READ: /* some v4l ioctls are marked wrong ... */ 369 case _IOC_WRITE: 370 case (_IOC_WRITE | _IOC_READ): 371 if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { 372 parg = sbuf; 373 } else { 374 /* too big to allocate from stack */ 375 mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); 376 if (NULL == mbuf) 377 return -ENOMEM; 378 parg = mbuf; 379 } 380 381 err = -EFAULT; 382 if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) 383 goto out; 384 break; 385 } 386 387 /* call driver */ 388 if ((err = func(inode, file, cmd, parg)) == -ENOIOCTLCMD) 389 err = -EINVAL; 390 391 if (err < 0) 392 goto out; 393 394 /* Copy results into user buffer */ 395 switch (_IOC_DIR(cmd)) 396 { 397 case _IOC_READ: 398 case (_IOC_WRITE | _IOC_READ): 399 if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) 400 err = -EFAULT; 401 break; 402 } 403 404out: 405 kfree(mbuf); 406 return err; 407} 408 409static int __init init_dvbdev(void) 410{ 411 int retval; 412 dev_t dev = MKDEV(DVB_MAJOR, 0); 413 414 if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) { 415 printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR); 416 return retval; 417 } 418 419 cdev_init(&dvb_device_cdev, &dvb_device_fops); 420 if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) { 421 printk(KERN_ERR "dvb-core: unable register character device\n"); 422 goto error; 423 } 424 425 dvb_class = class_create(THIS_MODULE, "dvb"); 426 if (IS_ERR(dvb_class)) { 427 retval = PTR_ERR(dvb_class); 428 goto error; 429 } 430 return 0; 431 432error: 433 cdev_del(&dvb_device_cdev); 434 unregister_chrdev_region(dev, MAX_DVB_MINORS); 435 return retval; 436} 437 438 439static void __exit exit_dvbdev(void) 440{ 441 class_destroy(dvb_class); 442 cdev_del(&dvb_device_cdev); 443 unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS); 444} 445 446subsys_initcall(init_dvbdev); 447module_exit(exit_dvbdev); 448 449MODULE_DESCRIPTION("DVB Core Driver"); 450MODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler"); 451MODULE_LICENSE("GPL");