* [RFC 0/4] V4L2 file handles and event interface
@ 2009-12-15 12:12 Sakari Ailus
2009-12-15 12:19 ` [RFC 1/4] V4L: File handles Sakari Ailus
0 siblings, 1 reply; 5+ messages in thread
From: Sakari Ailus @ 2009-12-15 12:12 UTC (permalink / raw)
To: linux-media@vger.kernel.org
Cc: Laurent Pinchart, Hans Verkuil, Guru Raj, Mauro Carvalho Chehab,
Mike Krufky, Devin Heitmueller, Ivan T. Ivanov, Zutshi Vimarsh
Hi,
Here's the first version of the V4L2 file handle and event interface
patchset. I posted it as RFC since there are a few issues with the
contents and I have no assurrances that this even is functional at the
moment.
The first patch adds the V4L2 file handle support and the rest are for
V4L2 events.
A few notes on the patches:
- I don't like the locking too much. Perhaps the file handle specific
lock (events->lock) could be dropped in favour of the lock for
v4l2_file_handle in video_device.
- Event queue depth is not controlled at the moment.
- (Un)subscribing all events is not supported.
Comments are very welcome.
Cheers,
--
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com
^ permalink raw reply [flat|nested] 5+ messages in thread
* [RFC 1/4] V4L: File handles
2009-12-15 12:12 [RFC 0/4] V4L2 file handles and event interface Sakari Ailus
@ 2009-12-15 12:19 ` Sakari Ailus
2009-12-15 12:19 ` [RFC 2/4] V4L: Events: Add new ioctls for events Sakari Ailus
0 siblings, 1 reply; 5+ messages in thread
From: Sakari Ailus @ 2009-12-15 12:19 UTC (permalink / raw)
To: linux-media
Cc: laurent.pinchart, hverkuil, gururaj.nagendra, mchehab, mkrufky,
dheitmueller, iivanov, vimarsh.zutshi
This patch adds a list of v4l2_file_handle structures to every video_device.
It allows using file handle related information in V4L2. The event interface
is one example of such use.
Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
---
drivers/media/video/Makefile | 2 +-
drivers/media/video/v4l2-dev.c | 7 +++-
drivers/media/video/v4l2-fh.c | 95 ++++++++++++++++++++++++++++++++++++++++
include/media/v4l2-dev.h | 4 ++
include/media/v4l2-fh.h | 45 +++++++++++++++++++
5 files changed, 151 insertions(+), 2 deletions(-)
create mode 100644 drivers/media/video/v4l2-fh.c
create mode 100644 include/media/v4l2-fh.h
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index a61e3f3..1947146 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -10,7 +10,7 @@ stkwebcam-objs := stk-webcam.o stk-sensor.o
omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o
-videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o
+videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o
# V4L2 core modules
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 7090699..387a302 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -283,7 +283,8 @@ static int v4l2_open(struct inode *inode, struct file *filp)
/* and increase the device refcount */
video_get(vdev);
mutex_unlock(&videodev_lock);
- if (vdev->fops->open)
+ ret = v4l2_file_handle_add(vdev, filp);
+ if (!ret && vdev->fops->open)
ret = vdev->fops->open(filp);
/* decrease the refcount in case of an error */
@@ -301,6 +302,8 @@ static int v4l2_release(struct inode *inode, struct file *filp)
if (vdev->fops->release)
vdev->fops->release(filp);
+ v4l2_file_handle_del(vdev, filp);
+
/* decrease the refcount unconditionally since the release()
return value is ignored. */
video_put(vdev);
@@ -421,6 +424,8 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
if (!vdev->release)
return -EINVAL;
+ v4l2_file_handle_init(vdev);
+
/* Part 1: check device type */
switch (type) {
case VFL_TYPE_GRABBER:
diff --git a/drivers/media/video/v4l2-fh.c b/drivers/media/video/v4l2-fh.c
new file mode 100644
index 0000000..52cb3b3
--- /dev/null
+++ b/drivers/media/video/v4l2-fh.c
@@ -0,0 +1,95 @@
+/*
+ * drivers/media/video/v4l2-fh.c
+ *
+ * V4L2 file handles.
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
+
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+
+static struct v4l2_file_handle *__v4l2_file_handle_get(
+ struct video_device *vdev, struct file *filp)
+{
+ struct v4l2_file_handle *fh;
+
+ list_for_each_entry(fh, &vdev->fh, list) {
+ if (fh->filp == filp)
+ return fh;
+ }
+
+ return NULL;
+}
+
+struct v4l2_file_handle *v4l2_file_handle_get(struct video_device *vdev,
+ struct file *filp)
+{
+ struct v4l2_file_handle *fh;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vdev->fh_lock, flags);
+ fh = __v4l2_file_handle_get(vdev, filp);
+ spin_unlock_irqrestore(&vdev->fh_lock, flags);
+
+ return fh;
+}
+EXPORT_SYMBOL_GPL(v4l2_file_handle_get);
+
+int v4l2_file_handle_add(struct video_device *vdev, struct file *filp)
+{
+ struct v4l2_file_handle *fh;
+ unsigned long flags;
+
+ fh = kmalloc(sizeof(*fh), GFP_KERNEL);
+ if (!fh)
+ return -ENOMEM;
+
+ fh->filp = filp;
+
+ spin_lock_irqsave(&vdev->fh_lock, flags);
+ list_add(&fh->list, &vdev->fh);
+ spin_unlock_irqrestore(&vdev->fh_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_file_handle_add);
+
+void v4l2_file_handle_del(struct video_device *vdev, struct file *filp)
+{
+ struct v4l2_file_handle *fh = v4l2_file_handle_get(vdev, filp);
+ unsigned long flags;
+
+ spin_lock_irqsave(&vdev->fh_lock, flags);
+ list_del(&fh->list);
+ spin_unlock_irqrestore(&vdev->fh_lock, flags);
+
+ kfree(fh);
+}
+EXPORT_SYMBOL_GPL(v4l2_file_handle_del);
+
+void v4l2_file_handle_init(struct video_device *vdev)
+{
+ spin_lock_init(&vdev->fh_lock);
+ INIT_LIST_HEAD(&vdev->fh);
+}
+EXPORT_SYMBOL_GPL(v4l2_file_handle_init);
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index 2dee938..8eac93d 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -16,6 +16,8 @@
#include <linux/mutex.h>
#include <linux/videodev2.h>
+#include <media/v4l2-fh.h>
+
#define VIDEO_MAJOR 81
#define VFL_TYPE_GRABBER 0
@@ -77,6 +79,8 @@ struct video_device
/* attribute to differentiate multiple indices on one physical device */
int index;
+ spinlock_t fh_lock; /* Lock for file handle list */
+ struct list_head fh; /* File handle list */
int debug; /* Activates debug level*/
/* Video standard vars */
diff --git a/include/media/v4l2-fh.h b/include/media/v4l2-fh.h
new file mode 100644
index 0000000..5c9d08b
--- /dev/null
+++ b/include/media/v4l2-fh.h
@@ -0,0 +1,45 @@
+/*
+ * include/media/v4l2-fh.h
+ *
+ * V4L2 file handle.
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef V4L2_FH_H
+#define V4L2_FH_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+struct v4l2_file_handle {
+ struct list_head list;
+ struct file *filp;
+};
+
+struct video_device;
+
+struct v4l2_file_handle *v4l2_file_handle_get(struct video_device *vdev,
+ struct file *filp);
+int __must_check v4l2_file_handle_add(struct video_device *vdev,
+ struct file *filp);
+void v4l2_file_handle_del(struct video_device *vdev, struct file *filp);
+void v4l2_file_handle_init(struct video_device *vdev);
+
+#endif /* V4L2_EVENT_H */
--
1.5.6.5
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [RFC 2/4] V4L: Events: Add new ioctls for events
2009-12-15 12:19 ` [RFC 1/4] V4L: File handles Sakari Ailus
@ 2009-12-15 12:19 ` Sakari Ailus
2009-12-15 12:19 ` [RFC 3/4] V4L: Events: Support event handling in do_ioctl Sakari Ailus
0 siblings, 1 reply; 5+ messages in thread
From: Sakari Ailus @ 2009-12-15 12:19 UTC (permalink / raw)
To: linux-media
Cc: laurent.pinchart, hverkuil, gururaj.nagendra, mchehab, mkrufky,
dheitmueller, iivanov, vimarsh.zutshi
This patch adds a set of new ioctls to the V4L2 API. The ioctls conform to
V4L2 Events RFC version 2.3:
<URL:http://www.spinics.net/lists/linux-media/msg12033.html>
Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
---
drivers/media/video/v4l2-compat-ioctl32.c | 3 +++
drivers/media/video/v4l2-ioctl.c | 3 +++
include/linux/videodev2.h | 24 ++++++++++++++++++++++++
3 files changed, 30 insertions(+), 0 deletions(-)
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index 997975d..cba704c 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -1077,6 +1077,9 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
case VIDIOC_DBG_G_REGISTER:
case VIDIOC_DBG_G_CHIP_IDENT:
case VIDIOC_S_HW_FREQ_SEEK:
+ case VIDIOC_DQEVENT:
+ case VIDIOC_SUBSCRIBE_EVENT:
+ case VIDIOC_UNSUBSCRIBE_EVENT:
ret = do_video_ioctl(file, cmd, arg);
break;
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 30cc334..bfc4696 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -283,6 +283,9 @@ static const char *v4l2_ioctls[] = {
[_IOC_NR(VIDIOC_DBG_G_CHIP_IDENT)] = "VIDIOC_DBG_G_CHIP_IDENT",
[_IOC_NR(VIDIOC_S_HW_FREQ_SEEK)] = "VIDIOC_S_HW_FREQ_SEEK",
+ [_IOC_NR(VIDIOC_DQEVENT)] = "VIDIOC_DQEVENT",
+ [_IOC_NR(VIDIOC_SUBSCRIBE_EVENT)] = "VIDIOC_SUBSCRIBE_EVENT",
+ [_IOC_NR(VIDIOC_UNSUBSCRIBE_EVENT)] = "VIDIOC_UNSUBSCRIBE_EVENT",
#endif
};
#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 54af357..397f8eb 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1536,6 +1536,27 @@ struct v4l2_streamparm {
};
/*
+ * E V E N T S
+ */
+
+struct v4l2_event {
+ __u32 count;
+ __u32 type;
+ __u32 sequence;
+ struct timespec timestamp;
+ __u32 reserved[8];
+ __u8 data[64];
+};
+
+struct v4l2_event_subscription {
+ __u32 type;
+ __u32 reserved[8];
+};
+
+#define V4L2_EVENT_ALL 0
+#define V4L2_EVENT_PRIVATE_START 0x08000000
+
+/*
* A D V A N C E D D E B U G G I N G
*
* NOTE: EXPERIMENTAL API, NEVER RELY ON THIS IN APPLICATIONS!
@@ -1651,6 +1672,9 @@ struct v4l2_dbg_chip_ident {
#endif
#define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek)
+#define VIDIOC_DQEVENT _IOR('V', 83, struct v4l2_event)
+#define VIDIOC_SUBSCRIBE_EVENT _IOW('V', 84, struct v4l2_event_subscription)
+#define VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 85, struct v4l2_event_subscription)
/* Reminder: when adding new ioctls please add support for them to
drivers/media/video/v4l2-compat-ioctl32.c as well! */
--
1.5.6.5
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [RFC 3/4] V4L: Events: Support event handling in do_ioctl
2009-12-15 12:19 ` [RFC 2/4] V4L: Events: Add new ioctls for events Sakari Ailus
@ 2009-12-15 12:19 ` Sakari Ailus
2009-12-15 12:19 ` [RFC 4/4] V4L: Events: Add backend Sakari Ailus
0 siblings, 1 reply; 5+ messages in thread
From: Sakari Ailus @ 2009-12-15 12:19 UTC (permalink / raw)
To: linux-media
Cc: laurent.pinchart, hverkuil, gururaj.nagendra, mchehab, mkrufky,
dheitmueller, iivanov, vimarsh.zutshi
Add support for event handling to do_ioctl.
Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
---
drivers/media/video/v4l2-ioctl.c | 48 ++++++++++++++++++++++++++++++++++++++
include/media/v4l2-ioctl.h | 7 +++++
2 files changed, 55 insertions(+), 0 deletions(-)
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index bfc4696..067ab3a 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -1797,7 +1797,55 @@ static long __video_do_ioctl(struct file *file,
}
break;
}
+ case VIDIOC_DQEVENT:
+ {
+ struct v4l2_event *ev = arg;
+
+ if (!ops->vidioc_dqevent)
+ break;
+
+ ret = ops->vidioc_dqevent(file, ev);
+ if (ret < 0) {
+ dbgarg(cmd, "no pending events?");
+ break;
+ }
+ dbgarg(cmd,
+ "count=%d, type=0x%8.8x, sequence=%d, "
+ "timestamp=%d.%9.9lu ",
+ ev->count, ev->type, ev->sequence,
+ (int)ev->timestamp.tv_sec, ev->timestamp.tv_nsec);
+ break;
+ }
+ case VIDIOC_SUBSCRIBE_EVENT:
+ {
+ struct v4l2_event_subscription *sub = arg;
+ if (!ops->vidioc_subscribe_event)
+ break;
+
+ ret = ops->vidioc_subscribe_event(file, sub);
+ if (ret < 0) {
+ dbgarg(cmd, "failed, ret=%ld", ret);
+ break;
+ }
+ dbgarg(cmd, "type=0x%8.8x", sub->type);
+ break;
+ }
+ case VIDIOC_UNSUBSCRIBE_EVENT:
+ {
+ struct v4l2_event_subscription *sub = arg;
+
+ if (!ops->vidioc_unsubscribe_event)
+ break;
+
+ ret = ops->vidioc_unsubscribe_event(file, sub);
+ if (ret < 0) {
+ dbgarg(cmd, "failed, ret=%ld", ret);
+ break;
+ }
+ dbgarg(cmd, "type=0x%8.8x", sub->type);
+ break;
+ }
default:
{
if (!ops->vidioc_default)
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index 7a4529d..77a71cc 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -239,6 +239,13 @@ struct v4l2_ioctl_ops {
int (*vidioc_enum_frameintervals) (struct file *file, void *fh,
struct v4l2_frmivalenum *fival);
+ int (*vidioc_dqevent) (struct file *file,
+ struct v4l2_event *ev);
+ int (*vidioc_subscribe_event) (struct file *file,
+ struct v4l2_event_subscription *sub);
+ int (*vidioc_unsubscribe_event) (struct file *file,
+ struct v4l2_event_subscription *sub);
+
/* For other private ioctls */
long (*vidioc_default) (struct file *file, void *fh,
int cmd, void *arg);
--
1.5.6.5
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [RFC 4/4] V4L: Events: Add backend
2009-12-15 12:19 ` [RFC 3/4] V4L: Events: Support event handling in do_ioctl Sakari Ailus
@ 2009-12-15 12:19 ` Sakari Ailus
0 siblings, 0 replies; 5+ messages in thread
From: Sakari Ailus @ 2009-12-15 12:19 UTC (permalink / raw)
To: linux-media
Cc: laurent.pinchart, hverkuil, gururaj.nagendra, mchehab, mkrufky,
dheitmueller, iivanov, vimarsh.zutshi
Add event handling backend to V4L2. The backend handles event subscription
and delivery to file handles. Event subscriptions are based on file handle.
Events may be delivered to all subscribed file handles on a device
independent of where they originate from.
Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
---
drivers/media/video/Makefile | 3 +-
drivers/media/video/v4l2-event.c | 254 ++++++++++++++++++++++++++++++++++++++
drivers/media/video/v4l2-fh.c | 9 ++
include/media/v4l2-event.h | 73 +++++++++++
include/media/v4l2-fh.h | 3 +
5 files changed, 341 insertions(+), 1 deletions(-)
create mode 100644 drivers/media/video/v4l2-event.c
create mode 100644 include/media/v4l2-event.h
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 1947146..dd6a853 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -10,7 +10,8 @@ stkwebcam-objs := stk-webcam.o stk-sensor.o
omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o
-videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o
+videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
+ v4l2-event.o
# V4L2 core modules
diff --git a/drivers/media/video/v4l2-event.c b/drivers/media/video/v4l2-event.c
new file mode 100644
index 0000000..91c3acc
--- /dev/null
+++ b/drivers/media/video/v4l2-event.c
@@ -0,0 +1,254 @@
+/*
+ * drivers/media/video/v4l2-event.c
+ *
+ * V4L2 events.
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-event.h>
+
+#include <linux/sched.h>
+
+static struct kmem_cache *event_kmem;
+
+static void v4l2_event_kmem_ctor(void *ptr)
+{
+ struct _v4l2_event *ev = ptr;
+
+ INIT_LIST_HEAD(&ev->list);
+}
+
+int v4l2_event_init(struct v4l2_events *events)
+{
+ if (!event_kmem)
+ event_kmem = kmem_cache_create("event_kmem",
+ sizeof(struct _v4l2_event), 0,
+ SLAB_HWCACHE_ALIGN,
+ &v4l2_event_kmem_ctor);
+
+ if (!event_kmem)
+ return -ENOMEM;
+
+ init_waitqueue_head(&events->wait);
+ spin_lock_init(&events->lock);
+
+ INIT_LIST_HEAD(&events->available);
+ INIT_LIST_HEAD(&events->subscribed);
+
+ return 0;
+};
+EXPORT_SYMBOL_GPL(v4l2_event_init);
+
+void v4l2_event_exit(struct v4l2_events *events)
+{
+ while (!list_empty(&events->available)) {
+ struct _v4l2_event *ev;
+
+ ev = list_entry(events->available.next,
+ struct _v4l2_event, list);
+
+ list_del(&ev->list);
+
+ kmem_cache_free(event_kmem, ev);
+ }
+
+ while (!list_empty(&events->subscribed)) {
+ struct v4l2_subscribed_event *sub;
+
+ sub = list_entry(events->subscribed.next,
+ struct v4l2_subscribed_event, list);
+
+ list_del(&sub->list);
+
+ kfree(sub);
+ }
+}
+EXPORT_SYMBOL_GPL(v4l2_event_exit);
+
+int v4l2_event_dequeue(struct v4l2_events *events, struct v4l2_event *event)
+{
+ struct _v4l2_event *ev;
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&events->lock, flags);
+
+ if (list_empty(&events->available)) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ev = list_first_entry(&events->available, struct _v4l2_event, list);
+ list_del(&ev->list);
+
+ ev->event.count = !list_empty(&events->available);
+
+ memcpy(event, &ev->event, sizeof(ev->event));
+
+ kmem_cache_free(event_kmem, ev);
+
+out:
+
+ spin_unlock_irqrestore(&events->lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_dequeue);
+
+static struct _v4l2_event *v4l2_event_queue_get(struct v4l2_events *events)
+{
+ return kmem_cache_alloc(event_kmem, GFP_KERNEL | GFP_ATOMIC);
+}
+
+static void v4l2_event_queue_put(struct v4l2_events *events,
+ struct _v4l2_event *ev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&events->lock, flags);
+
+ list_add(&ev->list, &events->available);
+
+ spin_unlock_irqrestore(&events->lock, flags);
+
+ wake_up_all(&events->wait);
+}
+
+static struct v4l2_subscribed_event *__v4l2_event_subscribed(
+ struct v4l2_events *events, u32 type)
+{
+ struct v4l2_subscribed_event *ev;
+
+ list_for_each_entry(ev, &events->subscribed, list) {
+ if (ev->type == type)
+ return ev;
+ }
+
+ return NULL;
+}
+
+struct v4l2_subscribed_event *v4l2_event_subscribed(
+ struct v4l2_events *events, u32 type)
+{
+ struct v4l2_subscribed_event *ev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&events->lock, flags);
+
+ ev = __v4l2_event_subscribed(events, type);
+
+ spin_unlock_irqrestore(&events->lock, flags);
+
+ return ev;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_subscribed);
+
+void v4l2_event_queue(struct video_device *vdev, struct v4l2_event *ev)
+{
+ struct v4l2_file_handle *fh;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vdev->fh_lock, flags);
+
+ list_for_each_entry(fh, &vdev->fh, list) {
+ struct _v4l2_event *_ev;
+
+ if (!v4l2_event_subscribed(&fh->events, ev->type))
+ continue;
+
+ _ev = v4l2_event_queue_get(&fh->events);
+ if (!_ev)
+ continue;
+
+ _ev->event = *ev;
+ v4l2_event_queue_put(&fh->events, _ev);
+
+ printk(KERN_ALERT "deliver to some fh\n");
+ }
+
+ spin_unlock_irqrestore(&vdev->fh_lock, flags);
+}
+EXPORT_SYMBOL_GPL(v4l2_event_queue);
+
+int v4l2_event_pending(struct v4l2_events *events)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&events->lock, flags);
+ ret = list_empty(&events->available);
+ spin_unlock_irqrestore(&events->lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_pending);
+
+int v4l2_event_subscribe(struct v4l2_events *events,
+ struct v4l2_event_subscription *sub)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct v4l2_subscribed_event *ev;
+
+ ev = kmalloc(sizeof(*ev), GFP_KERNEL);
+ if (!ev)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&events->lock, flags);
+
+ if (__v4l2_event_subscribed(events, sub->type) != NULL) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ INIT_LIST_HEAD(&ev->list);
+ ev->type = sub->type;
+
+ list_add(&ev->list, &events->subscribed);
+
+out:
+ spin_unlock_irqrestore(&events->lock, flags);
+
+ if (ret)
+ kfree(ev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_subscribe);
+
+int v4l2_event_unsubscribe(struct v4l2_events *events,
+ struct v4l2_event_subscription *sub)
+{
+ struct v4l2_subscribed_event *ev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&events->lock, flags);
+
+ ev = __v4l2_event_subscribed(events, sub->type);
+
+ if (ev != NULL)
+ list_del(&ev->list);
+
+ spin_unlock_irqrestore(&events->lock, flags);
+
+ return ev == NULL;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_unsubscribe);
diff --git a/drivers/media/video/v4l2-fh.c b/drivers/media/video/v4l2-fh.c
index 52cb3b3..a8d4318 100644
--- a/drivers/media/video/v4l2-fh.c
+++ b/drivers/media/video/v4l2-fh.c
@@ -59,6 +59,7 @@ int v4l2_file_handle_add(struct video_device *vdev, struct file *filp)
{
struct v4l2_file_handle *fh;
unsigned long flags;
+ int ret;
fh = kmalloc(sizeof(*fh), GFP_KERNEL);
if (!fh)
@@ -66,6 +67,12 @@ int v4l2_file_handle_add(struct video_device *vdev, struct file *filp)
fh->filp = filp;
+ ret = v4l2_event_init(&fh->events);
+ if (ret) {
+ kfree(fh);
+ return ret;
+ }
+
spin_lock_irqsave(&vdev->fh_lock, flags);
list_add(&fh->list, &vdev->fh);
spin_unlock_irqrestore(&vdev->fh_lock, flags);
@@ -79,6 +86,8 @@ void v4l2_file_handle_del(struct video_device *vdev, struct file *filp)
struct v4l2_file_handle *fh = v4l2_file_handle_get(vdev, filp);
unsigned long flags;
+ v4l2_event_exit(&fh->events);
+
spin_lock_irqsave(&vdev->fh_lock, flags);
list_del(&fh->list);
spin_unlock_irqrestore(&vdev->fh_lock, flags);
diff --git a/include/media/v4l2-event.h b/include/media/v4l2-event.h
new file mode 100644
index 0000000..6984fea
--- /dev/null
+++ b/include/media/v4l2-event.h
@@ -0,0 +1,73 @@
+/*
+ * include/media/v4l2-event.h
+ *
+ * V4L2 events.
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef V4L2_EVENT_H
+#define V4L2_EVENT_H
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/videodev2.h>
+
+#define V4L2_MAX_EVENTS 1024 /* Ought to be enough for everyone. */
+
+struct video_device;
+
+struct _v4l2_event {
+ struct list_head list;
+ struct v4l2_event event;
+};
+
+struct v4l2_events {
+ spinlock_t lock; /* Protect everything here. */
+ struct list_head available;
+ wait_queue_head_t wait;
+ struct list_head subscribed; /* Subscribed events. */
+};
+
+struct v4l2_subscribed_event {
+ struct list_head list;
+ u32 type;
+};
+
+int v4l2_event_init(struct v4l2_events *events);
+void v4l2_event_exit(struct v4l2_events *events);
+
+int v4l2_event_dequeue(struct v4l2_events *events, struct v4l2_event *event);
+
+struct v4l2_subscribed_event *v4l2_event_subscribed(struct v4l2_events *sub,
+ u32 type);
+
+void v4l2_event_queue(struct video_device *vdev, struct v4l2_event *ev);
+int v4l2_event_pending(struct v4l2_events *events);
+
+int v4l2_event_subscribe(struct v4l2_events *sub,
+ struct v4l2_event_subscription *s);
+int v4l2_event_unsubscribe(struct v4l2_events *sub,
+ struct v4l2_event_subscription *s);
+void v4l2_event_sub_init(struct v4l2_events *sub);
+void v4l2_event_sub_exit(struct v4l2_events *sub);
+
+#endif /* V4L2_EVENT_H */
diff --git a/include/media/v4l2-fh.h b/include/media/v4l2-fh.h
index 5c9d08b..6e92014 100644
--- a/include/media/v4l2-fh.h
+++ b/include/media/v4l2-fh.h
@@ -28,9 +28,12 @@
#include <linux/types.h>
#include <linux/list.h>
+#include <media/v4l2-event.h>
+
struct v4l2_file_handle {
struct list_head list;
struct file *filp;
+ struct v4l2_events events; /* events, pending and subscribed */
};
struct video_device;
--
1.5.6.5
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2009-12-15 12:20 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-12-15 12:12 [RFC 0/4] V4L2 file handles and event interface Sakari Ailus
2009-12-15 12:19 ` [RFC 1/4] V4L: File handles Sakari Ailus
2009-12-15 12:19 ` [RFC 2/4] V4L: Events: Add new ioctls for events Sakari Ailus
2009-12-15 12:19 ` [RFC 3/4] V4L: Events: Support event handling in do_ioctl Sakari Ailus
2009-12-15 12:19 ` [RFC 4/4] V4L: Events: Add backend Sakari Ailus
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox