[media] pvrusb2: convert to video_ioctl2
authorHans Verkuil <hverkuil@xs4all.nl>
Mon, 20 Feb 2012 05:21:00 +0000 (02:21 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 7 May 2012 19:49:09 +0000 (16:49 -0300)
Note: there is one FIXME remaining: the tvnorms field of struct
video_device should be set up correctly. I have used V4L2_STD_ALL for
now, but I'm sure this can be improved. This field is used by
video_ioctl2 to implement ENUMSTD.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mike Isely <isely@pobox.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/pvrusb2/pvrusb2-v4l2.c

index 5e462faa2726a875e1b3367007ab0631f4c96ee8..83bc4675ec2a8753a17136f86410edc1739e6bf6 100644 (file)
@@ -150,733 +150,719 @@ static struct v4l2_format pvr_format [] = {
 };
 
 
+
 /*
- * pvr_ioctl()
- *
- * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
- *
+ * This is part of Video 4 Linux API. These procedures handle ioctl() calls.
  */
-static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static int pvr2_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
 {
        struct pvr2_v4l2_fh *fh = file->private_data;
-       struct pvr2_v4l2 *vp = fh->vhead;
-       struct pvr2_v4l2_dev *pdi = fh->pdi;
        struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
-       long ret = -EINVAL;
-
-       if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
-               v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),cmd);
-       }
 
-       if (!pvr2_hdw_dev_ok(hdw)) {
-               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-                          "ioctl failed - bad or no context");
-               return -EFAULT;
-       }
-
-       /* check priority */
-       switch (cmd) {
-       case VIDIOC_S_CTRL:
-       case VIDIOC_S_STD:
-       case VIDIOC_S_INPUT:
-       case VIDIOC_S_TUNER:
-       case VIDIOC_S_FREQUENCY:
-               ret = v4l2_prio_check(&vp->prio, fh->prio);
-               if (ret)
-                       return ret;
-       }
+       memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
+       strlcpy(cap->bus_info, pvr2_hdw_get_bus_info(hdw),
+                       sizeof(cap->bus_info));
+       strlcpy(cap->card, pvr2_hdw_get_desc(hdw), sizeof(cap->card));
+       return 0;
+}
 
-       switch (cmd) {
-       case VIDIOC_QUERYCAP:
-       {
-               struct v4l2_capability *cap = arg;
+static int pvr2_g_priority(struct file *file, void *priv, enum v4l2_priority *p)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_v4l2 *vp = fh->vhead;
 
-               memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
-               strlcpy(cap->bus_info,pvr2_hdw_get_bus_info(hdw),
-                       sizeof(cap->bus_info));
-               strlcpy(cap->card,pvr2_hdw_get_desc(hdw),sizeof(cap->card));
+       *p = v4l2_prio_max(&vp->prio);
+       return 0;
+}
 
-               ret = 0;
-               break;
-       }
+static int pvr2_s_priority(struct file *file, void *priv, enum v4l2_priority prio)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_v4l2 *vp = fh->vhead;
 
-       case VIDIOC_G_PRIORITY:
-       {
-               enum v4l2_priority *p = arg;
+       return v4l2_prio_change(&vp->prio, &fh->prio, prio);
+}
 
-               *p = v4l2_prio_max(&vp->prio);
-               ret = 0;
-               break;
-       }
+static int pvr2_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       int val = 0;
+       int ret;
 
-       case VIDIOC_S_PRIORITY:
-       {
-               enum v4l2_priority *prio = arg;
+       ret = pvr2_ctrl_get_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_STDCUR), &val);
+       *std = val;
+       return ret;
+}
 
-               ret = v4l2_prio_change(&vp->prio, &fh->prio, *prio);
-               break;
-       }
+int pvr2_s_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
 
-       case VIDIOC_ENUMSTD:
-       {
-               struct v4l2_standard *vs = (struct v4l2_standard *)arg;
-               int idx = vs->index;
-               ret = pvr2_hdw_get_stdenum_value(hdw,vs,idx+1);
-               break;
-       }
+       return pvr2_ctrl_set_value(
+               pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_STDCUR), *std);
+}
 
-       case VIDIOC_QUERYSTD:
-       {
-               v4l2_std_id *std = arg;
-               *std = V4L2_STD_ALL;
-               ret = pvr2_hdw_get_detected_std(hdw, std);
-               break;
-       }
+static int pvr2_enum_input(struct file *file, void *priv, struct v4l2_input *vi)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       struct pvr2_ctrl *cptr;
+       struct v4l2_input tmp;
+       unsigned int cnt;
+       int val;
+       int ret;
 
-       case VIDIOC_G_STD:
-       {
-               int val = 0;
-               ret = pvr2_ctrl_get_value(
-                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),&val);
-               *(v4l2_std_id *)arg = val;
+       cptr = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT);
+
+       memset(&tmp, 0, sizeof(tmp));
+       tmp.index = vi->index;
+       ret = 0;
+       if (vi->index >= fh->input_cnt)
+               return -EINVAL;
+       val = fh->input_map[vi->index];
+       switch (val) {
+       case PVR2_CVAL_INPUT_TV:
+       case PVR2_CVAL_INPUT_DTV:
+       case PVR2_CVAL_INPUT_RADIO:
+               tmp.type = V4L2_INPUT_TYPE_TUNER;
                break;
-       }
-
-       case VIDIOC_S_STD:
-       {
-               ret = pvr2_ctrl_set_value(
-                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),
-                       *(v4l2_std_id *)arg);
+       case PVR2_CVAL_INPUT_SVIDEO:
+       case PVR2_CVAL_INPUT_COMPOSITE:
+               tmp.type = V4L2_INPUT_TYPE_CAMERA;
                break;
+       default:
+               return -EINVAL;
        }
 
-       case VIDIOC_ENUMINPUT:
-       {
-               struct pvr2_ctrl *cptr;
-               struct v4l2_input *vi = (struct v4l2_input *)arg;
-               struct v4l2_input tmp;
-               unsigned int cnt;
-               int val;
-
-               cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
-
-               memset(&tmp,0,sizeof(tmp));
-               tmp.index = vi->index;
-               ret = 0;
-               if (vi->index >= fh->input_cnt) {
-                       ret = -EINVAL;
-                       break;
-               }
-               val = fh->input_map[vi->index];
-               switch (val) {
-               case PVR2_CVAL_INPUT_TV:
-               case PVR2_CVAL_INPUT_DTV:
-               case PVR2_CVAL_INPUT_RADIO:
-                       tmp.type = V4L2_INPUT_TYPE_TUNER;
-                       break;
-               case PVR2_CVAL_INPUT_SVIDEO:
-               case PVR2_CVAL_INPUT_COMPOSITE:
-                       tmp.type = V4L2_INPUT_TYPE_CAMERA;
-                       break;
-               default:
-                       ret = -EINVAL;
-                       break;
-               }
-               if (ret < 0) break;
-
-               cnt = 0;
-               pvr2_ctrl_get_valname(cptr,val,
-                                     tmp.name,sizeof(tmp.name)-1,&cnt);
-               tmp.name[cnt] = 0;
-
-               /* Don't bother with audioset, since this driver currently
-                  always switches the audio whenever the video is
-                  switched. */
-
-               /* Handling std is a tougher problem.  It doesn't make
-                  sense in cases where a device might be multi-standard.
-                  We could just copy out the current value for the
-                  standard, but it can change over time.  For now just
-                  leave it zero. */
+       cnt = 0;
+       pvr2_ctrl_get_valname(cptr, val,
+                       tmp.name, sizeof(tmp.name) - 1, &cnt);
+       tmp.name[cnt] = 0;
 
-               memcpy(vi, &tmp, sizeof(tmp));
+       /* Don't bother with audioset, since this driver currently
+          always switches the audio whenever the video is
+          switched. */
 
-               ret = 0;
-               break;
-       }
+       /* Handling std is a tougher problem.  It doesn't make
+          sense in cases where a device might be multi-standard.
+          We could just copy out the current value for the
+          standard, but it can change over time.  For now just
+          leave it zero. */
+       *vi = tmp;
+       return 0;
+}
 
-       case VIDIOC_G_INPUT:
-       {
-               unsigned int idx;
-               struct pvr2_ctrl *cptr;
-               struct v4l2_input *vi = (struct v4l2_input *)arg;
-               int val;
-               cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
-               val = 0;
-               ret = pvr2_ctrl_get_value(cptr,&val);
-               vi->index = 0;
-               for (idx = 0; idx < fh->input_cnt; idx++) {
-                       if (fh->input_map[idx] == val) {
-                               vi->index = idx;
-                               break;
-                       }
-               }
-               break;
-       }
+static int pvr2_g_input(struct file *file, void *priv, unsigned int *i)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       unsigned int idx;
+       struct pvr2_ctrl *cptr;
+       int val;
+       int ret;
 
-       case VIDIOC_S_INPUT:
-       {
-               struct v4l2_input *vi = (struct v4l2_input *)arg;
-               if (vi->index >= fh->input_cnt) {
-                       ret = -ERANGE;
+       cptr = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT);
+       val = 0;
+       ret = pvr2_ctrl_get_value(cptr, &val);
+       *i = 0;
+       for (idx = 0; idx < fh->input_cnt; idx++) {
+               if (fh->input_map[idx] == val) {
+                       *i = idx;
                        break;
                }
-               ret = pvr2_ctrl_set_value(
-                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
-                       fh->input_map[vi->index]);
-               break;
        }
+       return ret;
+}
 
-       case VIDIOC_ENUMAUDIO:
-       {
-               /* pkt: FIXME: We are returning one "fake" input here
-                  which could very well be called "whatever_we_like".
-                  This is for apps that want to see an audio input
-                  just to feel comfortable, as well as to test if
-                  it can do stereo or sth. There is actually no guarantee
-                  that the actual audio input cannot change behind the app's
-                  back, but most applications should not mind that either.
-
-                  Hopefully, mplayer people will work with us on this (this
-                  whole mess is to support mplayer pvr://), or Hans will come
-                  up with a more standard way to say "we have inputs but we
-                  don 't want you to change them independent of video" which
-                  will sort this mess.
-                */
-               struct v4l2_audio *vin = arg;
-               ret = -EINVAL;
-               if (vin->index > 0) break;
-               strncpy(vin->name, "PVRUSB2 Audio",14);
-               vin->capability = V4L2_AUDCAP_STEREO;
-               ret = 0;
-               break;
-               break;
-       }
+static int pvr2_s_input(struct file *file, void *priv, unsigned int inp)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
 
-       case VIDIOC_G_AUDIO:
-       {
-               /* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */
-               struct v4l2_audio *vin = arg;
-               memset(vin,0,sizeof(*vin));
-               vin->index = 0;
-               strncpy(vin->name, "PVRUSB2 Audio",14);
-               vin->capability = V4L2_AUDCAP_STEREO;
-               ret = 0;
-               break;
-       }
+       if (inp >= fh->input_cnt)
+               return -EINVAL;
+       return pvr2_ctrl_set_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT),
+                       fh->input_map[inp]);
+}
 
-       case VIDIOC_G_TUNER:
-       {
-               struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
+static int pvr2_enumaudio(struct file *file, void *priv, struct v4l2_audio *vin)
+{
+       /* pkt: FIXME: We are returning one "fake" input here
+          which could very well be called "whatever_we_like".
+          This is for apps that want to see an audio input
+          just to feel comfortable, as well as to test if
+          it can do stereo or sth. There is actually no guarantee
+          that the actual audio input cannot change behind the app's
+          back, but most applications should not mind that either.
+
+          Hopefully, mplayer people will work with us on this (this
+          whole mess is to support mplayer pvr://), or Hans will come
+          up with a more standard way to say "we have inputs but we
+          don 't want you to change them independent of video" which
+          will sort this mess.
+        */
+
+       if (vin->index > 0)
+               return -EINVAL;
+       strncpy(vin->name, "PVRUSB2 Audio", 14);
+       vin->capability = V4L2_AUDCAP_STEREO;
+       return 0;
+}
 
-               if (vt->index != 0) break; /* Only answer for the 1st tuner */
+static int pvr2_g_audio(struct file *file, void *priv, struct v4l2_audio *vin)
+{
+       /* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */
+       vin->index = 0;
+       strncpy(vin->name, "PVRUSB2 Audio", 14);
+       vin->capability = V4L2_AUDCAP_STEREO;
+       return 0;
+}
 
-               pvr2_hdw_execute_tuner_poll(hdw);
-               ret = pvr2_hdw_get_tuner_status(hdw,vt);
-               break;
-       }
+static int pvr2_s_audio(struct file *file, void *priv, struct v4l2_audio *vout)
+{
+       if (vout->index)
+               return -EINVAL;
+       return 0;
+}
 
-       case VIDIOC_S_TUNER:
-       {
-               struct v4l2_tuner *vt=(struct v4l2_tuner *)arg;
+static int pvr2_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
 
-               if (vt->index != 0)
-                       break;
+       if (vt->index != 0)
+               return -EINVAL; /* Only answer for the 1st tuner */
 
-               ret = pvr2_ctrl_set_value(
-                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
+       pvr2_hdw_execute_tuner_poll(hdw);
+       return pvr2_hdw_get_tuner_status(hdw, vt);
+}
+
+static int pvr2_s_tuner(struct file *file, void *priv, struct v4l2_tuner *vt)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+
+       if (vt->index != 0)
+               return -EINVAL;
+
+       return pvr2_ctrl_set_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_AUDIOMODE),
                        vt->audmode);
-               break;
-       }
+}
 
-       case VIDIOC_S_FREQUENCY:
-       {
-               const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
-               unsigned long fv;
-               struct v4l2_tuner vt;
-               int cur_input;
-               struct pvr2_ctrl *ctrlp;
-               ret = pvr2_hdw_get_tuner_status(hdw,&vt);
-               if (ret != 0) break;
-               ctrlp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
-               ret = pvr2_ctrl_get_value(ctrlp,&cur_input);
-               if (ret != 0) break;
-               if (vf->type == V4L2_TUNER_RADIO) {
-                       if (cur_input != PVR2_CVAL_INPUT_RADIO) {
-                               pvr2_ctrl_set_value(ctrlp,
-                                                   PVR2_CVAL_INPUT_RADIO);
-                       }
-               } else {
-                       if (cur_input == PVR2_CVAL_INPUT_RADIO) {
-                               pvr2_ctrl_set_value(ctrlp,
-                                                   PVR2_CVAL_INPUT_TV);
-                       }
-               }
-               fv = vf->frequency;
-               if (vt.capability & V4L2_TUNER_CAP_LOW) {
-                       fv = (fv * 125) / 2;
-               } else {
-                       fv = fv * 62500;
-               }
-               ret = pvr2_ctrl_set_value(
+int pvr2_s_frequency(struct file *file, void *priv, struct v4l2_frequency *vf)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       unsigned long fv;
+       struct v4l2_tuner vt;
+       int cur_input;
+       struct pvr2_ctrl *ctrlp;
+       int ret;
+
+       ret = pvr2_hdw_get_tuner_status(hdw, &vt);
+       if (ret != 0)
+               return ret;
+       ctrlp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT);
+       ret = pvr2_ctrl_get_value(ctrlp, &cur_input);
+       if (ret != 0)
+               return ret;
+       if (vf->type == V4L2_TUNER_RADIO) {
+               if (cur_input != PVR2_CVAL_INPUT_RADIO)
+                       pvr2_ctrl_set_value(ctrlp, PVR2_CVAL_INPUT_RADIO);
+       } else {
+               if (cur_input == PVR2_CVAL_INPUT_RADIO)
+                       pvr2_ctrl_set_value(ctrlp, PVR2_CVAL_INPUT_TV);
+       }
+       fv = vf->frequency;
+       if (vt.capability & V4L2_TUNER_CAP_LOW)
+               fv = (fv * 125) / 2;
+       else
+               fv = fv * 62500;
+       return pvr2_ctrl_set_value(
                        pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),fv);
-               break;
-       }
+}
 
-       case VIDIOC_G_FREQUENCY:
-       {
-               struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
-               int val = 0;
-               int cur_input;
-               struct v4l2_tuner vt;
-               ret = pvr2_hdw_get_tuner_status(hdw,&vt);
-               if (ret != 0) break;
-               ret = pvr2_ctrl_get_value(
-                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
+static int pvr2_g_frequency(struct file *file, void *priv, struct v4l2_frequency *vf)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       int val = 0;
+       int cur_input;
+       struct v4l2_tuner vt;
+       int ret;
+
+       ret = pvr2_hdw_get_tuner_status(hdw, &vt);
+       if (ret != 0)
+               return ret;
+       ret = pvr2_ctrl_get_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_FREQUENCY),
                        &val);
-               if (ret != 0) break;
-               pvr2_ctrl_get_value(
-                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
+       if (ret != 0)
+               return ret;
+       pvr2_ctrl_get_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT),
                        &cur_input);
-               if (cur_input == PVR2_CVAL_INPUT_RADIO) {
-                       vf->type = V4L2_TUNER_RADIO;
-               } else {
-                       vf->type = V4L2_TUNER_ANALOG_TV;
-               }
-               if (vt.capability & V4L2_TUNER_CAP_LOW) {
-                       val = (val * 2) / 125;
-               } else {
-                       val /= 62500;
-               }
-               vf->frequency = val;
-               break;
-       }
+       if (cur_input == PVR2_CVAL_INPUT_RADIO)
+               vf->type = V4L2_TUNER_RADIO;
+       else
+               vf->type = V4L2_TUNER_ANALOG_TV;
+       if (vt.capability & V4L2_TUNER_CAP_LOW)
+               val = (val * 2) / 125;
+       else
+               val /= 62500;
+       vf->frequency = val;
+       return 0;
+}
 
-       case VIDIOC_ENUM_FMT:
-       {
-               struct v4l2_fmtdesc *fd = (struct v4l2_fmtdesc *)arg;
+static int pvr2_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *fd)
+{
+       /* Only one format is supported : mpeg.*/
+       if (fd->index != 0)
+               return -EINVAL;
 
-               /* Only one format is supported : mpeg.*/
-               if (fd->index != 0)
-                       break;
+       memcpy(fd, pvr_fmtdesc, sizeof(struct v4l2_fmtdesc));
+       return 0;
+}
 
-               memcpy(fd, pvr_fmtdesc, sizeof(struct v4l2_fmtdesc));
-               ret = 0;
-               break;
-       }
+static int pvr2_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       int val;
 
-       case VIDIOC_G_FMT:
-       {
-               struct v4l2_format *vf = (struct v4l2_format *)arg;
-               int val;
-               switch(vf->type) {
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-                       memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
-                              sizeof(struct v4l2_format));
-                       val = 0;
-                       pvr2_ctrl_get_value(
-                               pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES),
-                               &val);
-                       vf->fmt.pix.width = val;
-                       val = 0;
-                       pvr2_ctrl_get_value(
-                               pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES),
-                               &val);
-                       vf->fmt.pix.height = val;
-                       ret = 0;
-                       break;
-               case V4L2_BUF_TYPE_VBI_CAPTURE:
-                       // ????? Still need to figure out to do VBI correctly
-                       ret = -EINVAL;
-                       break;
-               default:
-                       ret = -EINVAL;
-                       break;
-               }
-               break;
-       }
+       memcpy(vf, &pvr_format[PVR_FORMAT_PIX], sizeof(struct v4l2_format));
+       val = 0;
+       pvr2_ctrl_get_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_HRES),
+                       &val);
+       vf->fmt.pix.width = val;
+       val = 0;
+       pvr2_ctrl_get_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_VRES),
+                       &val);
+       vf->fmt.pix.height = val;
+       return 0;
+}
 
-       case VIDIOC_TRY_FMT:
-       case VIDIOC_S_FMT:
-       {
-               struct v4l2_format *vf = (struct v4l2_format *)arg;
-
-               ret = 0;
-               switch(vf->type) {
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
-                       int lmin,lmax,ldef;
-                       struct pvr2_ctrl *hcp,*vcp;
-                       int h = vf->fmt.pix.height;
-                       int w = vf->fmt.pix.width;
-                       hcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES);
-                       vcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES);
-
-                       lmin = pvr2_ctrl_get_min(hcp);
-                       lmax = pvr2_ctrl_get_max(hcp);
-                       pvr2_ctrl_get_def(hcp, &ldef);
-                       if (w == -1) {
-                               w = ldef;
-                       } else if (w < lmin) {
-                               w = lmin;
-                       } else if (w > lmax) {
-                               w = lmax;
-                       }
-                       lmin = pvr2_ctrl_get_min(vcp);
-                       lmax = pvr2_ctrl_get_max(vcp);
-                       pvr2_ctrl_get_def(vcp, &ldef);
-                       if (h == -1) {
-                               h = ldef;
-                       } else if (h < lmin) {
-                               h = lmin;
-                       } else if (h > lmax) {
-                               h = lmax;
-                       }
+static int pvr2_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       int lmin, lmax, ldef;
+       struct pvr2_ctrl *hcp, *vcp;
+       int h = vf->fmt.pix.height;
+       int w = vf->fmt.pix.width;
+
+       hcp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_HRES);
+       vcp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_VRES);
+
+       lmin = pvr2_ctrl_get_min(hcp);
+       lmax = pvr2_ctrl_get_max(hcp);
+       pvr2_ctrl_get_def(hcp, &ldef);
+       if (w == -1)
+               w = ldef;
+       else if (w < lmin)
+               w = lmin;
+       else if (w > lmax)
+               w = lmax;
+       lmin = pvr2_ctrl_get_min(vcp);
+       lmax = pvr2_ctrl_get_max(vcp);
+       pvr2_ctrl_get_def(vcp, &ldef);
+       if (h == -1)
+               h = ldef;
+       else if (h < lmin)
+               h = lmin;
+       else if (h > lmax)
+               h = lmax;
+
+       memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
+                       sizeof(struct v4l2_format));
+       vf->fmt.pix.width = w;
+       vf->fmt.pix.height = h;
+       return 0;
+}
 
-                       memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
-                              sizeof(struct v4l2_format));
-                       vf->fmt.pix.width = w;
-                       vf->fmt.pix.height = h;
+static int pvr2_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       struct pvr2_ctrl *hcp, *vcp;
+       int ret = pvr2_try_fmt_vid_cap(file, fh, vf);
 
-                       if (cmd == VIDIOC_S_FMT) {
-                               pvr2_ctrl_set_value(hcp,vf->fmt.pix.width);
-                               pvr2_ctrl_set_value(vcp,vf->fmt.pix.height);
-                       }
-               } break;
-               case V4L2_BUF_TYPE_VBI_CAPTURE:
-                       // ????? Still need to figure out to do VBI correctly
-                       ret = -EINVAL;
-                       break;
-               default:
-                       ret = -EINVAL;
-                       break;
-               }
-               break;
-       }
+       if (ret)
+               return ret;
+       hcp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_HRES);
+       vcp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_VRES);
+       pvr2_ctrl_set_value(hcp, vf->fmt.pix.width);
+       pvr2_ctrl_set_value(vcp, vf->fmt.pix.height);
+       return 0;
+}
 
-       case VIDIOC_STREAMON:
-       {
-               if (!fh->pdi->stream) {
-                       /* No stream defined for this node.  This means
-                          that we're not currently allowed to stream from
-                          this node. */
-                       ret = -EPERM;
-                       break;
-               }
-               ret = pvr2_hdw_set_stream_type(hdw,pdi->config);
-               if (ret < 0) return ret;
-               ret = pvr2_hdw_set_streaming(hdw,!0);
-               break;
+static int pvr2_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       struct pvr2_v4l2_dev *pdi = fh->pdi;
+       int ret;
+
+       if (!fh->pdi->stream) {
+               /* No stream defined for this node.  This means
+                  that we're not currently allowed to stream from
+                  this node. */
+               return -EPERM;
        }
+       ret = pvr2_hdw_set_stream_type(hdw, pdi->config);
+       if (ret < 0)
+               return ret;
+       return pvr2_hdw_set_streaming(hdw, !0);
+}
 
-       case VIDIOC_STREAMOFF:
-       {
-               if (!fh->pdi->stream) {
-                       /* No stream defined for this node.  This means
-                          that we're not currently allowed to stream from
-                          this node. */
-                       ret = -EPERM;
-                       break;
-               }
-               ret = pvr2_hdw_set_streaming(hdw,0);
-               break;
+static int pvr2_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+
+       if (!fh->pdi->stream) {
+               /* No stream defined for this node.  This means
+                  that we're not currently allowed to stream from
+                  this node. */
+               return -EPERM;
        }
+       return pvr2_hdw_set_streaming(hdw, 0);
+}
 
-       case VIDIOC_QUERYCTRL:
-       {
-               struct pvr2_ctrl *cptr;
-               int val;
-               struct v4l2_queryctrl *vc = (struct v4l2_queryctrl *)arg;
-               ret = 0;
-               if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
-                       cptr = pvr2_hdw_get_ctrl_nextv4l(
-                               hdw,(vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL));
-                       if (cptr) vc->id = pvr2_ctrl_get_v4lid(cptr);
-               } else {
-                       cptr = pvr2_hdw_get_ctrl_v4l(hdw,vc->id);
-               }
-               if (!cptr) {
-                       pvr2_trace(PVR2_TRACE_V4LIOCTL,
-                                  "QUERYCTRL id=0x%x not implemented here",
-                                  vc->id);
-                       ret = -EINVAL;
-                       break;
-               }
+static int pvr2_queryctrl(struct file *file, void *priv,
+               struct v4l2_queryctrl *vc)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       struct pvr2_ctrl *cptr;
+       int val;
+       int ret;
 
+       ret = 0;
+       if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
+               cptr = pvr2_hdw_get_ctrl_nextv4l(
+                               hdw, (vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL));
+               if (cptr)
+                       vc->id = pvr2_ctrl_get_v4lid(cptr);
+       } else {
+               cptr = pvr2_hdw_get_ctrl_v4l(hdw, vc->id);
+       }
+       if (!cptr) {
                pvr2_trace(PVR2_TRACE_V4LIOCTL,
-                          "QUERYCTRL id=0x%x mapping name=%s (%s)",
-                          vc->id,pvr2_ctrl_get_name(cptr),
-                          pvr2_ctrl_get_desc(cptr));
-               strlcpy(vc->name,pvr2_ctrl_get_desc(cptr),sizeof(vc->name));
-               vc->flags = pvr2_ctrl_get_v4lflags(cptr);
-               pvr2_ctrl_get_def(cptr, &val);
-               vc->default_value = val;
-               switch (pvr2_ctrl_get_type(cptr)) {
-               case pvr2_ctl_enum:
-                       vc->type = V4L2_CTRL_TYPE_MENU;
-                       vc->minimum = 0;
-                       vc->maximum = pvr2_ctrl_get_cnt(cptr) - 1;
-                       vc->step = 1;
-                       break;
-               case pvr2_ctl_bool:
-                       vc->type = V4L2_CTRL_TYPE_BOOLEAN;
-                       vc->minimum = 0;
-                       vc->maximum = 1;
-                       vc->step = 1;
-                       break;
-               case pvr2_ctl_int:
-                       vc->type = V4L2_CTRL_TYPE_INTEGER;
-                       vc->minimum = pvr2_ctrl_get_min(cptr);
-                       vc->maximum = pvr2_ctrl_get_max(cptr);
-                       vc->step = 1;
-                       break;
-               default:
-                       pvr2_trace(PVR2_TRACE_V4LIOCTL,
-                                  "QUERYCTRL id=0x%x name=%s not mappable",
-                                  vc->id,pvr2_ctrl_get_name(cptr));
-                       ret = -EINVAL;
-                       break;
-               }
+                               "QUERYCTRL id=0x%x not implemented here",
+                               vc->id);
+               return -EINVAL;
+       }
+
+       pvr2_trace(PVR2_TRACE_V4LIOCTL,
+                       "QUERYCTRL id=0x%x mapping name=%s (%s)",
+                       vc->id, pvr2_ctrl_get_name(cptr),
+                       pvr2_ctrl_get_desc(cptr));
+       strlcpy(vc->name, pvr2_ctrl_get_desc(cptr), sizeof(vc->name));
+       vc->flags = pvr2_ctrl_get_v4lflags(cptr);
+       pvr2_ctrl_get_def(cptr, &val);
+       vc->default_value = val;
+       switch (pvr2_ctrl_get_type(cptr)) {
+       case pvr2_ctl_enum:
+               vc->type = V4L2_CTRL_TYPE_MENU;
+               vc->minimum = 0;
+               vc->maximum = pvr2_ctrl_get_cnt(cptr) - 1;
+               vc->step = 1;
                break;
-       }
-
-       case VIDIOC_QUERYMENU:
-       {
-               struct v4l2_querymenu *vm = (struct v4l2_querymenu *)arg;
-               unsigned int cnt = 0;
-               ret = pvr2_ctrl_get_valname(pvr2_hdw_get_ctrl_v4l(hdw,vm->id),
-                                           vm->index,
-                                           vm->name,sizeof(vm->name)-1,
-                                           &cnt);
-               vm->name[cnt] = 0;
+       case pvr2_ctl_bool:
+               vc->type = V4L2_CTRL_TYPE_BOOLEAN;
+               vc->minimum = 0;
+               vc->maximum = 1;
+               vc->step = 1;
                break;
-       }
-
-       case VIDIOC_G_CTRL:
-       {
-               struct v4l2_control *vc = (struct v4l2_control *)arg;
-               int val = 0;
-               ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
-                                         &val);
-               vc->value = val;
+       case pvr2_ctl_int:
+               vc->type = V4L2_CTRL_TYPE_INTEGER;
+               vc->minimum = pvr2_ctrl_get_min(cptr);
+               vc->maximum = pvr2_ctrl_get_max(cptr);
+               vc->step = 1;
                break;
+       default:
+               pvr2_trace(PVR2_TRACE_V4LIOCTL,
+                               "QUERYCTRL id=0x%x name=%s not mappable",
+                               vc->id, pvr2_ctrl_get_name(cptr));
+               return -EINVAL;
        }
+       return 0;
+}
 
-       case VIDIOC_S_CTRL:
-       {
-               struct v4l2_control *vc = (struct v4l2_control *)arg;
-               ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
-                                         vc->value);
-               break;
-       }
+static int pvr2_querymenu(struct file *file, void *priv, struct v4l2_querymenu *vm)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       unsigned int cnt = 0;
+       int ret;
 
-       case VIDIOC_G_EXT_CTRLS:
-       {
-               struct v4l2_ext_controls *ctls =
-                       (struct v4l2_ext_controls *)arg;
-               struct v4l2_ext_control *ctrl;
-               unsigned int idx;
-               int val;
-               ret = 0;
-               for (idx = 0; idx < ctls->count; idx++) {
-                       ctrl = ctls->controls + idx;
-                       ret = pvr2_ctrl_get_value(
-                               pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),&val);
-                       if (ret) {
-                               ctls->error_idx = idx;
-                               break;
-                       }
-                       /* Ensure that if read as a 64 bit value, the user
-                          will still get a hopefully sane value */
-                       ctrl->value64 = 0;
-                       ctrl->value = val;
+       ret = pvr2_ctrl_get_valname(pvr2_hdw_get_ctrl_v4l(hdw, vm->id),
+                       vm->index,
+                       vm->name, sizeof(vm->name) - 1,
+                       &cnt);
+       vm->name[cnt] = 0;
+       return ret;
+}
+
+static int pvr2_g_ctrl(struct file *file, void *priv, struct v4l2_control *vc)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       int val = 0;
+       int ret;
+
+       ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw, vc->id),
+                       &val);
+       vc->value = val;
+       return ret;
+}
+
+static int pvr2_s_ctrl(struct file *file, void *priv, struct v4l2_control *vc)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+
+       return pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw, vc->id),
+                       vc->value);
+}
+
+static int pvr2_g_ext_ctrls(struct file *file, void *priv,
+                                       struct v4l2_ext_controls *ctls)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       struct v4l2_ext_control *ctrl;
+       unsigned int idx;
+       int val;
+       int ret;
+
+       ret = 0;
+       for (idx = 0; idx < ctls->count; idx++) {
+               ctrl = ctls->controls + idx;
+               ret = pvr2_ctrl_get_value(
+                               pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id), &val);
+               if (ret) {
+                       ctls->error_idx = idx;
+                       return ret;
                }
-               break;
+               /* Ensure that if read as a 64 bit value, the user
+                  will still get a hopefully sane value */
+               ctrl->value64 = 0;
+               ctrl->value = val;
        }
+       return 0;
+}
 
-       case VIDIOC_S_EXT_CTRLS:
-       {
-               struct v4l2_ext_controls *ctls =
-                       (struct v4l2_ext_controls *)arg;
-               struct v4l2_ext_control *ctrl;
-               unsigned int idx;
-               ret = 0;
-               for (idx = 0; idx < ctls->count; idx++) {
-                       ctrl = ctls->controls + idx;
-                       ret = pvr2_ctrl_set_value(
-                               pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),
+static int pvr2_s_ext_ctrls(struct file *file, void *priv,
+               struct v4l2_ext_controls *ctls)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       struct v4l2_ext_control *ctrl;
+       unsigned int idx;
+       int ret;
+
+       ret = 0;
+       for (idx = 0; idx < ctls->count; idx++) {
+               ctrl = ctls->controls + idx;
+               ret = pvr2_ctrl_set_value(
+                               pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id),
                                ctrl->value);
-                       if (ret) {
-                               ctls->error_idx = idx;
-                               break;
-                       }
+               if (ret) {
+                       ctls->error_idx = idx;
+                       return ret;
                }
-               break;
        }
+       return 0;
+}
 
-       case VIDIOC_TRY_EXT_CTRLS:
-       {
-               struct v4l2_ext_controls *ctls =
-                       (struct v4l2_ext_controls *)arg;
-               struct v4l2_ext_control *ctrl;
-               struct pvr2_ctrl *pctl;
-               unsigned int idx;
-               /* For the moment just validate that the requested control
-                  actually exists. */
-               ret = 0;
-               for (idx = 0; idx < ctls->count; idx++) {
-                       ctrl = ctls->controls + idx;
-                       pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id);
-                       if (!pctl) {
-                               ret = -EINVAL;
-                               ctls->error_idx = idx;
-                               break;
-                       }
-               }
-               break;
-       }
+static int pvr2_try_ext_ctrls(struct file *file, void *priv,
+               struct v4l2_ext_controls *ctls)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       struct v4l2_ext_control *ctrl;
+       struct pvr2_ctrl *pctl;
+       unsigned int idx;
+       int ret;
 
-       case VIDIOC_CROPCAP:
-       {
-               struct v4l2_cropcap *cap = (struct v4l2_cropcap *)arg;
-               if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       ret = -EINVAL;
-                       break;
+       /* For the moment just validate that the requested control
+          actually exists. */
+       ret = 0;
+       for (idx = 0; idx < ctls->count; idx++) {
+               ctrl = ctls->controls + idx;
+               pctl = pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id);
+               if (!pctl) {
+                       ctls->error_idx = idx;
+                       return -EINVAL;
                }
-               ret = pvr2_hdw_get_cropcap(hdw, cap);
-               cap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* paranoia */
-               break;
        }
-       case VIDIOC_G_CROP:
-       {
-               struct v4l2_crop *crop = (struct v4l2_crop *)arg;
-               int val = 0;
-               if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       ret = -EINVAL;
-                       break;
-               }
-               ret = pvr2_ctrl_get_value(
+       return 0;
+}
+
+static int pvr2_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cap)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       int ret;
+
+       if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       ret = pvr2_hdw_get_cropcap(hdw, cap);
+       cap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* paranoia */
+       return ret;
+}
+
+static int pvr2_g_crop(struct file *file, void *priv, struct v4l2_crop *crop)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       int val = 0;
+       int ret;
+
+       if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       ret = pvr2_ctrl_get_value(
                        pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), &val);
-               if (ret != 0) {
-                       ret = -EINVAL;
-                       break;
-               }
-               crop->c.left = val;
-               ret = pvr2_ctrl_get_value(
+       if (ret != 0)
+               return -EINVAL;
+       crop->c.left = val;
+       ret = pvr2_ctrl_get_value(
                        pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), &val);
-               if (ret != 0) {
-                       ret = -EINVAL;
-                       break;
-               }
-               crop->c.top = val;
-               ret = pvr2_ctrl_get_value(
+       if (ret != 0)
+               return -EINVAL;
+       crop->c.top = val;
+       ret = pvr2_ctrl_get_value(
                        pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), &val);
-               if (ret != 0) {
-                       ret = -EINVAL;
-                       break;
-               }
-               crop->c.width = val;
-               ret = pvr2_ctrl_get_value(
+       if (ret != 0)
+               return -EINVAL;
+       crop->c.width = val;
+       ret = pvr2_ctrl_get_value(
                        pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), &val);
-               if (ret != 0) {
-                       ret = -EINVAL;
-                       break;
-               }
-               crop->c.height = val;
-       }
-       case VIDIOC_S_CROP:
-       {
-               struct v4l2_crop *crop = (struct v4l2_crop *)arg;
-               if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       ret = -EINVAL;
-                       break;
-               }
-               ret = pvr2_ctrl_set_value(
+       if (ret != 0)
+               return -EINVAL;
+       crop->c.height = val;
+       return 0;
+}
+
+static int pvr2_s_crop(struct file *file, void *priv, struct v4l2_crop *crop)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       struct v4l2_cropcap cap;
+       int ret;
+
+       if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       ret = pvr2_ctrl_set_value(
                        pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL),
                        crop->c.left);
-               if (ret != 0) {
-                       ret = -EINVAL;
-                       break;
-               }
-               ret = pvr2_ctrl_set_value(
+       if (ret != 0)
+               return -EINVAL;
+       ret = pvr2_ctrl_set_value(
                        pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT),
                        crop->c.top);
-               if (ret != 0) {
-                       ret = -EINVAL;
-                       break;
-               }
-               ret = pvr2_ctrl_set_value(
+       if (ret != 0)
+               return -EINVAL;
+       ret = pvr2_ctrl_set_value(
                        pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW),
                        crop->c.width);
-               if (ret != 0) {
-                       ret = -EINVAL;
-                       break;
-               }
-               ret = pvr2_ctrl_set_value(
+       if (ret != 0)
+               return -EINVAL;
+       ret = pvr2_ctrl_set_value(
                        pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH),
                        crop->c.height);
-               if (ret != 0) {
-                       ret = -EINVAL;
-                       break;
-               }
-       }
-       case VIDIOC_LOG_STATUS:
-       {
-               pvr2_hdw_trigger_module_log(hdw);
-               ret = 0;
-               break;
-       }
+       if (ret != 0)
+               return -EINVAL;
+       return 0;
+}
+
+static int pvr2_log_status(struct file *file, void *priv)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+
+       pvr2_hdw_trigger_module_log(hdw);
+       return 0;
+}
+
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-       case VIDIOC_DBG_S_REGISTER:
-       case VIDIOC_DBG_G_REGISTER:
-       {
-               u64 val;
-               struct v4l2_dbg_register *req = (struct v4l2_dbg_register *)arg;
-               if (cmd == VIDIOC_DBG_S_REGISTER) val = req->val;
-               ret = pvr2_hdw_register_access(
-                       hdw, &req->match, req->reg,
-                       cmd == VIDIOC_DBG_S_REGISTER, &val);
-               if (cmd == VIDIOC_DBG_G_REGISTER) req->val = val;
-               break;
-       }
-#endif
+static int pvr2_g_register(struct file *file, void *priv, struct v4l2_dbg_register *req)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       u64 val;
+       int ret;
 
-       default :
-               ret = -ENOTTY;
-               break;
-       }
+       ret = pvr2_hdw_register_access(
+                       hdw, &req->match, req->reg,
+                       0, &val);
+       req->val = val;
+       return ret;
+}
 
-       pvr2_hdw_commit_ctl(hdw);
+static int pvr2_s_register(struct file *file, void *priv, struct v4l2_dbg_register *req)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       u64 val;
+       int ret;
 
-       if (ret < 0) {
-               if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
-                       pvr2_trace(PVR2_TRACE_V4LIOCTL,
-                                  "pvr2_v4l2_do_ioctl failure, ret=%ld", ret);
-               } else {
-                       if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
-                               pvr2_trace(PVR2_TRACE_V4LIOCTL,
-                                          "pvr2_v4l2_do_ioctl failure, ret=%ld"
-                                          " command was:", ret);
-                               v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),
-                                               cmd);
-                       }
-               }
-       } else {
-               pvr2_trace(PVR2_TRACE_V4LIOCTL,
-                          "pvr2_v4l2_do_ioctl complete, ret=%ld (0x%lx)",
-                          ret, ret);
-       }
+       val = req->val;
+       ret = pvr2_hdw_register_access(
+                       hdw, &req->match, req->reg,
+                       1, &val);
        return ret;
 }
+#endif
+
+static const struct v4l2_ioctl_ops pvr2_ioctl_ops = {
+       .vidioc_querycap                    = pvr2_querycap,
+       .vidioc_g_priority                  = pvr2_g_priority,
+       .vidioc_s_priority                  = pvr2_s_priority,
+       .vidioc_s_audio                     = pvr2_s_audio,
+       .vidioc_g_audio                     = pvr2_g_audio,
+       .vidioc_enumaudio                   = pvr2_enumaudio,
+       .vidioc_enum_input                  = pvr2_enum_input,
+       .vidioc_cropcap                     = pvr2_cropcap,
+       .vidioc_s_crop                      = pvr2_s_crop,
+       .vidioc_g_crop                      = pvr2_g_crop,
+       .vidioc_g_input                     = pvr2_g_input,
+       .vidioc_s_input                     = pvr2_s_input,
+       .vidioc_g_frequency                 = pvr2_g_frequency,
+       .vidioc_s_frequency                 = pvr2_s_frequency,
+       .vidioc_s_tuner                     = pvr2_s_tuner,
+       .vidioc_g_tuner                     = pvr2_g_tuner,
+       .vidioc_g_std                       = pvr2_g_std,
+       .vidioc_s_std                       = pvr2_s_std,
+       .vidioc_log_status                  = pvr2_log_status,
+       .vidioc_enum_fmt_vid_cap            = pvr2_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap               = pvr2_g_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap               = pvr2_s_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap             = pvr2_try_fmt_vid_cap,
+       .vidioc_streamon                    = pvr2_streamon,
+       .vidioc_streamoff                   = pvr2_streamoff,
+       .vidioc_queryctrl                   = pvr2_queryctrl,
+       .vidioc_querymenu                   = pvr2_querymenu,
+       .vidioc_g_ctrl                      = pvr2_g_ctrl,
+       .vidioc_s_ctrl                      = pvr2_s_ctrl,
+       .vidioc_g_ext_ctrls                 = pvr2_g_ext_ctrls,
+       .vidioc_s_ext_ctrls                 = pvr2_s_ext_ctrls,
+       .vidioc_try_ext_ctrls               = pvr2_try_ext_ctrls,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register                  = pvr2_g_register,
+       .vidioc_s_register                  = pvr2_s_register,
+#endif
+};
 
 static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
 {
@@ -959,7 +945,56 @@ static long pvr2_v4l2_ioctl(struct file *file,
                           unsigned int cmd, unsigned long arg)
 {
 
-       return video_usercopy(file, cmd, arg, pvr2_v4l2_do_ioctl);
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_v4l2 *vp = fh->vhead;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       long ret = -EINVAL;
+
+       if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL)
+               v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw), cmd);
+
+       if (!pvr2_hdw_dev_ok(hdw)) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "ioctl failed - bad or no context");
+               return -EFAULT;
+       }
+
+       /* check priority */
+       switch (cmd) {
+       case VIDIOC_S_CTRL:
+       case VIDIOC_S_STD:
+       case VIDIOC_S_INPUT:
+       case VIDIOC_S_TUNER:
+       case VIDIOC_S_FREQUENCY:
+               ret = v4l2_prio_check(&vp->prio, fh->prio);
+               if (ret)
+                       return ret;
+       }
+
+       ret = video_ioctl2(file, cmd, arg);
+
+       pvr2_hdw_commit_ctl(hdw);
+
+       if (ret < 0) {
+               if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
+                       pvr2_trace(PVR2_TRACE_V4LIOCTL,
+                                  "pvr2_v4l2_do_ioctl failure, ret=%ld", ret);
+               } else {
+                       if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
+                               pvr2_trace(PVR2_TRACE_V4LIOCTL,
+                                          "pvr2_v4l2_do_ioctl failure, ret=%ld"
+                                          " command was:", ret);
+                               v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),
+                                               cmd);
+                       }
+               }
+       } else {
+               pvr2_trace(PVR2_TRACE_V4LIOCTL,
+                          "pvr2_v4l2_do_ioctl complete, ret=%ld (0x%lx)",
+                          ret, ret);
+       }
+       return ret;
+
 }
 
 
@@ -1298,6 +1333,11 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
 
        memcpy(&dip->devbase,&vdev_template,sizeof(vdev_template));
        dip->devbase.release = pvr2_video_device_release;
+       dip->devbase.ioctl_ops = &pvr2_ioctl_ops;
+       /* FIXME: tvnorms should be set to the set of supported standards
+          by this device. Then video_ioctl2 will implement VIDIOC_ENUMSTD
+          based on this field. */
+       dip->devbase.tvnorms = V4L2_STD_ALL;
 
        mindevnum = -1;
        unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw);