diff options
Diffstat (limited to 'drivers/media/v4l2-core/v4l2-event.c')
-rw-r--r-- | drivers/media/v4l2-core/v4l2-event.c | 43 |
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 | } |
194 | EXPORT_SYMBOL_GPL(v4l2_event_pending); | 194 | EXPORT_SYMBOL_GPL(v4l2_event_pending); |
195 | 195 | ||
196 | static 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 | |||
196 | int v4l2_event_subscribe(struct v4l2_fh *fh, | 212 | int 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 | |||
247 | out_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 | ||