Commit 03d5285b authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab

[media] v4l2-ctrls: Add v4l2_ctrl_[gs]_ctrl_int64()

These helper functions get and set a 64-bit control's value from within
a driver. They are similar to v4l2_ctrl_[gs]_ctrl() but operate on
64-bit integer controls instead of 32-bit controls.
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Acked-by: default avatarSakari Ailus <sakari.ailus@iki.fi>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 117a55b6
...@@ -1213,76 +1213,53 @@ static int cluster_changed(struct v4l2_ctrl *master) ...@@ -1213,76 +1213,53 @@ static int cluster_changed(struct v4l2_ctrl *master)
return diff; return diff;
} }
/* Validate integer-type control */ /* Validate a new control */
static int validate_new_int(const struct v4l2_ctrl *ctrl, s32 *pval) static int validate_new(const struct v4l2_ctrl *ctrl,
struct v4l2_ext_control *c)
{ {
s32 val = *pval; size_t len;
u32 offset; u32 offset;
s32 val;
switch (ctrl->type) { switch (ctrl->type) {
case V4L2_CTRL_TYPE_INTEGER: case V4L2_CTRL_TYPE_INTEGER:
/* Round towards the closest legal value */ /* Round towards the closest legal value */
val += ctrl->step / 2; val = c->value + ctrl->step / 2;
if (val < ctrl->minimum) val = clamp(val, ctrl->minimum, ctrl->maximum);
val = ctrl->minimum;
if (val > ctrl->maximum)
val = ctrl->maximum;
offset = val - ctrl->minimum; offset = val - ctrl->minimum;
offset = ctrl->step * (offset / ctrl->step); offset = ctrl->step * (offset / ctrl->step);
val = ctrl->minimum + offset; c->value = ctrl->minimum + offset;
*pval = val;
return 0; return 0;
case V4L2_CTRL_TYPE_BOOLEAN: case V4L2_CTRL_TYPE_BOOLEAN:
*pval = !!val; c->value = !!c->value;
return 0; return 0;
case V4L2_CTRL_TYPE_MENU: case V4L2_CTRL_TYPE_MENU:
case V4L2_CTRL_TYPE_INTEGER_MENU: case V4L2_CTRL_TYPE_INTEGER_MENU:
if (val < ctrl->minimum || val > ctrl->maximum) if (c->value < ctrl->minimum || c->value > ctrl->maximum)
return -ERANGE; return -ERANGE;
if (ctrl->menu_skip_mask & (1 << val)) if (ctrl->menu_skip_mask & (1 << c->value))
return -EINVAL; return -EINVAL;
if (ctrl->type == V4L2_CTRL_TYPE_MENU && if (ctrl->type == V4L2_CTRL_TYPE_MENU &&
ctrl->qmenu[val][0] == '\0') ctrl->qmenu[c->value][0] == '\0')
return -EINVAL; return -EINVAL;
return 0; return 0;
case V4L2_CTRL_TYPE_BITMASK: case V4L2_CTRL_TYPE_BITMASK:
*pval &= ctrl->maximum; c->value &= ctrl->maximum;
return 0; return 0;
case V4L2_CTRL_TYPE_BUTTON: case V4L2_CTRL_TYPE_BUTTON:
case V4L2_CTRL_TYPE_CTRL_CLASS: case V4L2_CTRL_TYPE_CTRL_CLASS:
*pval = 0; c->value = 0;
return 0; return 0;
default:
return -EINVAL;
}
}
/* Validate a new control */
static int validate_new(const struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c)
{
char *s = c->string;
size_t len;
switch (ctrl->type) {
case V4L2_CTRL_TYPE_INTEGER:
case V4L2_CTRL_TYPE_BOOLEAN:
case V4L2_CTRL_TYPE_MENU:
case V4L2_CTRL_TYPE_INTEGER_MENU:
case V4L2_CTRL_TYPE_BITMASK:
case V4L2_CTRL_TYPE_BUTTON:
case V4L2_CTRL_TYPE_CTRL_CLASS:
return validate_new_int(ctrl, &c->value);
case V4L2_CTRL_TYPE_INTEGER64: case V4L2_CTRL_TYPE_INTEGER64:
return 0; return 0;
case V4L2_CTRL_TYPE_STRING: case V4L2_CTRL_TYPE_STRING:
len = strlen(s); len = strlen(c->string);
if (len < ctrl->minimum) if (len < ctrl->minimum)
return -ERANGE; return -ERANGE;
if ((len - ctrl->minimum) % ctrl->step) if ((len - ctrl->minimum) % ctrl->step)
...@@ -2274,12 +2251,19 @@ int v4l2_subdev_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs ...@@ -2274,12 +2251,19 @@ int v4l2_subdev_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs
EXPORT_SYMBOL(v4l2_subdev_g_ext_ctrls); EXPORT_SYMBOL(v4l2_subdev_g_ext_ctrls);
/* Helper function to get a single control */ /* Helper function to get a single control */
static int get_ctrl(struct v4l2_ctrl *ctrl, s32 *val) static int get_ctrl(struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c)
{ {
struct v4l2_ctrl *master = ctrl->cluster[0]; struct v4l2_ctrl *master = ctrl->cluster[0];
int ret = 0; int ret = 0;
int i; int i;
/* String controls are not supported. The new_to_user() and
* cur_to_user() calls below would need to be modified not to access
* userspace memory when called from get_ctrl().
*/
if (ctrl->type == V4L2_CTRL_TYPE_STRING)
return -EINVAL;
if (ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY) if (ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
return -EACCES; return -EACCES;
...@@ -2289,9 +2273,9 @@ static int get_ctrl(struct v4l2_ctrl *ctrl, s32 *val) ...@@ -2289,9 +2273,9 @@ static int get_ctrl(struct v4l2_ctrl *ctrl, s32 *val)
for (i = 0; i < master->ncontrols; i++) for (i = 0; i < master->ncontrols; i++)
cur_to_new(master->cluster[i]); cur_to_new(master->cluster[i]);
ret = call_op(master, g_volatile_ctrl); ret = call_op(master, g_volatile_ctrl);
*val = ctrl->val; new_to_user(c, ctrl);
} else { } else {
*val = ctrl->cur.val; cur_to_user(c, ctrl);
} }
v4l2_ctrl_unlock(master); v4l2_ctrl_unlock(master);
return ret; return ret;
...@@ -2300,10 +2284,14 @@ static int get_ctrl(struct v4l2_ctrl *ctrl, s32 *val) ...@@ -2300,10 +2284,14 @@ static int get_ctrl(struct v4l2_ctrl *ctrl, s32 *val)
int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control) int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control)
{ {
struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id); struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id);
struct v4l2_ext_control c;
int ret;
if (ctrl == NULL || !type_is_int(ctrl)) if (ctrl == NULL || !type_is_int(ctrl))
return -EINVAL; return -EINVAL;
return get_ctrl(ctrl, &control->value); ret = get_ctrl(ctrl, &c);
control->value = c.value;
return ret;
} }
EXPORT_SYMBOL(v4l2_g_ctrl); EXPORT_SYMBOL(v4l2_g_ctrl);
...@@ -2315,15 +2303,28 @@ EXPORT_SYMBOL(v4l2_subdev_g_ctrl); ...@@ -2315,15 +2303,28 @@ EXPORT_SYMBOL(v4l2_subdev_g_ctrl);
s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl) s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl)
{ {
s32 val = 0; struct v4l2_ext_control c;
/* It's a driver bug if this happens. */ /* It's a driver bug if this happens. */
WARN_ON(!type_is_int(ctrl)); WARN_ON(!type_is_int(ctrl));
get_ctrl(ctrl, &val); c.value = 0;
return val; get_ctrl(ctrl, &c);
return c.value;
} }
EXPORT_SYMBOL(v4l2_ctrl_g_ctrl); EXPORT_SYMBOL(v4l2_ctrl_g_ctrl);
s64 v4l2_ctrl_g_ctrl_int64(struct v4l2_ctrl *ctrl)
{
struct v4l2_ext_control c;
/* It's a driver bug if this happens. */
WARN_ON(ctrl->type != V4L2_CTRL_TYPE_INTEGER64);
c.value = 0;
get_ctrl(ctrl, &c);
return c.value;
}
EXPORT_SYMBOL(v4l2_ctrl_g_ctrl_int64);
/* Core function that calls try/s_ctrl and ensures that the new value is /* Core function that calls try/s_ctrl and ensures that the new value is
copied to the current value on a set. copied to the current value on a set.
...@@ -2539,13 +2540,21 @@ int v4l2_subdev_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs ...@@ -2539,13 +2540,21 @@ int v4l2_subdev_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs
EXPORT_SYMBOL(v4l2_subdev_s_ext_ctrls); EXPORT_SYMBOL(v4l2_subdev_s_ext_ctrls);
/* Helper function for VIDIOC_S_CTRL compatibility */ /* Helper function for VIDIOC_S_CTRL compatibility */
static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, s32 *val) static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
struct v4l2_ext_control *c)
{ {
struct v4l2_ctrl *master = ctrl->cluster[0]; struct v4l2_ctrl *master = ctrl->cluster[0];
int ret; int ret;
int i; int i;
ret = validate_new_int(ctrl, val); /* String controls are not supported. The user_to_new() and
* cur_to_user() calls below would need to be modified not to access
* userspace memory when called from set_ctrl().
*/
if (ctrl->type == V4L2_CTRL_TYPE_STRING)
return -EINVAL;
ret = validate_new(ctrl, c);
if (ret) if (ret)
return ret; return ret;
...@@ -2560,12 +2569,13 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, s32 *val) ...@@ -2560,12 +2569,13 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, s32 *val)
manual mode we have to update the current volatile values since manual mode we have to update the current volatile values since
those will become the initial manual values after such a switch. */ those will become the initial manual values after such a switch. */
if (master->is_auto && master->has_volatiles && ctrl == master && if (master->is_auto && master->has_volatiles && ctrl == master &&
!is_cur_manual(master) && *val == master->manual_mode_value) !is_cur_manual(master) && c->value == master->manual_mode_value)
update_from_auto_cluster(master); update_from_auto_cluster(master);
ctrl->val = *val;
ctrl->is_new = 1; user_to_new(c, ctrl);
ret = try_or_set_cluster(fh, master, true); ret = try_or_set_cluster(fh, master, true);
*val = ctrl->cur.val; cur_to_user(c, ctrl);
v4l2_ctrl_unlock(ctrl); v4l2_ctrl_unlock(ctrl);
return ret; return ret;
} }
...@@ -2574,6 +2584,8 @@ int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, ...@@ -2574,6 +2584,8 @@ int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
struct v4l2_control *control) struct v4l2_control *control)
{ {
struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id); struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id);
struct v4l2_ext_control c;
int ret;
if (ctrl == NULL || !type_is_int(ctrl)) if (ctrl == NULL || !type_is_int(ctrl))
return -EINVAL; return -EINVAL;
...@@ -2581,7 +2593,10 @@ int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, ...@@ -2581,7 +2593,10 @@ int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
return -EACCES; return -EACCES;
return set_ctrl(fh, ctrl, &control->value); c.value = control->value;
ret = set_ctrl(fh, ctrl, &c);
control->value = c.value;
return ret;
} }
EXPORT_SYMBOL(v4l2_s_ctrl); EXPORT_SYMBOL(v4l2_s_ctrl);
...@@ -2593,12 +2608,26 @@ EXPORT_SYMBOL(v4l2_subdev_s_ctrl); ...@@ -2593,12 +2608,26 @@ EXPORT_SYMBOL(v4l2_subdev_s_ctrl);
int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val) int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)
{ {
struct v4l2_ext_control c;
/* It's a driver bug if this happens. */ /* It's a driver bug if this happens. */
WARN_ON(!type_is_int(ctrl)); WARN_ON(!type_is_int(ctrl));
return set_ctrl(NULL, ctrl, &val); c.value = val;
return set_ctrl(NULL, ctrl, &c);
} }
EXPORT_SYMBOL(v4l2_ctrl_s_ctrl); EXPORT_SYMBOL(v4l2_ctrl_s_ctrl);
int v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val)
{
struct v4l2_ext_control c;
/* It's a driver bug if this happens. */
WARN_ON(ctrl->type != V4L2_CTRL_TYPE_INTEGER64);
c.value64 = val;
return set_ctrl(NULL, ctrl, &c);
}
EXPORT_SYMBOL(v4l2_ctrl_s_ctrl_int64);
static int v4l2_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems) static int v4l2_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems)
{ {
struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id); struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id);
......
...@@ -511,6 +511,29 @@ s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl); ...@@ -511,6 +511,29 @@ s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl);
*/ */
int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val); int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val);
/** v4l2_ctrl_g_ctrl_int64() - Helper function to get a 64-bit control's value from within a driver.
* @ctrl: The control.
*
* This returns the control's value safely by going through the control
* framework. This function will lock the control's handler, so it cannot be
* used from within the &v4l2_ctrl_ops functions.
*
* This function is for 64-bit integer type controls only.
*/
s64 v4l2_ctrl_g_ctrl_int64(struct v4l2_ctrl *ctrl);
/** v4l2_ctrl_s_ctrl_int64() - Helper function to set a 64-bit control's value from within a driver.
* @ctrl: The control.
* @val: The new value.
*
* This set the control's new value safely by going through the control
* framework. This function will lock the control's handler, so it cannot be
* used from within the &v4l2_ctrl_ops functions.
*
* This function is for 64-bit integer type controls only.
*/
int v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val);
/* Internal helper functions that deal with control events. */ /* Internal helper functions that deal with control events. */
extern const struct v4l2_subscribed_event_ops v4l2_ctrl_sub_ev_ops; extern const struct v4l2_subscribed_event_ops v4l2_ctrl_sub_ev_ops;
void v4l2_ctrl_replace(struct v4l2_event *old, const struct v4l2_event *new); void v4l2_ctrl_replace(struct v4l2_event *old, const struct v4l2_event *new);
......
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