at v2.6.28 458 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(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 adap->mfe_shared = 0; 330 adap->mfe_dvbdev = NULL; 331 mutex_init (&adap->mfe_lock); 332 333 list_add_tail (&adap->list_head, &dvb_adapter_list); 334 335 mutex_unlock(&dvbdev_register_lock); 336 337 return num; 338} 339EXPORT_SYMBOL(dvb_register_adapter); 340 341 342int dvb_unregister_adapter(struct dvb_adapter *adap) 343{ 344 mutex_lock(&dvbdev_register_lock); 345 list_del (&adap->list_head); 346 mutex_unlock(&dvbdev_register_lock); 347 return 0; 348} 349EXPORT_SYMBOL(dvb_unregister_adapter); 350 351/* if the miracle happens and "generic_usercopy()" is included into 352 the kernel, then this can vanish. please don't make the mistake and 353 define this as video_usercopy(). this will introduce a dependecy 354 to the v4l "videodev.o" module, which is unnecessary for some 355 cards (ie. the budget dvb-cards don't need the v4l module...) */ 356int dvb_usercopy(struct inode *inode, struct file *file, 357 unsigned int cmd, unsigned long arg, 358 int (*func)(struct inode *inode, struct file *file, 359 unsigned int cmd, void *arg)) 360{ 361 char sbuf[128]; 362 void *mbuf = NULL; 363 void *parg = NULL; 364 int err = -EINVAL; 365 366 /* Copy arguments into temp kernel buffer */ 367 switch (_IOC_DIR(cmd)) { 368 case _IOC_NONE: 369 /* 370 * For this command, the pointer is actually an integer 371 * argument. 372 */ 373 parg = (void *) arg; 374 break; 375 case _IOC_READ: /* some v4l ioctls are marked wrong ... */ 376 case _IOC_WRITE: 377 case (_IOC_WRITE | _IOC_READ): 378 if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { 379 parg = sbuf; 380 } else { 381 /* too big to allocate from stack */ 382 mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); 383 if (NULL == mbuf) 384 return -ENOMEM; 385 parg = mbuf; 386 } 387 388 err = -EFAULT; 389 if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) 390 goto out; 391 break; 392 } 393 394 /* call driver */ 395 if ((err = func(inode, file, cmd, parg)) == -ENOIOCTLCMD) 396 err = -EINVAL; 397 398 if (err < 0) 399 goto out; 400 401 /* Copy results into user buffer */ 402 switch (_IOC_DIR(cmd)) 403 { 404 case _IOC_READ: 405 case (_IOC_WRITE | _IOC_READ): 406 if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) 407 err = -EFAULT; 408 break; 409 } 410 411out: 412 kfree(mbuf); 413 return err; 414} 415 416static int __init init_dvbdev(void) 417{ 418 int retval; 419 dev_t dev = MKDEV(DVB_MAJOR, 0); 420 421 if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) { 422 printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR); 423 return retval; 424 } 425 426 cdev_init(&dvb_device_cdev, &dvb_device_fops); 427 if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) { 428 printk(KERN_ERR "dvb-core: unable register character device\n"); 429 goto error; 430 } 431 432 dvb_class = class_create(THIS_MODULE, "dvb"); 433 if (IS_ERR(dvb_class)) { 434 retval = PTR_ERR(dvb_class); 435 goto error; 436 } 437 return 0; 438 439error: 440 cdev_del(&dvb_device_cdev); 441 unregister_chrdev_region(dev, MAX_DVB_MINORS); 442 return retval; 443} 444 445 446static void __exit exit_dvbdev(void) 447{ 448 class_destroy(dvb_class); 449 cdev_del(&dvb_device_cdev); 450 unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS); 451} 452 453subsys_initcall(init_dvbdev); 454module_exit(exit_dvbdev); 455 456MODULE_DESCRIPTION("DVB Core Driver"); 457MODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler"); 458MODULE_LICENSE("GPL");