V4L/DVB (11381): ivtv/cx18: remove VIDIOC_INT_S_AUDIO_ROUTING debug support.
[safe/jmp/linux-2.6] / drivers / media / video / ivtv / ivtv-ioctl.c
index 57eb8df..4a2d464 100644 (file)
@@ -38,7 +38,7 @@
 #include <linux/dvb/audio.h>
 #include <linux/i2c-id.h>
 
-u16 service2vbi(int type)
+u16 ivtv_service2vbi(int type)
 {
        switch (type) {
                case V4L2_SLICED_TELETEXT_B:
@@ -88,7 +88,7 @@ static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
        return 0;
 }
 
-void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
 {
        u16 set = fmt->service_set;
        int f, l;
@@ -101,21 +101,18 @@ void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
        }
 }
 
-static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+static void check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
 {
        int f, l;
-       u16 set = 0;
 
        for (f = 0; f < 2; f++) {
                for (l = 0; l < 24; l++) {
                        fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal);
-                       set |= fmt->service_lines[f][l];
                }
        }
-       return set != 0;
 }
 
-u16 get_service_set(struct v4l2_sliced_vbi_format *fmt)
+u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt)
 {
        int f, l;
        u16 set = 0;
@@ -128,37 +125,6 @@ u16 get_service_set(struct v4l2_sliced_vbi_format *fmt)
        return set;
 }
 
-static const struct {
-       v4l2_std_id  std;
-       char        *name;
-} enum_stds[] = {
-       { V4L2_STD_PAL_BG | V4L2_STD_PAL_H, "PAL-BGH" },
-       { V4L2_STD_PAL_DK,    "PAL-DK"    },
-       { V4L2_STD_PAL_I,     "PAL-I"     },
-       { V4L2_STD_PAL_M,     "PAL-M"     },
-       { V4L2_STD_PAL_N,     "PAL-N"     },
-       { V4L2_STD_PAL_Nc,    "PAL-Nc"    },
-       { V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, "SECAM-BGH" },
-       { V4L2_STD_SECAM_DK,  "SECAM-DK"  },
-       { V4L2_STD_SECAM_L,   "SECAM-L"   },
-       { V4L2_STD_SECAM_LC,  "SECAM-L'"  },
-       { V4L2_STD_NTSC_M,    "NTSC-M"    },
-       { V4L2_STD_NTSC_M_JP, "NTSC-J"    },
-       { V4L2_STD_NTSC_M_KR, "NTSC-K"    },
-};
-
-static const struct v4l2_standard ivtv_std_60hz =
-{
-       .frameperiod = {.numerator = 1001, .denominator = 30000},
-       .framelines = 525,
-};
-
-static const struct v4l2_standard ivtv_std_50hz =
-{
-       .frameperiod = {.numerator = 1, .denominator = 25},
-       .framelines = 625,
-};
-
 void ivtv_set_osd_alpha(struct ivtv *itv)
 {
        ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3,
@@ -243,20 +209,31 @@ static int ivtv_validate_speed(int cur_speed, int new_speed)
        int fact = new_speed < 0 ? -1 : 1;
        int s;
 
-       if (new_speed < 0) new_speed = -new_speed;
-       if (cur_speed < 0) cur_speed = -cur_speed;
+       if (cur_speed == 0)
+               cur_speed = 1000;
+       if (new_speed < 0)
+               new_speed = -new_speed;
+       if (cur_speed < 0)
+               cur_speed = -cur_speed;
 
        if (cur_speed <= new_speed) {
-               if (new_speed > 1500) return fact * 2000;
-               if (new_speed > 1000) return fact * 1500;
+               if (new_speed > 1500)
+                       return fact * 2000;
+               if (new_speed > 1000)
+                       return fact * 1500;
        }
        else {
-               if (new_speed >= 2000) return fact * 2000;
-               if (new_speed >= 1500) return fact * 1500;
-               if (new_speed >= 1000) return fact * 1000;
-       }
-       if (new_speed == 0) return 1000;
-       if (new_speed == 1 || new_speed == 1000) return fact * new_speed;
+               if (new_speed >= 2000)
+                       return fact * 2000;
+               if (new_speed >= 1500)
+                       return fact * 1500;
+               if (new_speed >= 1000)
+                       return fact * 1000;
+       }
+       if (new_speed == 0)
+               return 1000;
+       if (new_speed == 1 || new_speed == 1000)
+               return fact * new_speed;
 
        s = new_speed;
        new_speed = 1000 / new_speed;
@@ -334,10 +311,395 @@ static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id,
        return 0;
 }
 
+static int ivtv_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+
+       vbifmt->reserved[0] = 0;
+       vbifmt->reserved[1] = 0;
+       if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
+               return -EINVAL;
+       vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+       if (itv->is_60hz) {
+               vbifmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+               vbifmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
+       } else {
+               vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625;
+               vbifmt->service_lines[0][16] = V4L2_SLICED_VPS;
+       }
+       vbifmt->service_set = ivtv_get_service_set(vbifmt);
+       return 0;
+}
+
+static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct ivtv_open_id *id = fh;
+       struct ivtv *itv = id->itv;
+       struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+
+       pixfmt->width = itv->params.width;
+       pixfmt->height = itv->params.height;
+       pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+       pixfmt->field = V4L2_FIELD_INTERLACED;
+       pixfmt->priv = 0;
+       if (id->type == IVTV_ENC_STREAM_TYPE_YUV) {
+               pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
+               /* YUV size is (Y=(h*720) + UV=(h*(720/2))) */
+               pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2;
+               pixfmt->bytesperline = 720;
+       } else {
+               pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
+               pixfmt->sizeimage = 128 * 1024;
+               pixfmt->bytesperline = 0;
+       }
+       return 0;
+}
+
+static int ivtv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;
+
+       vbifmt->sampling_rate = 27000000;
+       vbifmt->offset = 248;
+       vbifmt->samples_per_line = itv->vbi.raw_decoder_line_size - 4;
+       vbifmt->sample_format = V4L2_PIX_FMT_GREY;
+       vbifmt->start[0] = itv->vbi.start[0];
+       vbifmt->start[1] = itv->vbi.start[1];
+       vbifmt->count[0] = vbifmt->count[1] = itv->vbi.count;
+       vbifmt->flags = 0;
+       vbifmt->reserved[0] = 0;
+       vbifmt->reserved[1] = 0;
+       return 0;
+}
+
+static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+       struct ivtv_open_id *id = fh;
+       struct ivtv *itv = id->itv;
+
+       vbifmt->reserved[0] = 0;
+       vbifmt->reserved[1] = 0;
+       vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+
+       if (id->type == IVTV_DEC_STREAM_TYPE_VBI) {
+               vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 :
+                       V4L2_SLICED_VBI_525;
+               ivtv_expand_service_set(vbifmt, itv->is_50hz);
+               return 0;
+       }
+
+       v4l2_subdev_call(itv->sd_video, video, g_fmt, fmt);
+       vbifmt->service_set = ivtv_get_service_set(vbifmt);
+       return 0;
+}
+
+static int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct ivtv_open_id *id = fh;
+       struct ivtv *itv = id->itv;
+       struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+
+       if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+               return -EINVAL;
+       pixfmt->width = itv->main_rect.width;
+       pixfmt->height = itv->main_rect.height;
+       pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+       pixfmt->field = V4L2_FIELD_INTERLACED;
+       pixfmt->priv = 0;
+       if (id->type == IVTV_DEC_STREAM_TYPE_YUV) {
+               switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) {
+               case IVTV_YUV_MODE_INTERLACED:
+                       pixfmt->field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ?
+                               V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB;
+                       break;
+               case IVTV_YUV_MODE_PROGRESSIVE:
+                       pixfmt->field = V4L2_FIELD_NONE;
+                       break;
+               default:
+                       pixfmt->field = V4L2_FIELD_ANY;
+                       break;
+               }
+               pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
+               pixfmt->bytesperline = 720;
+               pixfmt->width = itv->yuv_info.v4l2_src_w;
+               pixfmt->height = itv->yuv_info.v4l2_src_h;
+               /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
+               pixfmt->sizeimage =
+                       1080 * ((pixfmt->height + 31) & ~31);
+       } else {
+               pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
+               pixfmt->sizeimage = 128 * 1024;
+               pixfmt->bytesperline = 0;
+       }
+       return 0;
+}
+
+static int ivtv_g_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct v4l2_window *winfmt = &fmt->fmt.win;
+
+       if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+               return -EINVAL;
+       winfmt->chromakey = itv->osd_chroma_key;
+       winfmt->global_alpha = itv->osd_global_alpha;
+       winfmt->field = V4L2_FIELD_INTERLACED;
+       winfmt->clips = NULL;
+       winfmt->clipcount = 0;
+       winfmt->bitmap = NULL;
+       winfmt->w.top = winfmt->w.left = 0;
+       winfmt->w.width = itv->osd_rect.width;
+       winfmt->w.height = itv->osd_rect.height;
+       return 0;
+}
+
+static int ivtv_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt);
+}
+
+static int ivtv_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct ivtv_open_id *id = fh;
+       struct ivtv *itv = id->itv;
+       int w = fmt->fmt.pix.width;
+       int h = fmt->fmt.pix.height;
+       int min_h = 2;
+
+       w = min(w, 720);
+       w = max(w, 2);
+       if (id->type == IVTV_ENC_STREAM_TYPE_YUV) {
+               /* YUV height must be a multiple of 32 */
+               h &= ~0x1f;
+               min_h = 32;
+       }
+       h = min(h, itv->is_50hz ? 576 : 480);
+       h = max(h, min_h);
+       ivtv_g_fmt_vid_cap(file, fh, fmt);
+       fmt->fmt.pix.width = w;
+       fmt->fmt.pix.height = h;
+       return 0;
+}
+
+static int ivtv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       return ivtv_g_fmt_vbi_cap(file, fh, fmt);
+}
+
+static int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+       struct ivtv_open_id *id = fh;
+       struct ivtv *itv = id->itv;
+
+       if (id->type == IVTV_DEC_STREAM_TYPE_VBI)
+               return ivtv_g_fmt_sliced_vbi_cap(file, fh, fmt);
+
+       /* set sliced VBI capture format */
+       vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+       vbifmt->reserved[0] = 0;
+       vbifmt->reserved[1] = 0;
+
+       if (vbifmt->service_set)
+               ivtv_expand_service_set(vbifmt, itv->is_50hz);
+       check_service_set(vbifmt, itv->is_50hz);
+       vbifmt->service_set = ivtv_get_service_set(vbifmt);
+       return 0;
+}
+
+static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct ivtv_open_id *id = fh;
+       s32 w = fmt->fmt.pix.width;
+       s32 h = fmt->fmt.pix.height;
+       int field = fmt->fmt.pix.field;
+       int ret = ivtv_g_fmt_vid_out(file, fh, fmt);
+
+       w = min(w, 720);
+       w = max(w, 2);
+       /* Why can the height be 576 even when the output is NTSC?
+
+          Internally the buffers of the PVR350 are always set to 720x576. The
+          decoded video frame will always be placed in the top left corner of
+          this buffer. For any video which is not 720x576, the buffer will
+          then be cropped to remove the unused right and lower areas, with
+          the remaining image being scaled by the hardware to fit the display
+          area. The video can be scaled both up and down, so a 720x480 video
+          can be displayed full-screen on PAL and a 720x576 video can be
+          displayed without cropping on NTSC.
+
+          Note that the scaling only occurs on the video stream, the osd
+          resolution is locked to the broadcast standard and not scaled.
+
+          Thanks to Ian Armstrong for this explanation. */
+       h = min(h, 576);
+       h = max(h, 2);
+       if (id->type == IVTV_DEC_STREAM_TYPE_YUV)
+               fmt->fmt.pix.field = field;
+       fmt->fmt.pix.width = w;
+       fmt->fmt.pix.height = h;
+       return ret;
+}
+
+static int ivtv_try_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       u32 chromakey = fmt->fmt.win.chromakey;
+       u8 global_alpha = fmt->fmt.win.global_alpha;
+
+       if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+               return -EINVAL;
+       ivtv_g_fmt_vid_out_overlay(file, fh, fmt);
+       fmt->fmt.win.chromakey = chromakey;
+       fmt->fmt.win.global_alpha = global_alpha;
+       return 0;
+}
+
+static int ivtv_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt);
+}
+
+static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct ivtv_open_id *id = fh;
+       struct ivtv *itv = id->itv;
+       struct cx2341x_mpeg_params *p = &itv->params;
+       int ret = ivtv_try_fmt_vid_cap(file, fh, fmt);
+       int w = fmt->fmt.pix.width;
+       int h = fmt->fmt.pix.height;
+
+       if (ret)
+               return ret;
+
+       if (p->width == w && p->height == h)
+               return 0;
+
+       if (atomic_read(&itv->capturing) > 0)
+               return -EBUSY;
+
+       p->width = w;
+       p->height = h;
+       if (p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+               fmt->fmt.pix.width /= 2;
+       v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt);
+       return ivtv_g_fmt_vid_cap(file, fh, fmt);
+}
+
+static int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+       if (!ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0)
+               return -EBUSY;
+       itv->vbi.sliced_in->service_set = 0;
+       itv->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
+       v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt);
+       return ivtv_g_fmt_vbi_cap(file, fh, fmt);
+}
+
+static int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+       struct ivtv_open_id *id = fh;
+       struct ivtv *itv = id->itv;
+       int ret = ivtv_try_fmt_sliced_vbi_cap(file, fh, fmt);
+
+       if (ret || id->type == IVTV_DEC_STREAM_TYPE_VBI)
+               return ret;
+
+       check_service_set(vbifmt, itv->is_50hz);
+       if (ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0)
+               return -EBUSY;
+       itv->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+       v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt);
+       memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in));
+       return 0;
+}
+
+static int ivtv_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct ivtv_open_id *id = fh;
+       struct ivtv *itv = id->itv;
+       struct yuv_playback_info *yi = &itv->yuv_info;
+       int ret = ivtv_try_fmt_vid_out(file, fh, fmt);
+
+       if (ret)
+               return ret;
+
+       if (id->type != IVTV_DEC_STREAM_TYPE_YUV)
+               return 0;
+
+       /* Return now if we already have some frame data */
+       if (yi->stream_size)
+               return -EBUSY;
+
+       yi->v4l2_src_w = fmt->fmt.pix.width;
+       yi->v4l2_src_h = fmt->fmt.pix.height;
+
+       switch (fmt->fmt.pix.field) {
+       case V4L2_FIELD_NONE:
+               yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
+               break;
+       case V4L2_FIELD_ANY:
+               yi->lace_mode = IVTV_YUV_MODE_AUTO;
+               break;
+       case V4L2_FIELD_INTERLACED_BT:
+               yi->lace_mode =
+                       IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
+               break;
+       case V4L2_FIELD_INTERLACED_TB:
+       default:
+               yi->lace_mode = IVTV_YUV_MODE_INTERLACED;
+               break;
+       }
+       yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
+
+       if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
+               itv->dma_data_req_size =
+                       1080 * ((yi->v4l2_src_h + 31) & ~31);
+
+       return 0;
+}
+
+static int ivtv_s_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       int ret = ivtv_try_fmt_vid_out_overlay(file, fh, fmt);
+
+       if (ret == 0) {
+               itv->osd_chroma_key = fmt->fmt.win.chromakey;
+               itv->osd_global_alpha = fmt->fmt.win.global_alpha;
+               ivtv_set_osd_alpha(itv);
+       }
+       return ret;
+}
+
+static int ivtv_g_chip_ident(struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+       chip->ident = V4L2_IDENT_NONE;
+       chip->revision = 0;
+       if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
+               if (v4l2_chip_match_host(&chip->match))
+                       chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416;
+               return 0;
+       }
+       if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+           chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+               return -EINVAL;
+       /* TODO: is this correct? */
+       return ivtv_call_all_err(itv, core, g_chip_ident, chip);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
 static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg)
 {
-       struct v4l2_register *regs = arg;
-       unsigned long flags;
+       struct v4l2_dbg_register *regs = arg;
        volatile u8 __iomem *reg_start;
 
        if (!capable(CAP_SYS_ADMIN))
@@ -352,1054 +714,826 @@ static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg)
        else
                return -EINVAL;
 
-       spin_lock_irqsave(&ivtv_cards_lock, flags);
-       if (cmd == VIDIOC_DBG_G_REGISTER) {
+       regs->size = 4;
+       if (cmd == VIDIOC_DBG_G_REGISTER)
                regs->val = readl(regs->reg + reg_start);
-       } else {
+       else
                writel(regs->val, regs->reg + reg_start);
-       }
-       spin_unlock_irqrestore(&ivtv_cards_lock, flags);
        return 0;
 }
 
-static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fmt)
+static int ivtv_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
 {
-       switch (fmt->type) {
-       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-               if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
-                       return -EINVAL;
-               fmt->fmt.pix.width = itv->main_rect.width;
-               fmt->fmt.pix.height = itv->main_rect.height;
-               fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-               fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
-               if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
-                       switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) {
-                       case IVTV_YUV_MODE_INTERLACED:
-                               fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ?
-                                       V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB;
-                               break;
-                       case IVTV_YUV_MODE_PROGRESSIVE:
-                               fmt->fmt.pix.field = V4L2_FIELD_NONE;
-                               break;
-                       default:
-                               fmt->fmt.pix.field = V4L2_FIELD_ANY;
-                               break;
-                       }
-                       fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
-                       fmt->fmt.pix.bytesperline = 720;
-                       fmt->fmt.pix.width = itv->yuv_info.v4l2_src_w;
-                       fmt->fmt.pix.height = itv->yuv_info.v4l2_src_h;
-                       /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
-                       fmt->fmt.pix.sizeimage =
-                               1080 * ((fmt->fmt.pix.height + 31) & ~31);
-               } else if (streamtype == IVTV_ENC_STREAM_TYPE_YUV) {
-                       fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
-                       /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
-                       fmt->fmt.pix.sizeimage =
-                               fmt->fmt.pix.height * fmt->fmt.pix.width +
-                               fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
-               } else {
-                       fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
-                       fmt->fmt.pix.sizeimage = 128 * 1024;
-               }
-               break;
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               fmt->fmt.pix.width = itv->params.width;
-               fmt->fmt.pix.height = itv->params.height;
-               fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-               fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
-               if (streamtype == IVTV_ENC_STREAM_TYPE_YUV ||
-                               streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
-                       fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
-                       /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
-                       fmt->fmt.pix.sizeimage =
-                               fmt->fmt.pix.height * fmt->fmt.pix.width +
-                               fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
-               } else {
-                       fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
-                       fmt->fmt.pix.sizeimage = 128 * 1024;
-               }
-               break;
+       if (v4l2_chip_match_host(&reg->match))
+               return ivtv_itvc(itv, VIDIOC_DBG_G_REGISTER, reg);
+       /* TODO: subdev errors should not be ignored, this should become a
+          subdev helper function. */
+       ivtv_call_all(itv, core, g_register, reg);
+       return 0;
+}
 
-       case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
-               if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
-                       return -EINVAL;
-               fmt->fmt.win.chromakey = itv->osd_chroma_key;
-               fmt->fmt.win.global_alpha = itv->osd_global_alpha;
-               break;
+static int ivtv_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               fmt->fmt.vbi.sampling_rate = 27000000;
-               fmt->fmt.vbi.offset = 248;
-               fmt->fmt.vbi.samples_per_line = itv->vbi.raw_decoder_line_size - 4;
-               fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
-               fmt->fmt.vbi.start[0] = itv->vbi.start[0];
-               fmt->fmt.vbi.start[1] = itv->vbi.start[1];
-               fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = itv->vbi.count;
-               break;
+       if (v4l2_chip_match_host(&reg->match))
+               return ivtv_itvc(itv, VIDIOC_DBG_S_REGISTER, reg);
+       /* TODO: subdev errors should not be ignored, this should become a
+          subdev helper function. */
+       ivtv_call_all(itv, core, s_register, reg);
+       return 0;
+}
+#endif
 
-       case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
-       {
-               struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+static int ivtv_g_priority(struct file *file, void *fh, enum v4l2_priority *p)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-               if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
-                       return -EINVAL;
-               vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
-               memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
-               memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
-               if (itv->is_60hz) {
-                       vbifmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
-                       vbifmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
-               } else {
-                       vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625;
-                       vbifmt->service_lines[0][16] = V4L2_SLICED_VPS;
-               }
-               vbifmt->service_set = get_service_set(vbifmt);
-               break;
-       }
+       *p = v4l2_prio_max(&itv->prio);
 
-       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-       {
-               struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+       return 0;
+}
 
-               vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
-               memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
-               memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
+static int ivtv_s_priority(struct file *file, void *fh, enum v4l2_priority prio)
+{
+       struct ivtv_open_id *id = fh;
+       struct ivtv *itv = id->itv;
 
-               if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) {
-                       vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 :
-                                                V4L2_SLICED_VBI_525;
-                       expand_service_set(vbifmt, itv->is_50hz);
-                       break;
-               }
+       return v4l2_prio_change(&itv->prio, &id->prio, prio);
+}
 
-               itv->video_dec_func(itv, VIDIOC_G_FMT, fmt);
-               vbifmt->service_set = get_service_set(vbifmt);
-               break;
-       }
-       case V4L2_BUF_TYPE_VBI_OUTPUT:
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-       default:
-               return -EINVAL;
-       }
+static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+       strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
+       strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
+       snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev));
+       vcap->version = IVTV_DRIVER_VERSION;        /* version */
+       vcap->capabilities = itv->v4l2_cap;         /* capabilities */
        return 0;
 }
 
-static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
-               struct v4l2_format *fmt, int set_fmt)
+static int ivtv_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin)
 {
-       struct yuv_playback_info *yi = &itv->yuv_info;
-       struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
-       u16 set;
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-       if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-               struct v4l2_rect r;
-               int field;
+       return ivtv_get_audio_input(itv, vin->index, vin);
+}
 
-               if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
-                       return -EINVAL;
-               field = fmt->fmt.pix.field;
-               r.top = 0;
-               r.left = 0;
-               r.width = fmt->fmt.pix.width;
-               r.height = fmt->fmt.pix.height;
-               ivtv_get_fmt(itv, streamtype, fmt);
-               fmt->fmt.pix.width = r.width;
-               fmt->fmt.pix.height = r.height;
-               if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
-                       fmt->fmt.pix.field = field;
-                       if (fmt->fmt.pix.width < 2)
-                               fmt->fmt.pix.width = 2;
-                       if (fmt->fmt.pix.width > 720)
-                               fmt->fmt.pix.width = 720;
-                       if (fmt->fmt.pix.height < 2)
-                               fmt->fmt.pix.height = 2;
-                       if (fmt->fmt.pix.height > 576)
-                               fmt->fmt.pix.height = 576;
-               }
-               if (set_fmt && streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
-                       /* Return now if we already have some frame data */
-                       if (yi->stream_size)
-                               return -EBUSY;
+static int ivtv_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-                       yi->v4l2_src_w = r.width;
-                       yi->v4l2_src_h = r.height;
+       vin->index = itv->audio_input;
+       return ivtv_get_audio_input(itv, vin->index, vin);
+}
 
-                       switch (field) {
-                       case V4L2_FIELD_NONE:
-                               yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
-                               break;
-                       case V4L2_FIELD_ANY:
-                               yi->lace_mode = IVTV_YUV_MODE_AUTO;
-                               break;
-                       case V4L2_FIELD_INTERLACED_BT:
-                               yi->lace_mode =
-                                    IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
-                               break;
-                       case V4L2_FIELD_INTERLACED_TB:
-                       default:
-                               yi->lace_mode = IVTV_YUV_MODE_INTERLACED;
-                               break;
-                       }
-                       yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
+static int ivtv_s_audio(struct file *file, void *fh, struct v4l2_audio *vout)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-                       if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
-                               itv->dma_data_req_size =
-                                          1080 * ((yi->v4l2_src_h + 31) & ~31);
+       if (vout->index >= itv->nof_audio_inputs)
+               return -EINVAL;
 
-                       /* Force update of yuv registers */
-                       yi->yuv_forced_update = 1;
-                       return 0;
-               }
-               return 0;
-       }
+       itv->audio_input = vout->index;
+       ivtv_audio_set_io(itv);
 
-       if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) {
-               if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
-                       return -EINVAL;
-               if (set_fmt) {
-                       itv->osd_chroma_key = fmt->fmt.win.chromakey;
-                       itv->osd_global_alpha = fmt->fmt.win.global_alpha;
-                       ivtv_set_osd_alpha(itv);
-               }
-               return 0;
-       }
+       return 0;
+}
 
-       /* set window size */
-       if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               struct cx2341x_mpeg_params *p = &itv->params;
-               int w = fmt->fmt.pix.width;
-               int h = fmt->fmt.pix.height;
-
-               if (w > 720) w = 720;
-               else if (w < 1) w = 1;
-               if (h > (itv->is_50hz ? 576 : 480)) h = (itv->is_50hz ? 576 : 480);
-               else if (h < 2) h = 2;
-               ivtv_get_fmt(itv, streamtype, fmt);
-               fmt->fmt.pix.width = w;
-               fmt->fmt.pix.height = h;
-
-               if (!set_fmt || (p->width == w && p->height == h))
-                       return 0;
-               if (atomic_read(&itv->capturing) > 0)
-                       return -EBUSY;
+static int ivtv_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vin)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-               p->width = w;
-               p->height = h;
-               if (w != 720 || h != (itv->is_50hz ? 576 : 480))
-                       p->video_temporal_filter = 0;
-               else
-                       p->video_temporal_filter = 8;
-               if (p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
-                       fmt->fmt.pix.width /= 2;
-               itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
-               return ivtv_get_fmt(itv, streamtype, fmt);
-       }
+       /* set it to defaults from our table */
+       return ivtv_get_audio_output(itv, vin->index, vin);
+}
 
-       /* set raw VBI format */
-       if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-               if (set_fmt && atomic_read(&itv->capturing) > 0) {
-                       return -EBUSY;
-               }
-               if (set_fmt) {
-                       itv->vbi.sliced_in->service_set = 0;
-                       itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in);
-               }
-               return ivtv_get_fmt(itv, streamtype, fmt);
-       }
+static int ivtv_g_audout(struct file *file, void *fh, struct v4l2_audioout *vin)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-       /* set sliced VBI output
-          In principle the user could request that only certain
-          VBI types are output and that the others are ignored.
-          I.e., suppress CC in the even fields or only output
-          WSS and no VPS. Currently though there is no choice. */
-       if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT)
-               return ivtv_get_fmt(itv, streamtype, fmt);
+       vin->index = 0;
+       return ivtv_get_audio_output(itv, vin->index, vin);
+}
 
-       /* any else but sliced VBI capture is an error */
-       if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
-               return -EINVAL;
+static int ivtv_s_audout(struct file *file, void *fh, struct v4l2_audioout *vout)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-       if (streamtype == IVTV_DEC_STREAM_TYPE_VBI)
-               return ivtv_get_fmt(itv, streamtype, fmt);
+       return ivtv_get_audio_output(itv, vout->index, vout);
+}
 
-       /* set sliced VBI capture format */
-       vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
-       memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
+static int ivtv_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-       if (vbifmt->service_set)
-               expand_service_set(vbifmt, itv->is_50hz);
-       set = check_service_set(vbifmt, itv->is_50hz);
-       vbifmt->service_set = get_service_set(vbifmt);
+       /* set it to defaults from our table */
+       return ivtv_get_input(itv, vin->index, vin);
+}
 
-       if (!set_fmt)
-               return 0;
-       if (set == 0)
+static int ivtv_enum_output(struct file *file, void *fh, struct v4l2_output *vout)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+       return ivtv_get_output(itv, vout->index, vout);
+}
+
+static int ivtv_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap)
+{
+       struct ivtv_open_id *id = fh;
+       struct ivtv *itv = id->itv;
+       struct yuv_playback_info *yi = &itv->yuv_info;
+       int streamtype;
+
+       streamtype = id->type;
+
+       if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
                return -EINVAL;
-       if (atomic_read(&itv->capturing) > 0) {
-               return -EBUSY;
+       cropcap->bounds.top = cropcap->bounds.left = 0;
+       cropcap->bounds.width = 720;
+       if (cropcap->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               cropcap->bounds.height = itv->is_50hz ? 576 : 480;
+               cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10;
+               cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11;
+       } else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+               if (yi->track_osd) {
+                       cropcap->bounds.width = yi->osd_full_w;
+                       cropcap->bounds.height = yi->osd_full_h;
+               } else {
+                       cropcap->bounds.width = 720;
+                       cropcap->bounds.height =
+                                       itv->is_out_50hz ? 576 : 480;
+               }
+               cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
+               cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
+       } else {
+               cropcap->bounds.height = itv->is_out_50hz ? 576 : 480;
+               cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
+               cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
        }
-       itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
-       memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in));
+       cropcap->defrect = cropcap->bounds;
        return 0;
 }
 
-static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
+static int ivtv_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
 {
-       struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
+       struct ivtv_open_id *id = fh;
        struct ivtv *itv = id->itv;
-       struct v4l2_register *reg = arg;
+       struct yuv_playback_info *yi = &itv->yuv_info;
+       int streamtype;
 
-       switch (cmd) {
-       /* ioctls to allow direct access to the encoder registers for testing */
-       case VIDIOC_DBG_G_REGISTER:
-               if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
-                       return ivtv_itvc(itv, cmd, arg);
-               if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
-                       return ivtv_i2c_id(itv, reg->match_chip, cmd, arg);
-               return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg);
-
-       case VIDIOC_DBG_S_REGISTER:
-               if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
-                       return ivtv_itvc(itv, cmd, arg);
-               if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
-                       return ivtv_i2c_id(itv, reg->match_chip, cmd, arg);
-               return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg);
-
-       case VIDIOC_G_CHIP_IDENT: {
-               struct v4l2_chip_ident *chip = arg;
-
-               chip->ident = V4L2_IDENT_NONE;
-               chip->revision = 0;
-               if (reg->match_type == V4L2_CHIP_MATCH_HOST) {
-                       if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) {
-                               struct v4l2_chip_ident *chip = arg;
-
-                               chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416;
-                       }
+       streamtype = id->type;
+
+       if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+           (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+               if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+                       yi->main_rect = crop->c;
                        return 0;
+               } else {
+                       if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
+                               crop->c.width, crop->c.height, crop->c.left, crop->c.top)) {
+                               itv->main_rect = crop->c;
+                               return 0;
+                       }
                }
-               if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
-                       return ivtv_i2c_id(itv, reg->match_chip, cmd, arg);
-               if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
-                       return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg);
                return -EINVAL;
        }
+       return -EINVAL;
+}
 
-       case VIDIOC_INT_S_AUDIO_ROUTING: {
-               struct v4l2_routing *route = arg;
+static int ivtv_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+       struct ivtv_open_id *id = fh;
+       struct ivtv *itv = id->itv;
+       struct yuv_playback_info *yi = &itv->yuv_info;
+       int streamtype;
 
-               ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route);
-               break;
-       }
+       streamtype = id->type;
 
-       case VIDIOC_INT_RESET: {
-               u32 val = *(u32 *)arg;
+       if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+           (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+               if (streamtype == IVTV_DEC_STREAM_TYPE_YUV)
+                       crop->c = yi->main_rect;
+               else
+                       crop->c = itv->main_rect;
+               return 0;
+       }
+       return -EINVAL;
+}
 
-               if ((val == 0 && itv->options.newi2c) || (val & 0x01)) {
-                       ivtv_reset_ir_gpio(itv);
-               }
-               if (val & 0x02) {
-                       itv->video_dec_func(itv, cmd, 0);
+static int ivtv_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
+{
+       static struct v4l2_fmtdesc formats[] = {
+               { 0, 0, 0,
+                 "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12,
+                 { 0, 0, 0, 0 }
+               },
+               { 1, 0, V4L2_FMT_FLAG_COMPRESSED,
+                 "MPEG", V4L2_PIX_FMT_MPEG,
+                 { 0, 0, 0, 0 }
                }
-               break;
-       }
+       };
+       enum v4l2_buf_type type = fmt->type;
 
-       default:
+       if (fmt->index > 1)
                return -EINVAL;
-       }
+
+       *fmt = formats[fmt->index];
+       fmt->type = type;
        return 0;
 }
 
-int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg)
+static int ivtv_enum_fmt_vid_out(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
 {
-       struct ivtv_open_id *id = NULL;
-       u32 data[CX2341X_MBOX_MAX_DATA];
-       int streamtype = 0;
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+       static struct v4l2_fmtdesc formats[] = {
+               { 0, 0, 0,
+                 "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12,
+                 { 0, 0, 0, 0 }
+               },
+               { 1, 0, V4L2_FMT_FLAG_COMPRESSED,
+                 "MPEG", V4L2_PIX_FMT_MPEG,
+                 { 0, 0, 0, 0 }
+               }
+       };
+       enum v4l2_buf_type type = fmt->type;
 
-       if (filp) {
-               id = (struct ivtv_open_id *)filp->private_data;
-               streamtype = id->type;
-       }
+       if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+               return -EINVAL;
 
-       switch (cmd) {
-       case VIDIOC_G_PRIORITY:
-       {
-               enum v4l2_priority *p = arg;
+       if (fmt->index > 1)
+               return -EINVAL;
 
-               *p = v4l2_prio_max(&itv->prio);
-               break;
-       }
+       *fmt = formats[fmt->index];
+       fmt->type = type;
 
-       case VIDIOC_S_PRIORITY:
-       {
-               enum v4l2_priority *prio = arg;
+       return 0;
+}
 
-               return v4l2_prio_change(&itv->prio, &id->prio, *prio);
-       }
+static int ivtv_g_input(struct file *file, void *fh, unsigned int *i)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-       case VIDIOC_QUERYCAP:{
-               struct v4l2_capability *vcap = arg;
+       *i = itv->active_input;
 
-               memset(vcap, 0, sizeof(*vcap));
-               strcpy(vcap->driver, IVTV_DRIVER_NAME);     /* driver name */
-               strcpy(vcap->card, itv->card_name);         /* card type */
-               strcpy(vcap->bus_info, pci_name(itv->dev)); /* bus info... */
-               vcap->version = IVTV_DRIVER_VERSION;        /* version */
-               vcap->capabilities = itv->v4l2_cap;         /* capabilities */
+       return 0;
+}
 
-               /* reserved.. must set to 0! */
-               vcap->reserved[0] = vcap->reserved[1] =
-                       vcap->reserved[2] = vcap->reserved[3] = 0;
-               break;
-       }
+int ivtv_s_input(struct file *file, void *fh, unsigned int inp)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-       case VIDIOC_ENUMAUDIO:{
-               struct v4l2_audio *vin = arg;
+       if (inp < 0 || inp >= itv->nof_inputs)
+               return -EINVAL;
 
-               return ivtv_get_audio_input(itv, vin->index, vin);
+       if (inp == itv->active_input) {
+               IVTV_DEBUG_INFO("Input unchanged\n");
+               return 0;
        }
 
-       case VIDIOC_G_AUDIO:{
-               struct v4l2_audio *vin = arg;
-
-               vin->index = itv->audio_input;
-               return ivtv_get_audio_input(itv, vin->index, vin);
+       if (atomic_read(&itv->capturing) > 0) {
+               return -EBUSY;
        }
 
-       case VIDIOC_S_AUDIO:{
-               struct v4l2_audio *vout = arg;
-
-               if (vout->index >= itv->nof_audio_inputs)
-                       return -EINVAL;
-               itv->audio_input = vout->index;
-               ivtv_audio_set_io(itv);
-               break;
-       }
+       IVTV_DEBUG_INFO("Changing input from %d to %d\n",
+                       itv->active_input, inp);
 
-       case VIDIOC_ENUMAUDOUT:{
-               struct v4l2_audioout *vin = arg;
+       itv->active_input = inp;
+       /* Set the audio input to whatever is appropriate for the
+          input type. */
+       itv->audio_input = itv->card->video_inputs[inp].audio_index;
 
-               /* set it to defaults from our table */
-               return ivtv_get_audio_output(itv, vin->index, vin);
-       }
+       /* prevent others from messing with the streams until
+          we're finished changing inputs. */
+       ivtv_mute(itv);
+       ivtv_video_set_io(itv);
+       ivtv_audio_set_io(itv);
+       ivtv_unmute(itv);
 
-       case VIDIOC_G_AUDOUT:{
-               struct v4l2_audioout *vin = arg;
+       return 0;
+}
 
-               vin->index = 0;
-               return ivtv_get_audio_output(itv, vin->index, vin);
-       }
+static int ivtv_g_output(struct file *file, void *fh, unsigned int *i)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-       case VIDIOC_S_AUDOUT:{
-               struct v4l2_audioout *vout = arg;
+       if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+               return -EINVAL;
 
-               return ivtv_get_audio_output(itv, vout->index, vout);
-       }
+       *i = itv->active_output;
 
-       case VIDIOC_ENUMINPUT:{
-               struct v4l2_input *vin = arg;
+       return 0;
+}
 
-               /* set it to defaults from our table */
-               return ivtv_get_input(itv, vin->index, vin);
-       }
+static int ivtv_s_output(struct file *file, void *fh, unsigned int outp)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-       case VIDIOC_ENUMOUTPUT:{
-               struct v4l2_output *vout = arg;
+       if (outp >= itv->card->nof_outputs)
+               return -EINVAL;
 
-               return ivtv_get_output(itv, vout->index, vout);
+       if (outp == itv->active_output) {
+               IVTV_DEBUG_INFO("Output unchanged\n");
+               return 0;
        }
+       IVTV_DEBUG_INFO("Changing output from %d to %d\n",
+                  itv->active_output, outp);
 
-       case VIDIOC_TRY_FMT:
-       case VIDIOC_S_FMT: {
-               struct v4l2_format *fmt = arg;
+       itv->active_output = outp;
+       ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing,
+                       SAA7127_INPUT_TYPE_NORMAL,
+                       itv->card->video_outputs[outp].video_output, 0);
 
-               return ivtv_try_or_set_fmt(itv, id->type, fmt, cmd == VIDIOC_S_FMT);
-       }
+       return 0;
+}
 
-       case VIDIOC_G_FMT: {
-               struct v4l2_format *fmt = arg;
-               int type = fmt->type;
+static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-               memset(fmt, 0, sizeof(*fmt));
-               fmt->type = type;
-               return ivtv_get_fmt(itv, id->type, fmt);
-       }
+       if (vf->tuner != 0)
+               return -EINVAL;
 
-       case VIDIOC_CROPCAP: {
-               struct v4l2_cropcap *cropcap = arg;
+       ivtv_call_all(itv, tuner, g_frequency, vf);
+       return 0;
+}
 
-               if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-                   cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
-                       return -EINVAL;
-               cropcap->bounds.top = cropcap->bounds.left = 0;
-               cropcap->bounds.width = 720;
-               if (cropcap->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       cropcap->bounds.height = itv->is_50hz ? 576 : 480;
-                       cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10;
-                       cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11;
-               } else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
-                       cropcap->bounds.width = itv->yuv_info.osd_full_w;
-                       cropcap->bounds.height = itv->yuv_info.osd_full_h;
-                       cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
-                       cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
-               } else {
-                       cropcap->bounds.height = itv->is_out_50hz ? 576 : 480;
-                       cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
-                       cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
-               }
-               cropcap->defrect = cropcap->bounds;
-               return 0;
-       }
+int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-       case VIDIOC_S_CROP: {
-               struct v4l2_crop *crop = arg;
+       if (vf->tuner != 0)
+               return -EINVAL;
 
-               if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
-                   (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
-                       if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
-                               itv->yuv_info.main_rect = crop->c;
-                               return 0;
-                       } else {
-                               if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
-                                       crop->c.width, crop->c.height, crop->c.left, crop->c.top)) {
-                                       itv->main_rect = crop->c;
-                                       return 0;
-                               }
-                       }
-                       return -EINVAL;
-               }
-               if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-               return itv->video_dec_func(itv, VIDIOC_S_CROP, arg);
-       }
+       ivtv_mute(itv);
+       IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);
+       ivtv_call_all(itv, tuner, s_frequency, vf);
+       ivtv_unmute(itv);
+       return 0;
+}
 
-       case VIDIOC_G_CROP: {
-               struct v4l2_crop *crop = arg;
+static int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-               if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
-                   (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
-                       if (streamtype == IVTV_DEC_STREAM_TYPE_YUV)
-                               crop->c = itv->yuv_info.main_rect;
-                       else
-                               crop->c = itv->main_rect;
-                       return 0;
-               }
-               if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-               return itv->video_dec_func(itv, VIDIOC_G_CROP, arg);
-       }
+       *std = itv->std;
+       return 0;
+}
 
-       case VIDIOC_ENUM_FMT: {
-               static struct v4l2_fmtdesc formats[] = {
-                       { 0, 0, 0,
-                         "HM12 (YUV 4:2:2)", V4L2_PIX_FMT_HM12,
-                         { 0, 0, 0, 0 }
-                       },
-                       { 1, 0, V4L2_FMT_FLAG_COMPRESSED,
-                         "MPEG", V4L2_PIX_FMT_MPEG,
-                         { 0, 0, 0, 0 }
-                       }
-               };
-               struct v4l2_fmtdesc *fmt = arg;
-               enum v4l2_buf_type type = fmt->type;
+int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct yuv_playback_info *yi = &itv->yuv_info;
 
-               switch (type) {
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-                       break;
-               case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-                       if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
-                               return -EINVAL;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               if (fmt->index > 1)
-                       return -EINVAL;
-               *fmt = formats[fmt->index];
-               fmt->type = type;
+       if ((*std & V4L2_STD_ALL) == 0)
+               return -EINVAL;
+
+       if (*std == itv->std)
                return 0;
+
+       if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ||
+           atomic_read(&itv->capturing) > 0 ||
+           atomic_read(&itv->decoding) > 0) {
+               /* Switching standard would turn off the radio or mess
+                  with already running streams, prevent that by
+                  returning EBUSY. */
+               return -EBUSY;
        }
 
-       case VIDIOC_G_INPUT:{
-               *(int *)arg = itv->active_input;
-               break;
+       itv->std = *std;
+       itv->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
+       itv->params.is_50hz = itv->is_50hz = !itv->is_60hz;
+       itv->params.width = 720;
+       itv->params.height = itv->is_50hz ? 576 : 480;
+       itv->vbi.count = itv->is_50hz ? 18 : 12;
+       itv->vbi.start[0] = itv->is_50hz ? 6 : 10;
+       itv->vbi.start[1] = itv->is_50hz ? 318 : 273;
+
+       if (itv->hw_flags & IVTV_HW_CX25840)
+               itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284;
+
+       IVTV_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)itv->std);
+
+       /* Tuner */
+       ivtv_call_all(itv, core, s_std, itv->std);
+
+       if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+               /* set display standard */
+               itv->std_out = *std;
+               itv->is_out_60hz = itv->is_60hz;
+               itv->is_out_50hz = itv->is_50hz;
+               ivtv_call_all(itv, video, s_std_output, itv->std_out);
+               ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz);
+               itv->main_rect.left = itv->main_rect.top = 0;
+               itv->main_rect.width = 720;
+               itv->main_rect.height = itv->params.height;
+               ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
+                       720, itv->main_rect.height, 0, 0);
+               yi->main_rect = itv->main_rect;
+               if (!itv->osd_info) {
+                       yi->osd_full_w = 720;
+                       yi->osd_full_h = itv->is_out_50hz ? 576 : 480;
+               }
        }
+       return 0;
+}
+
+static int ivtv_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+       struct ivtv_open_id *id = fh;
+       struct ivtv *itv = id->itv;
 
-       case VIDIOC_S_INPUT:{
-               int inp = *(int *)arg;
+       if (vt->index != 0)
+               return -EINVAL;
 
-               if (inp < 0 || inp >= itv->nof_inputs)
-                       return -EINVAL;
+       ivtv_call_all(itv, tuner, s_tuner, vt);
 
-               if (inp == itv->active_input) {
-                       IVTV_DEBUG_INFO("Input unchanged\n");
-                       break;
-               }
-               if (atomic_read(&itv->capturing) > 0) {
-                       return -EBUSY;
-               }
-               IVTV_DEBUG_INFO("Changing input from %d to %d\n",
-                               itv->active_input, inp);
+       return 0;
+}
 
-               itv->active_input = inp;
-               /* Set the audio input to whatever is appropriate for the
-                  input type. */
-               itv->audio_input = itv->card->video_inputs[inp].audio_index;
+static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-               /* prevent others from messing with the streams until
-                  we're finished changing inputs. */
-               ivtv_mute(itv);
-               ivtv_video_set_io(itv);
-               ivtv_audio_set_io(itv);
-               ivtv_unmute(itv);
-               break;
-       }
+       if (vt->index != 0)
+               return -EINVAL;
 
-       case VIDIOC_G_OUTPUT:{
-               if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
-                       return -EINVAL;
-               *(int *)arg = itv->active_output;
-               break;
+       ivtv_call_all(itv, tuner, g_tuner, vt);
+
+       if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
+               strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name));
+               vt->type = V4L2_TUNER_RADIO;
+       } else {
+               strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name));
+               vt->type = V4L2_TUNER_ANALOG_TV;
        }
 
-       case VIDIOC_S_OUTPUT:{
-               int outp = *(int *)arg;
-               struct v4l2_routing route;
+       return 0;
+}
 
-               if (outp >= itv->card->nof_outputs)
-                       return -EINVAL;
+static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
+       int f, l;
 
-               if (outp == itv->active_output) {
-                       IVTV_DEBUG_INFO("Output unchanged\n");
-                       break;
+       if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+               for (f = 0; f < 2; f++) {
+                       for (l = 0; l < 24; l++) {
+                               if (valid_service_line(f, l, itv->is_50hz))
+                                       cap->service_lines[f][l] = set;
+                       }
                }
-               IVTV_DEBUG_INFO("Changing output from %d to %d\n",
-                          itv->active_output, outp);
-
-               itv->active_output = outp;
-               route.input = SAA7127_INPUT_TYPE_NORMAL;
-               route.output = itv->card->video_outputs[outp].video_output;
-               ivtv_saa7127(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
-               break;
+               return 0;
        }
-
-       case VIDIOC_G_FREQUENCY:{
-               struct v4l2_frequency *vf = arg;
-
-               if (vf->tuner != 0)
+       if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) {
+               if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
                        return -EINVAL;
-               ivtv_call_i2c_clients(itv, cmd, arg);
-               break;
+               if (itv->is_60hz) {
+                       cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+                       cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
+               } else {
+                       cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
+                       cap->service_lines[0][16] = V4L2_SLICED_VPS;
+               }
+               return 0;
        }
+       return -EINVAL;
+}
 
-       case VIDIOC_S_FREQUENCY:{
-               struct v4l2_frequency vf = *(struct v4l2_frequency *)arg;
-
-               if (vf.tuner != 0)
-                       return -EINVAL;
+static int ivtv_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *idx)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct v4l2_enc_idx_entry *e = idx->entry;
+       int entries;
+       int i;
 
-               ivtv_mute(itv);
-               IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency);
-               ivtv_call_i2c_clients(itv, cmd, &vf);
-               ivtv_unmute(itv);
-               break;
+       entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) %
+                               IVTV_MAX_PGM_INDEX;
+       if (entries > V4L2_ENC_IDX_ENTRIES)
+               entries = V4L2_ENC_IDX_ENTRIES;
+       idx->entries = 0;
+       for (i = 0; i < entries; i++) {
+               *e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX];
+               if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) {
+                       idx->entries++;
+                       e++;
+               }
        }
+       itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX;
+       return 0;
+}
 
-       case VIDIOC_ENUMSTD:{
-               struct v4l2_standard *vs = arg;
-               int idx = vs->index;
-
-               if (idx < 0 || idx >= ARRAY_SIZE(enum_stds))
-                       return -EINVAL;
-
-               *vs = (enum_stds[idx].std & V4L2_STD_525_60) ?
-                               ivtv_std_60hz : ivtv_std_50hz;
-               vs->index = idx;
-               vs->id = enum_stds[idx].std;
-               strcpy(vs->name, enum_stds[idx].name);
-               break;
-       }
+static int ivtv_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc)
+{
+       struct ivtv_open_id *id = fh;
+       struct ivtv *itv = id->itv;
 
-       case VIDIOC_G_STD:{
-               *(v4l2_std_id *) arg = itv->std;
-               break;
-       }
 
-       case VIDIOC_S_STD: {
-               v4l2_std_id std = *(v4l2_std_id *) arg;
+       switch (enc->cmd) {
+       case V4L2_ENC_CMD_START:
+               IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
+               enc->flags = 0;
+               return ivtv_start_capture(id);
 
-               if ((std & V4L2_STD_ALL) == 0)
-                       return -EINVAL;
+       case V4L2_ENC_CMD_STOP:
+               IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
+               enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
+               ivtv_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
+               return 0;
 
-               if (std == itv->std)
-                       break;
+       case V4L2_ENC_CMD_PAUSE:
+               IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
+               enc->flags = 0;
 
-               if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ||
-                   atomic_read(&itv->capturing) > 0 ||
-                   atomic_read(&itv->decoding) > 0) {
-                       /* Switching standard would turn off the radio or mess
-                          with already running streams, prevent that by
-                          returning EBUSY. */
-                       return -EBUSY;
-               }
+               if (!atomic_read(&itv->capturing))
+                       return -EPERM;
+               if (test_and_set_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
+                       return 0;
 
-               itv->std = std;
-               itv->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0;
-               itv->params.is_50hz = itv->is_50hz = !itv->is_60hz;
-               itv->params.width = 720;
-               itv->params.height = itv->is_50hz ? 576 : 480;
-               itv->vbi.count = itv->is_50hz ? 18 : 12;
-               itv->vbi.start[0] = itv->is_50hz ? 6 : 10;
-               itv->vbi.start[1] = itv->is_50hz ? 318 : 273;
-               if (itv->hw_flags & IVTV_HW_CX25840) {
-                       itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284;
-               }
-               IVTV_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)itv->std);
-
-               /* Tuner */
-               ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std);
-
-               if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
-                       /* set display standard */
-                       itv->std_out = std;
-                       itv->is_out_60hz = itv->is_60hz;
-                       itv->is_out_50hz = itv->is_50hz;
-                       ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std_out);
-                       ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz);
-                       itv->main_rect.left = itv->main_rect.top = 0;
-                       itv->main_rect.width = 720;
-                       itv->main_rect.height = itv->params.height;
-                       ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
-                               720, itv->main_rect.height, 0, 0);
-                       itv->yuv_info.main_rect = itv->main_rect;
-                       if (!itv->osd_info) {
-                               itv->yuv_info.osd_full_w = 720;
-                               itv->yuv_info.osd_full_h =
-                                               itv->is_out_50hz ? 576 : 480;
-                       }
-               }
+               ivtv_mute(itv);
+               ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 0);
                break;
-       }
 
-       case VIDIOC_S_TUNER: {  /* Setting tuner can only set audio mode */
-               struct v4l2_tuner *vt = arg;
+       case V4L2_ENC_CMD_RESUME:
+               IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
+               enc->flags = 0;
 
-               if (vt->index != 0)
-                       return -EINVAL;
+               if (!atomic_read(&itv->capturing))
+                       return -EPERM;
+
+               if (!test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
+                       return 0;
 
-               ivtv_call_i2c_clients(itv, VIDIOC_S_TUNER, vt);
+               ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1);
+               ivtv_unmute(itv);
                break;
+       default:
+               IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
+               return -EINVAL;
        }
 
-       case VIDIOC_G_TUNER: {
-               struct v4l2_tuner *vt = arg;
+       return 0;
+}
 
-               if (vt->index != 0)
-                       return -EINVAL;
+static int ivtv_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-               memset(vt, 0, sizeof(*vt));
-               ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt);
+       switch (enc->cmd) {
+       case V4L2_ENC_CMD_START:
+               IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
+               enc->flags = 0;
+               return 0;
 
-               if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
-                       strcpy(vt->name, "ivtv Radio Tuner");
-                       vt->type = V4L2_TUNER_RADIO;
-               } else {
-                       strcpy(vt->name, "ivtv TV Tuner");
-                       vt->type = V4L2_TUNER_ANALOG_TV;
-               }
-               break;
-       }
+       case V4L2_ENC_CMD_STOP:
+               IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
+               enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
+               return 0;
 
-       case VIDIOC_G_SLICED_VBI_CAP: {
-               struct v4l2_sliced_vbi_cap *cap = arg;
-               int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
-               int f, l;
-               enum v4l2_buf_type type = cap->type;
-
-               memset(cap, 0, sizeof(*cap));
-               cap->type = type;
-               if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
-                       for (f = 0; f < 2; f++) {
-                               for (l = 0; l < 24; l++) {
-                                       if (valid_service_line(f, l, itv->is_50hz)) {
-                                               cap->service_lines[f][l] = set;
-                                       }
-                               }
-                       }
-                       return 0;
-               }
-               if (type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) {
-                       if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
-                               return -EINVAL;
-                       if (itv->is_60hz) {
-                               cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
-                               cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
-                       } else {
-                               cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
-                               cap->service_lines[0][16] = V4L2_SLICED_VPS;
-                       }
-                       return 0;
-               }
-               return -EINVAL;
-       }
+       case V4L2_ENC_CMD_PAUSE:
+               IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
+               enc->flags = 0;
+               return 0;
 
-       case VIDIOC_G_ENC_INDEX: {
-               struct v4l2_enc_idx *idx = arg;
-               struct v4l2_enc_idx_entry *e = idx->entry;
-               int entries;
-               int i;
-
-               entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) %
-                                       IVTV_MAX_PGM_INDEX;
-               if (entries > V4L2_ENC_IDX_ENTRIES)
-                       entries = V4L2_ENC_IDX_ENTRIES;
-               idx->entries = 0;
-               for (i = 0; i < entries; i++) {
-                       *e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX];
-                       if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) {
-                               idx->entries++;
-                               e++;
-                       }
-               }
-               itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX;
-               break;
+       case V4L2_ENC_CMD_RESUME:
+               IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
+               enc->flags = 0;
+               return 0;
+       default:
+               IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
+               return -EINVAL;
        }
+}
 
-       case VIDIOC_ENCODER_CMD:
-       case VIDIOC_TRY_ENCODER_CMD: {
-               struct v4l2_encoder_cmd *enc = arg;
-               int try = cmd == VIDIOC_TRY_ENCODER_CMD;
-
-               memset(&enc->raw, 0, sizeof(enc->raw));
-               switch (enc->cmd) {
-               case V4L2_ENC_CMD_START:
-                       IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
-                       enc->flags = 0;
-                       if (try)
-                               return 0;
-                       return ivtv_start_capture(id);
-
-               case V4L2_ENC_CMD_STOP:
-                       IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
-                       enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
-                       if (try)
-                               return 0;
-                       ivtv_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
-                       return 0;
+static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       u32 data[CX2341X_MBOX_MAX_DATA];
+       struct yuv_playback_info *yi = &itv->yuv_info;
 
-               case V4L2_ENC_CMD_PAUSE:
-                       IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
-                       enc->flags = 0;
-                       if (try)
-                               return 0;
-                       if (!atomic_read(&itv->capturing))
-                               return -EPERM;
-                       if (test_and_set_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
-                               return 0;
-                       ivtv_mute(itv);
-                       ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 0);
-                       break;
+       int pixfmt;
+       static u32 pixel_format[16] = {
+               V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */
+               V4L2_PIX_FMT_RGB565,
+               V4L2_PIX_FMT_RGB555,
+               V4L2_PIX_FMT_RGB444,
+               V4L2_PIX_FMT_RGB32,
+               0,
+               0,
+               0,
+               V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */
+               V4L2_PIX_FMT_YUV565,
+               V4L2_PIX_FMT_YUV555,
+               V4L2_PIX_FMT_YUV444,
+               V4L2_PIX_FMT_YUV32,
+               0,
+               0,
+               0,
+       };
+
+       if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+               return -EINVAL;
+       if (!itv->osd_video_pbase)
+               return -EINVAL;
 
-               case V4L2_ENC_CMD_RESUME:
-                       IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
-                       enc->flags = 0;
-                       if (try)
-                               return 0;
-                       if (!atomic_read(&itv->capturing))
-                               return -EPERM;
-                       if (!test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
-                               return 0;
-                       ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1);
-                       ivtv_unmute(itv);
-                       break;
-               default:
-                       IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
-                       return -EINVAL;
-               }
-               break;
-       }
+       fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY |
+               V4L2_FBUF_CAP_GLOBAL_ALPHA;
+
+       ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
+       data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
+       pixfmt = (data[0] >> 3) & 0xf;
+
+       fb->fmt.pixelformat = pixel_format[pixfmt];
+       fb->fmt.width = itv->osd_rect.width;
+       fb->fmt.height = itv->osd_rect.height;
+       fb->fmt.field = V4L2_FIELD_INTERLACED;
+       fb->fmt.bytesperline = fb->fmt.width;
+       fb->fmt.colorspace = V4L2_COLORSPACE_SMPTE170M;
+       fb->fmt.field = V4L2_FIELD_INTERLACED;
+       fb->fmt.priv = 0;
+       if (fb->fmt.pixelformat != V4L2_PIX_FMT_PAL8)
+               fb->fmt.bytesperline *= 2;
+       if (fb->fmt.pixelformat == V4L2_PIX_FMT_RGB32 ||
+           fb->fmt.pixelformat == V4L2_PIX_FMT_YUV32)
+               fb->fmt.bytesperline *= 2;
+       fb->fmt.sizeimage = fb->fmt.bytesperline * fb->fmt.height;
+       fb->base = (void *)itv->osd_video_pbase;
+       fb->flags = 0;
+
+       if (itv->osd_chroma_key_state)
+               fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
+
+       if (itv->osd_global_alpha_state)
+               fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
+
+       if (yi->track_osd)
+               fb->flags |= V4L2_FBUF_FLAG_OVERLAY;
+
+       pixfmt &= 7;
+
+       /* no local alpha for RGB565 or unknown formats */
+       if (pixfmt == 1 || pixfmt > 4)
+               return 0;
 
-       case VIDIOC_G_FBUF: {
-               struct v4l2_framebuffer *fb = arg;
-               int pixfmt;
-               static u32 pixel_format[16] = {
-                       V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */
-                       V4L2_PIX_FMT_RGB565,
-                       V4L2_PIX_FMT_RGB555,
-                       V4L2_PIX_FMT_RGB444,
-                       V4L2_PIX_FMT_RGB32,
-                       0,
-                       0,
-                       0,
-                       V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */
-                       V4L2_PIX_FMT_YUV565,
-                       V4L2_PIX_FMT_YUV555,
-                       V4L2_PIX_FMT_YUV444,
-                       V4L2_PIX_FMT_YUV32,
-                       0,
-                       0,
-                       0,
-               };
+       /* 16-bit formats have inverted local alpha */
+       if (pixfmt == 2 || pixfmt == 3)
+               fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA;
+       else
+               fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA;
 
-               memset(fb, 0, sizeof(*fb));
-               if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
-                       return -EINVAL;
-               fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY |
-                       V4L2_FBUF_CAP_GLOBAL_ALPHA;
-               ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
-               data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
-               pixfmt = (data[0] >> 3) & 0xf;
-               fb->fmt.pixelformat = pixel_format[pixfmt];
-               fb->fmt.width = itv->osd_rect.width;
-               fb->fmt.height = itv->osd_rect.height;
-               fb->base = (void *)itv->osd_video_pbase;
-               if (itv->osd_chroma_key_state)
-                       fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
-               if (itv->osd_global_alpha_state)
-                       fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
-               pixfmt &= 7;
-               /* no local alpha for RGB565 or unknown formats */
-               if (pixfmt == 1 || pixfmt > 4)
-                       break;
+       if (itv->osd_local_alpha_state) {
                /* 16-bit formats have inverted local alpha */
                if (pixfmt == 2 || pixfmt == 3)
-                       fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA;
+                       fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA;
                else
-                       fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA;
-               if (itv->osd_local_alpha_state) {
-                       /* 16-bit formats have inverted local alpha */
-                       if (pixfmt == 2 || pixfmt == 3)
-                               fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA;
-                       else
-                               fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
-               }
-               break;
+                       fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
        }
 
-       case VIDIOC_S_FBUF: {
-               struct v4l2_framebuffer *fb = arg;
+       return 0;
+}
 
-               if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
-                       return -EINVAL;
-               itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
-               itv->osd_local_alpha_state =
-                       (fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0;
-               itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
-               ivtv_set_osd_alpha(itv);
-               break;
-       }
+static int ivtv_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
+{
+       struct ivtv_open_id *id = fh;
+       struct ivtv *itv = id->itv;
+       struct yuv_playback_info *yi = &itv->yuv_info;
 
-       case VIDIOC_OVERLAY: {
-               int *on = arg;
+       if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+               return -EINVAL;
+       if (!itv->osd_video_pbase)
+               return -EINVAL;
 
-               if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
-                       return -EINVAL;
-               ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, *on != 0);
-               break;
-       }
+       itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
+       itv->osd_local_alpha_state =
+               (fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0;
+       itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
+       ivtv_set_osd_alpha(itv);
+       yi->track_osd = (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0;
+       return ivtv_g_fbuf(file, fh, fb);
+}
 
-       case VIDIOC_LOG_STATUS:
-       {
-               int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT;
-               struct v4l2_input vidin;
-               struct v4l2_audio audin;
-               int i;
+static int ivtv_overlay(struct file *file, void *fh, unsigned int on)
+{
+       struct ivtv_open_id *id = fh;
+       struct ivtv *itv = id->itv;
 
-               IVTV_INFO("=================  START STATUS CARD #%d  =================\n", itv->num);
-               IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name);
-               if (itv->hw_flags & IVTV_HW_TVEEPROM) {
-                       struct tveeprom tv;
+       if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+               return -EINVAL;
 
-                       ivtv_read_eeprom(itv, &tv);
-               }
-               ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL);
-               ivtv_get_input(itv, itv->active_input, &vidin);
-               ivtv_get_audio_input(itv, itv->audio_input, &audin);
-               IVTV_INFO("Video Input:  %s\n", vidin.name);
-               IVTV_INFO("Audio Input:  %s%s\n", audin.name,
-                       (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : "");
-               if (has_output) {
-                       struct v4l2_output vidout;
-                       struct v4l2_audioout audout;
-                       int mode = itv->output_mode;
-                       static const char * const output_modes[5] = {
-                               "None",
-                               "MPEG Streaming",
-                               "YUV Streaming",
-                               "YUV Frames",
-                               "Passthrough",
-                       };
-                       static const char * const audio_modes[5] = {
-                               "Stereo",
-                               "Left",
-                               "Right",
-                               "Mono",
-                               "Swapped"
-                       };
-                       static const char * const alpha_mode[4] = {
-                               "None",
-                               "Global",
-                               "Local",
-                               "Global and Local"
-                       };
-                       static const char * const pixel_format[16] = {
-                               "ARGB Indexed",
-                               "RGB 5:6:5",
-                               "ARGB 1:5:5:5",
-                               "ARGB 1:4:4:4",
-                               "ARGB 8:8:8:8",
-                               "5",
-                               "6",
-                               "7",
-                               "AYUV Indexed",
-                               "YUV 5:6:5",
-                               "AYUV 1:5:5:5",
-                               "AYUV 1:4:4:4",
-                               "AYUV 8:8:8:8",
-                               "13",
-                               "14",
-                               "15",
-                       };
-
-                       ivtv_get_output(itv, itv->active_output, &vidout);
-                       ivtv_get_audio_output(itv, 0, &audout);
-                       IVTV_INFO("Video Output: %s\n", vidout.name);
-                       IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name,
-                               audio_modes[itv->audio_stereo_mode],
-                               audio_modes[itv->audio_bilingual_mode]);
-                       if (mode < 0 || mode > OUT_PASSTHROUGH)
-                               mode = OUT_NONE;
-                       IVTV_INFO("Output Mode:  %s\n", output_modes[mode]);
-                       ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
-                       data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
-                       IVTV_INFO("Overlay:      %s, Alpha: %s, Pixel Format: %s\n",
-                               data[0] & 1 ? "On" : "Off",
-                               alpha_mode[(data[0] >> 1) & 0x3],
-                               pixel_format[(data[0] >> 3) & 0xf]);
-               }
-               IVTV_INFO("Tuner:  %s\n",
-                       test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");
-               cx2341x_log_status(&itv->params, itv->name);
-               IVTV_INFO("Status flags:    0x%08lx\n", itv->i_flags);
-               for (i = 0; i < IVTV_MAX_STREAMS; i++) {
-                       struct ivtv_stream *s = &itv->streams[i];
-
-                       if (s->v4l2dev == NULL || s->buffers == 0)
-                               continue;
-                       IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags,
-                                       (s->buffers - s->q_free.buffers) * 100 / s->buffers,
-                                       (s->buffers * s->buf_size) / 1024, s->buffers);
-               }
-               IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted);
-               IVTV_INFO("==================  END STATUS CARD #%d  ==================\n", itv->num);
-               break;
-       }
+       ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, on != 0);
+
+       return 0;
+}
+
+static int ivtv_log_status(struct file *file, void *fh)
+{
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       u32 data[CX2341X_MBOX_MAX_DATA];
+
+       int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT;
+       struct v4l2_input vidin;
+       struct v4l2_audio audin;
+       int i;
+
+       IVTV_INFO("=================  START STATUS CARD #%d  =================\n",
+                      itv->instance);
+       IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name);
+       if (itv->hw_flags & IVTV_HW_TVEEPROM) {
+               struct tveeprom tv;
+
+               ivtv_read_eeprom(itv, &tv);
+       }
+       ivtv_call_all(itv, core, log_status);
+       ivtv_get_input(itv, itv->active_input, &vidin);
+       ivtv_get_audio_input(itv, itv->audio_input, &audin);
+       IVTV_INFO("Video Input:  %s\n", vidin.name);
+       IVTV_INFO("Audio Input:  %s%s\n", audin.name,
+               (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : "");
+       if (has_output) {
+               struct v4l2_output vidout;
+               struct v4l2_audioout audout;
+               int mode = itv->output_mode;
+               static const char * const output_modes[5] = {
+                       "None",
+                       "MPEG Streaming",
+                       "YUV Streaming",
+                       "YUV Frames",
+                       "Passthrough",
+               };
+               static const char * const audio_modes[5] = {
+                       "Stereo",
+                       "Left",
+                       "Right",
+                       "Mono",
+                       "Swapped"
+               };
+               static const char * const alpha_mode[4] = {
+                       "None",
+                       "Global",
+                       "Local",
+                       "Global and Local"
+               };
+               static const char * const pixel_format[16] = {
+                       "ARGB Indexed",
+                       "RGB 5:6:5",
+                       "ARGB 1:5:5:5",
+                       "ARGB 1:4:4:4",
+                       "ARGB 8:8:8:8",
+                       "5",
+                       "6",
+                       "7",
+                       "AYUV Indexed",
+                       "YUV 5:6:5",
+                       "AYUV 1:5:5:5",
+                       "AYUV 1:4:4:4",
+                       "AYUV 8:8:8:8",
+                       "13",
+                       "14",
+                       "15",
+               };
+
+               ivtv_get_output(itv, itv->active_output, &vidout);
+               ivtv_get_audio_output(itv, 0, &audout);
+               IVTV_INFO("Video Output: %s\n", vidout.name);
+               IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name,
+                       audio_modes[itv->audio_stereo_mode],
+                       audio_modes[itv->audio_bilingual_mode]);
+               if (mode < 0 || mode > OUT_PASSTHROUGH)
+                       mode = OUT_NONE;
+               IVTV_INFO("Output Mode:  %s\n", output_modes[mode]);
+               ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
+               data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
+               IVTV_INFO("Overlay:      %s, Alpha: %s, Pixel Format: %s\n",
+                       data[0] & 1 ? "On" : "Off",
+                       alpha_mode[(data[0] >> 1) & 0x3],
+                       pixel_format[(data[0] >> 3) & 0xf]);
+       }
+       IVTV_INFO("Tuner:  %s\n",
+               test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");
+       cx2341x_log_status(&itv->params, itv->v4l2_dev.name);
+       IVTV_INFO("Status flags:    0x%08lx\n", itv->i_flags);
+       for (i = 0; i < IVTV_MAX_STREAMS; i++) {
+               struct ivtv_stream *s = &itv->streams[i];
+
+               if (s->vdev == NULL || s->buffers == 0)
+                       continue;
+               IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags,
+                               (s->buffers - s->q_free.buffers) * 100 / s->buffers,
+                               (s->buffers * s->buf_size) / 1024, s->buffers);
+       }
+
+       IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n",
+                       (long long)itv->mpg_data_received,
+                       (long long)itv->vbi_data_inserted);
+       IVTV_INFO("==================  END STATUS CARD #%d  ==================\n",
+                       itv->instance);
 
-       default:
-               return -EINVAL;
-       }
        return 0;
 }
 
@@ -1421,7 +1555,7 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
                        return -EINVAL;
                if (itv->output_mode == OUT_UDMA_YUV && args->y_source == NULL)
                        return 0;
-               if (ivtv_claim_stream(id, id->type)) {
+               if (ivtv_start_decoding(id, id->type)) {
                        return -EBUSY;
                }
                if (ivtv_set_output_mode(itv, OUT_UDMA_YUV) != OUT_UDMA_YUV) {
@@ -1595,100 +1729,20 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
        return 0;
 }
 
-static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp,
-                             unsigned int cmd, void *arg)
+static long ivtv_default(struct file *file, void *fh, int cmd, void *arg)
 {
-       struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
-       struct ivtv *itv = id->itv;
-       int ret;
-
-       /* check priority */
-       switch (cmd) {
-       case VIDIOC_S_CTRL:
-       case VIDIOC_S_STD:
-       case VIDIOC_S_INPUT:
-       case VIDIOC_S_OUTPUT:
-       case VIDIOC_S_TUNER:
-       case VIDIOC_S_FREQUENCY:
-       case VIDIOC_S_FMT:
-       case VIDIOC_S_CROP:
-       case VIDIOC_S_AUDIO:
-       case VIDIOC_S_AUDOUT:
-       case VIDIOC_S_EXT_CTRLS:
-       case VIDIOC_S_FBUF:
-       case VIDIOC_OVERLAY:
-               ret = v4l2_prio_check(&itv->prio, &id->prio);
-               if (ret)
-                       return ret;
-       }
+       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
        switch (cmd) {
-       case VIDIOC_DBG_G_REGISTER:
-       case VIDIOC_DBG_S_REGISTER:
-       case VIDIOC_G_CHIP_IDENT:
-       case VIDIOC_INT_S_AUDIO_ROUTING:
-       case VIDIOC_INT_RESET:
-               if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
-                       printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
-                       v4l_printk_ioctl(cmd);
-               }
-               return ivtv_debug_ioctls(filp, cmd, arg);
-
-       case VIDIOC_G_PRIORITY:
-       case VIDIOC_S_PRIORITY:
-       case VIDIOC_QUERYCAP:
-       case VIDIOC_ENUMINPUT:
-       case VIDIOC_G_INPUT:
-       case VIDIOC_S_INPUT:
-       case VIDIOC_ENUMOUTPUT:
-       case VIDIOC_G_OUTPUT:
-       case VIDIOC_S_OUTPUT:
-       case VIDIOC_G_FMT:
-       case VIDIOC_S_FMT:
-       case VIDIOC_TRY_FMT:
-       case VIDIOC_ENUM_FMT:
-       case VIDIOC_CROPCAP:
-       case VIDIOC_G_CROP:
-       case VIDIOC_S_CROP:
-       case VIDIOC_G_FREQUENCY:
-       case VIDIOC_S_FREQUENCY:
-       case VIDIOC_ENUMSTD:
-       case VIDIOC_G_STD:
-       case VIDIOC_S_STD:
-       case VIDIOC_S_TUNER:
-       case VIDIOC_G_TUNER:
-       case VIDIOC_ENUMAUDIO:
-       case VIDIOC_S_AUDIO:
-       case VIDIOC_G_AUDIO:
-       case VIDIOC_ENUMAUDOUT:
-       case VIDIOC_S_AUDOUT:
-       case VIDIOC_G_AUDOUT:
-       case VIDIOC_G_SLICED_VBI_CAP:
-       case VIDIOC_LOG_STATUS:
-       case VIDIOC_G_ENC_INDEX:
-       case VIDIOC_ENCODER_CMD:
-       case VIDIOC_TRY_ENCODER_CMD:
-       case VIDIOC_G_FBUF:
-       case VIDIOC_S_FBUF:
-       case VIDIOC_OVERLAY:
-               if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
-                       printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
-                       v4l_printk_ioctl(cmd);
-               }
-               return ivtv_v4l2_ioctls(itv, filp, cmd, arg);
+       case VIDIOC_INT_RESET: {
+               u32 val = *(u32 *)arg;
 
-       case VIDIOC_QUERYMENU:
-       case VIDIOC_QUERYCTRL:
-       case VIDIOC_S_CTRL:
-       case VIDIOC_G_CTRL:
-       case VIDIOC_S_EXT_CTRLS:
-       case VIDIOC_G_EXT_CTRLS:
-       case VIDIOC_TRY_EXT_CTRLS:
-               if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
-                       printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
-                       v4l_printk_ioctl(cmd);
-               }
-               return ivtv_control_ioctls(itv, cmd, arg);
+               if ((val == 0 && itv->options.newi2c) || (val & 0x01))
+                       ivtv_reset_ir_gpio(itv);
+               if (val & 0x02)
+                       v4l2_subdev_call(itv->sd_video, core, reset, 0);
+               break;
+       }
 
        case IVTV_IOC_DMA_FRAME:
        case VIDEO_GET_PTS:
@@ -1700,21 +1754,22 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp,
        case VIDEO_CONTINUE:
        case VIDEO_COMMAND:
        case VIDEO_TRY_COMMAND:
-               return ivtv_decoder_ioctls(filp, cmd, arg);
+               return ivtv_decoder_ioctls(file, cmd, (void *)arg);
 
-       case 0x00005401:        /* Handle isatty() calls */
-               return -EINVAL;
        default:
-               return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
-                                                  ivtv_v4l2_do_ioctl);
+               return -EINVAL;
        }
        return 0;
 }
 
-static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct file *filp,
+static long ivtv_serialized_ioctl(struct ivtv *itv, struct file *filp,
                unsigned int cmd, unsigned long arg)
 {
-       /* Filter dvb ioctls that cannot be handled by video_usercopy */
+       struct video_device *vfd = video_devdata(filp);
+       struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
+       long ret;
+
+       /* Filter dvb ioctls that cannot be handled by the v4l ioctl framework */
        switch (cmd) {
        case VIDEO_SELECT_SOURCE:
                IVTV_DEBUG_IOCTL("VIDEO_SELECT_SOURCE\n");
@@ -1746,18 +1801,113 @@ static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct f
        default:
                break;
        }
-       return video_usercopy(inode, filp, cmd, arg, ivtv_v4l2_do_ioctl);
+
+       /* check priority */
+       switch (cmd) {
+       case VIDIOC_S_CTRL:
+       case VIDIOC_S_STD:
+       case VIDIOC_S_INPUT:
+       case VIDIOC_S_OUTPUT:
+       case VIDIOC_S_TUNER:
+       case VIDIOC_S_FREQUENCY:
+       case VIDIOC_S_FMT:
+       case VIDIOC_S_CROP:
+       case VIDIOC_S_AUDIO:
+       case VIDIOC_S_AUDOUT:
+       case VIDIOC_S_EXT_CTRLS:
+       case VIDIOC_S_FBUF:
+       case VIDIOC_OVERLAY:
+               ret = v4l2_prio_check(&itv->prio, &id->prio);
+               if (ret)
+                       return ret;
+       }
+
+       if (ivtv_debug & IVTV_DBGFLG_IOCTL)
+               vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
+       ret = video_ioctl2(filp, cmd, arg);
+       vfd->debug = 0;
+       return ret;
 }
 
-int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
-                   unsigned long arg)
+long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
        struct ivtv *itv = id->itv;
-       int res;
+       long res;
 
        mutex_lock(&itv->serialize_lock);
-       res = ivtv_serialized_ioctl(itv, inode, filp, cmd, arg);
+       res = ivtv_serialized_ioctl(itv, filp, cmd, arg);
        mutex_unlock(&itv->serialize_lock);
        return res;
 }
+
+static const struct v4l2_ioctl_ops ivtv_ioctl_ops = {
+       .vidioc_querycap                    = ivtv_querycap,
+       .vidioc_g_priority                  = ivtv_g_priority,
+       .vidioc_s_priority                  = ivtv_s_priority,
+       .vidioc_s_audio                     = ivtv_s_audio,
+       .vidioc_g_audio                     = ivtv_g_audio,
+       .vidioc_enumaudio                   = ivtv_enumaudio,
+       .vidioc_s_audout                    = ivtv_s_audout,
+       .vidioc_g_audout                    = ivtv_g_audout,
+       .vidioc_enum_input                  = ivtv_enum_input,
+       .vidioc_enum_output                 = ivtv_enum_output,
+       .vidioc_enumaudout                  = ivtv_enumaudout,
+       .vidioc_cropcap                     = ivtv_cropcap,
+       .vidioc_s_crop                      = ivtv_s_crop,
+       .vidioc_g_crop                      = ivtv_g_crop,
+       .vidioc_g_input                     = ivtv_g_input,
+       .vidioc_s_input                     = ivtv_s_input,
+       .vidioc_g_output                    = ivtv_g_output,
+       .vidioc_s_output                    = ivtv_s_output,
+       .vidioc_g_frequency                 = ivtv_g_frequency,
+       .vidioc_s_frequency                 = ivtv_s_frequency,
+       .vidioc_s_tuner                     = ivtv_s_tuner,
+       .vidioc_g_tuner                     = ivtv_g_tuner,
+       .vidioc_g_enc_index                 = ivtv_g_enc_index,
+       .vidioc_g_fbuf                      = ivtv_g_fbuf,
+       .vidioc_s_fbuf                      = ivtv_s_fbuf,
+       .vidioc_g_std                       = ivtv_g_std,
+       .vidioc_s_std                       = ivtv_s_std,
+       .vidioc_overlay                     = ivtv_overlay,
+       .vidioc_log_status                  = ivtv_log_status,
+       .vidioc_enum_fmt_vid_cap            = ivtv_enum_fmt_vid_cap,
+       .vidioc_encoder_cmd                 = ivtv_encoder_cmd,
+       .vidioc_try_encoder_cmd             = ivtv_try_encoder_cmd,
+       .vidioc_enum_fmt_vid_out            = ivtv_enum_fmt_vid_out,
+       .vidioc_g_fmt_vid_cap               = ivtv_g_fmt_vid_cap,
+       .vidioc_g_fmt_vbi_cap               = ivtv_g_fmt_vbi_cap,
+       .vidioc_g_fmt_sliced_vbi_cap        = ivtv_g_fmt_sliced_vbi_cap,
+       .vidioc_g_fmt_vid_out               = ivtv_g_fmt_vid_out,
+       .vidioc_g_fmt_vid_out_overlay       = ivtv_g_fmt_vid_out_overlay,
+       .vidioc_g_fmt_sliced_vbi_out        = ivtv_g_fmt_sliced_vbi_out,
+       .vidioc_s_fmt_vid_cap               = ivtv_s_fmt_vid_cap,
+       .vidioc_s_fmt_vbi_cap               = ivtv_s_fmt_vbi_cap,
+       .vidioc_s_fmt_sliced_vbi_cap        = ivtv_s_fmt_sliced_vbi_cap,
+       .vidioc_s_fmt_vid_out               = ivtv_s_fmt_vid_out,
+       .vidioc_s_fmt_vid_out_overlay       = ivtv_s_fmt_vid_out_overlay,
+       .vidioc_s_fmt_sliced_vbi_out        = ivtv_s_fmt_sliced_vbi_out,
+       .vidioc_try_fmt_vid_cap             = ivtv_try_fmt_vid_cap,
+       .vidioc_try_fmt_vbi_cap             = ivtv_try_fmt_vbi_cap,
+       .vidioc_try_fmt_sliced_vbi_cap      = ivtv_try_fmt_sliced_vbi_cap,
+       .vidioc_try_fmt_vid_out             = ivtv_try_fmt_vid_out,
+       .vidioc_try_fmt_vid_out_overlay     = ivtv_try_fmt_vid_out_overlay,
+       .vidioc_try_fmt_sliced_vbi_out      = ivtv_try_fmt_sliced_vbi_out,
+       .vidioc_g_sliced_vbi_cap            = ivtv_g_sliced_vbi_cap,
+       .vidioc_g_chip_ident                = ivtv_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register                  = ivtv_g_register,
+       .vidioc_s_register                  = ivtv_s_register,
+#endif
+       .vidioc_default                     = ivtv_default,
+       .vidioc_queryctrl                   = ivtv_queryctrl,
+       .vidioc_querymenu                   = ivtv_querymenu,
+       .vidioc_g_ext_ctrls                 = ivtv_g_ext_ctrls,
+       .vidioc_s_ext_ctrls                 = ivtv_s_ext_ctrls,
+       .vidioc_try_ext_ctrls               = ivtv_try_ext_ctrls,
+};
+
+void ivtv_set_funcs(struct video_device *vdev)
+{
+       vdev->ioctl_ops = &ivtv_ioctl_ops;
+}