Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] v4l2-event: fix regression with initial event handling

If the V4L2_EVENT_SUB_FL_SEND_INITIAL was set, then the application expects
to receive an initial event of the initial value of the control.

However, commit c53c2549333b340e2662dc64ec81323476b69a97 that added the new
v4l2_subscribed_event_ops introduced a regression: while the code still queued
that initial event the __v4l2_event_queue_fh() function was modified to ignore
such requests if sev->elems was 0 (meaning that the event subscription wasn't
finished yet).

And sev->elems was only set to a non-zero value after the add operation
returned.

This patch fixes this by passing the elems value to the add function. Then the
add function can set it before queuing the initial event.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

authored by

Hans Verkuil and committed by
Mauro Carvalho Chehab
6e6d76cd 69ecdbac

+10 -4
+4 -1
drivers/media/video/uvc/uvc_ctrl.c
··· 1250 1250 } 1251 1251 } 1252 1252 1253 - static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev) 1253 + static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems) 1254 1254 { 1255 1255 struct uvc_fh *handle = container_of(sev->fh, struct uvc_fh, vfh); 1256 1256 struct uvc_control_mapping *mapping; ··· 1278 1278 1279 1279 uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, val, 1280 1280 changes); 1281 + /* Mark the queue as active, allowing this initial 1282 + event to be accepted. */ 1283 + sev->elems = elems; 1281 1284 v4l2_event_queue_fh(sev->fh, &ev); 1282 1285 } 1283 1286
+4 -1
drivers/media/video/v4l2-ctrls.c
··· 2559 2559 } 2560 2560 EXPORT_SYMBOL(v4l2_ctrl_s_ctrl); 2561 2561 2562 - static int v4l2_ctrl_add_event(struct v4l2_subscribed_event *sev) 2562 + static int v4l2_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems) 2563 2563 { 2564 2564 struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id); 2565 2565 ··· 2576 2576 if (!(ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)) 2577 2577 changes |= V4L2_EVENT_CTRL_CH_VALUE; 2578 2578 fill_event(&ev, ctrl, changes); 2579 + /* Mark the queue as active, allowing this initial 2580 + event to be accepted. */ 2581 + sev->elems = elems; 2579 2582 v4l2_event_queue_fh(sev->fh, &ev); 2580 2583 } 2581 2584 v4l2_ctrl_unlock(ctrl);
+1 -1
drivers/media/video/v4l2-event.c
··· 239 239 } 240 240 241 241 if (sev->ops && sev->ops->add) { 242 - int ret = sev->ops->add(sev); 242 + int ret = sev->ops->add(sev, elems); 243 243 if (ret) { 244 244 sev->ops = NULL; 245 245 v4l2_event_unsubscribe(fh, sub);
+1 -1
include/media/v4l2-event.h
··· 85 85 * @merge: Optional callback that can merge event 'old' into event 'new'. 86 86 */ 87 87 struct v4l2_subscribed_event_ops { 88 - int (*add)(struct v4l2_subscribed_event *sev); 88 + int (*add)(struct v4l2_subscribed_event *sev, unsigned elems); 89 89 void (*del)(struct v4l2_subscribed_event *sev); 90 90 void (*replace)(struct v4l2_event *old, const struct v4l2_event *new); 91 91 void (*merge)(const struct v4l2_event *old, struct v4l2_event *new);