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
24862486 <structname>v4l2_buffer</structname>. See <xref
24872487 linkend="buffer-flags" />.</para>
24882488 </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>
24892493 </orderedlist>
24902494 </section>
24912495
Documentation/DocBook/media/v4l/v4l2.xml+3−1
@@ -142,10 +142,12 @@ applications. --> · 141 unmodified lines
142142 <revision>
143143 <revnumber>3.9</revnumber>
144144 <date>2012-12-03</date>
145− <authorinitials>sa</authorinitials>
145+ <authorinitials>sa, sn</authorinitials>
146146 <revremark>Added timestamp types to
147147 <structname>v4l2_buffer</structname>, see <xref
148148 linkend="buffer-flags" />.
149+ Added <constant>V4L2_EVENT_CTRL_CH_RANGE</constant> control
150+ event changes flag, see <xref linkend="changes-flags"/>.
149151 </revremark>
150152 </revision>
151153
Documentation/DocBook/media/v4l/vidioc-dqevent.xml+6−0
@@ -261,6 +261,12 @@ · 260 unmodified lines
261261 <entry>This control event was triggered because the control flags
262262 changed.</entry>
263263 </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>
264270 </tbody>
265271 </tgroup>
266272 </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
11581158 }
11591159
11601160 /* Copy the new value to the current value. */
1161−static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
1162− bool update_inactive)
1161+static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
11631162 {
11641163 bool changed = false;
11651164
@@ -1183,8 +1182,8 @@ static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, · 17 unmodified lines
11831182 ctrl->cur.val = ctrl->val;
11841183 break;
11851184 }
1186− if (update_inactive) {
1187− /* Note: update_inactive can only be true for auto clusters. */
1185+ if (ch_flags & V4L2_EVENT_CTRL_CH_FLAGS) {
1186+ /* Note: CH_FLAGS is only set for auto clusters. */
11881187 ctrl->flags &=
11891188 ~(V4L2_CTRL_FLAG_INACTIVE | V4L2_CTRL_FLAG_VOLATILE);
11901189 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
11941193 }
11951194 fh = NULL;
11961195 }
1197− if (changed || update_inactive) {
1196+ if (changed || ch_flags) {
11981197 /* If a control was changed that was not one of the controls
11991198 modified by the application, then send the event to all. */
12001199 if (!ctrl->is_new)
12011200 fh = NULL;
12021201 send_event(fh, ctrl,
1203− (changed ? V4L2_EVENT_CTRL_CH_VALUE : 0) |
1204− (update_inactive ? V4L2_EVENT_CTRL_CH_FLAGS : 0));
1202+ (changed ? V4L2_EVENT_CTRL_CH_VALUE : 0) | ch_flags);
12051203 if (ctrl->call_notify && changed && ctrl->handler->notify)
12061204 ctrl->handler->notify(ctrl, ctrl->handler->notify_priv);
12071205 }
@@ -1257,6 +1255,41 @@ static int cluster_changed(struct v4l2_ctrl *master) · 49 unmodified lines
12571255 return diff;
12581256 }
12591257
1258+/* Control range checking */
1259+static 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+
12601293 /* Validate a new control */
12611294 static int validate_new(const struct v4l2_ctrl *ctrl,
12621295 struct v4l2_ext_control *c)
@@ -1529,30 +1562,21 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, · 266 unmodified lines
15291562 {
15301563 struct v4l2_ctrl *ctrl;
15311564 unsigned sz_extra = 0;
1565+ int err;
15321566
15331567 if (hdl->error)
15341568 return NULL;
15351569
15361570 /* Sanity checks */
15371571 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) ||
15401572 (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||
1541− (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) {
1573+ (type == V4L2_CTRL_TYPE_INTEGER_MENU && qmenu_int == NULL)) {
15471574 handler_set_err(hdl, -ERANGE);
15481575 return NULL;
15491576 }
1550− if ((type == V4L2_CTRL_TYPE_INTEGER ||
1551− type == V4L2_CTRL_TYPE_MENU ||
1552− type == V4L2_CTRL_TYPE_INTEGER_MENU ||
1553− type == V4L2_CTRL_TYPE_BOOLEAN) &&
1554− (def < min || def > max)) {
1555− handler_set_err(hdl, -ERANGE);
1577+ err = check_range(type, min, max, step, def);
1578+ if (err) {
1579+ handler_set_err(hdl, err);
15561580 return NULL;
15571581 }
15581582 if (type == V4L2_CTRL_TYPE_BITMASK && ((def & ~max) || min || step)) {
@@ -2426,8 +2450,8 @@ EXPORT_SYMBOL(v4l2_ctrl_g_ctrl_int64); · 867 unmodified lines
24262450 /* Core function that calls try/s_ctrl and ensures that the new value is
24272451 copied to the current value on a set.
24282452 Must be called with ctrl->handler->lock held. */
2429−static int try_or_set_cluster(struct v4l2_fh *fh,
2430− struct v4l2_ctrl *master, bool set)
2453+static int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master,
2454+ bool set, u32 ch_flags)
24312455 {
24322456 bool update_flag;
24332457 int ret;
@@ -2465,7 +2489,8 @@ static int try_or_set_cluster(struct v4l2_fh *fh, · 31 unmodified lines
24652489 /* If OK, then make the new values permanent. */
24662490 update_flag = is_cur_manual(master) != is_new_manual(master);
24672491 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));
24692494 return 0;
24702495 }
24712496
@@ -2592,7 +2617,7 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, · 120 unmodified lines
25922617 } while (!ret && idx);
25932618
25942619 if (!ret)
2595− ret = try_or_set_cluster(fh, master, set);
2620+ ret = try_or_set_cluster(fh, master, set, 0);
25962621
25972622 /* Copy the new values back to userspace. */
25982623 if (!ret) {
@@ -2638,10 +2663,9 @@ EXPORT_SYMBOL(v4l2_subdev_s_ext_ctrls); · 39 unmodified lines
26382663
26392664 /* Helper function for VIDIOC_S_CTRL compatibility */
26402665 static 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)
26422667 {
26432668 struct v4l2_ctrl *master = ctrl->cluster[0];
2644− int ret;
26452669 int i;
26462670
26472671 /* 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
26512675 if (ctrl->type == V4L2_CTRL_TYPE_STRING)
26522676 return -EINVAL;
26532677
2654− ret = validate_new(ctrl, c);
2655− if (ret)
2656− return ret;
2657−
2658− v4l2_ctrl_lock(ctrl);
2659−
26602678 /* Reset the 'is_new' flags of the cluster */
26612679 for (i = 0; i < master->ncontrols; i++)
26622680 if (master->cluster[i])
@@ -2670,10 +2688,22 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, · 7 unmodified lines
26702688 update_from_auto_cluster(master);
26712689
26722690 user_to_new(c, ctrl);
2673− ret = try_or_set_cluster(fh, master, true);
2674− cur_to_user(c, ctrl);
2691+ return try_or_set_cluster(fh, master, true, ch_flags);
2692+}
26752693
2676− v4l2_ctrl_unlock(ctrl);
2694+/* Helper function for VIDIOC_S_CTRL compatibility */
2695+static 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+ }
26772707 return ret;
26782708 }
26792709
@@ -2691,7 +2721,7 @@ int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, · 11 unmodified lines
26912721 return -EACCES;
26922722
26932723 c.value = control->value;
2694− ret = set_ctrl(fh, ctrl, &c);
2724+ ret = set_ctrl_lock(fh, ctrl, &c);
26952725 control->value = c.value;
26962726 return ret;
26972727 }
@@ -2710,7 +2740,7 @@ int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val) · 12 unmodified lines
27102740 /* It's a driver bug if this happens. */
27112741 WARN_ON(!type_is_int(ctrl));
27122742 c.value = val;
2713− return set_ctrl(NULL, ctrl, &c);
2743+ return set_ctrl_lock(NULL, ctrl, &c);
27142744 }
27152745 EXPORT_SYMBOL(v4l2_ctrl_s_ctrl);
27162746
@@ -2721,7 +2751,7 @@ int v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val) · 4 unmodified lines
27212751 /* It's a driver bug if this happens. */
27222752 WARN_ON(ctrl->type != V4L2_CTRL_TYPE_INTEGER64);
27232753 c.value64 = val;
2724− return set_ctrl(NULL, ctrl, &c);
2754+ return set_ctrl_lock(NULL, ctrl, &c);
27252755 }
27262756 EXPORT_SYMBOL(v4l2_ctrl_s_ctrl_int64);
27272757
@@ -2741,6 +2771,41 @@ void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl, v4l2_ctrl_notify_fnc notify, void · 13 unmodified lines
27412771 }
27422772 EXPORT_SYMBOL(v4l2_ctrl_notify);
27432773
2774+int 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+}
2807+EXPORT_SYMBOL(v4l2_ctrl_modify_range);
2808+
27442809 static int v4l2_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems)
27452810 {
27462811 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
518518 */
519519 void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed);
520520
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+ */
538+int v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
539+ s32 min, s32 max, u32 step, s32 def);
540+
521541 /** v4l2_ctrl_lock() - Helper function to lock the handler
522542 * associated with the control.
523543 * @ctrl: The control to lock.
include/uapi/linux/videodev2.h+1−0
@@ -1822,6 +1822,7 @@ struct v4l2_event_vsync { · 1821 unmodified lines
18221822 /* Payload for V4L2_EVENT_CTRL */
18231823 #define V4L2_EVENT_CTRL_CH_VALUE (1 << 0)
18241824 #define V4L2_EVENT_CTRL_CH_FLAGS (1 << 1)
1825+#define V4L2_EVENT_CTRL_CH_RANGE (1 << 2)
18251826
18261827 struct v4l2_event_ctrl {
18271828 __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