vserver 1.9.5.x5
[linux-2.6.git] / drivers / media / dvb / dvb-core / dvbdev.c
1 /* 
2  * dvbdev.c
3  *
4  * Copyright (C) 2000 Ralph  Metzler <ralph@convergence.de>
5  *                  & Marcus Metzler <marcus@convergence.de>
6  *                    for convergence integrated media GmbH
7  *
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.
12  *
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.
17  *
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.
21  *
22  */
23
24 #include <linux/types.h>
25 #include <linux/errno.h>
26 #include <linux/string.h>
27 #include <linux/module.h>
28 #include <linux/moduleparam.h>
29 #include <linux/kernel.h>
30 #include <linux/sched.h>
31 #include <linux/init.h>
32 #include <linux/slab.h>
33 #include <linux/device.h>
34 #include <linux/fs.h>
35 #include <linux/cdev.h>
36
37 #include "dvbdev.h"
38
39 static int dvbdev_debug;
40
41 module_param(dvbdev_debug, int, 0644);
42 MODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off).");
43
44 #define dprintk if (dvbdev_debug) printk
45
46 static LIST_HEAD(dvb_adapter_list);
47 static DECLARE_MUTEX(dvbdev_register_lock);
48
49 static const char * const dnames[] = {
50         "video", "audio", "sec", "frontend", "demux", "dvr", "ca",
51         "net", "osd"
52 };
53
54
55 #define DVB_MAX_IDS              6
56 #define nums2minor(num,type,id)  ((num << 6) | (id << 4) | type)
57 #define MAX_DVB_MINORS           (DVB_MAX_IDS*64)
58
59 struct class_simple *dvb_class;
60 EXPORT_SYMBOL(dvb_class);
61
62 static struct dvb_device* dvbdev_find_device (int minor)
63 {
64         struct list_head *entry;
65
66         list_for_each (entry, &dvb_adapter_list) {
67                 struct list_head *entry0;
68                 struct dvb_adapter *adap;
69                 adap = list_entry (entry, struct dvb_adapter, list_head);
70                 list_for_each (entry0, &adap->device_list) {
71                         struct dvb_device *dev;
72                         dev = list_entry (entry0, struct dvb_device, list_head);
73                         if (nums2minor(adap->num, dev->type, dev->id) == minor)
74                                 return dev;
75                 }
76         }
77
78         return NULL;
79 }
80
81
82 static int dvb_device_open(struct inode *inode, struct file *file)
83 {
84         struct dvb_device *dvbdev;
85         
86         dvbdev = dvbdev_find_device (iminor(inode));
87
88         if (dvbdev && dvbdev->fops) {
89                 int err = 0;
90                 struct file_operations *old_fops;
91
92                 file->private_data = dvbdev;
93                 old_fops = file->f_op;
94                 file->f_op = fops_get(dvbdev->fops);
95                 if(file->f_op->open)
96                         err = file->f_op->open(inode,file);
97                 if (err) {
98                         fops_put(file->f_op);
99                         file->f_op = fops_get(old_fops);
100                 }
101                 fops_put(old_fops);
102                 return err;
103         }
104         return -ENODEV;
105 }
106
107
108 static struct file_operations dvb_device_fops =
109 {
110         .owner =        THIS_MODULE,
111         .open =         dvb_device_open,
112 };
113
114
115 static struct cdev dvb_device_cdev = {
116         .kobj   = {.name = "dvb", },
117         .owner  =       THIS_MODULE,
118 };
119
120 int dvb_generic_open(struct inode *inode, struct file *file)
121 {
122         struct dvb_device *dvbdev = file->private_data;
123
124         if (!dvbdev)
125                 return -ENODEV;
126
127         if (!dvbdev->users)
128                 return -EBUSY;
129
130         if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
131                 if (!dvbdev->readers)
132                         return -EBUSY;
133                 dvbdev->readers--;
134         } else {
135                 if (!dvbdev->writers)
136                         return -EBUSY;
137                 dvbdev->writers--;
138         }
139
140         dvbdev->users--;
141         return 0;
142 }
143 EXPORT_SYMBOL(dvb_generic_open);
144
145
146 int dvb_generic_release(struct inode *inode, struct file *file)
147 {
148         struct dvb_device *dvbdev = file->private_data;
149
150         if (!dvbdev)
151                 return -ENODEV;
152
153         if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
154                 dvbdev->readers++;
155         } else {
156                 dvbdev->writers++;
157         }
158
159         dvbdev->users++;
160         return 0;
161 }
162 EXPORT_SYMBOL(dvb_generic_release);
163
164
165 int dvb_generic_ioctl(struct inode *inode, struct file *file,
166                       unsigned int cmd, unsigned long arg)
167 {
168         struct dvb_device *dvbdev = file->private_data;
169         
170         if (!dvbdev)
171                 return -ENODEV;
172
173         if (!dvbdev->kernel_ioctl)
174                 return -EINVAL;
175
176         return dvb_usercopy (inode, file, cmd, arg, dvbdev->kernel_ioctl);
177 }
178 EXPORT_SYMBOL(dvb_generic_ioctl);
179
180
181 static int dvbdev_get_free_id (struct dvb_adapter *adap, int type)
182 {
183         u32 id = 0;
184
185         while (id < DVB_MAX_IDS) {
186                 struct list_head *entry;
187                 list_for_each (entry, &adap->device_list) {
188                         struct dvb_device *dev;
189                         dev = list_entry (entry, struct dvb_device, list_head);
190                         if (dev->type == type && dev->id == id)
191                                 goto skip;
192                 }
193                 return id;
194 skip:
195                 id++;
196         }
197         return -ENFILE;
198 }
199
200
201 int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, 
202                         const struct dvb_device *template, void *priv, int type)
203 {
204         struct dvb_device *dvbdev;
205         int id;
206
207         if (down_interruptible (&dvbdev_register_lock))
208                 return -ERESTARTSYS;
209
210         if ((id = dvbdev_get_free_id (adap, type)) < 0) {
211                 up (&dvbdev_register_lock);
212                 *pdvbdev = NULL;
213                 printk ("%s: could get find free device id...\n", __FUNCTION__);
214                 return -ENFILE;
215         }
216
217         *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL);
218
219         if (!dvbdev) {
220                 up(&dvbdev_register_lock);
221                 return -ENOMEM;
222         }
223
224         up (&dvbdev_register_lock);
225         
226         memcpy(dvbdev, template, sizeof(struct dvb_device));
227         dvbdev->type = type;
228         dvbdev->id = id;
229         dvbdev->adapter = adap;
230         dvbdev->priv = priv;
231
232         dvbdev->fops->owner = adap->module;
233
234         list_add_tail (&dvbdev->list_head, &adap->device_list);
235
236         devfs_mk_cdev(MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
237                         S_IFCHR | S_IRUSR | S_IWUSR,
238                         "dvb/adapter%d/%s%d", adap->num, dnames[type], id);
239
240         class_simple_device_add(dvb_class, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
241                                 NULL, "dvb%d.%s%d", adap->num, dnames[type], id);
242
243         dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
244                 adap->num, dnames[type], id, nums2minor(adap->num, type, id),
245                 nums2minor(adap->num, type, id));
246
247         return 0;
248 }
249 EXPORT_SYMBOL(dvb_register_device);
250
251
252 void dvb_unregister_device(struct dvb_device *dvbdev)
253 {
254         if (!dvbdev)
255                 return;
256
257                 devfs_remove("dvb/adapter%d/%s%d", dvbdev->adapter->num,
258                                 dnames[dvbdev->type], dvbdev->id);
259
260         class_simple_device_remove(MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
261                                         dvbdev->type, dvbdev->id)));
262
263                 list_del(&dvbdev->list_head);
264                 kfree(dvbdev);
265         }
266 EXPORT_SYMBOL(dvb_unregister_device);
267
268
269 static int dvbdev_get_free_adapter_num (void)
270 {
271         int num = 0;
272
273         while (1) {
274                 struct list_head *entry;
275                 list_for_each (entry, &dvb_adapter_list) {
276                         struct dvb_adapter *adap;
277                         adap = list_entry (entry, struct dvb_adapter, list_head);
278                         if (adap->num == num)
279                                 goto skip;
280                 }
281                 return num;
282 skip:
283                 num++;
284         }
285
286         return -ENFILE;
287 }
288
289
290 int dvb_register_adapter(struct dvb_adapter **padap, const char *name, struct module *module)
291 {
292         struct dvb_adapter *adap;
293         int num;
294
295         if (down_interruptible (&dvbdev_register_lock))
296                 return -ERESTARTSYS;
297
298         if ((num = dvbdev_get_free_adapter_num ()) < 0) {
299                 up (&dvbdev_register_lock);
300                 return -ENFILE;
301         }
302
303         if (!(*padap = adap = kmalloc(sizeof(struct dvb_adapter), GFP_KERNEL))) {
304                 up(&dvbdev_register_lock);
305                 return -ENOMEM;
306         }
307
308         memset (adap, 0, sizeof(struct dvb_adapter));
309         INIT_LIST_HEAD (&adap->device_list);
310
311         printk ("DVB: registering new adapter (%s).\n", name);
312         
313         devfs_mk_dir("dvb/adapter%d", num);
314
315         adap->num = num;
316         adap->name = name;
317         adap->module = module;
318
319         list_add_tail (&adap->list_head, &dvb_adapter_list);
320
321         up (&dvbdev_register_lock);
322
323         return num;
324 }
325 EXPORT_SYMBOL(dvb_register_adapter);
326
327
328 int dvb_unregister_adapter(struct dvb_adapter *adap)
329 {
330         devfs_remove("dvb/adapter%d", adap->num);
331
332         if (down_interruptible (&dvbdev_register_lock))
333                 return -ERESTARTSYS;
334         list_del (&adap->list_head);
335         up (&dvbdev_register_lock);
336         kfree (adap);
337         return 0;
338 }
339 EXPORT_SYMBOL(dvb_unregister_adapter);
340
341 /* if the miracle happens and "generic_usercopy()" is included into
342    the kernel, then this can vanish. please don't make the mistake and
343    define this as video_usercopy(). this will introduce a dependecy
344    to the v4l "videodev.o" module, which is unnecessary for some
345    cards (ie. the budget dvb-cards don't need the v4l module...) */
346 int dvb_usercopy(struct inode *inode, struct file *file,
347                      unsigned int cmd, unsigned long arg,
348                      int (*func)(struct inode *inode, struct file *file,
349                      unsigned int cmd, void *arg))
350 {
351         char    sbuf[128];
352         void    *mbuf = NULL;
353         void    *parg = NULL;
354         int     err  = -EINVAL;
355
356         /*  Copy arguments into temp kernel buffer  */
357         switch (_IOC_DIR(cmd)) {
358         case _IOC_NONE:
359                 /*
360                  * For this command, the pointer is actually an integer
361                  * argument.
362                  */
363                 parg = (void *) arg;
364                 break;
365         case _IOC_READ: /* some v4l ioctls are marked wrong ... */
366         case _IOC_WRITE:
367         case (_IOC_WRITE | _IOC_READ):
368                 if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
369                         parg = sbuf;
370                 } else {
371                         /* too big to allocate from stack */
372                         mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
373                         if (NULL == mbuf)
374                                 return -ENOMEM;
375                         parg = mbuf;
376                 }
377
378                 err = -EFAULT;
379                 if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
380                         goto out;
381                 break;
382         }
383
384         /* call driver */
385         if ((err = func(inode, file, cmd, parg)) == -ENOIOCTLCMD)
386                 err = -EINVAL;
387
388         if (err < 0)
389                 goto out;
390
391         /*  Copy results into user buffer  */
392         switch (_IOC_DIR(cmd))
393         {
394         case _IOC_READ:
395         case (_IOC_WRITE | _IOC_READ):
396                 if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
397                         err = -EFAULT;
398                 break;
399         }
400
401 out:
402         if (mbuf)
403                 kfree(mbuf);
404
405         return err;
406 }
407
408 static int __init init_dvbdev(void)
409 {
410         int retval;
411         dev_t dev = MKDEV(DVB_MAJOR, 0);
412
413         if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) {
414                 printk("dvb-core: unable to get major %d\n", DVB_MAJOR);
415                 return retval;
416         }
417
418         cdev_init(&dvb_device_cdev, &dvb_device_fops);
419         if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) {
420                 printk("dvb-core: unable to get major %d\n", DVB_MAJOR);
421                 goto error;
422         }
423
424         devfs_mk_dir("dvb");
425
426         dvb_class = class_simple_create(THIS_MODULE, "dvb");
427         if (IS_ERR(dvb_class)) {
428                 retval = PTR_ERR(dvb_class);
429                 goto error;
430         }
431         return 0;
432
433 error:
434         cdev_del(&dvb_device_cdev);
435         unregister_chrdev_region(dev, MAX_DVB_MINORS);
436         return retval;
437 }
438
439
440 static void __exit exit_dvbdev(void)
441 {
442         devfs_remove("dvb");
443         class_simple_destroy(dvb_class);
444         cdev_del(&dvb_device_cdev);
445         unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS);
446 }
447
448 module_init(init_dvbdev);
449 module_exit(exit_dvbdev);
450
451 MODULE_DESCRIPTION("DVB Core Driver");
452 MODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler");
453 MODULE_LICENSE("GPL");
454