public inbox for linux-media@vger.kernel.org
 help / color / mirror / Atom feed
* [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