1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/config.h>
19#include <linux/version.h>
20#include <linux/module.h>
21#include <linux/types.h>
22#include <linux/kernel.h>
23#include <linux/sched.h>
24#include <linux/smp_lock.h>
25#include <linux/mm.h>
26#include <linux/string.h>
27#include <linux/errno.h>
28#include <linux/init.h>
29#include <linux/kmod.h>
30#include <linux/slab.h>
31#include <asm/uaccess.h>
32#include <asm/system.h>
33#include <asm/semaphore.h>
34
35#include <linux/videodev.h>
36
37#define VIDEO_NUM_DEVICES 256
38
39
40
41
42
43static struct video_device *video_device[VIDEO_NUM_DEVICES];
44static DECLARE_MUTEX(videodev_lock);
45
46
47#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
48
49#include <linux/proc_fs.h>
50
51struct videodev_proc_data {
52 struct list_head proc_list;
53 char name[16];
54 struct video_device *vdev;
55 struct proc_dir_entry *proc_entry;
56};
57
58static struct proc_dir_entry *video_dev_proc_entry = NULL;
59struct proc_dir_entry *video_proc_entry = NULL;
60EXPORT_SYMBOL(video_proc_entry);
61LIST_HEAD(videodev_proc_list);
62
63#endif
64
65
66
67
68
69
70static ssize_t video_read(struct file *file,
71 char *buf, size_t count, loff_t *ppos)
72{
73 struct video_device *vfl = video_devdata(file);
74 if(vfl->read)
75 return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK);
76 else
77 return -EINVAL;
78}
79
80
81
82
83
84
85
86static ssize_t video_write(struct file *file, const char *buf,
87 size_t count, loff_t *ppos)
88{
89 struct video_device *vfl = video_devdata(file);
90 if(vfl->write)
91 return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK);
92 else
93 return 0;
94}
95
96struct video_device* video_devdata(struct file *file)
97{
98 return video_device[minor(file->f_dentry->d_inode->i_rdev)];
99}
100
101
102
103
104
105
106static unsigned int video_poll(struct file *file, poll_table * wait)
107{
108 struct video_device *vfl = video_devdata(file);
109 if(vfl->poll)
110 return vfl->poll(vfl, file, wait);
111 else
112 return 0;
113}
114
115
116
117
118
119
120static int video_open(struct inode *inode, struct file *file)
121{
122 unsigned int minor = minor(inode->i_rdev);
123 int err = 0;
124 struct video_device *vfl;
125
126 if(minor>=VIDEO_NUM_DEVICES)
127 return -ENODEV;
128 down(&videodev_lock);
129 vfl=video_device[minor];
130 if(vfl==NULL) {
131 char modname[20];
132
133 up(&videodev_lock);
134 sprintf (modname, "char-major-%d-%d", VIDEO_MAJOR, minor);
135 request_module(modname);
136 down(&videodev_lock);
137 vfl=video_device[minor];
138 if (vfl==NULL) {
139 err = -ENODEV;
140 goto unlock_out;
141 }
142 }
143 if (vfl->fops) {
144 struct file_operations *old_fops;
145
146 old_fops = file->f_op;
147 file->f_op = fops_get(vfl->fops);
148 if(file->f_op->open)
149 err = file->f_op->open(inode,file);
150 if (err) {
151 fops_put(file->f_op);
152 file->f_op = fops_get(old_fops);
153 }
154 fops_put(old_fops);
155 goto unlock_out;
156 }
157 if(vfl->users) {
158 err = -EBUSY;
159 goto unlock_out;
160 }
161 vfl->users++;
162
163 if(vfl->owner)
164 __MOD_INC_USE_COUNT(vfl->owner);
165
166 if (vfl->open) {
167 err=vfl->open(vfl,0);
168 if (err) {
169 vfl->users--;
170 if(vfl->owner)
171 __MOD_DEC_USE_COUNT(vfl->owner);
172 goto unlock_out;
173 }
174 }
175 err = 0;
176
177unlock_out:
178 up(&videodev_lock);
179 return err;
180}
181
182
183
184
185
186static int video_release(struct inode *inode, struct file *file)
187{
188 struct video_device *vfl;
189 struct module *owner;
190
191 vfl = video_devdata(file);
192 owner = vfl->owner;
193 if (vfl->close)
194 vfl->close(vfl);
195
196 down(&videodev_lock);
197
198
199 vfl = video_devdata(file);
200 if (NULL != vfl)
201 vfl->users--;
202 if (owner)
203 __MOD_DEC_USE_COUNT(owner);
204 up(&videodev_lock);
205 return 0;
206}
207
208static int video_ioctl(struct inode *inode, struct file *file,
209 unsigned int cmd, unsigned long arg)
210{
211 struct video_device *vfl = video_devdata(file);
212 int err=vfl->ioctl(vfl, cmd, (void *)arg);
213
214 if(err!=-ENOIOCTLCMD)
215 return err;
216
217 switch(cmd)
218 {
219 default:
220 return -EINVAL;
221 }
222}
223
224
225
226
227
228int video_mmap(struct file *file, struct vm_area_struct *vma)
229{
230 int ret = -EINVAL;
231 struct video_device *vfl = video_devdata(file);
232 if(vfl->mmap) {
233 lock_kernel();
234 ret = vfl->mmap(vfl, (char *)vma->vm_start,
235 (unsigned long)(vma->vm_end-vma->vm_start));
236 unlock_kernel();
237 }
238 return ret;
239}
240
241
242
243
244int
245video_usercopy(struct inode *inode, struct file *file,
246 unsigned int cmd, unsigned long arg,
247 int (*func)(struct inode *inode, struct file *file,
248 unsigned int cmd, void *arg))
249{
250 char sbuf[128];
251 void *mbuf = NULL;
252 void *parg = NULL;
253 int err = -EINVAL;
254
255
256 switch (_IOC_DIR(cmd)) {
257 case _IOC_NONE:
258 parg = (void *)arg;
259 break;
260 case _IOC_READ:
261 case _IOC_WRITE:
262 case (_IOC_WRITE | _IOC_READ):
263 if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
264 parg = sbuf;
265 } else {
266
267 mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
268 if (NULL == mbuf)
269 return -ENOMEM;
270 parg = mbuf;
271 }
272
273 err = -EFAULT;
274 if (copy_from_user(parg, (void *)arg, _IOC_SIZE(cmd)))
275 goto out;
276 break;
277 }
278
279
280 err = func(inode, file, cmd, parg);
281 if (err == -ENOIOCTLCMD)
282 err = -EINVAL;
283 if (err < 0)
284 goto out;
285
286
287 switch (_IOC_DIR(cmd))
288 {
289 case _IOC_READ:
290 case (_IOC_WRITE | _IOC_READ):
291 if (copy_to_user((void *)arg, parg, _IOC_SIZE(cmd)))
292 err = -EFAULT;
293 break;
294 }
295
296out:
297 if (mbuf)
298 kfree(mbuf);
299 return err;
300}
301
302
303
304
305extern int video_exclusive_open(struct inode *inode, struct file *file)
306{
307 struct video_device *vfl = video_devdata(file);
308 int retval = 0;
309
310 down(&vfl->lock);
311 if (vfl->users) {
312 retval = -EBUSY;
313 } else {
314 vfl->users++;
315 }
316 up(&vfl->lock);
317 return retval;
318}
319
320extern int video_exclusive_release(struct inode *inode, struct file *file)
321{
322 struct video_device *vfl = video_devdata(file);
323
324 vfl->users--;
325 return 0;
326}
327
328
329
330
331
332#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
333
334
335
336
337static int videodev_proc_read(char *page, char **start, off_t off,
338 int count, int *eof, void *data)
339{
340 char *out = page;
341 struct video_device *vfd = data;
342 struct videodev_proc_data *d;
343 struct list_head *tmp;
344 int len;
345 char c = ' ';
346
347 list_for_each (tmp, &videodev_proc_list) {
348 d = list_entry(tmp, struct videodev_proc_data, proc_list);
349 if (vfd == d->vdev)
350 break;
351 }
352
353
354 if (tmp == &videodev_proc_list)
355 goto skip;
356
357#define PRINT_VID_TYPE(x) do { if (vfd->type & x) \
358 out += sprintf (out, "%c%s", c, #x); c='|';} while (0)
359
360 out += sprintf (out, "name : %s\n", vfd->name);
361 out += sprintf (out, "type :");
362 PRINT_VID_TYPE(VID_TYPE_CAPTURE);
363 PRINT_VID_TYPE(VID_TYPE_TUNER);
364 PRINT_VID_TYPE(VID_TYPE_TELETEXT);
365 PRINT_VID_TYPE(VID_TYPE_OVERLAY);
366 PRINT_VID_TYPE(VID_TYPE_CHROMAKEY);
367 PRINT_VID_TYPE(VID_TYPE_CLIPPING);
368 PRINT_VID_TYPE(VID_TYPE_FRAMERAM);
369 PRINT_VID_TYPE(VID_TYPE_SCALES);
370 PRINT_VID_TYPE(VID_TYPE_MONOCHROME);
371 PRINT_VID_TYPE(VID_TYPE_SUBCAPTURE);
372 PRINT_VID_TYPE(VID_TYPE_MPEG_DECODER);
373 PRINT_VID_TYPE(VID_TYPE_MPEG_ENCODER);
374 PRINT_VID_TYPE(VID_TYPE_MJPEG_DECODER);
375 PRINT_VID_TYPE(VID_TYPE_MJPEG_ENCODER);
376 out += sprintf (out, "\n");
377 out += sprintf (out, "hardware : 0x%x\n", vfd->hardware);
378#if 0
379 out += sprintf (out, "channels : %d\n", d->vcap.channels);
380 out += sprintf (out, "audios : %d\n", d->vcap.audios);
381 out += sprintf (out, "maxwidth : %d\n", d->vcap.maxwidth);
382 out += sprintf (out, "maxheight : %d\n", d->vcap.maxheight);
383 out += sprintf (out, "minwidth : %d\n", d->vcap.minwidth);
384 out += sprintf (out, "minheight : %d\n", d->vcap.minheight);
385#endif
386
387skip:
388 len = out - page;
389 len -= off;
390 if (len < count) {
391 *eof = 1;
392 if (len <= 0)
393 return 0;
394 } else
395 len = count;
396
397 *start = page + off;
398
399 return len;
400}
401
402static void videodev_proc_create(void)
403{
404 video_proc_entry = create_proc_entry("video", S_IFDIR, &proc_root);
405
406 if (video_proc_entry == NULL) {
407 printk("video_dev: unable to initialise /proc/video\n");
408 return;
409 }
410
411 video_proc_entry->owner = THIS_MODULE;
412 video_dev_proc_entry = create_proc_entry("dev", S_IFDIR, video_proc_entry);
413
414 if (video_dev_proc_entry == NULL) {
415 printk("video_dev: unable to initialise /proc/video/dev\n");
416 return;
417 }
418
419 video_dev_proc_entry->owner = THIS_MODULE;
420}
421
422#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
423static void videodev_proc_destroy(void)
424{
425 if (video_dev_proc_entry != NULL)
426 remove_proc_entry("dev", video_proc_entry);
427
428 if (video_proc_entry != NULL)
429 remove_proc_entry("video", &proc_root);
430}
431#endif
432
433static void videodev_proc_create_dev (struct video_device *vfd, char *name)
434{
435 struct videodev_proc_data *d;
436 struct proc_dir_entry *p;
437
438 if (video_dev_proc_entry == NULL)
439 return;
440
441 d = kmalloc (sizeof (struct videodev_proc_data), GFP_KERNEL);
442 if (!d)
443 return;
444
445 p = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, video_dev_proc_entry);
446 if (!p)
447 return;
448 p->data = vfd;
449 p->read_proc = videodev_proc_read;
450
451 d->proc_entry = p;
452 d->vdev = vfd;
453 strcpy (d->name, name);
454
455
456
457 list_add (&d->proc_list, &videodev_proc_list);
458}
459
460static void videodev_proc_destroy_dev (struct video_device *vfd)
461{
462 struct list_head *tmp;
463 struct videodev_proc_data *d;
464
465 list_for_each (tmp, &videodev_proc_list) {
466 d = list_entry(tmp, struct videodev_proc_data, proc_list);
467 if (vfd == d->vdev) {
468 remove_proc_entry(d->name, video_dev_proc_entry);
469 list_del (&d->proc_list);
470 kfree(d);
471 break;
472 }
473 }
474}
475
476#endif
477
478extern struct file_operations video_fops;
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505int video_register_device(struct video_device *vfd, int type, int nr)
506{
507 int i=0;
508 int base;
509 int err;
510 int end;
511 char *name_base;
512 char name[16];
513
514 switch(type)
515 {
516 case VFL_TYPE_GRABBER:
517 base=0;
518 end=64;
519 name_base = "video";
520 break;
521 case VFL_TYPE_VTX:
522 base=192;
523 end=224;
524 name_base = "vtx";
525 break;
526 case VFL_TYPE_VBI:
527 base=224;
528 end=240;
529 name_base = "vbi";
530 break;
531 case VFL_TYPE_RADIO:
532 base=64;
533 end=128;
534 name_base = "radio";
535 break;
536 default:
537 return -1;
538 }
539
540
541 down(&videodev_lock);
542 if (-1 == nr) {
543
544 for(i=base;i<end;i++)
545 if (NULL == video_device[i])
546 break;
547 if (i == end) {
548 up(&videodev_lock);
549 return -ENFILE;
550 }
551 } else {
552
553 i = base+nr;
554 if (NULL != video_device[i]) {
555 up(&videodev_lock);
556 return -ENFILE;
557 }
558 }
559 video_device[i]=vfd;
560 vfd->minor=i;
561 up(&videodev_lock);
562
563
564
565 MOD_INC_USE_COUNT;
566 if(vfd->initialize) {
567 err=vfd->initialize(vfd);
568 if(err<0) {
569 video_device[i]=NULL;
570 MOD_DEC_USE_COUNT;
571 return err;
572 }
573 }
574 sprintf (name, "v4l/%s%d", name_base, i - base);
575
576
577
578
579 vfd->devfs_handle =
580 devfs_register (NULL, name, DEVFS_FL_DEFAULT,
581 VIDEO_MAJOR, vfd->minor,
582 S_IFCHR | S_IRUSR | S_IWUSR,
583 &video_fops,
584 NULL);
585 init_MUTEX(&vfd->lock);
586
587#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
588 sprintf (name, "%s%d", name_base, i - base);
589 videodev_proc_create_dev (vfd, name);
590#endif
591 return 0;
592}
593
594
595
596
597
598
599
600
601
602void video_unregister_device(struct video_device *vfd)
603{
604 down(&videodev_lock);
605
606 if(video_device[vfd->minor]!=vfd)
607 panic("videodev: bad unregister");
608
609#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
610 videodev_proc_destroy_dev (vfd);
611#endif
612
613 devfs_unregister (vfd->devfs_handle);
614 video_device[vfd->minor]=NULL;
615 MOD_DEC_USE_COUNT;
616 up(&videodev_lock);
617}
618
619
620static struct file_operations video_fops=
621{
622 owner: THIS_MODULE,
623 llseek: no_llseek,
624 read: video_read,
625 write: video_write,
626 ioctl: video_ioctl,
627 mmap: video_mmap,
628 open: video_open,
629 release: video_release,
630 poll: video_poll,
631};
632
633
634
635
636
637static int __init videodev_init(void)
638{
639 printk(KERN_INFO "Linux video capture interface: v1.00\n");
640 if(devfs_register_chrdev(VIDEO_MAJOR,"video_capture", &video_fops))
641 {
642 printk("video_dev: unable to get major %d\n", VIDEO_MAJOR);
643 return -EIO;
644 }
645
646#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
647 videodev_proc_create ();
648#endif
649
650 return 0;
651}
652
653static void __exit videodev_exit(void)
654{
655#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
656 videodev_proc_destroy ();
657#endif
658 devfs_unregister_chrdev(VIDEO_MAJOR, "video_capture");
659}
660
661module_init(videodev_init)
662module_exit(videodev_exit)
663
664EXPORT_SYMBOL(video_register_device);
665EXPORT_SYMBOL(video_unregister_device);
666EXPORT_SYMBOL(video_devdata);
667EXPORT_SYMBOL(video_usercopy);
668EXPORT_SYMBOL(video_exclusive_open);
669EXPORT_SYMBOL(video_exclusive_release);
670
671MODULE_AUTHOR("Alan Cox");
672MODULE_DESCRIPTION("Device registrar for Video4Linux drivers");
673MODULE_LICENSE("GPL");
674
675
676
677
678
679
680
681