aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/v4l2-ctrls.c
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2011-06-10 04:43:34 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-07-27 16:53:17 -0400
commitddac5c107942d9584a9f55701aad405b57618726 (patch)
treebb658b1179f6c763730157d0b4c10d0d287fe410 /drivers/media/video/v4l2-ctrls.c
parent18d171badf47a436045589668f785b7d278f4e4d (diff)
[media] v4l2-ctrls: fix and improve volatile control handling
If you have a cluster of controls that is a mix of volatile and non-volatile controls, then requesting the value of the volatile control would fail if the master control of that cluster was non-volatile. The code assumed that the volatile state of the master control was the same for all other controls in the cluster. This is now fixed. In addition, it was clear from bugs in some drivers that it was confusing that the ctrl->cur union had to be used in g_volatile_ctrl. Several drivers used the 'new' values instead. The framework was changed so that drivers now set the new value instead of the current value. This has an additional benefit as well: the volatile values are now only stored in the 'new' value, leaving the current value alone. This is useful for autofoo/foo control clusters where you want to have a 'foo' control act like a volatile control if 'autofoo' is on, but as a normal control when it is off. Since with this change the cur value is no longer overwritten when g_volatile_ctrl is called, you can use it to remember the original 'foo' value. For example: autofoo = 0, foo = 10 and foo is non-volatile. Now autofoo is set to 1 and foo is marked volatile. Retrieving the foo value will get the volatile value. Set autofoo back to 0, which marks foo as non- volatile again, and retrieving foo will get the old current value of 10. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/v4l2-ctrls.c')
-rw-r--r--drivers/media/video/v4l2-ctrls.c52
1 files changed, 44 insertions, 8 deletions
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 0b1b30fded60..98b1b8d55cd4 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -25,8 +25,10 @@
25#include <media/v4l2-ctrls.h> 25#include <media/v4l2-ctrls.h>
26#include <media/v4l2-dev.h> 26#include <media/v4l2-dev.h>
27 27
28#define has_op(master, op) \
29 (master->ops && master->ops->op)
28#define call_op(master, op) \ 30#define call_op(master, op) \
29 ((master->ops && master->ops->op) ? master->ops->op(master) : 0) 31 (has_op(master, op) ? master->ops->op(master) : 0)
30 32
31/* Internal temporary helper struct, one for each v4l2_ext_control */ 33/* Internal temporary helper struct, one for each v4l2_ext_control */
32struct ctrl_helper { 34struct ctrl_helper {
@@ -626,6 +628,20 @@ static int new_to_user(struct v4l2_ext_control *c,
626 return 0; 628 return 0;
627} 629}
628 630
631static int ctrl_to_user(struct v4l2_ext_control *c,
632 struct v4l2_ctrl *ctrl)
633{
634 if (ctrl->is_volatile)
635 return new_to_user(c, ctrl);
636 return cur_to_user(c, ctrl);
637}
638
639static int ctrl_is_volatile(struct v4l2_ext_control *c,
640 struct v4l2_ctrl *ctrl)
641{
642 return ctrl->is_volatile;
643}
644
629/* Copy the new value to the current value. */ 645/* Copy the new value to the current value. */
630static void new_to_cur(struct v4l2_ctrl *ctrl) 646static void new_to_cur(struct v4l2_ctrl *ctrl)
631{ 647{
@@ -1535,7 +1551,7 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
1535 struct ctrl_helper helper[4]; 1551 struct ctrl_helper helper[4];
1536 struct ctrl_helper *helpers = helper; 1552 struct ctrl_helper *helpers = helper;
1537 int ret; 1553 int ret;
1538 int i; 1554 int i, j;
1539 1555
1540 cs->error_idx = cs->count; 1556 cs->error_idx = cs->count;
1541 cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class); 1557 cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
@@ -1562,19 +1578,33 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
1562 for (i = 0; !ret && i < cs->count; i++) { 1578 for (i = 0; !ret && i < cs->count; i++) {
1563 struct v4l2_ctrl *ctrl = helpers[i].ctrl; 1579 struct v4l2_ctrl *ctrl = helpers[i].ctrl;
1564 struct v4l2_ctrl *master = ctrl->cluster[0]; 1580 struct v4l2_ctrl *master = ctrl->cluster[0];
1581 bool has_volatiles;
1565 1582
1566 if (helpers[i].handled) 1583 if (helpers[i].handled)
1567 continue; 1584 continue;
1568 1585
1569 cs->error_idx = i; 1586 cs->error_idx = i;
1570 1587
1588 /* Any volatile controls requested from this cluster? */
1589 has_volatiles = ctrl->is_volatile;
1590 if (!has_volatiles && has_op(master, g_volatile_ctrl) &&
1591 master->ncontrols > 1)
1592 has_volatiles = cluster_walk(i, cs, helpers,
1593 ctrl_is_volatile);
1594
1571 v4l2_ctrl_lock(master); 1595 v4l2_ctrl_lock(master);
1572 /* g_volatile_ctrl will update the current control values */ 1596
1573 if (ctrl->is_volatile) 1597 /* g_volatile_ctrl will update the new control values */
1598 if (has_volatiles) {
1599 for (j = 0; j < master->ncontrols; j++)
1600 cur_to_new(master->cluster[j]);
1574 ret = call_op(master, g_volatile_ctrl); 1601 ret = call_op(master, g_volatile_ctrl);
1575 /* If OK, then copy the current control values to the caller */ 1602 }
1603 /* If OK, then copy the current (for non-volatile controls)
1604 or the new (for volatile controls) control values to the
1605 caller */
1576 if (!ret) 1606 if (!ret)
1577 ret = cluster_walk(i, cs, helpers, cur_to_user); 1607 ret = cluster_walk(i, cs, helpers, ctrl_to_user);
1578 v4l2_ctrl_unlock(master); 1608 v4l2_ctrl_unlock(master);
1579 cluster_done(i, cs, helpers); 1609 cluster_done(i, cs, helpers);
1580 } 1610 }
@@ -1596,15 +1626,21 @@ static int get_ctrl(struct v4l2_ctrl *ctrl, s32 *val)
1596{ 1626{
1597 struct v4l2_ctrl *master = ctrl->cluster[0]; 1627 struct v4l2_ctrl *master = ctrl->cluster[0];
1598 int ret = 0; 1628 int ret = 0;
1629 int i;
1599 1630
1600 if (ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY) 1631 if (ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
1601 return -EACCES; 1632 return -EACCES;
1602 1633
1603 v4l2_ctrl_lock(master); 1634 v4l2_ctrl_lock(master);
1604 /* g_volatile_ctrl will update the current control values */ 1635 /* g_volatile_ctrl will update the current control values */
1605 if (ctrl->is_volatile) 1636 if (ctrl->is_volatile) {
1637 for (i = 0; i < master->ncontrols; i++)
1638 cur_to_new(master->cluster[i]);
1606 ret = call_op(master, g_volatile_ctrl); 1639 ret = call_op(master, g_volatile_ctrl);
1607 *val = ctrl->cur.val; 1640 *val = ctrl->val;
1641 } else {
1642 *val = ctrl->cur.val;
1643 }
1608 v4l2_ctrl_unlock(master); 1644 v4l2_ctrl_unlock(master);
1609 return ret; 1645 return ret;
1610} 1646}