V4L/DVB (10271): saa7146: convert to video_ioctl2.
Hans Verkuil [Sun, 18 Jan 2009 22:59:11 +0000 (19:59 -0300)]
The conversion to video_ioctl2 is the first phase to converting this driver
to the latest v4l2 framework.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

drivers/media/common/saa7146_fops.c
drivers/media/common/saa7146_video.c
drivers/media/dvb/ttpci/av7110_v4l.c
drivers/media/dvb/ttpci/budget-av.c
drivers/media/video/hexium_gemini.c
drivers/media/video/hexium_orion.c
drivers/media/video/mxb.c
include/media/saa7146_vv.h

index cf06f4d..4a27d4e 100644 (file)
@@ -308,14 +308,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;
@@ -425,7 +417,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)
@@ -452,19 +444,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));
 
@@ -521,6 +510,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));
 
@@ -529,16 +519,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 ) {
index 47fee05..91b7a4d 100644 (file)
@@ -97,172 +97,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));
@@ -294,12 +135,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",
@@ -355,58 +197,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 */
 
@@ -463,132 +253,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: {
-               mutex_unlock(&dev->lock);
-               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 +493,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;
 
-       long err = 0;
-       int result = 0, ee = 0;
+       *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;
 
-       struct saa7146_use_ops *ops;
-       struct videobuf_queue *q;
+       DEB_EE(("VIDIOC_S_FBUF\n"));
 
-       /* 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;
+       if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
+               return -EPERM;
+
+       /* 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 (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 (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
-               ops = &saa7146_video_uops;
-               q = &fh->video_q;
+       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 +950,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                                                  */
index c5b9c70..0433405 100644 (file)
@@ -316,253 +316,260 @@ 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;
+}
+
+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;
 
-               dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency);
+       dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency);
 
-               if (!av7110->analog_tuner_flags || av7110->current_input != 1)
-                       return -EINVAL;
+       if (!av7110->analog_tuner_flags || av7110->current_input != 1)
+               return -EINVAL;
 
-               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;
+       memset(f, 0, sizeof(*f));
+       f->type = V4L2_TUNER_ANALOG_TV;
+       f->frequency =  av7110->current_freq;
+       return 0;
+}
 
-               dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x.\n", f->frequency);
+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 (!av7110->analog_tuner_flags || av7110->current_input != 1)
-                       return -EINVAL;
+       dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x.\n", f->frequency);
 
-               if (V4L2_TUNER_ANALOG_TV != f->type)
-                       return -EINVAL;
+       if (!av7110->analog_tuner_flags || av7110->current_input != 1)
+               return -EINVAL;
 
-               msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); // fast mute
-               msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0);
+       if (V4L2_TUNER_ANALOG_TV != f->type)
+               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;
+       msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); /* fast mute */
+       msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0);
 
-               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;
+       /* 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;
 
-               dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index);
+       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;
+}
 
-               if (av7110->analog_tuner_flags) {
-                       if (i->index < 0 || i->index >= 4)
-                               return -EINVAL;
-               } else {
-                       if (i->index != 0)
-                               return -EINVAL;
-               }
+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;
 
-               memcpy(i, &inputs[i->index], sizeof(struct v4l2_input));
+       dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index);
 
-               return 0;
+       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");
+       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;
        }
-       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 +616,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 +779,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 +905,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 +920,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,
index 4182121..855fe74 100644 (file)
@@ -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;
index 79393d1..8e1463e 100644 (file)
@@ -56,17 +56,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 },
@@ -231,6 +220,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 */
@@ -279,6 +394,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;
@@ -306,153 +427,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;
@@ -514,8 +488,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 = {
index 074bec7..2bc39f6 100644 (file)
@@ -57,14 +57,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;
@@ -329,6 +321,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 */
@@ -339,6 +369,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;
@@ -370,58 +403,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;
@@ -479,8 +460,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 = {
index e3cbe14..8ecda8d 100644 (file)
@@ -110,26 +110,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;
@@ -424,387 +404,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;
 }
 
@@ -885,8 +908,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 = {
index c8d0b23..eed5fcc 100644 (file)
@@ -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);