diff options
Diffstat (limited to 'drivers/media/video/pvrusb2/pvrusb2-v4l2.c')
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-v4l2.c | 1341 |
1 files changed, 699 insertions, 642 deletions
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index e1111d9..7bddfae 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -107,7 +107,6 @@ static struct v4l2_fmtdesc pvr_fmtdesc [] = { // This should really be V4L2_PIX_FMT_MPEG, but xawtv // breaks when I do that. .pixelformat = 0, // V4L2_PIX_FMT_MPEG, - .reserved = { 0, 0, 0, 0 } } }; @@ -145,740 +144,739 @@ static struct v4l2_format pvr_format [] = { .start = { 0, 0 }, .count = { 0, 0 }, .flags = 0, - .reserved = { 0, 0 } } } } }; + /* - * 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); - } + 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; +} - if (!pvr2_hdw_dev_ok(hdw)) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "ioctl failed - bad or no context"); - return -EFAULT; - } +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; - /* 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; - } + *p = v4l2_prio_max(&vp->prio); + return 0; +} - switch (cmd) { - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = arg; +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; - 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 v4l2_prio_change(&vp->prio, &fh->prio, 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_G_PRIORITY: - { - enum v4l2_priority *p = arg; + ret = pvr2_ctrl_get_value( + pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_STDCUR), &val); + *std = val; + return ret; +} - *p = v4l2_prio_max(&vp->prio); - ret = 0; - 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_S_PRIORITY: - { - enum v4l2_priority *prio = arg; + return pvr2_ctrl_set_value( + pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_STDCUR), *std); +} - ret = v4l2_prio_change(&vp->prio, &fh->prio, *prio); - break; - } +static int pvr2_querystd(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_ENUMSTD: - { - struct v4l2_standard *vs = (struct v4l2_standard *)arg; - int idx = vs->index; - ret = pvr2_hdw_get_stdenum_value(hdw,vs,idx+1); - break; - } + ret = pvr2_ctrl_get_value( + pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_STDDETECT), &val); + *std = val; + return ret; +} - 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; + cnt = 0; + pvr2_ctrl_get_valname(cptr, val, + tmp.name, sizeof(tmp.name) - 1, &cnt); + tmp.name[cnt] = 0; - cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT); + /* Don't bother with audioset, since this driver currently + always switches the audio whenever the video is + switched. */ - 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. */ - - memcpy(vi, &tmp, sizeof(tmp)); - - 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_querystd = pvr2_querystd, + .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) { @@ -961,7 +959,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; + } @@ -1262,10 +1309,12 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, struct usb_device *usbdev; int mindevnum; int unit_number; + struct pvr2_hdw *hdw; int *nr_ptr = NULL; dip->v4lp = vp; - usbdev = pvr2_hdw_get_dev(vp->channel.mc_head->hdw); + hdw = vp->channel.mc_head->hdw; + usbdev = pvr2_hdw_get_dev(hdw); dip->v4l_type = v4l_type; switch (v4l_type) { case VFL_TYPE_GRABBER: @@ -1300,9 +1349,17 @@ 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; + { + int val; + pvr2_ctrl_get_value( + pvr2_hdw_get_ctrl_by_id(hdw, + PVR2_CID_STDAVAIL), &val); + dip->devbase.tvnorms = (v4l2_std_id)val; + } mindevnum = -1; - unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw); + unit_number = pvr2_hdw_get_unit_number(hdw); if (nr_ptr && (unit_number >= 0) && (unit_number < PVR_NUM)) { mindevnum = nr_ptr[unit_number]; } @@ -1319,7 +1376,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, video_device_node_name(&dip->devbase), pvr2_config_get_name(dip->config)); - pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw, + pvr2_hdw_v4l_store_minor_number(hdw, dip->minor_type,dip->devbase.minor); } |