diff options
Diffstat (limited to 'linux/drivers/media/video/videodev.c')
-rw-r--r-- | linux/drivers/media/video/videodev.c | 1069 |
1 files changed, 1062 insertions, 7 deletions
diff --git a/linux/drivers/media/video/videodev.c b/linux/drivers/media/video/videodev.c index c6d0825c8..727cccc07 100644 --- a/linux/drivers/media/video/videodev.c +++ b/linux/drivers/media/video/videodev.c @@ -1,5 +1,5 @@ /* - * Video capture interface for Linux + * Video capture interface for Linux version 2 * * A generic video device interface for the LINUX operating system * using a set of device structures/vectors for low level operations. @@ -9,12 +9,18 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Author: Alan Cox, <alan@redhat.com> + * Authors: Alan Cox, <alan@redhat.com> (version 1) + * Mauro Carvalho Chehab <mchehab@infradead.org> (version 2) * * Fixes: 20000516 Claudio Matsuoka <claudio@conectiva.com> * - Added procfs support */ +#define dbgarg(fmt, arg...) \ + if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \ + printk ("%s: " fmt, vfd->name, ## arg); + + #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> @@ -34,7 +40,13 @@ #include <asm/semaphore.h> #endif +#define __OLD_VIDIOC_ /* To allow fixing old calls*/ +#include <linux/videodev2.h> + +#ifdef CONFIG_VIDEO_V4L1 #include <linux/videodev.h> +#endif +#include <media/v4l2-common.h> #define VIDEO_NUM_DEVICES 256 #define VIDEO_NAME "video4linux" @@ -104,7 +116,7 @@ struct video_device* video_devdata(struct file *file) } /* - * Open a video device. + * Open a video device - FIXME: Obsoleted */ static int video_open(struct inode *inode, struct file *file) { @@ -148,6 +160,7 @@ static int video_open(struct inode *inode, struct file *file) * helper function -- handles userspace copying for ioctl arguments */ +#ifdef __OLD_VIDIOC_ static unsigned int video_fix_command(unsigned int cmd) { @@ -173,7 +186,11 @@ video_fix_command(unsigned int cmd) } return cmd; } +#endif +/* + * Obsolete usercopy function - Should be removed soon + */ int video_usercopy(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg, @@ -185,7 +202,9 @@ video_usercopy(struct inode *inode, struct file *file, void *parg = NULL; int err = -EINVAL; +#ifdef __OLD_VIDIOC_ cmd = video_fix_command(cmd); +#endif /* Copy arguments into temp kernel buffer */ switch (_IOC_DIR(cmd)) { @@ -236,6 +255,7 @@ out: /* * open/release helper functions -- handle exclusive opens + * Should be removed soon */ int video_exclusive_open(struct inode *inode, struct file *file) { @@ -260,6 +280,1038 @@ int video_exclusive_release(struct inode *inode, struct file *file) return 0; } +static char *v4l2_memory_names[] = { + [V4L2_MEMORY_MMAP] = "mmap", + [V4L2_MEMORY_USERPTR] = "userptr", + [V4L2_MEMORY_OVERLAY] = "overlay", +}; + + +/* FIXME: Those stuff are replicated also on v4l2-common.c */ +static char *v4l2_type_names_FIXME[] = { + [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap", + [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over", + [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out", + [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap", + [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", + [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", + [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-capture", + [V4L2_BUF_TYPE_PRIVATE] = "private", +}; + +static char *v4l2_field_names_FIXME[] = { + [V4L2_FIELD_ANY] = "any", + [V4L2_FIELD_NONE] = "none", + [V4L2_FIELD_TOP] = "top", + [V4L2_FIELD_BOTTOM] = "bottom", + [V4L2_FIELD_INTERLACED] = "interlaced", + [V4L2_FIELD_SEQ_TB] = "seq-tb", + [V4L2_FIELD_SEQ_BT] = "seq-bt", + [V4L2_FIELD_ALTERNATE] = "alternate", +}; + +#define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown" + +static void dbgbuf(struct video_device *vfd, struct v4l2_buffer *p) { + struct v4l2_timecode *tc=&p->timecode; + + dbgarg ("%02ld:%02d:%02d.%08ld index=%d, type=%s, " + "bytesused=%d, flags=0x%08d, " + "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx\n", + (p->timestamp.tv_sec/3600), + (int)(p->timestamp.tv_sec/60)%60, + (int)(p->timestamp.tv_sec%60), + p->timestamp.tv_usec, + p->index, + prt_names(p->type,v4l2_type_names_FIXME), + p->bytesused,p->flags, + p->field,p->sequence, + prt_names(p->memory,v4l2_memory_names), + p->m.userptr); + dbgarg ("timecode= %02d:%02d:%02d type=%d, " + "flags=0x%08d, frames=%d, userbits=0x%08x\n", + tc->hours,tc->minutes,tc->seconds, + tc->type, tc->flags, tc->frames, (__u32) tc->userbits); +} + +static inline void dbgrect(struct video_device *vfd, char *s, struct v4l2_rect *r) +{ + dbgarg ("%sRect start at %dx%d, size= %dx%d", s, r->left, r->top, + r->width, r->height); +}; + +static inline void v4l_print_pix_fmt (struct video_device *vfd, + struct v4l2_pix_format *fmt) +{ + dbgarg ("width=%d, height=%d, format=%d, field=%s, " + "bytesperline=%d sizeimage=%d, colorspace=%d\n", + fmt->width,fmt->height,fmt->pixelformat, + prt_names(fmt->field,v4l2_field_names_FIXME), + fmt->bytesperline,fmt->sizeimage,fmt->colorspace); +}; + + +static int check_fmt (struct video_device *vfd, enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (vfd->vidioc_try_fmt_cap) + return (0); + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (vfd->vidioc_try_fmt_overlay) + return (0); + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (vfd->vidioc_try_fmt_vbi) + return (0); + break; + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + if (vfd->vidioc_try_fmt_vbi_output) + return (0); + break; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + if (vfd->vidioc_try_fmt_vbi_capture) + return (0); + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (vfd->vidioc_try_fmt_video_output) + return (0); + break; + case V4L2_BUF_TYPE_VBI_OUTPUT: + if (vfd->vidioc_try_fmt_vbi_output) + return (0); + break; + case V4L2_BUF_TYPE_PRIVATE: + if (vfd->vidioc_try_fmt_type_private) + return (0); + break; + } + return (-EINVAL); +} + +static int __video_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) +{ + struct video_device *vfd; + void *fh; + int ret=-EINVAL; + + vfd = video_devdata(file); + fh = vfd->fh; + + if ( (vfd->debug & V4L2_DEBUG_IOCTL) && + !(vfd->debug | V4L2_DEBUG_IOCTL_ARG)) { + v4l_print_ioctl(vfd->name, cmd); + } + + switch(cmd) { + /* --- capabilities ------------------------------------------ */ + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *cap = (struct v4l2_capability*)arg; + memset(cap, 0, sizeof(*cap)); + + if (vfd->vidioc_querycap) { + ret=vfd->vidioc_querycap(file,fh, cap); + dbgarg ("driver=%s, card=%s, bus=%s, version=0x%08x, " + "capabilities=0x%08x\n", + cap->driver,cap->card,cap->bus_info, + cap->version, + cap->capabilities); + } + break; + } + + /* --- priority ------------------------------------------ */ + case VIDIOC_G_PRIORITY: + { + enum v4l2_priority *p=arg; + + if (vfd->vidioc_g_priority) { + dbgarg("priority is %d\n", *p); + ret=vfd->vidioc_g_priority(file, fh, p); + } + break; + } + case VIDIOC_S_PRIORITY: + { + enum v4l2_priority *p=arg; + + if (vfd->vidioc_s_priority) { + ret=vfd->vidioc_s_priority(file, fh, *p); + dbgarg("priority is %d\n", *p); + } + break; + } + + /* --- capture ioctls ---------------------------------------- */ + case VIDIOC_ENUM_FMT: + { + struct v4l2_fmtdesc *f = arg; + enum v4l2_buf_type type; + unsigned int index; + + index = f->index; + type = f->type; + memset(f,0,sizeof(*f)); + f->index = index; + f->type = type; + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (vfd->vidioc_enum_fmt_cap) + ret=vfd->vidioc_enum_fmt_cap(file, fh, f); + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (vfd->vidioc_enum_fmt_overlay) + ret=vfd->vidioc_enum_fmt_overlay(file, fh, f); + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (vfd->vidioc_enum_fmt_vbi) + ret=vfd->vidioc_enum_fmt_vbi(file, fh, f); + break; + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + if (vfd->vidioc_enum_fmt_vbi_output) + ret=vfd->vidioc_enum_fmt_vbi_output(file, fh, f); + break; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + if (vfd->vidioc_enum_fmt_vbi_capture) + ret=vfd->vidioc_enum_fmt_vbi_capture(file, fh, f); + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (vfd->vidioc_enum_fmt_video_output) + ret=vfd->vidioc_enum_fmt_video_output(file, fh, f); + break; + case V4L2_BUF_TYPE_VBI_OUTPUT: + if (vfd->vidioc_enum_fmt_vbi_output) + ret=vfd->vidioc_enum_fmt_vbi_output(file, fh, f); + break; + case V4L2_BUF_TYPE_PRIVATE: + if (vfd->vidioc_enum_fmt_type_private) + ret=vfd->vidioc_enum_fmt_type_private(file, fh, f); + break; + } + dbgarg ("index=%d, type=%d, flags=%d, description=%s," + " pixelformat=%d\n", + f->index, f->type, f->flags, f->description, + f->pixelformat); + + break; + } + case VIDIOC_G_FMT: + { + struct v4l2_format *f = (struct v4l2_format *)arg; + + enum v4l2_buf_type type=f->type; + + memset(&f->fmt.pix,0,sizeof(f->fmt.pix)); + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (vfd->vidioc_g_fmt_cap) + ret=vfd->vidioc_g_fmt_cap(file, fh, f); + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (vfd->vidioc_g_fmt_overlay) + ret=vfd->vidioc_g_fmt_overlay(file, fh, f); + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (vfd->vidioc_g_fmt_vbi) + ret=vfd->vidioc_g_fmt_vbi(file, fh, f); + break; + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + if (vfd->vidioc_g_fmt_vbi_output) + ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f); + break; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + if (vfd->vidioc_g_fmt_vbi_capture) + ret=vfd->vidioc_g_fmt_vbi_capture(file, fh, f); + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (vfd->vidioc_g_fmt_video_output) + ret=vfd->vidioc_g_fmt_video_output(file, fh, f); + break; + case V4L2_BUF_TYPE_VBI_OUTPUT: + if (vfd->vidioc_g_fmt_vbi_output) + ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f); + break; + case V4L2_BUF_TYPE_PRIVATE: + if (vfd->vidioc_g_fmt_type_private) + ret=vfd->vidioc_g_fmt_type_private(file, fh, f); + break; + } + /* FIXME: Should be one dump per type */ + dbgarg ("type=%s\n", prt_names(f->type,v4l2_type_names_FIXME)); + + break; + } + case VIDIOC_S_FMT: + { + struct v4l2_format *f = (struct v4l2_format *)arg; + + enum v4l2_buf_type type=f->type; + + memset(&f->fmt.pix,0,sizeof(f->fmt.pix)); + + /* FIXME: Should be one dump per type */ + dbgarg ("type=%s\n", prt_names(f->type,v4l2_type_names_FIXME)); + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (vfd->vidioc_s_fmt_cap) + ret=vfd->vidioc_s_fmt_cap(file, fh, f); + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (vfd->vidioc_s_fmt_overlay) + ret=vfd->vidioc_s_fmt_overlay(file, fh, f); + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (vfd->vidioc_s_fmt_vbi) + ret=vfd->vidioc_s_fmt_vbi(file, fh, f); + break; + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + if (vfd->vidioc_s_fmt_vbi_output) + ret=vfd->vidioc_s_fmt_vbi_output(file, fh, f); + break; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + if (vfd->vidioc_s_fmt_vbi_capture) + ret=vfd->vidioc_s_fmt_vbi_capture(file, fh, f); + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (vfd->vidioc_s_fmt_video_output) + ret=vfd->vidioc_s_fmt_video_output(file, fh, f); + break; + case V4L2_BUF_TYPE_VBI_OUTPUT: + if (vfd->vidioc_s_fmt_vbi_output) + ret=vfd->vidioc_s_fmt_vbi_output(file, fh, f); + break; + case V4L2_BUF_TYPE_PRIVATE: + if (vfd->vidioc_s_fmt_type_private) + ret=vfd->vidioc_s_fmt_type_private(file, fh, f); + break; + } + break; + } + case VIDIOC_TRY_FMT: + { + struct v4l2_format *f = (struct v4l2_format *)arg; + enum v4l2_buf_type type=f->type; + + memset(&f->fmt.pix,0,sizeof(f->fmt.pix)); + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (vfd->vidioc_try_fmt_cap) + ret=vfd->vidioc_try_fmt_cap(file, fh, f); + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (vfd->vidioc_try_fmt_overlay) + ret=vfd->vidioc_try_fmt_overlay(file, fh, f); + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (vfd->vidioc_try_fmt_vbi) + ret=vfd->vidioc_try_fmt_vbi(file, fh, f); + break; + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + if (vfd->vidioc_try_fmt_vbi_output) + ret=vfd->vidioc_try_fmt_vbi_output(file, fh, f); + break; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + if (vfd->vidioc_try_fmt_vbi_capture) + ret=vfd->vidioc_try_fmt_vbi_capture(file, fh, f); + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (vfd->vidioc_try_fmt_video_output) + ret=vfd->vidioc_try_fmt_video_output(file, fh, f); + break; + case V4L2_BUF_TYPE_VBI_OUTPUT: + if (vfd->vidioc_try_fmt_vbi_output) + ret=vfd->vidioc_try_fmt_vbi_output(file, fh, f); + break; + case V4L2_BUF_TYPE_PRIVATE: + if (vfd->vidioc_try_fmt_type_private) + ret=vfd->vidioc_try_fmt_type_private(file, fh, f); + break; + } + /* FIXME: Should be one dump per type */ + dbgarg ("type=%s\n", prt_names(f->type,v4l2_type_names_FIXME)); + + break; + } + /* FIXME: Those buf reqs could be handled here, + with some changes on videobuf to allow its header to be included at + videodev2.h or being merged at videodev2. + */ + case VIDIOC_REQBUFS: + { + struct v4l2_requestbuffers *p=arg; + + if (vfd->vidioc_reqbufs) { + ret = check_fmt (vfd, p->type); + if (ret) + break; + + ret=vfd->vidioc_reqbufs(file, fh, p); + dbgarg ("count=%d, type=%s, memory=%s\n", + p->count, + prt_names(p->type,v4l2_type_names_FIXME), + prt_names(p->memory,v4l2_memory_names)); + } + break; + } + case VIDIOC_QUERYBUF: + { + struct v4l2_buffer *p=arg; + + if (vfd->vidioc_querybuf) { + ret = check_fmt (vfd, p->type); + if (ret) + break; + + ret=vfd->vidioc_querybuf(file, fh, p); + dbgbuf(vfd,p); + } + break; + } + case VIDIOC_QBUF: + { + struct v4l2_buffer *p=arg; + + if (vfd->vidioc_qbuf) { + ret = check_fmt (vfd, p->type); + if (ret) + break; + + ret=vfd->vidioc_qbuf(file, fh, p); + dbgbuf(vfd,p); + } + break; + } + case VIDIOC_DQBUF: + { + struct v4l2_buffer *p=arg; + if (vfd->vidioc_qbuf) { + ret = check_fmt (vfd, p->type); + if (ret) + break; + + ret=vfd->vidioc_qbuf(file, fh, p); + dbgbuf(vfd,p); + } + break; + } + case VIDIOC_OVERLAY: + { + int *i = arg; + + if (vfd->vidioc_overlay) { + dbgarg ("value=%d\n",*i); + ret=vfd->vidioc_overlay(file, fh, *i); + } + break; + } +#ifdef HAVE_V4L1 + /* --- streaming capture ------------------------------------- */ + case VIDIOCGMBUF: + { + struct video_mbuf *p=arg; + + memset(&p,0,sizeof(p)); + + if (vfd->vidiocgmbuf) { + ret=vfd->vidiocgmbuf(file, fh, p); + dbgarg ("size=%d, frames=%d, offsets=0x%08lx\n", + p->size, + p->frames, + (unsigned long)p->offsets); + } + break; + } +#endif + case VIDIOC_G_FBUF: + { + struct v4l2_framebuffer *p=arg; + if (vfd->vidioc_g_fbuf) { + ret=vfd->vidioc_g_fbuf(file, fh, arg); + dbgarg ("capability=%d, flags=%d, base=0x%08lx\n", + p->capability,p->flags, + (unsigned long)p->base); + v4l_print_pix_fmt (vfd, &p->fmt); + } + break; + } + case VIDIOC_S_FBUF: + { + struct v4l2_framebuffer *p=arg; + dbgarg ("capability=%d, flags=%d, base=0x%08lx\n", + p->capability,p->flags,(unsigned long)p->base); + v4l_print_pix_fmt (vfd, &p->fmt); + if (vfd->vidioc_s_fbuf) + ret=vfd->vidioc_s_fbuf(file, fh, arg); + break; + } + case VIDIOC_STREAMON: + { + enum v4l2_buf_type i = *(int *)arg; + if (vfd->vidioc_streamon) { + dbgarg ("type=%s\n", prt_names(i,v4l2_type_names_FIXME)); + ret=vfd->vidioc_streamon(file, fh,i); + } + break; + } + case VIDIOC_STREAMOFF: + { + enum v4l2_buf_type i = *(int *)arg; + + if (vfd->vidioc_streamon){ + dbgarg ("type=%s\n", prt_names(i,v4l2_type_names_FIXME)); + ret=vfd->vidioc_streamoff(file, fh, i); + } + break; + } + /* ---------- tv norms ---------- */ + case VIDIOC_ENUMSTD: + { + struct v4l2_standard *p = arg; + unsigned int index = p->index; + + if (index<=0 || index >= vfd->tvnormsize) + break; + v4l2_video_std_construct(p, vfd->tvnorms[p->index].id, + vfd->tvnorms[p->index].name); + p->index = index; + + dbgarg ("index=%d, id=%Ld, name=%s, fps=%d/%d, " + "framelines=%d\n", p->index, + (unsigned long long)p->id, p->name, + p->frameperiod.numerator, + p->frameperiod.denominator, + p->framelines); + + ret=0; + break; + } + case VIDIOC_G_STD: + { + v4l2_std_id *id = arg; + + *id = vfd->current_norm; + + dbgarg ("value=%Lu\n", (long long unsigned) *id); + + ret=0; + break; + } + case VIDIOC_S_STD: + { + v4l2_std_id *id = arg; + unsigned int i; + + dbgarg ("value=%Lu\n", (long long unsigned) *id); + + ret=0; + /* First search for exact match */ + for (i = 0; i < vfd->tvnormsize; i++) + if (*id == vfd->tvnorms[i].id) + break; + /* Then for a generic video std that contains desired std */ + if (i == vfd->tvnormsize) + for (i = 0; i < vfd->tvnormsize; i++) + if (*id & vfd->tvnorms[i].id) + break; + if (i == vfd->tvnormsize) + return -EINVAL; + + /* Calls the specific handler */ + if (vfd->vidioc_s_std) + ret=vfd->vidioc_s_std(file, fh, i); + else + ret=-EINVAL; + + /* Updates standard information */ + if (!ret) + vfd->current_norm=*id; + + break; + } + case VIDIOC_QUERYSTD: + { + v4l2_std_id *p=arg; + + if (vfd->vidioc_querystd) { + ret=vfd->vidioc_querystd(file, fh, arg); + dbgarg ("detected std=%Lu\n", (unsigned long long)*p); + } + break; + } + /* ------ input switching ---------- */ + /* FIXME: Inputs can be handled inside videodev2 */ + case VIDIOC_ENUMINPUT: + { + struct v4l2_input *p=arg; + int i=p->index; + + if (vfd->vidioc_enum_input) { + + memset(p, 0, sizeof(*p)); + p->index=i; + + ret=vfd->vidioc_enum_input(file, fh, p); + dbgarg ("index=%d, name=%s, type=%d, audioset=%d, " + "tuner=%d, std=%Ld, status=%d\n", + p->index,p->name,p->type,p->audioset, + p->tuner, + (unsigned long long)p->std, + p->status); + } + break; + } + case VIDIOC_G_INPUT: + { + unsigned int *i = arg; + + if (vfd->vidioc_g_input) { + dbgarg ("value=%d\n",*i); + + ret=vfd->vidioc_g_input(file, fh, i); + } + break; + } + case VIDIOC_S_INPUT: + { + unsigned int *i = arg; + + if (vfd->vidioc_s_input) { + ret=vfd->vidioc_s_input(file, fh, *i); + + dbgarg ("value=%d\n",*i); + } + break; + } + + /* ------ output switching ---------- */ + case VIDIOC_G_OUTPUT: + { + unsigned int *i = arg; + + if (vfd->vidioc_g_output) { + ret=vfd->vidioc_g_output(file, fh, i); + dbgarg ("value=%d\n",*i); + } + break; + } + case VIDIOC_S_OUTPUT: + { + unsigned int *i = arg; + + + if (vfd->vidioc_s_output) { + dbgarg ("value=%d\n",*i); + ret=vfd->vidioc_s_output(file, fh, *i); + } + break; + } + + /* --- controls ---------------------------------------------- */ + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *p=arg; + + if (vfd->vidioc_queryctrl) { + ret=vfd->vidioc_queryctrl(file, fh, p); + + dbgarg ("id=%d, type=%d, name=%s, min/max=%d/%d," + " step=%d, default=%d, flags=0x%08x\n", + p->id,p->type,p->name,p->minimum,p->maximum, + p->step,p->default_value,p->flags); + } + break; + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *p = arg; + + if (vfd->vidioc_g_ctrl) { + dbgarg("Enum for index=%d\n", p->id); + + ret=vfd->vidioc_g_ctrl(file, fh, p); + dbgarg ("id=%d, value=%d\n", p->id, p->value); + } + break; + } + case VIDIOC_S_CTRL: + { + struct v4l2_control *p = arg; + + if (vfd->vidioc_s_ctrl) { + dbgarg ("id=%d, value=%d\n", p->id, p->value); + + ret=vfd->vidioc_s_ctrl(file, fh, p); + } + break; + } + case VIDIOC_QUERYMENU: + { + struct v4l2_querymenu *p=arg; + if (vfd->vidioc_querymenu) { + dbgarg ("id=%d, index=%d, name=%s\n", + p->id,p->index,p->name); + ret=vfd->vidioc_querymenu(file, fh, p); + } + break; + } + /* --- audio ---------------------------------------------- */ + case VIDIOC_ENUMAUDIO: + { + struct v4l2_audio *p=arg; + + if (vfd->vidioc_enumaudio) { + dbgarg("Enum for index=%d\n", p->index); + ret=vfd->vidioc_enumaudio(file, fh, p); + dbgarg("index=%d, name=%s, capability=%d, mode=%d\n", + p->index, p->name,p->capability, p->mode); + } + break; + } + case VIDIOC_G_AUDIO: + { + struct v4l2_audio *p=arg; + + if (vfd->vidioc_g_audio) { + dbgarg("Get for index=%d\n", p->index); + ret=vfd->vidioc_g_audio(file, fh, p); + dbgarg("index=%d, name=%s, capability=%d, mode=%d\n", + p->index, p->name,p->capability, p->mode); + } + break; + } + case VIDIOC_S_AUDIO: + { + struct v4l2_audio *p=arg; + + if (vfd->vidioc_s_audio) { + dbgarg("index=%d, name=%s, capability=%d, mode=%d\n", + p->index, p->name,p->capability, p->mode); + ret=vfd->vidioc_s_audio(file, fh, p); + } + break; + } + case VIDIOC_ENUMAUDOUT: + { + struct v4l2_audioout *p=arg; + + if (vfd->vidioc_enumaudout) { + dbgarg("Enum for index=%d\n", p->index); + ret=vfd->vidioc_enumaudout(file, fh, p); + dbgarg("index=%d, name=%s, capability=%d, mode=%d\n", + p->index, p->name, p->capability,p->mode); + } + break; + } + case VIDIOC_G_AUDOUT: + { + struct v4l2_audioout *p=arg; + + if (vfd->vidioc_g_audout) { + dbgarg("Enum for index=%d\n", p->index); + ret=vfd->vidioc_g_audout(file, fh, p); + dbgarg("index=%d, name=%s, capability=%d, mode=%d\n", + p->index, p->name, p->capability,p->mode); + } + break; + } + case VIDIOC_S_AUDOUT: + { + struct v4l2_audioout *p=arg; + + if (vfd->vidioc_s_audout) { + dbgarg("index=%d, name=%s, capability=%d, mode=%d\n", + p->index, p->name, p->capability,p->mode); + + ret=vfd->vidioc_s_audout(file, fh, p); + } + break; + } + case VIDIOC_G_MODULATOR: + { + struct v4l2_modulator *p=arg; + if (vfd->vidioc_g_modulator) { + ret=vfd->vidioc_g_modulator(file, fh, p); + dbgarg("index=%d, name=%s, capability=%d, rangelow=%d," + " rangehigh=%d, txsubchans=%d\n", + p->index, p->name,p->capability,p->rangelow, + p->rangehigh,p->txsubchans); + } + break; + } + case VIDIOC_S_MODULATOR: + { + struct v4l2_modulator *p=arg; + if (vfd->vidioc_s_modulator) { + dbgarg("index=%d, name=%s, capability=%d, rangelow=%d," + " rangehigh=%d, txsubchans=%d\n", + p->index, p->name,p->capability,p->rangelow, + p->rangehigh,p->txsubchans); + ret=vfd->vidioc_s_modulator(file, fh, p); + } + break; + } + case VIDIOC_G_CROP: + { + struct v4l2_crop *p=arg; + if (vfd->vidioc_g_crop) { + ret=vfd->vidioc_g_crop(file, fh, p); + dbgarg("type=%d\n", p->type); + dbgrect(vfd, "", &p->c); + } + break; + } + case VIDIOC_S_CROP: + { + struct v4l2_crop *p=arg; + if (vfd->vidioc_s_crop) { + dbgarg("type=%d\n", p->type); + dbgrect(vfd, "", &p->c); + ret=vfd->vidioc_s_crop(file, fh, p); + } + break; + } + case VIDIOC_CROPCAP: + { + struct v4l2_cropcap *p=arg; + /*FIXME: Should also show v4l2_fract pixelaspect */ + if (vfd->vidioc_cropcap) { + dbgarg("type=%d\n", p->type); + dbgrect(vfd, "bounds ", &p->bounds); + dbgrect(vfd, "defrect ", &p->defrect); + ret=vfd->vidioc_cropcap(file, fh, p); + } + break; + } + case VIDIOC_G_MPEGCOMP: + { + struct v4l2_mpeg_compression *p=arg; + /*FIXME: Several fields not shown */ + if (vfd->vidioc_g_mpegcomp) { + ret=vfd->vidioc_g_mpegcomp(file, fh, p); + dbgarg ("ts_pid_pmt=%d, ts_pid_audio=%d, " + "ts_pid_video=%d, ts_pid_pcr=%d, ps_size=%d, " + "au_sample_rate=%d, au_pesid=%c, " + "vi_frame_rate=%d, vi_frames_per_gop=%d, " + "vi_bframes_count=%d, vi_pesid=%c\n", + p->ts_pid_pmt,p->ts_pid_audio, p->ts_pid_video, + p->ts_pid_pcr, p->ps_size, p->au_sample_rate, + p->au_pesid, p->vi_frame_rate, + p->vi_frames_per_gop, p->vi_bframes_count, + p->vi_pesid); + } + break; + } + case VIDIOC_S_MPEGCOMP: + { + struct v4l2_mpeg_compression *p=arg; + /*FIXME: Several fields not shown */ + if (vfd->vidioc_s_mpegcomp) { + dbgarg ("ts_pid_pmt=%d, ts_pid_audio=%d, " + "ts_pid_video=%d, ts_pid_pcr=%d, ps_size=%d, " + "au_sample_rate=%d, au_pesid=%c, " + "vi_frame_rate=%d, vi_frames_per_gop=%d, " + "vi_bframes_count=%d, vi_pesid=%c\n", + p->ts_pid_pmt,p->ts_pid_audio, p->ts_pid_video, + p->ts_pid_pcr, p->ps_size, p->au_sample_rate, + p->au_pesid, p->vi_frame_rate, + p->vi_frames_per_gop, p->vi_bframes_count, + p->vi_pesid); + ret=vfd->vidioc_s_mpegcomp(file, fh, p); + } + break; + } + case VIDIOC_G_JPEGCOMP: + { + struct v4l2_jpegcompression *p=arg; + if (vfd->vidioc_g_jpegcomp) { + dbgarg ("quality=%d, APPn=%d, APP_len=%d, COM_len=%d," + " jpeg_markers=%d\n", + p->quality,p->APPn,p->APP_len, + p->COM_len,p->jpeg_markers); + ret=vfd->vidioc_g_jpegcomp(file, fh, p); + } + break; + } + case VIDIOC_S_JPEGCOMP: + { + struct v4l2_jpegcompression *p=arg; + if (vfd->vidioc_g_jpegcomp) { + ret=vfd->vidioc_s_jpegcomp(file, fh, p); + dbgarg ("quality=%d, APPn=%d, APP_len=%d, COM_len=%d," + " jpeg_markers=%d\n", + p->quality,p->APPn,p->APP_len, + p->COM_len,p->jpeg_markers); + } + break; + } + case VIDIOC_G_PARM: + { + struct v4l2_streamparm *p=arg; + if (vfd->vidioc_g_parm) { + dbgarg ("type=%d\n", p->type); + ret=vfd->vidioc_g_parm(file, fh, p); + } + break; + } + case VIDIOC_S_PARM: + { + struct v4l2_streamparm *p=arg; + if (vfd->vidioc_s_parm) { + ret=vfd->vidioc_s_parm(file, fh, p); + dbgarg ("type=%d\n", p->type); + } + break; + } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *p=arg; + if (vfd->vidioc_g_tuner) { + ret=vfd->vidioc_g_tuner(file, fh, p); + dbgarg ("index=%d, name=%s, type=%d, capability=%d, " + "rangelow=%d, rangehigh=%d, signal=%d, afc=%d, " + "rxsubchans=%d, audmode=%d\n", + p->index, p->name, p->type, + p->capability, p->rangelow,p->rangehigh, + p->rxsubchans, p->audmode, p->signal, + p->afc); + } + break; + } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *p=arg; + if (vfd->vidioc_s_tuner) { + dbgarg ("index=%d, name=%s, type=%d, capability=%d, " + "rangelow=%d, rangehigh=%d, signal=%d, afc=%d, " + "rxsubchans=%d, audmode=%d\n", + p->index, p->name, p->type, + p->capability, p->rangelow,p->rangehigh, + p->rxsubchans, p->audmode, p->signal, + p->afc); + ret=vfd->vidioc_s_tuner(file, fh, p); + } + break; + } + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *p=arg; + if (vfd->vidioc_g_frequency) { + dbgarg ("tuner=%d, type=%d, frequency=%d\n", + p->tuner,p->type,p->frequency); + ret=vfd->vidioc_g_frequency(file, fh, p); + } + break; + } + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *p=arg; + if (vfd->vidioc_s_frequency) { + ret=vfd->vidioc_s_frequency(file, fh, p); + dbgarg ("tuner=%d, type=%d, frequency=%d\n", + p->tuner,p->type,p->frequency); + } + break; + } + case VIDIOC_G_SLICED_VBI_CAP: + { + struct v4l2_sliced_vbi_cap *p=arg; + if (vfd->vidioc_g_sliced_vbi_cap) { + dbgarg ("service_set=%d\n", p->service_set); + ret=vfd->vidioc_g_sliced_vbi_cap(file, fh, p); + } + break; + } + case VIDIOC_LOG_STATUS: + { + if (vfd->vidioc_log_status) { + ret=vfd->vidioc_log_status(file, fh); + } + break; + } + + /* --- Others --------------------------------------------- */ + + default: + ret=v4l_compat_translate_ioctl(inode,file,cmd,arg,__video_do_ioctl); + } + + if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { + if (ret<0) { + printk ("%s", vfd->name); + v4l_print_ioctl("(err):", cmd); + } + } + + return ret; +} + +int video_ioctl2 (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + char sbuf[128]; + void *mbuf = NULL; + void *parg = NULL; + int err = -EINVAL; + +#ifdef __OLD_VIDIOC_ + cmd = video_fix_command(cmd); +#endif + + /* Copy arguments into temp kernel buffer */ + switch (_IOC_DIR(cmd)) { + case _IOC_NONE: + parg = NULL; + break; + case _IOC_READ: + case _IOC_WRITE: + case (_IOC_WRITE | _IOC_READ): + if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { + parg = sbuf; + } else { + /* too big to allocate from stack */ + mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); + if (NULL == mbuf) + return -ENOMEM; + parg = mbuf; + } + + err = -EFAULT; + if (_IOC_DIR(cmd) & _IOC_WRITE) + if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) + goto out; + break; + } + + /* Handles IOCTL */ + err = __video_do_ioctl(inode, file, cmd, parg); + if (err == -ENOIOCTLCMD) + err = -EINVAL; + if (err < 0) + goto out; + + /* Copy results into user buffer */ + switch (_IOC_DIR(cmd)) + { + case _IOC_READ: + case (_IOC_WRITE | _IOC_READ): + if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) + err = -EFAULT; + break; + } + +out: + kfree(mbuf); + return err; +} + + static struct file_operations video_fops; /** @@ -395,7 +1447,9 @@ void video_unregister_device(struct video_device *vfd) mutex_unlock(&videodev_lock); } - +/* + * Video fs operations + */ static struct file_operations video_fops= { .owner = THIS_MODULE, @@ -411,7 +1465,7 @@ static int __init videodev_init(void) { int ret; - printk(KERN_INFO "Linux video capture interface: v1.00\n"); + printk(KERN_INFO "Linux video capture interface: v2.00\n"); if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) { printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR); return -EIO; @@ -442,11 +1496,12 @@ EXPORT_SYMBOL(video_devdata); EXPORT_SYMBOL(video_usercopy); EXPORT_SYMBOL(video_exclusive_open); EXPORT_SYMBOL(video_exclusive_release); +EXPORT_SYMBOL(video_ioctl2); EXPORT_SYMBOL(video_device_alloc); EXPORT_SYMBOL(video_device_release); -MODULE_AUTHOR("Alan Cox"); -MODULE_DESCRIPTION("Device registrar for Video4Linux drivers"); +MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>"); +MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2"); MODULE_LICENSE("GPL"); |