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