dvbdev.c revision e454cea20bdcff10ee698d11b8882662a0153a47
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> 355794e1b14bcd9817c5fa27d3254996f0d9551296Jonathan Corbet#include <linux/smp_lock.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 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 715794e1b14bcd9817c5fa27d3254996f0d9551296Jonathan Corbet lock_kernel(); 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); 945794e1b14bcd9817c5fa27d3254996f0d9551296Jonathan Corbet unlock_kernel(); 95afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return err; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 97f41ced8f108cc80f16509b907cd7ac93944459bcLaurent Pinchartfail: 985dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter up_read(&minor_rwsem); 995794e1b14bcd9817c5fa27d3254996f0d9551296Jonathan Corbet unlock_kernel(); 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, 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1107e7654a92a5a75a350cc3458389bc76273498f6aGreg Kroah-Hartmanstatic struct cdev dvb_device_cdev; 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_generic_open(struct inode *inode, struct file *file) 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 114afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab struct dvb_device *dvbdev = file->private_data; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 116afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (!dvbdev) 117afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return -ENODEV; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev->users) 120afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return -EBUSY; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((file->f_flags & O_ACCMODE) == O_RDONLY) { 123afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (!dvbdev->readers) 124afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return -EBUSY; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->readers--; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 127afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (!dvbdev->writers) 128afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return -EBUSY; 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->writers--; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->users--; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_generic_open); 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_generic_release(struct inode *inode, struct file *file) 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 140afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab struct dvb_device *dvbdev = file->private_data; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev) 143afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return -ENODEV; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((file->f_flags & O_ACCMODE) == O_RDONLY) { 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->readers++; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->writers++; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->users++; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_generic_release); 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_generic_ioctl(struct inode *inode, struct file *file, 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cmd, unsigned long arg) 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 160afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab struct dvb_device *dvbdev = file->private_data; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 162afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (!dvbdev) 163afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return -ENODEV; 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev->kernel_ioctl) 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return dvb_usercopy (inode, file, cmd, arg, dvbdev->kernel_ioctl); 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_generic_ioctl); 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvbdev_get_free_id (struct dvb_adapter *adap, int type) 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 id = 0; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (id < DVB_MAX_IDS) { 1787948261942ffdb35e274b8e1a0889601f45d4603Trent Piepho struct dvb_device *dev; 1797948261942ffdb35e274b8e1a0889601f45d4603Trent Piepho list_for_each_entry(dev, &adap->device_list, list_head) 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->type == type && dev->id == id) 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto skip; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return id; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip: 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds id++; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENFILE; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct dvb_device *template, void *priv, int type) 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_device *dvbdev; 194b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert struct file_operations *dvbdevfops; 1955f553388b06532b495681f5d6c8e8fbff64ea86aKay Sievers struct device *clsdev; 1965dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter int minor; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int id; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 199c278850206fd9df0bb62a72ca0b277fe20c5a452Simon Arlott mutex_lock(&dvbdev_register_lock); 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 201b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert if ((id = dvbdev_get_free_id (adap, type)) < 0){ 2021e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar mutex_unlock(&dvbdev_register_lock); 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *pdvbdev = NULL; 20446b4f7c176a2dd4c60ddb7c80bd09ea2f3220674Harvey Harrison printk(KERN_ERR "%s: couldn't find free device id\n", __func__); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENFILE; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL); 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 210b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert if (!dvbdev){ 211b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert mutex_unlock(&dvbdev_register_lock); 212b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert return -ENOMEM; 213b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert } 214b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert 215b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL); 216b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert 217b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert if (!dvbdevfops){ 218b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert kfree (dvbdev); 2191e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar mutex_unlock(&dvbdev_register_lock); 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(dvbdev, template, sizeof(struct dvb_device)); 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->type = type; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->id = id; 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->adapter = adap; 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvbdev->priv = priv; 228b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert dvbdev->fops = dvbdevfops; 229ca5be9cd0516629cb8ee335b7dad076e66d72a22Markus Rechberger init_waitqueue_head (&dvbdev->wait_queue); 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 231784e29d2031b535637f65a8b81fb0871c7c51b3fJan Engelhardt memcpy(dvbdevfops, template->fops, sizeof(struct file_operations)); 232784e29d2031b535637f65a8b81fb0871c7c51b3fJan Engelhardt dvbdevfops->owner = adap->module; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail (&dvbdev->list_head, &adap->device_list); 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2365dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter down_write(&minor_rwsem); 2375dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter#ifdef CONFIG_DVB_DYNAMIC_MINORS 2385dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter for (minor = 0; minor < MAX_DVB_MINORS; minor++) 2395dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter if (dvb_minors[minor] == NULL) 2405dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter break; 2415dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter 2425dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter if (minor == MAX_DVB_MINORS) { 2435dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter kfree(dvbdevfops); 2445dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter kfree(dvbdev); 2455dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter mutex_unlock(&dvbdev_register_lock); 2465dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter return -EINVAL; 2475dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter } 2485dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter#else 2495dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter minor = nums2minor(adap->num, type, id); 2505dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter#endif 2515dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter 2525dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter dvbdev->minor = minor; 2535dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter dvb_minors[minor] = dvbdev; 2545dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter up_write(&minor_rwsem); 2555dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter 256f47f4763cde162656448fcd1ada9d5e8101a00d2Andrew de Quincey mutex_unlock(&dvbdev_register_lock); 257f47f4763cde162656448fcd1ada9d5e8101a00d2Andrew de Quincey 258a9b12619f7b6f19c871437ec24a088787a04b1deGreg Kroah-Hartman clsdev = device_create(dvb_class, adap->device, 259b7496780e800061522de2262b4b4d7bf7602ecfaHans Verkuil MKDEV(DVB_MAJOR, minor), 260a5f4c0ce682efa60fa9552514118bb70a7646e28Kay Sievers dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id); 2614abdcf933f647763592db6bef001d1fae61a5527Simon Arlott if (IS_ERR(clsdev)) { 2624abdcf933f647763592db6bef001d1fae61a5527Simon Arlott printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n", 26346b4f7c176a2dd4c60ddb7c80bd09ea2f3220674Harvey Harrison __func__, adap->num, dnames[type], id, PTR_ERR(clsdev)); 2644abdcf933f647763592db6bef001d1fae61a5527Simon Arlott return PTR_ERR(clsdev); 2654abdcf933f647763592db6bef001d1fae61a5527Simon Arlott } 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 267900858ecb30c27ac94369052be650e25c0fd7d2aSimon Arlott dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", 2685dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter adap->num, dnames[type], id, minor, minor); 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_register_device); 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid dvb_unregister_device(struct dvb_device *dvbdev) 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dvbdev) 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2805dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter down_write(&minor_rwsem); 2815dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter dvb_minors[dvbdev->minor] = NULL; 2825dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter up_write(&minor_rwsem); 2835dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter 2845dd3f3071070f5a306bdf8d474c80062f5691cbaAndreas Oberritter device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor)); 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del (&dvbdev->list_head); 287b61901024776b25ce7b8edc31bb1757c7382a88eMarcel Siegert kfree (dvbdev->fops); 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree (dvbdev); 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_unregister_device); 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29278e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunaustatic int dvbdev_check_free_adapter_num(int num) 29378e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau{ 29478e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau struct list_head *entry; 29578e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau list_for_each(entry, &dvb_adapter_list) { 29678e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau struct dvb_adapter *adap; 29778e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau adap = list_entry(entry, struct dvb_adapter, list_head); 29878e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau if (adap->num == num) 29978e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau return 0; 30078e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau } 30178e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau return 1; 30278e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau} 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvbdev_get_free_adapter_num (void) 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int num = 0; 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (num < DVB_MAX_ADAPTERS) { 30978e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau if (dvbdev_check_free_adapter_num(num)) 31078e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau return num; 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num++; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENFILE; 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31878e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunauint dvb_register_adapter(struct dvb_adapter *adap, const char *name, 31978e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau struct module *module, struct device *device, 32078e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau short *adapter_nums) 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 32278e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau int i, num; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 324c278850206fd9df0bb62a72ca0b277fe20c5a452Simon Arlott mutex_lock(&dvbdev_register_lock); 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32678e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau for (i = 0; i < DVB_MAX_ADAPTERS; ++i) { 32778e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau num = adapter_nums[i]; 32878e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau if (num >= 0 && num < DVB_MAX_ADAPTERS) { 32978e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau /* use the one the driver asked for */ 33078e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau if (dvbdev_check_free_adapter_num(num)) 33178e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau break; 33278e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau } else { 33378e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau num = dvbdev_get_free_adapter_num(); 33478e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau break; 33578e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau } 33678e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau num = -1; 33778e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau } 33878e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau 33978e92006f410a4044f8c1760c25ac9d11d259aa2Janne Grunau if (num < 0) { 3401e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar mutex_unlock(&dvbdev_register_lock); 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENFILE; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset (adap, 0, sizeof(struct dvb_adapter)); 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD (&adap->device_list); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 347900858ecb30c27ac94369052be650e25c0fd7d2aSimon Arlott printk(KERN_INFO "DVB: registering new adapter (%s)\n", name); 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap->num = num; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap->name = name; 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adap->module = module; 352d09dbf92ada861244056d914a8f68b8be99891edAndrew de Quincey adap->device = device; 35359b1842da1c6f33ad2e8da82d3dfb3445751d964Darron Broad adap->mfe_shared = 0; 35459b1842da1c6f33ad2e8da82d3dfb3445751d964Darron Broad adap->mfe_dvbdev = NULL; 35559b1842da1c6f33ad2e8da82d3dfb3445751d964Darron Broad mutex_init (&adap->mfe_lock); 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail (&adap->list_head, &dvb_adapter_list); 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3591e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar mutex_unlock(&dvbdev_register_lock); 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return num; 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_register_adapter); 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_unregister_adapter(struct dvb_adapter *adap) 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 368c278850206fd9df0bb62a72ca0b277fe20c5a452Simon Arlott mutex_lock(&dvbdev_register_lock); 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del (&adap->list_head); 3701e4baed379a2bff3c728ea34602d3432fb047af8Ingo Molnar mutex_unlock(&dvbdev_register_lock); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_unregister_adapter); 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* if the miracle happens and "generic_usercopy()" is included into 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the kernel, then this can vanish. please don't make the mistake and 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds define this as video_usercopy(). this will introduce a dependecy 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to the v4l "videodev.o" module, which is unnecessary for some 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cards (ie. the budget dvb-cards don't need the v4l module...) */ 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_usercopy(struct inode *inode, struct file *file, 381afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab unsigned int cmd, unsigned long arg, 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int (*func)(struct inode *inode, struct file *file, 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cmd, void *arg)) 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 385afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab char sbuf[128]; 386afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab void *mbuf = NULL; 387afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab void *parg = NULL; 388afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab int err = -EINVAL; 389afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab 390afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab /* Copy arguments into temp kernel buffer */ 391afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab switch (_IOC_DIR(cmd)) { 392afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case _IOC_NONE: 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For this command, the pointer is actually an integer 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * argument. 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parg = (void *) arg; 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 399afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case _IOC_READ: /* some v4l ioctls are marked wrong ... */ 400afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case _IOC_WRITE: 401afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case (_IOC_WRITE | _IOC_READ): 402afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { 40350c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky parg = sbuf; 404afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab } else { 40550c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky /* too big to allocate from stack */ 40650c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); 40750c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky if (NULL == mbuf) 40850c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky return -ENOMEM; 40950c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky parg = mbuf; 410afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab } 411afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab 412afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab err = -EFAULT; 413afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) 41450c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky goto out; 415afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab break; 416afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab } 417afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab 418afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab /* call driver */ 419afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if ((err = func(inode, file, cmd, parg)) == -ENOIOCTLCMD) 420afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab err = -EINVAL; 421afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab 422afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (err < 0) 423afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab goto out; 424afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab 425afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab /* Copy results into user buffer */ 426afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab switch (_IOC_DIR(cmd)) 427afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab { 428afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case _IOC_READ: 429afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab case (_IOC_WRITE | _IOC_READ): 430afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) 43150c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky err = -EFAULT; 432afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab break; 433afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab } 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 436afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab kfree(mbuf); 437afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab return err; 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 440a5f4c0ce682efa60fa9552514118bb70a7646e28Kay Sieversstatic int dvb_uevent(struct device *dev, struct kobj_uevent_env *env) 441a5f4c0ce682efa60fa9552514118bb70a7646e28Kay Sievers{ 442a5f4c0ce682efa60fa9552514118bb70a7646e28Kay Sievers struct dvb_device *dvbdev = dev_get_drvdata(dev); 443a5f4c0ce682efa60fa9552514118bb70a7646e28Kay Sievers 444a5f4c0ce682efa60fa9552514118bb70a7646e28Kay Sievers add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num); 445763d19bb90a005a339b7d5ba70a710bb17db2babKay Sievers add_uevent_var(env, "DVB_DEVICE_TYPE=%s", dnames[dvbdev->type]); 446763d19bb90a005a339b7d5ba70a710bb17db2babKay Sievers add_uevent_var(env, "DVB_DEVICE_NUM=%d", dvbdev->id); 447a5f4c0ce682efa60fa9552514118bb70a7646e28Kay Sievers return 0; 448a5f4c0ce682efa60fa9552514118bb70a7646e28Kay Sievers} 449a5f4c0ce682efa60fa9552514118bb70a7646e28Kay Sievers 450e454cea20bdcff10ee698d11b8882662a0153a47Kay Sieversstatic char *dvb_devnode(struct device *dev, mode_t *mode) 4518a8bdcc7533b104d789d9bb3ed90da9352515e21Kay Sievers{ 4528a8bdcc7533b104d789d9bb3ed90da9352515e21Kay Sievers struct dvb_device *dvbdev = dev_get_drvdata(dev); 4538a8bdcc7533b104d789d9bb3ed90da9352515e21Kay Sievers 4548a8bdcc7533b104d789d9bb3ed90da9352515e21Kay Sievers return kasprintf(GFP_KERNEL, "dvb/adapter%d/%s%d", 4558a8bdcc7533b104d789d9bb3ed90da9352515e21Kay Sievers dvbdev->adapter->num, dnames[dvbdev->type], dvbdev->id); 4568a8bdcc7533b104d789d9bb3ed90da9352515e21Kay Sievers} 4578a8bdcc7533b104d789d9bb3ed90da9352515e21Kay Sievers 4588a8bdcc7533b104d789d9bb3ed90da9352515e21Kay Sievers 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init_dvbdev(void) 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_t dev = MKDEV(DVB_MAJOR, 0); 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) { 465900858ecb30c27ac94369052be650e25c0fd7d2aSimon Arlott printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR); 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cdev_init(&dvb_device_cdev, &dvb_device_fops); 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) { 471900858ecb30c27ac94369052be650e25c0fd7d2aSimon Arlott printk(KERN_ERR "dvb-core: unable register character device\n"); 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47556b2293595b2eb52cc2aa2baf92c6cfa8265f9d5Greg Kroah-Hartman dvb_class = class_create(THIS_MODULE, "dvb"); 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(dvb_class)) { 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = PTR_ERR(dvb_class); 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 480a5f4c0ce682efa60fa9552514118bb70a7646e28Kay Sievers dvb_class->dev_uevent = dvb_uevent; 481e454cea20bdcff10ee698d11b8882662a0153a47Kay Sievers dvb_class->devnode = dvb_devnode; 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror: 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cdev_del(&dvb_device_cdev); 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_chrdev_region(dev, MAX_DVB_MINORS); 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit exit_dvbdev(void) 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 49356b2293595b2eb52cc2aa2baf92c6cfa8265f9d5Greg Kroah-Hartman class_destroy(dvb_class); 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cdev_del(&dvb_device_cdev); 495afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS); 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4984abdcf933f647763592db6bef001d1fae61a5527Simon Arlottsubsys_initcall(init_dvbdev); 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(exit_dvbdev); 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("DVB Core Driver"); 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler"); 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 504