4 * Copyright (C) 2000 Ralph Metzler <ralph@convergence.de>
5 * & Marcus Metzler <marcus@convergence.de>
6 * for convergence integrated media GmbH
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include <linux/types.h>
25 #include <linux/errno.h>
26 #include <linux/string.h>
27 #include <linux/module.h>
28 #include <linux/kernel.h>
29 #include <linux/sched.h>
30 #include <linux/init.h>
31 #include <linux/slab.h>
34 #include "dvb_functions.h"
36 static int dvbdev_debug = 0;
37 #define dprintk if (dvbdev_debug) printk
39 static LIST_HEAD(dvb_adapter_list);
40 static DECLARE_MUTEX(dvbdev_register_lock);
43 static char *dnames[] = {
44 "video", "audio", "sec", "frontend", "demux", "dvr", "ca",
50 #define nums2minor(num,type,id) ((num << 6) | (id << 4) | type)
52 static struct dvb_device* dvbdev_find_device (int minor)
54 struct list_head *entry;
56 list_for_each (entry, &dvb_adapter_list) {
57 struct list_head *entry0;
58 struct dvb_adapter *adap;
59 adap = list_entry (entry, struct dvb_adapter, list_head);
60 list_for_each (entry0, &adap->device_list) {
61 struct dvb_device *dev;
62 dev = list_entry (entry0, struct dvb_device, list_head);
63 if (nums2minor(adap->num, dev->type, dev->id) == minor)
72 static int dvb_device_open(struct inode *inode, struct file *file)
74 struct dvb_device *dvbdev;
76 dvbdev = dvbdev_find_device (iminor(inode));
78 if (dvbdev && dvbdev->fops) {
80 struct file_operations *old_fops;
82 file->private_data = dvbdev;
83 old_fops = file->f_op;
84 file->f_op = fops_get(dvbdev->fops);
86 err = file->f_op->open(inode,file);
89 file->f_op = fops_get(old_fops);
98 static struct file_operations dvb_device_fops =
100 .owner = THIS_MODULE,
101 .open = dvb_device_open,
105 int dvb_generic_open(struct inode *inode, struct file *file)
107 struct dvb_device *dvbdev = file->private_data;
115 if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
116 if (!dvbdev->readers)
120 if (!dvbdev->writers)
130 int dvb_generic_release(struct inode *inode, struct file *file)
132 struct dvb_device *dvbdev = file->private_data;
137 if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
148 int dvb_generic_ioctl(struct inode *inode, struct file *file,
149 unsigned int cmd, unsigned long arg)
151 struct dvb_device *dvbdev = file->private_data;
156 if (!dvbdev->kernel_ioctl)
159 return dvb_usercopy (inode, file, cmd, arg, dvbdev->kernel_ioctl);
163 static int dvbdev_get_free_id (struct dvb_adapter *adap, int type)
167 while (id < DVB_MAX_IDS) {
168 struct list_head *entry;
169 list_for_each (entry, &adap->device_list) {
170 struct dvb_device *dev;
171 dev = list_entry (entry, struct dvb_device, list_head);
172 if (dev->type == type && dev->id == id)
183 int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
184 const struct dvb_device *template, void *priv, int type)
186 struct dvb_device *dvbdev;
189 if (down_interruptible (&dvbdev_register_lock))
192 if ((id = dvbdev_get_free_id (adap, type)) < 0) {
193 up (&dvbdev_register_lock);
195 printk ("%s: could get find free device id...\n", __FUNCTION__);
199 *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL);
202 up(&dvbdev_register_lock);
206 up (&dvbdev_register_lock);
208 memcpy(dvbdev, template, sizeof(struct dvb_device));
211 dvbdev->adapter = adap;
214 dvbdev->fops->owner = adap->module;
216 list_add_tail (&dvbdev->list_head, &adap->device_list);
218 devfs_mk_cdev(MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
219 S_IFCHR | S_IRUSR | S_IWUSR,
220 "dvb/adapter%d/%s%d", adap->num, dnames[type], id);
222 dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
223 adap->num, dnames[type], id, nums2minor(adap->num, type, id),
224 nums2minor(adap->num, type, id));
230 void dvb_unregister_device(struct dvb_device *dvbdev)
235 devfs_remove("dvb/adapter%d/%s%d", dvbdev->adapter->num,
236 dnames[dvbdev->type], dvbdev->id);
238 list_del(&dvbdev->list_head);
243 static int dvbdev_get_free_adapter_num (void)
248 struct list_head *entry;
249 list_for_each (entry, &dvb_adapter_list) {
250 struct dvb_adapter *adap;
251 adap = list_entry (entry, struct dvb_adapter, list_head);
252 if (adap->num == num)
264 int dvb_register_adapter(struct dvb_adapter **padap, const char *name, struct module *module)
266 struct dvb_adapter *adap;
269 if (down_interruptible (&dvbdev_register_lock))
272 if ((num = dvbdev_get_free_adapter_num ()) < 0) {
273 up (&dvbdev_register_lock);
277 if (!(*padap = adap = kmalloc(sizeof(struct dvb_adapter), GFP_KERNEL))) {
278 up(&dvbdev_register_lock);
282 memset (adap, 0, sizeof(struct dvb_adapter));
283 INIT_LIST_HEAD (&adap->device_list);
285 printk ("DVB: registering new adapter (%s).\n", name);
287 devfs_mk_dir("dvb/adapter%d", num);
291 adap->module = module;
293 list_add_tail (&adap->list_head, &dvb_adapter_list);
295 up (&dvbdev_register_lock);
301 int dvb_unregister_adapter(struct dvb_adapter *adap)
303 if (down_interruptible (&dvbdev_register_lock))
305 devfs_remove("dvb/adapter%d", adap->num);
306 list_del (&adap->list_head);
307 up (&dvbdev_register_lock);
313 static int __init init_dvbdev(void)
318 retval = register_chrdev(DVB_MAJOR,"DVB", &dvb_device_fops);
320 printk("video_dev: unable to get major %d\n", DVB_MAJOR);
326 static void __exit exit_dvbdev(void)
328 unregister_chrdev(DVB_MAJOR, "DVB");
332 module_init(init_dvbdev);
333 module_exit(exit_dvbdev);
335 MODULE_DESCRIPTION("DVB Core Driver");
336 MODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler");
337 MODULE_LICENSE("GPL");
339 MODULE_PARM(dvbdev_debug,"i");
340 MODULE_PARM_DESC(dvbdev_debug, "enable verbose debug messages");