aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/v4l2-ctrls.c
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2011-06-10 04:44:36 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-07-27 16:53:18 -0400
commit72d877cac07c8d996918977c3162dd78b8097ca8 (patch)
tree03b03db2d5c44c6cca946cb7f24d61a1c15cce24 /drivers/media/video/v4l2-ctrls.c
parent78866efe8ae2862fef7ff37af36c6972651c2d0b (diff)
[media] v4l2-ctrls: add v4l2_ctrl_auto_cluster to simplify autogain/gain scenarios
It is a bit tricky to handle autogain/gain type scenerios correctly. Such controls need to be clustered and the V4L2_CTRL_FLAG_UPDATE should be set on the autofoo controls. In addition, the manual controls should be marked inactive when the automatic mode is on, and active when the manual mode is on. This also requires specialized volatile handling. The chances of drivers doing all these things correctly are pretty remote. So a new v4l2_ctrl_auto_cluster function was added that takes care of these issues. 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.c69
1 files changed, 57 insertions, 12 deletions
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 98b1b8d55cd4..30b0b4609b36 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -39,6 +39,20 @@ struct ctrl_helper {
39 bool handled; 39 bool handled;
40}; 40};
41 41
42/* Small helper function to determine if the autocluster is set to manual
43 mode. In that case the is_volatile flag should be ignored. */
44static bool is_cur_manual(const struct v4l2_ctrl *master)
45{
46 return master->is_auto && master->cur.val == master->manual_mode_value;
47}
48
49/* Same as above, but this checks the against the new value instead of the
50 current value. */
51static bool is_new_manual(const struct v4l2_ctrl *master)
52{
53 return master->is_auto && master->val == master->manual_mode_value;
54}
55
42/* Returns NULL or a character pointer array containing the menu for 56/* Returns NULL or a character pointer array containing the menu for
43 the given control ID. The pointer array ends with a NULL pointer. 57 the given control ID. The pointer array ends with a NULL pointer.
44 An empty string signifies a menu entry that is invalid. This allows 58 An empty string signifies a menu entry that is invalid. This allows
@@ -643,7 +657,7 @@ static int ctrl_is_volatile(struct v4l2_ext_control *c,
643} 657}
644 658
645/* Copy the new value to the current value. */ 659/* Copy the new value to the current value. */
646static void new_to_cur(struct v4l2_ctrl *ctrl) 660static void new_to_cur(struct v4l2_ctrl *ctrl, bool update_inactive)
647{ 661{
648 if (ctrl == NULL) 662 if (ctrl == NULL)
649 return; 663 return;
@@ -659,6 +673,11 @@ static void new_to_cur(struct v4l2_ctrl *ctrl)
659 ctrl->cur.val = ctrl->val; 673 ctrl->cur.val = ctrl->val;
660 break; 674 break;
661 } 675 }
676 if (update_inactive) {
677 ctrl->flags &= ~V4L2_CTRL_FLAG_INACTIVE;
678 if (!is_cur_manual(ctrl->cluster[0]))
679 ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
680 }
662} 681}
663 682
664/* Copy the current value to the new value */ 683/* Copy the current value to the new value */
@@ -1166,7 +1185,7 @@ void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls)
1166 int i; 1185 int i;
1167 1186
1168 /* The first control is the master control and it must not be NULL */ 1187 /* The first control is the master control and it must not be NULL */
1169 BUG_ON(controls[0] == NULL); 1188 BUG_ON(ncontrols == 0 || controls[0] == NULL);
1170 1189
1171 for (i = 0; i < ncontrols; i++) { 1190 for (i = 0; i < ncontrols; i++) {
1172 if (controls[i]) { 1191 if (controls[i]) {
@@ -1177,6 +1196,28 @@ void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls)
1177} 1196}
1178EXPORT_SYMBOL(v4l2_ctrl_cluster); 1197EXPORT_SYMBOL(v4l2_ctrl_cluster);
1179 1198
1199void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls,
1200 u8 manual_val, bool set_volatile)
1201{
1202 struct v4l2_ctrl *master = controls[0];
1203 u32 flag;
1204 int i;
1205
1206 v4l2_ctrl_cluster(ncontrols, controls);
1207 WARN_ON(ncontrols <= 1);
1208 master->is_auto = true;
1209 master->manual_mode_value = manual_val;
1210 master->flags |= V4L2_CTRL_FLAG_UPDATE;
1211 flag = is_cur_manual(master) ? 0 : V4L2_CTRL_FLAG_INACTIVE;
1212
1213 for (i = 1; i < ncontrols; i++)
1214 if (controls[i]) {
1215 controls[i]->is_volatile = set_volatile;
1216 controls[i]->flags |= flag;
1217 }
1218}
1219EXPORT_SYMBOL(v4l2_ctrl_auto_cluster);
1220
1180/* Activate/deactivate a control. */ 1221/* Activate/deactivate a control. */
1181void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active) 1222void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active)
1182{ 1223{
@@ -1595,7 +1636,7 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
1595 v4l2_ctrl_lock(master); 1636 v4l2_ctrl_lock(master);
1596 1637
1597 /* g_volatile_ctrl will update the new control values */ 1638 /* g_volatile_ctrl will update the new control values */
1598 if (has_volatiles) { 1639 if (has_volatiles && !is_cur_manual(master)) {
1599 for (j = 0; j < master->ncontrols; j++) 1640 for (j = 0; j < master->ncontrols; j++)
1600 cur_to_new(master->cluster[j]); 1641 cur_to_new(master->cluster[j]);
1601 ret = call_op(master, g_volatile_ctrl); 1642 ret = call_op(master, g_volatile_ctrl);
@@ -1633,7 +1674,7 @@ static int get_ctrl(struct v4l2_ctrl *ctrl, s32 *val)
1633 1674
1634 v4l2_ctrl_lock(master); 1675 v4l2_ctrl_lock(master);
1635 /* g_volatile_ctrl will update the current control values */ 1676 /* g_volatile_ctrl will update the current control values */
1636 if (ctrl->is_volatile) { 1677 if (ctrl->is_volatile && !is_cur_manual(master)) {
1637 for (i = 0; i < master->ncontrols; i++) 1678 for (i = 0; i < master->ncontrols; i++)
1638 cur_to_new(master->cluster[i]); 1679 cur_to_new(master->cluster[i]);
1639 ret = call_op(master, g_volatile_ctrl); 1680 ret = call_op(master, g_volatile_ctrl);
@@ -1678,6 +1719,7 @@ EXPORT_SYMBOL(v4l2_ctrl_g_ctrl);
1678 Must be called with ctrl->handler->lock held. */ 1719 Must be called with ctrl->handler->lock held. */
1679static int try_or_set_control_cluster(struct v4l2_ctrl *master, bool set) 1720static int try_or_set_control_cluster(struct v4l2_ctrl *master, bool set)
1680{ 1721{
1722 bool update_flag;
1681 bool try = !set; 1723 bool try = !set;
1682 int ret = 0; 1724 int ret = 0;
1683 int i; 1725 int i;
@@ -1717,14 +1759,17 @@ static int try_or_set_control_cluster(struct v4l2_ctrl *master, bool set)
1717 ret = call_op(master, try_ctrl); 1759 ret = call_op(master, try_ctrl);
1718 1760
1719 /* Don't set if there is no change */ 1761 /* Don't set if there is no change */
1720 if (!ret && set && cluster_changed(master)) { 1762 if (ret || !set || !cluster_changed(master))
1721 ret = call_op(master, s_ctrl); 1763 return ret;
1722 /* If OK, then make the new values permanent. */ 1764 ret = call_op(master, s_ctrl);
1723 if (!ret) 1765 /* If OK, then make the new values permanent. */
1724 for (i = 0; i < master->ncontrols; i++) 1766 if (ret)
1725 new_to_cur(master->cluster[i]); 1767 return ret;
1726 } 1768
1727 return ret; 1769 update_flag = is_cur_manual(master) != is_new_manual(master);
1770 for (i = 0; i < master->ncontrols; i++)
1771 new_to_cur(master->cluster[i], update_flag && i > 0);
1772 return 0;
1728} 1773}
1729 1774
1730/* Try or set controls. */ 1775/* Try or set controls. */