[media] v4l2-ctrls: create type_ops
Since compound controls can have non-standard types we need to be able to do type-specific checks etc. In order to make that easy type operations are added. There are four operations: - equal: check if two values are equal - init: initialize a value - log: log the value - validate: validate a new value The v4l2_ctrl struct adds p_new and p_cur unions at the end of the struct. This union provides a standard way of accessing control types through a pointer, which greatly simplifies internal control processing. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
This commit is contained in:
Родитель
e6bee3685e
Коммит
0176077a81
|
@ -1161,6 +1161,149 @@ static void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes)
|
||||||
v4l2_event_queue_fh(sev->fh, &ev);
|
v4l2_event_queue_fh(sev->fh, &ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool std_equal(const struct v4l2_ctrl *ctrl,
|
||||||
|
union v4l2_ctrl_ptr ptr1,
|
||||||
|
union v4l2_ctrl_ptr ptr2)
|
||||||
|
{
|
||||||
|
switch (ctrl->type) {
|
||||||
|
case V4L2_CTRL_TYPE_BUTTON:
|
||||||
|
return false;
|
||||||
|
case V4L2_CTRL_TYPE_STRING:
|
||||||
|
/* strings are always 0-terminated */
|
||||||
|
return !strcmp(ptr1.p_char, ptr2.p_char);
|
||||||
|
case V4L2_CTRL_TYPE_INTEGER64:
|
||||||
|
return *ptr1.p_s64 == *ptr2.p_s64;
|
||||||
|
default:
|
||||||
|
if (ctrl->is_ptr)
|
||||||
|
return !memcmp(ptr1.p, ptr2.p, ctrl->elem_size);
|
||||||
|
return *ptr1.p_s32 == *ptr2.p_s32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void std_init(const struct v4l2_ctrl *ctrl,
|
||||||
|
union v4l2_ctrl_ptr ptr)
|
||||||
|
{
|
||||||
|
switch (ctrl->type) {
|
||||||
|
case V4L2_CTRL_TYPE_STRING:
|
||||||
|
memset(ptr.p_char, ' ', ctrl->minimum);
|
||||||
|
ptr.p_char[ctrl->minimum] = '\0';
|
||||||
|
break;
|
||||||
|
case V4L2_CTRL_TYPE_INTEGER64:
|
||||||
|
*ptr.p_s64 = ctrl->default_value;
|
||||||
|
break;
|
||||||
|
case V4L2_CTRL_TYPE_INTEGER:
|
||||||
|
case V4L2_CTRL_TYPE_INTEGER_MENU:
|
||||||
|
case V4L2_CTRL_TYPE_MENU:
|
||||||
|
case V4L2_CTRL_TYPE_BITMASK:
|
||||||
|
case V4L2_CTRL_TYPE_BOOLEAN:
|
||||||
|
*ptr.p_s32 = ctrl->default_value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void std_log(const struct v4l2_ctrl *ctrl)
|
||||||
|
{
|
||||||
|
union v4l2_ctrl_ptr ptr = ctrl->p_cur;
|
||||||
|
|
||||||
|
switch (ctrl->type) {
|
||||||
|
case V4L2_CTRL_TYPE_INTEGER:
|
||||||
|
pr_cont("%d", *ptr.p_s32);
|
||||||
|
break;
|
||||||
|
case V4L2_CTRL_TYPE_BOOLEAN:
|
||||||
|
pr_cont("%s", *ptr.p_s32 ? "true" : "false");
|
||||||
|
break;
|
||||||
|
case V4L2_CTRL_TYPE_MENU:
|
||||||
|
pr_cont("%s", ctrl->qmenu[*ptr.p_s32]);
|
||||||
|
break;
|
||||||
|
case V4L2_CTRL_TYPE_INTEGER_MENU:
|
||||||
|
pr_cont("%lld", ctrl->qmenu_int[*ptr.p_s32]);
|
||||||
|
break;
|
||||||
|
case V4L2_CTRL_TYPE_BITMASK:
|
||||||
|
pr_cont("0x%08x", *ptr.p_s32);
|
||||||
|
break;
|
||||||
|
case V4L2_CTRL_TYPE_INTEGER64:
|
||||||
|
pr_cont("%lld", *ptr.p_s64);
|
||||||
|
break;
|
||||||
|
case V4L2_CTRL_TYPE_STRING:
|
||||||
|
pr_cont("%s", ptr.p_char);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pr_cont("unknown type %d", ctrl->type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Round towards the closest legal value */
|
||||||
|
#define ROUND_TO_RANGE(val, offset_type, ctrl) \
|
||||||
|
({ \
|
||||||
|
offset_type offset; \
|
||||||
|
val += (ctrl)->step / 2; \
|
||||||
|
val = clamp_t(typeof(val), val, \
|
||||||
|
(ctrl)->minimum, (ctrl)->maximum); \
|
||||||
|
offset = (val) - (ctrl)->minimum; \
|
||||||
|
offset = (ctrl)->step * (offset / (ctrl)->step); \
|
||||||
|
val = (ctrl)->minimum + offset; \
|
||||||
|
0; \
|
||||||
|
})
|
||||||
|
|
||||||
|
/* Validate a new control */
|
||||||
|
static int std_validate(const struct v4l2_ctrl *ctrl,
|
||||||
|
union v4l2_ctrl_ptr ptr)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
switch (ctrl->type) {
|
||||||
|
case V4L2_CTRL_TYPE_INTEGER:
|
||||||
|
return ROUND_TO_RANGE(*ptr.p_s32, u32, ctrl);
|
||||||
|
case V4L2_CTRL_TYPE_INTEGER64:
|
||||||
|
return ROUND_TO_RANGE(*ptr.p_s64, u64, ctrl);
|
||||||
|
|
||||||
|
case V4L2_CTRL_TYPE_BOOLEAN:
|
||||||
|
*ptr.p_s32 = !!*ptr.p_s32;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case V4L2_CTRL_TYPE_MENU:
|
||||||
|
case V4L2_CTRL_TYPE_INTEGER_MENU:
|
||||||
|
if (*ptr.p_s32 < ctrl->minimum || *ptr.p_s32 > ctrl->maximum)
|
||||||
|
return -ERANGE;
|
||||||
|
if (ctrl->menu_skip_mask & (1 << *ptr.p_s32))
|
||||||
|
return -EINVAL;
|
||||||
|
if (ctrl->type == V4L2_CTRL_TYPE_MENU &&
|
||||||
|
ctrl->qmenu[*ptr.p_s32][0] == '\0')
|
||||||
|
return -EINVAL;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case V4L2_CTRL_TYPE_BITMASK:
|
||||||
|
*ptr.p_s32 &= ctrl->maximum;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case V4L2_CTRL_TYPE_BUTTON:
|
||||||
|
case V4L2_CTRL_TYPE_CTRL_CLASS:
|
||||||
|
*ptr.p_s32 = 0;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case V4L2_CTRL_TYPE_STRING:
|
||||||
|
len = strlen(ptr.p_char);
|
||||||
|
if (len < ctrl->minimum)
|
||||||
|
return -ERANGE;
|
||||||
|
if ((len - ctrl->minimum) % ctrl->step)
|
||||||
|
return -ERANGE;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct v4l2_ctrl_type_ops std_type_ops = {
|
||||||
|
.equal = std_equal,
|
||||||
|
.init = std_init,
|
||||||
|
.log = std_log,
|
||||||
|
.validate = std_validate,
|
||||||
|
};
|
||||||
|
|
||||||
/* Helper function: copy the current control value back to the caller */
|
/* Helper function: copy the current control value back to the caller */
|
||||||
static int cur_to_user(struct v4l2_ext_control *c,
|
static int cur_to_user(struct v4l2_ext_control *c,
|
||||||
struct v4l2_ctrl *ctrl)
|
struct v4l2_ctrl *ctrl)
|
||||||
|
@ -1344,21 +1487,7 @@ static int cluster_changed(struct v4l2_ctrl *master)
|
||||||
|
|
||||||
if (ctrl == NULL)
|
if (ctrl == NULL)
|
||||||
continue;
|
continue;
|
||||||
switch (ctrl->type) {
|
diff = !ctrl->type_ops->equal(ctrl, ctrl->p_cur, ctrl->p_new);
|
||||||
case V4L2_CTRL_TYPE_BUTTON:
|
|
||||||
/* Button controls are always 'different' */
|
|
||||||
return 1;
|
|
||||||
case V4L2_CTRL_TYPE_STRING:
|
|
||||||
/* strings are always 0-terminated */
|
|
||||||
diff = strcmp(ctrl->string, ctrl->cur.string);
|
|
||||||
break;
|
|
||||||
case V4L2_CTRL_TYPE_INTEGER64:
|
|
||||||
diff = ctrl->val64 != ctrl->cur.val64;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
diff = ctrl->val != ctrl->cur.val;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
|
@ -1399,65 +1528,30 @@ static int check_range(enum v4l2_ctrl_type type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Round towards the closest legal value */
|
|
||||||
#define ROUND_TO_RANGE(val, offset_type, ctrl) \
|
|
||||||
({ \
|
|
||||||
offset_type offset; \
|
|
||||||
val += (ctrl)->step / 2; \
|
|
||||||
val = clamp_t(typeof(val), val, \
|
|
||||||
(ctrl)->minimum, (ctrl)->maximum); \
|
|
||||||
offset = (val) - (ctrl)->minimum; \
|
|
||||||
offset = (ctrl)->step * (offset / (ctrl)->step); \
|
|
||||||
val = (ctrl)->minimum + offset; \
|
|
||||||
0; \
|
|
||||||
})
|
|
||||||
|
|
||||||
/* Validate a new control */
|
/* Validate a new control */
|
||||||
static int validate_new(const struct v4l2_ctrl *ctrl,
|
static int validate_new(const struct v4l2_ctrl *ctrl,
|
||||||
struct v4l2_ext_control *c)
|
struct v4l2_ext_control *c)
|
||||||
{
|
{
|
||||||
size_t len;
|
union v4l2_ctrl_ptr ptr;
|
||||||
|
|
||||||
switch (ctrl->type) {
|
switch (ctrl->type) {
|
||||||
case V4L2_CTRL_TYPE_INTEGER:
|
case V4L2_CTRL_TYPE_INTEGER:
|
||||||
return ROUND_TO_RANGE(*(s32 *)&c->value, u32, ctrl);
|
|
||||||
case V4L2_CTRL_TYPE_INTEGER64:
|
|
||||||
return ROUND_TO_RANGE(*(s64 *)&c->value64, u64, ctrl);
|
|
||||||
|
|
||||||
case V4L2_CTRL_TYPE_BOOLEAN:
|
|
||||||
c->value = !!c->value;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case V4L2_CTRL_TYPE_MENU:
|
|
||||||
case V4L2_CTRL_TYPE_INTEGER_MENU:
|
case V4L2_CTRL_TYPE_INTEGER_MENU:
|
||||||
if (c->value < ctrl->minimum || c->value > ctrl->maximum)
|
case V4L2_CTRL_TYPE_MENU:
|
||||||
return -ERANGE;
|
|
||||||
if (ctrl->menu_skip_mask & (1 << c->value))
|
|
||||||
return -EINVAL;
|
|
||||||
if (ctrl->type == V4L2_CTRL_TYPE_MENU &&
|
|
||||||
ctrl->qmenu[c->value][0] == '\0')
|
|
||||||
return -EINVAL;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case V4L2_CTRL_TYPE_BITMASK:
|
case V4L2_CTRL_TYPE_BITMASK:
|
||||||
c->value &= ctrl->maximum;
|
case V4L2_CTRL_TYPE_BOOLEAN:
|
||||||
return 0;
|
|
||||||
|
|
||||||
case V4L2_CTRL_TYPE_BUTTON:
|
case V4L2_CTRL_TYPE_BUTTON:
|
||||||
case V4L2_CTRL_TYPE_CTRL_CLASS:
|
case V4L2_CTRL_TYPE_CTRL_CLASS:
|
||||||
c->value = 0;
|
ptr.p_s32 = &c->value;
|
||||||
return 0;
|
return ctrl->type_ops->validate(ctrl, ptr);
|
||||||
|
|
||||||
case V4L2_CTRL_TYPE_STRING:
|
case V4L2_CTRL_TYPE_INTEGER64:
|
||||||
len = strlen(c->string);
|
ptr.p_s64 = &c->value64;
|
||||||
if (len < ctrl->minimum)
|
return ctrl->type_ops->validate(ctrl, ptr);
|
||||||
return -ERANGE;
|
|
||||||
if ((len - ctrl->minimum) % ctrl->step)
|
|
||||||
return -ERANGE;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
ptr.p = c->ptr;
|
||||||
|
return ctrl->type_ops->validate(ctrl, ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1674,6 +1768,7 @@ unlock:
|
||||||
/* Add a new control */
|
/* Add a new control */
|
||||||
static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
|
static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
|
||||||
const struct v4l2_ctrl_ops *ops,
|
const struct v4l2_ctrl_ops *ops,
|
||||||
|
const struct v4l2_ctrl_type_ops *type_ops,
|
||||||
u32 id, const char *name, enum v4l2_ctrl_type type,
|
u32 id, const char *name, enum v4l2_ctrl_type type,
|
||||||
s64 min, s64 max, u64 step, s64 def,
|
s64 min, s64 max, u64 step, s64 def,
|
||||||
u32 elem_size,
|
u32 elem_size,
|
||||||
|
@ -1731,6 +1826,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
|
||||||
INIT_LIST_HEAD(&ctrl->ev_subs);
|
INIT_LIST_HEAD(&ctrl->ev_subs);
|
||||||
ctrl->handler = hdl;
|
ctrl->handler = hdl;
|
||||||
ctrl->ops = ops;
|
ctrl->ops = ops;
|
||||||
|
ctrl->type_ops = type_ops ? type_ops : &std_type_ops;
|
||||||
ctrl->id = id;
|
ctrl->id = id;
|
||||||
ctrl->name = name;
|
ctrl->name = name;
|
||||||
ctrl->type = type;
|
ctrl->type = type;
|
||||||
|
@ -1751,16 +1847,16 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
|
||||||
ctrl->cur.val = ctrl->val = def;
|
ctrl->cur.val = ctrl->val = def;
|
||||||
data = &ctrl->cur + 1;
|
data = &ctrl->cur + 1;
|
||||||
|
|
||||||
if (ctrl->is_string) {
|
if (ctrl->is_ptr) {
|
||||||
ctrl->string = data;
|
ctrl->p = ctrl->p_new.p = data;
|
||||||
ctrl->cur.string = data + elem_size;
|
ctrl->p_cur.p = data + elem_size;
|
||||||
|
} else {
|
||||||
if (ctrl->minimum)
|
ctrl->p_new.p = &ctrl->val;
|
||||||
memset(ctrl->cur.string, ' ', ctrl->minimum);
|
ctrl->p_cur.p = &ctrl->cur.val;
|
||||||
} else if (ctrl->is_ptr) {
|
|
||||||
ctrl->p = data;
|
|
||||||
ctrl->cur.p = data + elem_size;
|
|
||||||
}
|
}
|
||||||
|
ctrl->type_ops->init(ctrl, ctrl->p_cur);
|
||||||
|
ctrl->type_ops->init(ctrl, ctrl->p_new);
|
||||||
|
|
||||||
if (handler_new_ref(hdl, ctrl)) {
|
if (handler_new_ref(hdl, ctrl)) {
|
||||||
kfree(ctrl);
|
kfree(ctrl);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1804,7 +1900,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->id, name,
|
ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->type_ops, cfg->id, name,
|
||||||
type, min, max,
|
type, min, max,
|
||||||
is_menu ? cfg->menu_skip_mask : step,
|
is_menu ? cfg->menu_skip_mask : step,
|
||||||
def, cfg->elem_size,
|
def, cfg->elem_size,
|
||||||
|
@ -1831,7 +1927,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
|
||||||
handler_set_err(hdl, -EINVAL);
|
handler_set_err(hdl, -EINVAL);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return v4l2_ctrl_new(hdl, ops, id, name, type,
|
return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
|
||||||
min, max, step, def, 0,
|
min, max, step, def, 0,
|
||||||
flags, NULL, NULL, NULL);
|
flags, NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
@ -1864,7 +1960,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
|
||||||
handler_set_err(hdl, -EINVAL);
|
handler_set_err(hdl, -EINVAL);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return v4l2_ctrl_new(hdl, ops, id, name, type,
|
return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
|
||||||
0, max, mask, def, 0,
|
0, max, mask, def, 0,
|
||||||
flags, qmenu, qmenu_int, NULL);
|
flags, qmenu, qmenu_int, NULL);
|
||||||
}
|
}
|
||||||
|
@ -1896,7 +1992,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl,
|
||||||
handler_set_err(hdl, -EINVAL);
|
handler_set_err(hdl, -EINVAL);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return v4l2_ctrl_new(hdl, ops, id, name, type, 0, max, mask, def,
|
return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
|
||||||
|
0, max, mask, def,
|
||||||
0, flags, qmenu, NULL, NULL);
|
0, flags, qmenu, NULL, NULL);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1920,7 +2017,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
|
||||||
handler_set_err(hdl, -EINVAL);
|
handler_set_err(hdl, -EINVAL);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return v4l2_ctrl_new(hdl, ops, id, name, type,
|
return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
|
||||||
0, max, 0, def, 0,
|
0, max, 0, def, 0,
|
||||||
flags, NULL, qmenu_int, NULL);
|
flags, NULL, qmenu_int, NULL);
|
||||||
}
|
}
|
||||||
|
@ -2104,32 +2201,8 @@ static void log_ctrl(const struct v4l2_ctrl *ctrl,
|
||||||
|
|
||||||
pr_info("%s%s%s: ", prefix, colon, ctrl->name);
|
pr_info("%s%s%s: ", prefix, colon, ctrl->name);
|
||||||
|
|
||||||
switch (ctrl->type) {
|
ctrl->type_ops->log(ctrl);
|
||||||
case V4L2_CTRL_TYPE_INTEGER:
|
|
||||||
pr_cont("%d", ctrl->cur.val);
|
|
||||||
break;
|
|
||||||
case V4L2_CTRL_TYPE_BOOLEAN:
|
|
||||||
pr_cont("%s", ctrl->cur.val ? "true" : "false");
|
|
||||||
break;
|
|
||||||
case V4L2_CTRL_TYPE_MENU:
|
|
||||||
pr_cont("%s", ctrl->qmenu[ctrl->cur.val]);
|
|
||||||
break;
|
|
||||||
case V4L2_CTRL_TYPE_INTEGER_MENU:
|
|
||||||
pr_cont("%lld", ctrl->qmenu_int[ctrl->cur.val]);
|
|
||||||
break;
|
|
||||||
case V4L2_CTRL_TYPE_BITMASK:
|
|
||||||
pr_cont("0x%08x", ctrl->cur.val);
|
|
||||||
break;
|
|
||||||
case V4L2_CTRL_TYPE_INTEGER64:
|
|
||||||
pr_cont("%lld", ctrl->cur.val64);
|
|
||||||
break;
|
|
||||||
case V4L2_CTRL_TYPE_STRING:
|
|
||||||
pr_cont("%s", ctrl->cur.string);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
pr_cont("unknown type %d", ctrl->type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (ctrl->flags & (V4L2_CTRL_FLAG_INACTIVE |
|
if (ctrl->flags & (V4L2_CTRL_FLAG_INACTIVE |
|
||||||
V4L2_CTRL_FLAG_GRABBED |
|
V4L2_CTRL_FLAG_GRABBED |
|
||||||
V4L2_CTRL_FLAG_VOLATILE)) {
|
V4L2_CTRL_FLAG_VOLATILE)) {
|
||||||
|
|
|
@ -531,13 +531,12 @@ static void v4l_print_query_ext_ctrl(const void *arg, bool write_only)
|
||||||
|
|
||||||
pr_cont("id=0x%x, type=%d, name=%.*s, min/max=%lld/%lld, "
|
pr_cont("id=0x%x, type=%d, name=%.*s, min/max=%lld/%lld, "
|
||||||
"step=%lld, default=%lld, flags=0x%08x, elem_size=%u, elems=%u, "
|
"step=%lld, default=%lld, flags=0x%08x, elem_size=%u, elems=%u, "
|
||||||
"nr_of_dims=%u, dims=%u,%u,%u,%u,%u,%u,%u,%u\n",
|
"nr_of_dims=%u, dims=%u,%u,%u,%u\n",
|
||||||
p->id, p->type, (int)sizeof(p->name), p->name,
|
p->id, p->type, (int)sizeof(p->name), p->name,
|
||||||
p->minimum, p->maximum,
|
p->minimum, p->maximum,
|
||||||
p->step, p->default_value, p->flags,
|
p->step, p->default_value, p->flags,
|
||||||
p->elem_size, p->elems, p->nr_of_dims,
|
p->elem_size, p->elems, p->nr_of_dims,
|
||||||
p->dims[0], p->dims[1], p->dims[2], p->dims[3],
|
p->dims[0], p->dims[1], p->dims[2], p->dims[3]);
|
||||||
p->dims[4], p->dims[5], p->dims[6], p->dims[7]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void v4l_print_querymenu(const void *arg, bool write_only)
|
static void v4l_print_querymenu(const void *arg, bool write_only)
|
||||||
|
|
|
@ -36,6 +36,19 @@ struct v4l2_subscribed_event;
|
||||||
struct v4l2_fh;
|
struct v4l2_fh;
|
||||||
struct poll_table_struct;
|
struct poll_table_struct;
|
||||||
|
|
||||||
|
/** union v4l2_ctrl_ptr - A pointer to a control value.
|
||||||
|
* @p_s32: Pointer to a 32-bit signed value.
|
||||||
|
* @p_s64: Pointer to a 64-bit signed value.
|
||||||
|
* @p_char: Pointer to a string.
|
||||||
|
* @p: Pointer to a compound value.
|
||||||
|
*/
|
||||||
|
union v4l2_ctrl_ptr {
|
||||||
|
s32 *p_s32;
|
||||||
|
s64 *p_s64;
|
||||||
|
char *p_char;
|
||||||
|
void *p;
|
||||||
|
};
|
||||||
|
|
||||||
/** struct v4l2_ctrl_ops - The control operations that the driver has to provide.
|
/** struct v4l2_ctrl_ops - The control operations that the driver has to provide.
|
||||||
* @g_volatile_ctrl: Get a new value for this control. Generally only relevant
|
* @g_volatile_ctrl: Get a new value for this control. Generally only relevant
|
||||||
* for volatile (and usually read-only) controls such as a control
|
* for volatile (and usually read-only) controls such as a control
|
||||||
|
@ -54,6 +67,23 @@ struct v4l2_ctrl_ops {
|
||||||
int (*s_ctrl)(struct v4l2_ctrl *ctrl);
|
int (*s_ctrl)(struct v4l2_ctrl *ctrl);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** struct v4l2_ctrl_type_ops - The control type operations that the driver has to provide.
|
||||||
|
* @equal: return true if both values are equal.
|
||||||
|
* @init: initialize the value.
|
||||||
|
* @log: log the value.
|
||||||
|
* @validate: validate the value. Return 0 on success and a negative value otherwise.
|
||||||
|
*/
|
||||||
|
struct v4l2_ctrl_type_ops {
|
||||||
|
bool (*equal)(const struct v4l2_ctrl *ctrl,
|
||||||
|
union v4l2_ctrl_ptr ptr1,
|
||||||
|
union v4l2_ctrl_ptr ptr2);
|
||||||
|
void (*init)(const struct v4l2_ctrl *ctrl,
|
||||||
|
union v4l2_ctrl_ptr ptr);
|
||||||
|
void (*log)(const struct v4l2_ctrl *ctrl);
|
||||||
|
int (*validate)(const struct v4l2_ctrl *ctrl,
|
||||||
|
union v4l2_ctrl_ptr ptr);
|
||||||
|
};
|
||||||
|
|
||||||
typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
|
typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
|
||||||
|
|
||||||
/** struct v4l2_ctrl - The control structure.
|
/** struct v4l2_ctrl - The control structure.
|
||||||
|
@ -89,6 +119,7 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
|
||||||
* value, then the whole cluster is in manual mode. Drivers should
|
* value, then the whole cluster is in manual mode. Drivers should
|
||||||
* never set this flag directly.
|
* never set this flag directly.
|
||||||
* @ops: The control ops.
|
* @ops: The control ops.
|
||||||
|
* @type_ops: The control type ops.
|
||||||
* @id: The control ID.
|
* @id: The control ID.
|
||||||
* @name: The control name.
|
* @name: The control name.
|
||||||
* @type: The control type.
|
* @type: The control type.
|
||||||
|
@ -137,6 +168,7 @@ struct v4l2_ctrl {
|
||||||
unsigned int manual_mode_value:8;
|
unsigned int manual_mode_value:8;
|
||||||
|
|
||||||
const struct v4l2_ctrl_ops *ops;
|
const struct v4l2_ctrl_ops *ops;
|
||||||
|
const struct v4l2_ctrl_type_ops *type_ops;
|
||||||
u32 id;
|
u32 id;
|
||||||
const char *name;
|
const char *name;
|
||||||
enum v4l2_ctrl_type type;
|
enum v4l2_ctrl_type type;
|
||||||
|
@ -164,6 +196,9 @@ struct v4l2_ctrl {
|
||||||
char *string;
|
char *string;
|
||||||
void *p;
|
void *p;
|
||||||
} cur;
|
} cur;
|
||||||
|
|
||||||
|
union v4l2_ctrl_ptr p_new;
|
||||||
|
union v4l2_ctrl_ptr p_cur;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** struct v4l2_ctrl_ref - The control reference.
|
/** struct v4l2_ctrl_ref - The control reference.
|
||||||
|
@ -217,6 +252,7 @@ struct v4l2_ctrl_handler {
|
||||||
|
|
||||||
/** struct v4l2_ctrl_config - Control configuration structure.
|
/** struct v4l2_ctrl_config - Control configuration structure.
|
||||||
* @ops: The control ops.
|
* @ops: The control ops.
|
||||||
|
* @type_ops: The control type ops. Only needed for compound controls.
|
||||||
* @id: The control ID.
|
* @id: The control ID.
|
||||||
* @name: The control name.
|
* @name: The control name.
|
||||||
* @type: The control type.
|
* @type: The control type.
|
||||||
|
@ -241,6 +277,7 @@ struct v4l2_ctrl_handler {
|
||||||
*/
|
*/
|
||||||
struct v4l2_ctrl_config {
|
struct v4l2_ctrl_config {
|
||||||
const struct v4l2_ctrl_ops *ops;
|
const struct v4l2_ctrl_ops *ops;
|
||||||
|
const struct v4l2_ctrl_type_ops *type_ops;
|
||||||
u32 id;
|
u32 id;
|
||||||
const char *name;
|
const char *name;
|
||||||
enum v4l2_ctrl_type type;
|
enum v4l2_ctrl_type type;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче