|
@@ -30,44 +30,11 @@
|
|
|
#include <linux/sched.h>
|
|
|
#include <linux/slab.h>
|
|
|
|
|
|
-static void v4l2_event_unsubscribe_all(struct v4l2_fh *fh);
|
|
|
-
|
|
|
-int v4l2_event_alloc(struct v4l2_fh *fh, unsigned int n)
|
|
|
-{
|
|
|
- unsigned long flags;
|
|
|
-
|
|
|
- while (fh->nallocated < n) {
|
|
|
- struct v4l2_kevent *kev;
|
|
|
-
|
|
|
- kev = kzalloc(sizeof(*kev), GFP_KERNEL);
|
|
|
- if (kev == NULL)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
- spin_lock_irqsave(&fh->vdev->fh_lock, flags);
|
|
|
- list_add_tail(&kev->list, &fh->free);
|
|
|
- fh->nallocated++;
|
|
|
- spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-EXPORT_SYMBOL_GPL(v4l2_event_alloc);
|
|
|
-
|
|
|
-#define list_kfree(list, type, member) \
|
|
|
- while (!list_empty(list)) { \
|
|
|
- type *hi; \
|
|
|
- hi = list_first_entry(list, type, member); \
|
|
|
- list_del(&hi->member); \
|
|
|
- kfree(hi); \
|
|
|
- }
|
|
|
-
|
|
|
-void v4l2_event_free(struct v4l2_fh *fh)
|
|
|
+static unsigned sev_pos(const struct v4l2_subscribed_event *sev, unsigned idx)
|
|
|
{
|
|
|
- list_kfree(&fh->free, struct v4l2_kevent, list);
|
|
|
- list_kfree(&fh->available, struct v4l2_kevent, list);
|
|
|
- v4l2_event_unsubscribe_all(fh);
|
|
|
+ idx += sev->first;
|
|
|
+ return idx >= sev->elems ? idx - sev->elems : idx;
|
|
|
}
|
|
|
-EXPORT_SYMBOL_GPL(v4l2_event_free);
|
|
|
|
|
|
static int __v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event)
|
|
|
{
|
|
@@ -84,11 +51,13 @@ static int __v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event)
|
|
|
WARN_ON(fh->navailable == 0);
|
|
|
|
|
|
kev = list_first_entry(&fh->available, struct v4l2_kevent, list);
|
|
|
- list_move(&kev->list, &fh->free);
|
|
|
+ list_del(&kev->list);
|
|
|
fh->navailable--;
|
|
|
|
|
|
kev->event.pending = fh->navailable;
|
|
|
*event = kev->event;
|
|
|
+ kev->sev->first = sev_pos(kev->sev, 1);
|
|
|
+ kev->sev->in_use--;
|
|
|
|
|
|
spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
|
|
|
|
|
@@ -154,17 +123,24 @@ static void __v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *e
|
|
|
fh->sequence++;
|
|
|
|
|
|
/* Do we have any free events? */
|
|
|
- if (list_empty(&fh->free))
|
|
|
- return;
|
|
|
+ if (sev->in_use == sev->elems) {
|
|
|
+ /* no, remove the oldest one */
|
|
|
+ kev = sev->events + sev_pos(sev, 0);
|
|
|
+ list_del(&kev->list);
|
|
|
+ sev->in_use--;
|
|
|
+ sev->first = sev_pos(sev, 1);
|
|
|
+ fh->navailable--;
|
|
|
+ }
|
|
|
|
|
|
/* Take one and fill it. */
|
|
|
- kev = list_first_entry(&fh->free, struct v4l2_kevent, list);
|
|
|
+ kev = sev->events + sev_pos(sev, sev->in_use);
|
|
|
kev->event.type = ev->type;
|
|
|
kev->event.u = ev->u;
|
|
|
kev->event.id = ev->id;
|
|
|
kev->event.timestamp = *ts;
|
|
|
kev->event.sequence = fh->sequence;
|
|
|
- list_move_tail(&kev->list, &fh->available);
|
|
|
+ sev->in_use++;
|
|
|
+ list_add_tail(&kev->list, &fh->available);
|
|
|
|
|
|
fh->navailable++;
|
|
|
|
|
@@ -209,38 +185,39 @@ int v4l2_event_pending(struct v4l2_fh *fh)
|
|
|
EXPORT_SYMBOL_GPL(v4l2_event_pending);
|
|
|
|
|
|
int v4l2_event_subscribe(struct v4l2_fh *fh,
|
|
|
- struct v4l2_event_subscription *sub)
|
|
|
+ struct v4l2_event_subscription *sub, unsigned elems)
|
|
|
{
|
|
|
struct v4l2_subscribed_event *sev, *found_ev;
|
|
|
struct v4l2_ctrl *ctrl = NULL;
|
|
|
unsigned long flags;
|
|
|
+ unsigned i;
|
|
|
|
|
|
+ if (elems < 1)
|
|
|
+ elems = 1;
|
|
|
if (sub->type == V4L2_EVENT_CTRL) {
|
|
|
ctrl = v4l2_ctrl_find(fh->ctrl_handler, sub->id);
|
|
|
if (ctrl == NULL)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- sev = kzalloc(sizeof(*sev), GFP_KERNEL);
|
|
|
+ sev = kzalloc(sizeof(*sev) + sizeof(struct v4l2_kevent) * elems, GFP_KERNEL);
|
|
|
if (!sev)
|
|
|
return -ENOMEM;
|
|
|
+ for (i = 0; i < elems; i++)
|
|
|
+ sev->events[i].sev = sev;
|
|
|
+ sev->type = sub->type;
|
|
|
+ sev->id = sub->id;
|
|
|
+ sev->flags = sub->flags;
|
|
|
+ sev->fh = fh;
|
|
|
+ sev->elems = elems;
|
|
|
|
|
|
spin_lock_irqsave(&fh->vdev->fh_lock, flags);
|
|
|
-
|
|
|
found_ev = v4l2_event_subscribed(fh, sub->type, sub->id);
|
|
|
- if (!found_ev) {
|
|
|
- INIT_LIST_HEAD(&sev->list);
|
|
|
- sev->type = sub->type;
|
|
|
- sev->id = sub->id;
|
|
|
- sev->fh = fh;
|
|
|
- sev->flags = sub->flags;
|
|
|
-
|
|
|
+ if (!found_ev)
|
|
|
list_add(&sev->list, &fh->subscribed);
|
|
|
- }
|
|
|
-
|
|
|
spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
|
|
|
|
|
|
- /* v4l2_ctrl_add_fh uses a mutex, so do this outside the spin lock */
|
|
|
+ /* v4l2_ctrl_add_event uses a mutex, so do this outside the spin lock */
|
|
|
if (found_ev)
|
|
|
kfree(sev);
|
|
|
else if (ctrl)
|
|
@@ -250,7 +227,7 @@ int v4l2_event_subscribe(struct v4l2_fh *fh,
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(v4l2_event_subscribe);
|
|
|
|
|
|
-static void v4l2_event_unsubscribe_all(struct v4l2_fh *fh)
|
|
|
+void v4l2_event_unsubscribe_all(struct v4l2_fh *fh)
|
|
|
{
|
|
|
struct v4l2_event_subscription sub;
|
|
|
struct v4l2_subscribed_event *sev;
|
|
@@ -271,6 +248,7 @@ static void v4l2_event_unsubscribe_all(struct v4l2_fh *fh)
|
|
|
v4l2_event_unsubscribe(fh, &sub);
|
|
|
} while (sev);
|
|
|
}
|
|
|
+EXPORT_SYMBOL_GPL(v4l2_event_unsubscribe_all);
|
|
|
|
|
|
int v4l2_event_unsubscribe(struct v4l2_fh *fh,
|
|
|
struct v4l2_event_subscription *sub)
|