summaryrefslogtreecommitdiff
path: root/drivers/media/video/v4l2-event.c
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2011-06-18 07:02:20 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-07-27 17:53:31 -0300
commit2151bdc887acfd6dc2c931b4d3c01f95e30b7df8 (patch)
tree429683c0f6de68971d74fa379cf1dcfe4540c5a3 /drivers/media/video/v4l2-event.c
parentf1e393de382af9b9bd2462a42bfa16b8c501d81b (diff)
[media] v4l2-event: add optional merge and replace callbacks
When the event queue for a subscribed event is full, then the oldest event is dropped. It would be nice if the contents of that oldest event could be merged with the next-oldest. That way no information is lost, only intermediate steps are lost. This patch adds optional replace() (called when only one kevent was allocated) and merge() (called when more than one kevent was allocated) callbacks that will be called to do this job. These two callbacks are implemented for the V4L2_EVENT_CTRL event. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/v4l2-event.c')
-rw-r--r--drivers/media/video/v4l2-event.c31
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);