diff options
Diffstat (limited to 'drivers/media/v4l2-core/v4l2-event.c')
-rw-r--r-- | drivers/media/v4l2-core/v4l2-event.c | 38 |
1 files changed, 20 insertions, 18 deletions
diff --git a/drivers/media/v4l2-core/v4l2-event.c b/drivers/media/v4l2-core/v4l2-event.c index 127fe6eb91d9..a3ef1f50a4b3 100644 --- a/drivers/media/v4l2-core/v4l2-event.c +++ b/drivers/media/v4l2-core/v4l2-event.c | |||
@@ -115,14 +115,6 @@ static void __v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *e | |||
115 | if (sev == NULL) | 115 | if (sev == NULL) |
116 | return; | 116 | return; |
117 | 117 | ||
118 | /* | ||
119 | * If the event has been added to the fh->subscribed list, but its | ||
120 | * add op has not completed yet elems will be 0, treat this as | ||
121 | * not being subscribed. | ||
122 | */ | ||
123 | if (!sev->elems) | ||
124 | return; | ||
125 | |||
126 | /* Increase event sequence number on fh. */ | 118 | /* Increase event sequence number on fh. */ |
127 | fh->sequence++; | 119 | fh->sequence++; |
128 | 120 | ||
@@ -208,6 +200,7 @@ int v4l2_event_subscribe(struct v4l2_fh *fh, | |||
208 | struct v4l2_subscribed_event *sev, *found_ev; | 200 | struct v4l2_subscribed_event *sev, *found_ev; |
209 | unsigned long flags; | 201 | unsigned long flags; |
210 | unsigned i; | 202 | unsigned i; |
203 | int ret = 0; | ||
211 | 204 | ||
212 | if (sub->type == V4L2_EVENT_ALL) | 205 | if (sub->type == V4L2_EVENT_ALL) |
213 | return -EINVAL; | 206 | return -EINVAL; |
@@ -225,31 +218,36 @@ int v4l2_event_subscribe(struct v4l2_fh *fh, | |||
225 | sev->flags = sub->flags; | 218 | sev->flags = sub->flags; |
226 | sev->fh = fh; | 219 | sev->fh = fh; |
227 | sev->ops = ops; | 220 | sev->ops = ops; |
221 | sev->elems = elems; | ||
222 | |||
223 | mutex_lock(&fh->subscribe_lock); | ||
228 | 224 | ||
229 | spin_lock_irqsave(&fh->vdev->fh_lock, flags); | 225 | spin_lock_irqsave(&fh->vdev->fh_lock, flags); |
230 | found_ev = v4l2_event_subscribed(fh, sub->type, sub->id); | 226 | found_ev = v4l2_event_subscribed(fh, sub->type, sub->id); |
231 | if (!found_ev) | ||
232 | list_add(&sev->list, &fh->subscribed); | ||
233 | spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); | 227 | spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); |
234 | 228 | ||
235 | if (found_ev) { | 229 | if (found_ev) { |
230 | /* Already listening */ | ||
236 | kvfree(sev); | 231 | kvfree(sev); |
237 | return 0; /* Already listening */ | 232 | goto out_unlock; |
238 | } | 233 | } |
239 | 234 | ||
240 | if (sev->ops && sev->ops->add) { | 235 | if (sev->ops && sev->ops->add) { |
241 | int ret = sev->ops->add(sev, elems); | 236 | ret = sev->ops->add(sev, elems); |
242 | if (ret) { | 237 | if (ret) { |
243 | sev->ops = NULL; | 238 | kvfree(sev); |
244 | v4l2_event_unsubscribe(fh, sub); | 239 | goto out_unlock; |
245 | return ret; | ||
246 | } | 240 | } |
247 | } | 241 | } |
248 | 242 | ||
249 | /* Mark as ready for use */ | 243 | spin_lock_irqsave(&fh->vdev->fh_lock, flags); |
250 | sev->elems = elems; | 244 | list_add(&sev->list, &fh->subscribed); |
245 | spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); | ||
251 | 246 | ||
252 | return 0; | 247 | out_unlock: |
248 | mutex_unlock(&fh->subscribe_lock); | ||
249 | |||
250 | return ret; | ||
253 | } | 251 | } |
254 | EXPORT_SYMBOL_GPL(v4l2_event_subscribe); | 252 | EXPORT_SYMBOL_GPL(v4l2_event_subscribe); |
255 | 253 | ||
@@ -288,6 +286,8 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh, | |||
288 | return 0; | 286 | return 0; |
289 | } | 287 | } |
290 | 288 | ||
289 | mutex_lock(&fh->subscribe_lock); | ||
290 | |||
291 | spin_lock_irqsave(&fh->vdev->fh_lock, flags); | 291 | spin_lock_irqsave(&fh->vdev->fh_lock, flags); |
292 | 292 | ||
293 | sev = v4l2_event_subscribed(fh, sub->type, sub->id); | 293 | sev = v4l2_event_subscribed(fh, sub->type, sub->id); |
@@ -305,6 +305,8 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh, | |||
305 | if (sev && sev->ops && sev->ops->del) | 305 | if (sev && sev->ops && sev->ops->del) |
306 | sev->ops->del(sev); | 306 | sev->ops->del(sev); |
307 | 307 | ||
308 | mutex_unlock(&fh->subscribe_lock); | ||
309 | |||
308 | kvfree(sev); | 310 | kvfree(sev); |
309 | 311 | ||
310 | return 0; | 312 | return 0; |