ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[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/kernel.h>
29 #include <linux/sched.h>
30 #include <linux/init.h>
31 #include <linux/slab.h>
32
33 #include "dvbdev.h"
34 #include "dvb_functions.h"
35
36 static int dvbdev_debug = 0;
37 #define dprintk if (dvbdev_debug) printk
38
39 static LIST_HEAD(dvb_adapter_list);
40 static DECLARE_MUTEX(dvbdev_register_lock);
41
42
43 static char *dnames[] = { 
44         "video", "audio", "sec", "frontend", "demux", "dvr", "ca",
45         "net", "osd"
46 };
47
48
49 #define DVB_MAX_IDS              4
50 #define nums2minor(num,type,id)  ((num << 6) | (id << 4) | type)
51
52 static struct dvb_device* dvbdev_find_device (int minor)
53 {
54         struct list_head *entry;
55
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)
64                                 return dev;
65                 }
66         }
67
68         return NULL;
69 }
70
71
72 static int dvb_device_open(struct inode *inode, struct file *file)
73 {
74         struct dvb_device *dvbdev;
75         
76         dvbdev = dvbdev_find_device (iminor(inode));
77
78         if (dvbdev && dvbdev->fops) {
79                 int err = 0;
80                 struct file_operations *old_fops;
81
82                 file->private_data = dvbdev;
83                 old_fops = file->f_op;
84                 file->f_op = fops_get(dvbdev->fops);
85                 if(file->f_op->open)
86                         err = file->f_op->open(inode,file);
87                 if (err) {
88                         fops_put(file->f_op);
89                         file->f_op = fops_get(old_fops);
90                 }
91                 fops_put(old_fops);
92                 return err;
93         }
94         return -ENODEV;
95 }
96
97
98 static struct file_operations dvb_device_fops =
99 {
100         .owner =        THIS_MODULE,
101         .open =         dvb_device_open,
102 };
103
104
105 int dvb_generic_open(struct inode *inode, struct file *file)
106 {
107         struct dvb_device *dvbdev = file->private_data;
108
109         if (!dvbdev)
110                 return -ENODEV;
111
112         if (!dvbdev->users)
113                 return -EBUSY;
114
115         if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
116                 if (!dvbdev->readers)
117                         return -EBUSY;
118                 dvbdev->readers--;
119         } else {
120                 if (!dvbdev->writers)
121                         return -EBUSY;
122                 dvbdev->writers--;
123         }
124
125         dvbdev->users--;
126         return 0;
127 }
128
129
130 int dvb_generic_release(struct inode *inode, struct file *file)
131 {
132         struct dvb_device *dvbdev = file->private_data;
133
134         if (!dvbdev)
135                 return -ENODEV;
136
137         if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
138                 dvbdev->readers++;
139         } else {
140                 dvbdev->writers++;
141         }
142
143         dvbdev->users++;
144         return 0;
145 }
146
147
148 int dvb_generic_ioctl(struct inode *inode, struct file *file,
149                       unsigned int cmd, unsigned long arg)
150 {
151         struct dvb_device *dvbdev = file->private_data;
152         
153         if (!dvbdev)
154                 return -ENODEV;
155
156         if (!dvbdev->kernel_ioctl)
157                 return -EINVAL;
158
159         return dvb_usercopy (inode, file, cmd, arg, dvbdev->kernel_ioctl);
160 }
161
162
163 static int dvbdev_get_free_id (struct dvb_adapter *adap, int type)
164 {
165         u32 id = 0;
166
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)
173                                 goto skip;
174                 }
175                 return id;
176 skip:
177                 id++;
178         }
179         return -ENFILE;
180 }
181
182
183 int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, 
184                         const struct dvb_device *template, void *priv, int type)
185 {
186         struct dvb_device *dvbdev;
187         int id;
188
189         if (down_interruptible (&dvbdev_register_lock))
190                 return -ERESTARTSYS;
191
192         if ((id = dvbdev_get_free_id (adap, type)) < 0) {
193                 up (&dvbdev_register_lock);
194                 *pdvbdev = 0;
195                 printk ("%s: could get find free device id...\n", __FUNCTION__);
196                 return -ENFILE;
197         }
198
199         *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL);
200
201         if (!dvbdev) {
202                 up(&dvbdev_register_lock);
203                 return -ENOMEM;
204         }
205
206         up (&dvbdev_register_lock);
207         
208         memcpy(dvbdev, template, sizeof(struct dvb_device));
209         dvbdev->type = type;
210         dvbdev->id = id;
211         dvbdev->adapter = adap;
212         dvbdev->priv = priv;
213
214         dvbdev->fops->owner = adap->module;
215
216         list_add_tail (&dvbdev->list_head, &adap->device_list);
217
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);
221
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));
225
226         return 0;
227 }
228
229
230 void dvb_unregister_device(struct dvb_device *dvbdev)
231 {
232         if (!dvbdev)
233                 return;
234
235                 devfs_remove("dvb/adapter%d/%s%d", dvbdev->adapter->num,
236                                 dnames[dvbdev->type], dvbdev->id);
237
238                 list_del(&dvbdev->list_head);
239                 kfree(dvbdev);
240         }
241
242
243 static int dvbdev_get_free_adapter_num (void)
244 {
245         int num = 0;
246
247         while (1) {
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)
253                                 goto skip;
254                 }
255                 return num;
256 skip:
257                 num++;
258         }
259
260         return -ENFILE;
261 }
262
263
264 int dvb_register_adapter(struct dvb_adapter **padap, const char *name, struct module *module)
265 {
266         struct dvb_adapter *adap;
267         int num;
268
269         if (down_interruptible (&dvbdev_register_lock))
270                 return -ERESTARTSYS;
271
272         if ((num = dvbdev_get_free_adapter_num ()) < 0) {
273                 up (&dvbdev_register_lock);
274                 return -ENFILE;
275         }
276
277         if (!(*padap = adap = kmalloc(sizeof(struct dvb_adapter), GFP_KERNEL))) {
278                 up(&dvbdev_register_lock);
279                 return -ENOMEM;
280         }
281
282         memset (adap, 0, sizeof(struct dvb_adapter));
283         INIT_LIST_HEAD (&adap->device_list);
284
285         printk ("DVB: registering new adapter (%s).\n", name);
286         
287         devfs_mk_dir("dvb/adapter%d", num);
288
289         adap->num = num;
290         adap->name = name;
291         adap->module = module;
292
293         list_add_tail (&adap->list_head, &dvb_adapter_list);
294
295         up (&dvbdev_register_lock);
296
297         return num;
298 }
299
300
301 int dvb_unregister_adapter(struct dvb_adapter *adap)
302 {
303         if (down_interruptible (&dvbdev_register_lock))
304                 return -ERESTARTSYS;
305         devfs_remove("dvb/adapter%d", adap->num);
306         list_del (&adap->list_head);
307         up (&dvbdev_register_lock);
308         kfree (adap);
309         return 0;
310 }
311
312
313 static int __init init_dvbdev(void)
314 {
315         int retval;
316         devfs_mk_dir("dvb");
317
318         retval = register_chrdev(DVB_MAJOR,"DVB", &dvb_device_fops);
319         if (retval)
320                 printk("video_dev: unable to get major %d\n", DVB_MAJOR);
321
322         return retval;
323 }
324
325
326 static void __exit exit_dvbdev(void)
327 {
328         unregister_chrdev(DVB_MAJOR, "DVB");
329         devfs_remove("dvb");
330 }
331
332 module_init(init_dvbdev);
333 module_exit(exit_dvbdev);
334
335 MODULE_DESCRIPTION("DVB Core Driver");
336 MODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler");
337 MODULE_LICENSE("GPL");
338
339 MODULE_PARM(dvbdev_debug,"i");
340 MODULE_PARM_DESC(dvbdev_debug, "enable verbose debug messages");
341