aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSylwester Nawrocki <sylvester.nawrocki@gmail.com>2013-01-19 13:51:55 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-02-05 12:04:06 -0500
commit2ccbe779bcdee130ea7f1525670dc9d60318a981 (patch)
treef667acca6ab42a0565b062616b3a6f176508e874
parentaf9bb33aa33d4beb5d0ac505d48530a56856f66c (diff)
[media] v4l2-ctrl: Add helper function for the controls range update
This patch adds a helper function that allows to modify range, i.e. minimum, maximum, step and default value of a v4l2 control, after the control has been created and initialized. This is helpful in situations when range of a control depends on user configurable parameters, e.g. camera sensor absolute exposure time depending on an output image resolution and frame rate. v4l2_ctrl_modify_range() function allows to modify range of an INTEGER, BOOL, MENU, INTEGER_MENU and BITMASK type controls. Based on a patch from Hans Verkuil http://patchwork.linuxtv.org/patch/8654. Signed-off-by: Sylwester Nawrocki <sylvester.nawrocki@gmail.com> Acked-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--Documentation/DocBook/media/v4l/compat.xml4
-rw-r--r--Documentation/DocBook/media/v4l/v4l2.xml4
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-dqevent.xml6
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c143
-rw-r--r--include/media/v4l2-ctrls.h20
-rw-r--r--include/uapi/linux/videodev2.h1
6 files changed, 138 insertions, 40 deletions
diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml
index ebd2bfd1ee8e..104a1a2b8849 100644
--- a/Documentation/DocBook/media/v4l/compat.xml
+++ b/Documentation/DocBook/media/v4l/compat.xml
@@ -2486,6 +2486,10 @@ that used it. It was originally scheduled for removal in 2.6.35.
2486 <structname>v4l2_buffer</structname>. See <xref 2486 <structname>v4l2_buffer</structname>. See <xref
2487 linkend="buffer-flags" />.</para> 2487 linkend="buffer-flags" />.</para>
2488 </listitem> 2488 </listitem>
2489 <listitem>
2490 <para>Added <constant>V4L2_EVENT_CTRL_CH_RANGE</constant> control event
2491 changes flag. See <xref linkend="changes-flags"/>.</para>
2492 </listitem>
2489 </orderedlist> 2493 </orderedlist>
2490 </section> 2494 </section>
2491 2495
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
index 8fe29427c8e4..c3851a2fb50d 100644
--- a/Documentation/DocBook/media/v4l/v4l2.xml
+++ b/Documentation/DocBook/media/v4l/v4l2.xml
@@ -142,10 +142,12 @@ applications. -->
142 <revision> 142 <revision>
143 <revnumber>3.9</revnumber> 143 <revnumber>3.9</revnumber>
144 <date>2012-12-03</date> 144 <date>2012-12-03</date>
145 <authorinitials>sa</authorinitials> 145 <authorinitials>sa, sn</authorinitials>
146 <revremark>Added timestamp types to 146 <revremark>Added timestamp types to
147 <structname>v4l2_buffer</structname>, see <xref 147 <structname>v4l2_buffer</structname>, see <xref
148 linkend="buffer-flags" />. 148 linkend="buffer-flags" />.
149 Added <constant>V4L2_EVENT_CTRL_CH_RANGE</constant> control
150 event changes flag, see <xref linkend="changes-flags"/>.
149 </revremark> 151 </revremark>
150 </revision> 152 </revision>
151 153
diff --git a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
index 98a856f9ec30..89891adb928a 100644
--- a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
@@ -261,6 +261,12 @@
261 <entry>This control event was triggered because the control flags 261 <entry>This control event was triggered because the control flags
262 changed.</entry> 262 changed.</entry>
263 </row> 263 </row>
264 <row>
265 <entry><constant>V4L2_EVENT_CTRL_CH_RANGE</constant></entry>
266 <entry>0x0004</entry>
267 <entry>This control event was triggered because the minimum,
268 maximum, step or the default value of the control changed.</entry>
269 </row>
264 </tbody> 270 </tbody>
265 </tgroup> 271 </tgroup>
266 </table> 272 </table>
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 7b486ac3f4d9..3f27571b814d 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1158,8 +1158,7 @@ static int new_to_user(struct v4l2_ext_control *c,
1158} 1158}
1159 1159
1160/* Copy the new value to the current value. */ 1160/* Copy the new value to the current value. */
1161static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, 1161static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
1162 bool update_inactive)
1163{ 1162{
1164 bool changed = false; 1163 bool changed = false;
1165 1164
@@ -1183,8 +1182,8 @@ static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
1183 ctrl->cur.val = ctrl->val; 1182 ctrl->cur.val = ctrl->val;
1184 break; 1183 break;
1185 } 1184 }
1186 if (update_inactive) { 1185 if (ch_flags & V4L2_EVENT_CTRL_CH_FLAGS) {
1187 /* Note: update_inactive can only be true for auto clusters. */ 1186 /* Note: CH_FLAGS is only set for auto clusters. */
1188 ctrl->flags &= 1187 ctrl->flags &=
1189 ~(V4L2_CTRL_FLAG_INACTIVE | V4L2_CTRL_FLAG_VOLATILE); 1188 ~(V4L2_CTRL_FLAG_INACTIVE | V4L2_CTRL_FLAG_VOLATILE);
1190 if (!is_cur_manual(ctrl->cluster[0])) { 1189 if (!is_cur_manual(ctrl->cluster[0])) {
@@ -1194,14 +1193,13 @@ static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
1194 } 1193 }
1195 fh = NULL; 1194 fh = NULL;
1196 } 1195 }
1197 if (changed || update_inactive) { 1196 if (changed || ch_flags) {
1198 /* If a control was changed that was not one of the controls 1197 /* If a control was changed that was not one of the controls
1199 modified by the application, then send the event to all. */ 1198 modified by the application, then send the event to all. */
1200 if (!ctrl->is_new) 1199 if (!ctrl->is_new)
1201 fh = NULL; 1200 fh = NULL;
1202 send_event(fh, ctrl, 1201 send_event(fh, ctrl,
1203 (changed ? V4L2_EVENT_CTRL_CH_VALUE : 0) | 1202 (changed ? V4L2_EVENT_CTRL_CH_VALUE : 0) | ch_flags);
1204 (update_inactive ? V4L2_EVENT_CTRL_CH_FLAGS : 0));
1205 if (ctrl->call_notify && changed && ctrl->handler->notify) 1203 if (ctrl->call_notify && changed && ctrl->handler->notify)
1206 ctrl->handler->notify(ctrl, ctrl->handler->notify_priv); 1204 ctrl->handler->notify(ctrl, ctrl->handler->notify_priv);
1207 } 1205 }
@@ -1257,6 +1255,41 @@ static int cluster_changed(struct v4l2_ctrl *master)
1257 return diff; 1255 return diff;
1258} 1256}
1259 1257
1258/* Control range checking */
1259static int check_range(enum v4l2_ctrl_type type,
1260 s32 min, s32 max, u32 step, s32 def)
1261{
1262 switch (type) {
1263 case V4L2_CTRL_TYPE_BOOLEAN:
1264 if (step != 1 || max > 1 || min < 0)
1265 return -ERANGE;
1266 /* fall through */
1267 case V4L2_CTRL_TYPE_INTEGER:
1268 if (step <= 0 || min > max || def < min || def > max)
1269 return -ERANGE;
1270 return 0;
1271 case V4L2_CTRL_TYPE_BITMASK:
1272 if (step || min || !max || (def & ~max))
1273 return -ERANGE;
1274 return 0;
1275 case V4L2_CTRL_TYPE_MENU:
1276 case V4L2_CTRL_TYPE_INTEGER_MENU:
1277 if (min > max || def < min || def > max)
1278 return -ERANGE;
1279 /* Note: step == menu_skip_mask for menu controls.
1280 So here we check if the default value is masked out. */
1281 if (step && ((1 << def) & step))
1282 return -EINVAL;
1283 return 0;
1284 case V4L2_CTRL_TYPE_STRING:
1285 if (min > max || min < 0 || step < 1 || def)
1286 return -ERANGE;
1287 return 0;
1288 default:
1289 return 0;
1290 }
1291}
1292
1260/* Validate a new control */ 1293/* Validate a new control */
1261static int validate_new(const struct v4l2_ctrl *ctrl, 1294static int validate_new(const struct v4l2_ctrl *ctrl,
1262 struct v4l2_ext_control *c) 1295 struct v4l2_ext_control *c)
@@ -1529,30 +1562,21 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
1529{ 1562{
1530 struct v4l2_ctrl *ctrl; 1563 struct v4l2_ctrl *ctrl;
1531 unsigned sz_extra = 0; 1564 unsigned sz_extra = 0;
1565 int err;
1532 1566
1533 if (hdl->error) 1567 if (hdl->error)
1534 return NULL; 1568 return NULL;
1535 1569
1536 /* Sanity checks */ 1570 /* Sanity checks */
1537 if (id == 0 || name == NULL || id >= V4L2_CID_PRIVATE_BASE || 1571 if (id == 0 || name == NULL || id >= V4L2_CID_PRIVATE_BASE ||
1538 (type == V4L2_CTRL_TYPE_INTEGER && step == 0) ||
1539 (type == V4L2_CTRL_TYPE_BITMASK && max == 0) ||
1540 (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) || 1572 (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||
1541 (type == V4L2_CTRL_TYPE_INTEGER_MENU && qmenu_int == NULL) || 1573 (type == V4L2_CTRL_TYPE_INTEGER_MENU && qmenu_int == NULL)) {
1542 (type == V4L2_CTRL_TYPE_STRING && max == 0)) {
1543 handler_set_err(hdl, -ERANGE);
1544 return NULL;
1545 }
1546 if (type != V4L2_CTRL_TYPE_BITMASK && max < min) {
1547 handler_set_err(hdl, -ERANGE); 1574 handler_set_err(hdl, -ERANGE);
1548 return NULL; 1575 return NULL;
1549 } 1576 }
1550 if ((type == V4L2_CTRL_TYPE_INTEGER || 1577 err = check_range(type, min, max, step, def);
1551 type == V4L2_CTRL_TYPE_MENU || 1578 if (err) {
1552 type == V4L2_CTRL_TYPE_INTEGER_MENU || 1579 handler_set_err(hdl, err);
1553 type == V4L2_CTRL_TYPE_BOOLEAN) &&
1554 (def < min || def > max)) {
1555 handler_set_err(hdl, -ERANGE);
1556 return NULL; 1580 return NULL;
1557 } 1581 }
1558 if (type == V4L2_CTRL_TYPE_BITMASK && ((def & ~max) || min || step)) { 1582 if (type == V4L2_CTRL_TYPE_BITMASK && ((def & ~max) || min || step)) {
@@ -2426,8 +2450,8 @@ EXPORT_SYMBOL(v4l2_ctrl_g_ctrl_int64);
2426/* Core function that calls try/s_ctrl and ensures that the new value is 2450/* Core function that calls try/s_ctrl and ensures that the new value is
2427 copied to the current value on a set. 2451 copied to the current value on a set.
2428 Must be called with ctrl->handler->lock held. */ 2452 Must be called with ctrl->handler->lock held. */
2429static int try_or_set_cluster(struct v4l2_fh *fh, 2453static int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master,
2430 struct v4l2_ctrl *master, bool set) 2454 bool set, u32 ch_flags)
2431{ 2455{
2432 bool update_flag; 2456 bool update_flag;
2433 int ret; 2457 int ret;
@@ -2465,7 +2489,8 @@ static int try_or_set_cluster(struct v4l2_fh *fh,
2465 /* If OK, then make the new values permanent. */ 2489 /* If OK, then make the new values permanent. */
2466 update_flag = is_cur_manual(master) != is_new_manual(master); 2490 update_flag = is_cur_manual(master) != is_new_manual(master);
2467 for (i = 0; i < master->ncontrols; i++) 2491 for (i = 0; i < master->ncontrols; i++)
2468 new_to_cur(fh, master->cluster[i], update_flag && i > 0); 2492 new_to_cur(fh, master->cluster[i], ch_flags |
2493 ((update_flag && i > 0) ? V4L2_EVENT_CTRL_CH_FLAGS : 0));
2469 return 0; 2494 return 0;
2470} 2495}
2471 2496
@@ -2592,7 +2617,7 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
2592 } while (!ret && idx); 2617 } while (!ret && idx);
2593 2618
2594 if (!ret) 2619 if (!ret)
2595 ret = try_or_set_cluster(fh, master, set); 2620 ret = try_or_set_cluster(fh, master, set, 0);
2596 2621
2597 /* Copy the new values back to userspace. */ 2622 /* Copy the new values back to userspace. */
2598 if (!ret) { 2623 if (!ret) {
@@ -2638,10 +2663,9 @@ EXPORT_SYMBOL(v4l2_subdev_s_ext_ctrls);
2638 2663
2639/* Helper function for VIDIOC_S_CTRL compatibility */ 2664/* Helper function for VIDIOC_S_CTRL compatibility */
2640static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, 2665static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
2641 struct v4l2_ext_control *c) 2666 struct v4l2_ext_control *c, u32 ch_flags)
2642{ 2667{
2643 struct v4l2_ctrl *master = ctrl->cluster[0]; 2668 struct v4l2_ctrl *master = ctrl->cluster[0];
2644 int ret;
2645 int i; 2669 int i;
2646 2670
2647 /* String controls are not supported. The user_to_new() and 2671 /* String controls are not supported. The user_to_new() and
@@ -2651,12 +2675,6 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
2651 if (ctrl->type == V4L2_CTRL_TYPE_STRING) 2675 if (ctrl->type == V4L2_CTRL_TYPE_STRING)
2652 return -EINVAL; 2676 return -EINVAL;
2653 2677
2654 ret = validate_new(ctrl, c);
2655 if (ret)
2656 return ret;
2657
2658 v4l2_ctrl_lock(ctrl);
2659
2660 /* Reset the 'is_new' flags of the cluster */ 2678 /* Reset the 'is_new' flags of the cluster */
2661 for (i = 0; i < master->ncontrols; i++) 2679 for (i = 0; i < master->ncontrols; i++)
2662 if (master->cluster[i]) 2680 if (master->cluster[i])
@@ -2670,10 +2688,22 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
2670 update_from_auto_cluster(master); 2688 update_from_auto_cluster(master);
2671 2689
2672 user_to_new(c, ctrl); 2690 user_to_new(c, ctrl);
2673 ret = try_or_set_cluster(fh, master, true); 2691 return try_or_set_cluster(fh, master, true, ch_flags);
2674 cur_to_user(c, ctrl); 2692}
2675 2693
2676 v4l2_ctrl_unlock(ctrl); 2694/* Helper function for VIDIOC_S_CTRL compatibility */
2695static int set_ctrl_lock(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
2696 struct v4l2_ext_control *c)
2697{
2698 int ret = validate_new(ctrl, c);
2699
2700 if (!ret) {
2701 v4l2_ctrl_lock(ctrl);
2702 ret = set_ctrl(fh, ctrl, c, 0);
2703 if (!ret)
2704 cur_to_user(c, ctrl);
2705 v4l2_ctrl_unlock(ctrl);
2706 }
2677 return ret; 2707 return ret;
2678} 2708}
2679 2709
@@ -2691,7 +2721,7 @@ int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
2691 return -EACCES; 2721 return -EACCES;
2692 2722
2693 c.value = control->value; 2723 c.value = control->value;
2694 ret = set_ctrl(fh, ctrl, &c); 2724 ret = set_ctrl_lock(fh, ctrl, &c);
2695 control->value = c.value; 2725 control->value = c.value;
2696 return ret; 2726 return ret;
2697} 2727}
@@ -2710,7 +2740,7 @@ int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)
2710 /* It's a driver bug if this happens. */ 2740 /* It's a driver bug if this happens. */
2711 WARN_ON(!type_is_int(ctrl)); 2741 WARN_ON(!type_is_int(ctrl));
2712 c.value = val; 2742 c.value = val;
2713 return set_ctrl(NULL, ctrl, &c); 2743 return set_ctrl_lock(NULL, ctrl, &c);
2714} 2744}
2715EXPORT_SYMBOL(v4l2_ctrl_s_ctrl); 2745EXPORT_SYMBOL(v4l2_ctrl_s_ctrl);
2716 2746
@@ -2721,7 +2751,7 @@ int v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val)
2721 /* It's a driver bug if this happens. */ 2751 /* It's a driver bug if this happens. */
2722 WARN_ON(ctrl->type != V4L2_CTRL_TYPE_INTEGER64); 2752 WARN_ON(ctrl->type != V4L2_CTRL_TYPE_INTEGER64);
2723 c.value64 = val; 2753 c.value64 = val;
2724 return set_ctrl(NULL, ctrl, &c); 2754 return set_ctrl_lock(NULL, ctrl, &c);
2725} 2755}
2726EXPORT_SYMBOL(v4l2_ctrl_s_ctrl_int64); 2756EXPORT_SYMBOL(v4l2_ctrl_s_ctrl_int64);
2727 2757
@@ -2741,6 +2771,41 @@ void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl, v4l2_ctrl_notify_fnc notify, void
2741} 2771}
2742EXPORT_SYMBOL(v4l2_ctrl_notify); 2772EXPORT_SYMBOL(v4l2_ctrl_notify);
2743 2773
2774int v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
2775 s32 min, s32 max, u32 step, s32 def)
2776{
2777 int ret = check_range(ctrl->type, min, max, step, def);
2778 struct v4l2_ext_control c;
2779
2780 switch (ctrl->type) {
2781 case V4L2_CTRL_TYPE_INTEGER:
2782 case V4L2_CTRL_TYPE_BOOLEAN:
2783 case V4L2_CTRL_TYPE_MENU:
2784 case V4L2_CTRL_TYPE_INTEGER_MENU:
2785 case V4L2_CTRL_TYPE_BITMASK:
2786 if (ret)
2787 return ret;
2788 break;
2789 default:
2790 return -EINVAL;
2791 }
2792 v4l2_ctrl_lock(ctrl);
2793 ctrl->minimum = min;
2794 ctrl->maximum = max;
2795 ctrl->step = step;
2796 ctrl->default_value = def;
2797 c.value = ctrl->cur.val;
2798 if (validate_new(ctrl, &c))
2799 c.value = def;
2800 if (c.value != ctrl->cur.val)
2801 ret = set_ctrl(NULL, ctrl, &c, V4L2_EVENT_CTRL_CH_RANGE);
2802 else
2803 send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE);
2804 v4l2_ctrl_unlock(ctrl);
2805 return ret;
2806}
2807EXPORT_SYMBOL(v4l2_ctrl_modify_range);
2808
2744static int v4l2_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems) 2809static int v4l2_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems)
2745{ 2810{
2746 struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id); 2811 struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id);
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index c4cc04136074..91125b6f05a5 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -518,6 +518,26 @@ void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active);
518 */ 518 */
519void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed); 519void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed);
520 520
521/** v4l2_ctrl_modify_range() - Update the range of a control.
522 * @ctrl: The control to update.
523 * @min: The control's minimum value.
524 * @max: The control's maximum value.
525 * @step: The control's step value
526 * @def: The control's default value.
527 *
528 * Update the range of a control on the fly. This works for control types
529 * INTEGER, BOOLEAN, MENU, INTEGER MENU and BITMASK. For menu controls the
530 * @step value is interpreted as a menu_skip_mask.
531 *
532 * An error is returned if one of the range arguments is invalid for this
533 * control type.
534 *
535 * This function assumes that the control handler is not locked and will
536 * take the lock itself.
537 */
538int v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
539 s32 min, s32 max, u32 step, s32 def);
540
521/** v4l2_ctrl_lock() - Helper function to lock the handler 541/** v4l2_ctrl_lock() - Helper function to lock the handler
522 * associated with the control. 542 * associated with the control.
523 * @ctrl: The control to lock. 543 * @ctrl: The control to lock.
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 94cbe26e9f00..928799c2e2d9 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1822,6 +1822,7 @@ struct v4l2_event_vsync {
1822/* Payload for V4L2_EVENT_CTRL */ 1822/* Payload for V4L2_EVENT_CTRL */
1823#define V4L2_EVENT_CTRL_CH_VALUE (1 << 0) 1823#define V4L2_EVENT_CTRL_CH_VALUE (1 << 0)
1824#define V4L2_EVENT_CTRL_CH_FLAGS (1 << 1) 1824#define V4L2_EVENT_CTRL_CH_FLAGS (1 << 1)
1825#define V4L2_EVENT_CTRL_CH_RANGE (1 << 2)
1825 1826
1826struct v4l2_event_ctrl { 1827struct v4l2_event_ctrl {
1827 __u32 changes; 1828 __u32 changes;