summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/media/video/v4l2-event.c31
-rw-r--r--include/media/v4l2-event.h6
2 files changed, 36 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);
diff --git a/include/media/v4l2-event.h b/include/media/v4l2-event.h
index 8d681e5ca552..6da793fa4d34 100644
--- a/include/media/v4l2-event.h
+++ b/include/media/v4l2-event.h
@@ -55,6 +55,12 @@ struct v4l2_subscribed_event {
struct v4l2_fh *fh;
/* list node that hooks into the object's event list (if there is one) */
struct list_head node;
+ /* Optional callback that can replace event 'old' with event 'new'. */
+ void (*replace)(struct v4l2_event *old,
+ const struct v4l2_event *new);
+ /* Optional callback that can merge event 'old' into event 'new'. */
+ void (*merge)(const struct v4l2_event *old,
+ struct v4l2_event *new);
/* the number of elements in the events array */
unsigned elems;
/* the index of the events containing the oldest available event */