Skip to content

Commit

Permalink
[media] v4l2-event: add optional merge and replace callbacks
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Hans Verkuil authored and Mauro Carvalho Chehab committed Jul 27, 2011
1 parent f1e393d commit 2151bdc
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 1 deletion.
31 changes: 30 additions & 1 deletion drivers/media/video/v4l2-event.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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)
{
Expand All @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions include/media/v4l2-event.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down

0 comments on commit 2151bdc

Please sign in to comment.