summaryrefslogtreecommitdiffstats
path: root/drivers/media/video/v4l2-event.c
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2012-04-08 17:59:46 +0200
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-05-07 21:28:35 +0200
commitc53c2549333b340e2662dc64ec81323476b69a97 (patch)
tree4bd55780eba1302caaf7359631b996043dc1082f /drivers/media/video/v4l2-event.c
parent[media] media/radio: use v4l2_ctrl_subscribe_event where possible (diff)
downloadlinux-c53c2549333b340e2662dc64ec81323476b69a97.tar.xz
linux-c53c2549333b340e2662dc64ec81323476b69a97.zip
[media] v4l2-event: Add v4l2_subscribed_event_ops
Just like with ctrl events, drivers may want to get called back on listener add / remove for other event types too. Rather then special casing all of this in subscribe / unsubscribe event it is better to use ops for this. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.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.c54
1 files changed, 43 insertions, 11 deletions
diff --git a/drivers/media/video/v4l2-event.c b/drivers/media/video/v4l2-event.c
index c26ad9637143..0ba2dfa86d07 100644
--- a/drivers/media/video/v4l2-event.c
+++ b/drivers/media/video/v4l2-event.c
@@ -120,6 +120,14 @@ static void __v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *e
if (sev == NULL)
return;
+ /*
+ * If the event has been added to the fh->subscribed list, but its
+ * add op has not completed yet elems will be 0, treat this as
+ * not being subscribed.
+ */
+ if (!sev->elems)
+ return;
+
/* Increase event sequence number on fh. */
fh->sequence++;
@@ -132,14 +140,14 @@ static void __v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *e
sev->first = sev_pos(sev, 1);
fh->navailable--;
if (sev->elems == 1) {
- if (sev->replace) {
- sev->replace(&kev->event, ev);
+ if (sev->ops && sev->ops->replace) {
+ sev->ops->replace(&kev->event, ev);
copy_payload = false;
}
- } else if (sev->merge) {
+ } else if (sev->ops && sev->ops->merge) {
struct v4l2_kevent *second_oldest =
sev->events + sev_pos(sev, 0);
- sev->merge(&kev->event, &second_oldest->event);
+ sev->ops->merge(&kev->event, &second_oldest->event);
}
}
@@ -208,8 +216,14 @@ static void ctrls_merge(const struct v4l2_event *old, struct v4l2_event *new)
new->u.ctrl.changes |= old->u.ctrl.changes;
}
+static const struct v4l2_subscribed_event_ops ctrl_ops = {
+ .replace = ctrls_replace,
+ .merge = ctrls_merge,
+};
+
int v4l2_event_subscribe(struct v4l2_fh *fh,
- struct v4l2_event_subscription *sub, unsigned elems)
+ struct v4l2_event_subscription *sub, unsigned elems,
+ const struct v4l2_subscribed_event_ops *ops)
{
struct v4l2_subscribed_event *sev, *found_ev;
struct v4l2_ctrl *ctrl = NULL;
@@ -236,10 +250,9 @@ int v4l2_event_subscribe(struct v4l2_fh *fh,
sev->id = sub->id;
sev->flags = sub->flags;
sev->fh = fh;
- sev->elems = elems;
+ sev->ops = ops;
if (ctrl) {
- sev->replace = ctrls_replace;
- sev->merge = ctrls_merge;
+ sev->ops = &ctrl_ops;
}
spin_lock_irqsave(&fh->vdev->fh_lock, flags);
@@ -248,12 +261,27 @@ int v4l2_event_subscribe(struct v4l2_fh *fh,
list_add(&sev->list, &fh->subscribed);
spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
- /* v4l2_ctrl_add_event uses a mutex, so do this outside the spin lock */
- if (found_ev)
+ if (found_ev) {
kfree(sev);
- else if (ctrl)
+ return 0; /* Already listening */
+ }
+
+ if (sev->ops && sev->ops->add) {
+ int ret = sev->ops->add(sev);
+ if (ret) {
+ sev->ops = NULL;
+ v4l2_event_unsubscribe(fh, sub);
+ return ret;
+ }
+ }
+
+ /* v4l2_ctrl_add_event uses a mutex, so do this outside the spin lock */
+ if (ctrl)
v4l2_ctrl_add_event(ctrl, sev);
+ /* Mark as ready for use */
+ sev->elems = elems;
+
return 0;
}
EXPORT_SYMBOL_GPL(v4l2_event_subscribe);
@@ -306,6 +334,10 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh,
}
spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
+
+ if (sev && sev->ops && sev->ops->del)
+ sev->ops->del(sev);
+
if (sev && sev->type == V4L2_EVENT_CTRL) {
struct v4l2_ctrl *ctrl = v4l2_ctrl_find(fh->ctrl_handler, sev->id);