V4L/DVB (13555): v4l: Use video_device_node_name() instead of the minor number
[safe/jmp/linux-2.6] / drivers / media / video / saa7134 / saa7134-video.c
index 72f8673..9d26b1b 100644 (file)
@@ -1,5 +1,4 @@
 /*
- * $Id: saa7134-video.c,v 1.28 2005/02/15 15:59:35 kraxel Exp $
  *
  * device driver for philips saa7134 based TV cards
  * video4linux video interface
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/sort.h>
 
 #include "saa7134-reg.h"
 #include "saa7134.h"
-
-#define V4L2_I2C_CLIENTS 1
+#include <media/v4l2-common.h>
+#include <media/rds.h>
 
 /* ------------------------------------------------------------------ */
 
-static unsigned int video_debug   = 0;
+unsigned int video_debug;
 static unsigned int gbuffers      = 8;
-static unsigned int noninterlaced = 0;
+static unsigned int noninterlaced; /* 0 */
 static unsigned int gbufsize      = 720*576*4;
 static unsigned int gbufsize_max  = 720*576*4;
+static char secam[] = "--";
 module_param(video_debug, int, 0644);
 MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
 module_param(gbuffers, int, 0444);
 MODULE_PARM_DESC(gbuffers,"number of capture buffers, range 2-32");
 module_param(noninterlaced, int, 0644);
-MODULE_PARM_DESC(noninterlaced,"video input is noninterlaced");
+MODULE_PARM_DESC(noninterlaced,"capture non interlaced video");
+module_param_string(secam, secam, sizeof(secam), 0644);
+MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc");
+
 
-#define dprintk(fmt, arg...)   if (video_debug) \
+#define dprintk(fmt, arg...)   if (video_debug&0x04) \
        printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg)
 
 /* ------------------------------------------------------------------ */
+/* Defines for Video Output Port Register at address 0x191            */
+
+/* Bit 0: VIP code T bit polarity */
+
+#define VP_T_CODE_P_NON_INVERTED       0x00
+#define VP_T_CODE_P_INVERTED           0x01
+
+/* ------------------------------------------------------------------ */
+/* Defines for Video Output Port Register at address 0x195            */
+
+/* Bit 2: Video output clock delay control */
+
+#define VP_CLK_CTRL2_NOT_DELAYED       0x00
+#define VP_CLK_CTRL2_DELAYED           0x04
+
+/* Bit 1: Video output clock invert control */
+
+#define VP_CLK_CTRL1_NON_INVERTED      0x00
+#define VP_CLK_CTRL1_INVERTED          0x02
+
+/* ------------------------------------------------------------------ */
+/* Defines for Video Output Port Register at address 0x196            */
+
+/* Bits 2 to 0: VSYNC pin video vertical sync type */
+
+#define VP_VS_TYPE_MASK                        0x07
+
+#define VP_VS_TYPE_OFF                 0x00
+#define VP_VS_TYPE_V123                        0x01
+#define VP_VS_TYPE_V_ITU               0x02
+#define VP_VS_TYPE_VGATE_L             0x03
+#define VP_VS_TYPE_RESERVED1           0x04
+#define VP_VS_TYPE_RESERVED2           0x05
+#define VP_VS_TYPE_F_ITU               0x06
+#define VP_VS_TYPE_SC_FID              0x07
+
+/* ------------------------------------------------------------------ */
 /* data structs for video                                             */
 
 static int video_out[][9] = {
@@ -239,7 +279,43 @@ static struct saa7134_tvnorm tvnorms[] = {
                .id            = V4L2_STD_SECAM,
                NORM_625_50,
 
-               .sync_control  = 0x18, /* old: 0x58, */
+               .sync_control  = 0x18,
+               .luma_control  = 0x1b,
+               .chroma_ctrl1  = 0xd1,
+               .chroma_gain   = 0x80,
+               .chroma_ctrl2  = 0x00,
+               .vgate_misc    = 0x1c,
+
+       },{
+               .name          = "SECAM-DK",
+               .id            = V4L2_STD_SECAM_DK,
+               NORM_625_50,
+
+               .sync_control  = 0x18,
+               .luma_control  = 0x1b,
+               .chroma_ctrl1  = 0xd1,
+               .chroma_gain   = 0x80,
+               .chroma_ctrl2  = 0x00,
+               .vgate_misc    = 0x1c,
+
+       },{
+               .name          = "SECAM-L",
+               .id            = V4L2_STD_SECAM_L,
+               NORM_625_50,
+
+               .sync_control  = 0x18,
+               .luma_control  = 0x1b,
+               .chroma_ctrl1  = 0xd1,
+               .chroma_gain   = 0x80,
+               .chroma_ctrl2  = 0x00,
+               .vgate_misc    = 0x1c,
+
+       },{
+               .name          = "SECAM-Lc",
+               .id            = V4L2_STD_SECAM_LC,
+               NORM_625_50,
+
+               .sync_control  = 0x18,
                .luma_control  = 0x1b,
                .chroma_ctrl1  = 0xd1,
                .chroma_gain   = 0x80,
@@ -276,12 +352,12 @@ static struct saa7134_tvnorm tvnorms[] = {
 
                .h_start       = 0,
                .h_stop        = 719,
-               .video_v_start = 23,
-               .video_v_stop  = 262,
-               .vbi_v_start_0 = 10,
-               .vbi_v_stop_0  = 21,
-               .vbi_v_start_1 = 273,
-               .src_timing    = 7,
+               .video_v_start = 23,
+               .video_v_stop  = 262,
+               .vbi_v_start_0 = 10,
+               .vbi_v_stop_0  = 21,
+               .vbi_v_start_1 = 273,
+               .src_timing    = 7,
 
                .sync_control  = 0x18,
                .luma_control  = 0x40,
@@ -372,6 +448,7 @@ static const struct v4l2_queryctrl video_ctrls[] = {
                .name          = "y offset odd field",
                .minimum       = 0,
                .maximum       = 128,
+               .step          = 1,
                .default_value = 0,
                .type          = V4L2_CTRL_TYPE_INTEGER,
        },{
@@ -379,6 +456,7 @@ static const struct v4l2_queryctrl video_ctrls[] = {
                .name          = "y offset even field",
                .minimum       = 0,
                .maximum       = 128,
+               .step          = 1,
                .default_value = 0,
                .type          = V4L2_CTRL_TYPE_INTEGER,
        },{
@@ -422,28 +500,26 @@ static int res_get(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int
                return 1;
 
        /* is it free? */
-       down(&dev->lock);
+       mutex_lock(&dev->lock);
        if (dev->resources & bit) {
                /* no, someone else uses it */
-               up(&dev->lock);
+               mutex_unlock(&dev->lock);
                return 0;
        }
        /* it's free, grab it */
        fh->resources  |= bit;
        dev->resources |= bit;
        dprintk("res: get %d\n",bit);
-       up(&dev->lock);
+       mutex_unlock(&dev->lock);
        return 1;
 }
 
-static
-int res_check(struct saa7134_fh *fh, unsigned int bit)
+static int res_check(struct saa7134_fh *fh, unsigned int bit)
 {
        return (fh->resources & bit);
 }
 
-static
-int res_locked(struct saa7134_dev *dev, unsigned int bit)
+static int res_locked(struct saa7134_dev *dev, unsigned int bit)
 {
        return (dev->resources & bit);
 }
@@ -451,34 +527,22 @@ int res_locked(struct saa7134_dev *dev, unsigned int bit)
 static
 void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits)
 {
-       if ((fh->resources & bits) != bits)
-               BUG();
+       BUG_ON((fh->resources & bits) != bits);
 
-       down(&dev->lock);
+       mutex_lock(&dev->lock);
        fh->resources  &= ~bits;
        dev->resources &= ~bits;
        dprintk("res: put %d\n",bits);
-       up(&dev->lock);
+       mutex_unlock(&dev->lock);
 }
 
 /* ------------------------------------------------------------------ */
 
 static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
 {
-       int luma_control,sync_control,mux;
-
        dprintk("set tv norm = %s\n",norm->name);
        dev->tvnorm = norm;
 
-       mux = card_in(dev,dev->ctl_input).vmux;
-       luma_control = norm->luma_control;
-       sync_control = norm->sync_control;
-
-       if (mux > 5)
-               luma_control |= 0x80; /* svideo */
-       if (noninterlaced || dev->nosignal)
-               sync_control |= 0x20;
-
        /* setup cropping */
        dev->crop_bounds.left    = norm->h_start;
        dev->crop_defrect.left   = norm->h_start;
@@ -493,6 +557,33 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
 
        dev->crop_current = dev->crop_defrect;
 
+       saa7134_set_tvnorm_hw(dev);
+}
+
+static void video_mux(struct saa7134_dev *dev, int input)
+{
+       dprintk("video input = %d [%s]\n", input, card_in(dev, input).name);
+       dev->ctl_input = input;
+       set_tvnorm(dev, dev->tvnorm);
+       saa7134_tvaudio_setinput(dev, &card_in(dev, input));
+}
+
+
+static void saa7134_set_decoder(struct saa7134_dev *dev)
+{
+       int luma_control, sync_control, mux;
+
+       struct saa7134_tvnorm *norm = dev->tvnorm;
+       mux = card_in(dev, dev->ctl_input).vmux;
+
+       luma_control = norm->luma_control;
+       sync_control = norm->sync_control;
+
+       if (mux > 5)
+               luma_control |= 0x80; /* svideo */
+       if (noninterlaced || dev->nosignal)
+               sync_control |= 0x20;
+
        /* setup video decoder */
        saa_writeb(SAA7134_INCR_DELAY,            0x08);
        saa_writeb(SAA7134_ANALOG_IN_CTRL1,       0xc0 | mux);
@@ -507,9 +598,13 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
        saa_writeb(SAA7134_SYNC_CTRL,             sync_control);
        saa_writeb(SAA7134_LUMA_CTRL,             luma_control);
        saa_writeb(SAA7134_DEC_LUMA_BRIGHT,       dev->ctl_bright);
-       saa_writeb(SAA7134_DEC_LUMA_CONTRAST,     dev->ctl_contrast);
 
-       saa_writeb(SAA7134_DEC_CHROMA_SATURATION, dev->ctl_saturation);
+       saa_writeb(SAA7134_DEC_LUMA_CONTRAST,
+               dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast);
+
+       saa_writeb(SAA7134_DEC_CHROMA_SATURATION,
+               dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);
+
        saa_writeb(SAA7134_DEC_CHROMA_HUE,        dev->ctl_hue);
        saa_writeb(SAA7134_CHROMA_CTRL1,          norm->chroma_ctrl1);
        saa_writeb(SAA7134_CHROMA_GAIN,           norm->chroma_gain);
@@ -523,31 +618,17 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
        saa_writeb(SAA7134_MISC_VGATE_MSB,        norm->vgate_misc);
        saa_writeb(SAA7134_RAW_DATA_GAIN,         0x40);
        saa_writeb(SAA7134_RAW_DATA_OFFSET,       0x80);
-
-#ifdef V4L2_I2C_CLIENTS
-       saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id);
-#else
-       {
-               /* pass down info to the i2c chips (v4l1) */
-               struct video_channel c;
-               memset(&c,0,sizeof(c));
-               c.channel = dev->ctl_input;
-               c.norm = VIDEO_MODE_PAL;
-               if (norm->id & V4L2_STD_NTSC)
-                       c.norm = VIDEO_MODE_NTSC;
-               if (norm->id & V4L2_STD_SECAM)
-                       c.norm = VIDEO_MODE_SECAM;
-               saa7134_i2c_call_clients(dev,VIDIOCSCHAN,&c);
-       }
-#endif
 }
 
-static void video_mux(struct saa7134_dev *dev, int input)
+void saa7134_set_tvnorm_hw(struct saa7134_dev *dev)
 {
-       dprintk("video input = %d [%s]\n",input,card_in(dev,input).name);
-       dev->ctl_input = input;
-       set_tvnorm(dev,dev->tvnorm);
-       saa7134_tvaudio_setinput(dev,&card_in(dev,input));
+       saa7134_set_decoder(dev);
+
+       if (card_in(dev, dev->ctl_input).tv)
+               saa_call_all(dev, core, s_std, dev->tvnorm->id);
+       /* Set the correct norm for the saa6752hs. This function
+          does nothing if there is no saa6752hs. */
+       saa_call_empress(dev, core, s_std, dev->tvnorm->id);
 }
 
 static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale)
@@ -640,7 +721,7 @@ static void set_size(struct saa7134_dev *dev, int task,
                prescale = 1;
        xscale = 1024 * dev->crop_current.width / prescale / width;
        yscale = 512 * div * dev->crop_current.height / height;
-               dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale);
+       dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale);
        set_h_prescale(dev,task,prescale);
        saa_writeb(SAA7134_H_SCALE_INC1(task),      xscale &  0xff);
        saa_writeb(SAA7134_H_SCALE_INC2(task),      xscale >> 8);
@@ -668,25 +749,6 @@ struct cliplist {
        __u8  disable;
 };
 
-static void sort_cliplist(struct cliplist *cl, int entries)
-{
-       struct cliplist swap;
-       int i,j,n;
-
-       for (i = entries-2; i >= 0; i--) {
-               for (n = 0, j = 0; j <= i; j++) {
-                       if (cl[j].position > cl[j+1].position) {
-                               swap = cl[j];
-                               cl[j] = cl[j+1];
-                               cl[j+1] = swap;
-                               n++;
-                       }
-               }
-               if (0 == n)
-                       break;
-       }
-}
-
 static void set_cliplist(struct saa7134_dev *dev, int reg,
                        struct cliplist *cl, int entries, char *name)
 {
@@ -720,15 +782,27 @@ static int clip_range(int val)
        return val;
 }
 
+/* Sort into smallest position first order */
+static int cliplist_cmp(const void *a, const void *b)
+{
+       const struct cliplist *cla = a;
+       const struct cliplist *clb = b;
+       if (cla->position < clb->position)
+               return -1;
+       if (cla->position > clb->position)
+               return 1;
+       return 0;
+}
+
 static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips,
                          int nclips, int interlace)
 {
        struct cliplist col[16], row[16];
-       int cols, rows, i;
+       int cols = 0, rows = 0, i;
        int div = interlace ? 2 : 1;
 
-       memset(col,0,sizeof(col)); cols = 0;
-       memset(row,0,sizeof(row)); rows = 0;
+       memset(col, 0, sizeof(col));
+       memset(row, 0, sizeof(row));
        for (i = 0; i < nclips && i < 8; i++) {
                col[cols].position = clip_range(clips[i].c.left);
                col[cols].enable   = (1 << i);
@@ -744,8 +818,8 @@ static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips,
                row[rows].disable  = (1 << i);
                rows++;
        }
-       sort_cliplist(col,cols);
-       sort_cliplist(row,rows);
+       sort(col, cols, sizeof col[0], cliplist_cmp, NULL);
+       sort(row, rows, sizeof row[0], cliplist_cmp, NULL);
        set_cliplist(dev,0x380,col,cols,"cols");
        set_cliplist(dev,0x384,row,rows,"rows");
        return 0;
@@ -770,20 +844,20 @@ static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win)
        maxh  = dev->crop_current.height;
 
        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:
-                maxh = maxh / 2;
-                break;
-        case V4L2_FIELD_INTERLACED:
-                break;
-        default:
-                return -EINVAL;
-        }
+               field = (win->w.height > maxh/2)
+                       ? V4L2_FIELD_INTERLACED
+                       : V4L2_FIELD_TOP;
+       }
+       switch (field) {
+       case V4L2_FIELD_TOP:
+       case V4L2_FIELD_BOTTOM:
+               maxh = maxh / 2;
+               break;
+       case V4L2_FIELD_INTERLACED:
+               break;
+       default:
+               return -EINVAL;
+       }
 
        win->field = field;
        if (win->w.width > maxw)
@@ -865,7 +939,7 @@ static int buffer_activate(struct saa7134_dev *dev,
        unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */
 
        dprintk("buffer_activate buf=%p\n",buf);
-       buf->vb.state = STATE_ACTIVE;
+       buf->vb.state = VIDEOBUF_ACTIVE;
        buf->top_seen = 0;
 
        set_size(dev,TASK_A,buf->vb.width,buf->vb.height,
@@ -971,33 +1045,36 @@ static int buffer_prepare(struct videobuf_queue *q,
            buf->vb.size   != size       ||
            buf->vb.field  != field      ||
            buf->fmt       != fh->fmt) {
-               saa7134_dma_free(dev,buf);
+               saa7134_dma_free(q,buf);
        }
 
-       if (STATE_NEEDS_INIT == buf->vb.state) {
+       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+               struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
                buf->vb.width  = fh->width;
                buf->vb.height = fh->height;
                buf->vb.size   = size;
                buf->vb.field  = field;
                buf->fmt       = fh->fmt;
                buf->pt        = &fh->pt_cap;
+               dev->video_q.curr = NULL;
 
-               err = videobuf_iolock(dev->pci,&buf->vb,&dev->ovbuf);
+               err = videobuf_iolock(q,&buf->vb,&dev->ovbuf);
                if (err)
                        goto oops;
                err = saa7134_pgtable_build(dev->pci,buf->pt,
-                                           buf->vb.dma.sglist,
-                                           buf->vb.dma.sglen,
+                                           dma->sglist,
+                                           dma->sglen,
                                            saa7134_buffer_startpage(buf));
                if (err)
                        goto oops;
        }
-       buf->vb.state = STATE_PREPARED;
+       buf->vb.state = VIDEOBUF_PREPARED;
        buf->activate = buffer_activate;
        return 0;
 
  oops:
-       saa7134_dma_free(dev,buf);
+       saa7134_dma_free(q,buf);
        return err;
 }
 
@@ -1023,10 +1100,9 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
 
 static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
-       struct saa7134_fh *fh = q->priv_data;
        struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
 
-       saa7134_dma_free(fh->dev,buf);
+       saa7134_dma_free(q,buf);
 }
 
 static struct videobuf_queue_ops video_qops = {
@@ -1038,7 +1114,7 @@ static struct videobuf_queue_ops video_qops = {
 
 /* ------------------------------------------------------------------ */
 
-static int get_control(struct saa7134_dev *dev, struct v4l2_control *c)
+int saa7134_g_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c)
 {
        const struct v4l2_queryctrl* ctrl;
 
@@ -1084,17 +1160,38 @@ static int get_control(struct saa7134_dev *dev, struct v4l2_control *c)
        }
        return 0;
 }
+EXPORT_SYMBOL_GPL(saa7134_g_ctrl_internal);
+
+static int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c)
+{
+       struct saa7134_fh *fh = priv;
+
+       return saa7134_g_ctrl_internal(fh->dev, fh, c);
+}
 
-static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh,
-                      struct v4l2_control *c)
+int saa7134_s_ctrl_internal(struct saa7134_dev *dev,  struct saa7134_fh *fh, struct v4l2_control *c)
 {
        const struct v4l2_queryctrl* ctrl;
        unsigned long flags;
        int restart_overlay = 0;
+       int err;
+
+       /* When called from the empress code fh == NULL.
+          That needs to be fixed somehow, but for now this is
+          good enough. */
+       if (fh) {
+               err = v4l2_prio_check(&dev->prio, &fh->prio);
+               if (0 != err)
+                       return err;
+       }
+       err = -EINVAL;
+
+       mutex_lock(&dev->lock);
 
        ctrl = ctrl_by_id(c->id);
        if (NULL == ctrl)
-               return -EINVAL;
+               goto error;
+
        dprintk("set_control name=%s val=%d\n",ctrl->name,c->value);
        switch (ctrl->type) {
        case V4L2_CTRL_TYPE_BOOLEAN:
@@ -1155,18 +1252,25 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh,
                restart_overlay = 1;
                break;
        case V4L2_CID_PRIVATE_AUTOMUTE:
+       {
+               struct v4l2_priv_tun_config tda9887_cfg;
+
+               tda9887_cfg.tuner = TUNER_TDA9887;
+               tda9887_cfg.priv = &dev->tda9887_conf;
+
                dev->ctl_automute = c->value;
                if (dev->tda9887_conf) {
                        if (dev->ctl_automute)
                                dev->tda9887_conf |= TDA9887_AUTOMUTE;
                        else
                                dev->tda9887_conf &= ~TDA9887_AUTOMUTE;
-                       saa7134_i2c_call_clients(dev, TDA9887_SET_CONFIG,
-                                                &dev->tda9887_conf);
+
+                       saa_call_all(dev, tuner, s_config, &tda9887_cfg);
                }
                break;
+       }
        default:
-               return -EINVAL;
+               goto error;
        }
        if (restart_overlay && fh && res_check(fh, RESOURCE_OVERLAY)) {
                spin_lock_irqsave(&dev->slock,flags);
@@ -1174,7 +1278,19 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh,
                start_preview(dev,fh);
                spin_unlock_irqrestore(&dev->slock,flags);
        }
-       return 0;
+       err = 0;
+
+error:
+       mutex_unlock(&dev->lock);
+       return err;
+}
+EXPORT_SYMBOL_GPL(saa7134_s_ctrl_internal);
+
+static int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c)
+{
+       struct saa7134_fh *fh = f;
+
+       return saa7134_s_ctrl_internal(fh->dev, fh, c);
 }
 
 /* ------------------------------------------------------------------ */
@@ -1198,54 +1314,44 @@ static struct videobuf_queue* saa7134_queue(struct saa7134_fh *fh)
 
 static int saa7134_resource(struct saa7134_fh *fh)
 {
-       int res = 0;
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return RESOURCE_VIDEO;
 
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               res = RESOURCE_VIDEO;
-               break;
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               res = RESOURCE_VBI;
-               break;
-       default:
-               BUG();
-       }
-       return res;
+       if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               return RESOURCE_VBI;
+
+       BUG();
+       return 0;
 }
 
-static int video_open(struct inode *inode, struct file *file)
+static int video_open(struct file *file)
 {
-       int minor = iminor(inode);
-       struct saa7134_dev *h,*dev = NULL;
+       struct video_device *vdev = video_devdata(file);
+       struct saa7134_dev *dev = video_drvdata(file);
        struct saa7134_fh *fh;
-       struct list_head *list;
-       enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       enum v4l2_buf_type type = 0;
        int radio = 0;
 
-       list_for_each(list,&saa7134_devlist) {
-               h = list_entry(list, struct saa7134_dev, devlist);
-               if (h->video_dev && (h->video_dev->minor == minor))
-                       dev = h;
-               if (h->radio_dev && (h->radio_dev->minor == minor)) {
-                       radio = 1;
-                       dev = h;
-               }
-               if (h->vbi_dev && (h->vbi_dev->minor == minor)) {
-                       type = V4L2_BUF_TYPE_VBI_CAPTURE;
-                       dev = h;
-               }
+       switch (vdev->vfl_type) {
+       case VFL_TYPE_GRABBER:
+               type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               break;
+       case VFL_TYPE_VBI:
+               type = V4L2_BUF_TYPE_VBI_CAPTURE;
+               break;
+       case VFL_TYPE_RADIO:
+               radio = 1;
+               break;
        }
-       if (NULL == dev)
-               return -ENODEV;
 
-       dprintk("open minor=%d radio=%d type=%s\n",minor,radio,
-               v4l2_type_names[type]);
+       dprintk("open dev=%s radio=%d type=%s\n", video_device_node_name(vdev),
+               radio, v4l2_type_names[type]);
 
        /* allocate + initialize per filehandle data */
-       fh = kmalloc(sizeof(*fh),GFP_KERNEL);
+       fh = kzalloc(sizeof(*fh),GFP_KERNEL);
        if (NULL == fh)
                return -ENOMEM;
-       memset(fh,0,sizeof(*fh));
+
        file->private_data = fh;
        fh->dev      = dev;
        fh->radio    = radio;
@@ -1255,14 +1361,14 @@ static int video_open(struct inode *inode, struct file *file)
        fh->height   = 576;
        v4l2_prio_open(&dev->prio,&fh->prio);
 
-       videobuf_queue_init(&fh->cap, &video_qops,
-                           dev->pci, &dev->slock,
+       videobuf_queue_sg_init(&fh->cap, &video_qops,
+                           &dev->pci->dev, &dev->slock,
                            V4L2_BUF_TYPE_VIDEO_CAPTURE,
                            V4L2_FIELD_INTERLACED,
                            sizeof(struct saa7134_buf),
                            fh);
-       videobuf_queue_init(&fh->vbi, &saa7134_vbi_qops,
-                           dev->pci, &dev->slock,
+       videobuf_queue_sg_init(&fh->vbi, &saa7134_vbi_qops,
+                           &dev->pci->dev, &dev->slock,
                            V4L2_BUF_TYPE_VBI_CAPTURE,
                            V4L2_FIELD_SEQ_TB,
                            sizeof(struct saa7134_buf),
@@ -1273,12 +1379,12 @@ static int video_open(struct inode *inode, struct file *file)
        if (fh->radio) {
                /* switch to radio mode */
                saa7134_tvaudio_setinput(dev,&card(dev).radio);
-               saa7134_i2c_call_clients(dev,AUDC_SET_RADIO,NULL);
+               saa_call_all(dev, tuner, s_radio);
        } else {
                /* switch to video/vbi mode */
                video_mux(dev,dev->ctl_input);
        }
-        return 0;
+       return 0;
 }
 
 static ssize_t
@@ -1311,46 +1417,49 @@ video_poll(struct file *file, struct poll_table_struct *wait)
 {
        struct saa7134_fh *fh = file->private_data;
        struct videobuf_buffer *buf = NULL;
+       unsigned int rc = 0;
 
        if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
                return videobuf_poll_stream(file, &fh->vbi, wait);
 
        if (res_check(fh,RESOURCE_VIDEO)) {
+               mutex_lock(&fh->cap.vb_lock);
                if (!list_empty(&fh->cap.stream))
                        buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream);
        } else {
-               down(&fh->cap.lock);
+               mutex_lock(&fh->cap.vb_lock);
                if (UNSET == fh->cap.read_off) {
-                        /* need to capture a new frame */
-                       if (res_locked(fh->dev,RESOURCE_VIDEO)) {
-                                up(&fh->cap.lock);
-                                return POLLERR;
-                        }
-                        if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) {
-                                up(&fh->cap.lock);
-                                return POLLERR;
-                        }
-                        fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
-                        fh->cap.read_off = 0;
+                       /* need to capture a new frame */
+                       if (res_locked(fh->dev,RESOURCE_VIDEO))
+                               goto err;
+                       if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field))
+                               goto err;
+                       fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
+                       fh->cap.read_off = 0;
                }
-               up(&fh->cap.lock);
                buf = fh->cap.read_buf;
        }
 
        if (!buf)
-               return POLLERR;
+               goto err;
 
        poll_wait(file, &buf->done, wait);
-       if (buf->state == STATE_DONE ||
-           buf->state == STATE_ERROR)
-               return POLLIN|POLLRDNORM;
-       return 0;
+       if (buf->state == VIDEOBUF_DONE ||
+           buf->state == VIDEOBUF_ERROR)
+               rc = POLLIN|POLLRDNORM;
+       mutex_unlock(&fh->cap.vb_lock);
+       return rc;
+
+err:
+       mutex_unlock(&fh->cap.vb_lock);
+       return POLLERR;
 }
 
-static int video_release(struct inode *inode, struct file *file)
+static int video_release(struct file *file)
 {
        struct saa7134_fh  *fh  = file->private_data;
        struct saa7134_dev *dev = fh->dev;
+       struct rds_command cmd;
        unsigned long flags;
 
        /* turn off overlay */
@@ -1373,13 +1482,20 @@ static int video_release(struct inode *inode, struct file *file)
 
        /* stop vbi capture */
        if (res_check(fh, RESOURCE_VBI)) {
-               if (fh->vbi.streaming)
-                       videobuf_streamoff(&fh->vbi);
-               if (fh->vbi.reading)
-                       videobuf_read_stop(&fh->vbi);
+               videobuf_stop(&fh->vbi);
                res_free(dev,fh,RESOURCE_VBI);
        }
 
+       /* ts-capture will not work in planar mode, so turn it off Hac: 04.05*/
+       saa_andorb(SAA7134_OFMT_VIDEO_A, 0x1f, 0);
+       saa_andorb(SAA7134_OFMT_VIDEO_B, 0x1f, 0);
+       saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0);
+       saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0);
+
+       saa_call_all(dev, core, s_power, 0);
+       if (fh->radio)
+               saa_call_all(dev, core, ioctl, RDS_CMD_CLOSE, &cmd);
+
        /* free stuff */
        videobuf_mmap_free(&fh->cap);
        videobuf_mmap_free(&fh->vbi);
@@ -1392,18 +1508,51 @@ static int video_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-static int
-video_mmap(struct file *file, struct vm_area_struct * vma)
+static int video_mmap(struct file *file, struct vm_area_struct * vma)
 {
        struct saa7134_fh *fh = file->private_data;
 
        return videobuf_mmap_mapper(saa7134_queue(fh), vma);
 }
 
+static ssize_t radio_read(struct file *file, char __user *data,
+                        size_t count, loff_t *ppos)
+{
+       struct saa7134_fh *fh = file->private_data;
+       struct saa7134_dev *dev = fh->dev;
+       struct rds_command cmd;
+
+       cmd.block_count = count/3;
+       cmd.buffer = data;
+       cmd.instance = file;
+       cmd.result = -ENODEV;
+
+       saa_call_all(dev, core, ioctl, RDS_CMD_READ, &cmd);
+
+       return cmd.result;
+}
+
+static unsigned int radio_poll(struct file *file, poll_table *wait)
+{
+       struct saa7134_fh *fh = file->private_data;
+       struct saa7134_dev *dev = fh->dev;
+       struct rds_command cmd;
+
+       cmd.instance = file;
+       cmd.event_list = wait;
+       cmd.result = -ENODEV;
+       saa_call_all(dev, core, ioctl, RDS_CMD_POLL, &cmd);
+
+       return cmd.result;
+}
+
 /* ------------------------------------------------------------------ */
 
-static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f)
+static int saa7134_try_get_set_fmt_vbi_cap(struct file *file, void *priv,
+                                               struct v4l2_format *f)
 {
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
        struct saa7134_tvnorm *norm = dev->tvnorm;
 
        f->fmt.vbi.sampling_rate = 6750000 * 4;
@@ -1416,816 +1565,842 @@ static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f)
        f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
        f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */
 
-#if 0
-       if (V4L2_STD_PAL == norm->id) {
-               /* FIXME */
-               f->fmt.vbi.start[0] += 3;
-               f->fmt.vbi.start[1] += 3*2;
-       }
-#endif
+       return 0;
 }
 
-static int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
-                        struct v4l2_format *f)
+static int saa7134_g_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
 {
-       switch (f->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
-               f->fmt.pix.width        = fh->width;
-               f->fmt.pix.height       = fh->height;
-               f->fmt.pix.field        = fh->cap.field;
-               f->fmt.pix.pixelformat  = fh->fmt->fourcc;
-               f->fmt.pix.bytesperline =
-                       (f->fmt.pix.width * fh->fmt->depth) >> 3;
-               f->fmt.pix.sizeimage =
-                       f->fmt.pix.height * f->fmt.pix.bytesperline;
-               return 0;
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-               f->fmt.win = fh->win;
-               return 0;
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               saa7134_vbi_fmt(dev,f);
-               return 0;
-       default:
-               return -EINVAL;
-       }
+       struct saa7134_fh *fh = priv;
+
+       f->fmt.pix.width        = fh->width;
+       f->fmt.pix.height       = fh->height;
+       f->fmt.pix.field        = fh->cap.field;
+       f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+       f->fmt.pix.bytesperline =
+               (f->fmt.pix.width * fh->fmt->depth) >> 3;
+       f->fmt.pix.sizeimage =
+               f->fmt.pix.height * f->fmt.pix.bytesperline;
+       return 0;
 }
 
-static int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
-                          struct v4l2_format *f)
+static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv,
+                               struct v4l2_format *f)
 {
-       int err;
+       struct saa7134_fh *fh = priv;
 
-       switch (f->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-       {
-               struct saa7134_format *fmt;
-               enum v4l2_field field;
-               unsigned int maxw, maxh;
+       if (saa7134_no_overlay > 0) {
+               printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+               return -EINVAL;
+       }
+       f->fmt.win = fh->win;
 
-               fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-               if (NULL == fmt)
-                       return -EINVAL;
+       return 0;
+}
 
-               field = f->fmt.pix.field;
-               maxw  = min(dev->crop_current.width*4,  dev->crop_bounds.width);
-               maxh  = min(dev->crop_current.height*4, dev->crop_bounds.height);
+static int saa7134_try_fmt_vid_cap(struct file *file, void *priv,
+                                               struct v4l2_format *f)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_format *fmt;
+       enum v4l2_field field;
+       unsigned int maxw, maxh;
 
-               if (V4L2_FIELD_ANY == field) {
-                       field = (f->fmt.pix.height > maxh/2)
-                               ? V4L2_FIELD_INTERLACED
-                               : V4L2_FIELD_BOTTOM;
-               }
-               switch (field) {
-               case V4L2_FIELD_TOP:
-               case V4L2_FIELD_BOTTOM:
-                       maxh = maxh / 2;
-                       break;
-               case V4L2_FIELD_INTERLACED:
-                       break;
-               default:
-                       return -EINVAL;
-               }
+       fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+       if (NULL == fmt)
+               return -EINVAL;
 
-               f->fmt.pix.field = field;
-               if (f->fmt.pix.width  < 48)
-                       f->fmt.pix.width  = 48;
-               if (f->fmt.pix.height < 32)
-                       f->fmt.pix.height = 32;
-               if (f->fmt.pix.width > maxw)
-                       f->fmt.pix.width = maxw;
-               if (f->fmt.pix.height > maxh)
-                       f->fmt.pix.height = maxh;
-               f->fmt.pix.width &= ~0x03;
-               f->fmt.pix.bytesperline =
-                       (f->fmt.pix.width * fmt->depth) >> 3;
-               f->fmt.pix.sizeimage =
-                       f->fmt.pix.height * f->fmt.pix.bytesperline;
+       field = f->fmt.pix.field;
+       maxw  = min(dev->crop_current.width*4,  dev->crop_bounds.width);
+       maxh  = min(dev->crop_current.height*4, dev->crop_bounds.height);
 
-               return 0;
-       }
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-               err = verify_preview(dev,&f->fmt.win);
-               if (0 != err)
-                       return err;
-               return 0;
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               saa7134_vbi_fmt(dev,f);
-               return 0;
+       if (V4L2_FIELD_ANY == field) {
+               field = (f->fmt.pix.height > maxh/2)
+                       ? V4L2_FIELD_INTERLACED
+                       : V4L2_FIELD_BOTTOM;
+       }
+       switch (field) {
+       case V4L2_FIELD_TOP:
+       case V4L2_FIELD_BOTTOM:
+               maxh = maxh / 2;
+               break;
+       case V4L2_FIELD_INTERLACED:
+               break;
        default:
                return -EINVAL;
        }
-}
-
-static int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
-                        struct v4l2_format *f)
-{
-       unsigned long flags;
-       int err;
 
-       switch (f->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               err = saa7134_try_fmt(dev,fh,f);
-               if (0 != err)
-                       return err;
+       f->fmt.pix.field = field;
+       v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2,
+                             &f->fmt.pix.height, 32, maxh, 0, 0);
+       f->fmt.pix.bytesperline =
+               (f->fmt.pix.width * fmt->depth) >> 3;
+       f->fmt.pix.sizeimage =
+               f->fmt.pix.height * f->fmt.pix.bytesperline;
 
-               fh->fmt       = format_by_fourcc(f->fmt.pix.pixelformat);
-               fh->width     = f->fmt.pix.width;
-               fh->height    = f->fmt.pix.height;
-               fh->cap.field = f->fmt.pix.field;
-               return 0;
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-               err = verify_preview(dev,&f->fmt.win);
-               if (0 != err)
-                       return err;
+       return 0;
+}
 
-               down(&dev->lock);
-               fh->win    = f->fmt.win;
-               fh->nclips = f->fmt.win.clipcount;
-               if (fh->nclips > 8)
-                       fh->nclips = 8;
-               if (copy_from_user(fh->clips,f->fmt.win.clips,
-                                  sizeof(struct v4l2_clip)*fh->nclips)) {
-                       up(&dev->lock);
-                       return -EFAULT;
-               }
+static int saa7134_try_fmt_vid_overlay(struct file *file, void *priv,
+                                               struct v4l2_format *f)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
 
-               if (res_check(fh, RESOURCE_OVERLAY)) {
-                       spin_lock_irqsave(&dev->slock,flags);
-                       stop_preview(dev,fh);
-                       start_preview(dev,fh);
-                       spin_unlock_irqrestore(&dev->slock,flags);
-               }
-               up(&dev->lock);
-               return 0;
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               saa7134_vbi_fmt(dev,f);
-               return 0;
-       default:
+       if (saa7134_no_overlay > 0) {
+               printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
                return -EINVAL;
        }
+
+       return verify_preview(dev, &f->fmt.win);
 }
 
-int saa7134_common_ioctl(struct saa7134_dev *dev,
-                        unsigned int cmd, void *arg)
+static int saa7134_s_fmt_vid_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
 {
+       struct saa7134_fh *fh = priv;
        int err;
 
-       switch (cmd) {
-       case VIDIOC_QUERYCTRL:
-       {
-               const struct v4l2_queryctrl *ctrl;
-               struct v4l2_queryctrl *c = arg;
+       err = saa7134_try_fmt_vid_cap(file, priv, f);
+       if (0 != err)
+               return err;
 
-               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);
-               *c = (NULL != ctrl) ? *ctrl : no_ctrl;
-               return 0;
+       fh->fmt       = format_by_fourcc(f->fmt.pix.pixelformat);
+       fh->width     = f->fmt.pix.width;
+       fh->height    = f->fmt.pix.height;
+       fh->cap.field = f->fmt.pix.field;
+       return 0;
+}
+
+static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+       int err;
+       unsigned long flags;
+
+       if (saa7134_no_overlay > 0) {
+               printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+               return -EINVAL;
        }
-       case VIDIOC_G_CTRL:
-               return get_control(dev,arg);
-       case VIDIOC_S_CTRL:
-       {
-               down(&dev->lock);
-               err = set_control(dev,NULL,arg);
-               up(&dev->lock);
+       err = verify_preview(dev, &f->fmt.win);
+       if (0 != err)
                return err;
+
+       mutex_lock(&dev->lock);
+
+       fh->win    = f->fmt.win;
+       fh->nclips = f->fmt.win.clipcount;
+
+       if (fh->nclips > 8)
+               fh->nclips = 8;
+
+       if (copy_from_user(fh->clips, f->fmt.win.clips,
+                          sizeof(struct v4l2_clip)*fh->nclips)) {
+               mutex_unlock(&dev->lock);
+               return -EFAULT;
        }
-       /* --- input switching --------------------------------------- */
-       case VIDIOC_ENUMINPUT:
-       {
-               struct v4l2_input *i = arg;
-               unsigned int n;
 
-               n = i->index;
-               if (n >= SAA7134_INPUT_MAX)
-                       return -EINVAL;
-               if (NULL == card_in(dev,i->index).name)
-                       return -EINVAL;
-               memset(i,0,sizeof(*i));
-               i->index = n;
-               i->type  = V4L2_INPUT_TYPE_CAMERA;
-               strcpy(i->name,card_in(dev,n).name);
-               if (card_in(dev,n).tv)
-                       i->type = V4L2_INPUT_TYPE_TUNER;
-               i->audioset = 1;
-               if (n == dev->ctl_input) {
-                       int v1 = saa_readb(SAA7134_STATUS_VIDEO1);
-                       int v2 = saa_readb(SAA7134_STATUS_VIDEO2);
-
-                       if (0 != (v1 & 0x40))
-                               i->status |= V4L2_IN_ST_NO_H_LOCK;
-                       if (0 != (v2 & 0x40))
-                               i->status |= V4L2_IN_ST_NO_SYNC;
-                       if (0 != (v2 & 0x0e))
-                               i->status |= V4L2_IN_ST_MACROVISION;
-               }
-               for (n = 0; n < TVNORMS; n++)
-                       i->std |= tvnorms[n].id;
-               return 0;
-       }
-       case VIDIOC_G_INPUT:
-       {
-               int *i = arg;
-               *i = dev->ctl_input;
-               return 0;
+       if (res_check(fh, RESOURCE_OVERLAY)) {
+               spin_lock_irqsave(&dev->slock, flags);
+               stop_preview(dev, fh);
+               start_preview(dev, fh);
+               spin_unlock_irqrestore(&dev->slock, flags);
        }
-       case VIDIOC_S_INPUT:
-       {
-               int *i = arg;
 
-               if (*i < 0  ||  *i >= SAA7134_INPUT_MAX)
-                       return -EINVAL;
-               if (NULL == card_in(dev,*i).name)
-                       return -EINVAL;
-               down(&dev->lock);
-               video_mux(dev,*i);
-               up(&dev->lock);
-               return 0;
-       }
+       mutex_unlock(&dev->lock);
+       return 0;
+}
 
-       }
+int saa7134_queryctrl(struct file *file, void *priv, 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);
+       *c = (NULL != ctrl) ? *ctrl : no_ctrl;
        return 0;
 }
-EXPORT_SYMBOL(saa7134_common_ioctl);
+EXPORT_SYMBOL_GPL(saa7134_queryctrl);
 
-/*
- * This function is _not_ called directly, but from
- * video_generic_ioctl (and maybe others).  userspace
- * copying is done already, arg is a kernel pointer.
- */
-static int video_do_ioctl(struct inode *inode, struct file *file,
-                         unsigned int cmd, void *arg)
+static int saa7134_enum_input(struct file *file, void *priv,
+                                       struct v4l2_input *i)
 {
-       struct saa7134_fh *fh = file->private_data;
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+       unsigned int n;
+
+       n = i->index;
+       if (n >= SAA7134_INPUT_MAX)
+               return -EINVAL;
+       if (NULL == card_in(dev, i->index).name)
+               return -EINVAL;
+       memset(i, 0, sizeof(*i));
+       i->index = n;
+       i->type  = V4L2_INPUT_TYPE_CAMERA;
+       strcpy(i->name, card_in(dev, n).name);
+       if (card_in(dev, n).tv)
+               i->type = V4L2_INPUT_TYPE_TUNER;
+       i->audioset = 1;
+       if (n == dev->ctl_input) {
+               int v1 = saa_readb(SAA7134_STATUS_VIDEO1);
+               int v2 = saa_readb(SAA7134_STATUS_VIDEO2);
+
+               if (0 != (v1 & 0x40))
+                       i->status |= V4L2_IN_ST_NO_H_LOCK;
+               if (0 != (v2 & 0x40))
+                       i->status |= V4L2_IN_ST_NO_SYNC;
+               if (0 != (v2 & 0x0e))
+                       i->status |= V4L2_IN_ST_MACROVISION;
+       }
+       i->std = SAA7134_NORMS;
+       return 0;
+}
+
+static int saa7134_g_input(struct file *file, void *priv, unsigned int *i)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+
+       *i = dev->ctl_input;
+       return 0;
+}
+
+static int saa7134_s_input(struct file *file, void *priv, unsigned int i)
+{
+       struct saa7134_fh *fh = priv;
        struct saa7134_dev *dev = fh->dev;
-       unsigned long flags;
        int err;
 
-       if (video_debug > 1)
-               saa7134_print_ioctl(dev->name,cmd);
+       err = v4l2_prio_check(&dev->prio, &fh->prio);
+       if (0 != err)
+               return err;
 
-       switch (cmd) {
-       case VIDIOC_S_CTRL:
-       case VIDIOC_S_STD:
-       case VIDIOC_S_INPUT:
-       case VIDIOC_S_TUNER:
-       case VIDIOC_S_FREQUENCY:
-               err = v4l2_prio_check(&dev->prio,&fh->prio);
-               if (0 != err)
-                       return err;
-       }
+       if (i >= SAA7134_INPUT_MAX)
+               return -EINVAL;
+       if (NULL == card_in(dev, i).name)
+               return -EINVAL;
+       mutex_lock(&dev->lock);
+       video_mux(dev, i);
+       mutex_unlock(&dev->lock);
+       return 0;
+}
 
-       switch (cmd) {
-       case VIDIOC_QUERYCAP:
-       {
-               struct v4l2_capability *cap = arg;
-
-               memset(cap,0,sizeof(*cap));
-                strcpy(cap->driver, "saa7134");
-               strlcpy(cap->card, saa7134_boards[dev->board].name,
-                       sizeof(cap->card));
-               sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
-               cap->version = SAA7134_VERSION_CODE;
-               cap->capabilities =
-                       V4L2_CAP_VIDEO_CAPTURE |
-                       V4L2_CAP_VIDEO_OVERLAY |
-                       V4L2_CAP_VBI_CAPTURE |
-                       V4L2_CAP_TUNER |
-                       V4L2_CAP_READWRITE |
-                       V4L2_CAP_STREAMING;
+static int saa7134_querycap(struct file *file, void  *priv,
+                                       struct v4l2_capability *cap)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+
+       unsigned int tuner_type = dev->tuner_type;
+
+       strcpy(cap->driver, "saa7134");
+       strlcpy(cap->card, saa7134_boards[dev->board].name,
+               sizeof(cap->card));
+       sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+       cap->version = SAA7134_VERSION_CODE;
+       cap->capabilities =
+               V4L2_CAP_VIDEO_CAPTURE |
+               V4L2_CAP_VBI_CAPTURE |
+               V4L2_CAP_READWRITE |
+               V4L2_CAP_STREAMING |
+               V4L2_CAP_TUNER;
+       if (dev->has_rds)
+               cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
+       if (saa7134_no_overlay <= 0)
+               cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
+
+       if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET))
+               cap->capabilities &= ~V4L2_CAP_TUNER;
                return 0;
-       }
+}
 
-       /* --- tv standards ------------------------------------------ */
-       case VIDIOC_ENUMSTD:
-       {
-               struct v4l2_standard *e = arg;
-               unsigned int i;
+int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id *id)
+{
+       unsigned long flags;
+       unsigned int i;
+       v4l2_std_id fixup;
+       int err;
 
-               i = e->index;
-               if (i >= TVNORMS)
-                       return -EINVAL;
-               err = v4l2_video_std_construct(e, tvnorms[e->index].id,
-                                              tvnorms[e->index].name);
-               e->index = i;
-               if (err < 0)
+       /* When called from the empress code fh == NULL.
+          That needs to be fixed somehow, but for now this is
+          good enough. */
+       if (fh) {
+               err = v4l2_prio_check(&dev->prio, &fh->prio);
+               if (0 != err)
                        return err;
-               return 0;
+       } else if (res_locked(dev, RESOURCE_OVERLAY)) {
+               /* Don't change the std from the mpeg device
+                  if overlay is active. */
+               return -EBUSY;
        }
-       case VIDIOC_G_STD:
-       {
-               v4l2_std_id *id = arg;
 
-               *id = dev->tvnorm->id;
-               return 0;
-       }
-       case VIDIOC_S_STD:
-       {
-               v4l2_std_id *id = arg;
-               unsigned int i;
+       for (i = 0; i < TVNORMS; i++)
+               if (*id == tvnorms[i].id)
+                       break;
 
+       if (i == TVNORMS)
                for (i = 0; i < TVNORMS; i++)
-                       if (*id == tvnorms[i].id)
+                       if (*id & tvnorms[i].id)
                                break;
-               if (i == TVNORMS)
-                       for (i = 0; i < TVNORMS; i++)
-                               if (*id & tvnorms[i].id)
-                                       break;
-               if (i == TVNORMS)
-                       return -EINVAL;
+       if (i == TVNORMS)
+               return -EINVAL;
 
-               down(&dev->lock);
-               if (res_check(fh, RESOURCE_OVERLAY)) {
-                       spin_lock_irqsave(&dev->slock,flags);
-                       stop_preview(dev,fh);
-                       set_tvnorm(dev,&tvnorms[i]);
-                       start_preview(dev,fh);
-                       spin_unlock_irqrestore(&dev->slock,flags);
-               } else
-                       set_tvnorm(dev,&tvnorms[i]);
-               saa7134_tvaudio_do_scan(dev);
-               up(&dev->lock);
-               return 0;
+       if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) {
+               if (secam[0] == 'L' || secam[0] == 'l') {
+                       if (secam[1] == 'C' || secam[1] == 'c')
+                               fixup = V4L2_STD_SECAM_LC;
+                       else
+                               fixup = V4L2_STD_SECAM_L;
+               } else {
+                       if (secam[0] == 'D' || secam[0] == 'd')
+                               fixup = V4L2_STD_SECAM_DK;
+                       else
+                               fixup = V4L2_STD_SECAM;
+               }
+               for (i = 0; i < TVNORMS; i++)
+                       if (fixup == tvnorms[i].id)
+                               break;
        }
 
-       case VIDIOC_CROPCAP:
-       {
-               struct v4l2_cropcap *cap = arg;
+       *id = tvnorms[i].id;
 
-               if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-                   cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-                       return -EINVAL;
-               cap->bounds  = dev->crop_bounds;
-               cap->defrect = dev->crop_defrect;
-               cap->pixelaspect.numerator   = 1;
-               cap->pixelaspect.denominator = 1;
-               if (dev->tvnorm->id & V4L2_STD_525_60) {
-                       cap->pixelaspect.numerator   = 11;
-                       cap->pixelaspect.denominator = 10;
-               }
-               if (dev->tvnorm->id & V4L2_STD_625_50) {
-                       cap->pixelaspect.numerator   = 54;
-                       cap->pixelaspect.denominator = 59;
-               }
-               return 0;
-       }
+       mutex_lock(&dev->lock);
+       if (fh && res_check(fh, RESOURCE_OVERLAY)) {
+               spin_lock_irqsave(&dev->slock, flags);
+               stop_preview(dev, fh);
+               spin_unlock_irqrestore(&dev->slock, flags);
 
-       case VIDIOC_G_CROP:
-       {
-               struct v4l2_crop * crop = arg;
+               set_tvnorm(dev, &tvnorms[i]);
 
-               if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-                   crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-                       return -EINVAL;
-               crop->c = dev->crop_current;
-               return 0;
-       }
-       case VIDIOC_S_CROP:
-       {
-               struct v4l2_crop *crop = arg;
-               struct v4l2_rect *b = &dev->crop_bounds;
+               spin_lock_irqsave(&dev->slock, flags);
+               start_preview(dev, fh);
+               spin_unlock_irqrestore(&dev->slock, flags);
+       } else
+               set_tvnorm(dev, &tvnorms[i]);
 
-               if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-                   crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-                       return -EINVAL;
-               if (crop->c.height < 0)
-                       return -EINVAL;
-               if (crop->c.width < 0)
-                       return -EINVAL;
+       saa7134_tvaudio_do_scan(dev);
+       mutex_unlock(&dev->lock);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(saa7134_s_std_internal);
 
-               if (res_locked(fh->dev,RESOURCE_OVERLAY))
-                       return -EBUSY;
-               if (res_locked(fh->dev,RESOURCE_VIDEO))
-                       return -EBUSY;
+static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct saa7134_fh *fh = priv;
 
-               if (crop->c.top < b->top)
-                       crop->c.top = b->top;
-               if (crop->c.top > b->top + b->height)
-                       crop->c.top = b->top + b->height;
-               if (crop->c.height > b->top - crop->c.top + b->height)
-                       crop->c.height = b->top - crop->c.top + b->height;
-
-               if (crop->c.left < b->left)
-                       crop->c.top = b->left;
-               if (crop->c.left > b->left + b->width)
-                       crop->c.top = b->left + b->width;
-               if (crop->c.width > b->left - crop->c.left + b->width)
-                       crop->c.width = b->left - crop->c.left + b->width;
-
-               dev->crop_current = crop->c;
-               return 0;
-       }
+       return saa7134_s_std_internal(fh->dev, fh, id);
+}
 
-       /* --- tuner ioctls ------------------------------------------ */
-       case VIDIOC_G_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
-               int n;
+static int saa7134_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
 
-               if (0 != t->index)
-                       return -EINVAL;
-               memset(t,0,sizeof(*t));
-               for (n = 0; n < SAA7134_INPUT_MAX; n++)
-                       if (card_in(dev,n).tv)
-                               break;
-               if (NULL != card_in(dev,n).name) {
-                       strcpy(t->name, "Television");
-                       t->capability = V4L2_TUNER_CAP_NORM |
-                               V4L2_TUNER_CAP_STEREO |
-                               V4L2_TUNER_CAP_LANG1 |
-                               V4L2_TUNER_CAP_LANG2;
-                       t->rangehigh = 0xffffffffUL;
-                       t->rxsubchans = saa7134_tvaudio_getstereo(dev);
-                       t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans);
-               }
-               if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03))
-                       t->signal = 0xffff;
-               return 0;
-       }
-       case VIDIOC_S_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
-               int rx,mode;
+       *id = dev->tvnorm->id;
+       return 0;
+}
 
-               mode = dev->thread.mode;
-               if (UNSET == mode) {
-                       rx   = saa7134_tvaudio_getstereo(dev);
-                       mode = saa7134_tvaudio_rx2mode(t->rxsubchans);
-               }
-               if (mode != t->audmode) {
-                       dev->thread.mode = t->audmode;
-               }
-               return 0;
-       }
-       case VIDIOC_G_FREQUENCY:
-       {
-               struct v4l2_frequency *f = arg;
+static int saa7134_cropcap(struct file *file, void *priv,
+                                       struct v4l2_cropcap *cap)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
 
-               memset(f,0,sizeof(*f));
-               f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
-               f->frequency = dev->ctl_freq;
-               return 0;
+       if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+           cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+               return -EINVAL;
+       cap->bounds  = dev->crop_bounds;
+       cap->defrect = dev->crop_defrect;
+       cap->pixelaspect.numerator   = 1;
+       cap->pixelaspect.denominator = 1;
+       if (dev->tvnorm->id & V4L2_STD_525_60) {
+               cap->pixelaspect.numerator   = 11;
+               cap->pixelaspect.denominator = 10;
+       }
+       if (dev->tvnorm->id & V4L2_STD_625_50) {
+               cap->pixelaspect.numerator   = 54;
+               cap->pixelaspect.denominator = 59;
        }
-       case VIDIOC_S_FREQUENCY:
-       {
-               struct v4l2_frequency *f = arg;
+       return 0;
+}
 
-               if (0 != f->tuner)
-                       return -EINVAL;
-               if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
-                       return -EINVAL;
-               if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
-                       return -EINVAL;
-               down(&dev->lock);
-               dev->ctl_freq = f->frequency;
-#ifdef V4L2_I2C_CLIENTS
-               saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f);
-#else
-               saa7134_i2c_call_clients(dev,VIDIOCSFREQ,&dev->ctl_freq);
-#endif
-               saa7134_tvaudio_do_scan(dev);
-               up(&dev->lock);
-               return 0;
-       }
+static int saa7134_g_crop(struct file *file, void *f, struct v4l2_crop *crop)
+{
+       struct saa7134_fh *fh = f;
+       struct saa7134_dev *dev = fh->dev;
 
-       /* --- control ioctls ---------------------------------------- */
-       case VIDIOC_ENUMINPUT:
-       case VIDIOC_G_INPUT:
-       case VIDIOC_S_INPUT:
-       case VIDIOC_QUERYCTRL:
-       case VIDIOC_G_CTRL:
-       case VIDIOC_S_CTRL:
-               return saa7134_common_ioctl(dev, cmd, arg);
+       if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+           crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+               return -EINVAL;
+       crop->c = dev->crop_current;
+       return 0;
+}
 
-       case VIDIOC_G_AUDIO:
-       {
-               struct v4l2_audio *a = arg;
+static int saa7134_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
+{
+       struct saa7134_fh *fh = f;
+       struct saa7134_dev *dev = fh->dev;
+       struct v4l2_rect *b = &dev->crop_bounds;
 
-               memset(a,0,sizeof(*a));
-               strcpy(a->name,"audio");
-               return 0;
-       }
-       case VIDIOC_S_AUDIO:
-               return 0;
-        case VIDIOC_G_PARM:
-        {
-                struct v4l2_captureparm *parm = arg;
-                memset(parm,0,sizeof(*parm));
-                return 0;
-        }
-
-        case VIDIOC_G_PRIORITY:
-        {
-                enum v4l2_priority *p = arg;
-
-                *p = v4l2_prio_max(&dev->prio);
-                return 0;
-        }
-        case VIDIOC_S_PRIORITY:
-        {
-                enum v4l2_priority *prio = arg;
-
-                return v4l2_prio_change(&dev->prio, &fh->prio, *prio);
-        }
-
-       /* --- preview ioctls ---------------------------------------- */
-       case VIDIOC_ENUM_FMT:
-       {
-               struct v4l2_fmtdesc *f = arg;
-               enum v4l2_buf_type type;
-               unsigned int index;
-
-               index = f->index;
-               type  = f->type;
-               switch (type) {
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-                       if (index >= FORMATS)
-                               return -EINVAL;
-                       if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY &&
-                           formats[index].planar)
-                               return -EINVAL;
-                       memset(f,0,sizeof(*f));
-                       f->index = index;
-                       f->type  = type;
-                       strlcpy(f->description,formats[index].name,sizeof(f->description));
-                       f->pixelformat = formats[index].fourcc;
-                       break;
-               case V4L2_BUF_TYPE_VBI_CAPTURE:
-                       if (0 != index)
-                               return -EINVAL;
-                       memset(f,0,sizeof(*f));
-                       f->index = index;
-                       f->type  = type;
-                       f->pixelformat = V4L2_PIX_FMT_GREY;
-                       strcpy(f->description,"vbi data");
+       if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+           crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+               return -EINVAL;
+       if (crop->c.height < 0)
+               return -EINVAL;
+       if (crop->c.width < 0)
+               return -EINVAL;
+
+       if (res_locked(fh->dev, RESOURCE_OVERLAY))
+               return -EBUSY;
+       if (res_locked(fh->dev, RESOURCE_VIDEO))
+               return -EBUSY;
+
+       if (crop->c.top < b->top)
+               crop->c.top = b->top;
+       if (crop->c.top > b->top + b->height)
+               crop->c.top = b->top + b->height;
+       if (crop->c.height > b->top - crop->c.top + b->height)
+               crop->c.height = b->top - crop->c.top + b->height;
+
+       if (crop->c.left < b->left)
+               crop->c.left = b->left;
+       if (crop->c.left > b->left + b->width)
+               crop->c.left = b->left + b->width;
+       if (crop->c.width > b->left - crop->c.left + b->width)
+               crop->c.width = b->left - crop->c.left + b->width;
+
+       dev->crop_current = crop->c;
+       return 0;
+}
+
+static int saa7134_g_tuner(struct file *file, void *priv,
+                                       struct v4l2_tuner *t)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+       int n;
+
+       if (0 != t->index)
+               return -EINVAL;
+       memset(t, 0, sizeof(*t));
+       for (n = 0; n < SAA7134_INPUT_MAX; n++)
+               if (card_in(dev, n).tv)
                        break;
-               default:
-                       return -EINVAL;
-               }
-               return 0;
-       }
-       case VIDIOC_G_FBUF:
-       {
-               struct v4l2_framebuffer *fb = arg;
+       if (NULL != card_in(dev, n).name) {
+               strcpy(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;
+               t->rangehigh = 0xffffffffUL;
+               t->rxsubchans = saa7134_tvaudio_getstereo(dev);
+               t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans);
+       }
+       if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03))
+               t->signal = 0xffff;
+       return 0;
+}
 
-               *fb = dev->ovbuf;
-               fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
-               return 0;
+static int saa7134_s_tuner(struct file *file, void *priv,
+                                       struct v4l2_tuner *t)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+       int rx, mode, err;
+
+       err = v4l2_prio_check(&dev->prio, &fh->prio);
+       if (0 != err)
+               return err;
+
+       mode = dev->thread.mode;
+       if (UNSET == mode) {
+               rx   = saa7134_tvaudio_getstereo(dev);
+               mode = saa7134_tvaudio_rx2mode(t->rxsubchans);
        }
-       case VIDIOC_S_FBUF:
-       {
-               struct v4l2_framebuffer *fb = arg;
-               struct saa7134_format *fmt;
+       if (mode != t->audmode)
+               dev->thread.mode = t->audmode;
 
-               if(!capable(CAP_SYS_ADMIN) &&
-                  !capable(CAP_SYS_RAWIO))
-                       return -EPERM;
+       return 0;
+}
 
-               /* check args */
-               fmt = format_by_fourcc(fb->fmt.pixelformat);
-               if (NULL == fmt)
-                       return -EINVAL;
+static int saa7134_g_frequency(struct file *file, void *priv,
+                                       struct v4l2_frequency *f)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
 
-               /* ok, accept it */
-               dev->ovbuf = *fb;
-               dev->ovfmt = fmt;
-               if (0 == dev->ovbuf.fmt.bytesperline)
-                       dev->ovbuf.fmt.bytesperline =
-                               dev->ovbuf.fmt.width*fmt->depth/8;
-               return 0;
+       f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+       f->frequency = dev->ctl_freq;
+
+       return 0;
+}
+
+static int saa7134_s_frequency(struct file *file, void *priv,
+                                       struct v4l2_frequency *f)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+       int err;
+
+       err = v4l2_prio_check(&dev->prio, &fh->prio);
+       if (0 != err)
+               return err;
+
+       if (0 != f->tuner)
+               return -EINVAL;
+       if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
+               return -EINVAL;
+       if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
+               return -EINVAL;
+       mutex_lock(&dev->lock);
+       dev->ctl_freq = f->frequency;
+
+       saa_call_all(dev, tuner, s_frequency, f);
+
+       saa7134_tvaudio_do_scan(dev);
+       mutex_unlock(&dev->lock);
+       return 0;
+}
+
+static int saa7134_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+       strcpy(a->name, "audio");
+       return 0;
+}
+
+static int saa7134_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+       return 0;
+}
+
+static int saa7134_g_priority(struct file *file, void *f, enum v4l2_priority *p)
+{
+       struct saa7134_fh *fh = f;
+       struct saa7134_dev *dev = fh->dev;
+
+       *p = v4l2_prio_max(&dev->prio);
+       return 0;
+}
+
+static int saa7134_s_priority(struct file *file, void *f,
+                                       enum v4l2_priority prio)
+{
+       struct saa7134_fh *fh = f;
+       struct saa7134_dev *dev = fh->dev;
+
+       return v4l2_prio_change(&dev->prio, &fh->prio, prio);
+}
+
+static int saa7134_enum_fmt_vid_cap(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       if (f->index >= FORMATS)
+               return -EINVAL;
+
+       strlcpy(f->description, formats[f->index].name,
+               sizeof(f->description));
+
+       f->pixelformat = formats[f->index].fourcc;
+
+       return 0;
+}
+
+static int saa7134_enum_fmt_vid_overlay(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       if (saa7134_no_overlay > 0) {
+               printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+               return -EINVAL;
        }
-       case VIDIOC_OVERLAY:
-       {
-               int *on = arg;
-
-               if (*on) {
-                       if (!res_get(dev,fh,RESOURCE_OVERLAY))
-                               return -EBUSY;
-                       spin_lock_irqsave(&dev->slock,flags);
-                       start_preview(dev,fh);
-                       spin_unlock_irqrestore(&dev->slock,flags);
-               }
-               if (!*on) {
-                       if (!res_check(fh, RESOURCE_OVERLAY))
-                               return -EINVAL;
-                       spin_lock_irqsave(&dev->slock,flags);
-                       stop_preview(dev,fh);
-                       spin_unlock_irqrestore(&dev->slock,flags);
-                       res_free(dev,fh,RESOURCE_OVERLAY);
+
+       if ((f->index >= FORMATS) || formats[f->index].planar)
+               return -EINVAL;
+
+       strlcpy(f->description, formats[f->index].name,
+               sizeof(f->description));
+
+       f->pixelformat = formats[f->index].fourcc;
+
+       return 0;
+}
+
+static int saa7134_g_fbuf(struct file *file, void *f,
+                               struct v4l2_framebuffer *fb)
+{
+       struct saa7134_fh *fh = f;
+       struct saa7134_dev *dev = fh->dev;
+
+       *fb = dev->ovbuf;
+       fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+
+       return 0;
+}
+
+static int saa7134_s_fbuf(struct file *file, void *f,
+                                       struct v4l2_framebuffer *fb)
+{
+       struct saa7134_fh *fh = f;
+       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_format *fmt;
+
+       if (!capable(CAP_SYS_ADMIN) &&
+          !capable(CAP_SYS_RAWIO))
+               return -EPERM;
+
+       /* check args */
+       fmt = format_by_fourcc(fb->fmt.pixelformat);
+       if (NULL == fmt)
+               return -EINVAL;
+
+       /* ok, accept it */
+       dev->ovbuf = *fb;
+       dev->ovfmt = fmt;
+       if (0 == dev->ovbuf.fmt.bytesperline)
+               dev->ovbuf.fmt.bytesperline =
+                       dev->ovbuf.fmt.width*fmt->depth/8;
+       return 0;
+}
+
+static int saa7134_overlay(struct file *file, void *f, unsigned int on)
+{
+       struct saa7134_fh *fh = f;
+       struct saa7134_dev *dev = fh->dev;
+       unsigned long flags;
+
+       if (on) {
+               if (saa7134_no_overlay > 0) {
+                       dprintk("no_overlay\n");
+                       return -EINVAL;
                }
-               return 0;
-       }
 
-       /* --- capture ioctls ---------------------------------------- */
-       case VIDIOC_G_FMT:
-       {
-               struct v4l2_format *f = arg;
-               return saa7134_g_fmt(dev,fh,f);
-       }
-       case VIDIOC_S_FMT:
-       {
-               struct v4l2_format *f = arg;
-               return saa7134_s_fmt(dev,fh,f);
+               if (!res_get(dev, fh, RESOURCE_OVERLAY))
+                       return -EBUSY;
+               spin_lock_irqsave(&dev->slock, flags);
+               start_preview(dev, fh);
+               spin_unlock_irqrestore(&dev->slock, flags);
        }
-       case VIDIOC_TRY_FMT:
-       {
-               struct v4l2_format *f = arg;
-               return saa7134_try_fmt(dev,fh,f);
+       if (!on) {
+               if (!res_check(fh, RESOURCE_OVERLAY))
+                       return -EINVAL;
+               spin_lock_irqsave(&dev->slock, flags);
+               stop_preview(dev, fh);
+               spin_unlock_irqrestore(&dev->slock, flags);
+               res_free(dev, fh, RESOURCE_OVERLAY);
        }
+       return 0;
+}
 
-       case VIDIOCGMBUF:
-       {
-               struct video_mbuf *mbuf = arg;
-               struct videobuf_queue *q;
-               struct v4l2_requestbuffers req;
-               unsigned int i;
-
-               q = saa7134_queue(fh);
-               memset(&req,0,sizeof(req));
-               req.type   = q->type;
-               req.count  = gbuffers;
-               req.memory = V4L2_MEMORY_MMAP;
-               err = videobuf_reqbufs(q,&req);
-               if (err < 0)
-                       return err;
-               memset(mbuf,0,sizeof(*mbuf));
-               mbuf->frames = req.count;
-               mbuf->size   = 0;
-               for (i = 0; i < mbuf->frames; i++) {
-                       mbuf->offsets[i]  = q->bufs[i]->boff;
-                       mbuf->size       += q->bufs[i]->bsize;
-               }
-               return 0;
-       }
-       case VIDIOC_REQBUFS:
-               return videobuf_reqbufs(saa7134_queue(fh),arg);
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+       struct saa7134_fh *fh = file->private_data;
+       return videobuf_cgmbuf(saa7134_queue(fh), mbuf, 8);
+}
+#endif
 
-       case VIDIOC_QUERYBUF:
-               return videobuf_querybuf(saa7134_queue(fh),arg);
+static int saa7134_reqbufs(struct file *file, void *priv,
+                                       struct v4l2_requestbuffers *p)
+{
+       struct saa7134_fh *fh = priv;
+       return videobuf_reqbufs(saa7134_queue(fh), p);
+}
 
-       case VIDIOC_QBUF:
-               return videobuf_qbuf(saa7134_queue(fh),arg);
+static int saa7134_querybuf(struct file *file, void *priv,
+                                       struct v4l2_buffer *b)
+{
+       struct saa7134_fh *fh = priv;
+       return videobuf_querybuf(saa7134_queue(fh), b);
+}
 
-       case VIDIOC_DQBUF:
-               return videobuf_dqbuf(saa7134_queue(fh),arg,
-                                     file->f_flags & O_NONBLOCK);
+static int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+       struct saa7134_fh *fh = priv;
+       return videobuf_qbuf(saa7134_queue(fh), b);
+}
 
-       case VIDIOC_STREAMON:
-       {
-               int res = saa7134_resource(fh);
+static int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+       struct saa7134_fh *fh = priv;
+       return videobuf_dqbuf(saa7134_queue(fh), b,
+                               file->f_flags & O_NONBLOCK);
+}
 
-                if (!res_get(dev,fh,res))
-                       return -EBUSY;
-               return videobuf_streamon(saa7134_queue(fh));
-       }
-       case VIDIOC_STREAMOFF:
-       {
-               int res = saa7134_resource(fh);
+static int saa7134_streamon(struct file *file, void *priv,
+                                       enum v4l2_buf_type type)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+       int res = saa7134_resource(fh);
 
-               err = videobuf_streamoff(saa7134_queue(fh));
-               if (err < 0)
-                       return err;
-               res_free(dev,fh,res);
-               return 0;
-       }
+       if (!res_get(dev, fh, res))
+               return -EBUSY;
 
-       default:
-               return v4l_compat_translate_ioctl(inode,file,cmd,arg,
-                                                 video_do_ioctl);
-       }
+       return videobuf_streamon(saa7134_queue(fh));
+}
+
+static int saa7134_streamoff(struct file *file, void *priv,
+                                       enum v4l2_buf_type type)
+{
+       int err;
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+       int res = saa7134_resource(fh);
+
+       err = videobuf_streamoff(saa7134_queue(fh));
+       if (err < 0)
+               return err;
+       res_free(dev, fh, res);
        return 0;
 }
 
-static int video_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg)
+static int saa7134_g_parm(struct file *file, void *fh,
+                               struct v4l2_streamparm *parm)
 {
-       return video_usercopy(inode, file, cmd, arg, video_do_ioctl);
+       return 0;
 }
 
-static int radio_do_ioctl(struct inode *inode, struct file *file,
-                         unsigned int cmd, void *arg)
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register (struct file *file, void *priv,
+                             struct v4l2_dbg_register *reg)
 {
-       struct saa7134_fh *fh = file->private_data;
+       struct saa7134_fh *fh = priv;
        struct saa7134_dev *dev = fh->dev;
 
-       if (video_debug > 1)
-               saa7134_print_ioctl(dev->name,cmd);
-       switch (cmd) {
-       case VIDIOC_QUERYCAP:
-       {
-               struct v4l2_capability *cap = arg;
-
-               memset(cap,0,sizeof(*cap));
-                strcpy(cap->driver, "saa7134");
-               strlcpy(cap->card, saa7134_boards[dev->board].name,
-                       sizeof(cap->card));
-               sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
-               cap->version = SAA7134_VERSION_CODE;
-               cap->capabilities = V4L2_CAP_TUNER;
-               return 0;
-       }
-       case VIDIOC_G_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
+       if (!v4l2_chip_match_host(&reg->match))
+               return -EINVAL;
+       reg->val = saa_readb(reg->reg);
+       reg->size = 1;
+       return 0;
+}
 
-               if (0 != t->index)
-                       return -EINVAL;
+static int vidioc_s_register (struct file *file, void *priv,
+                               struct v4l2_dbg_register *reg)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
 
-               memset(t,0,sizeof(*t));
-               strcpy(t->name, "Radio");
-                t->rangelow  = (int)(65*16);
-                t->rangehigh = (int)(108*16);
-
-#ifdef V4L2_I2C_CLIENTS
-               saa7134_i2c_call_clients(dev,VIDIOC_G_TUNER,t);
-#else
-               {
-                       struct video_tuner vt;
-                       memset(&vt,0,sizeof(vt));
-                       saa7134_i2c_call_clients(dev,VIDIOCGTUNER,&vt);
-                       t->signal = vt.signal;
-               }
+       if (!v4l2_chip_match_host(&reg->match))
+               return -EINVAL;
+       saa_writeb(reg->reg&0xffffff, reg->val);
+       return 0;
+}
 #endif
-               return 0;
-       }
-       case VIDIOC_ENUMINPUT:
-       {
-               struct v4l2_input *i = arg;
 
-               if (i->index != 0)
-                       return -EINVAL;
-               strcpy(i->name,"Radio");
-               i->type = V4L2_INPUT_TYPE_TUNER;
-               return 0;
-       }
-       case VIDIOC_G_INPUT:
-       {
-               int *i = arg;
-               *i = 0;
-               return 0;
-       }
-       case VIDIOC_G_AUDIO:
-       {
-               struct v4l2_audio *a = arg;
+static int radio_querycap(struct file *file, void *priv,
+                                       struct v4l2_capability *cap)
+{
+       struct saa7134_fh *fh = file->private_data;
+       struct saa7134_dev *dev = fh->dev;
 
-               memset(a,0,sizeof(*a));
-               strcpy(a->name,"Radio");
-               return 0;
-       }
-       case VIDIOC_G_STD:
-       {
-               v4l2_std_id *id = arg;
-               *id = 0;
-               return 0;
-       }
-       case VIDIOC_S_AUDIO:
-       case VIDIOC_S_TUNER:
-       case VIDIOC_S_INPUT:
-       case VIDIOC_S_STD:
-               return 0;
+       strcpy(cap->driver, "saa7134");
+       strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card));
+       sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+       cap->version = SAA7134_VERSION_CODE;
+       cap->capabilities = V4L2_CAP_TUNER;
+       return 0;
+}
 
-       case VIDIOC_QUERYCTRL:
-       {
-               const struct v4l2_queryctrl *ctrl;
-               struct v4l2_queryctrl *c = arg;
+static int radio_g_tuner(struct file *file, void *priv,
+                                       struct v4l2_tuner *t)
+{
+       struct saa7134_fh *fh = file->private_data;
+       struct saa7134_dev *dev = fh->dev;
 
-               if (c->id <  V4L2_CID_BASE ||
-                   c->id >= V4L2_CID_LASTP1)
-                       return -EINVAL;
-               if (c->id == V4L2_CID_AUDIO_MUTE) {
-                       ctrl = ctrl_by_id(c->id);
-                       *c = *ctrl;
-               } else
-                       *c = no_ctrl;
-               return 0;
-       }
+       if (0 != t->index)
+               return -EINVAL;
 
-       case VIDIOC_G_CTRL:
-       case VIDIOC_S_CTRL:
-       case VIDIOC_G_FREQUENCY:
-       case VIDIOC_S_FREQUENCY:
-               return video_do_ioctl(inode,file,cmd,arg);
+       memset(t, 0, sizeof(*t));
+       strcpy(t->name, "Radio");
+       t->type = V4L2_TUNER_RADIO;
 
-       default:
-               return v4l_compat_translate_ioctl(inode,file,cmd,arg,
-                                                 radio_do_ioctl);
+       saa_call_all(dev, tuner, g_tuner, t);
+       if (dev->input->amux == TV) {
+               t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11);
+               t->rxsubchans = (saa_readb(0x529) & 0x08) ?
+                               V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
        }
        return 0;
 }
+static int radio_s_tuner(struct file *file, void *priv,
+                                       struct v4l2_tuner *t)
+{
+       struct saa7134_fh *fh = file->private_data;
+       struct saa7134_dev *dev = fh->dev;
+
+       if (0 != t->index)
+               return -EINVAL;
+
+       saa_call_all(dev, tuner, s_tuner, t);
+       return 0;
+}
 
-static int radio_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg)
+static int radio_enum_input(struct file *file, void *priv,
+                                       struct v4l2_input *i)
 {
-       return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
+       if (i->index != 0)
+               return -EINVAL;
+
+       strcpy(i->name, "Radio");
+       i->type = V4L2_INPUT_TYPE_TUNER;
+
+       return 0;
+}
+
+static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+       *i = 0;
+       return 0;
 }
 
-static struct file_operations video_fops =
+static int radio_g_audio(struct file *file, void *priv,
+                                       struct v4l2_audio *a)
+{
+       memset(a, 0, sizeof(*a));
+       strcpy(a->name, "Radio");
+       return 0;
+}
+
+static int radio_s_audio(struct file *file, void *priv,
+                                       struct v4l2_audio *a)
+{
+       return 0;
+}
+
+static int radio_s_input(struct file *filp, void *priv, unsigned int i)
+{
+       return 0;
+}
+
+static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+       return 0;
+}
+
+static int radio_queryctrl(struct file *file, void *priv,
+                                       struct v4l2_queryctrl *c)
+{
+       const struct v4l2_queryctrl *ctrl;
+
+       if (c->id <  V4L2_CID_BASE ||
+           c->id >= V4L2_CID_LASTP1)
+               return -EINVAL;
+       if (c->id == V4L2_CID_AUDIO_MUTE) {
+               ctrl = ctrl_by_id(c->id);
+               *c = *ctrl;
+       } else
+               *c = no_ctrl;
+       return 0;
+}
+
+static const struct v4l2_file_operations video_fops =
 {
        .owner    = THIS_MODULE,
        .open     = video_open,
@@ -2233,48 +2408,103 @@ static struct file_operations video_fops =
        .read     = video_read,
        .poll     = video_poll,
        .mmap     = video_mmap,
-       .ioctl    = video_ioctl,
-       .llseek   = no_llseek,
+       .ioctl    = video_ioctl2,
 };
 
-static struct file_operations radio_fops =
-{
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+       .vidioc_querycap                = saa7134_querycap,
+       .vidioc_enum_fmt_vid_cap        = saa7134_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap           = saa7134_g_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap         = saa7134_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap           = saa7134_s_fmt_vid_cap,
+       .vidioc_enum_fmt_vid_overlay    = saa7134_enum_fmt_vid_overlay,
+       .vidioc_g_fmt_vid_overlay       = saa7134_g_fmt_vid_overlay,
+       .vidioc_try_fmt_vid_overlay     = saa7134_try_fmt_vid_overlay,
+       .vidioc_s_fmt_vid_overlay       = saa7134_s_fmt_vid_overlay,
+       .vidioc_g_fmt_vbi_cap           = saa7134_try_get_set_fmt_vbi_cap,
+       .vidioc_try_fmt_vbi_cap         = saa7134_try_get_set_fmt_vbi_cap,
+       .vidioc_s_fmt_vbi_cap           = saa7134_try_get_set_fmt_vbi_cap,
+       .vidioc_g_audio                 = saa7134_g_audio,
+       .vidioc_s_audio                 = saa7134_s_audio,
+       .vidioc_cropcap                 = saa7134_cropcap,
+       .vidioc_reqbufs                 = saa7134_reqbufs,
+       .vidioc_querybuf                = saa7134_querybuf,
+       .vidioc_qbuf                    = saa7134_qbuf,
+       .vidioc_dqbuf                   = saa7134_dqbuf,
+       .vidioc_s_std                   = saa7134_s_std,
+       .vidioc_g_std                   = saa7134_g_std,
+       .vidioc_enum_input              = saa7134_enum_input,
+       .vidioc_g_input                 = saa7134_g_input,
+       .vidioc_s_input                 = saa7134_s_input,
+       .vidioc_queryctrl               = saa7134_queryctrl,
+       .vidioc_g_ctrl                  = saa7134_g_ctrl,
+       .vidioc_s_ctrl                  = saa7134_s_ctrl,
+       .vidioc_streamon                = saa7134_streamon,
+       .vidioc_streamoff               = saa7134_streamoff,
+       .vidioc_g_tuner                 = saa7134_g_tuner,
+       .vidioc_s_tuner                 = saa7134_s_tuner,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+       .vidiocgmbuf                    = vidiocgmbuf,
+#endif
+       .vidioc_g_crop                  = saa7134_g_crop,
+       .vidioc_s_crop                  = saa7134_s_crop,
+       .vidioc_g_fbuf                  = saa7134_g_fbuf,
+       .vidioc_s_fbuf                  = saa7134_s_fbuf,
+       .vidioc_overlay                 = saa7134_overlay,
+       .vidioc_g_priority              = saa7134_g_priority,
+       .vidioc_s_priority              = saa7134_s_priority,
+       .vidioc_g_parm                  = saa7134_g_parm,
+       .vidioc_g_frequency             = saa7134_g_frequency,
+       .vidioc_s_frequency             = saa7134_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register              = vidioc_g_register,
+       .vidioc_s_register              = vidioc_s_register,
+#endif
+};
+
+static const struct v4l2_file_operations radio_fops = {
        .owner    = THIS_MODULE,
        .open     = video_open,
+       .read     = radio_read,
        .release  = video_release,
-       .ioctl    = radio_ioctl,
-       .llseek   = no_llseek,
+       .ioctl    = video_ioctl2,
+       .poll     = radio_poll,
+};
+
+static const struct v4l2_ioctl_ops radio_ioctl_ops = {
+       .vidioc_querycap        = radio_querycap,
+       .vidioc_g_tuner         = radio_g_tuner,
+       .vidioc_enum_input      = radio_enum_input,
+       .vidioc_g_audio         = radio_g_audio,
+       .vidioc_s_tuner         = radio_s_tuner,
+       .vidioc_s_audio         = radio_s_audio,
+       .vidioc_s_input         = radio_s_input,
+       .vidioc_s_std           = radio_s_std,
+       .vidioc_queryctrl       = radio_queryctrl,
+       .vidioc_g_input         = radio_g_input,
+       .vidioc_g_ctrl          = saa7134_g_ctrl,
+       .vidioc_s_ctrl          = saa7134_s_ctrl,
+       .vidioc_g_frequency     = saa7134_g_frequency,
+       .vidioc_s_frequency     = saa7134_s_frequency,
 };
 
 /* ----------------------------------------------------------- */
 /* exported stuff                                              */
 
-struct video_device saa7134_video_template =
-{
-       .name          = "saa7134-video",
-       .type          = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_OVERLAY|
-                        VID_TYPE_CLIPPING|VID_TYPE_SCALES,
-       .hardware      = 0,
-       .fops          = &video_fops,
-       .minor         = -1,
+struct video_device saa7134_video_template = {
+       .name                           = "saa7134-video",
+       .fops                           = &video_fops,
+       .ioctl_ops                      = &video_ioctl_ops,
+       .minor                          = -1,
+       .tvnorms                        = SAA7134_NORMS,
+       .current_norm                   = V4L2_STD_PAL,
 };
 
-struct video_device saa7134_vbi_template =
-{
-       .name          = "saa7134-vbi",
-       .type          = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
-       .hardware      = 0,
-       .fops          = &video_fops,
-       .minor         = -1,
-};
-
-struct video_device saa7134_radio_template =
-{
-       .name          = "saa7134-radio",
-       .type          = VID_TYPE_TUNER,
-       .hardware      = 0,
-       .fops          = &radio_fops,
-       .minor         = -1,
+struct video_device saa7134_radio_template = {
+       .name                   = "saa7134-radio",
+       .fops                   = &radio_fops,
+       .ioctl_ops              = &radio_ioctl_ops,
+       .minor                  = -1,
 };
 
 int saa7134_video_init1(struct saa7134_dev *dev)
@@ -2300,25 +2530,50 @@ int saa7134_video_init1(struct saa7134_dev *dev)
                dev->tda9887_conf |= TDA9887_AUTOMUTE;
        dev->automute       = 0;
 
-        INIT_LIST_HEAD(&dev->video_q.queue);
+       INIT_LIST_HEAD(&dev->video_q.queue);
        init_timer(&dev->video_q.timeout);
        dev->video_q.timeout.function = saa7134_buffer_timeout;
        dev->video_q.timeout.data     = (unsigned long)(&dev->video_q);
        dev->video_q.dev              = dev;
 
-       if (saa7134_boards[dev->board].video_out) {
-               /* enable video output */
-               int vo = saa7134_boards[dev->board].video_out;
-               saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]);
-               saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_out[vo][1]);
-               saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]);
-               saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]);
-               saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]);
-               saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_out[vo][5]);
-               saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_out[vo][6]);
-               saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]);
-               saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]);
-       }
+       if (saa7134_boards[dev->board].video_out)
+               saa7134_videoport_init(dev);
+
+       return 0;
+}
+
+int saa7134_videoport_init(struct saa7134_dev *dev)
+{
+       /* enable video output */
+       int vo = saa7134_boards[dev->board].video_out;
+       int video_reg;
+       unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts;
+
+       /* Configure videoport */
+       saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]);
+       video_reg = video_out[vo][1];
+       if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED)
+               video_reg &= ~VP_T_CODE_P_INVERTED;
+       saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg);
+       saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]);
+       saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]);
+       video_reg = video_out[vo][5];
+       if (vid_port_opts & SET_CLOCK_NOT_DELAYED)
+               video_reg &= ~VP_CLK_CTRL2_DELAYED;
+       if (vid_port_opts & SET_CLOCK_INVERTED)
+               video_reg |= VP_CLK_CTRL1_INVERTED;
+       saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg);
+       video_reg = video_out[vo][6];
+       if (vid_port_opts & SET_VSYNC_OFF) {
+               video_reg &= ~VP_VS_TYPE_MASK;
+               video_reg |= VP_VS_TYPE_OFF;
+       }
+       saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg);
+       saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]);
+       saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]);
+
+       /* Start videoport */
+       saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]);
 
        return 0;
 }
@@ -2333,13 +2588,7 @@ int saa7134_video_init2(struct saa7134_dev *dev)
        return 0;
 }
 
-int saa7134_video_fini(struct saa7134_dev *dev)
-{
-       /* nothing */
-       return 0;
-}
-
-void saa7134_irq_video_intl(struct saa7134_dev *dev)
+void saa7134_irq_video_signalchange(struct saa7134_dev *dev)
 {
        static const char *st[] = {
                "(no signal)", "NTSC", "PAL", "SECAM" };
@@ -2351,24 +2600,28 @@ void saa7134_irq_video_intl(struct saa7134_dev *dev)
                (st1 & 0x40) ? "not locked" : "locked",
                (st2 & 0x40) ? "no"         : "yes",
                st[st1 & 0x03]);
-       dev->nosignal = (st1 & 0x40) || (st2 & 0x40);
+       dev->nosignal = (st1 & 0x40) || (st2 & 0x40)  || !(st2 & 0x1);
 
        if (dev->nosignal) {
                /* no video signal -> mute audio */
                if (dev->ctl_automute)
                        dev->automute = 1;
                saa7134_tvaudio_setmute(dev);
-               saa_setb(SAA7134_SYNC_CTRL, 0x20);
        } else {
                /* wake up tvaudio audio carrier scan thread */
                saa7134_tvaudio_do_scan(dev);
-               if (!noninterlaced)
-                       saa_clearb(SAA7134_SYNC_CTRL, 0x20);
        }
+
+       if ((st2 & 0x80) && !noninterlaced && !dev->nosignal)
+               saa_clearb(SAA7134_SYNC_CTRL, 0x20);
+       else
+               saa_setb(SAA7134_SYNC_CTRL, 0x20);
+
        if (dev->mops && dev->mops->signal_change)
                dev->mops->signal_change(dev);
 }
 
+
 void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status)
 {
        enum v4l2_field field;
@@ -2393,7 +2646,7 @@ void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status)
                                goto done;
                }
                dev->video_q.curr->vb.field_count = dev->video_fieldcount;
-               saa7134_buffer_finish(dev,&dev->video_q,STATE_DONE);
+               saa7134_buffer_finish(dev,&dev->video_q,VIDEOBUF_DONE);
        }
        saa7134_buffer_next(dev,&dev->video_q);