Commit ce580fe5 authored by Sakari Ailus's avatar Sakari Ailus Committed by Mauro Carvalho Chehab

[media] v4l: Introduce integer menu controls

Create a new control type called V4L2_CTRL_TYPE_INTEGER_MENU. Integer menu
controls are just like menu controls but the menu items are 64-bit integers
rather than strings.
Signed-off-by: default avatarSakari Ailus <sakari.ailus@iki.fi>
Acked-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Tested-by: default avatarSylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 3fd7e434
...@@ -852,7 +852,8 @@ static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 change ...@@ -852,7 +852,8 @@ static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 change
ev->u.ctrl.value64 = ctrl->cur.val64; ev->u.ctrl.value64 = ctrl->cur.val64;
ev->u.ctrl.minimum = ctrl->minimum; ev->u.ctrl.minimum = ctrl->minimum;
ev->u.ctrl.maximum = ctrl->maximum; ev->u.ctrl.maximum = ctrl->maximum;
if (ctrl->type == V4L2_CTRL_TYPE_MENU) if (ctrl->type == V4L2_CTRL_TYPE_MENU
|| ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
ev->u.ctrl.step = 1; ev->u.ctrl.step = 1;
else else
ev->u.ctrl.step = ctrl->step; ev->u.ctrl.step = ctrl->step;
...@@ -1083,10 +1084,13 @@ static int validate_new_int(const struct v4l2_ctrl *ctrl, s32 *pval) ...@@ -1083,10 +1084,13 @@ static int validate_new_int(const struct v4l2_ctrl *ctrl, s32 *pval)
return 0; return 0;
case V4L2_CTRL_TYPE_MENU: case V4L2_CTRL_TYPE_MENU:
case V4L2_CTRL_TYPE_INTEGER_MENU:
if (val < ctrl->minimum || val > ctrl->maximum) if (val < ctrl->minimum || val > ctrl->maximum)
return -ERANGE; return -ERANGE;
if (ctrl->qmenu[val][0] == '\0' || if (ctrl->menu_skip_mask & (1 << val))
(ctrl->menu_skip_mask & (1 << val))) return -EINVAL;
if (ctrl->type == V4L2_CTRL_TYPE_MENU &&
ctrl->qmenu[val][0] == '\0')
return -EINVAL; return -EINVAL;
return 0; return 0;
...@@ -1114,6 +1118,7 @@ static int validate_new(const struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c ...@@ -1114,6 +1118,7 @@ static int validate_new(const struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c
case V4L2_CTRL_TYPE_INTEGER: case V4L2_CTRL_TYPE_INTEGER:
case V4L2_CTRL_TYPE_BOOLEAN: case V4L2_CTRL_TYPE_BOOLEAN:
case V4L2_CTRL_TYPE_MENU: case V4L2_CTRL_TYPE_MENU:
case V4L2_CTRL_TYPE_INTEGER_MENU:
case V4L2_CTRL_TYPE_BITMASK: case V4L2_CTRL_TYPE_BITMASK:
case V4L2_CTRL_TYPE_BUTTON: case V4L2_CTRL_TYPE_BUTTON:
case V4L2_CTRL_TYPE_CTRL_CLASS: case V4L2_CTRL_TYPE_CTRL_CLASS:
...@@ -1343,7 +1348,8 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, ...@@ -1343,7 +1348,8 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
const struct v4l2_ctrl_ops *ops, const struct v4l2_ctrl_ops *ops,
u32 id, const char *name, enum v4l2_ctrl_type type, u32 id, const char *name, enum v4l2_ctrl_type type,
s32 min, s32 max, u32 step, s32 def, s32 min, s32 max, u32 step, s32 def,
u32 flags, const char * const *qmenu, void *priv) u32 flags, const char * const *qmenu,
const s64 *qmenu_int, void *priv)
{ {
struct v4l2_ctrl *ctrl; struct v4l2_ctrl *ctrl;
unsigned sz_extra = 0; unsigned sz_extra = 0;
...@@ -1356,6 +1362,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, ...@@ -1356,6 +1362,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
(type == V4L2_CTRL_TYPE_INTEGER && step == 0) || (type == V4L2_CTRL_TYPE_INTEGER && step == 0) ||
(type == V4L2_CTRL_TYPE_BITMASK && max == 0) || (type == V4L2_CTRL_TYPE_BITMASK && max == 0) ||
(type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) || (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||
(type == V4L2_CTRL_TYPE_INTEGER_MENU && qmenu_int == NULL) ||
(type == V4L2_CTRL_TYPE_STRING && max == 0)) { (type == V4L2_CTRL_TYPE_STRING && max == 0)) {
handler_set_err(hdl, -ERANGE); handler_set_err(hdl, -ERANGE);
return NULL; return NULL;
...@@ -1366,6 +1373,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, ...@@ -1366,6 +1373,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
} }
if ((type == V4L2_CTRL_TYPE_INTEGER || if ((type == V4L2_CTRL_TYPE_INTEGER ||
type == V4L2_CTRL_TYPE_MENU || type == V4L2_CTRL_TYPE_MENU ||
type == V4L2_CTRL_TYPE_INTEGER_MENU ||
type == V4L2_CTRL_TYPE_BOOLEAN) && type == V4L2_CTRL_TYPE_BOOLEAN) &&
(def < min || def > max)) { (def < min || def > max)) {
handler_set_err(hdl, -ERANGE); handler_set_err(hdl, -ERANGE);
...@@ -1400,7 +1408,10 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, ...@@ -1400,7 +1408,10 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
ctrl->minimum = min; ctrl->minimum = min;
ctrl->maximum = max; ctrl->maximum = max;
ctrl->step = step; ctrl->step = step;
if (type == V4L2_CTRL_TYPE_MENU)
ctrl->qmenu = qmenu; ctrl->qmenu = qmenu;
else if (type == V4L2_CTRL_TYPE_INTEGER_MENU)
ctrl->qmenu_int = qmenu_int;
ctrl->priv = priv; ctrl->priv = priv;
ctrl->cur.val = ctrl->val = ctrl->default_value = def; ctrl->cur.val = ctrl->val = ctrl->default_value = def;
...@@ -1427,6 +1438,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl, ...@@ -1427,6 +1438,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
struct v4l2_ctrl *ctrl; struct v4l2_ctrl *ctrl;
const char *name = cfg->name; const char *name = cfg->name;
const char * const *qmenu = cfg->qmenu; const char * const *qmenu = cfg->qmenu;
const s64 *qmenu_int = cfg->qmenu_int;
enum v4l2_ctrl_type type = cfg->type; enum v4l2_ctrl_type type = cfg->type;
u32 flags = cfg->flags; u32 flags = cfg->flags;
s32 min = cfg->min; s32 min = cfg->min;
...@@ -1438,18 +1450,24 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl, ...@@ -1438,18 +1450,24 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step, v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step,
&def, &flags); &def, &flags);
is_menu = (cfg->type == V4L2_CTRL_TYPE_MENU); is_menu = (cfg->type == V4L2_CTRL_TYPE_MENU ||
cfg->type == V4L2_CTRL_TYPE_INTEGER_MENU);
if (is_menu) if (is_menu)
WARN_ON(step); WARN_ON(step);
else else
WARN_ON(cfg->menu_skip_mask); WARN_ON(cfg->menu_skip_mask);
if (is_menu && qmenu == NULL) if (cfg->type == V4L2_CTRL_TYPE_MENU && qmenu == NULL)
qmenu = v4l2_ctrl_get_menu(cfg->id); qmenu = v4l2_ctrl_get_menu(cfg->id);
else if (cfg->type == V4L2_CTRL_TYPE_INTEGER_MENU &&
qmenu_int == NULL) {
handler_set_err(hdl, -EINVAL);
return NULL;
}
ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->id, name, ctrl = v4l2_ctrl_new(hdl, cfg->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, flags, qmenu, priv); def, flags, qmenu, qmenu_int, priv);
if (ctrl) if (ctrl)
ctrl->is_private = cfg->is_private; ctrl->is_private = cfg->is_private;
return ctrl; return ctrl;
...@@ -1466,12 +1484,13 @@ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl, ...@@ -1466,12 +1484,13 @@ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
u32 flags; u32 flags;
v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags); v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
if (type == V4L2_CTRL_TYPE_MENU) { if (type == V4L2_CTRL_TYPE_MENU
|| type == V4L2_CTRL_TYPE_INTEGER_MENU) {
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, id, name, type,
min, max, step, def, flags, NULL, NULL); min, max, step, def, flags, NULL, NULL, NULL);
} }
EXPORT_SYMBOL(v4l2_ctrl_new_std); EXPORT_SYMBOL(v4l2_ctrl_new_std);
...@@ -1493,7 +1512,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl, ...@@ -1493,7 +1512,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
return NULL; return NULL;
} }
return v4l2_ctrl_new(hdl, ops, id, name, type, return v4l2_ctrl_new(hdl, ops, id, name, type,
0, max, mask, def, flags, qmenu, NULL); 0, max, mask, def, flags, qmenu, NULL, NULL);
} }
EXPORT_SYMBOL(v4l2_ctrl_new_std_menu); EXPORT_SYMBOL(v4l2_ctrl_new_std_menu);
...@@ -1659,6 +1678,9 @@ static void log_ctrl(const struct v4l2_ctrl *ctrl, ...@@ -1659,6 +1678,9 @@ static void log_ctrl(const struct v4l2_ctrl *ctrl,
case V4L2_CTRL_TYPE_MENU: case V4L2_CTRL_TYPE_MENU:
printk(KERN_CONT "%s", ctrl->qmenu[ctrl->cur.val]); printk(KERN_CONT "%s", ctrl->qmenu[ctrl->cur.val]);
break; break;
case V4L2_CTRL_TYPE_INTEGER_MENU:
printk(KERN_CONT "%lld", ctrl->qmenu_int[ctrl->cur.val]);
break;
case V4L2_CTRL_TYPE_BITMASK: case V4L2_CTRL_TYPE_BITMASK:
printk(KERN_CONT "0x%08x", ctrl->cur.val); printk(KERN_CONT "0x%08x", ctrl->cur.val);
break; break;
...@@ -1795,7 +1817,8 @@ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc) ...@@ -1795,7 +1817,8 @@ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
qc->minimum = ctrl->minimum; qc->minimum = ctrl->minimum;
qc->maximum = ctrl->maximum; qc->maximum = ctrl->maximum;
qc->default_value = ctrl->default_value; qc->default_value = ctrl->default_value;
if (ctrl->type == V4L2_CTRL_TYPE_MENU) if (ctrl->type == V4L2_CTRL_TYPE_MENU
|| ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
qc->step = 1; qc->step = 1;
else else
qc->step = ctrl->step; qc->step = ctrl->step;
...@@ -1825,16 +1848,33 @@ int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm) ...@@ -1825,16 +1848,33 @@ int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm)
qm->reserved = 0; qm->reserved = 0;
/* Sanity checks */ /* Sanity checks */
if (ctrl->qmenu == NULL || switch (ctrl->type) {
i < ctrl->minimum || i > ctrl->maximum) case V4L2_CTRL_TYPE_MENU:
if (ctrl->qmenu == NULL)
return -EINVAL;
break;
case V4L2_CTRL_TYPE_INTEGER_MENU:
if (ctrl->qmenu_int == NULL)
return -EINVAL; return -EINVAL;
break;
default:
return -EINVAL;
}
if (i < ctrl->minimum || i > ctrl->maximum)
return -EINVAL;
/* Use mask to see if this menu item should be skipped */ /* Use mask to see if this menu item should be skipped */
if (ctrl->menu_skip_mask & (1 << i)) if (ctrl->menu_skip_mask & (1 << i))
return -EINVAL; return -EINVAL;
/* Empty menu items should also be skipped */ /* Empty menu items should also be skipped */
if (ctrl->type == V4L2_CTRL_TYPE_MENU) {
if (ctrl->qmenu[i] == NULL || ctrl->qmenu[i][0] == '\0') if (ctrl->qmenu[i] == NULL || ctrl->qmenu[i][0] == '\0')
return -EINVAL; return -EINVAL;
strlcpy(qm->name, ctrl->qmenu[i], sizeof(qm->name)); strlcpy(qm->name, ctrl->qmenu[i], sizeof(qm->name));
} else {
qm->value = ctrl->qmenu_int[i];
}
return 0; return 0;
} }
EXPORT_SYMBOL(v4l2_querymenu); EXPORT_SYMBOL(v4l2_querymenu);
......
...@@ -1151,6 +1151,7 @@ enum v4l2_ctrl_type { ...@@ -1151,6 +1151,7 @@ enum v4l2_ctrl_type {
V4L2_CTRL_TYPE_CTRL_CLASS = 6, V4L2_CTRL_TYPE_CTRL_CLASS = 6,
V4L2_CTRL_TYPE_STRING = 7, V4L2_CTRL_TYPE_STRING = 7,
V4L2_CTRL_TYPE_BITMASK = 8, V4L2_CTRL_TYPE_BITMASK = 8,
V4L2_CTRL_TYPE_INTEGER_MENU = 9,
}; };
/* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */ /* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
...@@ -1170,7 +1171,10 @@ struct v4l2_queryctrl { ...@@ -1170,7 +1171,10 @@ struct v4l2_queryctrl {
struct v4l2_querymenu { struct v4l2_querymenu {
__u32 id; __u32 id;
__u32 index; __u32 index;
union {
__u8 name[32]; /* Whatever */ __u8 name[32]; /* Whatever */
__s64 value;
};
__u32 reserved; __u32 reserved;
}; };
......
...@@ -130,7 +130,10 @@ struct v4l2_ctrl { ...@@ -130,7 +130,10 @@ struct v4l2_ctrl {
u32 step; u32 step;
u32 menu_skip_mask; u32 menu_skip_mask;
}; };
union {
const char * const *qmenu; const char * const *qmenu;
const s64 *qmenu_int;
};
unsigned long flags; unsigned long flags;
union { union {
s32 val; s32 val;
...@@ -220,6 +223,7 @@ struct v4l2_ctrl_config { ...@@ -220,6 +223,7 @@ struct v4l2_ctrl_config {
u32 flags; u32 flags;
u32 menu_skip_mask; u32 menu_skip_mask;
const char * const *qmenu; const char * const *qmenu;
const s64 *qmenu_int;
unsigned int is_private:1; unsigned int is_private:1;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment