提交 99c77aa4 编写于 作者: H Hans Verkuil 提交者: Mauro Carvalho Chehab

[media] hdpvr: convert to the control framework

Signed-off-by: NHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: NMauro Carvalho Chehab <mchehab@redhat.com>
上级 a7b74bd8
......@@ -710,335 +710,69 @@ static int vidioc_g_audio(struct file *file, void *private_data,
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; */
......@@ -1051,81 +785,37 @@ static int hdpvr_set_ctrl(struct hdpvr_device *dev,
/* 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)
{
......@@ -1215,12 +905,6 @@ static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = {
.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,
......@@ -1237,6 +921,7 @@ static void hdpvr_device_release(struct video_device *vdev)
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)
......@@ -1264,13 +949,85 @@ static const struct video_device hdpvr_video_template = {
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;
}
......@@ -1279,12 +1036,14 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
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;
}
......@@ -16,6 +16,7 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
#include <media/ir-kbd-i2c.h>
#define HDPVR_MAX 8
......@@ -65,10 +66,17 @@ struct hdpvr_options {
struct hdpvr_device {
/* the v4l device for this device */
struct video_device *video_dev;
/* the control handler for this device */
struct v4l2_ctrl_handler hdl;
/* the usb device for this device */
struct usb_device *udev;
/* v4l2-device unused */
struct v4l2_device v4l2_dev;
struct { /* video mode/bitrate control cluster */
struct v4l2_ctrl *video_mode;
struct v4l2_ctrl *video_bitrate;
struct v4l2_ctrl *video_bitrate_peak;
};
/* the max packet size of the bulk endpoint */
size_t bulk_in_size;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册