diff options
-rw-r--r-- | drivers/media/video/v4l2-ctrls.c | 69 | ||||
-rw-r--r-- | include/media/v4l2-ctrls.h | 45 |
2 files changed, 102 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. */ | ||
44 | static 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. */ | ||
51 | static 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. */ |
646 | static void new_to_cur(struct v4l2_ctrl *ctrl) | 660 | static 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 | } |
1178 | EXPORT_SYMBOL(v4l2_ctrl_cluster); | 1197 | EXPORT_SYMBOL(v4l2_ctrl_cluster); |
1179 | 1198 | ||
1199 | void 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 | } | ||
1219 | EXPORT_SYMBOL(v4l2_ctrl_auto_cluster); | ||
1220 | |||
1180 | /* Activate/deactivate a control. */ | 1221 | /* Activate/deactivate a control. */ |
1181 | void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active) | 1222 | void 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. */ |
1679 | static int try_or_set_control_cluster(struct v4l2_ctrl *master, bool set) | 1720 | static 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. */ |
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 97d063837b61..56323e341e02 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h | |||
@@ -65,6 +65,15 @@ struct v4l2_ctrl_ops { | |||
65 | * control's current value cannot be cached and needs to be | 65 | * control's current value cannot be cached and needs to be |
66 | * retrieved through the g_volatile_ctrl op. Drivers can set | 66 | * retrieved through the g_volatile_ctrl op. Drivers can set |
67 | * this flag. | 67 | * this flag. |
68 | * @is_auto: If set, then this control selects whether the other cluster | ||
69 | * members are in 'automatic' mode or 'manual' mode. This is | ||
70 | * used for autogain/gain type clusters. Drivers should never | ||
71 | * set this flag directly. | ||
72 | * @manual_mode_value: If the is_auto flag is set, then this is the value | ||
73 | * of the auto control that determines if that control is in | ||
74 | * manual mode. So if the value of the auto control equals this | ||
75 | * value, then the whole cluster is in manual mode. Drivers should | ||
76 | * never set this flag directly. | ||
68 | * @ops: The control ops. | 77 | * @ops: The control ops. |
69 | * @id: The control ID. | 78 | * @id: The control ID. |
70 | * @name: The control name. | 79 | * @name: The control name. |
@@ -105,6 +114,8 @@ struct v4l2_ctrl { | |||
105 | unsigned int is_new:1; | 114 | unsigned int is_new:1; |
106 | unsigned int is_private:1; | 115 | unsigned int is_private:1; |
107 | unsigned int is_volatile:1; | 116 | unsigned int is_volatile:1; |
117 | unsigned int is_auto:1; | ||
118 | unsigned int manual_mode_value:5; | ||
108 | 119 | ||
109 | const struct v4l2_ctrl_ops *ops; | 120 | const struct v4l2_ctrl_ops *ops; |
110 | u32 id; | 121 | u32 id; |
@@ -363,6 +374,40 @@ int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl, | |||
363 | void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls); | 374 | void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls); |
364 | 375 | ||
365 | 376 | ||
377 | /** v4l2_ctrl_auto_cluster() - Mark all controls in the cluster as belonging to | ||
378 | * that cluster and set it up for autofoo/foo-type handling. | ||
379 | * @ncontrols: The number of controls in this cluster. | ||
380 | * @controls: The cluster control array of size @ncontrols. The first control | ||
381 | * must be the 'auto' control (e.g. autogain, autoexposure, etc.) | ||
382 | * @manual_val: The value for the first control in the cluster that equals the | ||
383 | * manual setting. | ||
384 | * @set_volatile: If true, then all controls except the first auto control will | ||
385 | * have is_volatile set to true. If false, then is_volatile will not | ||
386 | * be touched. | ||
387 | * | ||
388 | * Use for control groups where one control selects some automatic feature and | ||
389 | * the other controls are only active whenever the automatic feature is turned | ||
390 | * off (manual mode). Typical examples: autogain vs gain, auto-whitebalance vs | ||
391 | * red and blue balance, etc. | ||
392 | * | ||
393 | * The behavior of such controls is as follows: | ||
394 | * | ||
395 | * When the autofoo control is set to automatic, then any manual controls | ||
396 | * are set to inactive and any reads will call g_volatile_ctrl (if the control | ||
397 | * was marked volatile). | ||
398 | * | ||
399 | * When the autofoo control is set to manual, then any manual controls will | ||
400 | * be marked active, and any reads will just return the current value without | ||
401 | * going through g_volatile_ctrl. | ||
402 | * | ||
403 | * In addition, this function will set the V4L2_CTRL_FLAG_UPDATE flag | ||
404 | * on the autofoo control and V4L2_CTRL_FLAG_INACTIVE on the foo control(s) | ||
405 | * if autofoo is in auto mode. | ||
406 | */ | ||
407 | void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls, | ||
408 | u8 manual_val, bool set_volatile); | ||
409 | |||
410 | |||
366 | /** v4l2_ctrl_find() - Find a control with the given ID. | 411 | /** v4l2_ctrl_find() - Find a control with the given ID. |
367 | * @hdl: The control handler. | 412 | * @hdl: The control handler. |
368 | * @id: The control ID to find. | 413 | * @id: The control ID to find. |