dvbdev.c revision c278850206fd9df0bb62a72ca0b277fe20c5a452
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/init.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/cdev.h>
351e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar#include <linux/mutex.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "dvbdev.h"
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvbdev_debug;
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(dvbdev_debug, int, 0644);
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off).");
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define dprintk if (dvbdev_debug) printk
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic LIST_HEAD(dvb_adapter_list);
461e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnarstatic DEFINE_MUTEX(dvbdev_register_lock);
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char * const dnames[] = {
49afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab	"video", "audio", "sec", "frontend", "demux", "dvr", "ca",
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"net", "osd"
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DVB_MAX_ADAPTERS	8
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DVB_MAX_IDS		4
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define nums2minor(num,type,id)	((num << 6) | (id << 4) | type)
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_DVB_MINORS		(DVB_MAX_ADAPTERS*64)
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5856b2293595b2eb52cc2aa2baf92c6cfa8265f9d5Greg Kroah-Hartmanstatic struct class *dvb_class;
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dvb_device* dvbdev_find_device (int minor)
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head *entry;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each (entry, &dvb_adapter_list) {
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct list_head *entry0;
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dvb_adapter *adap;
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adap = list_entry (entry, struct dvb_adapter, list_head);
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_for_each (entry0, &adap->device_list) {
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct dvb_device *dev;
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev = list_entry (entry0, struct dvb_device, list_head);
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (nums2minor(adap->num, dev->type, dev->id) == minor)
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return dev;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvb_device_open(struct inode *inode, struct file *file)
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dvb_device *dvbdev;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dvbdev = dvbdev_find_device (iminor(inode));
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dvbdev && dvbdev->fops) {
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int err = 0;
8899ac48f54a91d02140c497edc31dc57d4bc5c85dArjan van de Ven		const struct file_operations *old_fops;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		file->private_data = dvbdev;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		old_fops = file->f_op;
92afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab		file->f_op = fops_get(dvbdev->fops);
93afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab		if(file->f_op->open)
9450c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky			err = file->f_op->open(inode,file);
95afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab		if (err) {
9650c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky			fops_put(file->f_op);
9750c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky			file->f_op = fops_get(old_fops);
98afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab		}
99afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab		fops_put(old_fops);
100afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab		return err;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENODEV;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct file_operations dvb_device_fops =
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner =	THIS_MODULE,
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.open =		dvb_device_open,
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cdev dvb_device_cdev = {
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.kobj   = {.name = "dvb", },
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner  =       THIS_MODULE,
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_generic_open(struct inode *inode, struct file *file)
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
119afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab	struct dvb_device *dvbdev = file->private_data;
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
121afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab	if (!dvbdev)
122afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab		return -ENODEV;
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dvbdev->users)
125afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab		return -EBUSY;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
128afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab		if (!dvbdev->readers)
129afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab			return -EBUSY;
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dvbdev->readers--;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
132afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab		if (!dvbdev->writers)
133afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab			return -EBUSY;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dvbdev->writers--;
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dvbdev->users--;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_generic_open);
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_generic_release(struct inode *inode, struct file *file)
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
145afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab	struct dvb_device *dvbdev = file->private_data;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dvbdev)
148afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab		return -ENODEV;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dvbdev->readers++;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dvbdev->writers++;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dvbdev->users++;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_generic_release);
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_generic_ioctl(struct inode *inode, struct file *file,
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      unsigned int cmd, unsigned long arg)
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
165afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab	struct dvb_device *dvbdev = file->private_data;
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
167afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab	if (!dvbdev)
168afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab		return -ENODEV;
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dvbdev->kernel_ioctl)
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return dvb_usercopy (inode, file, cmd, arg, dvbdev->kernel_ioctl);
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_generic_ioctl);
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvbdev_get_free_id (struct dvb_adapter *adap, int type)
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 id = 0;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (id < DVB_MAX_IDS) {
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct list_head *entry;
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_for_each (entry, &adap->device_list) {
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct dvb_device *dev;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev = list_entry (entry, struct dvb_device, list_head);
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (dev->type == type && dev->id == id)
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto skip;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return id;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip:
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		id++;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENFILE;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			const struct dvb_device *template, void *priv, int type)
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dvb_device *dvbdev;
202b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert	struct file_operations *dvbdevfops;
203b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int id;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
206c278850206fd9df0bb62a72ca0b277fe20c5a452Simon Arlott	mutex_lock(&dvbdev_register_lock);
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
208b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert	if ((id = dvbdev_get_free_id (adap, type)) < 0){
2091e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar		mutex_unlock(&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
217b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert	if (!dvbdev){
218b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert		mutex_unlock(&dvbdev_register_lock);
219b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert		return -ENOMEM;
220b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert	}
221b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert
222b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert	dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
223b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert
224b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert	if (!dvbdevfops){
225b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert		kfree (dvbdev);
2261e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar		mutex_unlock(&dvbdev_register_lock);
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(dvbdev, template, sizeof(struct dvb_device));
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dvbdev->type = type;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dvbdev->id = id;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dvbdev->adapter = adap;
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dvbdev->priv = priv;
235b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert	dvbdev->fops = dvbdevfops;
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
237b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert	memcpy(dvbdev->fops, template->fops, sizeof(struct file_operations));
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dvbdev->fops->owner = adap->module;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_add_tail (&dvbdev->list_head, &adap->device_list);
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
242f47f4763cde162656448fcd1ada9d5e8101a00d2Andrew de Quincey	mutex_unlock(&dvbdev_register_lock);
243f47f4763cde162656448fcd1ada9d5e8101a00d2Andrew de Quincey
24453f4654272df7c51064825024340554b39c9efbaGreg Kroah-Hartman	class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
245d09dbf92ada861244056d914a8f68b8be99891edAndrew de Quincey			    adap->device, "dvb%d.%s%d", adap->num, dnames[type], id);
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adap->num, dnames[type], id, nums2minor(adap->num, type, id),
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nums2minor(adap->num, type, id));
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_register_device);
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid dvb_unregister_device(struct dvb_device *dvbdev)
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dvbdev)
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26156b2293595b2eb52cc2aa2baf92c6cfa8265f9d5Greg Kroah-Hartman	class_device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dvbdev->type, dvbdev->id)));
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_del (&dvbdev->list_head);
265b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert	kfree (dvbdev->fops);
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree (dvbdev);
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_unregister_device);
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvbdev_get_free_adapter_num (void)
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int num = 0;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (num < DVB_MAX_ADAPTERS) {
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct list_head *entry;
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_for_each (entry, &dvb_adapter_list) {
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct dvb_adapter *adap;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			adap = list_entry (entry, struct dvb_adapter, list_head);
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (adap->num == num)
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto skip;
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return num;
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip:
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		num++;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENFILE;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
292d09dbf92ada861244056d914a8f68b8be99891edAndrew de Quinceyint dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module, struct device *device)
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int num;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
296c278850206fd9df0bb62a72ca0b277fe20c5a452Simon Arlott	mutex_lock(&dvbdev_register_lock);
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((num = dvbdev_get_free_adapter_num ()) < 0) {
2991e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar		mutex_unlock(&dvbdev_register_lock);
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENFILE;
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset (adap, 0, sizeof(struct dvb_adapter));
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD (&adap->device_list);
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk ("DVB: registering new adapter (%s).\n", name);
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adap->num = num;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adap->name = name;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adap->module = module;
311d09dbf92ada861244056d914a8f68b8be99891edAndrew de Quincey	adap->device = device;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_add_tail (&adap->list_head, &dvb_adapter_list);
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3151e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar	mutex_unlock(&dvbdev_register_lock);
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return num;
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_register_adapter);
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_unregister_adapter(struct dvb_adapter *adap)
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
324c278850206fd9df0bb62a72ca0b277fe20c5a452Simon Arlott	mutex_lock(&dvbdev_register_lock);
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_del (&adap->list_head);
3261e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar	mutex_unlock(&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
41256b2293595b2eb52cc2aa2baf92c6cfa8265f9d5Greg Kroah-Hartman	dvb_class = class_create(THIS_MODULE, "dvb");
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (IS_ERR(dvb_class)) {
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = PTR_ERR(dvb_class);
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto error;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror:
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cdev_del(&dvb_device_cdev);
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unregister_chrdev_region(dev, MAX_DVB_MINORS);
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit exit_dvbdev(void)
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
42856b2293595b2eb52cc2aa2baf92c6cfa8265f9d5Greg Kroah-Hartman	class_destroy(dvb_class);
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cdev_del(&dvb_device_cdev);
430afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab	unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS);
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(init_dvbdev);
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(exit_dvbdev);
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("DVB Core Driver");
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler");
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
439