return 0;
}
-static const s32 supported_v4l2_ctrls[] = {
- V4L2_CID_BRIGHTNESS,
- V4L2_CID_CONTRAST,
- V4L2_CID_SATURATION,
- V4L2_CID_HUE,
- V4L2_CID_SHARPNESS,
- V4L2_CID_MPEG_AUDIO_ENCODING,
- V4L2_CID_MPEG_VIDEO_ENCODING,
- V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
- V4L2_CID_MPEG_VIDEO_BITRATE,
- V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
-};
-
-static int fill_queryctrl(struct hdpvr_options *opt, struct v4l2_queryctrl *qc,
- int ac3, int fw_ver)
-{
- int err;
-
- if (fw_ver > 0x15) {
- switch (qc->id) {
- case V4L2_CID_BRIGHTNESS:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
- case V4L2_CID_CONTRAST:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x40);
- case V4L2_CID_SATURATION:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x40);
- case V4L2_CID_HUE:
- return v4l2_ctrl_query_fill(qc, 0x0, 0x1e, 1, 0xf);
- case V4L2_CID_SHARPNESS:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
- }
- } else {
- switch (qc->id) {
- case V4L2_CID_BRIGHTNESS:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x86);
- case V4L2_CID_CONTRAST:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
- case V4L2_CID_SATURATION:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
- case V4L2_CID_HUE:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
- case V4L2_CID_SHARPNESS:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
- }
- }
-
- switch (qc->id) {
- case V4L2_CID_MPEG_AUDIO_ENCODING:
- return v4l2_ctrl_query_fill(
- qc, V4L2_MPEG_AUDIO_ENCODING_AAC,
- ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3
- : V4L2_MPEG_AUDIO_ENCODING_AAC,
- 1, V4L2_MPEG_AUDIO_ENCODING_AAC);
- case V4L2_CID_MPEG_VIDEO_ENCODING:
- return v4l2_ctrl_query_fill(
- qc, V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC,
- V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1,
- V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC);
-
-/* case V4L2_CID_MPEG_VIDEO_? maybe keyframe interval: */
-/* return v4l2_ctrl_query_fill(qc, 0, 128, 128, 0); */
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
- return v4l2_ctrl_query_fill(
- qc, V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
- V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
- V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
-
- case V4L2_CID_MPEG_VIDEO_BITRATE:
- return v4l2_ctrl_query_fill(qc, 1000000, 13500000, 100000,
- 6500000);
- case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
- err = v4l2_ctrl_query_fill(qc, 1100000, 20200000, 100000,
- 9000000);
- if (!err && opt->bitrate_mode == HDPVR_CONSTANT)
- qc->flags |= V4L2_CTRL_FLAG_INACTIVE;
- return err;
- default:
- return -EINVAL;
- }
-}
-
-static int vidioc_queryctrl(struct file *file, void *private_data,
- struct v4l2_queryctrl *qc)
+static int hdpvr_try_ctrl(struct v4l2_ctrl *ctrl)
{
- struct hdpvr_fh *fh = file->private_data;
- struct hdpvr_device *dev = fh->dev;
- int i, next;
- u32 id = qc->id;
-
- memset(qc, 0, sizeof(*qc));
-
- next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL);
- qc->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
-
- for (i = 0; i < ARRAY_SIZE(supported_v4l2_ctrls); i++) {
- if (next) {
- if (qc->id < supported_v4l2_ctrls[i])
- qc->id = supported_v4l2_ctrls[i];
- else
- continue;
- }
-
- if (qc->id == supported_v4l2_ctrls[i])
- return fill_queryctrl(&dev->options, qc,
- dev->flags & HDPVR_FLAG_AC3_CAP,
- dev->fw_ver);
-
- if (qc->id < supported_v4l2_ctrls[i])
- break;
- }
-
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *private_data,
- struct v4l2_control *ctrl)
-{
- struct hdpvr_fh *fh = file->private_data;
- struct hdpvr_device *dev = fh->dev;
+ struct hdpvr_device *dev =
+ container_of(ctrl->handler, struct hdpvr_device, hdl);
switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- ctrl->value = dev->options.brightness;
- break;
- case V4L2_CID_CONTRAST:
- ctrl->value = dev->options.contrast;
- break;
- case V4L2_CID_SATURATION:
- ctrl->value = dev->options.saturation;
- break;
- case V4L2_CID_HUE:
- ctrl->value = dev->options.hue;
- break;
- case V4L2_CID_SHARPNESS:
- ctrl->value = dev->options.sharpness;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+ dev->video_bitrate->val >= dev->video_bitrate_peak->val)
+ dev->video_bitrate_peak->val =
+ dev->video_bitrate->val + 100000;
break;
- default:
- return -EINVAL;
}
return 0;
}
-static int vidioc_s_ctrl(struct file *file, void *private_data,
- struct v4l2_control *ctrl)
+static int hdpvr_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct hdpvr_fh *fh = file->private_data;
- struct hdpvr_device *dev = fh->dev;
- int retval;
+ struct hdpvr_device *dev =
+ container_of(ctrl->handler, struct hdpvr_device, hdl);
+ struct hdpvr_options *opt = &dev->options;
+ int ret = -EINVAL;
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- retval = hdpvr_config_call(dev, CTRL_BRIGHTNESS, ctrl->value);
- if (!retval)
- dev->options.brightness = ctrl->value;
- break;
+ ret = hdpvr_config_call(dev, CTRL_BRIGHTNESS, ctrl->val);
+ if (ret)
+ break;
+ dev->options.brightness = ctrl->val;
+ return 0;
case V4L2_CID_CONTRAST:
- retval = hdpvr_config_call(dev, CTRL_CONTRAST, ctrl->value);
- if (!retval)
- dev->options.contrast = ctrl->value;
- break;
+ ret = hdpvr_config_call(dev, CTRL_CONTRAST, ctrl->val);
+ if (ret)
+ break;
+ dev->options.contrast = ctrl->val;
+ return 0;
case V4L2_CID_SATURATION:
- retval = hdpvr_config_call(dev, CTRL_SATURATION, ctrl->value);
- if (!retval)
- dev->options.saturation = ctrl->value;
- break;
+ ret = hdpvr_config_call(dev, CTRL_SATURATION, ctrl->val);
+ if (ret)
+ break;
+ dev->options.saturation = ctrl->val;
+ return 0;
case V4L2_CID_HUE:
- retval = hdpvr_config_call(dev, CTRL_HUE, ctrl->value);
- if (!retval)
- dev->options.hue = ctrl->value;
- break;
+ ret = hdpvr_config_call(dev, CTRL_HUE, ctrl->val);
+ if (ret)
+ break;
+ dev->options.hue = ctrl->val;
+ return 0;
case V4L2_CID_SHARPNESS:
- retval = hdpvr_config_call(dev, CTRL_SHARPNESS, ctrl->value);
- if (!retval)
- dev->options.sharpness = ctrl->value;
- break;
- default:
- return -EINVAL;
- }
-
- return retval;
-}
-
-
-static int hdpvr_get_ctrl(struct hdpvr_options *opt,
- struct v4l2_ext_control *ctrl)
-{
- switch (ctrl->id) {
- case V4L2_CID_MPEG_AUDIO_ENCODING:
- ctrl->value = opt->audio_codec;
- break;
- case V4L2_CID_MPEG_VIDEO_ENCODING:
- ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC;
- break;
-/* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
-/* ctrl->value = (opt->gop_mode & 0x2) ? 0 : 128; */
-/* break; */
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
- ctrl->value = opt->bitrate_mode == HDPVR_CONSTANT
- ? V4L2_MPEG_VIDEO_BITRATE_MODE_CBR
- : V4L2_MPEG_VIDEO_BITRATE_MODE_VBR;
- break;
- case V4L2_CID_MPEG_VIDEO_BITRATE:
- ctrl->value = opt->bitrate * 100000;
- break;
- case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
- ctrl->value = opt->peak_bitrate * 100000;
- break;
- case V4L2_CID_MPEG_STREAM_TYPE:
- ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int vidioc_g_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *ctrls)
-{
- struct hdpvr_fh *fh = file->private_data;
- struct hdpvr_device *dev = fh->dev;
- int i, err = 0;
-
- if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
- for (i = 0; i < ctrls->count; i++) {
- struct v4l2_ext_control *ctrl = ctrls->controls + i;
-
- err = hdpvr_get_ctrl(&dev->options, ctrl);
- if (err) {
- ctrls->error_idx = i;
- break;
- }
- }
- return err;
-
- }
-
- return -EINVAL;
-}
-
-
-static int hdpvr_try_ctrl(struct v4l2_ext_control *ctrl, int ac3)
-{
- int ret = -EINVAL;
-
- switch (ctrl->id) {
- case V4L2_CID_MPEG_AUDIO_ENCODING:
- if (ctrl->value == V4L2_MPEG_AUDIO_ENCODING_AAC ||
- (ac3 && ctrl->value == V4L2_MPEG_AUDIO_ENCODING_AC3))
- ret = 0;
- break;
- case V4L2_CID_MPEG_VIDEO_ENCODING:
- if (ctrl->value == V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC)
- ret = 0;
- break;
-/* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
-/* if (ctrl->value == 0 || ctrl->value == 128) */
-/* ret = 0; */
-/* break; */
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
- if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR ||
- ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR)
- ret = 0;
- break;
- case V4L2_CID_MPEG_VIDEO_BITRATE:
- {
- uint bitrate = ctrl->value / 100000;
- if (bitrate >= 10 && bitrate <= 135)
- ret = 0;
- break;
- }
- case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
- {
- uint peak_bitrate = ctrl->value / 100000;
- if (peak_bitrate >= 10 && peak_bitrate <= 202)
- ret = 0;
- break;
- }
- case V4L2_CID_MPEG_STREAM_TYPE:
- if (ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS)
- ret = 0;
- break;
- default:
- return -EINVAL;
- }
- return ret;
-}
-
-static int vidioc_try_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *ctrls)
-{
- struct hdpvr_fh *fh = file->private_data;
- struct hdpvr_device *dev = fh->dev;
- int i, err = 0;
-
- if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
- for (i = 0; i < ctrls->count; i++) {
- struct v4l2_ext_control *ctrl = ctrls->controls + i;
-
- err = hdpvr_try_ctrl(ctrl,
- dev->flags & HDPVR_FLAG_AC3_CAP);
- if (err) {
- ctrls->error_idx = i;
- break;
- }
- }
- return err;
- }
-
- return -EINVAL;
-}
-
-
-static int hdpvr_set_ctrl(struct hdpvr_device *dev,
- struct v4l2_ext_control *ctrl)
-{
- struct hdpvr_options *opt = &dev->options;
- int ret = 0;
-
- switch (ctrl->id) {
+ ret = hdpvr_config_call(dev, CTRL_SHARPNESS, ctrl->val);
+ if (ret)
+ break;
+ dev->options.sharpness = ctrl->val;
+ return 0;
case V4L2_CID_MPEG_AUDIO_ENCODING:
if (dev->flags & HDPVR_FLAG_AC3_CAP) {
- opt->audio_codec = ctrl->value;
- ret = hdpvr_set_audio(dev, opt->audio_input,
+ opt->audio_codec = ctrl->val;
+ return hdpvr_set_audio(dev, opt->audio_input,
opt->audio_codec);
}
- break;
+ return 0;
case V4L2_CID_MPEG_VIDEO_ENCODING:
- break;
+ return 0;
/* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
/* if (ctrl->value == 0 && !(opt->gop_mode & 0x2)) { */
/* opt->gop_mode |= 0x2; */
/* opt->gop_mode); */
/* } */
/* break; */
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
- if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR &&
- opt->bitrate_mode != HDPVR_CONSTANT) {
- opt->bitrate_mode = HDPVR_CONSTANT;
- hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
- opt->bitrate_mode);
- }
- if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
- opt->bitrate_mode == HDPVR_CONSTANT) {
- opt->bitrate_mode = HDPVR_VARIABLE_AVERAGE;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: {
+ uint peak_bitrate = dev->video_bitrate_peak->val / 100000;
+ uint bitrate = dev->video_bitrate->val / 100000;
+
+ if (ctrl->is_new) {
+ if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+ opt->bitrate_mode = HDPVR_CONSTANT;
+ else
+ opt->bitrate_mode = HDPVR_VARIABLE_AVERAGE;
hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
opt->bitrate_mode);
+ v4l2_ctrl_activate(dev->video_bitrate_peak,
+ ctrl->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
}
- break;
- case V4L2_CID_MPEG_VIDEO_BITRATE: {
- uint bitrate = ctrl->value / 100000;
-
- opt->bitrate = bitrate;
- if (bitrate >= opt->peak_bitrate)
- opt->peak_bitrate = bitrate+1;
-
- hdpvr_set_bitrate(dev);
- break;
- }
- case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: {
- uint peak_bitrate = ctrl->value / 100000;
- if (opt->bitrate_mode == HDPVR_CONSTANT)
- break;
-
- if (opt->bitrate < peak_bitrate) {
+ if (dev->video_bitrate_peak->is_new ||
+ dev->video_bitrate->is_new) {
+ opt->bitrate = bitrate;
opt->peak_bitrate = peak_bitrate;
hdpvr_set_bitrate(dev);
- } else
- ret = -EINVAL;
- break;
+ }
+ return 0;
}
case V4L2_CID_MPEG_STREAM_TYPE:
- break;
+ return 0;
default:
- return -EINVAL;
+ break;
}
return ret;
}
-static int vidioc_s_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *ctrls)
-{
- struct hdpvr_fh *fh = file->private_data;
- struct hdpvr_device *dev = fh->dev;
- int i, err = 0;
-
- if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
- for (i = 0; i < ctrls->count; i++) {
- struct v4l2_ext_control *ctrl = ctrls->controls + i;
-
- err = hdpvr_try_ctrl(ctrl,
- dev->flags & HDPVR_FLAG_AC3_CAP);
- if (err) {
- ctrls->error_idx = i;
- break;
- }
- err = hdpvr_set_ctrl(dev, ctrl);
- if (err) {
- ctrls->error_idx = i;
- break;
- }
- }
- return err;
-
- }
-
- return -EINVAL;
-}
-
static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data,
struct v4l2_fmtdesc *f)
{
.vidioc_enumaudio = vidioc_enumaudio,
.vidioc_g_audio = vidioc_g_audio,
.vidioc_s_audio = vidioc_s_audio,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
- .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
- .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_encoder_cmd = vidioc_encoder_cmd,
mutex_unlock(&dev->io_mutex);
v4l2_device_unregister(&dev->v4l2_dev);
+ v4l2_ctrl_handler_free(&dev->hdl);
/* deregister I2C adapter */
#if IS_ENABLED(CONFIG_I2C)
V4L2_STD_PAL_60,
};
+static const struct v4l2_ctrl_ops hdpvr_ctrl_ops = {
+ .try_ctrl = hdpvr_try_ctrl,
+ .s_ctrl = hdpvr_s_ctrl,
+};
+
int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
int devnum)
{
+ struct v4l2_ctrl_handler *hdl = &dev->hdl;
+ bool ac3 = dev->flags & HDPVR_FLAG_AC3_CAP;
+ int res;
+
+ v4l2_ctrl_handler_init(hdl, 11);
+ if (dev->fw_ver > 0x15) {
+ v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0x0, 0xff, 1, 0x80);
+ v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_CONTRAST, 0x0, 0xff, 1, 0x40);
+ v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_SATURATION, 0x0, 0xff, 1, 0x40);
+ v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_HUE, 0x0, 0x1e, 1, 0xf);
+ v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x80);
+ } else {
+ v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0x0, 0xff, 1, 0x86);
+ v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_CONTRAST, 0x0, 0xff, 1, 0x80);
+ v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_SATURATION, 0x0, 0xff, 1, 0x80);
+ v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_HUE, 0x0, 0xff, 1, 0x80);
+ v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x80);
+ }
+
+ v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_MPEG_STREAM_TYPE,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
+ 0x1, V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
+ v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_MPEG_AUDIO_ENCODING,
+ ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 : V4L2_MPEG_AUDIO_ENCODING_AAC,
+ 0x7, V4L2_MPEG_AUDIO_ENCODING_AAC);
+ v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_ENCODING,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 0x3,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC);
+
+ dev->video_mode = v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
+
+ dev->video_bitrate = v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_BITRATE,
+ 1000000, 13500000, 100000, 6500000);
+ dev->video_bitrate_peak = v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+ 1100000, 20200000, 100000, 9000000);
+ dev->v4l2_dev.ctrl_handler = hdl;
+ if (hdl->error) {
+ res = hdl->error;
+ v4l2_err(&dev->v4l2_dev, "Could not register controls\n");
+ goto error;
+ }
+ v4l2_ctrl_cluster(3, &dev->video_mode);
+ res = v4l2_ctrl_handler_setup(hdl);
+ if (res < 0) {
+ v4l2_err(&dev->v4l2_dev, "Could not setup controls\n");
+ goto error;
+ }
+
/* setup and register video device */
dev->video_dev = video_device_alloc();
if (!dev->video_dev) {
v4l2_err(&dev->v4l2_dev, "video_device_alloc() failed\n");
+ res = -ENOMEM;
goto error;
}
dev->video_dev->parent = parent;
video_set_drvdata(dev->video_dev, dev);
- if (video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum)) {
+ res = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum);
+ if (res < 0) {
v4l2_err(&dev->v4l2_dev, "video_device registration failed\n");
goto error;
}
return 0;
error:
- return -ENOMEM;
+ v4l2_ctrl_handler_free(hdl);
+ return res;
}