blob: e50e62cc0084a507815e4992c532921c2f649a13 [file] [log] [blame]
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-vmalloc.h>
#include <media/v4l2-ctrls.h>
#include "ambxc.h"
#include "ambxc_ctrls.h"
#define IS_AMBXC_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) \
&& V4L2_CTRL_DRIVER_PRIV(x))
struct ambxc_control {
__u32 id;
enum v4l2_ctrl_type type;
__u8 name[32]; /* Whatever */
__s32 minimum; /* Note signedness */
__s32 maximum;
__s32 step;
__u32 menu_skip_mask;
__s32 default_value;
__u32 flags;
__u32 reserved[2];
__u8 is_volatile;
};
static struct ambxc_control controls[] = {
{
.id = V4L2_CID_MPEG_VIDEO_GOP_SIZE,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = (1 << 16) - 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
.maximum = V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES,
.default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
.menu_skip_mask = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 1,
.maximum = (1 << 16) - 1,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 1900,
.maximum = (1 << 30) - 1,
.step = 1,
.default_value = 1900,
},
{
.id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = (1 << 16) - 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_BITRATE,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 1,
.maximum = (1 << 30) - 1,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_VBV_SIZE,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = (1 << 16) - 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = (1 << 16) - 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEADER_MODE,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
.maximum = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
.default_value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
.menu_skip_mask = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_B_FRAMES,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 2,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
.maximum = V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH,
.default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
.menu_skip_mask = ~(
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)
),
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
.maximum = V4L2_MPEG_VIDEO_H264_LEVEL_4_0,
.default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
},
{
.id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
.maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5,
.default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
.menu_skip_mask = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
.maximum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY,
.default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
.menu_skip_mask = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = -6,
.maximum = 6,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = -6,
.maximum = 6,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
.maximum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
.default_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
.menu_skip_mask = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "MPEG4 I-Frame QP value",
.minimum = 1,
.maximum = 31,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "MPEG4 Minimum QP value",
.minimum = 1,
.maximum = 31,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "MPEG4 Maximum QP value",
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "MPEG4 P frame QP value",
.minimum = 1,
.maximum = 31,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "MPEG4 B frame QP value",
.minimum = 1,
.maximum = 31,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED,
.maximum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED,
.default_value = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED,
.menu_skip_mask = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = (1 << 16) - 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = (1 << 16) - 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = (1 << 16) - 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
.maximum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE,
.default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
.menu_skip_mask = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_MPEG4_QPEL,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
};
#define NUM_CTRLS ARRAY_SIZE(controls)
/* Set controls - v4l2 control framework */
static int ambxc_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct ambxc_ctx *ctx;
struct ambxc_dev *dev;
int ret = 0;
ctx = container_of(ctrl->handler, struct ambxc_ctx, hdl);
dev = ctx->dev;
switch (ctrl->id) {
case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
break;
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
break;
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
break;
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
break;
case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
break;
case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
break;
case V4L2_CID_MPEG_VIDEO_BITRATE:
break;
case V4L2_CID_MPEG_VIDEO_VBV_SIZE:
break;
case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE:
break;
case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
break;
case V4L2_CID_MPEG_VIDEO_B_FRAMES:
break;
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
switch (ctrl->val) {
case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
break;
case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
break;
case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
break;
case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
break;
default:
ret = -EINVAL;
}
break;
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
break;
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
break;
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
break;
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
break;
case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
break;
case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
break;
case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
break;
case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
break;
case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
break;
case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
break;
case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
break;
case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:
case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:
case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:
case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP:
break;
case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
break;
case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
break;
case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH:
break;
case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT:
break;
case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
break;
case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
switch (ctrl->val) {
case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
break;
case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
break;
default:
ret = -EINVAL;
}
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:
break;
default:
v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n",
ctrl->id, ctrl->val);
ret = -EINVAL;
}
return ret;
}
static int ambxc_g_v_ctrl(struct v4l2_ctrl *ctrl)
{
struct ambxc_ctx *ctx;
struct ambxc_dev *dev;
ctx = container_of(ctrl->handler, struct ambxc_ctx, hdl);
dev = ctx->dev;
switch (ctrl->id) {
case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
break;
}
return 0;
}
static const struct v4l2_ctrl_ops ambxc_ctrl_ops = {
.s_ctrl = ambxc_s_ctrl,
.g_volatile_ctrl = ambxc_g_v_ctrl,
};
int ambxc_init_ctrls(struct ambxc_ctx *ctx)
{
struct ambxc_dev *dev = ctx->dev;
struct v4l2_ctrl_config cfg;
struct ambxc_control *ctrl;
int i;
v4l2_ctrl_handler_init(&ctx->hdl, NUM_CTRLS);
if (ctx->hdl.error) {
dprintk(dev, "v4l2_ctrl_handler_init failed\n");
return ctx->hdl.error;
}
for (i = 0; i < NUM_CTRLS; i++) {
ctrl = &controls[i];
if (IS_AMBXC_PRIV(ctrl->id)) {
memset(&cfg, 0, sizeof(struct v4l2_ctrl_config));
cfg.ops = &ambxc_ctrl_ops;
cfg.id = ctrl->id;
cfg.min = ctrl->minimum;
cfg.max = ctrl->maximum;
cfg.def = ctrl->default_value;
cfg.name = ctrl->name;
cfg.type = ctrl->type;
cfg.step = ctrl->step;
cfg.menu_skip_mask = 0;
ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->hdl,
&cfg, NULL);
}
else {
if (ctrl->type == V4L2_CTRL_TYPE_MENU) {
ctx->ctrls[i] = v4l2_ctrl_new_std_menu(
&ctx->hdl,
&ambxc_ctrl_ops, ctrl->id,
ctrl->maximum, 0,
ctrl->default_value);
}
else {
ctx->ctrls[i] = v4l2_ctrl_new_std(
&ctx->hdl,
&ambxc_ctrl_ops, ctrl->id,
ctrl->minimum,
ctrl->maximum, ctrl->step,
ctrl->default_value);
}
}
if (ctx->hdl.error) {
dprintk(dev, "Adding control (%d) failed\n", i);
return ctx->hdl.error;
}
if (ctrl->is_volatile && ctx->ctrls[i])
ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE;
}
v4l2_ctrl_handler_setup(&ctx->hdl);
return 0;
}
void ambxc_release_ctrls(struct ambxc_ctx *ctx)
{
v4l2_ctrl_handler_free(&ctx->hdl);
}