Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / media / video / saa7134 / saa7134-video.c
index 4b70156..e4156ec 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ *
  * 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 "saa7134-reg.h"
 #include "saa7134.h"
+#include <media/v4l2-common.h>
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+/* Include V4L1 specific functions. Should be removed soon */
+#include <linux/videodev.h>
+#endif
 
 /* ------------------------------------------------------------------ */
 
 static unsigned int video_debug   = 0;
 static unsigned int gbuffers      = 8;
 static unsigned int noninterlaced = 0;
-static unsigned int gbufsize      = 768*576*4;
-static unsigned int gbufsize_max  = 768*576*4;
-MODULE_PARM(video_debug,"i");
+static unsigned int gbufsize      = 720*576*4;
+static unsigned int gbufsize_max  = 720*576*4;
+module_param(video_debug, int, 0644);
 MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
-MODULE_PARM(gbuffers,"i");
+module_param(gbuffers, int, 0444);
 MODULE_PARM_DESC(gbuffers,"number of capture buffers, range 2-32");
-MODULE_PARM(noninterlaced,"i");
+module_param(noninterlaced, int, 0644);
 MODULE_PARM_DESC(noninterlaced,"video input is noninterlaced");
 
 #define dprintk(fmt, arg...)   if (video_debug) \
        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] = {
        [CCIR656] = { 0x00, 0xb1, 0x00, 0xa1, 0x00, 0x04, 0x06, 0x00, 0x00 },
 };
-               
+
 static struct saa7134_format formats[] = {
        {
                .name     = "8 bpp gray",
@@ -148,10 +193,67 @@ static struct saa7134_format formats[] = {
 };
 #define FORMATS ARRAY_SIZE(formats)
 
+#define NORM_625_50                    \
+               .h_start       = 0,     \
+               .h_stop        = 719,   \
+               .video_v_start = 24,    \
+               .video_v_stop  = 311,   \
+               .vbi_v_start_0 = 7,     \
+               .vbi_v_stop_0  = 22,    \
+               .vbi_v_start_1 = 319,   \
+               .src_timing    = 4
+
+#define NORM_525_60                    \
+               .h_start       = 0,     \
+               .h_stop        = 703,   \
+               .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
+
 static struct saa7134_tvnorm tvnorms[] = {
        {
-               .name          = "PAL",
+               .name          = "PAL", /* autodetect */
                .id            = V4L2_STD_PAL,
+               NORM_625_50,
+
+               .sync_control  = 0x18,
+               .luma_control  = 0x40,
+               .chroma_ctrl1  = 0x81,
+               .chroma_gain   = 0x2a,
+               .chroma_ctrl2  = 0x06,
+               .vgate_misc    = 0x1c,
+
+       },{
+               .name          = "PAL-BG",
+               .id            = V4L2_STD_PAL_BG,
+               NORM_625_50,
+
+               .sync_control  = 0x18,
+               .luma_control  = 0x40,
+               .chroma_ctrl1  = 0x81,
+               .chroma_gain   = 0x2a,
+               .chroma_ctrl2  = 0x06,
+               .vgate_misc    = 0x1c,
+
+       },{
+               .name          = "PAL-I",
+               .id            = V4L2_STD_PAL_I,
+               NORM_625_50,
+
+               .sync_control  = 0x18,
+               .luma_control  = 0x40,
+               .chroma_ctrl1  = 0x81,
+               .chroma_gain   = 0x2a,
+               .chroma_ctrl2  = 0x06,
+               .vgate_misc    = 0x1c,
+
+       },{
+               .name          = "PAL-DK",
+               .id            = V4L2_STD_PAL_DK,
+               NORM_625_50,
 
                .sync_control  = 0x18,
                .luma_control  = 0x40,
@@ -160,16 +262,10 @@ static struct saa7134_tvnorm tvnorms[] = {
                .chroma_ctrl2  = 0x06,
                .vgate_misc    = 0x1c,
 
-               .h_start       = 0,
-               .h_stop        = 719,
-               .video_v_start = 24,
-               .video_v_stop  = 311,
-               .vbi_v_start   = 7,
-               .vbi_v_stop    = 22,
-               .src_timing    = 4,
        },{
                .name          = "NTSC",
                .id            = V4L2_STD_NTSC,
+               NORM_525_60,
 
                .sync_control  = 0x59,
                .luma_control  = 0x40,
@@ -178,16 +274,10 @@ static struct saa7134_tvnorm tvnorms[] = {
                .chroma_ctrl2  = 0x0e,
                .vgate_misc    = 0x18,
 
-               .h_start       = 0,
-               .h_stop        = 719,
-               .video_v_start = 22,
-               .video_v_stop  = 22+240,
-               .vbi_v_start   = 10, /* FIXME */
-               .vbi_v_stop    = 21, /* FIXME */
-               .src_timing    = 1,
        },{
                .name          = "SECAM",
                .id            = V4L2_STD_SECAM,
+               NORM_625_50,
 
                .sync_control  = 0x18, /* old: 0x58, */
                .luma_control  = 0x1b,
@@ -196,16 +286,10 @@ static struct saa7134_tvnorm tvnorms[] = {
                .chroma_ctrl2  = 0x00,
                .vgate_misc    = 0x1c,
 
-               .h_start       = 0,
-               .h_stop        = 719,
-               .video_v_start = 24,
-               .video_v_stop  = 311,
-               .vbi_v_start   = 7,
-               .vbi_v_stop    = 22,
-               .src_timing    = 4,
        },{
                .name          = "PAL-M",
                .id            = V4L2_STD_PAL_M,
+               NORM_525_60,
 
                .sync_control  = 0x59,
                .luma_control  = 0x40,
@@ -214,16 +298,10 @@ static struct saa7134_tvnorm tvnorms[] = {
                .chroma_ctrl2  = 0x0e,
                .vgate_misc    = 0x18,
 
-               .h_start       = 0,
-               .h_stop        = 719,
-               .video_v_start = 22,
-               .video_v_stop  = 22+240,
-               .vbi_v_start   = 10, /* FIXME */
-               .vbi_v_stop    = 21, /* FIXME */
-               .src_timing    = 1,
        },{
                .name          = "PAL-Nc",
                .id            = V4L2_STD_PAL_Nc,
+               NORM_625_50,
 
                .sync_control  = 0x18,
                .luma_control  = 0x40,
@@ -232,35 +310,25 @@ static struct saa7134_tvnorm tvnorms[] = {
                .chroma_ctrl2  = 0x06,
                .vgate_misc    = 0x1c,
 
-               .h_start       = 0,
-               .h_stop        = 719,
-               .video_v_start = 24,
-               .video_v_stop  = 311,
-               .vbi_v_start   = 7,
-               .vbi_v_stop    = 22,
-               .src_timing    = 4,
-#if 0
        },{
-               .name          = "AUTO",
-               .id            = V4L2_STD_PAL|V4L2_STD_NTSC|V4L2_STD_SECAM,
-               .width         = 768,
-               .height        = 576,
-
-               .sync_control  = 0x98,
-               .luma_control  = 0x40,
-               .chroma_ctrl1  = 0x8b,
-               .chroma_gain   = 0x00,
-               .chroma_ctrl2  = 0x00,
-               .vgate_misc    = 0x18,
+               .name          = "PAL-60",
+               .id            = V4L2_STD_PAL_60,
 
                .h_start       = 0,
                .h_stop        = 719,
-               .video_v_start = 24,
-               .video_v_stop  = 311,
-               .vbi_v_start   = 7,
-               .vbi_v_stop    = 22,
-               .src_timing    = 4,
-#endif
+               .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,
+               .chroma_ctrl1  = 0x81,
+               .chroma_gain   = 0x2a,
+               .chroma_ctrl2  = 0x06,
+               .vgate_misc    = 0x1c,
        }
 };
 #define TVNORMS ARRAY_SIZE(tvnorms)
@@ -268,7 +336,8 @@ static struct saa7134_tvnorm tvnorms[] = {
 #define V4L2_CID_PRIVATE_INVERT      (V4L2_CID_PRIVATE_BASE + 0)
 #define V4L2_CID_PRIVATE_Y_ODD       (V4L2_CID_PRIVATE_BASE + 1)
 #define V4L2_CID_PRIVATE_Y_EVEN      (V4L2_CID_PRIVATE_BASE + 2)
-#define V4L2_CID_PRIVATE_LASTP1      (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_PRIVATE_AUTOMUTE    (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_PRIVATE_LASTP1      (V4L2_CID_PRIVATE_BASE + 4)
 
 static const struct v4l2_queryctrl no_ctrl = {
        .name  = "42",
@@ -309,8 +378,8 @@ static const struct v4l2_queryctrl video_ctrls[] = {
                .default_value = 0,
                .type          = V4L2_CTRL_TYPE_INTEGER,
        },{
-               .id            = V4L2_CID_VFLIP,
-               .name          = "vertical flip",
+               .id            = V4L2_CID_HFLIP,
+               .name          = "Mirror",
                .minimum       = 0,
                .maximum       = 1,
                .type          = V4L2_CTRL_TYPE_BOOLEAN,
@@ -352,6 +421,13 @@ static const struct v4l2_queryctrl video_ctrls[] = {
                .maximum       = 128,
                .default_value = 0,
                .type          = V4L2_CTRL_TYPE_INTEGER,
+       },{
+               .id            = V4L2_CID_PRIVATE_AUTOMUTE,
+               .name          = "automute",
+               .minimum       = 0,
+               .maximum       = 1,
+               .default_value = 1,
+               .type          = V4L2_CTRL_TYPE_BOOLEAN,
        }
 };
 static const unsigned int CTRLS = ARRAY_SIZE(video_ctrls);
@@ -359,7 +435,7 @@ static const unsigned int CTRLS = ARRAY_SIZE(video_ctrls);
 static const struct v4l2_queryctrl* ctrl_by_id(unsigned int id)
 {
        unsigned int i;
-       
+
        for (i = 0; i < CTRLS; i++)
                if (video_ctrls[i].id == id)
                        return video_ctrls+i;
@@ -386,17 +462,17 @@ 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;
 }
 
@@ -415,21 +491,19 @@ 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)
 {
-       struct video_channel c;
        int luma_control,sync_control,mux;
 
        dprintk("set tv norm = %s\n",norm->name);
@@ -441,7 +515,7 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
 
        if (mux > 5)
                luma_control |= 0x80; /* svideo */
-       if (noninterlaced)
+       if (noninterlaced || dev->nosignal)
                sync_control |= 0x20;
 
        /* setup cropping */
@@ -450,7 +524,7 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
        dev->crop_bounds.width   = norm->h_stop - norm->h_start +1;
        dev->crop_defrect.width  = norm->h_stop - norm->h_start +1;
 
-       dev->crop_bounds.top     = (norm->vbi_v_stop+1)*2;
+       dev->crop_bounds.top     = (norm->vbi_v_stop_0+1)*2;
        dev->crop_defrect.top    = norm->video_v_start*2;
        dev->crop_bounds.height  = ((norm->id & V4L2_STD_525_60) ? 524 : 624)
                - dev->crop_bounds.top;
@@ -468,12 +542,12 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
        saa_writeb(SAA7134_HSYNC_START,           0xeb);
        saa_writeb(SAA7134_HSYNC_STOP,            0xe0);
        saa_writeb(SAA7134_SOURCE_TIMING1,        norm->src_timing);
-       
+
        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_CHROMA_HUE,        dev->ctl_hue);
        saa_writeb(SAA7134_CHROMA_CTRL1,          norm->chroma_ctrl1);
@@ -489,15 +563,7 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
        saa_writeb(SAA7134_RAW_DATA_GAIN,         0x40);
        saa_writeb(SAA7134_RAW_DATA_OFFSET,       0x80);
 
-       /* pass down info to the i2c chips (v4l1) */
-       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);
+       saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id);
 }
 
 static void video_mux(struct saa7134_dev *dev, int input)
@@ -549,7 +615,7 @@ static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale)
 static void set_v_scale(struct saa7134_dev *dev, int task, int yscale)
 {
        int val,mirror;
-       
+
        saa_writeb(SAA7134_V_SCALE_RATIO1(task), yscale &  0xff);
        saa_writeb(SAA7134_V_SCALE_RATIO2(task), yscale >> 8);
 
@@ -593,17 +659,17 @@ static void set_size(struct saa7134_dev *dev, int task,
        saa_writeb(SAA7134_VIDEO_V_STOP1(task),  v_stop  &  0xff);
        saa_writeb(SAA7134_VIDEO_V_STOP2(task),  v_stop  >> 8);
 
-       prescale = dev->crop_defrect.width / width;
+       prescale = dev->crop_current.width / width;
        if (0 == prescale)
                prescale = 1;
-       xscale = 1024 * dev->crop_defrect.width / prescale / width;
-       yscale = 512 * div * dev->crop_defrect.height / height;
-               dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale);
+       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);
        set_h_prescale(dev,task,prescale);
        saa_writeb(SAA7134_H_SCALE_INC1(task),      xscale &  0xff);
        saa_writeb(SAA7134_H_SCALE_INC2(task),      xscale >> 8);
        set_v_scale(dev,task,yscale);
-       
+
        saa_writeb(SAA7134_VIDEO_PIXELS1(task),     width  & 0xff);
        saa_writeb(SAA7134_VIDEO_PIXELS2(task),     width  >> 8);
        saa_writeb(SAA7134_VIDEO_LINES1(task),      height/div & 0xff);
@@ -630,7 +696,7 @@ 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) {
@@ -728,20 +794,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)
@@ -825,7 +891,7 @@ static int buffer_activate(struct saa7134_dev *dev,
        dprintk("buffer_activate buf=%p\n",buf);
        buf->vb.state = STATE_ACTIVE;
        buf->top_seen = 0;
-       
+
        set_size(dev,TASK_A,buf->vb.width,buf->vb.height,
                 V4L2_FIELD_HAS_BOTH(buf->vb.field));
        if (buf->fmt->yuv)
@@ -897,22 +963,25 @@ static int buffer_activate(struct saa7134_dev *dev,
        return 0;
 }
 
-static int buffer_prepare(struct file *file, struct videobuf_buffer *vb,
+static int buffer_prepare(struct videobuf_queue *q,
+                         struct videobuf_buffer *vb,
                          enum v4l2_field field)
 {
-       struct saa7134_fh *fh = file->private_data;
+       struct saa7134_fh *fh = q->priv_data;
        struct saa7134_dev *dev = fh->dev;
-       struct saa7134_buf *buf = (struct saa7134_buf *)vb;
+       struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
        unsigned int size;
        int err;
-       
+
        /* sanity checks */
        if (NULL == fh->fmt)
                return -EINVAL;
-       if (fh->width  < 48 ||
-           fh->height < 32 ||
-           fh->width  > dev->crop_current.width ||
-           fh->height > dev->crop_current.height)
+       if (fh->width    < 48 ||
+           fh->height   < 32 ||
+           fh->width/4  > dev->crop_current.width  ||
+           fh->height/4 > dev->crop_current.height ||
+           fh->width    > dev->crop_bounds.width  ||
+           fh->height   > dev->crop_bounds.height)
                return -EINVAL;
        size = (fh->width * fh->height * fh->fmt->depth) >> 3;
        if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
@@ -926,7 +995,7 @@ static int buffer_prepare(struct file *file, struct videobuf_buffer *vb,
            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) {
@@ -937,7 +1006,7 @@ static int buffer_prepare(struct file *file, struct videobuf_buffer *vb,
                buf->fmt       = fh->fmt;
                buf->pt        = &fh->pt_cap;
 
-               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,
@@ -952,14 +1021,14 @@ static int buffer_prepare(struct file *file, struct videobuf_buffer *vb,
        return 0;
 
  oops:
-       saa7134_dma_free(dev,buf);
+       saa7134_dma_free(q,buf);
        return err;
 }
 
 static int
-buffer_setup(struct file *file, unsigned int *count, unsigned int *size)
+buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
 {
-       struct saa7134_fh *fh = file->private_data;
+       struct saa7134_fh *fh = q->priv_data;
 
        *size = fh->fmt->depth * fh->width * fh->height >> 3;
        if (0 == *count)
@@ -968,20 +1037,19 @@ buffer_setup(struct file *file, unsigned int *count, unsigned int *size)
        return 0;
 }
 
-static void buffer_queue(struct file *file, struct videobuf_buffer *vb)
+static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
-       struct saa7134_fh *fh = file->private_data;
-       struct saa7134_buf *buf = (struct saa7134_buf *)vb;
-       
+       struct saa7134_fh *fh = q->priv_data;
+       struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+
        saa7134_buffer_queue(fh->dev,&fh->dev->video_q,buf);
 }
 
-static void buffer_release(struct file *file, struct videobuf_buffer *vb)
+static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
-       struct saa7134_fh *fh = file->private_data;
-       struct saa7134_buf *buf = (struct saa7134_buf *)vb;
-       
-       saa7134_dma_free(fh->dev,buf);
+       struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+
+       saa7134_dma_free(q,buf);
 }
 
 static struct videobuf_queue_ops video_qops = {
@@ -1022,7 +1090,7 @@ static int get_control(struct saa7134_dev *dev, struct v4l2_control *c)
        case V4L2_CID_PRIVATE_INVERT:
                c->value = dev->ctl_invert;
                break;
-       case V4L2_CID_VFLIP:
+       case V4L2_CID_HFLIP:
                c->value = dev->ctl_mirror;
                break;
        case V4L2_CID_PRIVATE_Y_EVEN:
@@ -1031,6 +1099,9 @@ static int get_control(struct saa7134_dev *dev, struct v4l2_control *c)
        case V4L2_CID_PRIVATE_Y_ODD:
                c->value = dev->ctl_y_odd;
                break;
+       case V4L2_CID_PRIVATE_AUTOMUTE:
+               c->value = dev->ctl_automute;
+               break;
        default:
                return -EINVAL;
        }
@@ -1094,7 +1165,7 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh,
                saa_writeb(SAA7134_DEC_CHROMA_SATURATION,
                           dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);
                break;
-       case V4L2_CID_VFLIP:
+       case V4L2_CID_HFLIP:
                dev->ctl_mirror = c->value;
                restart_overlay = 1;
                break;
@@ -1106,6 +1177,17 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh,
                dev->ctl_y_odd = c->value;
                restart_overlay = 1;
                break;
+       case V4L2_CID_PRIVATE_AUTOMUTE:
+               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);
+               }
+               break;
        default:
                return -EINVAL;
        }
@@ -1123,7 +1205,7 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh,
 static struct videobuf_queue* saa7134_queue(struct saa7134_fh *fh)
 {
        struct videobuf_queue* q = NULL;
-       
+
        switch (fh->type) {
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
                q = &fh->cap;
@@ -1140,7 +1222,7 @@ static struct videobuf_queue* saa7134_queue(struct saa7134_fh *fh)
 static int saa7134_resource(struct saa7134_fh *fh)
 {
        int res = 0;
-       
+
        switch (fh->type) {
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
                res = RESOURCE_VIDEO;
@@ -1162,7 +1244,6 @@ static int video_open(struct inode *inode, struct file *file)
        struct list_head *list;
        enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        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))
@@ -1183,50 +1264,46 @@ static int video_open(struct inode *inode, struct file *file)
                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;
        fh->type     = type;
        fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_BGR24);
-       fh->width    = 768;
+       fh->width    = 720;
        fh->height   = 576;
-#ifdef VIDIOC_G_PRIORITY
        v4l2_prio_open(&dev->prio,&fh->prio);
-#endif
 
        videobuf_queue_init(&fh->cap, &video_qops,
                            dev->pci, &dev->slock,
                            V4L2_BUF_TYPE_VIDEO_CAPTURE,
                            V4L2_FIELD_INTERLACED,
-                           sizeof(struct saa7134_buf));
-       init_MUTEX(&fh->cap.lock);
-       saa7134_pgtable_alloc(dev->pci,&fh->pt_cap);
-
+                           sizeof(struct saa7134_buf),
+                           fh);
        videobuf_queue_init(&fh->vbi, &saa7134_vbi_qops,
                            dev->pci, &dev->slock,
                            V4L2_BUF_TYPE_VBI_CAPTURE,
                            V4L2_FIELD_SEQ_TB,
-                           sizeof(struct saa7134_buf));
-        init_MUTEX(&fh->vbi.lock);
+                           sizeof(struct saa7134_buf),
+                           fh);
+       saa7134_pgtable_alloc(dev->pci,&fh->pt_cap);
        saa7134_pgtable_alloc(dev->pci,&fh->pt_vbi);
 
        if (fh->radio) {
                /* switch to radio mode */
                saa7134_tvaudio_setinput(dev,&card(dev).radio);
-               saa7134_i2c_call_clients(dev,AUDC_SET_RADIO,NULL);
+               saa7134_i2c_call_clients(dev,AUDC_SET_RADIO, NULL);
        } else {
                /* switch to video/vbi mode */
                video_mux(dev,dev->ctl_input);
        }
-        return 0;
+       return 0;
 }
 
 static ssize_t
-video_read(struct file *file, char *data, size_t count, loff_t *ppos)
+video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 {
        struct saa7134_fh *fh = file->private_data;
 
@@ -1234,13 +1311,15 @@ video_read(struct file *file, char *data, size_t count, loff_t *ppos)
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
                if (res_locked(fh->dev,RESOURCE_VIDEO))
                        return -EBUSY;
-               return videobuf_read_one(file, saa7134_queue(fh),
-                                        data, count, ppos);
+               return videobuf_read_one(saa7134_queue(fh),
+                                        data, count, ppos,
+                                        file->f_flags & O_NONBLOCK);
        case V4L2_BUF_TYPE_VBI_CAPTURE:
                if (!res_get(fh->dev,fh,RESOURCE_VBI))
                        return -EBUSY;
-               return videobuf_read_stream(file, saa7134_queue(fh),
-                                           data, count, ppos, 1);
+               return videobuf_read_stream(saa7134_queue(fh),
+                                           data, count, ppos, 1,
+                                           file->f_flags & O_NONBLOCK);
                break;
        default:
                BUG();
@@ -1261,21 +1340,21 @@ video_poll(struct file *file, struct poll_table_struct *wait)
                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.lock);
                if (UNSET == fh->cap.read_off) {
-                        /* need to capture a new frame */
+                       /* 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(file,fh->cap.read_buf,fh->cap.field)) {
-                                up(&fh->cap.lock);
-                                return POLLERR;
-                        }
-                        fh->cap.ops->buf_queue(file,fh->cap.read_buf);
-                        fh->cap.read_off = 0;
+                               mutex_unlock(&fh->cap.lock);
+                               return POLLERR;
+                       }
+                       if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) {
+                               mutex_unlock(&fh->cap.lock);
+                               return POLLERR;
+                       }
+                       fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
+                       fh->cap.read_off = 0;
                }
-               up(&fh->cap.lock);
+               mutex_unlock(&fh->cap.lock);
                buf = fh->cap.read_buf;
        }
 
@@ -1305,29 +1384,38 @@ static int video_release(struct inode *inode, struct file *file)
 
        /* stop video capture */
        if (res_check(fh, RESOURCE_VIDEO)) {
-               videobuf_streamoff(file,&fh->cap);
+               videobuf_streamoff(&fh->cap);
                res_free(dev,fh,RESOURCE_VIDEO);
        }
        if (fh->cap.read_buf) {
-               buffer_release(file,fh->cap.read_buf);
+               buffer_release(&fh->cap,fh->cap.read_buf);
                kfree(fh->cap.read_buf);
        }
 
        /* stop vbi capture */
        if (res_check(fh, RESOURCE_VBI)) {
                if (fh->vbi.streaming)
-                       videobuf_streamoff(file,&fh->vbi);
+                       videobuf_streamoff(&fh->vbi);
                if (fh->vbi.reading)
-                       videobuf_read_stop(file,&fh->vbi);
+                       videobuf_read_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);
+
+       saa7134_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL);
+
+       /* free stuff */
+       videobuf_mmap_free(&fh->cap);
+       videobuf_mmap_free(&fh->vbi);
        saa7134_pgtable_free(dev->pci,&fh->pt_cap);
        saa7134_pgtable_free(dev->pci,&fh->pt_vbi);
 
-#ifdef VIDIOC_G_PRIORITY
        v4l2_prio_close(&dev->prio,&fh->prio);
-#endif
        file->private_data = NULL;
        kfree(fh);
        return 0;
@@ -1337,13 +1425,13 @@ static int
 video_mmap(struct file *file, struct vm_area_struct * vma)
 {
        struct saa7134_fh *fh = file->private_data;
-       
-       return videobuf_mmap_mapper(vma,saa7134_queue(fh));
+
+       return videobuf_mmap_mapper(saa7134_queue(fh), vma);
 }
 
 /* ------------------------------------------------------------------ */
 
-void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f)
+static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f)
 {
        struct saa7134_tvnorm *norm = dev->tvnorm;
 
@@ -1351,23 +1439,16 @@ void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f)
        f->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */;
        f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
        f->fmt.vbi.offset = 64 * 4;
-       f->fmt.vbi.start[0] = norm->vbi_v_start;
-       f->fmt.vbi.count[0] = norm->vbi_v_stop - norm->vbi_v_start +1;
-       f->fmt.vbi.start[1] = norm->video_v_stop + norm->vbi_v_start +1;
+       f->fmt.vbi.start[0] = norm->vbi_v_start_0;
+       f->fmt.vbi.count[0] = norm->vbi_v_stop_0 - norm->vbi_v_start_0 +1;
+       f->fmt.vbi.start[1] = norm->vbi_v_start_1;
        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
 }
 
-int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
-                 struct v4l2_format *f)
+static int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
+                        struct v4l2_format *f)
 {
        switch (f->type) {
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
@@ -1382,6 +1463,10 @@ int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
                        f->fmt.pix.height * f->fmt.pix.bytesperline;
                return 0;
        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               if (saa7134_no_overlay > 0) {
+                       printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+                       return -EINVAL;
+               }
                f->fmt.win = fh->win;
                return 0;
        case V4L2_BUF_TYPE_VBI_CAPTURE:
@@ -1392,11 +1477,11 @@ int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
        }
 }
 
-int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
-                   struct v4l2_format *f)
+static int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
+                          struct v4l2_format *f)
 {
        int err;
-       
+
        switch (f->type) {
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
        {
@@ -1409,9 +1494,9 @@ int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
                        return -EINVAL;
 
                field = f->fmt.pix.field;
-               maxw  = dev->crop_current.width;
-               maxh  = dev->crop_current.height;
-               
+               maxw  = min(dev->crop_current.width*4,  dev->crop_bounds.width);
+               maxh  = min(dev->crop_current.height*4, dev->crop_bounds.height);
+
                if (V4L2_FIELD_ANY == field) {
                        field = (f->fmt.pix.height > maxh/2)
                                ? V4L2_FIELD_INTERLACED
@@ -1437,14 +1522,19 @@ int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
                        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;
-               
+
                return 0;
        }
        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               if (saa7134_no_overlay > 0) {
+                       printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+                       return -EINVAL;
+               }
                err = verify_preview(dev,&f->fmt.win);
                if (0 != err)
                        return err;
@@ -1457,36 +1547,40 @@ int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
        }
 }
 
-int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
-                 struct v4l2_format *f)
+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;
-                       
+
                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:
+               if (saa7134_no_overlay > 0) {
+                       printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+                       return -EINVAL;
+               }
                err = verify_preview(dev,&f->fmt.win);
                if (0 != err)
                        return err;
 
-               down(&dev->lock);
+               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)) {
-                       up(&dev->lock);
+                       mutex_unlock(&dev->lock);
                        return -EFAULT;
                }
 
@@ -1496,7 +1590,7 @@ int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
                        start_preview(dev,fh);
                        spin_unlock_irqrestore(&dev->slock,flags);
                }
-               up(&dev->lock);
+               mutex_unlock(&dev->lock);
                return 0;
        case V4L2_BUF_TYPE_VBI_CAPTURE:
                saa7134_vbi_fmt(dev,f);
@@ -1510,7 +1604,7 @@ int saa7134_common_ioctl(struct saa7134_dev *dev,
                         unsigned int cmd, void *arg)
 {
        int err;
-       
+
        switch (cmd) {
        case VIDIOC_QUERYCTRL:
        {
@@ -1530,9 +1624,9 @@ int saa7134_common_ioctl(struct saa7134_dev *dev,
                return get_control(dev,arg);
        case VIDIOC_S_CTRL:
        {
-               down(&dev->lock);
+               mutex_lock(&dev->lock);
                err = set_control(dev,NULL,arg);
-               up(&dev->lock);
+               mutex_unlock(&dev->lock);
                return err;
        }
        /* --- input switching --------------------------------------- */
@@ -1577,20 +1671,21 @@ int saa7134_common_ioctl(struct saa7134_dev *dev,
        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);
+               mutex_lock(&dev->lock);
                video_mux(dev,*i);
-               up(&dev->lock);
+               mutex_unlock(&dev->lock);
                return 0;
        }
 
        }
        return 0;
 }
+EXPORT_SYMBOL(saa7134_common_ioctl);
 
 /*
  * This function is _not_ called directly, but from
@@ -1606,9 +1701,8 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
        int err;
 
        if (video_debug > 1)
-               saa7134_print_ioctl(dev->name,cmd);
+               v4l_print_ioctl(dev->name,cmd);
 
-#ifdef VIDIOC_G_PRIORITY
        switch (cmd) {
        case VIDIOC_S_CTRL:
        case VIDIOC_S_STD:
@@ -1619,26 +1713,32 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                if (0 != err)
                        return err;
        }
-#endif
 
        switch (cmd) {
        case VIDIOC_QUERYCAP:
        {
                struct v4l2_capability *cap = arg;
-               
+               unsigned int tuner_type = dev->tuner_type;
+
                memset(cap,0,sizeof(*cap));
-                strcpy(cap->driver, "saa7134");
+               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;
+                       V4L2_CAP_READWRITE |
+                       V4L2_CAP_STREAMING |
+                       V4L2_CAP_TUNER;
+               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;
        }
 
@@ -1670,22 +1770,27 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                v4l2_std_id *id = arg;
                unsigned int i;
 
-               for(i = 0; i < TVNORMS; i++)
-                       if (*id & tvnorms[i].id)
+               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)
+                                       break;
                if (i == TVNORMS)
                        return -EINVAL;
 
-               down(&dev->lock);
+               mutex_lock(&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 
+               } else
                        set_tvnorm(dev,&tvnorms[i]);
-               up(&dev->lock);
+               saa7134_tvaudio_do_scan(dev);
+               mutex_unlock(&dev->lock);
                return 0;
        }
 
@@ -1747,9 +1852,9 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                        crop->c.height = b->top - crop->c.top + b->height;
 
                if (crop->c.left < b->left)
-                       crop->c.top = b->left;
+                       crop->c.left = b->left;
                if (crop->c.left > b->left + b->width)
-                       crop->c.top = 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;
 
@@ -1771,6 +1876,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                                break;
                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 |
@@ -1803,7 +1909,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                struct v4l2_frequency *f = arg;
 
                memset(f,0,sizeof(*f));
-               f->type = V4L2_TUNER_ANALOG_TV;
+               f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
                f->frequency = dev->ctl_freq;
                return 0;
        }
@@ -1813,16 +1919,20 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
 
                if (0 != f->tuner)
                        return -EINVAL;
-               if (V4L2_TUNER_ANALOG_TV != f->type)
+               if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
                        return -EINVAL;
-               down(&dev->lock);
+               if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
+                       return -EINVAL;
+               mutex_lock(&dev->lock);
                dev->ctl_freq = f->frequency;
-               saa7134_i2c_call_clients(dev,VIDIOCSFREQ,&dev->ctl_freq);
+
+               saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f);
+
                saa7134_tvaudio_do_scan(dev);
-               up(&dev->lock);
+               mutex_unlock(&dev->lock);
                return 0;
        }
-               
+
        /* --- control ioctls ---------------------------------------- */
        case VIDIOC_ENUMINPUT:
        case VIDIOC_G_INPUT:
@@ -1842,28 +1952,26 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
        }
        case VIDIOC_S_AUDIO:
                return 0;
-        case VIDIOC_G_PARM:
-        {
-                struct v4l2_captureparm *parm = arg;
-                memset(parm,0,sizeof(*parm));
-                return 0;
-        }
-
-#ifdef VIDIOC_G_PRIORITY
-        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);
-        }
-#endif
+       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:
@@ -1877,6 +1985,10 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                switch (type) {
                case V4L2_BUF_TYPE_VIDEO_CAPTURE:
                case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+                       if (saa7134_no_overlay > 0) {
+                               printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+                               return -EINVAL;
+                       }
                        if (index >= FORMATS)
                                return -EINVAL;
                        if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY &&
@@ -1898,7 +2010,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                        strcpy(f->description,"vbi data");
                        break;
                default:
-                       return -EINVAL; 
+                       return -EINVAL;
                }
                return 0;
        }
@@ -1914,7 +2026,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
        {
                struct v4l2_framebuffer *fb = arg;
                struct saa7134_format *fmt;
-               
+
                if(!capable(CAP_SYS_ADMIN) &&
                   !capable(CAP_SYS_RAWIO))
                        return -EPERM;
@@ -1937,6 +2049,11 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                int *on = arg;
 
                if (*on) {
+                       if (saa7134_no_overlay > 0) {
+                               printk ("no_overlay\n");
+                               return -EINVAL;
+                       }
+
                        if (!res_get(dev,fh,RESOURCE_OVERLAY))
                                return -EBUSY;
                        spin_lock_irqsave(&dev->slock,flags);
@@ -1970,7 +2087,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                struct v4l2_format *f = arg;
                return saa7134_try_fmt(dev,fh,f);
        }
-       
+#ifdef HAVE_V4L1
        case VIDIOCGMBUF:
        {
                struct video_mbuf *mbuf = arg;
@@ -1983,7 +2100,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                req.type   = q->type;
                req.count  = gbuffers;
                req.memory = V4L2_MEMORY_MMAP;
-               err = videobuf_reqbufs(file,q,&req);
+               err = videobuf_reqbufs(q,&req);
                if (err < 0)
                        return err;
                memset(mbuf,0,sizeof(*mbuf));
@@ -1995,31 +2112,33 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                }
                return 0;
        }
+#endif
        case VIDIOC_REQBUFS:
-               return videobuf_reqbufs(file,saa7134_queue(fh),arg);
+               return videobuf_reqbufs(saa7134_queue(fh),arg);
 
        case VIDIOC_QUERYBUF:
                return videobuf_querybuf(saa7134_queue(fh),arg);
 
        case VIDIOC_QBUF:
-               return videobuf_qbuf(file,saa7134_queue(fh),arg);
+               return videobuf_qbuf(saa7134_queue(fh),arg);
 
        case VIDIOC_DQBUF:
-               return videobuf_dqbuf(file,saa7134_queue(fh),arg);
+               return videobuf_dqbuf(saa7134_queue(fh),arg,
+                                     file->f_flags & O_NONBLOCK);
 
        case VIDIOC_STREAMON:
        {
                int res = saa7134_resource(fh);
 
-                if (!res_get(dev,fh,res))
+               if (!res_get(dev,fh,res))
                        return -EBUSY;
-               return videobuf_streamon(file,saa7134_queue(fh));
+               return videobuf_streamon(saa7134_queue(fh));
        }
        case VIDIOC_STREAMOFF:
        {
                int res = saa7134_resource(fh);
 
-               err = videobuf_streamoff(file,saa7134_queue(fh));
+               err = videobuf_streamoff(saa7134_queue(fh));
                if (err < 0)
                        return err;
                res_free(dev,fh,res);
@@ -2044,16 +2163,16 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
 {
        struct saa7134_fh *fh = file->private_data;
        struct saa7134_dev *dev = fh->dev;
-       
+
        if (video_debug > 1)
-               saa7134_print_ioctl(dev->name,cmd);
+               v4l_print_ioctl(dev->name,cmd);
        switch (cmd) {
        case VIDIOC_QUERYCAP:
        {
                struct v4l2_capability *cap = arg;
 
                memset(cap,0,sizeof(*cap));
-                strcpy(cap->driver, "saa7134");
+               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));
@@ -2064,25 +2183,33 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_G_TUNER:
        {
                struct v4l2_tuner *t = arg;
-               struct video_tuner vt;
 
                if (0 != t->index)
                        return -EINVAL;
 
                memset(t,0,sizeof(*t));
                strcpy(t->name, "Radio");
-                t->rangelow  = (int)(65*16);
-                t->rangehigh = (int)(108*16);
-               
-               memset(&vt,0,sizeof(vt));
-               saa7134_i2c_call_clients(dev,VIDIOCGTUNER,&vt);
-               t->signal = vt.signal;
+               t->type = V4L2_TUNER_RADIO;
+
+               saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
+
+               return 0;
+       }
+       case VIDIOC_S_TUNER:
+       {
+               struct v4l2_tuner *t = arg;
+
+               if (0 != t->index)
+                       return -EINVAL;
+
+               saa7134_i2c_call_clients(dev,VIDIOC_S_TUNER,t);
+
                return 0;
        }
        case VIDIOC_ENUMINPUT:
        {
                struct v4l2_input *i = arg;
-               
+
                if (i->index != 0)
                        return -EINVAL;
                strcpy(i->name,"Radio");
@@ -2110,7 +2237,6 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
                return 0;
        }
        case VIDIOC_S_AUDIO:
-       case VIDIOC_S_TUNER:
        case VIDIOC_S_INPUT:
        case VIDIOC_S_STD:
                return 0;
@@ -2136,7 +2262,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_G_FREQUENCY:
        case VIDIOC_S_FREQUENCY:
                return video_do_ioctl(inode,file,cmd,arg);
-               
+
        default:
                return v4l_compat_translate_ioctl(inode,file,cmd,arg,
                                                  radio_do_ioctl);
@@ -2159,6 +2285,7 @@ static struct file_operations video_fops =
        .poll     = video_poll,
        .mmap     = video_mmap,
        .ioctl    = video_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek   = no_llseek,
 };
 
@@ -2168,6 +2295,7 @@ static struct file_operations radio_fops =
        .open     = video_open,
        .release  = video_release,
        .ioctl    = radio_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek   = no_llseek,
 };
 
@@ -2177,8 +2305,8 @@ static struct file_operations radio_fops =
 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,
+       .type          = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
+                        VID_TYPE_CLIPPING|VID_TYPE_SCALES,
        .hardware      = 0,
        .fops          = &video_fops,
        .minor         = -1,
@@ -2217,12 +2345,15 @@ int saa7134_video_init1(struct saa7134_dev *dev)
        dev->ctl_hue        = ctrl_by_id(V4L2_CID_HUE)->default_value;
        dev->ctl_saturation = ctrl_by_id(V4L2_CID_SATURATION)->default_value;
        dev->ctl_volume     = ctrl_by_id(V4L2_CID_AUDIO_VOLUME)->default_value;
+       dev->ctl_mute       = 1; // ctrl_by_id(V4L2_CID_AUDIO_MUTE)->default_value;
+       dev->ctl_invert     = ctrl_by_id(V4L2_CID_PRIVATE_INVERT)->default_value;
+       dev->ctl_automute   = ctrl_by_id(V4L2_CID_PRIVATE_AUTOMUTE)->default_value;
 
-       dev->ctl_invert     = 0;
-       dev->ctl_mute       = 1;
+       if (dev->tda9887_conf && dev->ctl_automute)
+               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);
@@ -2231,17 +2362,32 @@ int saa7134_video_init1(struct saa7134_dev *dev)
        if (saa7134_boards[dev->board].video_out) {
                /* 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;
                saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]);
-               saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_out[vo][1]);
+               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_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]);
+               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]);
        }
+
        return 0;
 }
 
@@ -2264,26 +2410,37 @@ int saa7134_video_fini(struct saa7134_dev *dev)
 void saa7134_irq_video_intl(struct saa7134_dev *dev)
 {
        static const char *st[] = {
-               "no signal", "found NTSC", "found PAL", "found SECAM" };
-       int norm;
-
-       norm = saa_readb(SAA7134_STATUS_VIDEO1) & 0x03;
-       dprintk("DCSDT: %s\n",st[norm]);
-       
-       if (0 != norm) {
-               /* wake up tvaudio audio carrier scan thread */
-               saa7134_tvaudio_do_scan(dev);
-       } else {
+               "(no signal)", "NTSC", "PAL", "SECAM" };
+       u32 st1,st2;
+
+       st1 = saa_readb(SAA7134_STATUS_VIDEO1);
+       st2 = saa_readb(SAA7134_STATUS_VIDEO2);
+       dprintk("DCSDT: pll: %s, sync: %s, norm: %s\n",
+               (st1 & 0x40) ? "not locked" : "locked",
+               (st2 & 0x40) ? "no"         : "yes",
+               st[st1 & 0x03]);
+       dev->nosignal = (st1 & 0x40) || (st2 & 0x40);
+
+       if (dev->nosignal) {
                /* no video signal -> mute audio */
-               dev->automute = 1;
+               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 (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;
-       
+
        spin_lock(&dev->slock);
        if (dev->video_q.curr) {
                dev->video_fieldcount++;