diff options
34 files changed, 1832 insertions, 1648 deletions
diff --git a/linux/Documentation/video4linux/CARDLIST.cx23885 b/linux/Documentation/video4linux/CARDLIST.cx23885 index 35ea130e9..5937ff958 100644 --- a/linux/Documentation/video4linux/CARDLIST.cx23885 +++ b/linux/Documentation/video4linux/CARDLIST.cx23885 @@ -12,3 +12,6 @@ 11 -> DViCO FusionHDTV DVB-T Dual Express [18ac:db78] 12 -> Leadtek Winfast PxDVR3200 H [107d:6681] 13 -> Compro VideoMate E650F [185b:e800] + 14 -> TurboSight TBS 6920 [6920:8888] + 15 -> TeVii S470 [d470:9022] + 16 -> DVBWorld DVB-S2 2005 [0001:2005] diff --git a/linux/drivers/media/common/saa7146_fops.c b/linux/drivers/media/common/saa7146_fops.c index b1ee5e3d9..4384bd16c 100644 --- a/linux/drivers/media/common/saa7146_fops.c +++ b/linux/drivers/media/common/saa7146_fops.c @@ -309,14 +309,6 @@ static int fops_release(struct file *file) return 0; } -static long fops_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ -/* - DEB_EE(("file:%p, cmd:%d, arg:%li\n", file, cmd, arg)); -*/ - return video_usercopy(file, cmd, arg, saa7146_video_do_ioctl); -} - static int fops_mmap(struct file *file, struct vm_area_struct * vma) { struct saa7146_fh *fh = file->private_data; @@ -426,7 +418,7 @@ static const struct v4l2_file_operations video_fops = .write = fops_write, .poll = fops_poll, .mmap = fops_mmap, - .ioctl = fops_ioctl, + .ioctl = video_ioctl2, }; static void vv_callback(struct saa7146_dev *dev, unsigned long status) @@ -453,19 +445,16 @@ static void vv_callback(struct saa7146_dev *dev, unsigned long status) } } -static struct video_device device_template = -{ - .fops = &video_fops, - .minor = -1, -}; - int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) { - struct saa7146_vv *vv = kzalloc (sizeof(struct saa7146_vv),GFP_KERNEL); - if( NULL == vv ) { + struct saa7146_vv *vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL); + + if (vv == NULL) { ERR(("out of memory. aborting.\n")); return -1; } + ext_vv->ops = saa7146_video_ioctl_ops; + ext_vv->core_ops = &saa7146_video_ioctl_ops; DEB_EE(("dev:%p\n",dev)); @@ -522,6 +511,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, { struct saa7146_vv *vv = dev->vv_data; struct video_device *vfd; + int err; DEB_EE(("dev:%p, name:'%s', type:%d\n",dev,name,type)); @@ -530,16 +520,18 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, if (vfd == NULL) return -ENOMEM; - memcpy(vfd, &device_template, sizeof(struct video_device)); - strlcpy(vfd->name, name, sizeof(vfd->name)); + vfd->fops = &video_fops; + vfd->ioctl_ops = dev->ext_vv_data ? &dev->ext_vv_data->ops : + &saa7146_video_ioctl_ops; vfd->release = video_device_release; + strlcpy(vfd->name, name, sizeof(vfd->name)); video_set_drvdata(vfd, dev); - // fixme: -1 should be an insmod parameter *for the extension* (like "video_nr"); - if (video_register_device(vfd, type, -1) < 0) { + err = video_register_device(vfd, type, -1); + if (err < 0) { ERR(("cannot register v4l2 device. skipping.\n")); video_device_release(vfd); - return -1; + return err; } if( VFL_TYPE_GRABBER == type ) { diff --git a/linux/drivers/media/common/saa7146_video.c b/linux/drivers/media/common/saa7146_video.c index 416a37f1b..a0cf6dacf 100644 --- a/linux/drivers/media/common/saa7146_video.c +++ b/linux/drivers/media/common/saa7146_video.c @@ -98,172 +98,13 @@ struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc) return NULL; } -static int g_fmt(struct saa7146_fh *fh, struct v4l2_format *f) -{ - struct saa7146_dev *dev = fh->dev; - DEB_EE(("dev:%p, fh:%p\n",dev,fh)); - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - f->fmt.pix = fh->video_fmt; - return 0; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - f->fmt.win = fh->ov.win; - return 0; - case V4L2_BUF_TYPE_VBI_CAPTURE: - { - f->fmt.vbi = fh->vbi_fmt; - return 0; - } - default: - DEB_D(("invalid format type '%d'.\n",f->type)); - return -EINVAL; - } -} - -static int try_win(struct saa7146_dev *dev, struct v4l2_window *win) -{ - struct saa7146_vv *vv = dev->vv_data; - enum v4l2_field field; - int maxw, maxh; - - DEB_EE(("dev:%p\n",dev)); - - if (NULL == vv->ov_fb.base) { - DEB_D(("no fb base set.\n")); - return -EINVAL; - } - if (NULL == vv->ov_fmt) { - DEB_D(("no fb fmt set.\n")); - return -EINVAL; - } - if (win->w.width < 48 || win->w.height < 32) { - DEB_D(("min width/height. (%d,%d)\n",win->w.width,win->w.height)); - return -EINVAL; - } - if (win->clipcount > 16) { - DEB_D(("clipcount too big.\n")); - return -EINVAL; - } - - field = win->field; - maxw = vv->standard->h_max_out; - maxh = vv->standard->v_max_out; - - if (V4L2_FIELD_ANY == field) { - field = (win->w.height > maxh/2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_TOP; - } - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - case V4L2_FIELD_ALTERNATE: - maxh = maxh / 2; - break; - case V4L2_FIELD_INTERLACED: - break; - default: { - DEB_D(("no known field mode '%d'.\n",field)); - return -EINVAL; - } - } - - win->field = field; - if (win->w.width > maxw) - win->w.width = maxw; - if (win->w.height > maxh) - win->w.height = maxh; - - return 0; -} - -static int try_fmt(struct saa7146_fh *fh, struct v4l2_format *f) -{ - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - int err; - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - { - struct saa7146_format *fmt; - enum v4l2_field field; - int maxw, maxh; - int calc_bpl; - - DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n",dev,fh)); - - fmt = format_by_fourcc(dev,f->fmt.pix.pixelformat); - if (NULL == fmt) { - return -EINVAL; - } - - field = f->fmt.pix.field; - maxw = vv->standard->h_max_out; - maxh = vv->standard->v_max_out; - - if (V4L2_FIELD_ANY == field) { - field = (f->fmt.pix.height > maxh/2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_BOTTOM; - } - switch (field) { - case V4L2_FIELD_ALTERNATE: { - vv->last_field = V4L2_FIELD_TOP; - maxh = maxh / 2; - break; - } - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - vv->last_field = V4L2_FIELD_INTERLACED; - maxh = maxh / 2; - break; - case V4L2_FIELD_INTERLACED: - vv->last_field = V4L2_FIELD_INTERLACED; - break; - default: { - DEB_D(("no known field mode '%d'.\n",field)); - return -EINVAL; - } - } - - f->fmt.pix.field = field; - if (f->fmt.pix.width > maxw) - f->fmt.pix.width = maxw; - if (f->fmt.pix.height > maxh) - f->fmt.pix.height = maxh; - - calc_bpl = (f->fmt.pix.width * fmt->depth)/8; - - if (f->fmt.pix.bytesperline < calc_bpl) - f->fmt.pix.bytesperline = calc_bpl; - - if (f->fmt.pix.bytesperline > (2*PAGE_SIZE * fmt->depth)/8) /* arbitrary constraint */ - f->fmt.pix.bytesperline = calc_bpl; - - f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; - DEB_D(("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n",f->fmt.pix.width,f->fmt.pix.height,f->fmt.pix.bytesperline,f->fmt.pix.sizeimage)); - - return 0; - } - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n",dev,fh)); - err = try_win(dev,&f->fmt.win); - if (0 != err) { - return err; - } - return 0; - default: - DEB_EE(("unknown format type '%d'\n",f->type)); - return -EINVAL; - } -} +static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f); int saa7146_start_preview(struct saa7146_fh *fh) { struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; + struct v4l2_format fmt; int ret = 0, err = 0; DEB_EE(("dev:%p, fh:%p\n",dev,fh)); @@ -295,12 +136,13 @@ int saa7146_start_preview(struct saa7146_fh *fh) return -EBUSY; } - err = try_win(dev,&fh->ov.win); + fmt.fmt.win = fh->ov.win; + err = vidioc_try_fmt_vid_overlay(NULL, fh, &fmt); if (0 != err) { saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); return -EBUSY; } - + fh->ov.win = fmt.fmt.win; vv->ov_data = &fh->ov; DEB_D(("%dx%d+%d+%d %s field=%s\n", @@ -356,58 +198,6 @@ int saa7146_stop_preview(struct saa7146_fh *fh) } EXPORT_SYMBOL_GPL(saa7146_stop_preview); -static int s_fmt(struct saa7146_fh *fh, struct v4l2_format *f) -{ - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - - int err; - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n",dev,fh)); - if (IS_CAPTURE_ACTIVE(fh) != 0) { - DEB_EE(("streaming capture is active\n")); - return -EBUSY; - } - err = try_fmt(fh,f); - if (0 != err) - return err; - fh->video_fmt = f->fmt.pix; - DEB_EE(("set to pixelformat '%4.4s'\n",(char *)&fh->video_fmt.pixelformat)); - return 0; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n",dev,fh)); - err = try_win(dev,&f->fmt.win); - if (0 != err) - return err; - mutex_lock(&dev->lock); - fh->ov.win = f->fmt.win; - fh->ov.nclips = f->fmt.win.clipcount; - if (fh->ov.nclips > 16) - fh->ov.nclips = 16; - if (copy_from_user(fh->ov.clips,f->fmt.win.clips,sizeof(struct v4l2_clip)*fh->ov.nclips)) { - mutex_unlock(&dev->lock); - return -EFAULT; - } - - /* fh->ov.fh is used to indicate that we have valid overlay informations, too */ - fh->ov.fh = fh; - - mutex_unlock(&dev->lock); - - /* check if our current overlay is active */ - if (IS_OVERLAY_ACTIVE(fh) != 0) { - saa7146_stop_preview(fh); - saa7146_start_preview(fh); - } - return 0; - default: - DEB_D(("unknown format type '%d'\n",f->type)); - return -EINVAL; - } -} - /********************************************************************************/ /* device controls */ @@ -464,131 +254,6 @@ static struct v4l2_queryctrl* ctrl_by_id(int id) return NULL; } -static int get_control(struct saa7146_fh *fh, struct v4l2_control *c) -{ - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - - const struct v4l2_queryctrl* ctrl; - u32 value = 0; - - ctrl = ctrl_by_id(c->id); - if (NULL == ctrl) - return -EINVAL; - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - value = saa7146_read(dev, BCS_CTRL); - c->value = 0xff & (value >> 24); - DEB_D(("V4L2_CID_BRIGHTNESS: %d\n",c->value)); - break; - case V4L2_CID_CONTRAST: - value = saa7146_read(dev, BCS_CTRL); - c->value = 0x7f & (value >> 16); - DEB_D(("V4L2_CID_CONTRAST: %d\n",c->value)); - break; - case V4L2_CID_SATURATION: - value = saa7146_read(dev, BCS_CTRL); - c->value = 0x7f & (value >> 0); - DEB_D(("V4L2_CID_SATURATION: %d\n",c->value)); - break; - case V4L2_CID_VFLIP: - c->value = vv->vflip; - DEB_D(("V4L2_CID_VFLIP: %d\n",c->value)); - break; - case V4L2_CID_HFLIP: - c->value = vv->hflip; - DEB_D(("V4L2_CID_HFLIP: %d\n",c->value)); - break; - default: - return -EINVAL; - } - - return 0; -} - -static int set_control(struct saa7146_fh *fh, struct v4l2_control *c) -{ - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - - const struct v4l2_queryctrl* ctrl; - - ctrl = ctrl_by_id(c->id); - if (NULL == ctrl) { - DEB_D(("unknown control %d\n",c->id)); - return -EINVAL; - } - - mutex_lock(&dev->lock); - - switch (ctrl->type) { - case V4L2_CTRL_TYPE_BOOLEAN: - case V4L2_CTRL_TYPE_MENU: - case V4L2_CTRL_TYPE_INTEGER: - if (c->value < ctrl->minimum) - c->value = ctrl->minimum; - if (c->value > ctrl->maximum) - c->value = ctrl->maximum; - break; - default: - /* nothing */; - }; - - switch (c->id) { - case V4L2_CID_BRIGHTNESS: { - u32 value = saa7146_read(dev, BCS_CTRL); - value &= 0x00ffffff; - value |= (c->value << 24); - saa7146_write(dev, BCS_CTRL, value); - saa7146_write(dev, MC2, MASK_22 | MASK_06 ); - break; - } - case V4L2_CID_CONTRAST: { - u32 value = saa7146_read(dev, BCS_CTRL); - value &= 0xff00ffff; - value |= (c->value << 16); - saa7146_write(dev, BCS_CTRL, value); - saa7146_write(dev, MC2, MASK_22 | MASK_06 ); - break; - } - case V4L2_CID_SATURATION: { - u32 value = saa7146_read(dev, BCS_CTRL); - value &= 0xffffff00; - value |= (c->value << 0); - saa7146_write(dev, BCS_CTRL, value); - saa7146_write(dev, MC2, MASK_22 | MASK_06 ); - break; - } - case V4L2_CID_HFLIP: - /* fixme: we can support changing VFLIP and HFLIP here... */ - if (IS_CAPTURE_ACTIVE(fh) != 0) { - DEB_D(("V4L2_CID_HFLIP while active capture.\n")); - mutex_unlock(&dev->lock); - return -EINVAL; - } - vv->hflip = c->value; - break; - case V4L2_CID_VFLIP: - if (IS_CAPTURE_ACTIVE(fh) != 0) { - DEB_D(("V4L2_CID_VFLIP while active capture.\n")); - mutex_unlock(&dev->lock); - return -EINVAL; - } - vv->vflip = c->value; - break; - default: { - return -EINVAL; - } - } - mutex_unlock(&dev->lock); - - if (IS_OVERLAY_ACTIVE(fh) != 0) { - saa7146_stop_preview(fh); - saa7146_start_preview(fh); - } - return 0; -} - /********************************************************************************/ /* common pagetable functions */ @@ -829,231 +494,451 @@ static int video_end(struct saa7146_fh *fh, struct file *file) 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 vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + + strcpy((char *)cap->driver, "saa7146 v4l2"); + strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card)); + sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci)); + cap->version = SAA7146_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VIDEO_OVERLAY | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + cap->capabilities |= dev->ext_vv_data->capabilities; + return 0; +} -long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg) +static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) { - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct saa7146_vv *vv = dev->vv_data; + + *fb = vv->ov_fb; + fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; + return 0; +} + +static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct saa7146_vv *vv = dev->vv_data; + struct saa7146_format *fmt; - long err = 0; - int result = 0, ee = 0; + DEB_EE(("VIDIOC_S_FBUF\n")); - struct saa7146_use_ops *ops; - struct videobuf_queue *q; + if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) + return -EPERM; - /* check if extension handles the command */ - for(ee = 0; dev->ext_vv_data->ioctls[ee].flags != 0; ee++) { - if( cmd == dev->ext_vv_data->ioctls[ee].cmd ) - break; + /* check args */ + fmt = format_by_fourcc(dev, fb->fmt.pixelformat); + if (NULL == fmt) + return -EINVAL; + + /* planar formats are not allowed for overlay video, clipping and video dma would clash */ + if (fmt->flags & FORMAT_IS_PLANAR) + DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n", + (char *)&fmt->pixelformat)); + + /* check if overlay is running */ + if (IS_OVERLAY_ACTIVE(fh) != 0) { + if (vv->video_fh != fh) { + DEB_D(("refusing to change framebuffer informations while overlay is active in another open.\n")); + return -EBUSY; + } } - if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_EXCLUSIVE) ) { - DEB_D(("extension handles ioctl exclusive.\n")); - result = dev->ext_vv_data->ioctl(fh, cmd, arg); - return result; + mutex_lock(&dev->lock); + + /* ok, accept it */ + vv->ov_fb = *fb; + vv->ov_fmt = fmt; + if (0 == vv->ov_fb.fmt.bytesperline) + vv->ov_fb.fmt.bytesperline = + vv->ov_fb.fmt.width * fmt->depth / 8; + + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + if (f->index >= NUM_FORMATS) + return -EINVAL; + strlcpy((char *)f->description, formats[f->index].name, + sizeof(f->description)); + f->pixelformat = formats[f->index].pixelformat; + return 0; +} + +static int vidioc_enum_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + return vidioc_enum_fmt_vid_cap(file, fh, f); +} + +static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c) +{ + const struct v4l2_queryctrl *ctrl; + + if ((c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) && + (c->id < V4L2_CID_PRIVATE_BASE || + c->id >= V4L2_CID_PRIVATE_LASTP1)) + return -EINVAL; + + ctrl = ctrl_by_id(c->id); + if (ctrl == NULL) + return -EINVAL; + + DEB_EE(("VIDIOC_QUERYCTRL: id:%d\n", c->id)); + *c = *ctrl; + return 0; +} + +static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct saa7146_vv *vv = dev->vv_data; + const struct v4l2_queryctrl *ctrl; + u32 value = 0; + + ctrl = ctrl_by_id(c->id); + if (NULL == ctrl) + return -EINVAL; + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + value = saa7146_read(dev, BCS_CTRL); + c->value = 0xff & (value >> 24); + DEB_D(("V4L2_CID_BRIGHTNESS: %d\n", c->value)); + break; + case V4L2_CID_CONTRAST: + value = saa7146_read(dev, BCS_CTRL); + c->value = 0x7f & (value >> 16); + DEB_D(("V4L2_CID_CONTRAST: %d\n", c->value)); + break; + case V4L2_CID_SATURATION: + value = saa7146_read(dev, BCS_CTRL); + c->value = 0x7f & (value >> 0); + DEB_D(("V4L2_CID_SATURATION: %d\n", c->value)); + break; + case V4L2_CID_VFLIP: + c->value = vv->vflip; + DEB_D(("V4L2_CID_VFLIP: %d\n", c->value)); + break; + case V4L2_CID_HFLIP: + c->value = vv->hflip; + DEB_D(("V4L2_CID_HFLIP: %d\n", c->value)); + break; + default: + return -EINVAL; } - if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_BEFORE) ) { - DEB_D(("extension handles ioctl before.\n")); - result = dev->ext_vv_data->ioctl(fh, cmd, arg); - if( -EAGAIN != result ) { - return result; - } + return 0; +} + +static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct saa7146_vv *vv = dev->vv_data; + const struct v4l2_queryctrl *ctrl; + + ctrl = ctrl_by_id(c->id); + if (NULL == ctrl) { + DEB_D(("unknown control %d\n", c->id)); + return -EINVAL; } - /* fixme: add handle "after" case (is it still needed?) */ + mutex_lock(&dev->lock); - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: { - ops = &saa7146_video_uops; - q = &fh->video_q; + switch (ctrl->type) { + case V4L2_CTRL_TYPE_BOOLEAN: + case V4L2_CTRL_TYPE_MENU: + case V4L2_CTRL_TYPE_INTEGER: + if (c->value < ctrl->minimum) + c->value = ctrl->minimum; + if (c->value > ctrl->maximum) + c->value = ctrl->maximum; break; + default: + /* nothing */; + } + + switch (c->id) { + case V4L2_CID_BRIGHTNESS: { + u32 value = saa7146_read(dev, BCS_CTRL); + value &= 0x00ffffff; + value |= (c->value << 24); + saa7146_write(dev, BCS_CTRL, value); + saa7146_write(dev, MC2, MASK_22 | MASK_06); + break; + } + case V4L2_CID_CONTRAST: { + u32 value = saa7146_read(dev, BCS_CTRL); + value &= 0xff00ffff; + value |= (c->value << 16); + saa7146_write(dev, BCS_CTRL, value); + saa7146_write(dev, MC2, MASK_22 | MASK_06); + break; + } + case V4L2_CID_SATURATION: { + u32 value = saa7146_read(dev, BCS_CTRL); + value &= 0xffffff00; + value |= (c->value << 0); + saa7146_write(dev, BCS_CTRL, value); + saa7146_write(dev, MC2, MASK_22 | MASK_06); + break; + } + case V4L2_CID_HFLIP: + /* fixme: we can support changing VFLIP and HFLIP here... */ + if (IS_CAPTURE_ACTIVE(fh) != 0) { + DEB_D(("V4L2_CID_HFLIP while active capture.\n")); + mutex_unlock(&dev->lock); + return -EINVAL; } - case V4L2_BUF_TYPE_VBI_CAPTURE: { - ops = &saa7146_vbi_uops; - q = &fh->vbi_q; + vv->hflip = c->value; break; + case V4L2_CID_VFLIP: + if (IS_CAPTURE_ACTIVE(fh) != 0) { + DEB_D(("V4L2_CID_VFLIP while active capture.\n")); + mutex_unlock(&dev->lock); + return -EINVAL; } + vv->vflip = c->value; + break; default: - BUG(); - return 0; + mutex_unlock(&dev->lock); + return -EINVAL; } + mutex_unlock(&dev->lock); - switch (cmd) { - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = arg; - memset(cap,0,sizeof(*cap)); - - DEB_EE(("VIDIOC_QUERYCAP\n")); - - strcpy((char *)cap->driver, "saa7146 v4l2"); - strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card)); - sprintf((char *)cap->bus_info,"PCI:%s", pci_name(dev->pci)); - cap->version = SAA7146_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VIDEO_OVERLAY | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - cap->capabilities |= dev->ext_vv_data->capabilities; - return 0; + if (IS_OVERLAY_ACTIVE(fh) != 0) { + saa7146_stop_preview(fh); + saa7146_start_preview(fh); } - case VIDIOC_G_FBUF: - { - struct v4l2_framebuffer *fb = arg; + return 0; +} - DEB_EE(("VIDIOC_G_FBUF\n")); +static int vidioc_g_parm(struct file *file, void *fh, + struct v4l2_streamparm *parm) +{ + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + parm->parm.capture.readbuffers = 1; + /* fixme: only for PAL! */ + parm->parm.capture.timeperframe.numerator = 1; + parm->parm.capture.timeperframe.denominator = 25; + return 0; +} - *fb = vv->ov_fb; - fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; - return 0; - } - case VIDIOC_S_FBUF: - { - struct v4l2_framebuffer *fb = arg; - struct saa7146_format *fmt; +static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + f->fmt.pix = ((struct saa7146_fh *)fh)->video_fmt; + return 0; +} - DEB_EE(("VIDIOC_S_FBUF\n")); +static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f) +{ + f->fmt.win = ((struct saa7146_fh *)fh)->ov.win; + return 0; +} - if(!capable(CAP_SYS_ADMIN) && - !capable(CAP_SYS_RAWIO)) - return -EPERM; +static int vidioc_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + f->fmt.vbi = ((struct saa7146_fh *)fh)->vbi_fmt; + return 0; +} - /* check args */ - fmt = format_by_fourcc(dev,fb->fmt.pixelformat); - if (NULL == fmt) { - return -EINVAL; - } +static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct saa7146_vv *vv = dev->vv_data; + struct saa7146_format *fmt; + enum v4l2_field field; + int maxw, maxh; + int calc_bpl; - /* planar formats are not allowed for overlay video, clipping and video dma would clash */ - if (0 != (fmt->flags & FORMAT_IS_PLANAR)) { - DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n",(char *)&fmt->pixelformat)); - } + DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh)); - /* check if overlay is running */ - if (IS_OVERLAY_ACTIVE(fh) != 0) { - if (vv->video_fh != fh) { - DEB_D(("refusing to change framebuffer informations while overlay is active in another open.\n")); - return -EBUSY; - } - } + fmt = format_by_fourcc(dev, f->fmt.pix.pixelformat); + if (NULL == fmt) + return -EINVAL; - mutex_lock(&dev->lock); + field = f->fmt.pix.field; + maxw = vv->standard->h_max_out; + maxh = vv->standard->v_max_out; - /* ok, accept it */ - vv->ov_fb = *fb; - vv->ov_fmt = fmt; - if (0 == vv->ov_fb.fmt.bytesperline) - vv->ov_fb.fmt.bytesperline = - vv->ov_fb.fmt.width*fmt->depth/8; + if (V4L2_FIELD_ANY == field) { + field = (f->fmt.pix.height > maxh / 2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; + } + switch (field) { + case V4L2_FIELD_ALTERNATE: + vv->last_field = V4L2_FIELD_TOP; + maxh = maxh / 2; + break; + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + vv->last_field = V4L2_FIELD_INTERLACED; + maxh = maxh / 2; + break; + case V4L2_FIELD_INTERLACED: + vv->last_field = V4L2_FIELD_INTERLACED; + break; + default: + DEB_D(("no known field mode '%d'.\n", field)); + return -EINVAL; + } - mutex_unlock(&dev->lock); + f->fmt.pix.field = field; + if (f->fmt.pix.width > maxw) + f->fmt.pix.width = maxw; + if (f->fmt.pix.height > maxh) + f->fmt.pix.height = maxh; - return 0; - } - case VIDIOC_ENUM_FMT: - { - struct v4l2_fmtdesc *f = arg; - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (f->index >= NUM_FORMATS) - return -EINVAL; - strlcpy((char *)f->description, formats[f->index].name, - sizeof(f->description)); - f->pixelformat = formats[f->index].pixelformat; - f->flags = 0; - memset(f->reserved, 0, sizeof(f->reserved)); - break; - default: - return -EINVAL; - } + calc_bpl = (f->fmt.pix.width * fmt->depth) / 8; - DEB_EE(("VIDIOC_ENUM_FMT: type:%d, index:%d\n",f->type,f->index)); - return 0; - } - case VIDIOC_QUERYCTRL: - { - const struct v4l2_queryctrl *ctrl; - struct v4l2_queryctrl *c = arg; + if (f->fmt.pix.bytesperline < calc_bpl) + f->fmt.pix.bytesperline = calc_bpl; - if ((c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) && - (c->id < V4L2_CID_PRIVATE_BASE || - c->id >= V4L2_CID_PRIVATE_LASTP1)) - return -EINVAL; + if (f->fmt.pix.bytesperline > (2 * PAGE_SIZE * fmt->depth) / 8) /* arbitrary constraint */ + f->fmt.pix.bytesperline = calc_bpl; - ctrl = ctrl_by_id(c->id); - if( NULL == ctrl ) { - return -EINVAL; -/* - c->flags = V4L2_CTRL_FLAG_DISABLED; - return 0; -*/ - } + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; + DEB_D(("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n", f->fmt.pix.width, + f->fmt.pix.height, f->fmt.pix.bytesperline, f->fmt.pix.sizeimage)); - DEB_EE(("VIDIOC_QUERYCTRL: id:%d\n",c->id)); - *c = *ctrl; - return 0; + return 0; +} + + +static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct saa7146_vv *vv = dev->vv_data; + struct v4l2_window *win = &f->fmt.win; + enum v4l2_field field; + int maxw, maxh; + + DEB_EE(("dev:%p\n", dev)); + + if (NULL == vv->ov_fb.base) { + DEB_D(("no fb base set.\n")); + return -EINVAL; } - case VIDIOC_G_CTRL: { - DEB_EE(("VIDIOC_G_CTRL\n")); - return get_control(fh,arg); + if (NULL == vv->ov_fmt) { + DEB_D(("no fb fmt set.\n")); + return -EINVAL; } - case VIDIOC_S_CTRL: - { - DEB_EE(("VIDIOC_S_CTRL\n")); - err = set_control(fh,arg); - return err; + if (win->w.width < 48 || win->w.height < 32) { + DEB_D(("min width/height. (%d,%d)\n", win->w.width, win->w.height)); + return -EINVAL; } - case VIDIOC_G_PARM: - { - struct v4l2_streamparm *parm = arg; - if( parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ) { - return -EINVAL; - } - memset(&parm->parm.capture,0,sizeof(struct v4l2_captureparm)); - parm->parm.capture.readbuffers = 1; - // fixme: only for PAL! - parm->parm.capture.timeperframe.numerator = 1; - parm->parm.capture.timeperframe.denominator = 25; - return 0; + if (win->clipcount > 16) { + DEB_D(("clipcount too big.\n")); + return -EINVAL; } - case VIDIOC_G_FMT: - { - struct v4l2_format *f = arg; - DEB_EE(("VIDIOC_G_FMT\n")); - return g_fmt(fh,f); + + field = win->field; + maxw = vv->standard->h_max_out; + maxh = vv->standard->v_max_out; + + if (V4L2_FIELD_ANY == field) { + field = (win->w.height > maxh / 2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_TOP; + } + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + case V4L2_FIELD_ALTERNATE: + maxh = maxh / 2; + break; + case V4L2_FIELD_INTERLACED: + break; + default: + DEB_D(("no known field mode '%d'.\n", field)); + return -EINVAL; } - case VIDIOC_S_FMT: - { - struct v4l2_format *f = arg; - DEB_EE(("VIDIOC_S_FMT\n")); - return s_fmt(fh,f); + + win->field = field; + if (win->w.width > maxw) + win->w.width = maxw; + if (win->w.height > maxh) + win->w.height = maxh; + + return 0; +} + +static int vidioc_s_fmt_vid_cap(struct file *file, void *__fh, struct v4l2_format *f) +{ + struct saa7146_fh *fh = __fh; + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + int err; + + DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh)); + if (IS_CAPTURE_ACTIVE(fh) != 0) { + DEB_EE(("streaming capture is active\n")); + return -EBUSY; } - case VIDIOC_TRY_FMT: - { - struct v4l2_format *f = arg; - DEB_EE(("VIDIOC_TRY_FMT\n")); - return try_fmt(fh,f); + err = vidioc_try_fmt_vid_cap(file, fh, f); + if (0 != err) + return err; + fh->video_fmt = f->fmt.pix; + DEB_EE(("set to pixelformat '%4.4s'\n", (char *)&fh->video_fmt.pixelformat)); + return 0; +} + +static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_format *f) +{ + struct saa7146_fh *fh = __fh; + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + int err; + + DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n", dev, fh)); + err = vidioc_try_fmt_vid_overlay(file, fh, f); + if (0 != err) + return err; + mutex_lock(&dev->lock); + fh->ov.win = f->fmt.win; + fh->ov.nclips = f->fmt.win.clipcount; + if (fh->ov.nclips > 16) + fh->ov.nclips = 16; + if (copy_from_user(fh->ov.clips, f->fmt.win.clips, + sizeof(struct v4l2_clip) * fh->ov.nclips)) { + mutex_unlock(&dev->lock); + return -EFAULT; } - case VIDIOC_G_STD: - { - v4l2_std_id *id = arg; - DEB_EE(("VIDIOC_G_STD\n")); - *id = vv->standard->id; - return 0; + + /* fh->ov.fh is used to indicate that we have valid overlay informations, too */ + fh->ov.fh = fh; + + mutex_unlock(&dev->lock); + + /* check if our current overlay is active */ + if (IS_OVERLAY_ACTIVE(fh) != 0) { + saa7146_stop_preview(fh); + saa7146_start_preview(fh); } + return 0; +} + +static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct saa7146_vv *vv = dev->vv_data; + + *norm = vv->standard->id; + return 0; +} + /* the saa7146 supfhrts (used in conjunction with the saa7111a for example) PAL / NTSC / SECAM. if your hardware does not (or does more) -- override this function in your extension */ +/* case VIDIOC_ENUMSTD: { struct v4l2_standard *e = arg; @@ -1066,162 +951,228 @@ long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg) } return -EINVAL; } - case VIDIOC_S_STD: - { - v4l2_std_id *id = arg; - int found = 0; - int i; - - DEB_EE(("VIDIOC_S_STD\n")); + */ - if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) { - DEB_D(("cannot change video standard while streaming capture is active\n")); - return -EBUSY; - } +static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct saa7146_vv *vv = dev->vv_data; + int found = 0; + int err, i; - if ((vv->video_status & STATUS_OVERLAY) != 0) { - vv->ov_suspend = vv->video_fh; - err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */ - if (0 != err) { - DEB_D(("suspending video failed. aborting\n")); - return err; - } - } + DEB_EE(("VIDIOC_S_STD\n")); - mutex_lock(&dev->lock); + if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) { + DEB_D(("cannot change video standard while streaming capture is active\n")); + return -EBUSY; + } - for(i = 0; i < dev->ext_vv_data->num_stds; i++) - if (*id & dev->ext_vv_data->stds[i].id) - break; - if (i != dev->ext_vv_data->num_stds) { - vv->standard = &dev->ext_vv_data->stds[i]; - if( NULL != dev->ext_vv_data->std_callback ) - dev->ext_vv_data->std_callback(dev, vv->standard); - found = 1; + if ((vv->video_status & STATUS_OVERLAY) != 0) { + vv->ov_suspend = vv->video_fh; + err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */ + if (0 != err) { + DEB_D(("suspending video failed. aborting\n")); + return err; } + } - mutex_unlock(&dev->lock); + mutex_lock(&dev->lock); - if (vv->ov_suspend != NULL) { - saa7146_start_preview(vv->ov_suspend); - vv->ov_suspend = NULL; - } + for (i = 0; i < dev->ext_vv_data->num_stds; i++) + if (*id & dev->ext_vv_data->stds[i].id) + break; + if (i != dev->ext_vv_data->num_stds) { + vv->standard = &dev->ext_vv_data->stds[i]; + if (NULL != dev->ext_vv_data->std_callback) + dev->ext_vv_data->std_callback(dev, vv->standard); + found = 1; + } - if( 0 == found ) { - DEB_EE(("VIDIOC_S_STD: standard not found.\n")); - return -EINVAL; - } + mutex_unlock(&dev->lock); - DEB_EE(("VIDIOC_S_STD: set to standard to '%s'\n",vv->standard->name)); - return 0; + if (vv->ov_suspend != NULL) { + saa7146_start_preview(vv->ov_suspend); + vv->ov_suspend = NULL; } - case VIDIOC_OVERLAY: - { - int on = *(int *)arg; - DEB_D(("VIDIOC_OVERLAY on:%d\n",on)); - if (on != 0) { - err = saa7146_start_preview(fh); - } else { - err = saa7146_stop_preview(fh); - } - return err; - } - case VIDIOC_REQBUFS: { - struct v4l2_requestbuffers *req = arg; - DEB_D(("VIDIOC_REQBUFS, type:%d\n",req->type)); - return videobuf_reqbufs(q,req); - } - case VIDIOC_QUERYBUF: { - struct v4l2_buffer *buf = arg; - DEB_D(("VIDIOC_QUERYBUF, type:%d, offset:%d\n",buf->type,buf->m.offset)); - return videobuf_querybuf(q,buf); - } - case VIDIOC_QBUF: { - struct v4l2_buffer *buf = arg; - int ret = 0; - ret = videobuf_qbuf(q,buf); - DEB_D(("VIDIOC_QBUF: ret:%d, index:%d\n",ret,buf->index)); - return ret; - } - case VIDIOC_DQBUF: { - struct v4l2_buffer *buf = arg; - int ret = 0; - ret = videobuf_dqbuf(q,buf,file->f_flags & O_NONBLOCK); - DEB_D(("VIDIOC_DQBUF: ret:%d, index:%d\n",ret,buf->index)); - return ret; + if (!found) { + DEB_EE(("VIDIOC_S_STD: standard not found.\n")); + return -EINVAL; } - case VIDIOC_STREAMON: { - int *type = arg; - DEB_D(("VIDIOC_STREAMON, type:%d\n",*type)); - err = video_begin(fh); - if( 0 != err) { - return err; - } - err = videobuf_streamon(q); - return err; - } - case VIDIOC_STREAMOFF: { - int *type = arg; + DEB_EE(("VIDIOC_S_STD: set to standard to '%s'\n", vv->standard->name)); + return 0; +} - DEB_D(("VIDIOC_STREAMOFF, type:%d\n",*type)); +static int vidioc_overlay(struct file *file, void *fh, unsigned int on) +{ + int err; - /* ugly: we need to copy some checks from video_end(), - because videobuf_streamoff() relies on the capture running. - check and fix this */ - if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) { - DEB_S(("not capturing.\n")); - return 0; - } + DEB_D(("VIDIOC_OVERLAY on:%d\n", on)); + if (on) + err = saa7146_start_preview(fh); + else + err = saa7146_stop_preview(fh); + return err; +} - if (vv->video_fh != fh) { - DEB_S(("capturing, but in another open.\n")); - return -EBUSY; - } +static int vidioc_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *b) +{ + struct saa7146_fh *fh = __fh; - err = videobuf_streamoff(q); - if (0 != err) { - DEB_D(("warning: videobuf_streamoff() failed.\n")); - video_end(fh, file); - } else { - err = video_end(fh, file); - } - return err; - } -#ifdef CONFIG_VIDEO_V4L1_COMPAT - case VIDIOCGMBUF: - { - struct video_mbuf *mbuf = arg; - int i; + if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return videobuf_reqbufs(&fh->video_q, b); + if (b->type == V4L2_BUF_TYPE_VBI_CAPTURE) + return videobuf_reqbufs(&fh->vbi_q, b); + return -EINVAL; +} + +static int vidioc_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf) +{ + struct saa7146_fh *fh = __fh; - /* fixme: number of capture buffers and sizes for v4l apps */ - int gbuffers = 2; - int gbufsize = 768*576*4; + if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return videobuf_querybuf(&fh->video_q, buf); + if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE) + return videobuf_querybuf(&fh->vbi_q, buf); + return -EINVAL; +} - DEB_D(("VIDIOCGMBUF \n")); +static int vidioc_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf) +{ + struct saa7146_fh *fh = __fh; - q = &fh->video_q; - err = videobuf_mmap_setup(q,gbuffers,gbufsize, - V4L2_MEMORY_MMAP); - if (err < 0) - return err; + if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return videobuf_qbuf(&fh->video_q, buf); + if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE) + return videobuf_qbuf(&fh->vbi_q, buf); + return -EINVAL; +} + +static int vidioc_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf) +{ + struct saa7146_fh *fh = __fh; + + if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return videobuf_dqbuf(&fh->video_q, buf, file->f_flags & O_NONBLOCK); + if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE) + return videobuf_dqbuf(&fh->vbi_q, buf, file->f_flags & O_NONBLOCK); + return -EINVAL; +} + +static int vidioc_streamon(struct file *file, void *__fh, enum v4l2_buf_type type) +{ + struct saa7146_fh *fh = __fh; + int err; + + DEB_D(("VIDIOC_STREAMON, type:%d\n", type)); + + err = video_begin(fh); + if (err) + return err; + if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return videobuf_streamon(&fh->video_q); + if (type == V4L2_BUF_TYPE_VBI_CAPTURE) + return videobuf_streamon(&fh->vbi_q); + return -EINVAL; +} + +static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type) +{ + struct saa7146_fh *fh = __fh; + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + int err; + + DEB_D(("VIDIOC_STREAMOFF, type:%d\n", type)); - gbuffers = err; - memset(mbuf,0,sizeof(*mbuf)); - mbuf->frames = gbuffers; - mbuf->size = gbuffers * gbufsize; - for (i = 0; i < gbuffers; i++) - mbuf->offsets[i] = i * gbufsize; + /* ugly: we need to copy some checks from video_end(), + because videobuf_streamoff() relies on the capture running. + check and fix this */ + if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) { + DEB_S(("not capturing.\n")); return 0; } -#endif - default: - return v4l_compat_translate_ioctl(file, cmd, arg, - saa7146_video_do_ioctl); + + if (vv->video_fh != fh) { + DEB_S(("capturing, but in another open.\n")); + return -EBUSY; } + + err = -EINVAL; + if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + err = videobuf_streamoff(&fh->video_q); + else if (type == V4L2_BUF_TYPE_VBI_CAPTURE) + err = videobuf_streamoff(&fh->vbi_q); + if (0 != err) { + DEB_D(("warning: videobuf_streamoff() failed.\n")); + video_end(fh, file); + } else { + err = video_end(fh, file); + } + return err; +} + +#ifdef CONFIG_VIDEO_V4L1_COMPAT +static int vidiocgmbuf(struct file *file, void *__fh, struct video_mbuf *mbuf) +{ + struct saa7146_fh *fh = __fh; + struct videobuf_queue *q = &fh->video_q; + int err, i; + + /* fixme: number of capture buffers and sizes for v4l apps */ + int gbuffers = 2; + int gbufsize = 768 * 576 * 4; + + DEB_D(("VIDIOCGMBUF \n")); + + q = &fh->video_q; + err = videobuf_mmap_setup(q, gbuffers, gbufsize, + V4L2_MEMORY_MMAP); + if (err < 0) + return err; + + gbuffers = err; + memset(mbuf, 0, sizeof(*mbuf)); + mbuf->frames = gbuffers; + mbuf->size = gbuffers * gbufsize; + for (i = 0; i < gbuffers; i++) + mbuf->offsets[i] = i * gbufsize; return 0; } +#endif + +const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay, + .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay, + .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay, + .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, + + .vidioc_overlay = vidioc_overlay, + .vidioc_g_fbuf = vidioc_g_fbuf, + .vidioc_s_fbuf = vidioc_s_fbuf, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_g_std = vidioc_g_std, + .vidioc_s_std = vidioc_s_std, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_g_parm = vidioc_g_parm, +#ifdef CONFIG_VIDEO_V4L1_COMPAT + .vidiocgmbuf = vidiocgmbuf, +#endif +}; /*********************************************************************************/ /* buffer handling functions */ diff --git a/linux/drivers/media/dvb/dvb-usb/af9015.c b/linux/drivers/media/dvb/dvb-usb/af9015.c index f0b57c739..b1f231781 100644 --- a/linux/drivers/media/dvb/dvb-usb/af9015.c +++ b/linux/drivers/media/dvb/dvb-usb/af9015.c @@ -697,7 +697,12 @@ static int af9015_read_config(struct usb_device *udev) /* IR remote controller */ req.addr = AF9015_EEPROM_IR_MODE; - ret = af9015_rw_udev(udev, &req); + /* first message will timeout often due to possible hw bug */ + for (i = 0; i < 4; i++) { + ret = af9015_rw_udev(udev, &req); + if (!ret) + break; + } if (ret) goto error; deb_info("%s: IR mode:%d\n", __func__, val); @@ -838,18 +843,19 @@ static int af9015_read_config(struct usb_device *udev) if (!dvb_usb_af9015_dual_mode) af9015_config.dual_mode = 0; - /* set buffer size according to USB port speed */ + /* Set adapter0 buffer size according to USB port speed, adapter1 buffer + size can be static because it is enabled only USB2.0 */ for (i = 0; i < af9015_properties_count; i++) { /* USB1.1 set smaller buffersize and disable 2nd adapter */ if (udev->speed == USB_SPEED_FULL) { - af9015_properties[i].adapter->stream.u.bulk.buffersize = - TS_USB11_MAX_PACKET_SIZE; + af9015_properties[i].adapter[0].stream.u.bulk.buffersize + = TS_USB11_MAX_PACKET_SIZE; /* disable 2nd adapter because we don't have PID-filters */ af9015_config.dual_mode = 0; } else { - af9015_properties[i].adapter->stream.u.bulk.buffersize = - TS_USB20_MAX_PACKET_SIZE; + af9015_properties[i].adapter[0].stream.u.bulk.buffersize + = TS_USB20_MAX_PACKET_SIZE; } } @@ -1215,6 +1221,7 @@ static struct usb_device_id af9015_usb_table[] = { {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)}, /* 15 */{USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)}, {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)}, + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2)}, {0}, }; MODULE_DEVICE_TABLE(usb, af9015_usb_table); @@ -1257,6 +1264,12 @@ static struct dvb_usb_device_properties af9015_properties[] = { .type = USB_BULK, .count = 6, .endpoint = 0x85, + .u = { + .bulk = { + .buffersize = + TS_USB20_MAX_PACKET_SIZE, + } + } }, } }, @@ -1356,6 +1369,12 @@ static struct dvb_usb_device_properties af9015_properties[] = { .type = USB_BULK, .count = 6, .endpoint = 0x85, + .u = { + .bulk = { + .buffersize = + TS_USB20_MAX_PACKET_SIZE, + } + } }, } }, @@ -1402,7 +1421,8 @@ static struct dvb_usb_device_properties af9015_properties[] = { { .name = "KWorld USB DVB-T TV Stick II " \ "(VS-DVB-T 395U)", - .cold_ids = {&af9015_usb_table[16], NULL}, + .cold_ids = {&af9015_usb_table[16], + &af9015_usb_table[17], NULL}, .warm_ids = {NULL}, }, } diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 0db0c06ee..4ab5ec9a0 100644 --- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -97,6 +97,7 @@ #define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 #define USB_PID_KWORLD_399U 0xe399 #define USB_PID_KWORLD_395U 0xe396 +#define USB_PID_KWORLD_395U_2 0xe39b #define USB_PID_KWORLD_PC160_2T 0xc160 #define USB_PID_KWORLD_VSTREAM_COLD 0x17de #define USB_PID_KWORLD_VSTREAM_WARM 0x17df diff --git a/linux/drivers/media/dvb/frontends/cx24116.c b/linux/drivers/media/dvb/frontends/cx24116.c index aba75dd2e..db1e1e4ea 100644 --- a/linux/drivers/media/dvb/frontends/cx24116.c +++ b/linux/drivers/media/dvb/frontends/cx24116.c @@ -15,6 +15,9 @@ September, 9th 2008 Fixed locking on high symbol rates (>30000). Implement MPEG initialization parameter. + January, 17th 2009 + Fill set_voltage with actually control voltage code. + Correct set tone to not affect voltage. 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 @@ -146,7 +149,7 @@ enum cmds { CMD_GETAGC = 0x19, CMD_LNBCONFIG = 0x20, CMD_LNBSEND = 0x21, /* Formerly CMD_SEND_DISEQC */ - CMD_SET_TONEPRE = 0x22, + CMD_LNBDCLEVEL = 0x22, CMD_SET_TONE = 0x23, CMD_UPDFWVERS = 0x35, CMD_TUNERSLEEP = 0x36, @@ -667,16 +670,6 @@ static int cx24116_load_firmware(struct dvb_frontend *fe, return 0; } -static int cx24116_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) -{ - /* The isl6421 module will override this function in the fops. */ - dprintk("%s() This should never appear if the isl6421 module " - "is loaded correctly\n", __func__); - - return -EOPNOTSUPP; -} - static int cx24116_read_status(struct dvb_frontend *fe, fe_status_t *status) { struct cx24116_state *state = fe->demodulator_priv; @@ -837,6 +830,34 @@ static int cx24116_wait_for_lnb(struct dvb_frontend *fe) return -ETIMEDOUT; /* -EBUSY ? */ } +static int cx24116_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + struct cx24116_cmd cmd; + int ret; + + dprintk("%s: %s\n", __func__, + voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : + voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); + + /* Wait for LNB ready */ + ret = cx24116_wait_for_lnb(fe); + if (ret != 0) + return ret; + + /* Wait for voltage/min repeat delay */ + msleep(100); + + cmd.args[0x00] = CMD_LNBDCLEVEL; + cmd.args[0x01] = (voltage == SEC_VOLTAGE_18 ? 0x01 : 0x00); + cmd.len = 0x02; + + /* Min delay time before DiSEqC send */ + msleep(15); + + return cx24116_cmd_execute(fe, &cmd); +} + static int cx24116_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) { @@ -857,14 +878,6 @@ static int cx24116_set_tone(struct dvb_frontend *fe, /* Min delay time after DiSEqC send */ msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */ - /* This is always done before the tone is set */ - cmd.args[0x00] = CMD_SET_TONEPRE; - cmd.args[0x01] = 0x00; - cmd.len = 0x02; - ret = cx24116_cmd_execute(fe, &cmd); - if (ret != 0) - return ret; - /* Now we set the tone */ cmd.args[0x00] = CMD_SET_TONE; cmd.args[0x01] = 0x00; diff --git a/linux/drivers/media/dvb/ttpci/av7110_v4l.c b/linux/drivers/media/dvb/ttpci/av7110_v4l.c index c5b9c7056..2210cff73 100644 --- a/linux/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/linux/drivers/media/dvb/ttpci/av7110_v4l.c @@ -316,253 +316,261 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh) return 0; } -static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) +static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t) { - struct saa7146_dev *dev = fh->dev; - struct av7110 *av7110 = (struct av7110*) dev->ext_priv; - dprintk(4, "saa7146_dev: %p\n", dev); + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + u16 stereo_det; + s8 stereo; - switch (cmd) { - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *t = arg; - u16 stereo_det; - s8 stereo; + dprintk(2, "VIDIOC_G_TUNER: %d\n", t->index); - dprintk(2, "VIDIOC_G_TUNER: %d\n", t->index); + if (!av7110->analog_tuner_flags || t->index != 0) + return -EINVAL; - if (!av7110->analog_tuner_flags || t->index != 0) - return -EINVAL; + memset(t, 0, sizeof(*t)); + strcpy((char *)t->name, "Television"); + + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; + t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */ + t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */ + /* FIXME: add the real signal strength here */ + t->signal = 0xffff; + t->afc = 0; + + /* FIXME: standard / stereo detection is still broken */ + msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det); + dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det); + msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det); + dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det); + stereo = (s8)(stereo_det >> 8); + if (stereo > 0x10) { + /* stereo */ + t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; + t->audmode = V4L2_TUNER_MODE_STEREO; + } else if (stereo < -0x10) { + /* bilingual */ + t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + t->audmode = V4L2_TUNER_MODE_LANG1; + } else /* mono */ + t->rxsubchans = V4L2_TUNER_SUB_MONO; - memset(t, 0, sizeof(*t)); - strcpy((char *)t->name, "Television"); - - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; - t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */ - t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */ - /* FIXME: add the real signal strength here */ - t->signal = 0xffff; - t->afc = 0; - - // FIXME: standard / stereo detection is still broken - msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det); - dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det); - msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det); - dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det); - stereo = (s8)(stereo_det >> 8); - if (stereo > 0x10) { - /* stereo */ - t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; - t->audmode = V4L2_TUNER_MODE_STEREO; - } - else if (stereo < -0x10) { - /* bilingual */ - t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - t->audmode = V4L2_TUNER_MODE_LANG1; - } - else /* mono */ - t->rxsubchans = V4L2_TUNER_SUB_MONO; + return 0; +} - return 0; - } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *t = arg; - u16 fm_matrix, src; - dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index); +static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + u16 fm_matrix, src; + dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index); - if (!av7110->analog_tuner_flags || av7110->current_input != 1) - return -EINVAL; + if (!av7110->analog_tuner_flags || av7110->current_input != 1) + return -EINVAL; - switch (t->audmode) { - case V4L2_TUNER_MODE_STEREO: - dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n"); - fm_matrix = 0x3001; // stereo - src = 0x0020; - break; - case V4L2_TUNER_MODE_LANG1_LANG2: - dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n"); - fm_matrix = 0x3000; // bilingual - src = 0x0020; - break; - case V4L2_TUNER_MODE_LANG1: - dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n"); - fm_matrix = 0x3000; // mono - src = 0x0000; - break; - case V4L2_TUNER_MODE_LANG2: - dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n"); - fm_matrix = 0x3000; // mono - src = 0x0010; - break; - default: /* case V4L2_TUNER_MODE_MONO: */ - dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n"); - fm_matrix = 0x3000; // mono - src = 0x0030; - break; - } - msp_writereg(av7110, MSP_WR_DSP, 0x000e, fm_matrix); - msp_writereg(av7110, MSP_WR_DSP, 0x0008, src); - msp_writereg(av7110, MSP_WR_DSP, 0x0009, src); - msp_writereg(av7110, MSP_WR_DSP, 0x000a, src); - return 0; + switch (t->audmode) { + case V4L2_TUNER_MODE_STEREO: + dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n"); + fm_matrix = 0x3001; /* stereo */ + src = 0x0020; + break; + case V4L2_TUNER_MODE_LANG1_LANG2: + dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n"); + fm_matrix = 0x3000; /* bilingual */ + src = 0x0020; + break; + case V4L2_TUNER_MODE_LANG1: + dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n"); + fm_matrix = 0x3000; /* mono */ + src = 0x0000; + break; + case V4L2_TUNER_MODE_LANG2: + dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n"); + fm_matrix = 0x3000; /* mono */ + src = 0x0010; + break; + default: /* case V4L2_TUNER_MODE_MONO: */ + dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n"); + fm_matrix = 0x3000; /* mono */ + src = 0x0030; + break; } - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *f = arg; + msp_writereg(av7110, MSP_WR_DSP, 0x000e, fm_matrix); + msp_writereg(av7110, MSP_WR_DSP, 0x0008, src); + msp_writereg(av7110, MSP_WR_DSP, 0x0009, src); + msp_writereg(av7110, MSP_WR_DSP, 0x000a, src); + return 0; +} - dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency); +static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - if (!av7110->analog_tuner_flags || av7110->current_input != 1) - return -EINVAL; + dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency); - memset(f, 0, sizeof(*f)); - f->type = V4L2_TUNER_ANALOG_TV; - f->frequency = av7110->current_freq; - return 0; - } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *f = arg; + if (!av7110->analog_tuner_flags || av7110->current_input != 1) + return -EINVAL; - dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x.\n", f->frequency); + memset(f, 0, sizeof(*f)); + f->type = V4L2_TUNER_ANALOG_TV; + f->frequency = av7110->current_freq; + return 0; +} - if (!av7110->analog_tuner_flags || av7110->current_input != 1) - return -EINVAL; +static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - if (V4L2_TUNER_ANALOG_TV != f->type) - return -EINVAL; + dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x.\n", f->frequency); - msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); // fast mute - msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0); + if (!av7110->analog_tuner_flags || av7110->current_input != 1) + return -EINVAL; - /* tune in desired frequency */ - if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { - ves1820_set_tv_freq(dev, f->frequency); - } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { - stv0297_set_tv_freq(dev, f->frequency); - } - av7110->current_freq = f->frequency; + if (V4L2_TUNER_ANALOG_TV != f->type) + return -EINVAL; - msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); // start stereo detection - msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x0000); - msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone - msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume - return 0; - } - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *i = arg; + msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); /* fast mute */ + msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0); - dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index); + /* tune in desired frequency */ + if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) + ves1820_set_tv_freq(dev, f->frequency); + else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) + stv0297_set_tv_freq(dev, f->frequency); + av7110->current_freq = f->frequency; - if (av7110->analog_tuner_flags) { - if (i->index < 0 || i->index >= 4) - return -EINVAL; - } else { - if (i->index != 0) - return -EINVAL; - } + msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); /* start stereo detection */ + msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x0000); + msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); /* loudspeaker + headphone */ + msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); /* SCART 1 volume */ + return 0; +} - memcpy(i, &inputs[i->index], sizeof(struct v4l2_input)); +static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - return 0; + dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index); + + if (av7110->analog_tuner_flags) { + if (i->index < 0 || i->index >= 4) + return -EINVAL; + } else { + if (i->index != 0) + return -EINVAL; } - case VIDIOC_G_INPUT: - { - int *input = (int *)arg; - *input = av7110->current_input; - dprintk(2, "VIDIOC_G_INPUT: %d\n", *input); + + memcpy(i, &inputs[i->index], sizeof(struct v4l2_input)); + + return 0; +} + +static int vidioc_g_input(struct file *file, void *fh, unsigned int *input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + *input = av7110->current_input; + dprintk(2, "VIDIOC_G_INPUT: %d\n", *input); + return 0; +} + +static int vidioc_s_input(struct file *file, void *fh, unsigned int input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_S_INPUT: %d\n", input); + + if (!av7110->analog_tuner_flags) return 0; - } - case VIDIOC_S_INPUT: - { - int input = *(int *)arg; - dprintk(2, "VIDIOC_S_INPUT: %d\n", input); + if (input < 0 || input >= 4) + return -EINVAL; - if (!av7110->analog_tuner_flags) - return 0; + av7110->current_input = input; + return av7110_dvb_c_switch(fh); +} - if (input < 0 || input >= 4) - return -EINVAL; +static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a) +{ + dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index); + if (a->index != 0) + return -EINVAL; + memcpy(a, &msp3400_v4l2_audio, sizeof(struct v4l2_audio)); + return 0; +} - av7110->current_input = input; - return av7110_dvb_c_switch(fh); - } - case VIDIOC_G_AUDIO: - { - struct v4l2_audio *a = arg; +static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a) +{ + dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index); + return 0; +} - dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index); - if (a->index != 0) - return -EINVAL; - memcpy(a, &msp3400_v4l2_audio, sizeof(struct v4l2_audio)); - break; - } - case VIDIOC_S_AUDIO: - { - struct v4l2_audio *a = arg; - dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index); - break; - } - case VIDIOC_G_SLICED_VBI_CAP: - { - struct v4l2_sliced_vbi_cap *cap = arg; - dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n"); - memset(cap, 0, sizeof *cap); - if (FW_VERSION(av7110->arm_app) >= 0x2623) { - cap->service_set = V4L2_SLICED_WSS_625; - cap->service_lines[0][23] = V4L2_SLICED_WSS_625; - } - break; - } - case VIDIOC_G_FMT: - { - struct v4l2_format *f = arg; - dprintk(2, "VIDIOC_G_FMT:\n"); - if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT || - FW_VERSION(av7110->arm_app) < 0x2623) - return -EAGAIN; /* handled by core driver */ - memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced); - if (av7110->wssMode) { - f->fmt.sliced.service_set = V4L2_SLICED_WSS_625; - f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; - f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data); - } - break; +static int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, + struct v4l2_sliced_vbi_cap *cap) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n"); + if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) + return -EINVAL; + if (FW_VERSION(av7110->arm_app) >= 0x2623) { + cap->service_set = V4L2_SLICED_WSS_625; + cap->service_lines[0][23] = V4L2_SLICED_WSS_625; } - case VIDIOC_S_FMT: - { - struct v4l2_format *f = arg; - dprintk(2, "VIDIOC_S_FMT\n"); - if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT || - FW_VERSION(av7110->arm_app) < 0x2623) - return -EAGAIN; /* handled by core driver */ - if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 && - f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) { - memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced); - /* WSS controlled by firmware */ - av7110->wssMode = 0; - av7110->wssData = 0; - return av7110_fw_cmd(av7110, COMTYPE_ENCODER, - SetWSSConfig, 1, 0); - } else { - memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced); - f->fmt.sliced.service_set = V4L2_SLICED_WSS_625; - f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; - f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data); - /* WSS controlled by userspace */ - av7110->wssMode = 1; - av7110->wssData = 0; - } - break; + return 0; +} + +static int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_G_FMT:\n"); + if (FW_VERSION(av7110->arm_app) < 0x2623) + return -EINVAL; + memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced); + if (av7110->wssMode) { + f->fmt.sliced.service_set = V4L2_SLICED_WSS_625; + f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; + f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data); } - default: - printk("no such ioctl\n"); - return -ENOIOCTLCMD; + return 0; +} + +static int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_S_FMT\n"); + if (FW_VERSION(av7110->arm_app) < 0x2623) + return -EINVAL; + if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 && + f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) { + memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced)); + /* WSS controlled by firmware */ + av7110->wssMode = 0; + av7110->wssData = 0; + return av7110_fw_cmd(av7110, COMTYPE_ENCODER, + SetWSSConfig, 1, 0); + } else { + memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced)); + f->fmt.sliced.service_set = V4L2_SLICED_WSS_625; + f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; + f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data); + /* WSS controlled by userspace */ + av7110->wssMode = 1; + av7110->wssData = 0; } return 0; } @@ -609,22 +617,6 @@ static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size * INITIALIZATION ****************************************************************************/ -static struct saa7146_extension_ioctls ioctls[] = { - { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_G_FREQUENCY, SAA7146_EXCLUSIVE }, - { VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE }, - { VIDIOC_G_TUNER, SAA7146_EXCLUSIVE }, - { VIDIOC_S_TUNER, SAA7146_EXCLUSIVE }, - { VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE }, - { VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE }, - { VIDIOC_G_SLICED_VBI_CAP, SAA7146_EXCLUSIVE }, - { VIDIOC_G_FMT, SAA7146_BEFORE }, - { VIDIOC_S_FMT, SAA7146_BEFORE }, - { 0, 0 } -}; - static u8 saa7113_init_regs[] = { 0x02, 0xd0, 0x03, 0x23, @@ -788,20 +780,34 @@ int av7110_init_analog_module(struct av7110 *av7110) int av7110_init_v4l(struct av7110 *av7110) { struct saa7146_dev* dev = av7110->dev; + struct saa7146_ext_vv *vv_data; int ret; /* special case DVB-C: these cards have an analog tuner plus need some special handling, so we have separate saa7146_ext_vv data for these... */ if (av7110->analog_tuner_flags) - ret = saa7146_vv_init(dev, &av7110_vv_data_c); + vv_data = &av7110_vv_data_c; else - ret = saa7146_vv_init(dev, &av7110_vv_data_st); + vv_data = &av7110_vv_data_st; + ret = saa7146_vv_init(dev, vv_data); if (ret) { ERR(("cannot init capture device. skipping.\n")); return -ENODEV; } + vv_data->ops.vidioc_enum_input = vidioc_enum_input; + vv_data->ops.vidioc_g_input = vidioc_g_input; + vv_data->ops.vidioc_s_input = vidioc_s_input; + vv_data->ops.vidioc_g_tuner = vidioc_g_tuner; + vv_data->ops.vidioc_s_tuner = vidioc_s_tuner; + vv_data->ops.vidioc_g_frequency = vidioc_g_frequency; + vv_data->ops.vidioc_s_frequency = vidioc_s_frequency; + vv_data->ops.vidioc_g_audio = vidioc_g_audio; + vv_data->ops.vidioc_s_audio = vidioc_s_audio; + vv_data->ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap; + vv_data->ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out; + vv_data->ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out; if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) { ERR(("cannot register capture device. skipping.\n")); @@ -900,9 +906,6 @@ static struct saa7146_ext_vv av7110_vv_data_st = { .num_stds = ARRAY_SIZE(standard), .std_callback = &std_callback, - .ioctls = &ioctls[0], - .ioctl = av7110_ioctl, - .vbi_fops.open = av7110_vbi_reset, .vbi_fops.release = av7110_vbi_reset, .vbi_fops.write = av7110_vbi_write, @@ -918,9 +921,6 @@ static struct saa7146_ext_vv av7110_vv_data_c = { .num_stds = ARRAY_SIZE(standard), .std_callback = &std_callback, - .ioctls = &ioctls[0], - .ioctl = av7110_ioctl, - .vbi_fops.open = av7110_vbi_reset, .vbi_fops.release = av7110_vbi_reset, .vbi_fops.write = av7110_vbi_write, diff --git a/linux/drivers/media/dvb/ttpci/budget-av.c b/linux/drivers/media/dvb/ttpci/budget-av.c index 4182121d7..855fe74b6 100644 --- a/linux/drivers/media/dvb/ttpci/budget-av.c +++ b/linux/drivers/media/dvb/ttpci/budget-av.c @@ -1404,6 +1404,41 @@ static int budget_av_detach(struct saa7146_dev *dev) return err; } +#define KNC1_INPUTS 2 +static struct v4l2_input knc1_inputs[KNC1_INPUTS] = { + {0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0}, + {1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0}, +}; + +static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) +{ + dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index); + if (i->index < 0 || i->index >= KNC1_INPUTS) + return -EINVAL; + memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input)); + return 0; +} + +static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct budget_av *budget_av = (struct budget_av *)dev->ext_priv; + + *i = budget_av->cur_input; + + dprintk(1, "VIDIOC_G_INPUT %d.\n", *i); + return 0; +} + +static int vidioc_s_input(struct file *file, void *fh, unsigned int input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct budget_av *budget_av = (struct budget_av *)dev->ext_priv; + + dprintk(1, "VIDIOC_S_INPUT %d.\n", input); + return saa7113_setinput(budget_av, input); +} + static struct saa7146_ext_vv vv_data; static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) @@ -1442,6 +1477,9 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio ERR(("cannot init vv subsystem.\n")); return err; } + vv_data.ops.vidioc_enum_input = vidioc_enum_input; + vv_data.ops.vidioc_g_input = vidioc_g_input; + vv_data.ops.vidioc_s_input = vidioc_s_input; if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) { /* fixme: proper cleanup here */ @@ -1480,54 +1518,6 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio return 0; } -#define KNC1_INPUTS 2 -static struct v4l2_input knc1_inputs[KNC1_INPUTS] = { - {0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0}, - {1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0}, -}; - -static struct saa7146_extension_ioctls ioctls[] = { - {VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE}, - {VIDIOC_G_INPUT, SAA7146_EXCLUSIVE}, - {VIDIOC_S_INPUT, SAA7146_EXCLUSIVE}, - {0, 0} -}; - -static long av_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) -{ - struct saa7146_dev *dev = fh->dev; - struct budget_av *budget_av = (struct budget_av *) dev->ext_priv; - - switch (cmd) { - case VIDIOC_ENUMINPUT:{ - struct v4l2_input *i = arg; - - dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index); - if (i->index < 0 || i->index >= KNC1_INPUTS) { - return -EINVAL; - } - memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input)); - return 0; - } - case VIDIOC_G_INPUT:{ - int *input = (int *) arg; - - *input = budget_av->cur_input; - - dprintk(1, "VIDIOC_G_INPUT %d.\n", *input); - return 0; - } - case VIDIOC_S_INPUT:{ - int input = *(int *) arg; - dprintk(1, "VIDIOC_S_INPUT %d.\n", input); - return saa7113_setinput(budget_av, input); - } - default: - return -ENOIOCTLCMD; - } - return 0; -} - static struct saa7146_standard standard[] = { {.name = "PAL",.id = V4L2_STD_PAL, .v_offset = 0x17,.v_field = 288, @@ -1546,8 +1536,6 @@ static struct saa7146_ext_vv vv_data = { .flags = 0, .stds = &standard[0], .num_stds = ARRAY_SIZE(standard), - .ioctls = &ioctls[0], - .ioctl = av_ioctl, }; static struct saa7146_extension budget_extension; diff --git a/linux/drivers/media/dvb/ttpci/budget.c b/linux/drivers/media/dvb/ttpci/budget.c index 1638e1d9f..83e9e7750 100644 --- a/linux/drivers/media/dvb/ttpci/budget.c +++ b/linux/drivers/media/dvb/ttpci/budget.c @@ -470,6 +470,7 @@ static void frontend_init(struct budget *budget) budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config, &budget->i2c_adap); if (budget->dvb_frontend) { budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params; + budget->dvb_frontend->tuner_priv = NULL; break; } break; diff --git a/linux/drivers/media/video/cx18/cx18-av-firmware.c b/linux/drivers/media/video/cx18/cx18-av-firmware.c index c64fd0a05..b374c74d3 100644 --- a/linux/drivers/media/video/cx18/cx18-av-firmware.c +++ b/linux/drivers/media/video/cx18/cx18-av-firmware.c @@ -36,7 +36,7 @@ int cx18_av_loadfw(struct cx18 *cx) int i; int retries1 = 0; - if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) { + if (request_firmware(&fw, FWFILE, &cx->pci_dev->dev) != 0) { CX18_ERR("unable to open firmware %s\n", FWFILE); return -EINVAL; } @@ -115,9 +115,9 @@ int cx18_av_loadfw(struct cx18 *cx) are generated) */ cx18_av_write4(cx, CXADEC_I2S_OUT_CTL, 0x000001A0); - /* set alt I2s master clock to /16 and enable alt divider i2s + /* set alt I2s master clock to /0x16 and enable alt divider i2s passthrough */ - cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5000B687); + cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5600B687); cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, 0x000000F6, 0x000000F6, 0x3F00FFFF); diff --git a/linux/drivers/media/video/cx18/cx18-cards.c b/linux/drivers/media/video/cx18/cx18-cards.c index 10cddba3e..53217cf45 100644 --- a/linux/drivers/media/video/cx18/cx18-cards.c +++ b/linux/drivers/media/video/cx18/cx18-cards.c @@ -349,13 +349,14 @@ static const struct cx18_card cx18_card_toshiba_qosmio_dvbt = { /* Leadtek WinFast PVR2100 */ static const struct cx18_card_pci_info cx18_pci_leadtek_pvr2100[] = { - { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6f27 }, + { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6f27 }, /* PVR2100 */ + { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6690 }, /* DVR3100 H */ { 0, 0, 0 } }; static const struct cx18_card cx18_card_leadtek_pvr2100 = { .type = CX18_CARD_LEADTEK_PVR2100, - .name = "Leadtek WinFast PVR2100", + .name = "Leadtek WinFast PVR2100/DVR3100 H", .comment = "Experimenters and photos needed for device to work well.\n" "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", .v4l2_capabilities = CX18_CAP_ENCODER, diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c index e447b4ce7..fe2324ef2 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.c +++ b/linux/drivers/media/video/cx18/cx18-driver.c @@ -159,7 +159,7 @@ MODULE_PARM_DESC(cardtype, "\t\t\t 4 = Yuan MPC718\n" "\t\t\t 5 = Conexant Raptor PAL/SECAM\n" "\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n" - "\t\t\t 7 = Leadtek WinFast PVR2100\n" + "\t\t\t 7 = Leadtek WinFast PVR2100/DVR3100 H\n" "\t\t\t 0 = Autodetect (default)\n" "\t\t\t-1 = Ignore this card\n\t\t"); MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); @@ -502,7 +502,7 @@ static void cx18_process_options(struct cx18 *cx) else if (cx->options.cardtype != 0) CX18_ERR("Unknown user specified type, trying to autodetect card\n"); if (cx->card == NULL) { - if (cx->dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) { + if (cx->pci_dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) { cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); CX18_INFO("Autodetected Hauppauge card\n"); } @@ -512,13 +512,13 @@ static void cx18_process_options(struct cx18 *cx) if (cx->card->pci_list == NULL) continue; for (j = 0; cx->card->pci_list[j].device; j++) { - if (cx->dev->device != + if (cx->pci_dev->device != cx->card->pci_list[j].device) continue; - if (cx->dev->subsystem_vendor != + if (cx->pci_dev->subsystem_vendor != cx->card->pci_list[j].subsystem_vendor) continue; - if (cx->dev->subsystem_device != + if (cx->pci_dev->subsystem_device != cx->card->pci_list[j].subsystem_device) continue; CX18_INFO("Autodetected %s card\n", cx->card->name); @@ -531,9 +531,10 @@ done: if (cx->card == NULL) { cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); CX18_ERR("Unknown card: vendor/device: [%04x:%04x]\n", - cx->dev->vendor, cx->dev->device); + cx->pci_dev->vendor, cx->pci_dev->device); CX18_ERR(" subsystem vendor/device: [%04x:%04x]\n", - cx->dev->subsystem_vendor, cx->dev->subsystem_device); + cx->pci_dev->subsystem_vendor, + cx->pci_dev->subsystem_device); CX18_ERR("Defaulting to %s card\n", cx->card->name); CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n"); CX18_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n"); @@ -553,7 +554,7 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) { int i; - cx->base_addr = pci_resource_start(cx->dev, 0); + cx->base_addr = pci_resource_start(cx->pci_dev, 0); mutex_init(&cx->serialize_lock); mutex_init(&cx->i2c_bus_lock[0]); @@ -592,7 +593,7 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) (cx->params.video_temporal_filter_mode << 1) | (cx->params.video_median_filter_type << 2); cx->params.port = CX2341X_PORT_MEMORY; - cx->params.capabilities = CX2341X_CAP_HAS_TS; + cx->params.capabilities = CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_AC3; init_waitqueue_head(&cx->cap_w); init_waitqueue_head(&cx->mb_apu_waitq); init_waitqueue_head(&cx->mb_cpu_waitq); @@ -681,7 +682,7 @@ static void __devinit cx18_init_struct2(struct cx18 *cx) cx->av_state.vbi_line_offset = 8; } -static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *dev, +static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { u16 cmd; @@ -689,11 +690,11 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *dev, CX18_DEBUG_INFO("Enabling pci device\n"); - if (pci_enable_device(dev)) { + if (pci_enable_device(pci_dev)) { CX18_ERR("Can't enable device %d!\n", cx->num); return -EIO; } - if (pci_set_dma_mask(dev, 0xffffffff)) { + if (pci_set_dma_mask(pci_dev, 0xffffffff)) { CX18_ERR("No suitable DMA available on card %d.\n", cx->num); return -EIO; } @@ -703,25 +704,25 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *dev, } /* Enable bus mastering and memory mapped IO for the CX23418 */ - pci_read_config_word(dev, PCI_COMMAND, &cmd); + pci_read_config_word(pci_dev, PCI_COMMAND, &cmd); cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; - pci_write_config_word(dev, PCI_COMMAND, cmd); + pci_write_config_word(pci_dev, PCI_COMMAND, cmd); - pci_read_config_byte(dev, PCI_CLASS_REVISION, &cx->card_rev); - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency); + pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &cx->card_rev); + pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency < 64 && cx18_pci_latency) { CX18_INFO("Unreasonably low latency timer, " "setting to 64 (was %d)\n", pci_latency); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency); + pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, 64); + pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency); } CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, " "irq: %d, latency: %d, memory: 0x%lx\n", - cx->dev->device, cx->card_rev, dev->bus->number, - PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), - cx->dev->irq, pci_latency, (unsigned long)cx->base_addr); + cx->pci_dev->device, cx->card_rev, pci_dev->bus->number, + PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn), + cx->pci_dev->irq, pci_latency, (unsigned long)cx->base_addr); return 0; } @@ -732,7 +733,7 @@ static u32 cx18_request_module(struct cx18 *cx, u32 hw, { if ((hw & id) == 0) return hw; - if (request_module(name) != 0) { + if (request_module("%s", name) != 0) { CX18_ERR("Failed to load module %s\n", name); return hw & ~id; } @@ -776,7 +777,7 @@ static void cx18_load_and_init_modules(struct cx18 *cx) hw = cx->hw_flags; } -static int __devinit cx18_probe(struct pci_dev *dev, +static int __devinit cx18_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { int retval = 0; @@ -801,33 +802,37 @@ static int __devinit cx18_probe(struct pci_dev *dev, return -ENOMEM; } cx18_cards[cx18_cards_active] = cx; - cx->dev = dev; cx->num = cx18_cards_active++; snprintf(cx->name, sizeof(cx->name), "cx18-%d", cx->num); CX18_INFO("Initializing card #%d\n", cx->num); spin_unlock(&cx18_cards_lock); + cx->pci_dev = pci_dev; + retval = v4l2_device_register(&pci_dev->dev, &cx->v4l2_dev); + if (retval) { + CX18_ERR("Call to v4l2_device_register() failed\n"); + goto err; + } + CX18_DEBUG_INFO("registered v4l2_device name: %s\n", cx->v4l2_dev.name); + cx18_process_options(cx); if (cx->options.cardtype == -1) { retval = -ENODEV; - goto err; + goto unregister_v4l2; } if (cx18_init_struct1(cx)) { retval = -ENOMEM; - goto err; + goto unregister_v4l2; } CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr); /* PCI Device Setup */ - retval = cx18_setup_pci(cx, dev, pci_id); + retval = cx18_setup_pci(cx, pci_dev, pci_id); if (retval != 0) goto free_workqueue; - /* save cx in the pci struct for later use */ - pci_set_drvdata(dev, cx); - /* map io memory */ CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE); @@ -886,7 +891,7 @@ static int __devinit cx18_probe(struct pci_dev *dev, cx18_init_scb(cx); /* Register IRQ */ - retval = request_irq(cx->dev->irq, cx18_irq_handler, + retval = request_irq(cx->pci_dev->irq, cx18_irq_handler, IRQF_SHARED | IRQF_DISABLED, cx->name, (void *)cx); if (retval) { CX18_ERR("Failed to register irq %d\n", retval); @@ -997,7 +1002,7 @@ static int __devinit cx18_probe(struct pci_dev *dev, free_streams: cx18_streams_cleanup(cx, 1); free_irq: - free_irq(cx->dev->irq, (void *)cx); + free_irq(cx->pci_dev->irq, (void *)cx); free_i2c: exit_cx18_i2c(cx); free_map: @@ -1006,6 +1011,8 @@ free_mem: release_mem_region(cx->base_addr, CX18_MEM_SIZE); free_workqueue: destroy_workqueue(cx->work_queue); +unregister_v4l2: + v4l2_device_unregister(&cx->v4l2_dev); err: if (retval == 0) retval = -ENODEV; @@ -1048,8 +1055,21 @@ int cx18_init_on_first_open(struct cx18 *cx) } set_bit(CX18_F_I_LOADED_FW, &cx->i_flags); - /* Init the firmware twice to work around a silicon bug - * transport related. */ + /* + * Init the firmware twice to work around a silicon bug + * with the digital TS. + * + * The second firmware load requires us to normalize the APU state, + * or the audio for the first analog capture will be badly incorrect. + * + * I can't seem to call APU_RESETAI and have it succeed without the + * APU capturing audio, so we start and stop it here to do the reset + */ + + /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */ + cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0); + cx18_vapi(cx, CX18_APU_RESETAI, 0); + cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG); fw_retry_count = 3; while (--fw_retry_count > 0) { @@ -1099,7 +1119,8 @@ static void cx18_cancel_epu_work_orders(struct cx18 *cx) #endif static void cx18_remove(struct pci_dev *pci_dev) { - struct cx18 *cx = pci_get_drvdata(pci_dev); + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct cx18 *cx = container_of(v4l2_dev, struct cx18, v4l2_dev); CX18_DEBUG_INFO("Removing Card #%d\n", cx->num); @@ -1131,13 +1152,15 @@ static void cx18_remove(struct pci_dev *pci_dev) exit_cx18_i2c(cx); - free_irq(cx->dev->irq, (void *)cx); + free_irq(cx->pci_dev->irq, (void *)cx); cx18_iounmap(cx); release_mem_region(cx->base_addr, CX18_MEM_SIZE); - pci_disable_device(cx->dev); + pci_disable_device(cx->pci_dev); + + v4l2_device_unregister(v4l2_dev); CX18_INFO("Removed %s, card #%d\n", cx->card_name, cx->num); } diff --git a/linux/drivers/media/video/cx18/cx18-driver.h b/linux/drivers/media/video/cx18/cx18-driver.h index 0d2edebc3..3a21013cd 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.h +++ b/linux/drivers/media/video/cx18/cx18-driver.h @@ -48,6 +48,7 @@ #include <linux/dvb/audio.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-device.h> #include <media/tuner.h> #include "cx18-mailbox.h" #include "cx18-av-core.h" @@ -79,7 +80,7 @@ #define CX18_CARD_YUAN_MPC718 3 /* Yuan MPC718 */ #define CX18_CARD_CNXT_RAPTOR_PAL 4 /* Conexant Raptor PAL */ #define CX18_CARD_TOSHIBA_QOSMIO_DVBT 5 /* Toshiba Qosmio Interal DVB-T/Analog*/ -#define CX18_CARD_LEADTEK_PVR2100 6 /* Leadtek WinFast PVR2100 */ +#define CX18_CARD_LEADTEK_PVR2100 6 /* Leadtek WinFast PVR2100/DVR3100 H */ #define CX18_CARD_LAST 6 #define CX18_ENC_STREAM_TYPE_MPG 0 @@ -279,7 +280,7 @@ struct cx18_epu_work_order { struct cx18_stream { /* These first four fields are always set, even if the stream is not actually created. */ - struct video_device *v4l2dev; /* NULL when stream not created */ + struct video_device *video_dev; /* NULL when stream not created */ struct cx18 *cx; /* for ease of use */ const char *name; /* name of the stream */ int type; /* stream type */ @@ -385,7 +386,9 @@ struct cx18_i2c_algo_callback_data { struct cx18 { int num; /* board number, -1 during init! */ char name[8]; /* board name for printk and interrupts (e.g. 'cx180') */ - struct pci_dev *dev; /* PCI device */ + struct pci_dev *pci_dev; + struct v4l2_device v4l2_dev; + const struct cx18_card *card; /* card information */ const char *card_name; /* full name of the card */ const struct cx18_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */ @@ -413,7 +416,7 @@ struct cx18 { /* dualwatch */ unsigned long dualwatch_jiffies; - u16 dualwatch_stereo_mode; + u32 dualwatch_stereo_mode; /* Digitizer type */ int digitizer; /* 0x00EF = saa7114 0x00FO = saa7115 0x0106 = mic */ diff --git a/linux/drivers/media/video/cx18/cx18-dvb.c b/linux/drivers/media/video/cx18/cx18-dvb.c index bd5e6f3fd..3b86f57cd 100644 --- a/linux/drivers/media/video/cx18/cx18-dvb.c +++ b/linux/drivers/media/video/cx18/cx18-dvb.c @@ -167,7 +167,7 @@ int cx18_dvb_register(struct cx18_stream *stream) ret = dvb_register_adapter(&dvb->dvb_adapter, CX18_DRIVER_NAME, - THIS_MODULE, &cx->dev->dev, adapter_nr); + THIS_MODULE, &cx->pci_dev->dev, adapter_nr); if (ret < 0) goto err_out; diff --git a/linux/drivers/media/video/cx18/cx18-fileops.c b/linux/drivers/media/video/cx18/cx18-fileops.c index 0aaea0e7f..36c380b66 100644 --- a/linux/drivers/media/video/cx18/cx18-fileops.c +++ b/linux/drivers/media/video/cx18/cx18-fileops.c @@ -128,10 +128,10 @@ static void cx18_release_stream(struct cx18_stream *s) static void cx18_dualwatch(struct cx18 *cx) { struct v4l2_tuner vt; - u16 new_bitmap; - u16 new_stereo_mode; - const u16 stereo_mask = 0x0300; - const u16 dual = 0x0200; + u32 new_bitmap; + u32 new_stereo_mode; + const u32 stereo_mask = 0x0300; + const u32 dual = 0x0200; u32 h; new_stereo_mode = cx->params.audio_properties & stereo_mask; @@ -703,7 +703,7 @@ int cx18_v4l2_open(struct file *filp) if (cx18_cards[x] == NULL) continue; s = &cx18_cards[x]->streams[y]; - if (s->v4l2dev && s->v4l2dev->minor == minor) { + if (s->video_dev && s->video_dev->minor == minor) { cx = cx18_cards[x]; break; } diff --git a/linux/drivers/media/video/cx18/cx18-firmware.c b/linux/drivers/media/video/cx18/cx18-firmware.c index 1fa95da15..aa89bee65 100644 --- a/linux/drivers/media/video/cx18/cx18-firmware.c +++ b/linux/drivers/media/video/cx18/cx18-firmware.c @@ -107,7 +107,7 @@ static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx) u32 __iomem *dst = (u32 __iomem *)mem; const u32 *src; - if (request_firmware(&fw, fn, &cx->dev->dev)) { + if (request_firmware(&fw, fn, &cx->pci_dev->dev)) { CX18_ERR("Unable to open firmware %s\n", fn); CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n"); return -ENOMEM; @@ -151,7 +151,7 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, u32 apu_version = 0; int sz; - if (request_firmware(&fw, fn, &cx->dev->dev)) { + if (request_firmware(&fw, fn, &cx->pci_dev->dev)) { CX18_ERR("unable to open firmware %s\n", fn); CX18_ERR("did you put the firmware in the hotplug firmware directory?\n"); cx18_setup_page(cx, 0); diff --git a/linux/drivers/media/video/cx18/cx18-i2c.c b/linux/drivers/media/video/cx18/cx18-i2c.c index efae2301a..fe6fa60a7 100644 --- a/linux/drivers/media/video/cx18/cx18-i2c.c +++ b/linux/drivers/media/video/cx18/cx18-i2c.c @@ -393,7 +393,7 @@ int init_cx18_i2c(struct cx18 *cx) strlen(cx->i2c_client[i].name), "%d", i); cx->i2c_client[i].adapter = &cx->i2c_adap[i]; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) - cx->i2c_adap[i].dev.parent = &cx->dev->dev; + cx->i2c_adap[i].dev.parent = &cx->pci_dev->dev; #endif } diff --git a/linux/drivers/media/video/cx18/cx18-ioctl.c b/linux/drivers/media/video/cx18/cx18-ioctl.c index 84d6381aa..4a49b0819 100644 --- a/linux/drivers/media/video/cx18/cx18-ioctl.c +++ b/linux/drivers/media/video/cx18/cx18-ioctl.c @@ -407,7 +407,8 @@ static int cx18_querycap(struct file *file, void *fh, strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver)); strlcpy(vcap->card, cx->card_name, sizeof(vcap->card)); - snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(cx->dev)); + snprintf(vcap->bus_info, sizeof(vcap->bus_info), + "PCI:%s", pci_name(cx->pci_dev)); vcap->version = CX18_DRIVER_VERSION; /* version */ vcap->capabilities = cx->v4l2_cap; /* capabilities */ return 0; @@ -813,7 +814,9 @@ static int cx18_log_status(struct file *file, void *fh) struct v4l2_audio audin; int i; - CX18_INFO("================= START STATUS CARD #%d =================\n", cx->num); + CX18_INFO("================= START STATUS CARD #%d " + "=================\n", cx->num); + CX18_INFO("Version: %s Card: %s\n", CX18_VERSION, cx->card_name); if (cx->hw_flags & CX18_HW_TVEEPROM) { struct tveeprom tv; @@ -835,7 +838,7 @@ static int cx18_log_status(struct file *file, void *fh) for (i = 0; i < CX18_MAX_STREAMS; i++) { struct cx18_stream *s = &cx->streams[i]; - if (s->v4l2dev == NULL || s->buffers == 0) + if (s->video_dev == NULL || s->buffers == 0) continue; CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags, diff --git a/linux/drivers/media/video/cx18/cx18-mailbox.c b/linux/drivers/media/video/cx18/cx18-mailbox.c index 89a45f51f..66964722f 100644 --- a/linux/drivers/media/video/cx18/cx18-mailbox.c +++ b/linux/drivers/media/video/cx18/cx18-mailbox.c @@ -83,6 +83,8 @@ static const struct cx18_api_info api_info[] = { API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0), API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST), API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW), + API_ENTRY(APU, CX18_APU_START, 0), + API_ENTRY(APU, CX18_APU_STOP, 0), API_ENTRY(APU, CX18_APU_RESETAI, 0), API_ENTRY(CPU, CX18_CPU_DEBUG_PEEK32, 0), API_ENTRY(0, 0, 0), @@ -98,21 +100,30 @@ static const struct cx18_api_info *find_api_info(u32 cmd) return NULL; } -static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name) +/* Call with buf of n*11+1 bytes */ +static char *u32arr2hex(u32 data[], int n, char *buf) { - char argstr[MAX_MB_ARGUMENTS*11+1]; char *p; int i; + for (i = 0, p = buf; i < n; i++, p += 11) { + /* kernel snprintf() appends '\0' always */ + snprintf(p, 12, " %#010x", data[i]); + } + *p = '\0'; + return buf; +} + +static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name) +{ + char argstr[MAX_MB_ARGUMENTS*11+1]; + if (!(cx18_debug & CX18_DBGFLG_API)) return; - for (i = 0, p = argstr; i < MAX_MB_ARGUMENTS; i++, p += 11) { - /* kernel snprintf() appends '\0' always */ - snprintf(p, 12, " %#010x", mb->args[i]); - } CX18_DEBUG_API("%s: req %#010x ack %#010x cmd %#010x err %#010x args%s" - "\n", name, mb->request, mb->ack, mb->cmd, mb->error, argstr); + "\n", name, mb->request, mb->ack, mb->cmd, mb->error, + u32arr2hex(mb->args, MAX_MB_ARGUMENTS, argstr)); } @@ -445,7 +456,8 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu) "incoming %s to EPU mailbox (sequence no. %u)" "\n", rpu_str[rpu], rpu_str[rpu], order_mb->request); - dump_mb(cx, order_mb, "incoming"); + if (cx18_debug & CX18_DBGFLG_WARN) + dump_mb(cx, order_mb, "incoming"); order->flags = CX18_F_EWO_MB_STALE_UPON_RECEIPT; } @@ -474,16 +486,24 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) struct mutex *mb_lock; long int timeout, ret; int i; + char argstr[MAX_MB_ARGUMENTS*11+1]; if (info == NULL) { CX18_WARN("unknown cmd %x\n", cmd); return -EINVAL; } - if (cmd == CX18_CPU_DE_SET_MDL) - CX18_DEBUG_HI_API("%s\n", info->name); - else - CX18_DEBUG_API("%s\n", info->name); + if (cx18_debug & CX18_DBGFLG_API) { /* only call u32arr2hex if needed */ + if (cmd == CX18_CPU_DE_SET_MDL) { + if (cx18_debug & CX18_DBGFLG_HIGHVOL) + CX18_DEBUG_HI_API("%s\tcmd %#010x args%s\n", + info->name, cmd, + u32arr2hex(data, args, argstr)); + } else + CX18_DEBUG_API("%s\tcmd %#010x args%s\n", + info->name, cmd, + u32arr2hex(data, args, argstr)); + } switch (info->rpu) { case APU: diff --git a/linux/drivers/media/video/cx18/cx18-queue.c b/linux/drivers/media/video/cx18/cx18-queue.c index 8d9441e88..3046b8e74 100644 --- a/linux/drivers/media/video/cx18/cx18-queue.c +++ b/linux/drivers/media/video/cx18/cx18-queue.c @@ -204,7 +204,7 @@ int cx18_stream_alloc(struct cx18_stream *s) } buf->id = cx->buffer_id++; INIT_LIST_HEAD(&buf->list); - buf->dma_handle = pci_map_single(s->cx->dev, + buf->dma_handle = pci_map_single(s->cx->pci_dev, buf->buf, s->buf_size, s->dma); cx18_buf_sync_for_cpu(s, buf); cx18_enqueue(s, buf, &s->q_free); @@ -227,7 +227,7 @@ void cx18_stream_free(struct cx18_stream *s) /* empty q_free */ while ((buf = cx18_dequeue(s, &s->q_free))) { - pci_unmap_single(s->cx->dev, buf->dma_handle, + pci_unmap_single(s->cx->pci_dev, buf->dma_handle, s->buf_size, s->dma); kfree(buf->buf); kfree(buf); diff --git a/linux/drivers/media/video/cx18/cx18-queue.h b/linux/drivers/media/video/cx18/cx18-queue.h index 456cec3bc..4de06269d 100644 --- a/linux/drivers/media/video/cx18/cx18-queue.h +++ b/linux/drivers/media/video/cx18/cx18-queue.h @@ -29,14 +29,14 @@ static inline void cx18_buf_sync_for_cpu(struct cx18_stream *s, struct cx18_buffer *buf) { - pci_dma_sync_single_for_cpu(s->cx->dev, buf->dma_handle, + pci_dma_sync_single_for_cpu(s->cx->pci_dev, buf->dma_handle, s->buf_size, s->dma); } static inline void cx18_buf_sync_for_device(struct cx18_stream *s, struct cx18_buffer *buf) { - pci_dma_sync_single_for_device(s->cx->dev, buf->dma_handle, + pci_dma_sync_single_for_device(s->cx->pci_dev, buf->dma_handle, s->buf_size, s->dma); } diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c index 5eb99ea7b..88b101401 100644 --- a/linux/drivers/media/video/cx18/cx18-streams.c +++ b/linux/drivers/media/video/cx18/cx18-streams.c @@ -101,11 +101,11 @@ static struct { static void cx18_stream_init(struct cx18 *cx, int type) { struct cx18_stream *s = &cx->streams[type]; - struct video_device *dev = s->v4l2dev; + struct video_device *video_dev = s->video_dev; - /* we need to keep v4l2dev, so restore it afterwards */ + /* we need to keep video_dev, so restore it afterwards */ memset(s, 0, sizeof(*s)); - s->v4l2dev = dev; + s->video_dev = video_dev; /* initialize cx18_stream fields */ s->cx = cx; @@ -132,10 +132,10 @@ static int cx18_prep_dev(struct cx18 *cx, int type) int num_offset = cx18_stream_info[type].num_offset; int num = cx->num + cx18_first_minor + num_offset; - /* These four fields are always initialized. If v4l2dev == NULL, then + /* These four fields are always initialized. If video_dev == NULL, then this stream is not in use. In that case no other fields but these four can be used. */ - s->v4l2dev = NULL; + s->video_dev = NULL; s->cx = cx; s->type = type; s->name = cx18_stream_info[type].name; @@ -163,22 +163,22 @@ static int cx18_prep_dev(struct cx18 *cx, int type) return 0; /* allocate and initialize the v4l2 video device structure */ - s->v4l2dev = video_device_alloc(); - if (s->v4l2dev == NULL) { + s->video_dev = video_device_alloc(); + if (s->video_dev == NULL) { CX18_ERR("Couldn't allocate v4l2 video_device for %s\n", s->name); return -ENOMEM; } - snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18-%d", + snprintf(s->video_dev->name, sizeof(s->video_dev->name), "cx18-%d", cx->num); - s->v4l2dev->num = num; - s->v4l2dev->parent = &cx->dev->dev; - s->v4l2dev->fops = &cx18_v4l2_enc_fops; - s->v4l2dev->release = video_device_release; - s->v4l2dev->tvnorms = V4L2_STD_ALL; - cx18_set_funcs(s->v4l2dev); + s->video_dev->num = num; + s->video_dev->parent = &cx->pci_dev->dev; + s->video_dev->fops = &cx18_v4l2_enc_fops; + s->video_dev->release = video_device_release; + s->video_dev->tvnorms = V4L2_STD_ALL; + cx18_set_funcs(s->video_dev); return 0; } @@ -227,28 +227,29 @@ static int cx18_reg_dev(struct cx18 *cx, int type) } } - if (s->v4l2dev == NULL) + if (s->video_dev == NULL) return 0; - num = s->v4l2dev->num; + num = s->video_dev->num; /* card number + user defined offset + device offset */ if (type != CX18_ENC_STREAM_TYPE_MPG) { struct cx18_stream *s_mpg = &cx->streams[CX18_ENC_STREAM_TYPE_MPG]; - if (s_mpg->v4l2dev) - num = s_mpg->v4l2dev->num + cx18_stream_info[type].num_offset; + if (s_mpg->video_dev) + num = s_mpg->video_dev->num + + cx18_stream_info[type].num_offset; } /* Register device. First try the desired minor, then any free one. */ - ret = video_register_device(s->v4l2dev, vfl_type, num); + ret = video_register_device(s->video_dev, vfl_type, num); if (ret < 0) { CX18_ERR("Couldn't register v4l2 device for %s kernel number %d\n", s->name, num); - video_device_release(s->v4l2dev); - s->v4l2dev = NULL; + video_device_release(s->video_dev); + s->video_dev = NULL; return ret; } - num = s->v4l2dev->num; + num = s->video_dev->num; switch (vfl_type) { case VFL_TYPE_GRABBER: @@ -312,9 +313,9 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister) cx->streams[type].dvb.enabled = false; } - vdev = cx->streams[type].v4l2dev; + vdev = cx->streams[type].video_dev; - cx->streams[type].v4l2dev = NULL; + cx->streams[type].video_dev = NULL; if (vdev == NULL) continue; @@ -437,7 +438,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) int ts = 0; int captype = 0; - if (s->v4l2dev == NULL && s->dvb.enabled == 0) + if (s->video_dev == NULL && s->dvb.enabled == 0) return -EINVAL; CX18_DEBUG_INFO("Start encoder stream %s\n", s->name); @@ -565,7 +566,7 @@ void cx18_stop_all_captures(struct cx18 *cx) for (i = CX18_MAX_STREAMS - 1; i >= 0; i--) { struct cx18_stream *s = &cx->streams[i]; - if (s->v4l2dev == NULL && s->dvb.enabled == 0) + if (s->video_dev == NULL && s->dvb.enabled == 0) continue; if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) cx18_stop_v4l2_encode_stream(s, 0); @@ -577,7 +578,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end) struct cx18 *cx = s->cx; unsigned long then; - if (s->v4l2dev == NULL && s->dvb.enabled == 0) + if (s->video_dev == NULL && s->dvb.enabled == 0) return -EINVAL; /* This function assumes that you are allowed to stop the capture @@ -656,7 +657,7 @@ u32 cx18_find_handle(struct cx18 *cx) for (i = 0; i < CX18_MAX_STREAMS; i++) { struct cx18_stream *s = &cx->streams[i]; - if (s->v4l2dev && (s->handle != CX18_INVALID_TASK_HANDLE)) + if (s->video_dev && (s->handle != CX18_INVALID_TASK_HANDLE)) return s->handle; } return CX18_INVALID_TASK_HANDLE; @@ -674,7 +675,7 @@ struct cx18_stream *cx18_handle_to_stream(struct cx18 *cx, u32 handle) s = &cx->streams[i]; if (s->handle != handle) continue; - if (s->v4l2dev || s->dvb.enabled) + if (s->video_dev || s->dvb.enabled) return s; } return NULL; diff --git a/linux/drivers/media/video/cx18/cx23418.h b/linux/drivers/media/video/cx18/cx23418.h index 601f3a2ab..9956abf57 100644 --- a/linux/drivers/media/video/cx18/cx23418.h +++ b/linux/drivers/media/video/cx18/cx23418.h @@ -56,6 +56,22 @@ #define APU_CMD_MASK 0x10000000 #define APU_CMD_MASK_ACK (APU_CMD_MASK | 0x80000000) +#define CX18_APU_ENCODING_METHOD_MPEG (0 << 28) +#define CX18_APU_ENCODING_METHOD_AC3 (1 << 28) + +/* Description: Command APU to start audio + IN[0] - audio parameters (same as CX18_CPU_SET_AUDIO_PARAMETERS?) + IN[1] - caller buffer address, or 0 + ReturnCode - ??? */ +#define CX18_APU_START (APU_CMD_MASK | 0x01) + +/* Description: Command APU to stop audio + IN[0] - encoding method to stop + ReturnCode - ??? */ +#define CX18_APU_STOP (APU_CMD_MASK | 0x02) + +/* Description: Command APU to reset the AI + ReturnCode - ??? */ #define CX18_APU_RESETAI (APU_CMD_MASK | 0x05) /* Description: This command indicates that a Memory Descriptor List has been diff --git a/linux/drivers/media/video/cx2341x.c b/linux/drivers/media/video/cx2341x.c index f31f11e3f..c92b98135 100644 --- a/linux/drivers/media/video/cx2341x.c +++ b/linux/drivers/media/video/cx2341x.c @@ -1,5 +1,5 @@ /* - * cx2341x - generic code for cx23415/6 based devices + * cx2341x - generic code for cx23415/6/8 based devices * * Copyright (C) 2006 Hans Verkuil <hverkuil@xs4all.nl> * @@ -31,7 +31,7 @@ #include <media/v4l2-common.h> #include "compat.h" -MODULE_DESCRIPTION("cx23415/6 driver"); +MODULE_DESCRIPTION("cx23415/6/8 driver"); MODULE_AUTHOR("Hans Verkuil"); MODULE_LICENSE("GPL"); @@ -46,6 +46,7 @@ const u32 cx2341x_mpeg_ctrls[] = { V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, V4L2_CID_MPEG_AUDIO_ENCODING, V4L2_CID_MPEG_AUDIO_L2_BITRATE, + V4L2_CID_MPEG_AUDIO_AC3_BITRATE, V4L2_CID_MPEG_AUDIO_MODE, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION, V4L2_CID_MPEG_AUDIO_EMPHASIS, @@ -95,6 +96,7 @@ static const struct cx2341x_mpeg_params default_params = { .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, .audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2, .audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K, + .audio_ac3_bitrate = V4L2_MPEG_AUDIO_AC3_BITRATE_224K, .audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO, .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4, .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE, @@ -149,6 +151,9 @@ static int cx2341x_get_ctrl(const struct cx2341x_mpeg_params *params, case V4L2_CID_MPEG_AUDIO_L2_BITRATE: ctrl->value = params->audio_l2_bitrate; break; + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + ctrl->value = params->audio_ac3_bitrate; + break; case V4L2_CID_MPEG_AUDIO_MODE: ctrl->value = params->audio_mode; break; @@ -257,6 +262,12 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy, params->audio_sampling_freq = ctrl->value; break; case V4L2_CID_MPEG_AUDIO_ENCODING: + if (busy) + return -EBUSY; + if (params->capabilities & CX2341X_CAP_HAS_AC3) + if (ctrl->value != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 && + ctrl->value != V4L2_MPEG_AUDIO_ENCODING_AC3) + return -ERANGE; params->audio_encoding = ctrl->value; break; case V4L2_CID_MPEG_AUDIO_L2_BITRATE: @@ -264,6 +275,13 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy, return -EBUSY; params->audio_l2_bitrate = ctrl->value; break; + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + if (busy) + return -EBUSY; + if (!(params->capabilities & CX2341X_CAP_HAS_AC3)) + return -EINVAL; + params->audio_ac3_bitrate = ctrl->value; + break; case V4L2_CID_MPEG_AUDIO_MODE: params->audio_mode = ctrl->value; break; @@ -483,21 +501,55 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params, switch (qctrl->id) { case V4L2_CID_MPEG_AUDIO_ENCODING: + if (params->capabilities & CX2341X_CAP_HAS_AC3) { + /* + * The state of L2 & AC3 bitrate controls can change + * when this control changes, but v4l2_ctrl_query_fill() + * already sets V4L2_CTRL_FLAG_UPDATE for + * V4L2_CID_MPEG_AUDIO_ENCODING, so we don't here. + */ + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_ENCODING_LAYER_2, + V4L2_MPEG_AUDIO_ENCODING_AC3, 1, + default_params.audio_encoding); + } + return v4l2_ctrl_query_fill(qctrl, V4L2_MPEG_AUDIO_ENCODING_LAYER_2, V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1, default_params.audio_encoding); case V4L2_CID_MPEG_AUDIO_L2_BITRATE: - return v4l2_ctrl_query_fill(qctrl, + err = v4l2_ctrl_query_fill(qctrl, V4L2_MPEG_AUDIO_L2_BITRATE_192K, V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1, default_params.audio_l2_bitrate); + if (err) + return err; + if (params->capabilities & CX2341X_CAP_HAS_AC3 && + params->audio_encoding != V4L2_MPEG_AUDIO_ENCODING_LAYER_2) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return 0; case V4L2_CID_MPEG_AUDIO_L1_BITRATE: case V4L2_CID_MPEG_AUDIO_L3_BITRATE: return -EINVAL; + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + err = v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_AC3_BITRATE_48K, + V4L2_MPEG_AUDIO_AC3_BITRATE_448K, 1, + default_params.audio_ac3_bitrate); + if (err) + return err; + if (params->capabilities & CX2341X_CAP_HAS_AC3) { + if (params->audio_encoding != + V4L2_MPEG_AUDIO_ENCODING_AC3) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + } else + qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; + return 0; + case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: err = v4l2_ctrl_query_fill_std(qctrl); if (err == 0 && @@ -672,6 +724,15 @@ const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id) NULL }; + static const char *mpeg_audio_encoding_l2_ac3[] = { + "", + "MPEG-1/2 Layer II", + "", + "", + "AC-3", + NULL + }; + static const char *cx2341x_video_spatial_filter_mode_menu[] = { "Manual", "Auto", @@ -712,6 +773,9 @@ const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id) case V4L2_CID_MPEG_STREAM_TYPE: return (p->capabilities & CX2341X_CAP_HAS_TS) ? mpeg_stream_type_with_ts : mpeg_stream_type_without_ts; + case V4L2_CID_MPEG_AUDIO_ENCODING: + return (p->capabilities & CX2341X_CAP_HAS_AC3) ? + mpeg_audio_encoding_l2_ac3 : v4l2_ctrl_get_menu(id); case V4L2_CID_MPEG_AUDIO_L1_BITRATE: case V4L2_CID_MPEG_AUDIO_L3_BITRATE: return NULL; @@ -731,16 +795,36 @@ const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id) } EXPORT_SYMBOL(cx2341x_ctrl_get_menu); +/* definitions for audio properties bits 29-28 */ +#define CX2341X_AUDIO_ENCODING_METHOD_MPEG 0 +#define CX2341X_AUDIO_ENCODING_METHOD_AC3 1 +#define CX2341X_AUDIO_ENCODING_METHOD_LPCM 2 + static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params) { - params->audio_properties = (params->audio_sampling_freq << 0) | - ((3 - params->audio_encoding) << 2) | - ((1 + params->audio_l2_bitrate) << 4) | + params->audio_properties = + (params->audio_sampling_freq << 0) | (params->audio_mode << 8) | (params->audio_mode_extension << 10) | (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) ? 3 : params->audio_emphasis) << 12) | (params->audio_crc << 14); + + if ((params->capabilities & CX2341X_CAP_HAS_AC3) && + params->audio_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3) { + params->audio_properties |= +#if 1 + /* Not sure if this MPEG Layer II setting is required */ + ((3 - V4L2_MPEG_AUDIO_ENCODING_LAYER_2) << 2) | +#endif + (params->audio_ac3_bitrate << 4) | + (CX2341X_AUDIO_ENCODING_METHOD_AC3 << 28); + } else { + /* Assuming MPEG Layer II */ + params->audio_properties |= + ((3 - params->audio_encoding) << 2) | + ((1 + params->audio_l2_bitrate) << 4); + } } int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy, @@ -1023,7 +1107,10 @@ void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix) prefix, cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ), cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING), - cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE), + cx2341x_menu_item(p, + p->audio_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3 + ? V4L2_CID_MPEG_AUDIO_AC3_BITRATE + : V4L2_CID_MPEG_AUDIO_L2_BITRATE), cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE), p->audio_mute ? " (muted)" : ""); if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) diff --git a/linux/drivers/media/video/cx23885/cx23885-cards.c b/linux/drivers/media/video/cx23885/cx23885-cards.c index db1e8bdab..a8201ceaa 100644 --- a/linux/drivers/media/video/cx23885/cx23885-cards.c +++ b/linux/drivers/media/video/cx23885/cx23885-cards.c @@ -163,6 +163,18 @@ struct cx23885_board cx23885_boards[] = { .name = "Compro VideoMate E650F", .portc = CX23885_MPEG_DVB, }, + [CX23885_BOARD_TBS_6920] = { + .name = "TurboSight TBS 6920", + .portb = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_TEVII_S470] = { + .name = "TeVii S470", + .portb = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_DVBWORLD_2005] = { + .name = "DVBWorld DVB-S2 2005", + .portb = CX23885_MPEG_DVB, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -246,6 +258,18 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x185b, .subdevice = 0xe800, .card = CX23885_BOARD_COMPRO_VIDEOMATE_E650F, + }, { + .subvendor = 0x6920, + .subdevice = 0x8888, + .card = CX23885_BOARD_TBS_6920, + }, { + .subvendor = 0xd470, + .subdevice = 0x9022, + .card = CX23885_BOARD_TEVII_S470, + }, { + .subvendor = 0x0001, + .subdevice = 0x2005, + .card = CX23885_BOARD_DVBWORLD_2005, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -553,6 +577,12 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) mdelay(20); cx_set(GP0_IO, 0x00040004); break; + case CX23885_BOARD_TBS_6920: + case CX23885_BOARD_TEVII_S470: + cx_write(MC417_CTL, 0x00000036); + cx_write(MC417_OEN, 0x00001000); + cx_write(MC417_RWD, 0x00001800); + break; } } @@ -633,6 +663,13 @@ void cx23885_card_setup(struct cx23885_dev *dev) ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; break; + case CX23885_BOARD_TEVII_S470: + case CX23885_BOARD_TBS_6920: + case CX23885_BOARD_DVBWORLD_2005: + ts1->gen_ctrl_val = 0x5; /* Parallel */ + ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + break; case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1500: case CX23885_BOARD_HAUPPAUGE_HVR1500Q: diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c index 990fd217b..90dbf49ea 100644 --- a/linux/drivers/media/video/cx23885/cx23885-dvb.c +++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c @@ -44,6 +44,7 @@ #include "dib7000p.h" #include "dibx000_common.h" #include "zl10353.h" +#include "cx24116.h" static unsigned int debug; @@ -309,6 +310,32 @@ static struct zl10353_config dvico_fusionhdtv_xc3028 = { .no_tuner = 1, }; +static int tbs_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct cx23885_tsport *port = fe->dvb->priv; + struct cx23885_dev *dev = port->dev; + + if (voltage == SEC_VOLTAGE_18) + cx_write(MC417_RWD, 0x00001e00);/* GPIO-13 high */ + else if (voltage == SEC_VOLTAGE_13) + cx_write(MC417_RWD, 0x00001a00);/* GPIO-13 low */ + else + cx_write(MC417_RWD, 0x00001800);/* GPIO-12 low */ + return 0; +} + +static struct cx24116_config tbs_cx24116_config = { + .demod_address = 0x05, +}; + +static struct cx24116_config tevii_cx24116_config = { + .demod_address = 0x55, +}; + +static struct cx24116_config dvbworld_cx24116_config = { + .demod_address = 0x05, +}; + static int dvb_register(struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; @@ -527,6 +554,33 @@ static int dvb_register(struct cx23885_tsport *port) fe->ops.tuner_ops.set_config(fe, &ctl); } break; + case CX23885_BOARD_TBS_6920: + i2c_bus = &dev->i2c_bus[0]; + + fe0->dvb.frontend = dvb_attach(cx24116_attach, + &tbs_cx24116_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) + fe0->dvb.frontend->ops.set_voltage = tbs_set_voltage; + + break; + case CX23885_BOARD_TEVII_S470: + i2c_bus = &dev->i2c_bus[1]; + + fe0->dvb.frontend = dvb_attach(cx24116_attach, + &tevii_cx24116_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) + fe0->dvb.frontend->ops.set_voltage = tbs_set_voltage; + + break; + case CX23885_BOARD_DVBWORLD_2005: + i2c_bus = &dev->i2c_bus[1]; + + fe0->dvb.frontend = dvb_attach(cx24116_attach, + &dvbworld_cx24116_config, + &i2c_bus->i2c_adap); + break; default: printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " " isn't supported yet\n", diff --git a/linux/drivers/media/video/cx23885/cx23885.h b/linux/drivers/media/video/cx23885/cx23885.h index ad93e0e88..cae0a74bd 100644 --- a/linux/drivers/media/video/cx23885/cx23885.h +++ b/linux/drivers/media/video/cx23885/cx23885.h @@ -68,6 +68,9 @@ #define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP 11 #define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H 12 #define CX23885_BOARD_COMPRO_VIDEOMATE_E650F 13 +#define CX23885_BOARD_TBS_6920 14 +#define CX23885_BOARD_TEVII_S470 15 +#define CX23885_BOARD_DVBWORLD_2005 16 /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */ #define CX23885_NORMS (\ diff --git a/linux/drivers/media/video/hexium_gemini.c b/linux/drivers/media/video/hexium_gemini.c index 043a3080b..bcd8144c5 100644 --- a/linux/drivers/media/video/hexium_gemini.c +++ b/linux/drivers/media/video/hexium_gemini.c @@ -57,17 +57,6 @@ struct hexium_data u8 byte; }; -static struct saa7146_extension_ioctls ioctls[] = { - { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_QUERYCTRL, SAA7146_BEFORE }, - { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_S_STD, SAA7146_AFTER }, - { VIDIOC_G_CTRL, SAA7146_BEFORE }, - { VIDIOC_S_CTRL, SAA7146_BEFORE }, - { 0, 0 } -}; - #define HEXIUM_CONTROLS 1 static struct v4l2_queryctrl hexium_controls[] = { { V4L2_CID_PRIVATE_BASE, V4L2_CTRL_TYPE_BOOLEAN, "B/W", 0, 1, 1, 0, 0 }, @@ -232,6 +221,132 @@ static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec) return 0; } +static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) +{ + DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); + + if (i->index < 0 || i->index >= HEXIUM_INPUTS) + return -EINVAL; + + memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); + + DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index)); + return 0; +} + +static int vidioc_g_input(struct file *file, void *fh, unsigned int *input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + *input = hexium->cur_input; + + DEB_D(("VIDIOC_G_INPUT: %d\n", *input)); + return 0; +} + +static int vidioc_s_input(struct file *file, void *fh, unsigned int input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + DEB_EE(("VIDIOC_S_INPUT %d.\n", input)); + + if (input < 0 || input >= HEXIUM_INPUTS) + return -EINVAL; + + hexium->cur_input = input; + hexium_set_input(hexium, input); + return 0; +} + +/* the saa7146 provides some controls (brightness, contrast, saturation) + which gets registered *after* this function. because of this we have + to return with a value != 0 even if the function succeded.. */ +static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + int i; + + for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { + if (hexium_controls[i].id == qc->id) { + *qc = hexium_controls[i]; + DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id)); + return 0; + } + } + return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc); +} + +static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct hexium *hexium = (struct hexium *) dev->ext_priv; + int i; + + for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { + if (hexium_controls[i].id == vc->id) + break; + } + + if (i < 0) + return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc); + + if (vc->id == V4L2_CID_PRIVATE_BASE) { + vc->value = hexium->cur_bw; + DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value)); + return 0; + } + return -EINVAL; +} + +static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct hexium *hexium = (struct hexium *) dev->ext_priv; + int i = 0; + + for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { + if (hexium_controls[i].id == vc->id) + break; + } + + if (i < 0) + return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc); + + if (vc->id == V4L2_CID_PRIVATE_BASE) + hexium->cur_bw = vc->value; + + DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw)); + + if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) { + hexium_set_standard(hexium, hexium_pal); + return 0; + } + if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) { + hexium_set_standard(hexium, hexium_ntsc); + return 0; + } + if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) { + hexium_set_standard(hexium, hexium_secam); + return 0; + } + if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) { + hexium_set_standard(hexium, hexium_pal_bw); + return 0; + } + if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) { + hexium_set_standard(hexium, hexium_ntsc_bw); + return 0; + } + if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) + /* fixme: is there no bw secam mode? */ + return -EINVAL; + + return -EINVAL; +} + + static struct saa7146_ext_vv vv_data; /* this function only gets called when the probing was successful */ @@ -280,6 +395,12 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d hexium->cur_input = 0; saa7146_vv_init(dev, &vv_data); + vv_data.ops.vidioc_queryctrl = vidioc_queryctrl; + vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl; + vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl; + vv_data.ops.vidioc_enum_input = vidioc_enum_input; + vv_data.ops.vidioc_g_input = vidioc_g_input; + vv_data.ops.vidioc_s_input = vidioc_s_input; if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER)) { printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n"); return -1; @@ -307,153 +428,6 @@ static int hexium_detach(struct saa7146_dev *dev) return 0; } -static long hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) -{ - struct saa7146_dev *dev = fh->dev; - struct hexium *hexium = (struct hexium *) dev->ext_priv; -/* - struct saa7146_vv *vv = dev->vv_data; -*/ - switch (cmd) { - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *i = arg; - DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); - - if (i->index < 0 || i->index >= HEXIUM_INPUTS) { - return -EINVAL; - } - - memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); - - DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index)); - return 0; - } - case VIDIOC_G_INPUT: - { - int *input = (int *) arg; - *input = hexium->cur_input; - - DEB_D(("VIDIOC_G_INPUT: %d\n", *input)); - return 0; - } - case VIDIOC_S_INPUT: - { - int input = *(int *) arg; - - DEB_EE(("VIDIOC_S_INPUT %d.\n", input)); - - if (input < 0 || input >= HEXIUM_INPUTS) { - return -EINVAL; - } - - hexium->cur_input = input; - hexium_set_input(hexium, input); - - return 0; - } - /* the saa7146 provides some controls (brightness, contrast, saturation) - which gets registered *after* this function. because of this we have - to return with a value != 0 even if the function succeded.. */ - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *qc = arg; - int i; - - for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { - if (hexium_controls[i].id == qc->id) { - *qc = hexium_controls[i]; - DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id)); - return 0; - } - } - return -EAGAIN; - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *vc = arg; - int i; - - for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { - if (hexium_controls[i].id == vc->id) { - break; - } - } - - if (i < 0) { - return -EAGAIN; - } - - switch (vc->id) { - case V4L2_CID_PRIVATE_BASE:{ - vc->value = hexium->cur_bw; - DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value)); - return 0; - } - } - return -EINVAL; - } - - case VIDIOC_S_CTRL: - { - struct v4l2_control *vc = arg; - int i = 0; - - for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { - if (hexium_controls[i].id == vc->id) { - break; - } - } - - if (i < 0) { - return -EAGAIN; - } - - switch (vc->id) { - case V4L2_CID_PRIVATE_BASE:{ - hexium->cur_bw = vc->value; - break; - } - } - - DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw)); - - if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) { - hexium_set_standard(hexium, hexium_pal); - return 0; - } - if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) { - hexium_set_standard(hexium, hexium_ntsc); - return 0; - } - if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) { - hexium_set_standard(hexium, hexium_secam); - return 0; - } - if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) { - hexium_set_standard(hexium, hexium_pal_bw); - return 0; - } - if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) { - hexium_set_standard(hexium, hexium_ntsc_bw); - return 0; - } - if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) { - /* fixme: is there no bw secam mode? */ - return -EINVAL; - } - - return -EINVAL; - } - default: -/* - DEB_D(("hexium_ioctl() does not handle this ioctl.\n")); -*/ - return -ENOIOCTLCMD; - } - return 0; -} - static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std) { struct hexium *hexium = (struct hexium *) dev->ext_priv; @@ -515,8 +489,6 @@ static struct saa7146_ext_vv vv_data = { .stds = &hexium_standards[0], .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard), .std_callback = &std_callback, - .ioctls = &ioctls[0], - .ioctl = hexium_ioctl, }; static struct saa7146_extension hexium_extension = { diff --git a/linux/drivers/media/video/hexium_orion.c b/linux/drivers/media/video/hexium_orion.c index 847518f78..4178edcc2 100644 --- a/linux/drivers/media/video/hexium_orion.c +++ b/linux/drivers/media/video/hexium_orion.c @@ -58,14 +58,6 @@ struct hexium_data u8 byte; }; -static struct saa7146_extension_ioctls ioctls[] = { - { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_S_STD, SAA7146_AFTER }, - { 0, 0 } -}; - struct hexium { int type; @@ -330,6 +322,44 @@ static int hexium_set_input(struct hexium *hexium, int input) return 0; } +static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) +{ + DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); + + if (i->index < 0 || i->index >= HEXIUM_INPUTS) + return -EINVAL; + + memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); + + DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index)); + return 0; +} + +static int vidioc_g_input(struct file *file, void *fh, unsigned int *input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + *input = hexium->cur_input; + + DEB_D(("VIDIOC_G_INPUT: %d\n", *input)); + return 0; +} + +static int vidioc_s_input(struct file *file, void *fh, unsigned int input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + if (input < 0 || input >= HEXIUM_INPUTS) + return -EINVAL; + + hexium->cur_input = input; + hexium_set_input(hexium, input); + + return 0; +} + static struct saa7146_ext_vv vv_data; /* this function only gets called when the probing was successful */ @@ -340,6 +370,9 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d DEB_EE((".\n")); saa7146_vv_init(dev, &vv_data); + vv_data.ops.vidioc_enum_input = vidioc_enum_input; + vv_data.ops.vidioc_g_input = vidioc_g_input; + vv_data.ops.vidioc_s_input = vidioc_s_input; if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) { printk("hexium_orion: cannot register capture v4l2 device. skipping.\n"); return -1; @@ -371,58 +404,6 @@ static int hexium_detach(struct saa7146_dev *dev) return 0; } -static long hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) -{ - struct saa7146_dev *dev = fh->dev; - struct hexium *hexium = (struct hexium *) dev->ext_priv; -/* - struct saa7146_vv *vv = dev->vv_data; -*/ - switch (cmd) { - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *i = arg; - DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); - - if (i->index < 0 || i->index >= HEXIUM_INPUTS) { - return -EINVAL; - } - - memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); - - DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index)); - return 0; - } - case VIDIOC_G_INPUT: - { - int *input = (int *) arg; - *input = hexium->cur_input; - - DEB_D(("VIDIOC_G_INPUT: %d\n", *input)); - return 0; - } - case VIDIOC_S_INPUT: - { - int input = *(int *) arg; - - if (input < 0 || input >= HEXIUM_INPUTS) { - return -EINVAL; - } - - hexium->cur_input = input; - hexium_set_input(hexium, input); - - return 0; - } - default: -/* - DEB_D(("hexium_ioctl() does not handle this ioctl.\n")); -*/ - return -ENOIOCTLCMD; - } - return 0; -} - static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std) { return 0; @@ -480,8 +461,6 @@ static struct saa7146_ext_vv vv_data = { .stds = &hexium_standards[0], .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard), .std_callback = &std_callback, - .ioctls = &ioctls[0], - .ioctl = hexium_ioctl, }; static struct saa7146_extension extension = { diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.h b/linux/drivers/media/video/ivtv/ivtv-driver.h index 51f6e54ba..03df1cb7d 100644 --- a/linux/drivers/media/video/ivtv/ivtv-driver.h +++ b/linux/drivers/media/video/ivtv/ivtv-driver.h @@ -697,7 +697,7 @@ struct ivtv { u64 vbi_data_inserted; /* number of VBI bytes inserted into the MPEG stream */ u32 last_dec_timing[3]; /* cache last retrieved pts/scr/frame values */ unsigned long dualwatch_jiffies;/* jiffies value of the previous dualwatch check */ - u16 dualwatch_stereo_mode; /* current detected dualwatch stereo mode */ + u32 dualwatch_stereo_mode; /* current detected dualwatch stereo mode */ /* VBI state info */ diff --git a/linux/drivers/media/video/ivtv/ivtv-fileops.c b/linux/drivers/media/video/ivtv/ivtv-fileops.c index d594bc29f..617667d1c 100644 --- a/linux/drivers/media/video/ivtv/ivtv-fileops.c +++ b/linux/drivers/media/video/ivtv/ivtv-fileops.c @@ -148,10 +148,10 @@ void ivtv_release_stream(struct ivtv_stream *s) static void ivtv_dualwatch(struct ivtv *itv) { struct v4l2_tuner vt; - u16 new_bitmap; - u16 new_stereo_mode; - const u16 stereo_mask = 0x0300; - const u16 dual = 0x0200; + u32 new_bitmap; + u32 new_stereo_mode; + const u32 stereo_mask = 0x0300; + const u32 dual = 0x0200; new_stereo_mode = itv->params.audio_properties & stereo_mask; memset(&vt, 0, sizeof(vt)); diff --git a/linux/drivers/media/video/mxb.c b/linux/drivers/media/video/mxb.c index 974d9bcbd..e7b94e6b1 100644 --- a/linux/drivers/media/video/mxb.c +++ b/linux/drivers/media/video/mxb.c @@ -111,26 +111,6 @@ static struct v4l2_queryctrl mxb_controls[] = { { V4L2_CID_AUDIO_MUTE, V4L2_CTRL_TYPE_BOOLEAN, "Mute", 0, 1, 1, 0, 0 }, }; -static struct saa7146_extension_ioctls ioctls[] = { - { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_QUERYCTRL, SAA7146_BEFORE }, - { VIDIOC_G_CTRL, SAA7146_BEFORE }, - { VIDIOC_S_CTRL, SAA7146_BEFORE }, - { VIDIOC_G_TUNER, SAA7146_EXCLUSIVE }, - { VIDIOC_S_TUNER, SAA7146_EXCLUSIVE }, - { VIDIOC_G_FREQUENCY, SAA7146_EXCLUSIVE }, - { VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE }, - { VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE }, - { VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE }, - { VIDIOC_DBG_G_REGISTER, SAA7146_EXCLUSIVE }, - { VIDIOC_DBG_S_REGISTER, SAA7146_EXCLUSIVE }, - { MXB_S_AUDIO_CD, SAA7146_EXCLUSIVE }, /* custom control */ - { MXB_S_AUDIO_LINE, SAA7146_EXCLUSIVE }, /* custom control */ - { 0, 0 } -}; - struct mxb { struct video_device *video_dev; @@ -425,387 +405,430 @@ void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask) } */ -static struct saa7146_ext_vv vv_data; - -/* this function only gets called when the probing was successful */ -static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) +static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc) { - struct mxb *mxb = (struct mxb *)dev->ext_priv; + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + int i; - DEB_EE(("dev:%p\n", dev)); + for (i = MAXCONTROLS - 1; i >= 0; i--) { + if (mxb_controls[i].id == qc->id) { + *qc = mxb_controls[i]; + DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id)); + return 0; + } + } + return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc); +} - /* checking for i2c-devices can be omitted here, because we - already did this in "mxb_vl42_probe" */ +static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; + int i; - saa7146_vv_init(dev, &vv_data); - if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) { - ERR(("cannot register capture v4l2 device. skipping.\n")); - return -1; + for (i = MAXCONTROLS - 1; i >= 0; i--) { + if (mxb_controls[i].id == vc->id) + break; } - /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/ - if (MXB_BOARD_CAN_DO_VBI(dev)) { - if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) { - ERR(("cannot register vbi v4l2 device. skipping.\n")); - } - } + if (i < 0) + return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc); - i2c_use_client(mxb->tea6420_1); - i2c_use_client(mxb->tea6420_2); - i2c_use_client(mxb->tea6415c); - i2c_use_client(mxb->tda9840); - i2c_use_client(mxb->saa7111a); - i2c_use_client(mxb->tuner); - - printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num); + if (vc->id == V4L2_CID_AUDIO_MUTE) { + vc->value = mxb->cur_mute; + DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value)); + return 0; + } - mxb_num++; - mxb_init_done(dev); + DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value)); return 0; } -static int mxb_detach(struct saa7146_dev *dev) +static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc) { + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct mxb *mxb = (struct mxb *)dev->ext_priv; + int i = 0; - DEB_EE(("dev:%p\n", dev)); - - i2c_release_client(mxb->tea6420_1); - i2c_release_client(mxb->tea6420_2); - i2c_release_client(mxb->tea6415c); - i2c_release_client(mxb->tda9840); - i2c_release_client(mxb->saa7111a); - i2c_release_client(mxb->tuner); - - saa7146_unregister_device(&mxb->video_dev,dev); - if (MXB_BOARD_CAN_DO_VBI(dev)) - saa7146_unregister_device(&mxb->vbi_dev, dev); - saa7146_vv_release(dev); + for (i = MAXCONTROLS - 1; i >= 0; i--) { + if (mxb_controls[i].id == vc->id) + break; + } - mxb_num--; + if (i < 0) + return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc); - i2c_del_adapter(&mxb->i2c_adapter); - kfree(mxb); + if (vc->id == V4L2_CID_AUDIO_MUTE) { + mxb->cur_mute = vc->value; + if (!vc->value) { + /* switch the audio-source */ + mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, + &TEA6420_line[video_audio_connect[mxb->cur_input]][0]); + mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, + &TEA6420_line[video_audio_connect[mxb->cur_input]][1]); + } else { + mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, + &TEA6420_line[6][0]); + mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, + &TEA6420_line[6][1]); + } + DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value)); + } + return 0; +} +static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) +{ + DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); + if (i->index < 0 || i->index >= MXB_INPUTS) + return -EINVAL; + memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input)); return 0; } -static long mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) +static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) { - struct saa7146_dev *dev = fh->dev; + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct mxb *mxb = (struct mxb *)dev->ext_priv; - struct saa7146_vv *vv = dev->vv_data; + *i = mxb->cur_input; - switch(cmd) { - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *i = arg; + DEB_EE(("VIDIOC_G_INPUT %d.\n", *i)); + return 0; +} - DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index)); - if (i->index < 0 || i->index >= MXB_INPUTS) - return -EINVAL; - memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input)); - return 0; - } - /* the saa7146 provides some controls (brightness, contrast, saturation) - which gets registered *after* this function. because of this we have - to return with a value != 0 even if the function succeded.. */ - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *qc = arg; - int i; - - for (i = MAXCONTROLS - 1; i >= 0; i--) { - if (mxb_controls[i].id == qc->id) { - *qc = mxb_controls[i]; - DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id)); - return 0; - } - } - return -EAGAIN; - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *vc = arg; - int i; +static int vidioc_s_input(struct file *file, void *fh, unsigned int input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; + struct tea6415c_multiplex vm; + struct v4l2_routing route; + int i = 0; - for (i = MAXCONTROLS - 1; i >= 0; i--) { - if (mxb_controls[i].id == vc->id) - break; - } + DEB_EE(("VIDIOC_S_INPUT %d.\n", input)); - if (i < 0) - return -EAGAIN; + if (input < 0 || input >= MXB_INPUTS) + return -EINVAL; - if (vc->id == V4L2_CID_AUDIO_MUTE) { - vc->value = mxb->cur_mute; - DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value)); - return 0; - } + mxb->cur_input = input; - DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value)); - return 0; - } + saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, + input_port_selection[input].hps_sync); - case VIDIOC_S_CTRL: - { - struct v4l2_control *vc = arg; - int i = 0; + /* prepare switching of tea6415c and saa7111a; + have a look at the 'background'-file for further informations */ + switch (input) { + case TUNER: + i = SAA7115_COMPOSITE0; + vm.in = 3; + vm.out = 17; - for (i = MAXCONTROLS - 1; i >= 0; i--) { - if (mxb_controls[i].id == vc->id) - break; + if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) { + printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #1\n"); + return -EFAULT; } + /* connect tuner-output always to multicable */ + vm.in = 3; + vm.out = 13; + break; + case AUX3_YC: + /* nothing to be done here. aux3_yc is + directly connected to the saa711a */ + i = SAA7115_SVIDEO1; + break; + case AUX3: + /* nothing to be done here. aux3 is + directly connected to the saa711a */ + i = SAA7115_COMPOSITE1; + break; + case AUX1: + i = SAA7115_COMPOSITE0; + vm.in = 1; + vm.out = 17; + break; + } - if (i < 0) - return -EAGAIN; - - if (vc->id == V4L2_CID_AUDIO_MUTE) { - mxb->cur_mute = vc->value; - if (!vc->value) { - /* switch the audio-source */ - mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, - &TEA6420_line[video_audio_connect[mxb->cur_input]][0]); - mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, - &TEA6420_line[video_audio_connect[mxb->cur_input]][1]); - } else { - mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, - &TEA6420_line[6][0]); - mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, - &TEA6420_line[6][1]); - } - DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value)); + /* switch video in tea6415c only if necessary */ + switch (input) { + case TUNER: + case AUX1: + if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) { + printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #3\n"); + return -EFAULT; } - return 0; + break; + default: + break; } - case VIDIOC_G_INPUT: - { - int *input = (int *)arg; - *input = mxb->cur_input; - DEB_EE(("VIDIOC_G_INPUT %d.\n", *input)); - return 0; + /* switch video in saa7111a */ + route.input = i; + route.output = 0; + if (mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route)) + printk(KERN_ERR "VIDIOC_S_INPUT: could not address saa7111a #1.\n"); + + /* switch the audio-source only if necessary */ + if (0 == mxb->cur_mute) { + mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, + &TEA6420_line[video_audio_connect[input]][0]); + mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, + &TEA6420_line[video_audio_connect[input]][1]); } - case VIDIOC_S_INPUT: - { - int input = *(int *)arg; - struct tea6415c_multiplex vm; - struct v4l2_routing route; - int i = 0; - DEB_EE(("VIDIOC_S_INPUT %d.\n", input)); + return 0; +} - if (input < 0 || input >= MXB_INPUTS) - return -EINVAL; +static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; - mxb->cur_input = input; + if (t->index) { + DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index)); + return -EINVAL; + } - saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, - input_port_selection[input].hps_sync); + DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index)); - /* prepare switching of tea6415c and saa7111a; - have a look at the 'background'-file for further informations */ - switch (input) { - case TUNER: - i = SAA7115_COMPOSITE0; - vm.in = 3; - vm.out = 17; + memset(t, 0, sizeof(*t)); + i2c_clients_command(&mxb->i2c_adapter, VIDIOC_G_TUNER, t); - if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) { - printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #1\n"); - return -EFAULT; - } - /* connect tuner-output always to multicable */ - vm.in = 3; - vm.out = 13; - break; - case AUX3_YC: - /* nothing to be done here. aux3_yc is - directly connected to the saa711a */ - i = SAA7115_SVIDEO1; - break; - case AUX3: - /* nothing to be done here. aux3 is - directly connected to the saa711a */ - i = SAA7115_COMPOSITE1; - break; - case AUX1: - i = SAA7115_COMPOSITE0; - vm.in = 1; - vm.out = 17; - break; - } + strlcpy(t->name, "TV Tuner", sizeof(t->name)); + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; + t->audmode = mxb->cur_mode; + return 0; +} - /* switch video in tea6415c only if necessary */ - switch (input) { - case TUNER: - case AUX1: - if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) { - printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #3\n"); - return -EFAULT; - } - break; - default: - break; - } +static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; - /* switch video in saa7111a */ - route.input = i; - route.output = 0; - if (mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route)) - printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n"); + if (t->index) { + DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n", t->index)); + return -EINVAL; + } - /* switch the audio-source only if necessary */ - if( 0 == mxb->cur_mute ) { - mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, - &TEA6420_line[video_audio_connect[input]][0]); - mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, - &TEA6420_line[video_audio_connect[input]][1]); - } + mxb->cur_mode = t->audmode; + i2c_clients_command(&mxb->i2c_adapter, VIDIOC_S_TUNER, t); + return 0; +} - return 0; +static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; + + if (mxb->cur_input) { + DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n", + mxb->cur_input)); + return -EINVAL; } - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *t = arg; - if (t->index) { - DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index)); - return -EINVAL; - } + *f = mxb->cur_freq; - DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index)); + DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency)); + return 0; +} - memset(t, 0, sizeof(*t)); - i2c_clients_command(&mxb->i2c_adapter, cmd, arg); +static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; + struct saa7146_vv *vv = dev->vv_data; - strlcpy(t->name, "TV Tuner", sizeof(t->name)); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | \ - V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; - t->audmode = mxb->cur_mode; - return 0; - } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *t = arg; + if (f->tuner) + return -EINVAL; - if (t->index) { - DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index)); - return -EINVAL; - } + if (V4L2_TUNER_ANALOG_TV != f->type) + return -EINVAL; - mxb->cur_mode = t->audmode; - i2c_clients_command(&mxb->i2c_adapter, cmd, arg); - return 0; + if (mxb->cur_input) { + DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input)); + return -EINVAL; } - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *f = arg; - if (mxb->cur_input) { - DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n", - mxb->cur_input)); - return -EINVAL; - } + mxb->cur_freq = *f; + DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency)); - *f = mxb->cur_freq; + /* tune in desired frequency */ + mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq); - DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency)); - return 0; + /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */ + spin_lock(&dev->slock); + vv->vbi_fieldcount = 0; + spin_unlock(&dev->slock); + + return 0; +} + +static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; + + if (a->index < 0 || a->index > MXB_INPUTS) { + DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index)); + return -EINVAL; } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *f = arg; - if (f->tuner) - return -EINVAL; + DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index)); + memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio)); + return 0; +} - if (V4L2_TUNER_ANALOG_TV != f->type) - return -EINVAL; +static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a) +{ + DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index)); + return 0; +} - if (mxb->cur_input) { - DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input)); - return -EINVAL; - } +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; - mxb->cur_freq = *f; - DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency)); + i2c_clients_command(&mxb->i2c_adapter, VIDIOC_DBG_G_REGISTER, reg); + return 0; +} - /* tune in desired frequency */ - mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq); +static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; - /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */ - spin_lock(&dev->slock); - vv->vbi_fieldcount = 0; - spin_unlock(&dev->slock); + i2c_clients_command(&mxb->i2c_adapter, VIDIOC_DBG_S_REGISTER, reg); + return 0; +} +#endif - return 0; - } +static long vidioc_default(struct file *file, void *fh, int cmd, void *arg) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; + + switch (cmd) { case MXB_S_AUDIO_CD: { - int i = *(int*)arg; + int i = *(int *)arg; if (i < 0 || i >= MXB_AUDIOS) { - DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i)); + DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n", i)); return -EINVAL; } - DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i)); + DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n", i)); - mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]); - mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[i][1]); + mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_cd[i][0]); + mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_cd[i][1]); return 0; } case MXB_S_AUDIO_LINE: { - int i = *(int*)arg; + int i = *(int *)arg; if (i < 0 || i >= MXB_AUDIOS) { - DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i)); + DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n", i)); return -EINVAL; } - DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n",i)); - mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]); - mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]); + DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n", i)); + mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_line[i][0]); + mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_line[i][1]); return 0; } - case VIDIOC_G_AUDIO: - { - struct v4l2_audio *a = arg; + default: +/* + DEB2(printk("does not handle this ioctl.\n")); +*/ + return -ENOIOCTLCMD; + } + return 0; +} - if (a->index < 0 || a->index > MXB_INPUTS) { - DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index)); - return -EINVAL; - } +static struct saa7146_ext_vv vv_data; + +/* this function only gets called when the probing was successful */ +static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) +{ + struct mxb *mxb = (struct mxb *)dev->ext_priv; - DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index)); - memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio)); + DEB_EE(("dev:%p\n", dev)); - return 0; - } - case VIDIOC_S_AUDIO: - { - struct v4l2_audio *a = arg; + /* checking for i2c-devices can be omitted here, because we + already did this in "mxb_vl42_probe" */ - DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index)); - return 0; - } + saa7146_vv_init(dev, &vv_data); + vv_data.ops.vidioc_queryctrl = vidioc_queryctrl; + vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl; + vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl; + vv_data.ops.vidioc_enum_input = vidioc_enum_input; + vv_data.ops.vidioc_g_input = vidioc_g_input; + vv_data.ops.vidioc_s_input = vidioc_s_input; + vv_data.ops.vidioc_g_tuner = vidioc_g_tuner; + vv_data.ops.vidioc_s_tuner = vidioc_s_tuner; + vv_data.ops.vidioc_g_frequency = vidioc_g_frequency; + vv_data.ops.vidioc_s_frequency = vidioc_s_frequency; + vv_data.ops.vidioc_g_audio = vidioc_g_audio; + vv_data.ops.vidioc_s_audio = vidioc_s_audio; #ifdef CONFIG_VIDEO_ADV_DEBUG - case VIDIOC_DBG_S_REGISTER: - case VIDIOC_DBG_G_REGISTER: - i2c_clients_command(&mxb->i2c_adapter, cmd, arg); - return 0; + vv_data.ops.vidioc_g_register = vidioc_g_register; + vv_data.ops.vidioc_s_register = vidioc_s_register; #endif - default: -/* - DEB2(printk("does not handle this ioctl.\n")); -*/ - return -ENOIOCTLCMD; + vv_data.ops.vidioc_default = vidioc_default; + if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) { + ERR(("cannot register capture v4l2 device. skipping.\n")); + return -1; + } + + /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/ + if (MXB_BOARD_CAN_DO_VBI(dev)) { + if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) { + ERR(("cannot register vbi v4l2 device. skipping.\n")); + } } + + i2c_use_client(mxb->tea6420_1); + i2c_use_client(mxb->tea6420_2); + i2c_use_client(mxb->tea6415c); + i2c_use_client(mxb->tda9840); + i2c_use_client(mxb->saa7111a); + i2c_use_client(mxb->tuner); + + printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num); + + mxb_num++; + mxb_init_done(dev); + return 0; +} + +static int mxb_detach(struct saa7146_dev *dev) +{ + struct mxb *mxb = (struct mxb *)dev->ext_priv; + + DEB_EE(("dev:%p\n", dev)); + + i2c_release_client(mxb->tea6420_1); + i2c_release_client(mxb->tea6420_2); + i2c_release_client(mxb->tea6415c); + i2c_release_client(mxb->tda9840); + i2c_release_client(mxb->saa7111a); + i2c_release_client(mxb->tuner); + + saa7146_unregister_device(&mxb->video_dev,dev); + if (MXB_BOARD_CAN_DO_VBI(dev)) + saa7146_unregister_device(&mxb->vbi_dev, dev); + saa7146_vv_release(dev); + + mxb_num--; + + i2c_del_adapter(&mxb->i2c_adapter); + kfree(mxb); + return 0; } @@ -886,8 +909,6 @@ static struct saa7146_ext_vv vv_data = { .stds = &standard[0], .num_stds = sizeof(standard)/sizeof(struct saa7146_standard), .std_callback = &std_callback, - .ioctls = &ioctls[0], - .ioctl = mxb_ioctl, }; static struct saa7146_extension extension = { diff --git a/linux/include/media/cx2341x.h b/linux/include/media/cx2341x.h index 9ec4d5889..9ebe8558b 100644 --- a/linux/include/media/cx2341x.h +++ b/linux/include/media/cx2341x.h @@ -1,5 +1,5 @@ /* - cx23415/6 header containing common defines. + cx23415/6/8 header containing common defines. 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 @@ -28,6 +28,7 @@ enum cx2341x_port { enum cx2341x_cap { CX2341X_CAP_HAS_SLICED_VBI = 1 << 0, CX2341X_CAP_HAS_TS = 1 << 1, + CX2341X_CAP_HAS_AC3 = 1 << 2, }; struct cx2341x_mpeg_params { @@ -47,11 +48,12 @@ struct cx2341x_mpeg_params { enum v4l2_mpeg_audio_sampling_freq audio_sampling_freq; enum v4l2_mpeg_audio_encoding audio_encoding; enum v4l2_mpeg_audio_l2_bitrate audio_l2_bitrate; + enum v4l2_mpeg_audio_ac3_bitrate audio_ac3_bitrate; enum v4l2_mpeg_audio_mode audio_mode; enum v4l2_mpeg_audio_mode_extension audio_mode_extension; enum v4l2_mpeg_audio_emphasis audio_emphasis; enum v4l2_mpeg_audio_crc audio_crc; - u16 audio_properties; + u32 audio_properties; u16 audio_mute; /* video */ diff --git a/linux/include/media/saa7146_vv.h b/linux/include/media/saa7146_vv.h index c8d0b23fd..eed5fccc8 100644 --- a/linux/include/media/saa7146_vv.h +++ b/linux/include/media/saa7146_vv.h @@ -150,16 +150,6 @@ struct saa7146_vv unsigned int resources; /* resource management for device */ }; -#define SAA7146_EXCLUSIVE 0x1 -#define SAA7146_BEFORE 0x2 -#define SAA7146_AFTER 0x4 - -struct saa7146_extension_ioctls -{ - unsigned int cmd; - int flags; -}; - /* flags */ #define SAA7146_USE_PORT_B_FOR_VBI 0x2 /* use input port b for vbi hardware bug workaround */ @@ -176,8 +166,10 @@ struct saa7146_ext_vv int num_stds; int (*std_callback)(struct saa7146_dev*, struct saa7146_standard *); - struct saa7146_extension_ioctls *ioctls; - long (*ioctl)(struct saa7146_fh *, unsigned int cmd, void *arg); + /* the extension can override this */ + struct v4l2_ioctl_ops ops; + /* pointer to the saa7146 core ops */ + const struct v4l2_ioctl_ops *core_ops; struct v4l2_file_operations vbi_fops; }; @@ -213,6 +205,7 @@ void saa7146_set_hps_source_and_sync(struct saa7146_dev *saa, int source, int sy void saa7146_set_gpio(struct saa7146_dev *saa, u8 pin, u8 data); /* from saa7146_video.c */ +extern const struct v4l2_ioctl_ops saa7146_video_ioctl_ops; extern struct saa7146_use_ops saa7146_video_uops; int saa7146_start_preview(struct saa7146_fh *fh); int saa7146_stop_preview(struct saa7146_fh *fh); |