diff options
Diffstat (limited to 'drivers/media/video/v4l2-event.c')
-rw-r--r-- | drivers/media/video/v4l2-event.c | 31 |
1 files changed, 30 insertions, 1 deletions
diff --git a/drivers/media/video/v4l2-event.c b/drivers/media/video/v4l2-event.c index 9e325dd3ce27..b1c19fc2f08c 100644 --- a/drivers/media/video/v4l2-event.c +++ b/drivers/media/video/v4l2-event.c @@ -113,6 +113,7 @@ static void __v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *e { struct v4l2_subscribed_event *sev; struct v4l2_kevent *kev; + bool copy_payload = true; /* Are we subscribed? */ sev = v4l2_event_subscribed(fh, ev->type, ev->id); @@ -130,12 +131,23 @@ static void __v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *e sev->in_use--; sev->first = sev_pos(sev, 1); fh->navailable--; + if (sev->elems == 1) { + if (sev->replace) { + sev->replace(&kev->event, ev); + copy_payload = false; + } + } else if (sev->merge) { + struct v4l2_kevent *second_oldest = + sev->events + sev_pos(sev, 0); + sev->merge(&kev->event, &second_oldest->event); + } } /* Take one and fill it. */ kev = sev->events + sev_pos(sev, sev->in_use); kev->event.type = ev->type; - kev->event.u = ev->u; + if (copy_payload) + kev->event.u = ev->u; kev->event.id = ev->id; kev->event.timestamp = *ts; kev->event.sequence = fh->sequence; @@ -184,6 +196,19 @@ int v4l2_event_pending(struct v4l2_fh *fh) } EXPORT_SYMBOL_GPL(v4l2_event_pending); +static void ctrls_replace(struct v4l2_event *old, const struct v4l2_event *new) +{ + u32 old_changes = old->u.ctrl.changes; + + old->u.ctrl = new->u.ctrl; + old->u.ctrl.changes |= old_changes; +} + +static void ctrls_merge(const struct v4l2_event *old, struct v4l2_event *new) +{ + new->u.ctrl.changes |= old->u.ctrl.changes; +} + int v4l2_event_subscribe(struct v4l2_fh *fh, struct v4l2_event_subscription *sub, unsigned elems) { @@ -210,6 +235,10 @@ int v4l2_event_subscribe(struct v4l2_fh *fh, sev->flags = sub->flags; sev->fh = fh; sev->elems = elems; + if (ctrl) { + sev->replace = ctrls_replace; + sev->merge = ctrls_merge; + } spin_lock_irqsave(&fh->vdev->fh_lock, flags); found_ev = v4l2_event_subscribed(fh, sub->type, sub->id); |