dvbdev.c revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dvbdev.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2000 Ralph Metzler <ralph@convergence.de> 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * & Marcus Metzler <marcus@convergence.de> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for convergence integrated media GmbH 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU Lesser General Public License 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as published by the Free Software Foundation; either version 2.1 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the License, or (at your option) any later version. 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details. 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU Lesser General Public License 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/cdev.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "dvbdev.h" 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvbdev_debug; 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(dvbdev_debug, int, 0644); 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off)."); 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define dprintk if (dvbdev_debug) printk 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic LIST_HEAD(dvb_adapter_list); 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DECLARE_MUTEX(dvbdev_register_lock); 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char * const dnames[] = { 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "video", "audio", "sec", "frontend", "demux", "dvr", "ca", 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "net", "osd" 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DVB_MAX_ADAPTERS 8 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DVB_MAX_IDS 4 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type) 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64) 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct class_simple *dvb_class; 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_class); 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dvb_device* dvbdev_find_device (int minor) 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *entry; 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (entry, &dvb_adapter_list) { 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *entry0; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_adapter *adap; 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap = list_entry (entry, struct dvb_adapter, list_head); 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (entry0, &adap->device_list) { 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_device *dev; 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = list_entry (entry0, struct dvb_device, list_head); 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nums2minor(adap->num, dev->type, dev->id) == minor) 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return dev; 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvb_device_open(struct inode *inode, struct file *file) 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_device *dvbdev; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev = dvbdev_find_device (iminor(inode)); 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dvbdev && dvbdev->fops) { 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = 0; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct file_operations *old_fops; 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file->private_data = dvbdev; 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds old_fops = file->f_op; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file->f_op = fops_get(dvbdev->fops); 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(file->f_op->open) 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = file->f_op->open(inode,file); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) { 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fops_put(file->f_op); 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file->f_op = fops_get(old_fops); 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fops_put(old_fops); 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct file_operations dvb_device_fops = 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = dvb_device_open, 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cdev dvb_device_cdev = { 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .kobj = {.name = "dvb", }, 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_generic_open(struct inode *inode, struct file *file) 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_device *dvbdev = file->private_data; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev) 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev->users) 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((file->f_flags & O_ACCMODE) == O_RDONLY) { 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev->readers) 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->readers--; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev->writers) 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->writers--; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->users--; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_generic_open); 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_generic_release(struct inode *inode, struct file *file) 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_device *dvbdev = file->private_data; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev) 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((file->f_flags & O_ACCMODE) == O_RDONLY) { 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->readers++; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->writers++; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->users++; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_generic_release); 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_generic_ioctl(struct inode *inode, struct file *file, 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cmd, unsigned long arg) 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_device *dvbdev = file->private_data; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev) 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev->kernel_ioctl) 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return dvb_usercopy (inode, file, cmd, arg, dvbdev->kernel_ioctl); 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_generic_ioctl); 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvbdev_get_free_id (struct dvb_adapter *adap, int type) 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 id = 0; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (id < DVB_MAX_IDS) { 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *entry; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (entry, &adap->device_list) { 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_device *dev; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = list_entry (entry, struct dvb_device, list_head); 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->type == type && dev->id == id) 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto skip; 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return id; 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip: 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds id++; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENFILE; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct dvb_device *template, void *priv, int type) 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_device *dvbdev; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int id; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (down_interruptible (&dvbdev_register_lock)) 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ERESTARTSYS; 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((id = dvbdev_get_free_id (adap, type)) < 0) { 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up (&dvbdev_register_lock); 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *pdvbdev = NULL; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk ("%s: could get find free device id...\n", __FUNCTION__); 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENFILE; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL); 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev) { 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up(&dvbdev_register_lock); 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up (&dvbdev_register_lock); 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(dvbdev, template, sizeof(struct dvb_device)); 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->type = type; 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->id = id; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->adapter = adap; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->priv = priv; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->fops->owner = adap->module; 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail (&dvbdev->list_head, &adap->device_list); 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devfs_mk_cdev(MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds S_IFCHR | S_IRUSR | S_IWUSR, 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "dvb/adapter%d/%s%d", adap->num, dnames[type], id); 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds class_simple_device_add(dvb_class, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NULL, "dvb%d.%s%d", adap->num, dnames[type], id); 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap->num, dnames[type], id, nums2minor(adap->num, type, id), 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nums2minor(adap->num, type, id)); 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_register_device); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid dvb_unregister_device(struct dvb_device *dvbdev) 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev) 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devfs_remove("dvb/adapter%d/%s%d", dvbdev->adapter->num, 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dnames[dvbdev->type], dvbdev->id); 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds class_simple_device_remove(MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num, 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->type, dvbdev->id))); 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del (&dvbdev->list_head); 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree (dvbdev); 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_unregister_device); 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvbdev_get_free_adapter_num (void) 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int num = 0; 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (num < DVB_MAX_ADAPTERS) { 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *entry; 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (entry, &dvb_adapter_list) { 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_adapter *adap; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap = list_entry (entry, struct dvb_adapter, list_head); 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (adap->num == num) 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto skip; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return num; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip: 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num++; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENFILE; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_register_adapter(struct dvb_adapter **padap, const char *name, struct module *module) 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_adapter *adap; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int num; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (down_interruptible (&dvbdev_register_lock)) 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ERESTARTSYS; 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((num = dvbdev_get_free_adapter_num ()) < 0) { 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up (&dvbdev_register_lock); 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENFILE; 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(*padap = adap = kmalloc(sizeof(struct dvb_adapter), GFP_KERNEL))) { 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up(&dvbdev_register_lock); 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset (adap, 0, sizeof(struct dvb_adapter)); 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD (&adap->device_list); 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk ("DVB: registering new adapter (%s).\n", name); 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devfs_mk_dir("dvb/adapter%d", num); 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap->num = num; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap->name = name; 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap->module = module; 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail (&adap->list_head, &dvb_adapter_list); 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up (&dvbdev_register_lock); 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return num; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_register_adapter); 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_unregister_adapter(struct dvb_adapter *adap) 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devfs_remove("dvb/adapter%d", adap->num); 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (down_interruptible (&dvbdev_register_lock)) 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ERESTARTSYS; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del (&adap->list_head); 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up (&dvbdev_register_lock); 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree (adap); 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_unregister_adapter); 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* if the miracle happens and "generic_usercopy()" is included into 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the kernel, then this can vanish. please don't make the mistake and 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds define this as video_usercopy(). this will introduce a dependecy 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to the v4l "videodev.o" module, which is unnecessary for some 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cards (ie. the budget dvb-cards don't need the v4l module...) */ 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_usercopy(struct inode *inode, struct file *file, 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cmd, unsigned long arg, 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int (*func)(struct inode *inode, struct file *file, 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cmd, void *arg)) 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char sbuf[128]; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *mbuf = NULL; 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *parg = NULL; 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = -EINVAL; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Copy arguments into temp kernel buffer */ 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (_IOC_DIR(cmd)) { 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case _IOC_NONE: 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For this command, the pointer is actually an integer 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * argument. 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parg = (void *) arg; 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case _IOC_READ: /* some v4l ioctls are marked wrong ... */ 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case _IOC_WRITE: 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case (_IOC_WRITE | _IOC_READ): 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parg = sbuf; 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* too big to allocate from stack */ 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (NULL == mbuf) 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parg = mbuf; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EFAULT; 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* call driver */ 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = func(inode, file, cmd, parg)) == -ENOIOCTLCMD) 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EINVAL; 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err < 0) 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Copy results into user buffer */ 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (_IOC_DIR(cmd)) 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case _IOC_READ: 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case (_IOC_WRITE | _IOC_READ): 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EFAULT; 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(mbuf); 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init_dvbdev(void) 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_t dev = MKDEV(DVB_MAJOR, 0); 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) { 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("dvb-core: unable to get major %d\n", DVB_MAJOR); 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cdev_init(&dvb_device_cdev, &dvb_device_fops); 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) { 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("dvb-core: unable to get major %d\n", DVB_MAJOR); 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devfs_mk_dir("dvb"); 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_class = class_simple_create(THIS_MODULE, "dvb"); 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(dvb_class)) { 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = PTR_ERR(dvb_class); 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror: 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cdev_del(&dvb_device_cdev); 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_chrdev_region(dev, MAX_DVB_MINORS); 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit exit_dvbdev(void) 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devfs_remove("dvb"); 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds class_simple_destroy(dvb_class); 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cdev_del(&dvb_device_cdev); 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS); 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(init_dvbdev); 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(exit_dvbdev); 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("DVB Core Driver"); 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler"); 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 450