History

[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.

Sylwester Nawrocki committed 13 years ago

Commit 2ccbe771 parent af9bb336 files · +138 −40Browse files

Unified · Split

6 files
  1. Documentation/DocBook/media/v4l/compat.xml +4 −0
  2. Documentation/DocBook/media/v4l/v4l2.xml +3 −1
  3. Documentation/DocBook/media/v4l/vidioc-dqevent.xml +6 −0
  4. drivers/media/v4l2-core/v4l2-ctrls.c +104 −39
  5. include/media/v4l2-ctrls.h +20 −0
  6. include/uapi/linux/videodev2.h +1 −0
Documentation/DocBook/media/v4l/compat.xml+4−0
@@ -2486,6 +2486,10 @@ that used it. It was originally scheduled for removal in 2.6.35. · 2485 unmodified lines
2486 <structname>v4l2_buffer</structname>. See <xref2486 <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
Documentation/DocBook/media/v4l/v4l2.xml+3−1
@@ -142,10 +142,12 @@ applications. --> · 141 unmodified lines
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 to146 <revremark>Added timestamp types to
147 <structname>v4l2_buffer</structname>, see <xref147 <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
Documentation/DocBook/media/v4l/vidioc-dqevent.xml+6−0
@@ -261,6 +261,12 @@ · 260 unmodified lines
261 <entry>This control event was triggered because the control flags261 <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>
drivers/media/v4l2-core/v4l2-ctrls.c+104−39
@@ -1158,8 +1158,7 @@ static int new_to_user(struct v4l2_ext_control *c, · 1157 unmodified lines
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, · 17 unmodified lines
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, · 3 unmodified lines
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 controls1197 /* 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) · 49 unmodified lines
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, · 266 unmodified lines
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); · 867 unmodified lines
2426/* Core function that calls try/s_ctrl and ensures that the new value is2450/* 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, · 31 unmodified lines
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, · 120 unmodified lines
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); · 39 unmodified lines
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() and2671 /* 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, · 3 unmodified lines
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, · 7 unmodified lines
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, · 11 unmodified lines
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) · 12 unmodified lines
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) · 4 unmodified lines
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 · 13 unmodified lines
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);
include/media/v4l2-ctrls.h+20−0
@@ -518,6 +518,26 @@ void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active); · 517 unmodified lines
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 handler541/** 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.
include/uapi/linux/videodev2.h+1−0
@@ -1822,6 +1822,7 @@ struct v4l2_event_vsync { · 1821 unmodified lines
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;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t