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/kernel.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/cdev.h> 341e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar#include <linux/mutex.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "dvbdev.h" 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3772024f1ec5164a70d84dd8cf4458fe4064a6b692Arnd Bergmannstatic DEFINE_MUTEX(dvbdev_mutex); 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 535dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter#ifdef CONFIG_DVB_DYNAMIC_MINORS 545dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter#define MAX_DVB_MINORS 256 555dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter#define DVB_MAX_IDS MAX_DVB_MINORS 565dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter#else 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DVB_MAX_IDS 4 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type) 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64) 605dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter#endif 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6256b2293595b2eb52cc2aa2baf92c6cfa8265f9d5Greg Kroah-Hartmanstatic struct class *dvb_class; 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 645dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritterstatic struct dvb_device *dvb_minors[MAX_DVB_MINORS]; 655dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritterstatic DECLARE_RWSEM(minor_rwsem); 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvb_device_open(struct inode *inode, struct file *file) 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_device *dvbdev; 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7172024f1ec5164a70d84dd8cf4458fe4064a6b692Arnd Bergmann mutex_lock(&dvbdev_mutex); 725dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter down_read(&minor_rwsem); 735dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter dvbdev = dvb_minors[iminor(inode)]; 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dvbdev && dvbdev->fops) { 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = 0; 7799ac48f54a91d02140c497edc31dc57d4bc5c85dArjan van de Ven const struct file_operations *old_fops; 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file->private_data = dvbdev; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds old_fops = file->f_op; 81afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab file->f_op = fops_get(dvbdev->fops); 82f41ced8f108cc80f16509b907cd7ac93944459bcLaurent Pinchart if (file->f_op == NULL) { 83f41ced8f108cc80f16509b907cd7ac93944459bcLaurent Pinchart file->f_op = old_fops; 84f41ced8f108cc80f16509b907cd7ac93944459bcLaurent Pinchart goto fail; 85f41ced8f108cc80f16509b907cd7ac93944459bcLaurent Pinchart } 86afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if(file->f_op->open) 8750c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky err = file->f_op->open(inode,file); 88afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (err) { 8950c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky fops_put(file->f_op); 9050c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky file->f_op = fops_get(old_fops); 91afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab } 92afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab fops_put(old_fops); 935dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter up_read(&minor_rwsem); 9472024f1ec5164a70d84dd8cf4458fe4064a6b692Arnd Bergmann mutex_unlock(&dvbdev_mutex); 95afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return err; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 97f41ced8f108cc80f16509b907cd7ac93944459bcLaurent Pinchartfail: 985dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter up_read(&minor_rwsem); 9972024f1ec5164a70d84dd8cf4458fe4064a6b692Arnd Bergmann mutex_unlock(&dvbdev_mutex); 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10427a643b1a9eded6a1b54df2743a7fb4383fd0cf9Jan Engelhardtstatic const struct file_operations dvb_device_fops = 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = dvb_device_open, 1086038f373a3dc1f1c26496e60b6c40b164716f07eArnd Bergmann .llseek = noop_llseek, 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1117e7654a92a5a75a350cc3458389bc76273498f6aGreg Kroah-Hartmanstatic struct cdev dvb_device_cdev; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_generic_open(struct inode *inode, struct file *file) 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 115afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab struct dvb_device *dvbdev = file->private_data; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 117afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (!dvbdev) 118afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return -ENODEV; 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev->users) 121afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return -EBUSY; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((file->f_flags & O_ACCMODE) == O_RDONLY) { 124afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (!dvbdev->readers) 125afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return -EBUSY; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->readers--; 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 128afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (!dvbdev->writers) 129afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return -EBUSY; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->writers--; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->users--; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_generic_open); 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_generic_release(struct inode *inode, struct file *file) 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 141afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab struct dvb_device *dvbdev = file->private_data; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev) 144afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return -ENODEV; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((file->f_flags & O_ACCMODE) == O_RDONLY) { 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->readers++; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->writers++; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->users++; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_generic_release); 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15816ef8def80ea97c3cacdcaa765bdf62b2d94f86dArnd Bergmannlong dvb_generic_ioctl(struct file *file, 15916ef8def80ea97c3cacdcaa765bdf62b2d94f86dArnd Bergmann unsigned int cmd, unsigned long arg) 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 161afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab struct dvb_device *dvbdev = file->private_data; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 163afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (!dvbdev) 164afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return -ENODEV; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev->kernel_ioctl) 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16972024f1ec5164a70d84dd8cf4458fe4064a6b692Arnd Bergmann return dvb_usercopy(file, cmd, arg, dvbdev->kernel_ioctl); 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_generic_ioctl); 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvbdev_get_free_id (struct dvb_adapter *adap, int type) 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 id = 0; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (id < DVB_MAX_IDS) { 1797948261942ffdb35e274b8e1a0889601f45d4603Trent Piepho struct dvb_device *dev; 1807948261942ffdb35e274b8e1a0889601f45d4603Trent Piepho list_for_each_entry(dev, &adap->device_list, list_head) 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->type == type && dev->id == id) 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto skip; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return id; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip: 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds id++; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENFILE; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct dvb_device *template, void *priv, int type) 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_device *dvbdev; 195b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert struct file_operations *dvbdevfops; 1965f553388b06532b495681f5d6c8e8fbff64ea86aKay Sievers struct device *clsdev; 1975dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter int minor; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int id; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 200c278850206fd9df0bb62a72ca0b277fe20c5a452Simon Arlott mutex_lock(&dvbdev_register_lock); 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 202b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert if ((id = dvbdev_get_free_id (adap, type)) < 0){ 2031e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar mutex_unlock(&dvbdev_register_lock); 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *pdvbdev = NULL; 20546b4f7c176a2dd4c60ddb7c80bd09ea2f3220674Harvey Harrison printk(KERN_ERR "%s: couldn't find free device id\n", __func__); 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENFILE; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL); 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 211b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert if (!dvbdev){ 212b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert mutex_unlock(&dvbdev_register_lock); 213b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert return -ENOMEM; 214b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert } 215b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert 216b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL); 217b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert 218b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert if (!dvbdevfops){ 219b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert kfree (dvbdev); 2201e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar mutex_unlock(&dvbdev_register_lock); 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 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; 229b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert dvbdev->fops = dvbdevfops; 230ca5be9cd0516629cb8ee335b7dad076e66d72a22Markus Rechberger init_waitqueue_head (&dvbdev->wait_queue); 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 232784e29d2031b535637f65a8b81fb0871c7c51b3fJan Engelhardt memcpy(dvbdevfops, template->fops, sizeof(struct file_operations)); 233784e29d2031b535637f65a8b81fb0871c7c51b3fJan Engelhardt dvbdevfops->owner = adap->module; 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail (&dvbdev->list_head, &adap->device_list); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2375dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter down_write(&minor_rwsem); 2385dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter#ifdef CONFIG_DVB_DYNAMIC_MINORS 2395dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter for (minor = 0; minor < MAX_DVB_MINORS; minor++) 2405dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter if (dvb_minors[minor] == NULL) 2415dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter break; 2425dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter 2435dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter if (minor == MAX_DVB_MINORS) { 2445dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter kfree(dvbdevfops); 2455dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter kfree(dvbdev); 2465dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter mutex_unlock(&dvbdev_register_lock); 2475dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter return -EINVAL; 2485dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter } 2495dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter#else 2505dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter minor = nums2minor(adap->num, type, id); 2515dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter#endif 2525dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter 2535dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter dvbdev->minor = minor; 2545dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter dvb_minors[minor] = dvbdev; 2555dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter up_write(&minor_rwsem); 2565dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter 257f47f4763cde162656448fcd1ada9d5e8101a00d2Andrew de Quincey mutex_unlock(&dvbdev_register_lock); 258f47f4763cde162656448fcd1ada9d5e8101a00d2Andrew de Quincey 259a9b12619f7b6f19c871437ec24a088787a04b1deGreg Kroah-Hartman clsdev = device_create(dvb_class, adap->device, 260b7496780e800061522de2262b4b4d7bf7602ecfaHans Verkuil MKDEV(DVB_MAJOR, minor), 261a5f4c0ce682efa60fa9552514118bb70a7646e28Kay Sievers dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id); 2624abdcf933f647763592db6bef001d1fae61a5527Simon Arlott if (IS_ERR(clsdev)) { 2634abdcf933f647763592db6bef001d1fae61a5527Simon Arlott printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n", 26446b4f7c176a2dd4c60ddb7c80bd09ea2f3220674Harvey Harrison __func__, adap->num, dnames[type], id, PTR_ERR(clsdev)); 2654abdcf933f647763592db6bef001d1fae61a5527Simon Arlott return PTR_ERR(clsdev); 2664abdcf933f647763592db6bef001d1fae61a5527Simon Arlott } 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 268900858ecb30c27ac94369052be650e25c0fd7d2aSimon Arlott dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", 2695dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter adap->num, dnames[type], id, minor, minor); 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_register_device); 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid dvb_unregister_device(struct dvb_device *dvbdev) 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev) 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2815dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter down_write(&minor_rwsem); 2825dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter dvb_minors[dvbdev->minor] = NULL; 2835dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter up_write(&minor_rwsem); 2845dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter 2855dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor)); 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del (&dvbdev->list_head); 288b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert kfree (dvbdev->fops); 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree (dvbdev); 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_unregister_device); 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29378e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunaustatic int dvbdev_check_free_adapter_num(int num) 29478e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau{ 29578e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau struct list_head *entry; 29678e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau list_for_each(entry, &dvb_adapter_list) { 29778e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau struct dvb_adapter *adap; 29878e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau adap = list_entry(entry, struct dvb_adapter, list_head); 29978e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau if (adap->num == num) 30078e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau return 0; 30178e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau } 30278e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau return 1; 30378e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau} 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvbdev_get_free_adapter_num (void) 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int num = 0; 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (num < DVB_MAX_ADAPTERS) { 31078e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau if (dvbdev_check_free_adapter_num(num)) 31178e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau return num; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num++; 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENFILE; 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31978e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunauint dvb_register_adapter(struct dvb_adapter *adap, const char *name, 32078e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau struct module *module, struct device *device, 32178e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau short *adapter_nums) 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 32378e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau int i, num; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 325c278850206fd9df0bb62a72ca0b277fe20c5a452Simon Arlott mutex_lock(&dvbdev_register_lock); 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32778e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau for (i = 0; i < DVB_MAX_ADAPTERS; ++i) { 32878e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau num = adapter_nums[i]; 32978e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau if (num >= 0 && num < DVB_MAX_ADAPTERS) { 33078e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau /* use the one the driver asked for */ 33178e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau if (dvbdev_check_free_adapter_num(num)) 33278e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau break; 33378e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau } else { 33478e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau num = dvbdev_get_free_adapter_num(); 33578e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau break; 33678e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau } 33778e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau num = -1; 33878e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau } 33978e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau 34078e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau if (num < 0) { 3411e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar mutex_unlock(&dvbdev_register_lock); 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENFILE; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset (adap, 0, sizeof(struct dvb_adapter)); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD (&adap->device_list); 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 348900858ecb30c27ac94369052be650e25c0fd7d2aSimon Arlott printk(KERN_INFO "DVB: registering new adapter (%s)\n", name); 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap->num = num; 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap->name = name; 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap->module = module; 353d09dbf92ada861244056d914a8f68b8be99891edAndrew de Quincey adap->device = device; 35459b1842da1c6f33ad2e8da82d3dfb3445751d964Darron Broad adap->mfe_shared = 0; 35559b1842da1c6f33ad2e8da82d3dfb3445751d964Darron Broad adap->mfe_dvbdev = NULL; 35659b1842da1c6f33ad2e8da82d3dfb3445751d964Darron Broad mutex_init (&adap->mfe_lock); 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail (&adap->list_head, &dvb_adapter_list); 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3601e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar mutex_unlock(&dvbdev_register_lock); 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return num; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_register_adapter); 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_unregister_adapter(struct dvb_adapter *adap) 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 369c278850206fd9df0bb62a72ca0b277fe20c5a452Simon Arlott mutex_lock(&dvbdev_register_lock); 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del (&adap->list_head); 3711e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar mutex_unlock(&dvbdev_register_lock); 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_unregister_adapter); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* if the miracle happens and "generic_usercopy()" is included into 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the kernel, then this can vanish. please don't make the mistake and 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds define this as video_usercopy(). this will introduce a dependecy 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to the v4l "videodev.o" module, which is unnecessary for some 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cards (ie. the budget dvb-cards don't need the v4l module...) */ 38116ef8def80ea97c3cacdcaa765bdf62b2d94f86dArnd Bergmannint dvb_usercopy(struct file *file, 382afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab unsigned int cmd, unsigned long arg, 38316ef8def80ea97c3cacdcaa765bdf62b2d94f86dArnd Bergmann int (*func)(struct file *file, 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cmd, void *arg)) 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 386afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab char sbuf[128]; 387afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab void *mbuf = NULL; 388afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab void *parg = NULL; 389afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab int err = -EINVAL; 390afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab 391afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab /* Copy arguments into temp kernel buffer */ 392afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab switch (_IOC_DIR(cmd)) { 393afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case _IOC_NONE: 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For this command, the pointer is actually an integer 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * argument. 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parg = (void *) arg; 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 400afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case _IOC_READ: /* some v4l ioctls are marked wrong ... */ 401afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case _IOC_WRITE: 402afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case (_IOC_WRITE | _IOC_READ): 403afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { 40450c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky parg = sbuf; 405afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab } else { 40650c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky /* too big to allocate from stack */ 40750c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); 40850c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky if (NULL == mbuf) 40950c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky return -ENOMEM; 41050c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky parg = mbuf; 411afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab } 412afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab 413afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab err = -EFAULT; 414afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) 41550c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky goto out; 416afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab break; 417afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab } 418afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab 419afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab /* call driver */ 42072024f1ec5164a70d84dd8cf4458fe4064a6b692Arnd Bergmann mutex_lock(&dvbdev_mutex); 42116ef8def80ea97c3cacdcaa765bdf62b2d94f86dArnd Bergmann if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD) 422afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab err = -EINVAL; 42372024f1ec5164a70d84dd8cf4458fe4064a6b692Arnd Bergmann mutex_unlock(&dvbdev_mutex); 424afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab 425afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (err < 0) 426afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab goto out; 427afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab 428afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab /* Copy results into user buffer */ 429afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab switch (_IOC_DIR(cmd)) 430afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab { 431afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case _IOC_READ: 432afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case (_IOC_WRITE | _IOC_READ): 433afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) 43450c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky err = -EFAULT; 435afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab break; 436afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab } 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 439afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab kfree(mbuf); 440afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return err; 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 443a5f4c0ce682efa60fa9552514118bb70a7646e28Kay Sieversstatic int dvb_uevent(struct device *dev, struct kobj_uevent_env *env) 444a5f4c0ce682efa60fa9552514118bb70a7646e28Kay Sievers{ 445a5f4c0ce682efa60fa9552514118bb70a7646e28Kay Sievers struct dvb_device *dvbdev = dev_get_drvdata(dev); 446a5f4c0ce682efa60fa9552514118bb70a7646e28Kay Sievers 447a5f4c0ce682efa60fa9552514118bb70a7646e28Kay Sievers add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num); 448763d19bb90a005a339b7d5ba70a710bb17db2babKay Sievers add_uevent_var(env, "DVB_DEVICE_TYPE=%s", dnames[dvbdev->type]); 449763d19bb90a005a339b7d5ba70a710bb17db2babKay Sievers add_uevent_var(env, "DVB_DEVICE_NUM=%d", dvbdev->id); 450a5f4c0ce682efa60fa9552514118bb70a7646e28Kay Sievers return 0; 451a5f4c0ce682efa60fa9552514118bb70a7646e28Kay Sievers} 452a5f4c0ce682efa60fa9552514118bb70a7646e28Kay Sievers 4532c9ede55ecec58099b72e4bb8eab719f32f72c31Al Virostatic char *dvb_devnode(struct device *dev, umode_t *mode) 4548a8bdcc7533b104d789d9bb3ed90da9352515e21Kay Sievers{ 4558a8bdcc7533b104d789d9bb3ed90da9352515e21Kay Sievers struct dvb_device *dvbdev = dev_get_drvdata(dev); 4568a8bdcc7533b104d789d9bb3ed90da9352515e21Kay Sievers 4578a8bdcc7533b104d789d9bb3ed90da9352515e21Kay Sievers return kasprintf(GFP_KERNEL, "dvb/adapter%d/%s%d", 4588a8bdcc7533b104d789d9bb3ed90da9352515e21Kay Sievers dvbdev->adapter->num, dnames[dvbdev->type], dvbdev->id); 4598a8bdcc7533b104d789d9bb3ed90da9352515e21Kay Sievers} 4608a8bdcc7533b104d789d9bb3ed90da9352515e21Kay Sievers 4618a8bdcc7533b104d789d9bb3ed90da9352515e21Kay Sievers 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init_dvbdev(void) 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_t dev = MKDEV(DVB_MAJOR, 0); 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) { 468900858ecb30c27ac94369052be650e25c0fd7d2aSimon Arlott printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR); 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cdev_init(&dvb_device_cdev, &dvb_device_fops); 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) { 474900858ecb30c27ac94369052be650e25c0fd7d2aSimon Arlott printk(KERN_ERR "dvb-core: unable register character device\n"); 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47856b2293595b2eb52cc2aa2baf92c6cfa8265f9d5Greg Kroah-Hartman dvb_class = class_create(THIS_MODULE, "dvb"); 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(dvb_class)) { 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = PTR_ERR(dvb_class); 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 483a5f4c0ce682efa60fa9552514118bb70a7646e28Kay Sievers dvb_class->dev_uevent = dvb_uevent; 484e454cea20bdcff10ee698d11b8882662a0153a47Kay Sievers dvb_class->devnode = dvb_devnode; 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror: 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cdev_del(&dvb_device_cdev); 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_chrdev_region(dev, MAX_DVB_MINORS); 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit exit_dvbdev(void) 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 49656b2293595b2eb52cc2aa2baf92c6cfa8265f9d5Greg Kroah-Hartman class_destroy(dvb_class); 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cdev_del(&dvb_device_cdev); 498afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS); 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5014abdcf933f647763592db6bef001d1fae61a5527Simon Arlottsubsys_initcall(init_dvbdev); 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(exit_dvbdev); 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("DVB Core Driver"); 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler"); 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 507