OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [media/] [video/] [videodev.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * Video capture interface for Linux
3
 *
4
 *              A generic video device interface for the LINUX operating system
5
 *              using a set of device structures/vectors for low level operations.
6
 *
7
 *              This program is free software; you can redistribute it and/or
8
 *              modify it under the terms of the GNU General Public License
9
 *              as published by the Free Software Foundation; either version
10
 *              2 of the License, or (at your option) any later version.
11
 *
12
 * Author:      Alan Cox, <alan@redhat.com>
13
 *
14
 * Fixes:       20000516  Claudio Matsuoka <claudio@conectiva.com>
15
 *              - Added procfs support
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
 *      Active devices
41
 */
42
 
43
static struct video_device *video_device[VIDEO_NUM_DEVICES];
44
static 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
 
51
struct 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
 
58
static struct proc_dir_entry *video_dev_proc_entry = NULL;
59
struct proc_dir_entry *video_proc_entry = NULL;
60
EXPORT_SYMBOL(video_proc_entry);
61
LIST_HEAD(videodev_proc_list);
62
 
63
#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */
64
 
65
struct video_device *video_device_alloc(void)
66
{
67
        struct video_device *vfd;
68
        vfd = kmalloc(sizeof(*vfd),GFP_KERNEL);
69
        if (NULL == vfd)
70
                return NULL;
71
        memset(vfd,0,sizeof(*vfd));
72
        return vfd;
73
}
74
 
75
void video_device_release(struct video_device *vfd)
76
{
77
        kfree(vfd);
78
}
79
 
80
/*
81
 *      Read will do some smarts later on. Buffer pin etc.
82
 */
83
 
84
static ssize_t video_read(struct file *file,
85
        char *buf, size_t count, loff_t *ppos)
86
{
87
        struct video_device *vfl = video_devdata(file);
88
        if(vfl->read)
89
                return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK);
90
        else
91
                return -EINVAL;
92
}
93
 
94
 
95
/*
96
 *      Write for now does nothing. No reason it shouldnt do overlay setting
97
 *      for some boards I guess..
98
 */
99
 
100
static ssize_t video_write(struct file *file, const char *buf,
101
        size_t count, loff_t *ppos)
102
{
103
        struct video_device *vfl = video_devdata(file);
104
        if(vfl->write)
105
                return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK);
106
        else
107
                return 0;
108
}
109
 
110
struct video_device* video_devdata(struct file *file)
111
{
112
        return video_device[minor(file->f_dentry->d_inode->i_rdev)];
113
}
114
 
115
/*
116
 *      Poll to see if we're readable, can probably be used for timing on incoming
117
 *      frames, etc..
118
 */
119
 
120
static unsigned int video_poll(struct file *file, poll_table * wait)
121
{
122
        struct video_device *vfl = video_devdata(file);
123
        if(vfl->poll)
124
                return vfl->poll(vfl, file, wait);
125
        else
126
                return 0;
127
}
128
 
129
 
130
/*
131
 *      Open a video device.
132
 */
133
 
134
static int video_open(struct inode *inode, struct file *file)
135
{
136
        unsigned int minor = minor(inode->i_rdev);
137
        int err = 0;
138
        struct video_device *vfl;
139
 
140
        if(minor>=VIDEO_NUM_DEVICES)
141
                return -ENODEV;
142
        down(&videodev_lock);
143
        vfl=video_device[minor];
144
        if(vfl==NULL) {
145
                char modname[20];
146
 
147
                up(&videodev_lock);
148
                sprintf (modname, "char-major-%d-%d", VIDEO_MAJOR, minor);
149
                request_module(modname);
150
                down(&videodev_lock);
151
                vfl=video_device[minor];
152
                if (vfl==NULL) {
153
                        err = -ENODEV;
154
                        goto unlock_out;
155
                }
156
        }
157
        if (vfl->fops) {
158
                struct file_operations *old_fops;
159
 
160
                old_fops = file->f_op;
161
                file->f_op = fops_get(vfl->fops);
162
                if(file->f_op->open)
163
                        err = file->f_op->open(inode,file);
164
                if (err) {
165
                        fops_put(file->f_op);
166
                        file->f_op = fops_get(old_fops);
167
                }
168
                fops_put(old_fops);
169
                goto unlock_out;
170
        }
171
        if(vfl->users) {
172
                err = -EBUSY;
173
                goto unlock_out;
174
        }
175
        vfl->users++;           /* In case vfl->open sleeps */
176
 
177
        if(vfl->owner)
178
                __MOD_INC_USE_COUNT(vfl->owner);
179
 
180
        if (vfl->open) {
181
                err=vfl->open(vfl,0);    /* Tell the device it is open */
182
                if (err) {
183
                        vfl->users--;
184
                        if(vfl->owner)
185
                                __MOD_DEC_USE_COUNT(vfl->owner);
186
                        goto unlock_out;
187
                }
188
        }
189
        err = 0;
190
 
191
unlock_out:
192
        up(&videodev_lock);
193
        return err;
194
}
195
 
196
/*
197
 *      Last close of a video for Linux device
198
 */
199
 
200
static int video_release(struct inode *inode, struct file *file)
201
{
202
        struct video_device *vfl;
203
        struct module *owner;
204
 
205
        vfl = video_devdata(file);
206
        owner = vfl->owner;
207
        if (vfl->close)
208
                vfl->close(vfl);
209
 
210
        down(&videodev_lock);
211
        /* ->close() might have called video_device_unregister()
212
           in case of a hot unplug, thus we have to get vfl again */
213
        vfl = video_devdata(file);
214
        if (NULL != vfl)
215
                vfl->users--;
216
        if (owner)
217
                __MOD_DEC_USE_COUNT(owner);
218
        up(&videodev_lock);
219
        return 0;
220
}
221
 
222
static int video_ioctl(struct inode *inode, struct file *file,
223
        unsigned int cmd, unsigned long arg)
224
{
225
        struct video_device *vfl = video_devdata(file);
226
        int err=vfl->ioctl(vfl, cmd, (void *)arg);
227
 
228
        if(err!=-ENOIOCTLCMD)
229
                return err;
230
 
231
        switch(cmd)
232
        {
233
                default:
234
                        return -EINVAL;
235
        }
236
}
237
 
238
/*
239
 *      We need to do MMAP support
240
 */
241
 
242
int video_mmap(struct file *file, struct vm_area_struct *vma)
243
{
244
        int ret = -EINVAL;
245
        struct video_device *vfl = video_devdata(file);
246
        if(vfl->mmap) {
247
                lock_kernel();
248
                ret = vfl->mmap(vfl, (char *)vma->vm_start,
249
                                (unsigned long)(vma->vm_end-vma->vm_start));
250
                unlock_kernel();
251
        }
252
        return ret;
253
}
254
 
255
/*
256
 * helper function -- handles userspace copying for ioctl arguments
257
 */
258
int
259
video_usercopy(struct inode *inode, struct file *file,
260
               unsigned int cmd, unsigned long arg,
261
               int (*func)(struct inode *inode, struct file *file,
262
                           unsigned int cmd, void *arg))
263
{
264
        char    sbuf[128];
265
        void    *mbuf = NULL;
266
        void    *parg = NULL;
267
        int     err  = -EINVAL;
268
 
269
        /*  Copy arguments into temp kernel buffer  */
270
        switch (_IOC_DIR(cmd)) {
271
        case _IOC_NONE:
272
                parg = (void *)arg;
273
                break;
274
        case _IOC_READ: /* some v4l ioctls are marked wrong ... */
275
        case _IOC_WRITE:
276
        case (_IOC_WRITE | _IOC_READ):
277
                if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
278
                        parg = sbuf;
279
                } else {
280
                        /* too big to allocate from stack */
281
                        mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
282
                        if (NULL == mbuf)
283
                                return -ENOMEM;
284
                        parg = mbuf;
285
                }
286
 
287
                err = -EFAULT;
288
                if (copy_from_user(parg, (void *)arg, _IOC_SIZE(cmd)))
289
                        goto out;
290
                break;
291
        }
292
 
293
        /* call driver */
294
        err = func(inode, file, cmd, parg);
295
        if (err == -ENOIOCTLCMD)
296
                err = -EINVAL;
297
        if (err < 0)
298
                goto out;
299
 
300
        /*  Copy results into user buffer  */
301
        switch (_IOC_DIR(cmd))
302
        {
303
        case _IOC_READ:
304
        case (_IOC_WRITE | _IOC_READ):
305
                if (copy_to_user((void *)arg, parg, _IOC_SIZE(cmd)))
306
                        err = -EFAULT;
307
                break;
308
        }
309
 
310
out:
311
        if (mbuf)
312
                kfree(mbuf);
313
        return err;
314
}
315
 
316
/*
317
 * open/release helper functions -- handle exclusive opens
318
 */
319
extern int video_exclusive_open(struct inode *inode, struct file *file)
320
{
321
        struct  video_device *vfl = video_devdata(file);
322
        int retval = 0;
323
 
324
        down(&vfl->lock);
325
        if (vfl->users) {
326
                retval = -EBUSY;
327
        } else {
328
                vfl->users++;
329
        }
330
        up(&vfl->lock);
331
        return retval;
332
}
333
 
334
extern int video_exclusive_release(struct inode *inode, struct file *file)
335
{
336
        struct  video_device *vfl = video_devdata(file);
337
 
338
        vfl->users--;
339
        return 0;
340
}
341
 
342
/*
343
 *      /proc support
344
 */
345
 
346
#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
347
 
348
/* Hmm... i'd like to see video_capability information here, but
349
 * how can I access it (without changing the other drivers? -claudio
350
 */
351
static int videodev_proc_read(char *page, char **start, off_t off,
352
                               int count, int *eof, void *data)
353
{
354
        char *out = page;
355
        struct video_device *vfd = data;
356
        struct videodev_proc_data *d;
357
        struct list_head *tmp;
358
        int len;
359
        char c = ' ';
360
 
361
        list_for_each (tmp, &videodev_proc_list) {
362
                d = list_entry(tmp, struct videodev_proc_data, proc_list);
363
                if (vfd == d->vdev)
364
                        break;
365
        }
366
 
367
        /* Sanity check */
368
        if (tmp == &videodev_proc_list)
369
                goto skip;
370
 
371
#define PRINT_VID_TYPE(x) do { if (vfd->type & x) \
372
        out += sprintf (out, "%c%s", c, #x); c='|';} while (0)
373
 
374
        out += sprintf (out, "name            : %s\n", vfd->name);
375
        out += sprintf (out, "type            :");
376
                PRINT_VID_TYPE(VID_TYPE_CAPTURE);
377
                PRINT_VID_TYPE(VID_TYPE_TUNER);
378
                PRINT_VID_TYPE(VID_TYPE_TELETEXT);
379
                PRINT_VID_TYPE(VID_TYPE_OVERLAY);
380
                PRINT_VID_TYPE(VID_TYPE_CHROMAKEY);
381
                PRINT_VID_TYPE(VID_TYPE_CLIPPING);
382
                PRINT_VID_TYPE(VID_TYPE_FRAMERAM);
383
                PRINT_VID_TYPE(VID_TYPE_SCALES);
384
                PRINT_VID_TYPE(VID_TYPE_MONOCHROME);
385
                PRINT_VID_TYPE(VID_TYPE_SUBCAPTURE);
386
                PRINT_VID_TYPE(VID_TYPE_MPEG_DECODER);
387
                PRINT_VID_TYPE(VID_TYPE_MPEG_ENCODER);
388
                PRINT_VID_TYPE(VID_TYPE_MJPEG_DECODER);
389
                PRINT_VID_TYPE(VID_TYPE_MJPEG_ENCODER);
390
        out += sprintf (out, "\n");
391
        out += sprintf (out, "hardware        : 0x%x\n", vfd->hardware);
392
#if 0
393
        out += sprintf (out, "channels        : %d\n", d->vcap.channels);
394
        out += sprintf (out, "audios          : %d\n", d->vcap.audios);
395
        out += sprintf (out, "maxwidth        : %d\n", d->vcap.maxwidth);
396
        out += sprintf (out, "maxheight       : %d\n", d->vcap.maxheight);
397
        out += sprintf (out, "minwidth        : %d\n", d->vcap.minwidth);
398
        out += sprintf (out, "minheight       : %d\n", d->vcap.minheight);
399
#endif
400
 
401
skip:
402
        len = out - page;
403
        len -= off;
404
        if (len < count) {
405
                *eof = 1;
406
                if (len <= 0)
407
                        return 0;
408
        } else
409
                len = count;
410
 
411
        *start = page + off;
412
 
413
        return len;
414
}
415
 
416
static void videodev_proc_create(void)
417
{
418
        video_proc_entry = create_proc_entry("video", S_IFDIR, &proc_root);
419
 
420
        if (video_proc_entry == NULL) {
421
                printk("video_dev: unable to initialise /proc/video\n");
422
                return;
423
        }
424
 
425
        video_proc_entry->owner = THIS_MODULE;
426
        video_dev_proc_entry = create_proc_entry("dev", S_IFDIR, video_proc_entry);
427
 
428
        if (video_dev_proc_entry == NULL) {
429
                printk("video_dev: unable to initialise /proc/video/dev\n");
430
                return;
431
        }
432
 
433
        video_dev_proc_entry->owner = THIS_MODULE;
434
}
435
 
436
#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
437
static void videodev_proc_destroy(void)
438
{
439
        if (video_dev_proc_entry != NULL)
440
                remove_proc_entry("dev", video_proc_entry);
441
 
442
        if (video_proc_entry != NULL)
443
                remove_proc_entry("video", &proc_root);
444
}
445
#endif
446
 
447
static void videodev_proc_create_dev (struct video_device *vfd, char *name)
448
{
449
        struct videodev_proc_data *d;
450
        struct proc_dir_entry *p;
451
 
452
        if (video_dev_proc_entry == NULL)
453
                return;
454
 
455
        d = kmalloc (sizeof (struct videodev_proc_data), GFP_KERNEL);
456
        if (!d)
457
                return;
458
 
459
        p = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, video_dev_proc_entry);
460
        if (!p)
461
                return;
462
        p->data = vfd;
463
        p->read_proc = videodev_proc_read;
464
 
465
        d->proc_entry = p;
466
        d->vdev = vfd;
467
        strcpy (d->name, name);
468
 
469
        /* How can I get capability information ? */
470
 
471
        list_add (&d->proc_list, &videodev_proc_list);
472
}
473
 
474
static void videodev_proc_destroy_dev (struct video_device *vfd)
475
{
476
        struct list_head *tmp;
477
        struct videodev_proc_data *d;
478
 
479
        list_for_each (tmp, &videodev_proc_list) {
480
                d = list_entry(tmp, struct videodev_proc_data, proc_list);
481
                if (vfd == d->vdev) {
482
                        remove_proc_entry(d->name, video_dev_proc_entry);
483
                        list_del (&d->proc_list);
484
                        kfree(d);
485
                        break;
486
                }
487
        }
488
}
489
 
490
#endif /* CONFIG_VIDEO_PROC_FS */
491
 
492
extern struct file_operations video_fops;
493
 
494
/**
495
 *      video_register_device - register video4linux devices
496
 *      @vfd:  video device structure we want to register
497
 *      @type: type of device to register
498
 *      @nr:   which device number (0 == /dev/video0, 1 == /dev/video1, ...
499
 *             -1 == first free)
500
 *
501
 *      The registration code assigns minor numbers based on the type
502
 *      requested. -ENFILE is returned in all the device slots for this
503
 *      category are full. If not then the minor field is set and the
504
 *      driver initialize function is called (if non %NULL).
505
 *
506
 *      Zero is returned on success.
507
 *
508
 *      Valid types are
509
 *
510
 *      %VFL_TYPE_GRABBER - A frame grabber
511
 *
512
 *      %VFL_TYPE_VTX - A teletext device
513
 *
514
 *      %VFL_TYPE_VBI - Vertical blank data (undecoded)
515
 *
516
 *      %VFL_TYPE_RADIO - A radio card
517
 */
518
 
519
int video_register_device(struct video_device *vfd, int type, int nr)
520
{
521
        int i=0;
522
        int base;
523
        int err;
524
        int end;
525
        char *name_base;
526
        char name[16];
527
 
528
        switch(type)
529
        {
530
                case VFL_TYPE_GRABBER:
531
                        base=0;
532
                        end=64;
533
                        name_base = "video";
534
                        break;
535
                case VFL_TYPE_VTX:
536
                        base=192;
537
                        end=224;
538
                        name_base = "vtx";
539
                        break;
540
                case VFL_TYPE_VBI:
541
                        base=224;
542
                        end=240;
543
                        name_base = "vbi";
544
                        break;
545
                case VFL_TYPE_RADIO:
546
                        base=64;
547
                        end=128;
548
                        name_base = "radio";
549
                        break;
550
                default:
551
                        return -1;
552
        }
553
 
554
        /* pick a minor number */
555
        down(&videodev_lock);
556
        if (-1 == nr) {
557
                /* use first free */
558
                for(i=base;i<end;i++)
559
                        if (NULL == video_device[i])
560
                                break;
561
                if (i == end) {
562
                        up(&videodev_lock);
563
                        return -ENFILE;
564
                }
565
        } else {
566
                /* use the one the driver asked for */
567
                i = base+nr;
568
                if (NULL != video_device[i]) {
569
                        up(&videodev_lock);
570
                        return -ENFILE;
571
                }
572
        }
573
        video_device[i]=vfd;
574
        vfd->minor=i;
575
        up(&videodev_lock);
576
 
577
        /* The init call may sleep so we book the slot out
578
           then call */
579
        MOD_INC_USE_COUNT;
580
        if(vfd->initialize) {
581
                err=vfd->initialize(vfd);
582
                if(err<0) {
583
                        video_device[i]=NULL;
584
                        MOD_DEC_USE_COUNT;
585
                        return err;
586
                }
587
        }
588
        sprintf (name, "v4l/%s%d", name_base, i - base);
589
        /*
590
         *      Start the device root only. Anything else
591
         *      has serious privacy issues.
592
         */
593
        vfd->devfs_handle =
594
                devfs_register (NULL, name, DEVFS_FL_DEFAULT,
595
                                VIDEO_MAJOR, vfd->minor,
596
                                S_IFCHR | S_IRUSR | S_IWUSR,
597
                                &video_fops,
598
                                NULL);
599
        init_MUTEX(&vfd->lock);
600
 
601
#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
602
        sprintf (name, "%s%d", name_base, i - base);
603
        videodev_proc_create_dev (vfd, name);
604
#endif
605
        return 0;
606
}
607
 
608
/**
609
 *      video_unregister_device - unregister a video4linux device
610
 *      @vfd: the device to unregister
611
 *
612
 *      This unregisters the passed device and deassigns the minor
613
 *      number. Future open calls will be met with errors.
614
 */
615
 
616
void video_unregister_device(struct video_device *vfd)
617
{
618
        down(&videodev_lock);
619
 
620
        if(video_device[vfd->minor]!=vfd)
621
                panic("videodev: bad unregister");
622
 
623
#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
624
        videodev_proc_destroy_dev (vfd);
625
#endif
626
 
627
        devfs_unregister (vfd->devfs_handle);
628
        if (vfd->release)
629
                vfd->release(vfd);
630
        video_device[vfd->minor]=NULL;
631
        MOD_DEC_USE_COUNT;
632
        up(&videodev_lock);
633
}
634
 
635
 
636
static struct file_operations video_fops=
637
{
638
        owner:          THIS_MODULE,
639
        llseek:         no_llseek,
640
        read:           video_read,
641
        write:          video_write,
642
        ioctl:          video_ioctl,
643
        mmap:           video_mmap,
644
        open:           video_open,
645
        release:        video_release,
646
        poll:           video_poll,
647
};
648
 
649
/*
650
 *      Initialise video for linux
651
 */
652
 
653
static int __init videodev_init(void)
654
{
655
        printk(KERN_INFO "Linux video capture interface: v1.00\n");
656
        if(devfs_register_chrdev(VIDEO_MAJOR,"video_capture", &video_fops))
657
        {
658
                printk("video_dev: unable to get major %d\n", VIDEO_MAJOR);
659
                return -EIO;
660
        }
661
 
662
#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
663
        videodev_proc_create ();
664
#endif
665
 
666
        return 0;
667
}
668
 
669
static void __exit videodev_exit(void)
670
{
671
#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
672
        videodev_proc_destroy ();
673
#endif
674
        devfs_unregister_chrdev(VIDEO_MAJOR, "video_capture");
675
}
676
 
677
module_init(videodev_init)
678
module_exit(videodev_exit)
679
 
680
EXPORT_SYMBOL(video_device_alloc);
681
EXPORT_SYMBOL(video_device_release);
682
EXPORT_SYMBOL(video_register_device);
683
EXPORT_SYMBOL(video_unregister_device);
684
EXPORT_SYMBOL(video_devdata);
685
EXPORT_SYMBOL(video_usercopy);
686
EXPORT_SYMBOL(video_exclusive_open);
687
EXPORT_SYMBOL(video_exclusive_release);
688
 
689
MODULE_AUTHOR("Alan Cox");
690
MODULE_DESCRIPTION("Device registrar for Video4Linux drivers");
691
MODULE_LICENSE("GPL");
692
 
693
 
694
/*
695
 * Local variables:
696
 * c-basic-offset: 8
697
 * End:
698
 */

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.