aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/v4l2-core/v4l2-event.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/v4l2-core/v4l2-event.c')
-rw-r--r--drivers/media/v4l2-core/v4l2-event.c43
1 files changed, 24 insertions, 19 deletions
diff --git a/drivers/media/v4l2-core/v4l2-event.c b/drivers/media/v4l2-core/v4l2-event.c
index a3ef1f50a4b3..481e3c65cf97 100644
--- a/drivers/media/v4l2-core/v4l2-event.c
+++ b/drivers/media/v4l2-core/v4l2-event.c
@@ -193,6 +193,22 @@ int v4l2_event_pending(struct v4l2_fh *fh)
193} 193}
194EXPORT_SYMBOL_GPL(v4l2_event_pending); 194EXPORT_SYMBOL_GPL(v4l2_event_pending);
195 195
196static void __v4l2_event_unsubscribe(struct v4l2_subscribed_event *sev)
197{
198 struct v4l2_fh *fh = sev->fh;
199 unsigned int i;
200
201 lockdep_assert_held(&fh->subscribe_lock);
202 assert_spin_locked(&fh->vdev->fh_lock);
203
204 /* Remove any pending events for this subscription */
205 for (i = 0; i < sev->in_use; i++) {
206 list_del(&sev->events[sev_pos(sev, i)].list);
207 fh->navailable--;
208 }
209 list_del(&sev->list);
210}
211
196int v4l2_event_subscribe(struct v4l2_fh *fh, 212int v4l2_event_subscribe(struct v4l2_fh *fh,
197 const struct v4l2_event_subscription *sub, unsigned elems, 213 const struct v4l2_event_subscription *sub, unsigned elems,
198 const struct v4l2_subscribed_event_ops *ops) 214 const struct v4l2_subscribed_event_ops *ops)
@@ -224,27 +240,23 @@ int v4l2_event_subscribe(struct v4l2_fh *fh,
224 240
225 spin_lock_irqsave(&fh->vdev->fh_lock, flags); 241 spin_lock_irqsave(&fh->vdev->fh_lock, flags);
226 found_ev = v4l2_event_subscribed(fh, sub->type, sub->id); 242 found_ev = v4l2_event_subscribed(fh, sub->type, sub->id);
243 if (!found_ev)
244 list_add(&sev->list, &fh->subscribed);
227 spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); 245 spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
228 246
229 if (found_ev) { 247 if (found_ev) {
230 /* Already listening */ 248 /* Already listening */
231 kvfree(sev); 249 kvfree(sev);
232 goto out_unlock; 250 } else if (sev->ops && sev->ops->add) {
233 }
234
235 if (sev->ops && sev->ops->add) {
236 ret = sev->ops->add(sev, elems); 251 ret = sev->ops->add(sev, elems);
237 if (ret) { 252 if (ret) {
253 spin_lock_irqsave(&fh->vdev->fh_lock, flags);
254 __v4l2_event_unsubscribe(sev);
255 spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
238 kvfree(sev); 256 kvfree(sev);
239 goto out_unlock;
240 } 257 }
241 } 258 }
242 259
243 spin_lock_irqsave(&fh->vdev->fh_lock, flags);
244 list_add(&sev->list, &fh->subscribed);
245 spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
246
247out_unlock:
248 mutex_unlock(&fh->subscribe_lock); 260 mutex_unlock(&fh->subscribe_lock);
249 261
250 return ret; 262 return ret;
@@ -279,7 +291,6 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh,
279{ 291{
280 struct v4l2_subscribed_event *sev; 292 struct v4l2_subscribed_event *sev;
281 unsigned long flags; 293 unsigned long flags;
282 int i;
283 294
284 if (sub->type == V4L2_EVENT_ALL) { 295 if (sub->type == V4L2_EVENT_ALL) {
285 v4l2_event_unsubscribe_all(fh); 296 v4l2_event_unsubscribe_all(fh);
@@ -291,14 +302,8 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh,
291 spin_lock_irqsave(&fh->vdev->fh_lock, flags); 302 spin_lock_irqsave(&fh->vdev->fh_lock, flags);
292 303
293 sev = v4l2_event_subscribed(fh, sub->type, sub->id); 304 sev = v4l2_event_subscribed(fh, sub->type, sub->id);
294 if (sev != NULL) { 305 if (sev != NULL)
295 /* Remove any pending events for this subscription */ 306 __v4l2_event_unsubscribe(sev);
296 for (i = 0; i < sev->in_use; i++) {
297 list_del(&sev->events[sev_pos(sev, i)].list);
298 fh->navailable--;
299 }
300 list_del(&sev->list);
301 }
302 307
303 spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); 308 spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
304 309