aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2012-04-08 11:59:46 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-05-07 15:28:35 -0400
commitc53c2549333b340e2662dc64ec81323476b69a97 (patch)
tree4bd55780eba1302caaf7359631b996043dc1082f
parenta22d85fea89744fad2cb215da1fe0c1ce226a613 (diff)
[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>
-rw-r--r--Documentation/video4linux/v4l2-framework.txt28
-rw-r--r--drivers/media/video/ivtv/ivtv-ioctl.c2
-rw-r--r--drivers/media/video/omap3isp/ispccdc.c2
-rw-r--r--drivers/media/video/omap3isp/ispstat.c2
-rw-r--r--drivers/media/video/v4l2-ctrls.c2
-rw-r--r--drivers/media/video/v4l2-event.c54
-rw-r--r--drivers/usb/gadget/uvc_v4l2.c2
-rw-r--r--include/media/v4l2-event.h24
8 files changed, 86 insertions, 30 deletions
diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
index e3dfc268d9c1..369d4bc87828 100644
--- a/Documentation/video4linux/v4l2-framework.txt
+++ b/Documentation/video4linux/v4l2-framework.txt
@@ -945,21 +945,35 @@ fast.
945 945
946Useful functions: 946Useful functions:
947 947
948- v4l2_event_queue() 948void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev)
949 949
950 Queue events to video device. The driver's only responsibility is to fill 950 Queue events to video device. The driver's only responsibility is to fill
951 in the type and the data fields. The other fields will be filled in by 951 in the type and the data fields. The other fields will be filled in by
952 V4L2. 952 V4L2.
953 953
954- v4l2_event_subscribe() 954int v4l2_event_subscribe(struct v4l2_fh *fh,
955 struct v4l2_event_subscription *sub, unsigned elems,
956 const struct v4l2_subscribed_event_ops *ops)
955 957
956 The video_device->ioctl_ops->vidioc_subscribe_event must check the driver 958 The video_device->ioctl_ops->vidioc_subscribe_event must check the driver
957 is able to produce events with specified event id. Then it calls 959 is able to produce events with specified event id. Then it calls
958 v4l2_event_subscribe() to subscribe the event. The last argument is the 960 v4l2_event_subscribe() to subscribe the event.
959 size of the event queue for this event. If it is 0, then the framework
960 will fill in a default value (this depends on the event type).
961 961
962- v4l2_event_unsubscribe() 962 The elems argument is the size of the event queue for this event. If it is 0,
963 then the framework will fill in a default value (this depends on the event
964 type).
965
966 The ops argument allows the driver to specify a number of callbacks:
967 * add: called when a new listener gets added (subscribing to the same
968 event twice will only cause this callback to get called once)
969 * del: called when a listener stops listening
970 * replace: replace event 'old' with event 'new'.
971 * merge: merge event 'old' into event 'new'.
972 All 4 callbacks are optional, if you don't want to specify any callbacks
973 the ops argument itself maybe NULL.
974
975int v4l2_event_unsubscribe(struct v4l2_fh *fh,
976 struct v4l2_event_subscription *sub)
963 977
964 vidioc_unsubscribe_event in struct v4l2_ioctl_ops. A driver may use 978 vidioc_unsubscribe_event in struct v4l2_ioctl_ops. A driver may use
965 v4l2_event_unsubscribe() directly unless it wants to be involved in 979 v4l2_event_unsubscribe() directly unless it wants to be involved in
@@ -968,7 +982,7 @@ Useful functions:
968 The special type V4L2_EVENT_ALL may be used to unsubscribe all events. The 982 The special type V4L2_EVENT_ALL may be used to unsubscribe all events. The
969 drivers may want to handle this in a special way. 983 drivers may want to handle this in a special way.
970 984
971- v4l2_event_pending() 985int v4l2_event_pending(struct v4l2_fh *fh)
972 986
973 Returns the number of pending events. Useful when implementing poll. 987 Returns the number of pending events. Useful when implementing poll.
974 988
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index a151271f60e1..a7730fd4827f 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -1469,7 +1469,7 @@ static int ivtv_subscribe_event(struct v4l2_fh *fh, struct v4l2_event_subscripti
1469 case V4L2_EVENT_VSYNC: 1469 case V4L2_EVENT_VSYNC:
1470 case V4L2_EVENT_EOS: 1470 case V4L2_EVENT_EOS:
1471 case V4L2_EVENT_CTRL: 1471 case V4L2_EVENT_CTRL:
1472 return v4l2_event_subscribe(fh, sub, 0); 1472 return v4l2_event_subscribe(fh, sub, 0, NULL);
1473 default: 1473 default:
1474 return -EINVAL; 1474 return -EINVAL;
1475 } 1475 }
diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c
index eaabc27f0fa2..1f3c16d8f0b4 100644
--- a/drivers/media/video/omap3isp/ispccdc.c
+++ b/drivers/media/video/omap3isp/ispccdc.c
@@ -1703,7 +1703,7 @@ static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
1703 if (sub->id != 0) 1703 if (sub->id != 0)
1704 return -EINVAL; 1704 return -EINVAL;
1705 1705
1706 return v4l2_event_subscribe(fh, sub, OMAP3ISP_CCDC_NEVENTS); 1706 return v4l2_event_subscribe(fh, sub, OMAP3ISP_CCDC_NEVENTS, NULL);
1707} 1707}
1708 1708
1709static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, 1709static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
diff --git a/drivers/media/video/omap3isp/ispstat.c b/drivers/media/video/omap3isp/ispstat.c
index 11871ecc6d25..b8640be692f1 100644
--- a/drivers/media/video/omap3isp/ispstat.c
+++ b/drivers/media/video/omap3isp/ispstat.c
@@ -1032,7 +1032,7 @@ int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev,
1032 if (sub->type != stat->event_type) 1032 if (sub->type != stat->event_type)
1033 return -EINVAL; 1033 return -EINVAL;
1034 1034
1035 return v4l2_event_subscribe(fh, sub, STAT_NEVENTS); 1035 return v4l2_event_subscribe(fh, sub, STAT_NEVENTS, NULL);
1036} 1036}
1037 1037
1038int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev, 1038int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev,
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index c93a9796f1fb..91b197819fc2 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -2468,7 +2468,7 @@ int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh,
2468 struct v4l2_event_subscription *sub) 2468 struct v4l2_event_subscription *sub)
2469{ 2469{
2470 if (sub->type == V4L2_EVENT_CTRL) 2470 if (sub->type == V4L2_EVENT_CTRL)
2471 return v4l2_event_subscribe(fh, sub, 0); 2471 return v4l2_event_subscribe(fh, sub, 0, NULL);
2472 return -EINVAL; 2472 return -EINVAL;
2473} 2473}
2474EXPORT_SYMBOL(v4l2_ctrl_subscribe_event); 2474EXPORT_SYMBOL(v4l2_ctrl_subscribe_event);
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
120 if (sev == NULL) 120 if (sev == NULL)
121 return; 121 return;
122 122
123 /*
124 * If the event has been added to the fh->subscribed list, but its
125 * add op has not completed yet elems will be 0, treat this as
126 * not being subscribed.
127 */
128 if (!sev->elems)
129 return;
130
123 /* Increase event sequence number on fh. */ 131 /* Increase event sequence number on fh. */
124 fh->sequence++; 132 fh->sequence++;
125 133
@@ -132,14 +140,14 @@ static void __v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *e
132 sev->first = sev_pos(sev, 1); 140 sev->first = sev_pos(sev, 1);
133 fh->navailable--; 141 fh->navailable--;
134 if (sev->elems == 1) { 142 if (sev->elems == 1) {
135 if (sev->replace) { 143 if (sev->ops && sev->ops->replace) {
136 sev->replace(&kev->event, ev); 144 sev->ops->replace(&kev->event, ev);
137 copy_payload = false; 145 copy_payload = false;
138 } 146 }
139 } else if (sev->merge) { 147 } else if (sev->ops && sev->ops->merge) {
140 struct v4l2_kevent *second_oldest = 148 struct v4l2_kevent *second_oldest =
141 sev->events + sev_pos(sev, 0); 149 sev->events + sev_pos(sev, 0);
142 sev->merge(&kev->event, &second_oldest->event); 150 sev->ops->merge(&kev->event, &second_oldest->event);
143 } 151 }
144 } 152 }
145 153
@@ -208,8 +216,14 @@ static void ctrls_merge(const struct v4l2_event *old, struct v4l2_event *new)
208 new->u.ctrl.changes |= old->u.ctrl.changes; 216 new->u.ctrl.changes |= old->u.ctrl.changes;
209} 217}
210 218
219static const struct v4l2_subscribed_event_ops ctrl_ops = {
220 .replace = ctrls_replace,
221 .merge = ctrls_merge,
222};
223
211int v4l2_event_subscribe(struct v4l2_fh *fh, 224int v4l2_event_subscribe(struct v4l2_fh *fh,
212 struct v4l2_event_subscription *sub, unsigned elems) 225 struct v4l2_event_subscription *sub, unsigned elems,
226 const struct v4l2_subscribed_event_ops *ops)
213{ 227{
214 struct v4l2_subscribed_event *sev, *found_ev; 228 struct v4l2_subscribed_event *sev, *found_ev;
215 struct v4l2_ctrl *ctrl = NULL; 229 struct v4l2_ctrl *ctrl = NULL;
@@ -236,10 +250,9 @@ int v4l2_event_subscribe(struct v4l2_fh *fh,
236 sev->id = sub->id; 250 sev->id = sub->id;
237 sev->flags = sub->flags; 251 sev->flags = sub->flags;
238 sev->fh = fh; 252 sev->fh = fh;
239 sev->elems = elems; 253 sev->ops = ops;
240 if (ctrl) { 254 if (ctrl) {
241 sev->replace = ctrls_replace; 255 sev->ops = &ctrl_ops;
242 sev->merge = ctrls_merge;
243 } 256 }
244 257
245 spin_lock_irqsave(&fh->vdev->fh_lock, flags); 258 spin_lock_irqsave(&fh->vdev->fh_lock, flags);
@@ -248,12 +261,27 @@ int v4l2_event_subscribe(struct v4l2_fh *fh,
248 list_add(&sev->list, &fh->subscribed); 261 list_add(&sev->list, &fh->subscribed);
249 spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); 262 spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
250 263
251 /* v4l2_ctrl_add_event uses a mutex, so do this outside the spin lock */ 264 if (found_ev) {
252 if (found_ev)
253 kfree(sev); 265 kfree(sev);
254 else if (ctrl) 266 return 0; /* Already listening */
267 }
268
269 if (sev->ops && sev->ops->add) {
270 int ret = sev->ops->add(sev);
271 if (ret) {
272 sev->ops = NULL;
273 v4l2_event_unsubscribe(fh, sub);
274 return ret;
275 }
276 }
277
278 /* v4l2_ctrl_add_event uses a mutex, so do this outside the spin lock */
279 if (ctrl)
255 v4l2_ctrl_add_event(ctrl, sev); 280 v4l2_ctrl_add_event(ctrl, sev);
256 281
282 /* Mark as ready for use */
283 sev->elems = elems;
284
257 return 0; 285 return 0;
258} 286}
259EXPORT_SYMBOL_GPL(v4l2_event_subscribe); 287EXPORT_SYMBOL_GPL(v4l2_event_subscribe);
@@ -306,6 +334,10 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh,
306 } 334 }
307 335
308 spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); 336 spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
337
338 if (sev && sev->ops && sev->ops->del)
339 sev->ops->del(sev);
340
309 if (sev && sev->type == V4L2_EVENT_CTRL) { 341 if (sev && sev->type == V4L2_EVENT_CTRL) {
310 struct v4l2_ctrl *ctrl = v4l2_ctrl_find(fh->ctrl_handler, sev->id); 342 struct v4l2_ctrl *ctrl = v4l2_ctrl_find(fh->ctrl_handler, sev->id);
311 343
diff --git a/drivers/usb/gadget/uvc_v4l2.c b/drivers/usb/gadget/uvc_v4l2.c
index f6e083b50191..90db5fe9c56e 100644
--- a/drivers/usb/gadget/uvc_v4l2.c
+++ b/drivers/usb/gadget/uvc_v4l2.c
@@ -296,7 +296,7 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
296 if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST) 296 if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST)
297 return -EINVAL; 297 return -EINVAL;
298 298
299 return v4l2_event_subscribe(&handle->vfh, arg, 2); 299 return v4l2_event_subscribe(&handle->vfh, arg, 2, NULL);
300 } 300 }
301 301
302 case VIDIOC_UNSUBSCRIBE_EVENT: 302 case VIDIOC_UNSUBSCRIBE_EVENT:
diff --git a/include/media/v4l2-event.h b/include/media/v4l2-event.h
index 5f14e8895ce2..88fa9a1e0df3 100644
--- a/include/media/v4l2-event.h
+++ b/include/media/v4l2-event.h
@@ -78,6 +78,19 @@ struct v4l2_kevent {
78 struct v4l2_event event; 78 struct v4l2_event event;
79}; 79};
80 80
81/** struct v4l2_subscribed_event_ops - Subscribed event operations.
82 * @add: Optional callback, called when a new listener is added
83 * @del: Optional callback, called when a listener stops listening
84 * @replace: Optional callback that can replace event 'old' with event 'new'.
85 * @merge: Optional callback that can merge event 'old' into event 'new'.
86 */
87struct v4l2_subscribed_event_ops {
88 int (*add)(struct v4l2_subscribed_event *sev);
89 void (*del)(struct v4l2_subscribed_event *sev);
90 void (*replace)(struct v4l2_event *old, const struct v4l2_event *new);
91 void (*merge)(const struct v4l2_event *old, struct v4l2_event *new);
92};
93
81/** struct v4l2_subscribed_event - Internal struct representing a subscribed event. 94/** struct v4l2_subscribed_event - Internal struct representing a subscribed event.
82 * @list: List node for the v4l2_fh->subscribed list. 95 * @list: List node for the v4l2_fh->subscribed list.
83 * @type: Event type. 96 * @type: Event type.
@@ -85,8 +98,7 @@ struct v4l2_kevent {
85 * @flags: Copy of v4l2_event_subscription->flags. 98 * @flags: Copy of v4l2_event_subscription->flags.
86 * @fh: Filehandle that subscribed to this event. 99 * @fh: Filehandle that subscribed to this event.
87 * @node: List node that hooks into the object's event list (if there is one). 100 * @node: List node that hooks into the object's event list (if there is one).
88 * @replace: Optional callback that can replace event 'old' with event 'new'. 101 * @ops: v4l2_subscribed_event_ops
89 * @merge: Optional callback that can merge event 'old' into event 'new'.
90 * @elems: The number of elements in the events array. 102 * @elems: The number of elements in the events array.
91 * @first: The index of the events containing the oldest available event. 103 * @first: The index of the events containing the oldest available event.
92 * @in_use: The number of queued events. 104 * @in_use: The number of queued events.
@@ -99,10 +111,7 @@ struct v4l2_subscribed_event {
99 u32 flags; 111 u32 flags;
100 struct v4l2_fh *fh; 112 struct v4l2_fh *fh;
101 struct list_head node; 113 struct list_head node;
102 void (*replace)(struct v4l2_event *old, 114 const struct v4l2_subscribed_event_ops *ops;
103 const struct v4l2_event *new);
104 void (*merge)(const struct v4l2_event *old,
105 struct v4l2_event *new);
106 unsigned elems; 115 unsigned elems;
107 unsigned first; 116 unsigned first;
108 unsigned in_use; 117 unsigned in_use;
@@ -115,7 +124,8 @@ void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev);
115void v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *ev); 124void v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *ev);
116int v4l2_event_pending(struct v4l2_fh *fh); 125int v4l2_event_pending(struct v4l2_fh *fh);
117int v4l2_event_subscribe(struct v4l2_fh *fh, 126int v4l2_event_subscribe(struct v4l2_fh *fh,
118 struct v4l2_event_subscription *sub, unsigned elems); 127 struct v4l2_event_subscription *sub, unsigned elems,
128 const struct v4l2_subscribed_event_ops *ops);
119int v4l2_event_unsubscribe(struct v4l2_fh *fh, 129int v4l2_event_unsubscribe(struct v4l2_fh *fh,
120 struct v4l2_event_subscription *sub); 130 struct v4l2_event_subscription *sub);
121void v4l2_event_unsubscribe_all(struct v4l2_fh *fh); 131void v4l2_event_unsubscribe_all(struct v4l2_fh *fh);