dvbdev.c revision 50c25fff5385c6baf3114f7c369b0f75a29ac1e8
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[] = { 50afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab "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 5956b2293595b2eb52cc2aa2baf92c6cfa8265f9d5Greg Kroah-Hartmanstatic struct class *dvb_class; 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dvb_device* dvbdev_find_device (int minor) 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *entry; 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (entry, &dvb_adapter_list) { 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *entry0; 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_adapter *adap; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap = list_entry (entry, struct dvb_adapter, list_head); 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (entry0, &adap->device_list) { 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_device *dev; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = list_entry (entry0, struct dvb_device, list_head); 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nums2minor(adap->num, dev->type, dev->id) == minor) 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return dev; 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvb_device_open(struct inode *inode, struct file *file) 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_device *dvbdev; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev = dvbdev_find_device (iminor(inode)); 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dvbdev && dvbdev->fops) { 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = 0; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct file_operations *old_fops; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file->private_data = dvbdev; 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds old_fops = file->f_op; 93afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab file->f_op = fops_get(dvbdev->fops); 94afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if(file->f_op->open) 9550c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky err = file->f_op->open(inode,file); 96afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (err) { 9750c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky fops_put(file->f_op); 9850c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky file->f_op = fops_get(old_fops); 99afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab } 100afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab fops_put(old_fops); 101afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return err; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct file_operations dvb_device_fops = 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = dvb_device_open, 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cdev dvb_device_cdev = { 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .kobj = {.name = "dvb", }, 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_generic_open(struct inode *inode, struct file *file) 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 120afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab struct dvb_device *dvbdev = file->private_data; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 122afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (!dvbdev) 123afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return -ENODEV; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev->users) 126afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return -EBUSY; 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((file->f_flags & O_ACCMODE) == O_RDONLY) { 129afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (!dvbdev->readers) 130afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return -EBUSY; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->readers--; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 133afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (!dvbdev->writers) 134afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return -EBUSY; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->writers--; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->users--; 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_generic_open); 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_generic_release(struct inode *inode, struct file *file) 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 146afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab struct dvb_device *dvbdev = file->private_data; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev) 149afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return -ENODEV; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((file->f_flags & O_ACCMODE) == O_RDONLY) { 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->readers++; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->writers++; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->users++; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_generic_release); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_generic_ioctl(struct inode *inode, struct file *file, 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cmd, unsigned long arg) 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 166afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab struct dvb_device *dvbdev = file->private_data; 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 168afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (!dvbdev) 169afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return -ENODEV; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev->kernel_ioctl) 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return dvb_usercopy (inode, file, cmd, arg, dvbdev->kernel_ioctl); 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_generic_ioctl); 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvbdev_get_free_id (struct dvb_adapter *adap, int type) 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 id = 0; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (id < DVB_MAX_IDS) { 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *entry; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (entry, &adap->device_list) { 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_device *dev; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = list_entry (entry, struct dvb_device, list_head); 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->type == type && dev->id == id) 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto skip; 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return id; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip: 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds id++; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENFILE; 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct dvb_device *template, void *priv, int type) 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_device *dvbdev; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int id; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (down_interruptible (&dvbdev_register_lock)) 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ERESTARTSYS; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((id = dvbdev_get_free_id (adap, type)) < 0) { 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up (&dvbdev_register_lock); 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *pdvbdev = NULL; 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk ("%s: could get find free device id...\n", __FUNCTION__); 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENFILE; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL); 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev) { 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up(&dvbdev_register_lock); 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up (&dvbdev_register_lock); 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(dvbdev, template, sizeof(struct dvb_device)); 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->type = type; 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->id = id; 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->adapter = adap; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->priv = priv; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->fops->owner = adap->module; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail (&dvbdev->list_head, &adap->device_list); 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devfs_mk_cdev(MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds S_IFCHR | S_IRUSR | S_IWUSR, 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "dvb/adapter%d/%s%d", adap->num, dnames[type], id); 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23853f4654272df7c51064825024340554b39c9efbaGreg Kroah-Hartman class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), 23956b2293595b2eb52cc2aa2baf92c6cfa8265f9d5Greg Kroah-Hartman NULL, "dvb%d.%s%d", adap->num, dnames[type], id); 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap->num, dnames[type], id, nums2minor(adap->num, type, id), 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nums2minor(adap->num, type, id)); 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_register_device); 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid dvb_unregister_device(struct dvb_device *dvbdev) 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev) 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devfs_remove("dvb/adapter%d/%s%d", dvbdev->adapter->num, 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dnames[dvbdev->type], dvbdev->id); 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25856b2293595b2eb52cc2aa2baf92c6cfa8265f9d5Greg Kroah-Hartman class_device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num, 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->type, dvbdev->id))); 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del (&dvbdev->list_head); 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree (dvbdev); 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_unregister_device); 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvbdev_get_free_adapter_num (void) 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int num = 0; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (num < DVB_MAX_ADAPTERS) { 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *entry; 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (entry, &dvb_adapter_list) { 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_adapter *adap; 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap = list_entry (entry, struct dvb_adapter, list_head); 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (adap->num == num) 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto skip; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return num; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip: 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num++; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENFILE; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 288fdc53a6dbfea18e621dd23ed5cfb160837d7ce52Johannes Stezenbachint dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module) 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int num; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (down_interruptible (&dvbdev_register_lock)) 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ERESTARTSYS; 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((num = dvbdev_get_free_adapter_num ()) < 0) { 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up (&dvbdev_register_lock); 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENFILE; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset (adap, 0, sizeof(struct dvb_adapter)); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD (&adap->device_list); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk ("DVB: registering new adapter (%s).\n", name); 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devfs_mk_dir("dvb/adapter%d", num); 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap->num = num; 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap->name = name; 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap->module = module; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail (&adap->list_head, &dvb_adapter_list); 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up (&dvbdev_register_lock); 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return num; 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_register_adapter); 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_unregister_adapter(struct dvb_adapter *adap) 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devfs_remove("dvb/adapter%d", adap->num); 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (down_interruptible (&dvbdev_register_lock)) 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ERESTARTSYS; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del (&adap->list_head); 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up (&dvbdev_register_lock); 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_unregister_adapter); 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* if the miracle happens and "generic_usercopy()" is included into 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the kernel, then this can vanish. please don't make the mistake and 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds define this as video_usercopy(). this will introduce a dependecy 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to the v4l "videodev.o" module, which is unnecessary for some 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cards (ie. the budget dvb-cards don't need the v4l module...) */ 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_usercopy(struct inode *inode, struct file *file, 337afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab unsigned int cmd, unsigned long arg, 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int (*func)(struct inode *inode, struct file *file, 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cmd, void *arg)) 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 341afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab char sbuf[128]; 342afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab void *mbuf = NULL; 343afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab void *parg = NULL; 344afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab int err = -EINVAL; 345afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab 346afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab /* Copy arguments into temp kernel buffer */ 347afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab switch (_IOC_DIR(cmd)) { 348afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case _IOC_NONE: 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For this command, the pointer is actually an integer 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * argument. 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parg = (void *) arg; 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 355afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case _IOC_READ: /* some v4l ioctls are marked wrong ... */ 356afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case _IOC_WRITE: 357afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case (_IOC_WRITE | _IOC_READ): 358afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { 35950c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky parg = sbuf; 360afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab } else { 36150c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky /* too big to allocate from stack */ 36250c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); 36350c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky if (NULL == mbuf) 36450c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky return -ENOMEM; 36550c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky parg = mbuf; 366afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab } 367afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab 368afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab err = -EFAULT; 369afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) 37050c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky goto out; 371afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab break; 372afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab } 373afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab 374afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab /* call driver */ 375afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if ((err = func(inode, file, cmd, parg)) == -ENOIOCTLCMD) 376afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab err = -EINVAL; 377afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab 378afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (err < 0) 379afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab goto out; 380afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab 381afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab /* Copy results into user buffer */ 382afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab switch (_IOC_DIR(cmd)) 383afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab { 384afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case _IOC_READ: 385afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case (_IOC_WRITE | _IOC_READ): 386afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) 38750c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky err = -EFAULT; 388afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab break; 389afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab } 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 392afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab kfree(mbuf); 393afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return err; 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init_dvbdev(void) 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_t dev = MKDEV(DVB_MAJOR, 0); 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) { 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("dvb-core: unable to get major %d\n", DVB_MAJOR); 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cdev_init(&dvb_device_cdev, &dvb_device_fops); 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) { 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("dvb-core: unable to get major %d\n", DVB_MAJOR); 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devfs_mk_dir("dvb"); 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41456b2293595b2eb52cc2aa2baf92c6cfa8265f9d5Greg Kroah-Hartman dvb_class = class_create(THIS_MODULE, "dvb"); 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(dvb_class)) { 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = PTR_ERR(dvb_class); 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror: 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cdev_del(&dvb_device_cdev); 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_chrdev_region(dev, MAX_DVB_MINORS); 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit exit_dvbdev(void) 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 430afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab devfs_remove("dvb"); 43156b2293595b2eb52cc2aa2baf92c6cfa8265f9d5Greg Kroah-Hartman class_destroy(dvb_class); 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cdev_del(&dvb_device_cdev); 433afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS); 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(init_dvbdev); 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(exit_dvbdev); 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("DVB Core Driver"); 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler"); 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 442