dvbdev.c revision b61901024776b25ce7b8edc31bb1757c7382a88e
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 2061e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar if (mutex_lock_interruptible(&dvbdev_register_lock)) 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ERESTARTSYS; 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 209b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert if ((id = dvbdev_get_free_id (adap, type)) < 0){ 2101e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar mutex_unlock(&dvbdev_register_lock); 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *pdvbdev = NULL; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk ("%s: could get find free device id...\n", __FUNCTION__); 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENFILE; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL); 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 218b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert if (!dvbdev){ 219b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert mutex_unlock(&dvbdev_register_lock); 220b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert return -ENOMEM; 221b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert } 222b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert 223b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL); 224b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert 225b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert if (!dvbdevfops){ 226b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert kfree (dvbdev); 2271e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar mutex_unlock(&dvbdev_register_lock); 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(dvbdev, template, sizeof(struct dvb_device)); 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->type = type; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->id = id; 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->adapter = adap; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->priv = priv; 236b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert dvbdev->fops = dvbdevfops; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 238b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert memcpy(dvbdev->fops, template->fops, sizeof(struct file_operations)); 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->fops->owner = adap->module; 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail (&dvbdev->list_head, &adap->device_list); 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 243f47f4763cde162656448fcd1ada9d5e8101a00d2Andrew de Quincey mutex_unlock(&dvbdev_register_lock); 244f47f4763cde162656448fcd1ada9d5e8101a00d2Andrew de Quincey 24553f4654272df7c51064825024340554b39c9efbaGreg Kroah-Hartman class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), 246d09dbf92ada861244056d914a8f68b8be99891edAndrew de Quincey adap->device, "dvb%d.%s%d", adap->num, dnames[type], id); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap->num, dnames[type], id, nums2minor(adap->num, type, id), 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nums2minor(adap->num, type, id)); 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_register_device); 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid dvb_unregister_device(struct dvb_device *dvbdev) 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev) 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26256b2293595b2eb52cc2aa2baf92c6cfa8265f9d5Greg Kroah-Hartman class_device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num, 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->type, dvbdev->id))); 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del (&dvbdev->list_head); 266b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert kfree (dvbdev->fops); 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree (dvbdev); 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_unregister_device); 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvbdev_get_free_adapter_num (void) 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int num = 0; 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (num < DVB_MAX_ADAPTERS) { 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *entry; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (entry, &dvb_adapter_list) { 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_adapter *adap; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap = list_entry (entry, struct dvb_adapter, list_head); 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (adap->num == num) 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto skip; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return num; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip: 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num++; 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENFILE; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 293d09dbf92ada861244056d914a8f68b8be99891edAndrew de Quinceyint dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module, struct device *device) 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int num; 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2971e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar if (mutex_lock_interruptible(&dvbdev_register_lock)) 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ERESTARTSYS; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((num = dvbdev_get_free_adapter_num ()) < 0) { 3011e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar mutex_unlock(&dvbdev_register_lock); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENFILE; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset (adap, 0, sizeof(struct dvb_adapter)); 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD (&adap->device_list); 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk ("DVB: registering new adapter (%s).\n", name); 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap->num = num; 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap->name = name; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap->module = module; 313d09dbf92ada861244056d914a8f68b8be99891edAndrew de Quincey adap->device = device; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail (&adap->list_head, &dvb_adapter_list); 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3171e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar mutex_unlock(&dvbdev_register_lock); 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return num; 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_register_adapter); 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_unregister_adapter(struct dvb_adapter *adap) 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3261e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar if (mutex_lock_interruptible(&dvbdev_register_lock)) 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ERESTARTSYS; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del (&adap->list_head); 3291e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar mutex_unlock(&dvbdev_register_lock); 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_unregister_adapter); 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* if the miracle happens and "generic_usercopy()" is included into 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the kernel, then this can vanish. please don't make the mistake and 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds define this as video_usercopy(). this will introduce a dependecy 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to the v4l "videodev.o" module, which is unnecessary for some 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cards (ie. the budget dvb-cards don't need the v4l module...) */ 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_usercopy(struct inode *inode, struct file *file, 340afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab unsigned int cmd, unsigned long arg, 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int (*func)(struct inode *inode, struct file *file, 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cmd, void *arg)) 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 344afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab char sbuf[128]; 345afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab void *mbuf = NULL; 346afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab void *parg = NULL; 347afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab int err = -EINVAL; 348afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab 349afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab /* Copy arguments into temp kernel buffer */ 350afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab switch (_IOC_DIR(cmd)) { 351afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case _IOC_NONE: 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For this command, the pointer is actually an integer 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * argument. 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parg = (void *) arg; 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 358afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case _IOC_READ: /* some v4l ioctls are marked wrong ... */ 359afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case _IOC_WRITE: 360afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case (_IOC_WRITE | _IOC_READ): 361afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { 36250c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky parg = sbuf; 363afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab } else { 36450c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky /* too big to allocate from stack */ 36550c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); 36650c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky if (NULL == mbuf) 36750c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky return -ENOMEM; 36850c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky parg = mbuf; 369afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab } 370afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab 371afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab err = -EFAULT; 372afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) 37350c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky goto out; 374afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab break; 375afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab } 376afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab 377afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab /* call driver */ 378afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if ((err = func(inode, file, cmd, parg)) == -ENOIOCTLCMD) 379afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab err = -EINVAL; 380afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab 381afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (err < 0) 382afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab goto out; 383afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab 384afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab /* Copy results into user buffer */ 385afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab switch (_IOC_DIR(cmd)) 386afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab { 387afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case _IOC_READ: 388afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case (_IOC_WRITE | _IOC_READ): 389afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) 39050c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky err = -EFAULT; 391afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab break; 392afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab } 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 395afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab kfree(mbuf); 396afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return err; 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init_dvbdev(void) 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_t dev = MKDEV(DVB_MAJOR, 0); 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) { 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("dvb-core: unable to get major %d\n", DVB_MAJOR); 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cdev_init(&dvb_device_cdev, &dvb_device_fops); 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) { 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("dvb-core: unable to get major %d\n", DVB_MAJOR); 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41556b2293595b2eb52cc2aa2baf92c6cfa8265f9d5Greg Kroah-Hartman dvb_class = class_create(THIS_MODULE, "dvb"); 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(dvb_class)) { 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = PTR_ERR(dvb_class); 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror: 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cdev_del(&dvb_device_cdev); 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_chrdev_region(dev, MAX_DVB_MINORS); 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit exit_dvbdev(void) 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 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