diff options
author | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-01-20 14:58:17 -0200 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-01-20 14:58:17 -0200 |
commit | d0eb1f909832fbb0959a05a7bb96d31f2c385515 (patch) | |
tree | 2f90105f0835176e651e0085bd3130401a6f8d99 /linux/drivers/media/video/cx88/cx88-video.c | |
parent | c0720857a3c9833755f75a795763004cf643a0ae (diff) | |
download | mediapointer-dvb-s2-d0eb1f909832fbb0959a05a7bb96d31f2c385515.tar.gz mediapointer-dvb-s2-d0eb1f909832fbb0959a05a7bb96d31f2c385515.tar.bz2 |
Convert cx8800 driver to video_ioctl2 handler
From: Mauro Carvalho Chehab <mchehab@infradead.org>
video_ioctl2 handler provides V4L2 API parsing.
Using it makes the driver simpler, and isolates API parsing.
This allows future reusage of driver controls using other ways, like sysfs
and/or procfs and increases isolation of driver-specific handling from the
generic common ioctl processing.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'linux/drivers/media/video/cx88/cx88-video.c')
-rw-r--r-- | linux/drivers/media/video/cx88/cx88-video.c | 1154 |
1 files changed, 517 insertions, 637 deletions
diff --git a/linux/drivers/media/video/cx88/cx88-video.c b/linux/drivers/media/video/cx88/cx88-video.c index 6a420d6db..7456daf3c 100644 --- a/linux/drivers/media/video/cx88/cx88-video.c +++ b/linux/drivers/media/video/cx88/cx88-video.c @@ -1,3 +1,4 @@ + /* * * device driver for Conexant 2388x based TV cards @@ -5,6 +6,11 @@ * * (c) 2003-04 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] * + * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org> + * - Multituner support + * - video_ioctl2 conversion + * - PAL/M fixes + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -96,69 +102,52 @@ static LIST_HEAD(cx8800_devlist); /* ------------------------------------------------------------------- */ /* static data */ -static struct cx88_tvnorm tvnorms[] = { +static struct v4l2_tvnorm tvnorms[] = { { .name = "NTSC-M", .id = V4L2_STD_NTSC_M, - .cxiformat = VideoFormatNTSC, - .cxoformat = 0x181f0008, },{ .name = "NTSC-JP", .id = V4L2_STD_NTSC_M_JP, - .cxiformat = VideoFormatNTSCJapan, - .cxoformat = 0x181f0008, #if 0 },{ .name = "NTSC-4.43", .id = FIXME, - .cxiformat = VideoFormatNTSC443, - .cxoformat = 0x181f0008, #endif },{ .name = "PAL-BG", .id = V4L2_STD_PAL_BG, - .cxiformat = VideoFormatPAL, - .cxoformat = 0x181f0008, },{ .name = "PAL-DK", .id = V4L2_STD_PAL_DK, - .cxiformat = VideoFormatPAL, - .cxoformat = 0x181f0008, },{ .name = "PAL-I", .id = V4L2_STD_PAL_I, - .cxiformat = VideoFormatPAL, - .cxoformat = 0x181f0008, },{ .name = "PAL-M", .id = V4L2_STD_PAL_M, - .cxiformat = VideoFormatPALM, - .cxoformat = 0x1c1f0008, },{ .name = "PAL-N", .id = V4L2_STD_PAL_N, - .cxiformat = VideoFormatPALN, - .cxoformat = 0x1c1f0008, },{ .name = "PAL-Nc", .id = V4L2_STD_PAL_Nc, - .cxiformat = VideoFormatPALNC, - .cxoformat = 0x1c1f0008, },{ .name = "PAL-60", .id = V4L2_STD_PAL_60, - .cxiformat = VideoFormatPAL60, - .cxoformat = 0x181f0008, },{ .name = "SECAM-L", .id = V4L2_STD_SECAM_L, - .cxiformat = VideoFormatSECAM, - .cxoformat = 0x181f0008, },{ .name = "SECAM-DK", .id = V4L2_STD_SECAM_DK, - .cxiformat = VideoFormatSECAM, - .cxoformat = 0x181f0008, + } +}; + +static struct v4l2_tvnorm radionorms[] = { + { + .name = "RADIO", + .id = 0, } }; @@ -387,14 +376,6 @@ int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl) } EXPORT_SYMBOL(cx8800_ctrl_query); -static int cx88_queryctrl(struct v4l2_queryctrl *qctrl) -{ - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); - if (qctrl->id == 0) - return -EINVAL; - return cx8800_ctrl_query(qctrl); -} - /* ------------------------------------------------------------------- */ /* resource management */ @@ -1192,19 +1173,20 @@ video_mmap(struct file *file, struct vm_area_struct * vma) } /* ------------------------------------------------------------------ */ +/* VIDEO CTRL IOCTLS */ -/* static int get_control(struct cx8800_dev *dev, struct v4l2_control *ctl) */ -static int get_control(struct cx88_core *core, struct v4l2_control *ctl) +static int vidioc_g_ctrl (struct file *file, void *priv, + struct v4l2_control *ctl) { - /* struct cx88_core *core = dev->core; */ - struct cx88_ctrl *c = NULL; + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; + struct cx88_ctrl *c = NULL; u32 value; int i; for (i = 0; i < CX8800_CTLS; i++) if (cx8800_ctls[i].v.id == ctl->id) c = &cx8800_ctls[i]; - if (NULL == c) + if (unlikely(NULL == c)) return -EINVAL; value = c->sreg ? cx_sread(c->sreg) : cx_read(c->reg); @@ -1226,19 +1208,18 @@ static int get_control(struct cx88_core *core, struct v4l2_control *ctl) return 0; } -/* static int set_control(struct cx8800_dev *dev, struct v4l2_control *ctl) */ static int set_control(struct cx88_core *core, struct v4l2_control *ctl) { - /* struct cx88_core *core = dev->core; */ struct cx88_ctrl *c = NULL; u32 value,mask; int i; + for (i = 0; i < CX8800_CTLS; i++) { if (cx8800_ctls[i].v.id == ctl->id) { c = &cx8800_ctls[i]; } } - if (NULL == c) + if (unlikely(NULL == c)) return -EINVAL; if (ctl->value < c->v.minimum) @@ -1298,681 +1279,538 @@ static void init_controls(struct cx88_core *core) for (i = 0; i < CX8800_CTLS; i++) { ctrl.id=cx8800_ctls[i].v.id; ctrl.value=cx8800_ctls[i].v.default_value; + set_control(core, &ctrl); } } /* ------------------------------------------------------------------ */ +/* VIDEO IOCTLS */ -static int cx8800_g_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh, - struct v4l2_format *f) +static int vidioc_g_fmt_cap (struct file *file, void *priv, + struct v4l2_format *f) { - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - memset(&f->fmt.pix,0,sizeof(f->fmt.pix)); - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; - f->fmt.pix.field = fh->vidq.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fh->fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - return 0; - case V4L2_BUF_TYPE_VBI_CAPTURE: - cx8800_vbi_fmt(dev, f); - return 0; - default: - return -EINVAL; - } + struct cx8800_fh *fh = priv; + + f->fmt.pix.width = fh->width; + f->fmt.pix.height = fh->height; + f->fmt.pix.field = fh->vidq.field; + f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.bytesperline = + (f->fmt.pix.width * fh->fmt->depth) >> 3; + f->fmt.pix.sizeimage = + f->fmt.pix.height * f->fmt.pix.bytesperline; + return 0; } -static int cx8800_try_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh, - struct v4l2_format *f) +static int vidioc_try_fmt_cap (struct file *file, void *priv, + struct v4l2_format *f) { - struct cx88_core *core = dev->core; + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; + struct cx8800_fmt *fmt; + enum v4l2_field field; + unsigned int maxw, maxh; - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - { - struct cx8800_fmt *fmt; - enum v4l2_field field; - unsigned int maxw, maxh; - - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (NULL == fmt) - return -EINVAL; - - field = f->fmt.pix.field; - maxw = norm_maxw(core->tvnorm); - maxh = norm_maxh(core->tvnorm); - - if (V4L2_FIELD_ANY == field) { - field = (f->fmt.pix.height > maxh/2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_BOTTOM; - } - - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - maxh = maxh / 2; - break; - case V4L2_FIELD_INTERLACED: - break; - default: - return -EINVAL; - } + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (NULL == fmt) + return -EINVAL; - f->fmt.pix.field = field; - if (f->fmt.pix.height < 32) - f->fmt.pix.height = 32; - if (f->fmt.pix.height > maxh) - f->fmt.pix.height = maxh; - if (f->fmt.pix.width < 48) - f->fmt.pix.width = 48; - if (f->fmt.pix.width > maxw) - f->fmt.pix.width = maxw; - f->fmt.pix.width &= ~0x03; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; + field = f->fmt.pix.field; + maxw = norm_maxw(core->tvnorm); + maxh = norm_maxh(core->tvnorm); - return 0; + if (V4L2_FIELD_ANY == field) { + field = (f->fmt.pix.height > maxh/2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; } - case V4L2_BUF_TYPE_VBI_CAPTURE: - cx8800_vbi_fmt(dev, f); - return 0; + + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + maxh = maxh / 2; + break; + case V4L2_FIELD_INTERLACED: + break; default: return -EINVAL; } + + f->fmt.pix.field = field; + if (f->fmt.pix.height < 32) + f->fmt.pix.height = 32; + if (f->fmt.pix.height > maxh) + f->fmt.pix.height = maxh; + if (f->fmt.pix.width < 48) + f->fmt.pix.width = 48; + if (f->fmt.pix.width > maxw) + f->fmt.pix.width = maxw; + f->fmt.pix.width &= ~0x03; + f->fmt.pix.bytesperline = + (f->fmt.pix.width * fmt->depth) >> 3; + f->fmt.pix.sizeimage = + f->fmt.pix.height * f->fmt.pix.bytesperline; + + return 0; } -static int cx8800_s_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh, - struct v4l2_format *f) +static int vidioc_s_fmt_cap (struct file *file, void *priv, + struct v4l2_format *f) { - int err; + struct cx8800_fh *fh = priv; + int err = vidioc_try_fmt_cap (file,priv,f); - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - err = cx8800_try_fmt(dev,fh,f); - if (0 != err) - return err; - - fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; - fh->vidq.field = f->fmt.pix.field; - return 0; - case V4L2_BUF_TYPE_VBI_CAPTURE: - cx8800_vbi_fmt(dev, f); - return 0; - default: - return -EINVAL; - } + if (0 != err) + return err; + fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + fh->width = f->fmt.pix.width; + fh->height = f->fmt.pix.height; + fh->vidq.field = f->fmt.pix.field; + return 0; } -/* - * This function is _not_ called directly, but from - * video_generic_ioctl (and maybe others). userspace - * copying is done already, arg is a kernel pointer. - */ -static int video_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int vidioc_querycap (struct file *file, void *priv, + struct v4l2_capability *cap) { - struct cx8800_fh *fh = file->private_data; - struct cx8800_dev *dev = fh->dev; + struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev; struct cx88_core *core = dev->core; - int err; - if (video_debug > 1) - v4l_print_ioctl(core->name,cmd); - switch (cmd) { - - /* --- capabilities ------------------------------------------ */ - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = arg; - - memset(cap,0,sizeof(*cap)); - strcpy(cap->driver, "cx8800"); - strlcpy(cap->card, cx88_boards[core->board].name, - sizeof(cap->card)); - sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); - cap->version = CX88_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_VBI_CAPTURE | + strcpy(cap->driver, "cx8800"); + strlcpy(cap->card, cx88_boards[core->board].name, + sizeof(cap->card)); + sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); + cap->version = CX88_VERSION_CODE; + cap->capabilities = #if 0 - V4L2_CAP_VIDEO_OVERLAY | + V4L2_CAP_VIDEO_OVERLAY | #endif - 0; - if (UNSET != core->tuner_type) - cap->capabilities |= V4L2_CAP_TUNER; - return 0; - } + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | + V4L2_CAP_VBI_CAPTURE; + if (UNSET != core->tuner_type) + cap->capabilities |= V4L2_CAP_TUNER; + return 0; +} + +static int vidioc_enum_fmt_cap (struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (unlikely(f->index >= ARRAY_SIZE(formats))) + return -EINVAL; + + strlcpy(f->description,formats[f->index].name,sizeof(f->description)); + f->pixelformat = formats[f->index].fourcc; + + return 0; +} - /* --- 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; - switch (type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (index >= ARRAY_SIZE(formats)) - return -EINVAL; - memset(f,0,sizeof(*f)); - f->index = index; - f->type = type; - strlcpy(f->description,formats[index].name,sizeof(f->description)); - f->pixelformat = formats[index].fourcc; - break; - default: - return -EINVAL; - } - return 0; - } - case VIDIOC_G_FMT: - { - struct v4l2_format *f = arg; - return cx8800_g_fmt(dev,fh,f); - } - case VIDIOC_S_FMT: - { - struct v4l2_format *f = arg; - return cx8800_s_fmt(dev,fh,f); - } - case VIDIOC_TRY_FMT: - { - struct v4l2_format *f = arg; - return cx8800_try_fmt(dev,fh,f); - } #ifdef CONFIG_VIDEO_V4L1_COMPAT - /* --- streaming capture ------------------------------------- */ - case VIDIOCGMBUF: - { - struct video_mbuf *mbuf = arg; - struct videobuf_queue *q; - struct v4l2_requestbuffers req; - unsigned int i; - - q = get_queue(fh); - memset(&req,0,sizeof(req)); - req.type = q->type; - req.count = 8; - req.memory = V4L2_MEMORY_MMAP; - err = videobuf_reqbufs(q,&req); - if (err < 0) - return err; - memset(mbuf,0,sizeof(*mbuf)); - mbuf->frames = req.count; - mbuf->size = 0; - for (i = 0; i < mbuf->frames; i++) { - mbuf->offsets[i] = q->bufs[i]->boff; - mbuf->size += q->bufs[i]->bsize; - } - return 0; +static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf) +{ + struct cx8800_fh *fh = priv; + struct videobuf_queue *q; + struct v4l2_requestbuffers req; + unsigned int i; + int err; + + q = get_queue(fh); + memset(&req,0,sizeof(req)); + req.type = q->type; + req.count = 8; + req.memory = V4L2_MEMORY_MMAP; + err = videobuf_reqbufs(q,&req); + if (err < 0) + return err; + + mbuf->frames = req.count; + mbuf->size = 0; + for (i = 0; i < mbuf->frames; i++) { + mbuf->offsets[i] = q->bufs[i]->boff; + mbuf->size += q->bufs[i]->bsize; } + return 0; +} #endif - case VIDIOC_REQBUFS: - return videobuf_reqbufs(get_queue(fh), arg); - case VIDIOC_QUERYBUF: - return videobuf_querybuf(get_queue(fh), arg); - case VIDIOC_QBUF: - return videobuf_qbuf(get_queue(fh), arg); +static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p) +{ + struct cx8800_fh *fh = priv; + return (videobuf_reqbufs(get_queue(fh), p)); +} - case VIDIOC_DQBUF: - return videobuf_dqbuf(get_queue(fh), arg, - file->f_flags & O_NONBLOCK); +static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct cx8800_fh *fh = priv; + return (videobuf_querybuf(get_queue(fh), p)); +} - case VIDIOC_STREAMON: - { - int res = get_ressource(fh); +static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct cx8800_fh *fh = priv; + return (videobuf_qbuf(get_queue(fh), p)); +} - if (!res_get(dev,fh,res)) - return -EBUSY; - return videobuf_streamon(get_queue(fh)); - } - case VIDIOC_STREAMOFF: - { - int res = get_ressource(fh); +static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct cx8800_fh *fh = priv; + return (videobuf_dqbuf(get_queue(fh), p, + file->f_flags & O_NONBLOCK)); +} - err = videobuf_streamoff(get_queue(fh)); - if (err < 0) - return err; - res_free(dev,fh,res); - return 0; - } - default: - return cx88_do_ioctl( inode, file, fh->radio, core, cmd, arg, video_do_ioctl ); - } +static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct cx8800_fh *fh = priv; + struct cx8800_dev *dev = fh->dev; + + if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) + return -EINVAL; + if (unlikely(i != fh->type)) + return -EINVAL; + + if (unlikely(!res_get(dev,fh,get_ressource(fh)))) + return -EBUSY; + return videobuf_streamon(get_queue(fh)); +} + +static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct cx8800_fh *fh = priv; + struct cx8800_dev *dev = fh->dev; + int err, res; + + if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (i != fh->type) + return -EINVAL; + + res = get_ressource(fh); + err = videobuf_streamoff(get_queue(fh)); + if (err < 0) + return err; + res_free(dev,fh,res); return 0; } -int cx88_do_ioctl(struct inode *inode, struct file *file, int radio, - struct cx88_core *core, unsigned int cmd, void *arg, v4l2_kioctl driver_ioctl) +static int vidioc_s_std (struct file *file, void *priv, unsigned int i) { - int err; + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - if (video_debug) { - if (video_debug > 1) { - if (_IOC_DIR(cmd) & _IOC_WRITE) - v4l_printk_ioctl_arg("cx88(w)",cmd, arg); - else if (!_IOC_DIR(cmd) & _IOC_READ) { - v4l_print_ioctl("cx88", cmd); - } - } else - v4l_print_ioctl(core->name,cmd); - - } - - switch (cmd) { - /* ---------- tv norms ---------- */ - case VIDIOC_ENUMSTD: - { - struct v4l2_standard *e = arg; - unsigned int i; - - i = e->index; - if (i >= ARRAY_SIZE(tvnorms)) - return -EINVAL; - err = v4l2_video_std_construct(e, tvnorms[e->index].id, - tvnorms[e->index].name); - e->index = i; - if (err < 0) - return err; - return 0; - } - case VIDIOC_G_STD: - { - v4l2_std_id *id = arg; + mutex_lock(&core->lock); + cx88_set_tvnorm(core,&tvnorms[i]); + mutex_unlock(&core->lock); + return 0; +} - *id = core->tvnorm->id; - return 0; - } - case VIDIOC_S_STD: - { - v4l2_std_id *id = arg; - unsigned int i; +/* only one input in this sample driver */ +static int vidioc_enum_input (struct file *file, void *priv, + struct v4l2_input *i) +{ + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; + + static const char *iname[] = { + [ CX88_VMUX_COMPOSITE1 ] = "Composite1", + [ CX88_VMUX_COMPOSITE2 ] = "Composite2", + [ CX88_VMUX_COMPOSITE3 ] = "Composite3", + [ CX88_VMUX_COMPOSITE4 ] = "Composite4", + [ CX88_VMUX_SVIDEO ] = "S-Video", + [ CX88_VMUX_TELEVISION ] = "Television", + [ CX88_VMUX_CABLE ] = "Cable TV", + [ CX88_VMUX_DVB ] = "DVB", + [ CX88_VMUX_DEBUG ] = "for debug only", + }; + unsigned int n; - for(i = 0; i < ARRAY_SIZE(tvnorms); i++) - if (*id & tvnorms[i].id) - break; - if (i == ARRAY_SIZE(tvnorms)) - return -EINVAL; + n = i->index; + if (n >= 4) + return -EINVAL; + if (0 == INPUT(n)->type) + return -EINVAL; + memset(i,0,sizeof(*i)); + i->index = n; + i->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(i->name,iname[INPUT(n)->type]); + if ((CX88_VMUX_TELEVISION == INPUT(n)->type) || + (CX88_VMUX_CABLE == INPUT(n)->type)) + i->type = V4L2_INPUT_TYPE_TUNER; + for (n = 0; n < ARRAY_SIZE(tvnorms); n++) + i->std |= tvnorms[n].id; + return 0; +} - mutex_lock(&core->lock); - cx88_set_tvnorm(core,&tvnorms[i]); - mutex_unlock(&core->lock); - return 0; - } +static int vidioc_g_input (struct file *file, void *priv, unsigned int *i) +{ + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - /* ------ input switching ---------- */ - case VIDIOC_ENUMINPUT: - { - static const char *iname[] = { - [ CX88_VMUX_COMPOSITE1 ] = "Composite1", - [ CX88_VMUX_COMPOSITE2 ] = "Composite2", - [ CX88_VMUX_COMPOSITE3 ] = "Composite3", - [ CX88_VMUX_COMPOSITE4 ] = "Composite4", - [ CX88_VMUX_SVIDEO ] = "S-Video", - [ CX88_VMUX_TELEVISION ] = "Television", - [ CX88_VMUX_CABLE ] = "Cable TV", - [ CX88_VMUX_DVB ] = "DVB", - [ CX88_VMUX_DEBUG ] = "for debug only", - }; - struct v4l2_input *i = arg; - unsigned int n; - - n = i->index; - if (n >= 4) - return -EINVAL; - if (0 == INPUT(n)->type) - return -EINVAL; - memset(i,0,sizeof(*i)); - i->index = n; - i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name,iname[INPUT(n)->type]); - if ((CX88_VMUX_TELEVISION == INPUT(n)->type) || - (CX88_VMUX_CABLE == INPUT(n)->type)) - i->type = V4L2_INPUT_TYPE_TUNER; - for (n = 0; n < ARRAY_SIZE(tvnorms); n++) - i->std |= tvnorms[n].id; - return 0; - } - case VIDIOC_G_INPUT: - { - unsigned int *i = arg; + *i = core->input; + return 0; +} - *i = core->input; - return 0; - } - case VIDIOC_S_INPUT: - { - unsigned int *i = arg; +static int vidioc_s_input (struct file *file, void *priv, unsigned int i) +{ + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - if (*i >= 4) - return -EINVAL; - mutex_lock(&core->lock); - cx88_newstation(core); - video_mux(core,*i); - mutex_unlock(&core->lock); - return 0; - } + if (i >= 4) + return -EINVAL; + + mutex_lock(&core->lock); + cx88_newstation(core); + video_mux(core,i); + mutex_unlock(&core->lock); + return 0; +} #if 0 - /* needs review */ - case VIDIOC_G_AUDIO: - { - struct v4l2_audio *a = arg; - unsigned int n = a->index; - - memset(a,0,sizeof(*a)); - a->index = n; - switch (n) { - case 0: - if ((CX88_VMUX_TELEVISION == INPUT(n)->type) - || (CX88_VMUX_CABLE == INPUT(n)->type)) { - strcpy(a->name,"Television"); - /* FIXME figure out if stereo received and set V4L2_AUDCAP_STEREO. */ - return 0; - } - break; - case 1: - if (CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q == core->board) { - strcpy(a->name,"Line In"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; - } - break; +static int vidioc_g_audio (struct file *file, void *priv, unsigned int i) +{ + struct v4l2_audio *a = arg; + unsigned int n = a->index; + + memset(a,0,sizeof(*a)); + a->index = n; + switch (n) { + case 0: + if ((CX88_VMUX_TELEVISION == INPUT(n)->type) + || (CX88_VMUX_CABLE == INPUT(n)->type)) { + strcpy(a->name,"Television"); + /* FIXME figure out if stereo received and set V4L2_AUDCAP_STEREO. */ + return 0; } - /* Audio input not available. */ - return -EINVAL; + break; + case 1: + if (CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q == core->board) { + strcpy(a->name,"Line In"); + a->capability = V4L2_AUDCAP_STEREO; + return 0; + } + break; } + /* Audio input not available. */ + return -EINVAL; +} #endif - /* --- controls ---------------------------------------------- */ - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *c = arg; +static int vidioc_queryctrl (struct file *file, void *priv, + struct v4l2_queryctrl *qctrl) +{ + qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); + if (unlikely(qctrl->id == 0)) + return -EINVAL; + return cx8800_ctrl_query(qctrl); +} - return cx88_queryctrl(c); - } - case VIDIOC_G_CTRL: - return get_control(core,arg); - case VIDIOC_S_CTRL: - return set_control(core,arg); +static int vidioc_s_ctrl (struct file *file, void *priv, + struct v4l2_control *ctl) +{ + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - /* --- tuner ioctls ------------------------------------------ */ - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *t = arg; - u32 reg; - - if (UNSET == core->tuner_type) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - - memset(t,0,sizeof(*t)); - strcpy(t->name, "Television"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM; - t->rangehigh = 0xffffffffUL; - - cx88_get_stereo(core ,t); - reg = cx_read(MO_DEVICE_STATUS); - t->signal = (reg & (1<<5)) ? 0xffff : 0x0000; - return 0; - } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *t = arg; + return + set_control(core,ctl); +} - if (UNSET == core->tuner_type) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - cx88_set_stereo(core, t->audmode, 1); - return 0; - } - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *f = arg; +static int vidioc_g_tuner (struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; + u32 reg; - memset(f,0,sizeof(*f)); + if (unlikely(UNSET == core->tuner_type)) + return -EINVAL; - if (UNSET == core->tuner_type) - return -EINVAL; + strcpy(t->name, "Television"); + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM; + t->rangehigh = 0xffffffffUL; - /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ - f->type = radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - f->frequency = core->freq; + cx88_get_stereo(core ,t); + reg = cx_read(MO_DEVICE_STATUS); + t->signal = (reg & (1<<5)) ? 0xffff : 0x0000; + return 0; +} - cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f); +static int vidioc_s_tuner (struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - return 0; - } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *f = arg; - - if (UNSET == core->tuner_type) - return -EINVAL; - if (f->tuner != 0) - return -EINVAL; - if (0 == radio && f->type != V4L2_TUNER_ANALOG_TV) - return -EINVAL; - if (1 == radio && f->type != V4L2_TUNER_RADIO) - return -EINVAL; - mutex_lock(&core->lock); - core->freq = f->frequency; - cx88_newstation(core); - cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f); - - /* When changing channels it is required to reset TVAUDIO */ - msleep (10); - cx88_set_tvaudio(core); + if (UNSET == core->tuner_type) + return -EINVAL; + if (0 != t->index) + return -EINVAL; - mutex_unlock(&core->lock); - return 0; - } -#ifdef CONFIG_VIDEO_ADV_DEBUG - /* ioctls to allow direct acces to the cx2388x registers */ - case VIDIOC_INT_G_REGISTER: - { - struct v4l2_register *reg = arg; + cx88_set_stereo(core, t->audmode, 1); + return 0; +} - if (reg->i2c_id != 0) - return -EINVAL; - /* cx2388x has a 24-bit register space */ - reg->val = cx_read(reg->reg&0xffffff); - return 0; - } - case VIDIOC_INT_S_REGISTER: - { - struct v4l2_register *reg = arg; +static int vidioc_g_frequency (struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct cx8800_fh *fh = priv; + struct cx88_core *core = fh->dev->core; - if (reg->i2c_id != 0) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - cx_write(reg->reg&0xffffff, reg->val); - return 0; - } -#endif + if (unlikely(UNSET == core->tuner_type)) + return -EINVAL; + + /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ + f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + f->frequency = core->freq; + + cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f); - default: - return v4l_compat_translate_ioctl(inode,file,cmd,arg, - driver_ioctl); - } return 0; } -static int video_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int vidioc_s_frequency (struct file *file, void *priv, + struct v4l2_frequency *f) { - int retval; + struct cx8800_fh *fh = priv; + struct cx88_core *core = fh->dev->core; - retval=video_usercopy(inode, file, cmd, arg, video_do_ioctl); + if (unlikely(UNSET == core->tuner_type)) + return -EINVAL; + if (unlikely(f->tuner != 0)) + return -EINVAL; + if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) + return -EINVAL; + if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) + return -EINVAL; + mutex_lock(&core->lock); + core->freq = f->frequency; + cx88_newstation(core); + cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f); - if (video_debug > 1) { - if (retval < 0) { - v4l_print_ioctl("cx88(err)", cmd); - printk(KERN_DEBUG "cx88(err): errcode=%d\n",retval); - } else if (_IOC_DIR(cmd) & _IOC_READ) - v4l_printk_ioctl_arg("cx88(r)",cmd, (void *)arg); - } + /* When changing channels it is required to reset TVAUDIO */ + msleep (10); + cx88_set_tvaudio(core); - return retval; + mutex_unlock(&core->lock); + return 0; } +#if 0 //ifdef CONFIG_VIDEO_ADV_DEBUG +static int vidioc_g_register (struct file *file, void *priv, + v4l2_register *reg) +{ + if (reg->i2c_id != 0) + return -EINVAL; + /* cx2388x has a 24-bit register space */ + reg->val = cx_read(reg->reg&0xffffff); + return 0; +} + +static int vidioc_s_register (struct file *file, void *fh, + v4l2_register *reg) +{ + + if (reg->i2c_id != 0) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + cx_write(reg->reg&0xffffff, reg->val); + return 0; +} +#endif + +/* ----------------------------------------------------------- */ +/* RADIO ESPECIFIC IOCTLS */ /* ----------------------------------------------------------- */ -static int radio_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int radio_querycap (struct file *file, void *priv, + struct v4l2_capability *cap) { - struct cx8800_fh *fh = file->private_data; - struct cx8800_dev *dev = fh->dev; + struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev; struct cx88_core *core = dev->core; - if (video_debug > 1) - v4l_print_ioctl(core->name,cmd); - - switch (cmd) { - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = arg; - - memset(cap,0,sizeof(*cap)); - strcpy(cap->driver, "cx8800"); - strlcpy(cap->card, cx88_boards[core->board].name, - sizeof(cap->card)); - sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci)); - cap->version = CX88_VERSION_CODE; - cap->capabilities = V4L2_CAP_TUNER; - return 0; - } - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *t = arg; + strcpy(cap->driver, "cx8800"); + strlcpy(cap->card, cx88_boards[core->board].name, + sizeof(cap->card)); + sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci)); + cap->version = CX88_VERSION_CODE; + cap->capabilities = V4L2_CAP_TUNER; + return 0; +} - if (t->index > 0) - return -EINVAL; +static int radio_g_tuner (struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - memset(t,0,sizeof(*t)); - strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; + if (unlikely(t->index > 0)) + return -EINVAL; - cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t); - return 0; - } - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *i = arg; + strcpy(t->name, "Radio"); + t->type = V4L2_TUNER_RADIO; - if (i->index != 0) - return -EINVAL; - strcpy(i->name,"Radio"); - i->type = V4L2_INPUT_TYPE_TUNER; - return 0; - } - case VIDIOC_G_INPUT: - { - int *i = arg; - *i = 0; - return 0; - } - case VIDIOC_G_AUDIO: - { - struct v4l2_audio *a = arg; + cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t); + return 0; +} - memset(a,0,sizeof(*a)); - strcpy(a->name,"Radio"); - return 0; - } - case VIDIOC_G_STD: - { - v4l2_std_id *id = arg; - *id = 0; - return 0; - } -#ifdef CONFIG_VIDEO_V4L1_COMPAT - case VIDIOCSTUNER: - { - struct video_tuner *v = arg; +static int radio_enum_input (struct file *file, void *priv, + struct v4l2_input *i) +{ + if (i->index != 0) + return -EINVAL; + strcpy(i->name,"Radio"); + i->type = V4L2_INPUT_TYPE_TUNER; - if (v->tuner) /* Only tuner 0 */ - return -EINVAL; + return 0; +} - cx88_call_i2c_clients(core,VIDIOCSTUNER,v); - return 0; - } -#endif - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *t = arg; +static int radio_g_audio (struct file *file, void *priv, struct v4l2_audio *a) +{ + if (unlikely(a->index)) + return -EINVAL; - if (0 != t->index) - return -EINVAL; + memset(a,0,sizeof(*a)); + strcpy(a->name,"Radio"); + return 0; +} - cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t); +/* FIXME: Should add a standard for radio */ - return 0; - } +static int radio_s_tuner (struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - case VIDIOC_S_AUDIO: - case VIDIOC_S_INPUT: - case VIDIOC_S_STD: - return 0; + if (0 != t->index) + return -EINVAL; - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *c = arg; - int i; - - if (c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) - return -EINVAL; - if (c->id == V4L2_CID_AUDIO_MUTE) { - for (i = 0; i < CX8800_CTLS; i++) - if (cx8800_ctls[i].v.id == c->id) - break; - *c = cx8800_ctls[i].v; - } else - *c = no_ctl; - return 0; - } + cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t); + return 0; +} - case VIDIOC_G_CTRL: - case VIDIOC_S_CTRL: - case VIDIOC_G_FREQUENCY: - case VIDIOC_S_FREQUENCY: - return video_do_ioctl(inode,file,cmd,arg); +static int radio_s_audio (struct file *file, void *fh, + struct v4l2_audio *a) +{ + return 0; +} - default: - return v4l_compat_translate_ioctl(inode,file,cmd,arg, - radio_do_ioctl); - } +static int radio_s_input (struct file *file, void *fh, unsigned int i) +{ return 0; -}; +} -static int radio_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int radio_queryctrl (struct file *file, void *priv, + struct v4l2_queryctrl *c) { - return video_usercopy(inode, file, cmd, arg, radio_do_ioctl); -}; + int i; + + if (c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) + return -EINVAL; + if (c->id == V4L2_CID_AUDIO_MUTE) { + for (i = 0; i < CX8800_CTLS; i++) + if (cx8800_ctls[i].v.id == c->id) + break; + *c = cx8800_ctls[i].v; + } else + *c = no_ctl; + return 0; +} /* ----------------------------------------------------------- */ @@ -2109,29 +1947,50 @@ static struct file_operations video_fops = .read = video_read, .poll = video_poll, .mmap = video_mmap, - .ioctl = video_ioctl, + .ioctl = video_ioctl2, #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11) .compat_ioctl = v4l_compat_ioctl32, #endif .llseek = no_llseek, }; +static struct video_device cx8800_vbi_template; static struct video_device cx8800_video_template = { - .name = "cx8800-video", - .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES, - .hardware = 0, - .fops = &video_fops, - .minor = -1, -}; - -static struct video_device cx8800_vbi_template = -{ - .name = "cx8800-vbi", - .type = VID_TYPE_TELETEXT|VID_TYPE_TUNER, - .hardware = 0, - .fops = &video_fops, - .minor = -1, + .name = "cx8800-video", + .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES, + .fops = &video_fops, + .minor = -1, + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, + .vidioc_g_fmt_cap = vidioc_g_fmt_cap, + .vidioc_try_fmt_cap = vidioc_try_fmt_cap, + .vidioc_s_fmt_cap = vidioc_s_fmt_cap, + .vidioc_g_fmt_vbi = cx8800_vbi_fmt, + .vidioc_try_fmt_vbi = cx8800_vbi_fmt, + .vidioc_s_fmt_vbi = cx8800_vbi_fmt, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_s_std = vidioc_s_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, +#ifdef CONFIG_VIDEO_V4L1_COMPAT + .vidiocgmbuf = vidiocgmbuf, +#endif + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .tvnorms = tvnorms, + .tvnormsize = ARRAY_SIZE(tvnorms), }; static struct file_operations radio_fops = @@ -2139,7 +1998,7 @@ static struct file_operations radio_fops = .owner = THIS_MODULE, .open = video_open, .release = video_release, - .ioctl = radio_ioctl, + .ioctl = video_ioctl2, #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11) .compat_ioctl = v4l_compat_ioctl32, #endif @@ -2148,11 +2007,25 @@ static struct file_operations radio_fops = static struct video_device cx8800_radio_template = { - .name = "cx8800-radio", - .type = VID_TYPE_TUNER, - .hardware = 0, - .fops = &radio_fops, - .minor = -1, + .name = "cx8800-radio", + .type = VID_TYPE_TUNER, + .hardware = 0, + .fops = &radio_fops, + .minor = -1, + .vidioc_querycap = radio_querycap, + .vidioc_g_tuner = radio_g_tuner, + .vidioc_enum_input = radio_enum_input, + .vidioc_g_audio = radio_g_audio, + .vidioc_s_tuner = radio_s_tuner, + .vidioc_s_audio = radio_s_audio, + .vidioc_s_input = radio_s_input, + .vidioc_queryctrl = radio_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .tvnorms = radionorms, + .tvnormsize = ARRAY_SIZE(radionorms), }; /* ----------------------------------------------------------- */ @@ -2187,6 +2060,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, { struct cx8800_dev *dev; struct cx88_core *core; + int err; dev = kzalloc(sizeof(*dev),GFP_KERNEL); @@ -2221,6 +2095,12 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, goto fail_core; } + /* Initialize VBI template */ + memcpy( &cx8800_vbi_template, &cx8800_video_template, + sizeof(cx8800_vbi_template) ); + strcpy(cx8800_vbi_template.name,"cx8800-vbi"); + cx8800_vbi_template.type = VID_TYPE_TELETEXT|VID_TYPE_TUNER; + /* initialize driver struct */ #if 0 /* moved to cx88_core_get */ |