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