linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH v1 0/7] media&omap4: introduce face detection(FD) driver
@ 2011-12-02  9:12 Ming Lei
  2011-12-02  9:12 ` [RFC PATCH v1 1/7] omap4: introduce fdif(face detect module) hwmod Ming Lei
                   ` (7 more replies)
  0 siblings, 8 replies; 26+ messages in thread
From: Ming Lei @ 2011-12-02  9:12 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

These v1 patches(against -next tree) introduce v4l2 based face
detection(FD) device driver, and enable FD hardware[1] on omap4 SoC..
The idea of implementing it on v4l2 is from from Alan Cox, Sylwester
and Greg-Kh.

For verification purpose, I write one user space utility[2] to
test the module and driver, follows its basic functions:

	- detect faces in input grayscal picture(PGM raw, 320 by 240)
	- detect faces in input y8 format video stream
	- plot a rectangle to mark the detected faces, and save it as 
	another same format picture or video stream

Looks the performance of the module is not bad, see some detection
results on the link[3][4].

Face detection can be used to implement some interesting applications
(camera, face unlock, baby monitor, ...).

TODO:
	- implement FD setting interfaces with v4l2 controls or
	ext controls

thanks,
--
Ming Lei

[1], Ch9 of OMAP4 Technical Reference Manual
[2], http://kernel.ubuntu.com/git?p=ming/fdif.git;a=shortlog;h=refs/heads/v4l2-fdif
[3], http://kernel.ubuntu.com/~ming/dev/fdif/output
[4], All pictures are taken from http://www.google.com/imghp
and converted to pnm from jpeg format, only for test purpose.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 1/7] omap4: introduce fdif(face detect module) hwmod
  2011-12-02  9:12 [RFC PATCH v1 0/7] media&omap4: introduce face detection(FD) driver Ming Lei
@ 2011-12-02  9:12 ` Ming Lei
  2011-12-13  2:42   ` Ming Lei
  2011-12-02  9:12 ` [RFC PATCH v1 2/7] omap4: build fdif omap device from hwmod Ming Lei
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 26+ messages in thread
From: Ming Lei @ 2011-12-02  9:12 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Ming Lei <ming.lei@canonical.com>
---
 arch/arm/mach-omap2/omap_hwmod_44xx_data.c |   81 ++++++++++++++++++++++++++++
 1 files changed, 81 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index 6cf21ee..30db754 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -53,6 +53,7 @@ static struct omap_hwmod omap44xx_dmm_hwmod;
 static struct omap_hwmod omap44xx_dsp_hwmod;
 static struct omap_hwmod omap44xx_dss_hwmod;
 static struct omap_hwmod omap44xx_emif_fw_hwmod;
+static struct omap_hwmod omap44xx_fdif_hwmod;
 static struct omap_hwmod omap44xx_hsi_hwmod;
 static struct omap_hwmod omap44xx_ipu_hwmod;
 static struct omap_hwmod omap44xx_iss_hwmod;
@@ -354,6 +355,14 @@ static struct omap_hwmod_ocp_if omap44xx_dma_system__l3_main_2 = {
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+/* fdif -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_fdif__l3_main_2 = {
+	.master		= &omap44xx_fdif_hwmod,
+	.slave		= &omap44xx_l3_main_2_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 /* hsi -> l3_main_2 */
 static struct omap_hwmod_ocp_if omap44xx_hsi__l3_main_2 = {
 	.master		= &omap44xx_hsi_hwmod,
@@ -5444,6 +5453,75 @@ static struct omap_hwmod omap44xx_wd_timer3_hwmod = {
 	.slaves_cnt	= ARRAY_SIZE(omap44xx_wd_timer3_slaves),
 };
 
+/* 'fdif' class */
+static struct omap_hwmod_class_sysconfig omap44xx_fdif_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.sysc_flags	= (SYSC_HAS_MIDLEMODE | SYSC_HAS_RESET_STATUS |
+			   SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			   MSTANDBY_FORCE | MSTANDBY_NO |
+			   MSTANDBY_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_fdif_hwmod_class = {
+	.name	= "fdif",
+	.sysc	= &omap44xx_fdif_sysc,
+};
+
+/*fdif*/
+static struct omap_hwmod_addr_space omap44xx_fdif_addrs[] = {
+	{
+		.pa_start	= 0x4a10a000,
+		.pa_end		= 0x4a10afff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+/* l4_cfg -> fdif */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__fdif = {
+	.master		= &omap44xx_l4_cfg_hwmod,
+	.slave		= &omap44xx_fdif_hwmod,
+	.clk		= "l4_div_ck",
+	.addr		= omap44xx_fdif_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* fdif slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_fdif_slaves[] = {
+	&omap44xx_l4_cfg__fdif,
+};
+static struct omap_hwmod_irq_info omap44xx_fdif_irqs[] = {
+	{ .irq = 69 + OMAP44XX_IRQ_GIC_START },
+	{ .irq = -1 }
+};
+
+/* fdif master ports */
+static struct omap_hwmod_ocp_if *omap44xx_fdif_masters[] = {
+	&omap44xx_fdif__l3_main_2,
+};
+
+static struct omap_hwmod omap44xx_fdif_hwmod = {
+	.name		= "fdif",
+	.class		= &omap44xx_fdif_hwmod_class,
+	.clkdm_name	= "iss_clkdm",
+	.mpu_irqs	= omap44xx_fdif_irqs,
+	.main_clk	= "fdif_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = OMAP4_CM_CAM_FDIF_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_CAM_FDIF_CONTEXT_OFFSET,
+			.modulemode   = MODULEMODE_SWCTRL,
+		},
+	},
+	.slaves		= omap44xx_fdif_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_fdif_slaves),
+	.masters	= omap44xx_fdif_masters,
+	.masters_cnt	= ARRAY_SIZE(omap44xx_fdif_masters),
+};
+
 static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
 
 	/* dmm class */
@@ -5593,6 +5671,9 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
 	&omap44xx_wd_timer2_hwmod,
 	&omap44xx_wd_timer3_hwmod,
 
+	/* fdif class */
+	&omap44xx_fdif_hwmod,
+
 	NULL,
 };
 
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 2/7] omap4: build fdif omap device from hwmod
  2011-12-02  9:12 [RFC PATCH v1 0/7] media&omap4: introduce face detection(FD) driver Ming Lei
  2011-12-02  9:12 ` [RFC PATCH v1 1/7] omap4: introduce fdif(face detect module) hwmod Ming Lei
@ 2011-12-02  9:12 ` Ming Lei
  2011-12-02 12:10   ` Sergei Shtylyov
  2011-12-02  9:12 ` [RFC PATCH v1 3/7] media: videobuf2: move out of setting pgprot_noncached from vb2_mmap_pfn_range Ming Lei
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 26+ messages in thread
From: Ming Lei @ 2011-12-02  9:12 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Ming Lei <ming.lei@canonical.com>
---
 arch/arm/mach-omap2/devices.c |   33 +++++++++++++++++++++++++++++++++
 1 files changed, 33 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 1166bdc..a392af5 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -728,6 +728,38 @@ void __init omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data)
 
 #endif
 
+static struct platform_device* __init omap4_init_fdif(void)
+{
+	int id = -1;
+	struct platform_device *pd;
+	struct omap_hwmod *oh;
+	const char *dev_name = "fdif";
+
+	oh = omap_hwmod_lookup("fdif");
+	if (!oh) {
+		pr_err("Could not look up fdif hwmod\n");
+		return NULL;
+	}
+
+	pd = omap_device_build(dev_name, id, oh, NULL, 0, NULL, 0, 0);
+	WARN(IS_ERR(pd), "Can't build omap_device for %s.\n",
+				dev_name);
+	return pd;
+}
+
+static void __init omap_init_fdif(void)
+{
+	if (cpu_is_omap44xx()) {
+		struct platform_device *pd;
+
+		pd = omap4_init_fdif();
+		if (!pd)
+			return;
+
+		pm_runtime_enable(&pd->dev);
+	}
+}
+
 /*-------------------------------------------------------------------------*/
 
 #if defined(CONFIG_HDQ_MASTER_OMAP) || defined(CONFIG_HDQ_MASTER_OMAP_MODULE)
@@ -808,6 +840,7 @@ static int __init omap2_init_devices(void)
 	omap_init_sham();
 	omap_init_aes();
 	omap_init_vout();
+	omap_init_fdif();
 
 	return 0;
 }
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 3/7] media: videobuf2: move out of setting pgprot_noncached from vb2_mmap_pfn_range
  2011-12-02  9:12 [RFC PATCH v1 0/7] media&omap4: introduce face detection(FD) driver Ming Lei
  2011-12-02  9:12 ` [RFC PATCH v1 1/7] omap4: introduce fdif(face detect module) hwmod Ming Lei
  2011-12-02  9:12 ` [RFC PATCH v1 2/7] omap4: build fdif omap device from hwmod Ming Lei
@ 2011-12-02  9:12 ` Ming Lei
  2011-12-02  9:12 ` [RFC PATCH v1 4/7] media: videobuf2: introduce VIDEOBUF2_PAGE memops Ming Lei
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Ming Lei @ 2011-12-02  9:12 UTC (permalink / raw)
  To: linux-arm-kernel

So that we can reuse vb2_mmap_pfn_range for the coming videobuf2_page
memops.

Signed-off-by: Ming Lei <ming.lei@canonical.com>
---
 drivers/media/video/videobuf2-dma-contig.c |    1 +
 drivers/media/video/videobuf2-memops.c     |    1 -
 2 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/media/video/videobuf2-dma-contig.c b/drivers/media/video/videobuf2-dma-contig.c
index f17ad98..0ea8866 100644
--- a/drivers/media/video/videobuf2-dma-contig.c
+++ b/drivers/media/video/videobuf2-dma-contig.c
@@ -106,6 +106,7 @@ static int vb2_dma_contig_mmap(void *buf_priv, struct vm_area_struct *vma)
 		return -EINVAL;
 	}
 
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 	return vb2_mmap_pfn_range(vma, buf->dma_addr, buf->size,
 				  &vb2_common_vm_ops, &buf->handler);
 }
diff --git a/drivers/media/video/videobuf2-memops.c b/drivers/media/video/videobuf2-memops.c
index 71a7a78..77e0def 100644
--- a/drivers/media/video/videobuf2-memops.c
+++ b/drivers/media/video/videobuf2-memops.c
@@ -162,7 +162,6 @@ int vb2_mmap_pfn_range(struct vm_area_struct *vma, unsigned long paddr,
 
 	size = min_t(unsigned long, vma->vm_end - vma->vm_start, size);
 
-	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 	ret = remap_pfn_range(vma, vma->vm_start, paddr >> PAGE_SHIFT,
 				size, vma->vm_page_prot);
 	if (ret) {
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 4/7] media: videobuf2: introduce VIDEOBUF2_PAGE memops
  2011-12-02  9:12 [RFC PATCH v1 0/7] media&omap4: introduce face detection(FD) driver Ming Lei
                   ` (2 preceding siblings ...)
  2011-12-02  9:12 ` [RFC PATCH v1 3/7] media: videobuf2: move out of setting pgprot_noncached from vb2_mmap_pfn_range Ming Lei
@ 2011-12-02  9:12 ` Ming Lei
  2011-12-02 16:35   ` Aguirre, Sergio
  2011-12-02  9:12 ` [RFC PATCH v1 5/7] media: v4l2: introduce two IOCTLs for face detection Ming Lei
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 26+ messages in thread
From: Ming Lei @ 2011-12-02  9:12 UTC (permalink / raw)
  To: linux-arm-kernel

DMA contig memory resource is very limited and precious, also
accessing to it from CPU is very slow on some platform.

For some cases(such as the comming face detection driver), DMA Streaming
buffer is enough, so introduce VIDEOBUF2_PAGE to allocate continuous
physical memory but letting video device driver to handle DMA buffer mapping
and unmapping things.

Signed-off-by: Ming Lei <ming.lei@canonical.com>
---
 drivers/media/video/Kconfig          |    4 +
 drivers/media/video/Makefile         |    1 +
 drivers/media/video/videobuf2-page.c |  115 ++++++++++++++++++++++++++++++++++
 include/media/videobuf2-page.h       |   20 ++++++
 4 files changed, 140 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/videobuf2-page.c
 create mode 100644 include/media/videobuf2-page.h

diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 4e8a0c4..5684a00 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -60,6 +60,10 @@ config VIDEOBUF2_VMALLOC
 	select VIDEOBUF2_MEMOPS
 	tristate
 
+config VIDEOBUF2_PAGE
+	select VIDEOBUF2_CORE
+	select VIDEOBUF2_MEMOPS
+	tristate
 
 config VIDEOBUF2_DMA_SG
 	#depends on HAS_DMA
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index ddeaa6c..bc797f2 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -125,6 +125,7 @@ obj-$(CONFIG_VIDEO_BTCX)  += btcx-risc.o
 obj-$(CONFIG_VIDEOBUF2_CORE)		+= videobuf2-core.o
 obj-$(CONFIG_VIDEOBUF2_MEMOPS)		+= videobuf2-memops.o
 obj-$(CONFIG_VIDEOBUF2_VMALLOC)		+= videobuf2-vmalloc.o
+obj-$(CONFIG_VIDEOBUF2_PAGE)		+= videobuf2-page.o
 obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG)	+= videobuf2-dma-contig.o
 obj-$(CONFIG_VIDEOBUF2_DMA_SG)		+= videobuf2-dma-sg.o
 
diff --git a/drivers/media/video/videobuf2-page.c b/drivers/media/video/videobuf2-page.c
new file mode 100644
index 0000000..b3f003a
--- /dev/null
+++ b/drivers/media/video/videobuf2-page.c
@@ -0,0 +1,115 @@
+/*
+ * videobuf2-page.c - page memory allocator for videobuf2
+ *
+ * Copyright (C) 2011 Canonical Ltd.
+ *
+ * Author: Ming Lei <ming.lei@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-memops.h>
+
+struct vb2_page_buf {
+	void				*vaddr;
+	unsigned long			size;
+	atomic_t			refcount;
+	struct vb2_vmarea_handler	handler;
+};
+
+static void vb2_page_put(void *buf_priv);
+
+static void *vb2_page_alloc(void *alloc_ctx, unsigned long size)
+{
+	struct vb2_page_buf *buf;
+
+	buf = kzalloc(sizeof *buf, GFP_KERNEL);
+	if (!buf)
+		return NULL;
+
+	buf->size = size;
+	buf->vaddr = (void *)__get_free_pages(GFP_KERNEL,
+			get_order(buf->size));
+	buf->handler.refcount = &buf->refcount;
+	buf->handler.put = vb2_page_put;
+	buf->handler.arg = buf;
+
+	if (!buf->vaddr) {
+		printk(KERN_ERR "page of size %ld failed\n", buf->size);
+		kfree(buf);
+		return NULL;
+	}
+
+	atomic_inc(&buf->refcount);
+	printk(KERN_DEBUG "Allocated page buffer of size %ld at vaddr=%p\n",
+			buf->size, buf->vaddr);
+
+	return buf;
+}
+
+static void vb2_page_put(void *buf_priv)
+{
+	struct vb2_page_buf *buf = buf_priv;
+
+	if (atomic_dec_and_test(&buf->refcount)) {
+		printk(KERN_DEBUG "%s: Freeing page mem at vaddr=%p\n",
+			__func__, buf->vaddr);
+		free_pages((unsigned long)buf->vaddr, get_order(buf->size));
+		kfree(buf);
+	}
+}
+
+static void *vb2_page_vaddr(void *buf_priv)
+{
+	struct vb2_page_buf *buf = buf_priv;
+
+	BUG_ON(!buf);
+
+	if (!buf->vaddr) {
+		printk(KERN_ERR "Address of an unallocated plane requested\n");
+		return NULL;
+	}
+
+	return buf->vaddr;
+}
+
+static unsigned int vb2_page_num_users(void *buf_priv)
+{
+	struct vb2_page_buf *buf = buf_priv;
+	return atomic_read(&buf->refcount);
+}
+
+static int vb2_page_mmap(void *buf_priv, struct vm_area_struct *vma)
+{
+	struct vb2_page_buf *buf = buf_priv;
+
+	if (!buf) {
+		printk(KERN_ERR "No memory to map\n");
+		return -EINVAL;
+	}
+
+	vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+	return vb2_mmap_pfn_range(vma, virt_to_phys(buf->vaddr),
+			buf->size, &vb2_common_vm_ops,
+			&buf->handler);
+}
+
+const struct vb2_mem_ops vb2_page_memops = {
+	.alloc		= vb2_page_alloc,
+	.put		= vb2_page_put,
+	.vaddr		= vb2_page_vaddr,
+	.mmap		= vb2_page_mmap,
+	.num_users	= vb2_page_num_users,
+};
+EXPORT_SYMBOL_GPL(vb2_page_memops);
+
+MODULE_DESCRIPTION("page memory handling routines for videobuf2");
+MODULE_AUTHOR("Ming Lei");
+MODULE_LICENSE("GPL");
diff --git a/include/media/videobuf2-page.h b/include/media/videobuf2-page.h
new file mode 100644
index 0000000..29b3e20
--- /dev/null
+++ b/include/media/videobuf2-page.h
@@ -0,0 +1,20 @@
+/*
+ * videobuf2-vmalloc.h - vmalloc memory allocator for videobuf2
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <pawel@osciak.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ */
+
+#ifndef _MEDIA_VIDEOBUF2_VMALLOC_H
+#define _MEDIA_VIDEOBUF2_VMALLOC_H
+
+#include <media/videobuf2-core.h>
+
+extern const struct vb2_mem_ops vb2_page_memops;
+
+#endif
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 5/7] media: v4l2: introduce two IOCTLs for face detection
  2011-12-02  9:12 [RFC PATCH v1 0/7] media&omap4: introduce face detection(FD) driver Ming Lei
                   ` (3 preceding siblings ...)
  2011-12-02  9:12 ` [RFC PATCH v1 4/7] media: videobuf2: introduce VIDEOBUF2_PAGE memops Ming Lei
@ 2011-12-02  9:12 ` Ming Lei
  2011-12-02 12:33   ` Arnd Bergmann
  2011-12-02  9:12 ` [RFC PATCH v1 6/7] media: video: introduce face detection driver module Ming Lei
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 26+ messages in thread
From: Ming Lei @ 2011-12-02  9:12 UTC (permalink / raw)
  To: linux-arm-kernel

This patch introduces two new IOCTLs and related data
structure defination which will be used by the coming
face detection video device.

The two IOCTLs and related data structure are used by
user space application to retrieve the results of face
detection. They can be called after one v4l2_buffer
has been ioctl(VIDIOC_DQBUF) and before it will be
ioctl(VIDIOC_QBUF).

The utility fdif[1] is useing the two IOCTLs to find
faces deteced in raw images or video streams.

[1],http://kernel.ubuntu.com/git?p=ming/fdif.git;a=shortlog;h=refs/heads/v4l2-fdif

Signed-off-by: Ming Lei <ming.lei@canonical.com>
---
 drivers/media/video/v4l2-ioctl.c |   38 ++++++++++++++++++++
 include/linux/videodev2.h        |   70 ++++++++++++++++++++++++++++++++++++++
 include/media/v4l2-ioctl.h       |    6 +++
 3 files changed, 114 insertions(+), 0 deletions(-)

diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index e1da8fc..fc6266f 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -2140,6 +2140,30 @@ static long __video_do_ioctl(struct file *file,
 		dbgarg(cmd, "index=%d", b->index);
 		break;
 	}
+	case VIDIOC_G_FD_RESULT:
+	{
+		struct v4l2_fd_result *fr = arg;
+
+		if (!ops->vidioc_g_fd_result)
+			break;
+
+		ret = ops->vidioc_g_fd_result(file, fh, fr);
+
+		dbgarg(cmd, "index=%d", fr->buf_index);
+		break;
+	}
+	case VIDIOC_G_FD_COUNT:
+	{
+		struct v4l2_fd_count *fc = arg;
+
+		if (!ops->vidioc_g_fd_count)
+			break;
+
+		ret = ops->vidioc_g_fd_count(file, fh, fc);
+
+		dbgarg(cmd, "index=%d", fc->buf_index);
+		break;
+	}
 	default:
 		if (!ops->vidioc_default)
 			break;
@@ -2234,6 +2258,20 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
 		}
 		break;
 	}
+
+	case VIDIOC_G_FD_RESULT: {
+		struct v4l2_fd_result *fr = parg;
+
+		if (fr->face_cnt != 0) {
+			*user_ptr = (void __user *)fr->fd;
+			*kernel_ptr = (void *)&fr->fd;
+			*array_size = sizeof(struct v4l2_fd_detection)
+				    * fr->face_cnt;
+			ret = 1;
+		}
+		break;
+
+	}
 	}
 
 	return ret;
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 4b752d5..073eb4d 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -2160,6 +2160,74 @@ struct v4l2_create_buffers {
 	__u32			reserved[8];
 };
 
+/**
+ * struct v4l2_obj_detection
+ * @buf_index:	entry, index of v4l2_buffer for face detection
+ * @centerx:	return, position in x direction of detected object
+ * @centery:	return, position in y direction of detected object
+ * @angle:	return, angle of detected object
+ * 		0 deg ~ 359 deg, vertical is 0 deg, clockwise
+ * @sizex:	return, size in x direction of detected object
+ * @sizey:	return, size in y direction of detected object
+ * @confidence:	return, confidence level of detection result
+ * 		0: the heighest level, 9: the lowest level
+ * @reserved:	future extensions
+ */
+struct v4l2_obj_detection {
+	__u16		centerx;
+	__u16		centery;
+	__u16		angle;
+	__u16		sizex;
+	__u16		sizey;
+	__u16		confidence;
+	__u32		reserved[4];
+};
+
+#define V4L2_FD_HAS_LEFT_EYE	0x1
+#define V4L2_FD_HAS_RIGHT_EYE	0x2
+#define V4L2_FD_HAS_MOUTH	0x4
+#define V4L2_FD_HAS_FACE	0x8
+
+/**
+ * struct v4l2_fd_detection - VIDIOC_G_FD_RESULT argument
+ * @flag:	return, describe which objects are detected
+ * @left_eye:	return, left_eye position if detected
+ * @right_eye:	return, right_eye position if detected
+ * @mouth_eye:	return, mouth_eye position if detected
+ * @face:	return, face position if detected
+ */
+struct v4l2_fd_detection {
+	__u32	flag;
+	struct v4l2_obj_detection	left_eye;
+	struct v4l2_obj_detection	right_eye;
+	struct v4l2_obj_detection	mouth;
+	struct v4l2_obj_detection	face;
+};
+
+/**
+ * struct v4l2_fd_result - VIDIOC_G_FD_RESULT argument
+ * @buf_index:	entry, index of v4l2_buffer for face detection
+ * @face_cnt:	return, how many faces detected from the @buf_index
+ * @fd:		return, result of faces' detection
+ */
+struct v4l2_fd_result {
+	__u32	buf_index;
+	__u32	face_cnt;
+	__u32	reserved[6];
+	struct v4l2_fd_detection *fd;
+};
+
+/**
+ * struct v4l2_fd_count - VIDIOC_G_FD_COUNT argument
+ * @buf_index:	entry, index of v4l2_buffer for face detection
+ * @face_cnt:	return, how many faces detected from the @buf_index
+ */
+struct v4l2_fd_count {
+	__u32	buf_index;
+	__u32	face_cnt;
+	__u32	reserved[6];
+};
+
 /*
  *	I O C T L   C O D E S   F O R   V I D E O   D E V I C E S
  *
@@ -2254,6 +2322,8 @@ struct v4l2_create_buffers {
    versions */
 #define VIDIOC_CREATE_BUFS	_IOWR('V', 92, struct v4l2_create_buffers)
 #define VIDIOC_PREPARE_BUF	_IOWR('V', 93, struct v4l2_buffer)
+#define VIDIOC_G_FD_COUNT	_IOWR('V', 94, struct v4l2_fd_count)
+#define VIDIOC_G_FD_RESULT	_IOWR('V', 95, struct v4l2_fd_result)
 
 /* Reminder: when adding new ioctls please add support for them to
    drivers/media/video/v4l2-compat-ioctl32.c as well! */
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index 4d1c74a..19f03b0 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -270,6 +270,12 @@ struct v4l2_ioctl_ops {
 	int (*vidioc_unsubscribe_event)(struct v4l2_fh *fh,
 					struct v4l2_event_subscription *sub);
 
+	/* Face detect IOCTLs */
+	int (*vidioc_g_fd_count) (struct file *file, void *fh,
+					struct v4l2_fd_count *arg);
+	int (*vidioc_g_fd_result) (struct file *file, void *fh,
+					struct v4l2_fd_result *arg);
+
 	/* For other private ioctls */
 	long (*vidioc_default)	       (struct file *file, void *fh,
 					bool valid_prio, int cmd, void *arg);
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 6/7] media: video: introduce face detection driver module
  2011-12-02  9:12 [RFC PATCH v1 0/7] media&omap4: introduce face detection(FD) driver Ming Lei
                   ` (4 preceding siblings ...)
  2011-12-02  9:12 ` [RFC PATCH v1 5/7] media: v4l2: introduce two IOCTLs for face detection Ming Lei
@ 2011-12-02  9:12 ` Ming Lei
  2011-12-02  9:12 ` [RFC PATCH v1 7/7] media: video: introduce omap4 face detection module driver Ming Lei
  2011-12-02 10:28 ` [RFC PATCH v1 0/7] media&omap4: introduce face detection(FD) driver Sylwester Nawrocki
  7 siblings, 0 replies; 26+ messages in thread
From: Ming Lei @ 2011-12-02  9:12 UTC (permalink / raw)
  To: linux-arm-kernel

This patch introduces one driver for face detection purpose.

The driver is responsible for all v4l2 stuff, buffer management
and other general things, and doesn't touch face detection hardware
directly. Several interfaces are exported to low level drivers
(such as the coming omap4 FD driver)which will communicate with
face detection hw module.

So the driver will make driving face detection hw modules more
easy.

TODO:
	- implement FD setting interfaces with v4l2 controls or
	ext controls

Signed-off-by: Ming Lei <ming.lei@canonical.com>
---
 drivers/media/video/Kconfig       |    2 +
 drivers/media/video/Makefile      |    1 +
 drivers/media/video/fdif/Kconfig  |    7 +
 drivers/media/video/fdif/Makefile |    1 +
 drivers/media/video/fdif/fdif.c   |  645 +++++++++++++++++++++++++++++++++++++
 drivers/media/video/fdif/fdif.h   |  114 +++++++
 6 files changed, 770 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/fdif/Kconfig
 create mode 100644 drivers/media/video/fdif/Makefile
 create mode 100644 drivers/media/video/fdif/fdif.c
 create mode 100644 drivers/media/video/fdif/fdif.h

diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 5684a00..2b01402 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -1166,3 +1166,5 @@ config VIDEO_SAMSUNG_S5P_MFC
 	    MFC 5.1 driver for V4L2.
 
 endif # V4L_MEM2MEM_DRIVERS
+
+source "drivers/media/video/fdif/Kconfig"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index bc797f2..fdf6b1a 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -197,6 +197,7 @@ obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
 obj-y	+= davinci/
 
 obj-$(CONFIG_ARCH_OMAP)	+= omap/
+obj-$(CONFIG_FDIF)	+= fdif/
 
 ccflags-y += -Idrivers/media/dvb/dvb-core
 ccflags-y += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/fdif/Kconfig b/drivers/media/video/fdif/Kconfig
new file mode 100644
index 0000000..e214cb4
--- /dev/null
+++ b/drivers/media/video/fdif/Kconfig
@@ -0,0 +1,7 @@
+config FDIF
+	depends on VIDEO_DEV && VIDEO_V4L2
+	select VIDEOBUF2_PAGE
+	tristate "Face Detection module"
+	help
+	  The FDIF is a face detection module, which can be integrated into
+	  some SoCs to detect the location of faces in one image or video.
diff --git a/drivers/media/video/fdif/Makefile b/drivers/media/video/fdif/Makefile
new file mode 100644
index 0000000..ba1e4c8
--- /dev/null
+++ b/drivers/media/video/fdif/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_FDIF)		+= fdif.o
diff --git a/drivers/media/video/fdif/fdif.c b/drivers/media/video/fdif/fdif.c
new file mode 100644
index 0000000..84522d6
--- /dev/null
+++ b/drivers/media/video/fdif/fdif.c
@@ -0,0 +1,645 @@
+/*
+ *      fdif.c  --  face detection module driver
+ *
+ *      Copyright (C) 2011  Ming Lei (ming.lei at canonical.com)
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/signal.h>
+#include <linux/wait.h>
+#include <linux/poll.h>
+#include <linux/mman.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include "fdif.h"
+
+static unsigned debug = 0;
+module_param(debug, uint, 0644);
+MODULE_PARM_DESC(debug, "activates debug info");
+
+static LIST_HEAD(fdif_devlist);
+static unsigned video_nr = -1;
+
+int fdif_open(struct file *file)
+{
+	struct fdif_dev *dev = video_drvdata(file);
+
+	kref_get(&dev->ref);
+	return v4l2_fh_open(file);
+}
+
+static unsigned int
+fdif_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct fdif_dev *dev = video_drvdata(file);
+	unsigned int mask = 0;
+	unsigned long flags;
+
+	poll_wait(file, &dev->fdif_dq.wq, wait);
+
+	spin_lock_irqsave(&dev->lock, flags);
+	if ((file->f_mode & FMODE_READ) &&
+		!list_empty(&dev->fdif_dq.complete))
+		mask |= POLLIN | POLLWRNORM;
+	spin_unlock_irqrestore(&dev->lock, flags);
+	return mask;
+}
+
+static int fdif_close(struct file *file)
+{
+	struct video_device  *vdev = video_devdata(file);
+	struct fdif_dev *dev = video_drvdata(file);
+	int ret;
+
+	dprintk(dev, 1, "close called (dev=%s), file %p\n",
+		video_device_node_name(vdev), file);
+
+	if (v4l2_fh_is_singular_file(file))
+		vb2_queue_release(&dev->vbq);
+
+	ret = v4l2_fh_release(file);
+	kref_put(&dev->ref, fdif_release);
+
+	return ret;
+}
+
+static int fdif_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct fdif_dev *dev = video_drvdata(file);
+	int ret;
+
+	dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
+
+	ret = vb2_mmap(&dev->vbq, vma);
+	dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n",
+		(unsigned long)vma->vm_start,
+		(unsigned long)vma->vm_end - (unsigned long)vma->vm_start,
+		ret);
+	return ret;
+}
+
+static const struct v4l2_file_operations fdif_fops = {
+	.owner		= THIS_MODULE,
+	.open           = fdif_open,
+	.release        = fdif_close,
+	.poll		= fdif_poll,
+	.unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
+	.mmap           = fdif_mmap,
+};
+
+/* ------------------------------------------------------------------
+	IOCTL vidioc handling
+   ------------------------------------------------------------------*/
+static int vidioc_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *cap)
+{
+	struct fdif_dev *dev = video_drvdata(file);
+
+	strcpy(cap->driver, "fdif");
+	strcpy(cap->card, "fdif");
+	strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
+	cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	struct fdif_fmt *fmt;
+	struct fdif_dev *dev = video_drvdata(file);
+
+	if (f->index >= dev->ops->fmt_cnt) {
+		return -EINVAL;
+	}
+
+	fmt = &dev->ops->table[f->index];
+
+	strlcpy(f->description, fmt->name, sizeof(f->description));
+	f->pixelformat = fmt->fourcc;
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct fdif_dev *dev = video_drvdata(file);
+
+	f->fmt.pix.width        = dev->s.width;
+	f->fmt.pix.height       = dev->s.height;
+	f->fmt.pix.field        = dev->s.field;
+	f->fmt.pix.pixelformat  = dev->s.fmt->fourcc;
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * dev->s.fmt->depth) >> 3;
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * f->fmt.pix.bytesperline;
+	return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *p)
+{
+	struct fdif_dev *dev = video_drvdata(file);
+	dprintk(dev, 1, "%s\n", __func__);
+	return vb2_reqbufs(&dev->vbq, p);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct fdif_dev *dev = video_drvdata(file);
+	dprintk(dev, 1, "%s\n", __func__);
+	return vb2_querybuf(&dev->vbq, p);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct fdif_dev *dev = video_drvdata(file);
+	dprintk(dev, 1, "%s\n", __func__);
+	return vb2_qbuf(&dev->vbq, p);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct fdif_dev *dev = video_drvdata(file);
+	dprintk(dev, 1, "%s\n", __func__);
+	return vb2_dqbuf(&dev->vbq, p, file->f_flags & O_NONBLOCK);
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct fdif_dev *dev = video_drvdata(file);
+	dprintk(dev, 1, "%s\n", __func__);
+	return vb2_streamon(&dev->vbq, i);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct fdif_dev *dev = video_drvdata(file);
+	dprintk(dev, 1, "%s\n", __func__);
+	return vb2_streamoff(&dev->vbq, i);
+}
+
+static int vidioc_g_fd_count(struct file *file, void *priv,
+					struct v4l2_fd_count *f)
+{
+	struct fdif_dev *dev = video_drvdata(file);
+	unsigned long flags;
+	struct v4l2_fdif_result *tmp;
+	int ret = -EINVAL;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	list_for_each_entry(tmp, &dev->fdif_dq.complete, list)
+		if (tmp->index == f->buf_index) {
+			f->face_cnt = tmp->face_cnt;
+			ret = 0;
+			break;
+		}
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return ret;
+}
+
+static int vidioc_g_fd_result(struct file *file, void *priv,
+					struct v4l2_fd_result *f)
+{
+	struct fdif_dev *dev = video_drvdata(file);
+	unsigned long flags;
+	struct v4l2_fdif_result *tmp;
+	struct v4l2_fdif_result *fr = NULL;
+	unsigned int cnt = 0;
+	int ret = -EINVAL;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	list_for_each_entry(tmp, &dev->fdif_dq.complete, list)
+		if (tmp->index == f->buf_index) {
+			fr = tmp;
+			list_del(&tmp->list);
+			break;
+		}
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	if (fr) {
+		ret = 0;
+		cnt = min(f->face_cnt, fr->face_cnt);
+		if (cnt)
+			memcpy(f->fd, fr->faces,
+				sizeof(struct v4l2_fd_detection) * cnt);
+		f->face_cnt = cnt;
+		kfree(fr->faces);
+		kfree(fr);
+	}
+	return ret;
+}
+
+static const struct v4l2_ioctl_ops fdif_ioctl_ops = {
+	.vidioc_querycap      = vidioc_querycap,
+	.vidioc_enum_fmt_vid_out  = vidioc_enum_fmt_vid_out,
+	.vidioc_g_fmt_vid_out     = vidioc_g_fmt_vid_out,
+	.vidioc_reqbufs       = vidioc_reqbufs,
+	.vidioc_querybuf      = vidioc_querybuf,
+	.vidioc_qbuf          = vidioc_qbuf,
+	.vidioc_dqbuf         = vidioc_dqbuf,
+	.vidioc_streamon      = vidioc_streamon,
+	.vidioc_streamoff     = vidioc_streamoff,
+	.vidioc_g_fd_count    = vidioc_g_fd_count,
+	.vidioc_g_fd_result   = vidioc_g_fd_result,
+};
+
+static void fdif_vdev_release(struct video_device *vdev)
+{
+	kfree(vdev->lock);
+	video_device_release(vdev);
+}
+
+static struct video_device fdif_template = {
+	.name		= "fdif",
+	.fops           = &fdif_fops,
+	.ioctl_ops 	= &fdif_ioctl_ops,
+	.release	= fdif_vdev_release,
+};
+
+static int fdif_start_detect(struct fdif_dev *dev)
+{
+	int ret;
+
+	dprintk(dev, 1, "%s\n", __func__);
+
+	ret = dev->ops->start_detect(dev);
+
+	dprintk(dev, 1, "returning from %s, ret is %d\n",
+			__func__, ret);
+	return ret;
+}
+
+static void fdif_stop_detect(struct fdif_dev *dev)
+{
+	struct fdif_dmaqueue *dma_q = &dev->fdif_dq;
+	unsigned long flags;
+
+	dprintk(dev, 1, "%s\n", __func__);
+
+	/*stop hardware first*/
+	dev->ops->stop_detect(dev);
+
+	spin_lock_irqsave(&dev->lock, flags);
+	/* Release all active buffers */
+	while (!list_empty(&dma_q->active)) {
+		struct fdif_buffer *buf;
+		buf = list_entry(dma_q->active.next, struct fdif_buffer, list);
+		list_del(&buf->list);
+		spin_unlock_irqrestore(&dev->lock, flags);
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+		dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+
+	/* Release all complete detect result, so user space __must__ read
+	 * the results before stream off*/
+	while (!list_empty(&dma_q->complete)) {
+		struct v4l2_fdif_result *result;
+		result = list_entry(dma_q->complete.next, struct v4l2_fdif_result, list);
+		list_del(&result->list);
+		spin_unlock_irqrestore(&dev->lock, flags);
+		kfree(result->faces);
+		kfree(result);
+		dprintk(dev, 2, "[buf->index:%d] result removed\n", result->index);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+/* ------------------------------------------------------------------
+	Videobuf operations
+   ------------------------------------------------------------------*/
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+				unsigned int *nbuffers, unsigned int *nplanes,
+				unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct fdif_dev *dev = vb2_get_drv_priv(vq);
+	unsigned long size;
+
+	dprintk(dev, 1, "%s\n", __func__);
+
+	BUG_ON(!dev->s.fmt);
+	size = (dev->s.width * dev->s.height * dev->s.fmt->depth) >> 3;
+
+	if (0 == *nbuffers)
+		*nbuffers = 2;
+	*nplanes = 1;
+	sizes[0] = size;
+
+	dprintk(dev, 1, "%s, count=%d, size=%ld\n", __func__,
+		*nbuffers, size);
+
+	return 0;
+}
+
+static int buffer_init(struct vb2_buffer *vb)
+{
+	struct fdif_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+
+	/*
+	 * This callback is called once per buffer, after its allocation.
+	 *
+	 * Vivi does not allow changing format during streaming, but it is
+	 * possible to do so when streaming is paused (i.e. in streamoff state).
+	 * Buffers however are not freed when going into streamoff and so
+	 * buffer size verification has to be done in buffer_prepare, on each
+	 * qbuf.
+	 * It would be best to move verification code here to buf_init and
+	 * s_fmt though.
+	 */
+	dprintk(dev, 1, "%s vaddr=%p\n", __func__,
+			vb2_plane_vaddr(vb, 0));
+
+	return 0;
+}
+
+static int buffer_prepare(struct vb2_buffer *vb)
+{
+	struct fdif_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+	struct fdif_buffer *buf = container_of(vb, struct fdif_buffer, vb);
+	unsigned long size;
+
+	dprintk(dev, 1, "%s, field=%d\n", __func__, vb->v4l2_buf.field);
+
+	BUG_ON(!dev->s.fmt);
+	size = (dev->s.width * dev->s.height * dev->s.fmt->depth) >> 3;
+	if (vb2_plane_size(vb, 0) < size) {
+		dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n",
+				__func__, vb2_plane_size(vb, 0), size);
+		return -EINVAL;
+	}
+
+	vb2_set_plane_payload(&buf->vb, 0, size);
+
+	return 0;
+}
+
+static int buffer_finish(struct vb2_buffer *vb)
+{
+	struct fdif_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+	dprintk(dev, 1, "%s\n", __func__);
+	return 0;
+}
+
+static void buffer_cleanup(struct vb2_buffer *vb)
+{
+	struct fdif_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+	dprintk(dev, 1, "%s\n", __func__);
+}
+
+static void buffer_queue(struct vb2_buffer *vb)
+{
+	struct fdif_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+	struct fdif_buffer *buf = container_of(vb, struct fdif_buffer, vb);
+	struct fdif_dmaqueue *dq = &dev->fdif_dq;
+	unsigned long flags = 0;
+
+	dprintk(dev, 1, "%s vaddr:%p\n", __func__,
+			vb2_plane_vaddr(vb, 0));
+
+	spin_lock_irqsave(&dev->lock, flags);
+	list_add_tail(&buf->list, &dq->active);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	if (vb->vb2_queue->streaming)
+		dev->ops->submit_detect(dev);
+}
+
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+	struct fdif_dev *dev = vb2_get_drv_priv(vq);
+	dprintk(dev, 1, "%s\n", __func__);
+	return fdif_start_detect(dev);
+}
+
+/* abort streaming and wait for last buffer */
+static int stop_streaming(struct vb2_queue *vq)
+{
+	struct fdif_dev *dev = vb2_get_drv_priv(vq);
+	dprintk(dev, 1, "%s\n", __func__);
+	fdif_stop_detect(dev);
+	return 0;
+}
+
+static void fdif_lock(struct vb2_queue *vq)
+{
+	struct fdif_dev *dev = vb2_get_drv_priv(vq);
+
+	mutex_lock(&dev->mutex);
+}
+
+static void fdif_unlock(struct vb2_queue *vq)
+{
+	struct fdif_dev *dev = vb2_get_drv_priv(vq);
+	mutex_unlock(&dev->mutex);
+}
+static struct vb2_ops fdif_video_qops = {
+	.queue_setup		= queue_setup,
+	.buf_init		= buffer_init,
+	.buf_prepare		= buffer_prepare,
+	.buf_finish		= buffer_finish,
+	.buf_cleanup		= buffer_cleanup,
+	.buf_queue		= buffer_queue,
+	.start_streaming	= start_streaming,
+	.stop_streaming		= stop_streaming,
+	.wait_prepare		= fdif_unlock,
+	.wait_finish		= fdif_lock,
+};
+
+/*only store one detection result for one buf*/
+void fdif_add_detection(struct fdif_dev *dev,
+		struct v4l2_fdif_result *v4l2_fr)
+{
+	unsigned long flags;
+	struct v4l2_fdif_result *old = NULL;
+	struct v4l2_fdif_result *tmp;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	list_for_each_entry(tmp, &dev->fdif_dq.complete, list)
+		if (tmp->index == v4l2_fr->index) {
+			old = tmp;
+			list_del(&tmp->list);
+			break;
+		}
+	list_add_tail(&v4l2_fr->list, &dev->fdif_dq.complete);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	if (old) {
+		kfree(old->faces);
+		kfree(old);
+	}
+}
+EXPORT_SYMBOL_GPL(fdif_add_detection);
+
+struct fdif_buffer *fdif_get_buffer(struct fdif_dev *dev)
+{
+	struct fdif_buffer *buf = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	if (list_empty(&dev->fdif_dq.active))
+		goto out;
+	buf = list_entry(dev->fdif_dq.active.next,
+				struct fdif_buffer, list);
+	list_del(&buf->list);
+out:
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return buf;
+}
+EXPORT_SYMBOL_GPL(fdif_get_buffer);
+
+void fdif_release(struct kref *ref)
+{
+	struct fdif_dev *dev = container_of(ref, struct fdif_dev, ref);
+
+	v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+		video_device_node_name(dev->vfd));
+
+	list_del(&dev->fdif_devlist);
+	video_unregister_device(dev->vfd);
+	v4l2_device_unregister(&dev->v4l2_dev);
+	kfree(dev);
+}
+EXPORT_SYMBOL_GPL(fdif_release);
+
+int fdif_create_instance(struct device *parent, int priv_size,
+		struct fdif_ops *ops, struct fdif_dev **fdif_dev)
+{
+	struct fdif_dev *dev;
+	struct video_device *vfd;
+	struct vb2_queue *q;
+	int ret, len;
+	struct mutex	*vmutex;
+
+	dev = kzalloc(sizeof(*dev) + priv_size, GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	kref_init(&dev->ref);
+	dev->ops = ops;
+	dev->dev = parent;
+
+	len = snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
+			"%s", "fdif");
+	dev->v4l2_dev.name[len] = '\0';
+
+	ret = v4l2_device_register(dev->dev, &dev->v4l2_dev);
+	if (ret)
+		goto free_dev;
+
+	/* initialize locks */
+	spin_lock_init(&dev->lock);
+
+	/* initialize queue */
+	q = &dev->vbq;
+	memset(q, 0, sizeof(dev->vbq));
+	q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	q->io_modes = VB2_MMAP;
+	q->drv_priv = dev;
+	q->buf_struct_size = sizeof(struct fdif_buffer);
+	q->ops = &fdif_video_qops;
+	q->mem_ops = &vb2_page_memops;
+
+	vb2_queue_init(q);
+
+	mutex_init(&dev->mutex);
+
+	/* init video dma queues */
+	INIT_LIST_HEAD(&dev->fdif_dq.active);
+	INIT_LIST_HEAD(&dev->fdif_dq.complete);
+	init_waitqueue_head(&dev->fdif_dq.wq);
+
+	ret = -ENOMEM;
+	vfd = video_device_alloc();
+	if (!vfd)
+		goto unreg_dev;
+
+	*vfd = fdif_template;
+	vfd->debug = debug;
+	vfd->v4l2_dev = &dev->v4l2_dev;
+	set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
+
+	vmutex = kzalloc(sizeof(struct mutex), GFP_KERNEL);
+	if (!vmutex)
+		goto err_alloc_mutex;
+
+	mutex_init(vmutex);
+	/*
+	 * Provide a mutex to v4l2 core. It will be used to protect
+	 * all fops and v4l2 ioctls.
+	 */
+	vfd->lock = vmutex;
+
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
+	if (ret < 0)
+		goto rel_vdev;
+
+	if (video_nr != -1)
+		video_nr++;
+
+	dev->vfd = vfd;
+	video_set_drvdata(vfd, dev);
+
+	/* Now that everything is fine, let's add it to device list */
+	list_add_tail(&dev->fdif_devlist, &fdif_devlist);
+
+	v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
+		  video_device_node_name(vfd));
+
+	*fdif_dev = dev;
+	return 0;
+
+rel_vdev:
+	kfree(vmutex);
+err_alloc_mutex:
+	video_device_release(vfd);
+unreg_dev:
+	v4l2_device_unregister(&dev->v4l2_dev);
+free_dev:
+	kfree(dev);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(fdif_create_instance);
+
+static int __init fdif_init(void)
+{
+	return 0;
+}
+
+static void __exit fdif_exit(void)
+{
+}
+
+module_init(fdif_init);
+module_exit(fdif_exit);
+
+MODULE_DESCRIPTION("face detection module");
+MODULE_AUTHOR("Ming Lei");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/fdif/fdif.h b/drivers/media/video/fdif/fdif.h
new file mode 100644
index 0000000..ae37ab8
--- /dev/null
+++ b/drivers/media/video/fdif/fdif.h
@@ -0,0 +1,114 @@
+#ifndef _LINUX_FDIF_H
+#define _LINUX_FDIF_H
+
+#include <linux/types.h>
+#include <linux/magic.h>
+#include <linux/errno.h>
+#include <linux/kref.h>
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+#include <media/videobuf2-page.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-common.h>
+
+#define MAX_FACE_COUNT		40
+
+#define	FACE_SIZE_20_PIXELS	0
+#define	FACE_SIZE_25_PIXELS	1
+#define	FACE_SIZE_32_PIXELS	2
+#define	FACE_SIZE_40_PIXELS	3
+
+#define FACE_DIR_UP		0
+#define FACE_DIR_RIGHT		1
+#define FACE_DIR_LIFT		2
+
+struct fdif_fmt {
+	char  *name;
+	u32   fourcc;          /* v4l2 format id */
+	int   depth;
+	int   width, height;
+};
+
+struct fdif_setting {
+	struct fdif_fmt            *fmt;
+	enum v4l2_field            field;
+
+	int 			min_face_size;
+	int			face_dir;
+
+	int			startx, starty;
+	int			sizex, sizey;
+	int			lhit;
+
+	int			width, height;
+};
+
+/* buffer for one video frame */
+struct fdif_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct vb2_buffer	vb;
+	struct list_head	list;
+};
+
+
+struct v4l2_fdif_result {
+	struct list_head		list;
+	unsigned int			face_cnt;
+	struct v4l2_fd_detection	*faces;
+
+	/*v4l2 buffer index*/
+	__u32				index;
+};
+
+struct fdif_dmaqueue {
+	struct list_head	complete;
+	struct list_head	active;
+	wait_queue_head_t	wq;
+};
+
+
+struct fdif_dev {
+	struct kref		ref;
+	struct device		*dev;
+
+	struct list_head        fdif_devlist;
+	struct v4l2_device	v4l2_dev;
+	struct vb2_queue        vbq;
+	struct mutex            mutex;
+	spinlock_t		lock;
+
+	struct video_device        *vfd;
+	struct fdif_dmaqueue	fdif_dq;
+
+	/*setting*/
+	struct fdif_setting	s;
+
+	struct fdif_ops	*ops;
+
+	unsigned long	priv[0];
+};
+
+struct fdif_ops {
+	struct fdif_fmt *table;
+	int fmt_cnt;
+	int (*start_detect)(struct fdif_dev *fdif);
+	int (*stop_detect)(struct fdif_dev *fdif);
+	int (*submit_detect)(struct fdif_dev *fdif);
+};
+
+#define dprintk(dev, level, fmt, arg...) \
+	v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
+
+
+extern int fdif_create_instance(struct device *parent, int priv_size,
+		struct fdif_ops *ops, struct fdif_dev **dev);
+extern void fdif_release(struct kref *ref);
+extern void fdif_add_detection(struct fdif_dev *dev,
+		struct v4l2_fdif_result *v4l2_fr);
+extern struct fdif_buffer *fdif_get_buffer(struct fdif_dev *dev);
+
+#endif /* _LINUX_FDIF_H */
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 7/7] media: video: introduce omap4 face detection module driver
  2011-12-02  9:12 [RFC PATCH v1 0/7] media&omap4: introduce face detection(FD) driver Ming Lei
                   ` (5 preceding siblings ...)
  2011-12-02  9:12 ` [RFC PATCH v1 6/7] media: video: introduce face detection driver module Ming Lei
@ 2011-12-02  9:12 ` Ming Lei
  2011-12-02 10:28 ` [RFC PATCH v1 0/7] media&omap4: introduce face detection(FD) driver Sylwester Nawrocki
  7 siblings, 0 replies; 26+ messages in thread
From: Ming Lei @ 2011-12-02  9:12 UTC (permalink / raw)
  To: linux-arm-kernel

The patch introduces one face detection device driver for
driving face detection hardware on omap4[1].

Most things of the driver are dealing with omap4 face detection
hardware.

This driver is platform independent, so in theory it can
be used to drive same IP module on other platforms.

[1], Ch9 of OMAP4 Technical Reference Manual

Signed-off-by: Ming Lei <ming.lei@canonical.com>
---
 drivers/media/video/fdif/Kconfig      |    6 +
 drivers/media/video/fdif/Makefile     |    1 +
 drivers/media/video/fdif/fdif_omap4.c |  663 +++++++++++++++++++++++++++++++++
 3 files changed, 670 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/fdif/fdif_omap4.c

diff --git a/drivers/media/video/fdif/Kconfig b/drivers/media/video/fdif/Kconfig
index e214cb4..0482a83 100644
--- a/drivers/media/video/fdif/Kconfig
+++ b/drivers/media/video/fdif/Kconfig
@@ -5,3 +5,9 @@ config FDIF
 	help
 	  The FDIF is a face detection module, which can be integrated into
 	  some SoCs to detect the location of faces in one image or video.
+
+config FDIF_OMAP4
+	depends on FDIF
+	tristate "OMAP4 Face Detection module"
+	help
+	  OMAP4 face detection support
diff --git a/drivers/media/video/fdif/Makefile b/drivers/media/video/fdif/Makefile
index ba1e4c8..3744ced 100644
--- a/drivers/media/video/fdif/Makefile
+++ b/drivers/media/video/fdif/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_FDIF)		+= fdif.o
+obj-$(CONFIG_FDIF_OMAP4)	+= fdif_omap4.o
diff --git a/drivers/media/video/fdif/fdif_omap4.c b/drivers/media/video/fdif/fdif_omap4.c
new file mode 100644
index 0000000..956ec51
--- /dev/null
+++ b/drivers/media/video/fdif/fdif_omap4.c
@@ -0,0 +1,663 @@
+/*
+ *      fdif_omap4.c  --  face detection module driver
+ *
+ *      Copyright (C) 2011  Ming Lei (ming.lei at canonical.com)
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*****************************************************************************/
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/signal.h>
+#include <linux/wait.h>
+#include <linux/poll.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <linux/user_namespace.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include "fdif.h"
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+
+#undef DEBUG
+
+#define PICT_SIZE_X     320
+#define PICT_SIZE_Y     240
+
+#define	WORK_MEM_SIZE	(52*1024)
+
+/* 9.5 FDIF Register Manua of TI OMAP4 TRM */
+#define FDIF_REVISION		0x0
+#define FDIF_HWINFO		0x4
+#define FDIF_SYSCONFIG		0x10
+#define SOFTRESET		(1 << 0)
+
+#define FDIF_IRQSTATUS_RAW_j	(0x24 + 2*0x10)
+#define FDIF_IRQSTATUS_j	(0x28 + 2*0x10)
+#define FDIF_IRQENABLE_SET_j	(0x2c + 2*0x10)
+#define FDIF_IRQENABLE_CLR_j	(0x30 + 2*0x10)
+#define FINISH_IRQ		(1 << 8)
+#define ERR_IRQ			(1 << 0)
+
+#define FDIF_PICADDR		0x60
+#define FDIF_CTRL		0x64
+#define CTRL_MAX_TAGS		0x0A
+
+#define FDIF_WKADDR		0x68
+#define FD_CTRL			0x80
+#define CTRL_FINISH		(1 << 2)
+#define CTRL_RUN		(1 << 1)
+#define CTRL_SRST		(1 << 0)
+
+
+#define FD_DNUM			0x84
+#define FD_DCOND		0x88
+#define FD_STARTX		0x8c
+#define FD_STARTY		0x90
+#define FD_SIZEX		0x94
+#define FD_SIZEY		0x98
+#define FD_LHIT			0x9c
+#define FD_CENTERX_i		0x160
+#define FD_CENTERY_i		0x164
+#define FD_CONFSIZE_i		0x168
+#define FD_ANGLE_i		0x16c
+
+static inline void fd_writel(void __iomem *base, u32 reg, u32 val)
+{
+	__raw_writel(val, base + reg);
+}
+
+static inline u32 fd_readl(void __iomem *base, u32 reg)
+{
+	return __raw_readl(base + reg);
+}
+
+struct fdif_qvga {
+	struct fdif_dev *dev;
+
+	/*should be removed*/
+	struct platform_device	*pdev;
+	int			irq;
+	void __iomem		*base;
+
+	void			*work_mem_addr;
+	dma_addr_t 		work_dma;
+	dma_addr_t 		pict_dma;
+	unsigned long 		pict_mem_len;
+
+	struct fdif_buffer	*pending;
+	spinlock_t		lock;
+};
+
+struct fdif_fmt qvga_fmt[] = {
+	{
+		.name		= "8  Greyscale",
+		.fourcc		= V4L2_PIX_FMT_GREY,
+		.depth		= 8,
+		.width		= PICT_SIZE_X,
+		.height		= PICT_SIZE_Y,
+	},
+};
+
+
+#ifdef DEBUG
+static void dump_fdif_setting(struct fdif_qvga *fdif, const char *func)
+{
+	printk("%s: %s\n", func, __func__);
+	printk("work mem addr:%8p\n", fdif->work_mem_addr);
+	printk("face size=%2d, face dir=%2d, lhit=%d\n",
+			fdif->dev->s.min_face_size, fdif->dev->s.face_dir,
+			fdif->dev->s.lhit);
+	printk("startx =%4d starty=%4d sizex=%4d sizey=%4d\n",
+			fdif->dev->s.startx, fdif->dev->s.starty,
+			fdif->dev->s.sizex, fdif->dev->s.sizey);
+}
+
+static void dump_fdif_results(struct v4l2_fdif_result *fdif, const char *func)
+{
+	int idx;
+
+	printk("%s: %s\n", func, __func__);
+
+	printk("found %d faces, but index:%d\n", fdif->face_cnt,
+			fdif->index);
+	for(idx=0; idx < fdif->face_cnt; idx++) {
+		struct v4l2_fd_detection *fr = &fdif->faces[idx];
+		printk("	No.%d x=%3d y=%2d sz=%2d ang=%3d conf=%2d\n",
+				idx, fr->face.centerx, fr->face.centery,
+				fr->face.sizex, fr->face.angle,
+				fr->face.confidence);
+	}
+}
+
+static void dump_fdif_regs(struct fdif_qvga *fdif, const char *func)
+{
+	printk("%s:%s\n", __func__, func);
+	printk("FDIF_CTRL=%08x FDIF_SYSCONFIG=%08x\n",
+			fd_readl(fdif->base, FDIF_CTRL),
+			fd_readl(fdif->base, FDIF_SYSCONFIG));
+	printk("FDIF_IRQSTATUS_RAW_j=%08x FDIF_IRQSTATUS_j=%08x\n",
+			fd_readl(fdif->base, FDIF_IRQSTATUS_RAW_j),
+			fd_readl(fdif->base, FDIF_IRQSTATUS_j));
+	printk("FDIF_PICADDR=%08x FDIF_WKADDR=%08x\n",
+			fd_readl(fdif->base, FDIF_PICADDR),
+			fd_readl(fdif->base, FDIF_WKADDR));
+	printk("FD_CTRL=%04x, FDIF_IRQENABLE_SET_j=%04x\n",
+			fd_readl(fdif->base, FD_CTRL),
+			fd_readl(fdif->base, FDIF_IRQENABLE_SET_j));
+}
+
+#else
+static inline void dump_fdif_setting(struct fdif_qvga *fdif, const char *func)
+{
+}
+static inline void dump_fdif_results(struct v4l2_fdif_result *fdif, const char *func)
+{
+}
+static inline void dump_fdif_regs(struct fdif_qvga *fdif, const char *func)
+{
+}
+#endif
+
+static void install_default_setting(struct fdif_qvga *fdif)
+{
+	fdif->dev->s.fmt		= &qvga_fmt[0];
+	fdif->dev->s.field		= V4L2_FIELD_NONE;
+
+	fdif->dev->s.min_face_size	= FACE_SIZE_25_PIXELS;
+	fdif->dev->s.face_dir		= FACE_DIR_UP;
+	fdif->dev->s.startx		= 0;
+	fdif->dev->s.starty		= 0;
+	fdif->dev->s.sizex		= 0x140;
+	fdif->dev->s.sizey		= 0xf0;
+	fdif->dev->s.lhit		= 0x5;
+
+	fdif->dev->s.width		= PICT_SIZE_X;
+	fdif->dev->s.height		= PICT_SIZE_Y;
+}
+
+static void commit_image_setting(struct fdif_qvga *fdif)
+{
+	unsigned long conf;
+	struct vb2_buffer *vb = &fdif->pending->vb;
+	void *pict_vaddr = vb2_plane_vaddr(vb, 0);
+
+	fdif->pict_mem_len = vb2_plane_size(vb, 0);
+	fdif->pict_dma = dma_map_single(&fdif->pdev->dev,
+				pict_vaddr,
+				fdif->pict_mem_len,
+				DMA_TO_DEVICE);
+
+	fd_writel(fdif->base, FDIF_PICADDR, fdif->pict_dma);
+
+	conf = (fdif->dev->s.min_face_size & 0x3) ||
+		((fdif->dev->s.face_dir & 0x3) << 2);
+	fd_writel(fdif->base, FD_DCOND, conf);
+
+	fd_writel(fdif->base, FD_STARTX, fdif->dev->s.startx);
+	fd_writel(fdif->base, FD_STARTY, fdif->dev->s.starty);
+	fd_writel(fdif->base, FD_SIZEX, fdif->dev->s.sizex);
+	fd_writel(fdif->base, FD_SIZEY, fdif->dev->s.sizey);
+	fd_writel(fdif->base, FD_LHIT, fdif->dev->s.lhit);
+}
+
+
+/*softreset fdif*/
+static int softreset_fdif(struct fdif_qvga *fdif)
+{
+	unsigned long conf;
+	int to = 0;
+
+	conf = fd_readl(fdif->base, FDIF_SYSCONFIG);
+	conf |= SOFTRESET;
+	fd_writel(fdif->base, FDIF_SYSCONFIG, conf);
+
+	while ((conf & SOFTRESET) && to++ < 2000) {
+		conf = fd_readl(fdif->base, FDIF_SYSCONFIG);
+		udelay(2);
+	}
+
+	if (to == 2000)
+		dev_err(&fdif->pdev->dev, "%s: reset failed\n", __func__);
+
+	return to == 2000;
+}
+
+static void __start_detect(struct fdif_qvga *fdif)
+{
+	unsigned long conf;
+
+	dump_fdif_setting(fdif, __func__);
+
+	commit_image_setting(fdif);
+
+	/*enable finish irq*/
+	conf = FINISH_IRQ;
+	fd_writel(fdif->base, FDIF_IRQENABLE_SET_j, conf);
+
+	/*set RUN flag*/
+	conf = CTRL_RUN;
+	fd_writel(fdif->base, FD_CTRL, conf);
+
+	dump_fdif_regs(fdif, __func__);
+}
+
+static void __stop_detect(struct fdif_qvga *fdif)
+{
+	unsigned long conf;
+
+	dump_fdif_regs(fdif, __func__);
+
+	dma_unmap_single(&fdif->pdev->dev, fdif->pict_dma,
+				fdif->pict_mem_len,
+				DMA_TO_DEVICE);
+	/*disable finish irq*/
+	conf = FINISH_IRQ;
+	fd_writel(fdif->base, FDIF_IRQENABLE_CLR_j, conf);
+
+	/*mark FINISH flag*/
+	conf = CTRL_FINISH;
+	fd_writel(fdif->base, FD_CTRL, conf);
+}
+
+static int read_faces(struct fdif_qvga *fdif, int is_err)
+{
+	int cnt, idx = 0;
+	struct v4l2_fdif_result *v4l2_fr;
+	struct fdif_dev *dev = fdif->dev;
+	struct fdif_buffer *buf;
+	unsigned long flags;
+
+	spin_lock_irqsave(&fdif->lock, flags);
+
+	buf = fdif->pending;
+	if (!buf) {
+		WARN_ON(1);
+		cnt = -EIO;
+		goto out;
+	}
+
+	buf->vb.v4l2_buf.sequence++;
+
+	if (!is_err)
+		cnt = fd_readl(fdif->base, FD_DNUM) & 0x3f;
+	else
+		cnt = 0;
+
+	v4l2_fr = kzalloc(sizeof(*v4l2_fr), GFP_ATOMIC);
+	if (!v4l2_fr) {
+		cnt = -ENOMEM;
+		goto out;
+	}
+	if (cnt)
+		v4l2_fr->faces =
+			kmalloc(sizeof(struct v4l2_fd_detection) * cnt,
+				GFP_ATOMIC);
+
+	if (cnt && !v4l2_fr->faces) {
+		cnt = -ENOMEM;
+		goto out_err;
+	}
+
+	v4l2_fr->face_cnt = cnt;
+	v4l2_fr->index = buf->vb.v4l2_buf.index;
+
+	while(idx < cnt) {
+		struct v4l2_fd_detection *fr = &v4l2_fr->faces[idx];
+
+		fr->flag = V4L2_FD_HAS_FACE;
+
+		fr->face.centerx = fd_readl(fdif->base,
+				FD_CENTERX_i + idx * 0x10) & 0x1ff;
+		fr->face.centery = fd_readl(fdif->base,
+				FD_CENTERY_i + idx * 0x10) & 0xff;
+		fr->face.angle = fd_readl(fdif->base,
+				FD_ANGLE_i + idx * 0x10) & 0x1ff;
+		fr->face.sizex = fd_readl(fdif->base,
+				FD_CONFSIZE_i + idx * 0x10);
+		fr->face.confidence = (fr->face.sizex >> 8) & 0xf;
+		fr->face.sizey = fr->face.sizex = fr->face.sizex & 0xff;
+
+		idx++;
+	}
+
+	__stop_detect(fdif);
+	fdif->pending = NULL;
+	spin_unlock_irqrestore(&fdif->lock, flags);
+
+	dump_fdif_results(v4l2_fr, __func__);
+
+	/*queue the detection result to complete queue*/
+	fdif_add_detection(dev, v4l2_fr);
+
+	if (is_err)
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+	else
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
+
+	wake_up(&dev->fdif_dq.wq);
+
+	return cnt;
+
+out_err:
+	kfree(v4l2_fr);
+out:
+	spin_unlock_irqrestore(&fdif->lock, flags);
+	return cnt;
+}
+
+static int __submit_detection(struct fdif_qvga *fdif)
+{
+	struct fdif_dev *dev = fdif->dev;
+	struct fdif_buffer *buf;
+	unsigned long flags;
+	unsigned int ret = 0;
+
+	buf = fdif_get_buffer(dev);
+	if (!buf)
+		goto out;
+
+	spin_lock_irqsave(&fdif->lock, flags);
+	if (fdif->pending) {
+		spin_unlock_irqrestore(&fdif->lock, flags);
+		ret = -EBUSY;
+		goto out;
+	}
+	fdif->pending = buf;
+	__start_detect(fdif);
+	spin_unlock_irqrestore(&fdif->lock, flags);
+
+	return 0;
+
+out:
+	return ret;
+}
+
+static irqreturn_t handle_detection(int irq, void *__fdif)
+{
+	unsigned long irqsts;
+	struct fdif_qvga *fdif = __fdif;
+	irqreturn_t ret = IRQ_HANDLED;
+
+	/*clear irq status*/
+	irqsts = fd_readl(fdif->base, FDIF_IRQSTATUS_j);
+
+	if (irqsts & (FINISH_IRQ | ERR_IRQ)) {
+		int is_err = irqsts & ERR_IRQ;
+
+		fd_writel(fdif->base, FDIF_IRQSTATUS_j, irqsts);
+
+		read_faces(fdif, is_err);
+		if (is_err)
+			softreset_fdif(fdif);
+
+		__submit_detection(fdif);
+	} else {
+		ret = IRQ_NONE;
+	}
+
+	return ret;
+}
+
+static void fdif_global_init(struct fdif_qvga *fdif)
+{
+	unsigned long conf;
+	struct device *dev = &fdif->pdev->dev;
+
+	/*softreset fdif*/
+	softreset_fdif(fdif);
+
+	/*set max tags*/
+	conf = fd_readl(fdif->base, FDIF_CTRL);
+	conf &= ~0x1e;
+	conf |= (CTRL_MAX_TAGS << 1);
+	fd_writel(fdif->base, FDIF_CTRL, conf);
+
+	/*enable error irq*/
+	conf = ERR_IRQ;
+	fd_writel(fdif->base, FDIF_IRQENABLE_SET_j, conf);
+
+	fdif->work_dma = dma_map_single(dev,
+				fdif->work_mem_addr,
+		                WORK_MEM_SIZE,
+				DMA_TO_DEVICE);
+	fd_writel(fdif->base, FDIF_WKADDR, fdif->work_dma);
+}
+
+static void fdif_global_deinit(struct fdif_qvga *fdif)
+{
+	unsigned long conf;
+	struct device *dev = &fdif->pdev->dev;
+
+	/*enable error irq*/
+	conf = ERR_IRQ;
+	fd_writel(fdif->base, FDIF_IRQENABLE_CLR_j, conf);
+
+	dma_unmap_single(dev, fdif->work_dma,
+			WORK_MEM_SIZE, DMA_TO_DEVICE);
+}
+
+
+static int start_detect(struct fdif_dev *dev)
+{
+	struct fdif_qvga *fdif = dev_get_drvdata(dev->dev);
+
+	pm_runtime_get_sync(dev->dev);
+	fdif_global_init(fdif);
+
+	return  __submit_detection(fdif);
+}
+
+static int stop_detect(struct fdif_dev *dev)
+{
+	struct fdif_qvga *fdif = dev_get_drvdata(dev->dev);
+	unsigned long flags, irqsts;
+	struct fdif_buffer	*buf;
+
+	spin_lock_irqsave(&fdif->lock, flags);
+
+	/*stop current transfer first*/
+	__stop_detect(fdif);
+
+	buf = fdif->pending;
+	fdif->pending = NULL;
+
+	/*clear irq status in case that it is set*/
+	irqsts = fd_readl(fdif->base, FDIF_IRQSTATUS_j);
+	fd_writel(fdif->base, FDIF_IRQSTATUS_j, irqsts);
+
+	spin_unlock_irqrestore(&fdif->lock, flags);
+
+	if (buf)
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+
+	fdif_global_deinit(fdif);
+	pm_runtime_put(dev->dev);
+	return 0;
+}
+
+static int submit_detect(struct fdif_dev *dev)
+{
+	struct fdif_qvga *fdif = dev_get_drvdata(dev->dev);
+
+	__submit_detection(fdif);
+
+	return 0;
+}
+
+static struct fdif_ops qvga_ops = {
+	.table	= qvga_fmt,
+	.fmt_cnt = 1,
+	.start_detect = start_detect,
+	.stop_detect = stop_detect,
+	.submit_detect = submit_detect,
+};
+
+static int fdif_probe(struct platform_device *pdev)
+{
+	struct device	*dev = &pdev->dev;
+	struct fdif_qvga *fdif;
+	struct fdif_dev *fdev;
+	struct resource *res;
+	int ret, order;
+
+	ret = fdif_create_instance(dev, sizeof(struct fdif_qvga),
+			&qvga_ops, &fdev);
+	if (ret) {
+		dev_err(dev, "fdif_create_instance failed:%d\n", ret);
+		goto end_probe;
+	}
+
+	fdif = (struct fdif_qvga *)fdev->priv;
+	fdif->dev = fdev;
+
+	spin_lock_init(&fdif->lock);
+	fdif->pdev = pdev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "fdif get resource failed\n");
+		ret = -ENODEV;
+		goto err_iomap;
+	}
+
+	fdif->base = ioremap(res->start, resource_size(res));
+	if (!fdif->base) {
+		dev_err(dev, "fdif ioremap failed\n");
+		ret = -ENOMEM;
+		goto err_iomap;
+	}
+
+	fdif->irq = platform_get_irq(pdev, 0);
+	if (fdif->irq < 0) {
+		dev_err(dev, "fdif get irq failed\n");
+		ret = -ENODEV;
+		goto err_get_irq;
+	}
+
+	ret = request_irq(fdif->irq, handle_detection, 0, "fdif-qvga",
+			fdif);
+	if (ret) {
+		dev_err(dev, "request_irq failed:%d\n", ret);
+		goto err_get_irq;
+	}
+
+	order = get_order(WORK_MEM_SIZE);
+	fdif->work_mem_addr = (void *)__get_free_pages(GFP_KERNEL, order);
+	if (!fdif->work_mem_addr) {
+		dev_err(dev, "fdif buffer allocation(%d) failed\n", order);
+		ret = -ENOMEM;
+		goto err_work_mem;
+	}
+
+	install_default_setting(fdif);
+
+	platform_set_drvdata(pdev, fdif);
+
+	pm_suspend_ignore_children(dev, true);
+	pm_runtime_get_sync(dev);
+	dev_info(dev, "fdif version=%8x hwinfo=%08x\n",
+			fd_readl(fdif->base, FDIF_REVISION),
+			fd_readl(fdif->base, FDIF_HWINFO));
+	pm_runtime_put(dev);
+
+	return 0;
+
+err_work_mem:
+	free_irq(fdif->irq, fdif);
+err_get_irq:
+	iounmap(fdif->base);
+err_iomap:
+	kref_put(&fdif->dev->ref, fdif_release);
+end_probe:
+	return ret;
+}
+
+static int fdif_remove(struct platform_device *pdev)
+{
+	struct fdif_qvga *fdif = platform_get_drvdata(pdev);
+	int order;
+
+	platform_set_drvdata(pdev, NULL);
+
+	free_irq(fdif->irq, fdif);
+
+	order = get_order(WORK_MEM_SIZE);
+	free_pages((unsigned long)fdif->work_mem_addr, order);
+
+	iounmap(fdif->base);
+
+	kref_put(&fdif->dev->ref, fdif_release);
+
+	return 0;
+}
+
+static int fdif_suspend(struct platform_device *pdev, pm_message_t msg)
+{
+	return 0;
+}
+
+static int fdif_resume(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_device_id fdif_device_ids[] = {
+	{.name = "fdif"},
+	{},
+};
+
+struct platform_driver fdif_driver = {
+	.probe =	fdif_probe,
+	.remove =	fdif_remove,
+	.suspend =	fdif_suspend,
+	.resume =	fdif_resume,
+	.driver = {
+		.name  =	"fdif",
+		.owner =	THIS_MODULE,
+	},
+	.id_table = 	fdif_device_ids,
+};
+
+static int __init omap4_fdif_init(void)
+{
+	int retval;
+	retval = platform_driver_register(&fdif_driver);
+	if (retval) {
+		printk(KERN_ERR "Unable to register fdif driver\n");
+		return retval;
+	}
+	return 0;
+}
+
+static void omap4_fdif_cleanup(void)
+{
+	platform_driver_unregister(&fdif_driver);
+}
+
+module_init(omap4_fdif_init);
+module_exit(omap4_fdif_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:fdif");
+MODULE_AUTHOR("Ming Lei");
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 0/7] media&omap4: introduce face detection(FD) driver
  2011-12-02  9:12 [RFC PATCH v1 0/7] media&omap4: introduce face detection(FD) driver Ming Lei
                   ` (6 preceding siblings ...)
  2011-12-02  9:12 ` [RFC PATCH v1 7/7] media: video: introduce omap4 face detection module driver Ming Lei
@ 2011-12-02 10:28 ` Sylwester Nawrocki
  2011-12-02 14:59   ` Ming Lei
  7 siblings, 1 reply; 26+ messages in thread
From: Sylwester Nawrocki @ 2011-12-02 10:28 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Ming,

On 12/02/2011 10:12 AM, Ming Lei wrote:
> Hi,
> 
> These v1 patches(against -next tree) introduce v4l2 based face
> detection(FD) device driver, and enable FD hardware[1] on omap4 SoC..
> The idea of implementing it on v4l2 is from from Alan Cox, Sylwester
> and Greg-Kh.
> 
> For verification purpose, I write one user space utility[2] to
> test the module and driver, follows its basic functions:
> 
> 	- detect faces in input grayscal picture(PGM raw, 320 by 240)
> 	- detect faces in input y8 format video stream
> 	- plot a rectangle to mark the detected faces, and save it as 
> 	another same format picture or video stream
> 
> Looks the performance of the module is not bad, see some detection
> results on the link[3][4].
> 
> Face detection can be used to implement some interesting applications
> (camera, face unlock, baby monitor, ...).
> 
> TODO:
> 	- implement FD setting interfaces with v4l2 controls or
> 	ext controls
> 
> thanks,
> --
> Ming Lei
> 
> [1], Ch9 of OMAP4 Technical Reference Manual
> [2], http://kernel.ubuntu.com/git?p=ming/fdif.git;a=shortlog;h=refs/heads/v4l2-fdif
> [3], http://kernel.ubuntu.com/~ming/dev/fdif/output
> [4], All pictures are taken from http://www.google.com/imghp
> and converted to pnm from jpeg format, only for test purpose.
> 

Could you please resend this series to Linux Media mailing list
(linux-media at vger.kernel.org) ? It touches V4L core code and I'm
sure other v4l2 developers will have some comments on it.
I'll try to review it on the weekend.

-- 

Thanks,
Sylwester

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 2/7] omap4: build fdif omap device from hwmod
  2011-12-02  9:12 ` [RFC PATCH v1 2/7] omap4: build fdif omap device from hwmod Ming Lei
@ 2011-12-02 12:10   ` Sergei Shtylyov
  2011-12-05  4:25     ` Ming Lei
  0 siblings, 1 reply; 26+ messages in thread
From: Sergei Shtylyov @ 2011-12-02 12:10 UTC (permalink / raw)
  To: linux-arm-kernel

Hello.

On 02-12-2011 13:12, Ming Lei wrote:

> Signed-off-by: Ming Lei<ming.lei@canonical.com>
> ---
>   arch/arm/mach-omap2/devices.c |   33 +++++++++++++++++++++++++++++++++
>   1 files changed, 33 insertions(+), 0 deletions(-)

> diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
> index 1166bdc..a392af5 100644
> --- a/arch/arm/mach-omap2/devices.c
> +++ b/arch/arm/mach-omap2/devices.c
> @@ -728,6 +728,38 @@ void __init omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data)
>
>   #endif
>
> +static struct platform_device* __init omap4_init_fdif(void)

    Shouldn't there be space before *? checkpatch.pl is silent about it?
ALso, I'd have placed '__init' after 'static'...

> +{
> +	int id = -1;
> +	struct platform_device *pd;
> +	struct omap_hwmod *oh;
> +	const char *dev_name = "fdif";

    Why you need this variable at all?

WBR, Sergei

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 5/7] media: v4l2: introduce two IOCTLs for face detection
  2011-12-02  9:12 ` [RFC PATCH v1 5/7] media: v4l2: introduce two IOCTLs for face detection Ming Lei
@ 2011-12-02 12:33   ` Arnd Bergmann
  2011-12-04 11:18     ` Ming Lei
  0 siblings, 1 reply; 26+ messages in thread
From: Arnd Bergmann @ 2011-12-02 12:33 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday 02 December 2011 17:12:56 Ming Lei wrote:
> +/**
> + * struct v4l2_fd_result - VIDIOC_G_FD_RESULT argument
> + * @buf_index: entry, index of v4l2_buffer for face detection
> + * @face_cnt:  return, how many faces detected from the @buf_index
> + * @fd:                return, result of faces' detection
> + */
> +struct v4l2_fd_result {
> +       __u32   buf_index;
> +       __u32   face_cnt;
> +       __u32   reserved[6];
> +       struct v4l2_fd_detection *fd;
> +};


This data structure is not 32/64 bit safe: running a 64 bit kernel with 32 bit
user space will see an incompatible layout.

One way to solve this is to remove the pointer and just start the array
directly after the __u32 members. Alternatively, you can use a __u64
to pass the pointer in an integer representation.

A nicer interface from the data structure perspective would be to
get rid of the array altogether and always return exactly one face.

	Arnd

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 0/7] media&omap4: introduce face detection(FD) driver
  2011-12-02 10:28 ` [RFC PATCH v1 0/7] media&omap4: introduce face detection(FD) driver Sylwester Nawrocki
@ 2011-12-02 14:59   ` Ming Lei
  0 siblings, 0 replies; 26+ messages in thread
From: Ming Lei @ 2011-12-02 14:59 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Fri, Dec 2, 2011 at 6:28 PM, Sylwester Nawrocki <snjw23@gmail.com> wrote:
> Hi Ming,
>
> On 12/02/2011 10:12 AM, Ming Lei wrote:
>> Hi,
>>
>> These v1 patches(against -next tree) introduce v4l2 based face
>> detection(FD) device driver, and enable FD hardware[1] on omap4 SoC..
>> The idea of implementing it on v4l2 is from from Alan Cox, Sylwester
>> and Greg-Kh.
>>
>> For verification purpose, I write one user space utility[2] to
>> test the module and driver, follows its basic functions:
>>
>> ? ? ? - detect faces in input grayscal picture(PGM raw, 320 by 240)
>> ? ? ? - detect faces in input y8 format video stream
>> ? ? ? - plot a rectangle to mark the detected faces, and save it as
>> ? ? ? another same format picture or video stream
>>
>> Looks the performance of the module is not bad, see some detection
>> results on the link[3][4].
>>
>> Face detection can be used to implement some interesting applications
>> (camera, face unlock, baby monitor, ...).
>>
>> TODO:
>> ? ? ? - implement FD setting interfaces with v4l2 controls or
>> ? ? ? ext controls
>>
>> thanks,
>> --
>> Ming Lei
>>
>> [1], Ch9 of OMAP4 Technical Reference Manual
>> [2], http://kernel.ubuntu.com/git?p=ming/fdif.git;a=shortlog;h=refs/heads/v4l2-fdif
>> [3], http://kernel.ubuntu.com/~ming/dev/fdif/output
>> [4], All pictures are taken from http://www.google.com/imghp
>> and converted to pnm from jpeg format, only for test purpose.
>>
>
> Could you please resend this series to Linux Media mailing list
> (linux-media at vger.kernel.org) ? It touches V4L core code and I'm

Yes, I will resend this series to linux-media mail list, thanks for pointing
it out.  Of course, the most important mail list is missed for the patches,
very sorry about it.

thanks,
--
Ming Lei

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 0/7] media&omap4: introduce face detection(FD) driver
@ 2011-12-02 15:02 Ming Lei
  0 siblings, 0 replies; 26+ messages in thread
From: Ming Lei @ 2011-12-02 15:02 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

These v1 patches(against -next tree) introduce v4l2 based face
detection(FD) device driver, and enable FD hardware[1] on omap4 SoC..
The idea of implementing it on v4l2 is from from Alan Cox, Sylwester
and Greg-Kh.

For verification purpose, I write one user space utility[2] to
test the module and driver, follows its basic functions:

	- detect faces in input grayscal picture(PGM raw, 320 by 240)
	- detect faces in input y8 format video stream
	- plot a rectangle to mark the detected faces, and save it as 
	another same type grayscal picture

Looks the performance of the module is not bad, see some detection
results on the link[3][4].

Face detection can be used to implement some interesting applications
(camera, face unlock, baby monitor, ...).

TODO:
	- implement FD setting interfaces with v4l2 controls or
	ext controls

thanks,
--
Ming Lei

[1], Ch9 of OMAP4 Technical Reference Manual
[2], http://kernel.ubuntu.com/git?p=ming/fdif.git;a=shortlog;h=refs/heads/v4l2-fdif
[3], http://kernel.ubuntu.com/~ming/dev/fdif/output
[4], All pictures are taken from http://www.google.com/imghp
and converted to pnm from jpeg format, only for test purpose.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 4/7] media: videobuf2: introduce VIDEOBUF2_PAGE memops
  2011-12-02  9:12 ` [RFC PATCH v1 4/7] media: videobuf2: introduce VIDEOBUF2_PAGE memops Ming Lei
@ 2011-12-02 16:35   ` Aguirre, Sergio
  2011-12-05  2:16     ` Ming Lei
  0 siblings, 1 reply; 26+ messages in thread
From: Aguirre, Sergio @ 2011-12-02 16:35 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Ming,

On Fri, Dec 2, 2011 at 3:12 AM, Ming Lei <ming.lei@canonical.com> wrote:
> DMA contig memory resource is very limited and precious, also
> accessing to it from CPU is very slow on some platform.
>
> For some cases(such as the comming face detection driver), DMA Streaming
> buffer is enough, so introduce VIDEOBUF2_PAGE to allocate continuous
> physical memory but letting video device driver to handle DMA buffer mapping
> and unmapping things.
>
> Signed-off-by: Ming Lei <ming.lei@canonical.com>
> ---
> ?drivers/media/video/Kconfig ? ? ? ? ?| ? ?4 +
> ?drivers/media/video/Makefile ? ? ? ? | ? ?1 +
> ?drivers/media/video/videobuf2-page.c | ?115 ++++++++++++++++++++++++++++++++++
> ?include/media/videobuf2-page.h ? ? ? | ? 20 ++++++
> ?4 files changed, 140 insertions(+), 0 deletions(-)
> ?create mode 100644 drivers/media/video/videobuf2-page.c
> ?create mode 100644 include/media/videobuf2-page.h
>
> diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
> index 4e8a0c4..5684a00 100644
> --- a/drivers/media/video/Kconfig
> +++ b/drivers/media/video/Kconfig
> @@ -60,6 +60,10 @@ config VIDEOBUF2_VMALLOC
> ? ? ? ?select VIDEOBUF2_MEMOPS
> ? ? ? ?tristate
>
> +config VIDEOBUF2_PAGE
> + ? ? ? select VIDEOBUF2_CORE
> + ? ? ? select VIDEOBUF2_MEMOPS
> + ? ? ? tristate
>
> ?config VIDEOBUF2_DMA_SG
> ? ? ? ?#depends on HAS_DMA
> diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
> index ddeaa6c..bc797f2 100644
> --- a/drivers/media/video/Makefile
> +++ b/drivers/media/video/Makefile
> @@ -125,6 +125,7 @@ obj-$(CONFIG_VIDEO_BTCX) ?+= btcx-risc.o
> ?obj-$(CONFIG_VIDEOBUF2_CORE) ? ? ? ? ? += videobuf2-core.o
> ?obj-$(CONFIG_VIDEOBUF2_MEMOPS) ? ? ? ? += videobuf2-memops.o
> ?obj-$(CONFIG_VIDEOBUF2_VMALLOC) ? ? ? ? ? ? ? ?+= videobuf2-vmalloc.o
> +obj-$(CONFIG_VIDEOBUF2_PAGE) ? ? ? ? ? += videobuf2-page.o
> ?obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) ? ? += videobuf2-dma-contig.o
> ?obj-$(CONFIG_VIDEOBUF2_DMA_SG) ? ? ? ? += videobuf2-dma-sg.o
>
> diff --git a/drivers/media/video/videobuf2-page.c b/drivers/media/video/videobuf2-page.c
> new file mode 100644
> index 0000000..b3f003a
> --- /dev/null
> +++ b/drivers/media/video/videobuf2-page.c
> @@ -0,0 +1,115 @@
> +/*
> + * videobuf2-page.c - page memory allocator for videobuf2
> + *
> + * Copyright (C) 2011 Canonical Ltd.
> + *
> + * Author: Ming Lei <ming.lei@canonical.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/mm.h>
> +#include <linux/slab.h>
> +
> +#include <media/videobuf2-core.h>
> +#include <media/videobuf2-memops.h>
> +
> +struct vb2_page_buf {
> + ? ? ? void ? ? ? ? ? ? ? ? ? ? ? ? ? ?*vaddr;
> + ? ? ? unsigned long ? ? ? ? ? ? ? ? ? size;
> + ? ? ? atomic_t ? ? ? ? ? ? ? ? ? ? ? ?refcount;
> + ? ? ? struct vb2_vmarea_handler ? ? ? handler;
> +};
> +
> +static void vb2_page_put(void *buf_priv);
> +
> +static void *vb2_page_alloc(void *alloc_ctx, unsigned long size)
> +{
> + ? ? ? struct vb2_page_buf *buf;
> +
> + ? ? ? buf = kzalloc(sizeof *buf, GFP_KERNEL);
> + ? ? ? if (!buf)
> + ? ? ? ? ? ? ? return NULL;
> +
> + ? ? ? buf->size = size;
> + ? ? ? buf->vaddr = (void *)__get_free_pages(GFP_KERNEL,
> + ? ? ? ? ? ? ? ? ? ? ? get_order(buf->size));
> + ? ? ? buf->handler.refcount = &buf->refcount;
> + ? ? ? buf->handler.put = vb2_page_put;
> + ? ? ? buf->handler.arg = buf;
> +
> + ? ? ? if (!buf->vaddr) {
> + ? ? ? ? ? ? ? printk(KERN_ERR "page of size %ld failed\n", buf->size);
> + ? ? ? ? ? ? ? kfree(buf);
> + ? ? ? ? ? ? ? return NULL;
> + ? ? ? }
> +
> + ? ? ? atomic_inc(&buf->refcount);
> + ? ? ? printk(KERN_DEBUG "Allocated page buffer of size %ld at vaddr=%p\n",
> + ? ? ? ? ? ? ? ? ? ? ? buf->size, buf->vaddr);
> +
> + ? ? ? return buf;
> +}
> +
> +static void vb2_page_put(void *buf_priv)
> +{
> + ? ? ? struct vb2_page_buf *buf = buf_priv;
> +
> + ? ? ? if (atomic_dec_and_test(&buf->refcount)) {
> + ? ? ? ? ? ? ? printk(KERN_DEBUG "%s: Freeing page mem at vaddr=%p\n",
> + ? ? ? ? ? ? ? ? ? ? ? __func__, buf->vaddr);
> + ? ? ? ? ? ? ? free_pages((unsigned long)buf->vaddr, get_order(buf->size));
> + ? ? ? ? ? ? ? kfree(buf);
> + ? ? ? }
> +}
> +
> +static void *vb2_page_vaddr(void *buf_priv)
> +{
> + ? ? ? struct vb2_page_buf *buf = buf_priv;
> +
> + ? ? ? BUG_ON(!buf);
> +
> + ? ? ? if (!buf->vaddr) {
> + ? ? ? ? ? ? ? printk(KERN_ERR "Address of an unallocated plane requested\n");
> + ? ? ? ? ? ? ? return NULL;
> + ? ? ? }
> +
> + ? ? ? return buf->vaddr;
> +}
> +
> +static unsigned int vb2_page_num_users(void *buf_priv)
> +{
> + ? ? ? struct vb2_page_buf *buf = buf_priv;
> + ? ? ? return atomic_read(&buf->refcount);
> +}
> +
> +static int vb2_page_mmap(void *buf_priv, struct vm_area_struct *vma)
> +{
> + ? ? ? struct vb2_page_buf *buf = buf_priv;
> +
> + ? ? ? if (!buf) {
> + ? ? ? ? ? ? ? printk(KERN_ERR "No memory to map\n");
> + ? ? ? ? ? ? ? return -EINVAL;
> + ? ? ? }
> +
> + ? ? ? vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
> + ? ? ? return vb2_mmap_pfn_range(vma, virt_to_phys(buf->vaddr),
> + ? ? ? ? ? ? ? ? ? ? ? buf->size, &vb2_common_vm_ops,
> + ? ? ? ? ? ? ? ? ? ? ? &buf->handler);
> +}
> +
> +const struct vb2_mem_ops vb2_page_memops = {
> + ? ? ? .alloc ? ? ? ? ?= vb2_page_alloc,
> + ? ? ? .put ? ? ? ? ? ?= vb2_page_put,
> + ? ? ? .vaddr ? ? ? ? ?= vb2_page_vaddr,
> + ? ? ? .mmap ? ? ? ? ? = vb2_page_mmap,
> + ? ? ? .num_users ? ? ?= vb2_page_num_users,
> +};
> +EXPORT_SYMBOL_GPL(vb2_page_memops);
> +
> +MODULE_DESCRIPTION("page memory handling routines for videobuf2");
> +MODULE_AUTHOR("Ming Lei");
> +MODULE_LICENSE("GPL");
> diff --git a/include/media/videobuf2-page.h b/include/media/videobuf2-page.h
> new file mode 100644
> index 0000000..29b3e20
> --- /dev/null
> +++ b/include/media/videobuf2-page.h
> @@ -0,0 +1,20 @@
> +/*
> + * videobuf2-vmalloc.h - vmalloc memory allocator for videobuf2
> + *
> + * Copyright (C) 2010 Samsung Electronics
> + *
> + * Author: Pawel Osciak <pawel@osciak.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation.
> + */
> +
> +#ifndef _MEDIA_VIDEOBUF2_VMALLOC_H
> +#define _MEDIA_VIDEOBUF2_VMALLOC_H

Copy-paste much? :)

Fix header and match above define with something that matches the actual file:

#ifndef _MEDIA_VIDEOBUF2_PAGE_H
#define _MEDIA_VIDEOBUF2_PAGE_H

Regards,
Sergio

> +
> +#include <media/videobuf2-core.h>
> +
> +extern const struct vb2_mem_ops vb2_page_memops;
> +
> +#endif
> --
> 1.7.5.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 5/7] media: v4l2: introduce two IOCTLs for face detection
  2011-12-02 12:33   ` Arnd Bergmann
@ 2011-12-04 11:18     ` Ming Lei
  2011-12-05 14:37       ` Arnd Bergmann
  0 siblings, 1 reply; 26+ messages in thread
From: Ming Lei @ 2011-12-04 11:18 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Fri, Dec 2, 2011 at 8:33 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Friday 02 December 2011 17:12:56 Ming Lei wrote:
>> +/**
>> + * struct v4l2_fd_result - VIDIOC_G_FD_RESULT argument
>> + * @buf_index: entry, index of v4l2_buffer for face detection
>> + * @face_cnt: ?return, how many faces detected from the @buf_index
>> + * @fd: ? ? ? ? ? ? ? ?return, result of faces' detection
>> + */
>> +struct v4l2_fd_result {
>> + ? ? ? __u32 ? buf_index;
>> + ? ? ? __u32 ? face_cnt;
>> + ? ? ? __u32 ? reserved[6];
>> + ? ? ? struct v4l2_fd_detection *fd;
>> +};
>
>
> This data structure is not 32/64 bit safe: running a 64 bit kernel with 32 bit
> user space will see an incompatible layout.

I agree that this is not 32/64 bit safe, but I understand lib32 can handle
this correctly, otherwise many 32bit applications can't run on current
64bit kernel
since many kernel structures used by user space contained pointer,
such as struct v4l2_buffer, struct v4l2_ext_controls in v4l2 ABI.

> One way to solve this is to remove the pointer and just start the array
> directly after the __u32 members. Alternatively, you can use a __u64
> to pass the pointer in an integer representation.

So I think this need not to be solved.

>
> A nicer interface from the data structure perspective would be to
> get rid of the array altogether and always return exactly one face.

I choose to return array to user space since v4l2 ioctl has provided
this kind of support, see video_usercopy().

thanks,
--
Ming Lei

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 4/7] media: videobuf2: introduce VIDEOBUF2_PAGE memops
  2011-12-02 16:35   ` Aguirre, Sergio
@ 2011-12-05  2:16     ` Ming Lei
  0 siblings, 0 replies; 26+ messages in thread
From: Ming Lei @ 2011-12-05  2:16 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Sat, Dec 3, 2011 at 12:35 AM, Aguirre, Sergio <saaguirre@ti.com> wrote:
> Hi Ming,
>> diff --git a/include/media/videobuf2-page.h b/include/media/videobuf2-page.h
>> new file mode 100644
>> index 0000000..29b3e20
>> --- /dev/null
>> +++ b/include/media/videobuf2-page.h
>> @@ -0,0 +1,20 @@
>> +/*
>> + * videobuf2-vmalloc.h - vmalloc memory allocator for videobuf2
>> + *
>> + * Copyright (C) 2010 Samsung Electronics
>> + *
>> + * Author: Pawel Osciak <pawel@osciak.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation.
>> + */
>> +
>> +#ifndef _MEDIA_VIDEOBUF2_VMALLOC_H
>> +#define _MEDIA_VIDEOBUF2_VMALLOC_H
>
> Copy-paste much? :)

Yes, will fix it in next version, :-)

thanks,
--
Ming Lei

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 2/7] omap4: build fdif omap device from hwmod
  2011-12-02 12:10   ` Sergei Shtylyov
@ 2011-12-05  4:25     ` Ming Lei
  0 siblings, 0 replies; 26+ messages in thread
From: Ming Lei @ 2011-12-05  4:25 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Fri, Dec 2, 2011 at 8:10 PM, Sergei Shtylyov <sshtylyov@ru.mvista.com> wrote:
> Hello.
>
>
> On 02-12-2011 13:12, Ming Lei wrote:
>
>> Signed-off-by: Ming Lei<ming.lei@canonical.com>
>> ---
>> ?arch/arm/mach-omap2/devices.c | ? 33 +++++++++++++++++++++++++++++++++
>> ?1 files changed, 33 insertions(+), 0 deletions(-)
>
>
>> diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
>> index 1166bdc..a392af5 100644
>> --- a/arch/arm/mach-omap2/devices.c
>> +++ b/arch/arm/mach-omap2/devices.c
>> @@ -728,6 +728,38 @@ void __init omap242x_init_mmc(struct
>> omap_mmc_platform_data **mmc_data)
>>
>> ?#endif
>>
>> +static struct platform_device* __init omap4_init_fdif(void)
>
>
> ? Shouldn't there be space before *? checkpatch.pl is silent about it?
> ALso, I'd have placed '__init' after 'static'...

Yes, you are right, will do do it in next version.

>
>> +{
>> + ? ? ? int id = -1;
>> + ? ? ? struct platform_device *pd;
>> + ? ? ? struct omap_hwmod *oh;
>> + ? ? ? const char *dev_name = "fdif";
>
>
> ? Why you need this variable at all?

Will remove some of them.

thanks,
--
Ming Lei

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 5/7] media: v4l2: introduce two IOCTLs for face detection
  2011-12-04 11:18     ` Ming Lei
@ 2011-12-05 14:37       ` Arnd Bergmann
  2011-12-06  6:30         ` Ming Lei
  0 siblings, 1 reply; 26+ messages in thread
From: Arnd Bergmann @ 2011-12-05 14:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Sunday 04 December 2011, Ming Lei wrote:
> >
> > This data structure is not 32/64 bit safe: running a 64 bit kernel with 32 bit
> > user space will see an incompatible layout.
> 
> I agree that this is not 32/64 bit safe, but I understand lib32 can handle
> this correctly, otherwise many 32bit applications can't run on current
> 64bit kernel
> since many kernel structures used by user space contained pointer,
> such as struct v4l2_buffer, struct v4l2_ext_controls in v4l2 ABI.

The other ones you mentioned are handled in the kernel in
drivers/media/video/v4l2-compat-ioctl32.c. For new ioctl commands,
it's better to define the data structure in a compatible way
so you do not need a wrapper like that.

	Arnd

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 5/7] media: v4l2: introduce two IOCTLs for face detection
  2011-12-05 14:37       ` Arnd Bergmann
@ 2011-12-06  6:30         ` Ming Lei
  2011-12-06 12:55           ` Arnd Bergmann
  0 siblings, 1 reply; 26+ messages in thread
From: Ming Lei @ 2011-12-06  6:30 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Mon, Dec 5, 2011 at 10:37 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Sunday 04 December 2011, Ming Lei wrote:
>> >
>> > This data structure is not 32/64 bit safe: running a 64 bit kernel with 32 bit
>> > user space will see an incompatible layout.
>>
>> I agree that this is not 32/64 bit safe, but I understand lib32 can handle
>> this correctly, otherwise many 32bit applications can't run on current
>> 64bit kernel
>> since many kernel structures used by user space contained pointer,
>> such as struct v4l2_buffer, struct v4l2_ext_controls in v4l2 ABI.
>
> The other ones you mentioned are handled in the kernel in
> drivers/media/video/v4l2-compat-ioctl32.c. For new ioctl commands,
> it's better to define the data structure in a compatible way
> so you do not need a wrapper like that.

OK, I opt to use __u64 to pass the user pointer, so how about the blow
changes on this patch?

diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 073eb4d..8aeaa1e 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -2214,7 +2214,12 @@ struct v4l2_fd_result {
 	__u32	buf_index;
 	__u32	face_cnt;
 	__u32	reserved[6];
-	struct v4l2_fd_detection *fd;
+
+	/*make 64/32 compatible*/
+	union {
+		struct v4l2_fd_detection *fd;
+		__u64	dummy;
+	};
 };

 /**

thanks,
--
Ming Lei

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 5/7] media: v4l2: introduce two IOCTLs for face detection
  2011-12-06  6:30         ` Ming Lei
@ 2011-12-06 12:55           ` Arnd Bergmann
  2011-12-06 13:11             ` Ming Lei
  0 siblings, 1 reply; 26+ messages in thread
From: Arnd Bergmann @ 2011-12-06 12:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday 06 December 2011, Ming Lei wrote:
> diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
> index 073eb4d..8aeaa1e 100644
> --- a/include/linux/videodev2.h
> +++ b/include/linux/videodev2.h
> @@ -2214,7 +2214,12 @@ struct v4l2_fd_result {
>         __u32   buf_index;
>         __u32   face_cnt;
>         __u32   reserved[6];
> -       struct v4l2_fd_detection *fd;
> +
> +       /*make 64/32 compatible*/
> +       union {
> +               struct v4l2_fd_detection *fd;
> +               __u64   dummy;
> +       };
>  };
> 

That's not compatible, at least not on any big-endian architecture.
If you want to have an indirect pointer, you have to cast it to the
__u64 member in user space and back in kernel space.

Using an array added to the end of the v4l2_fd_result structure
rather than a pointer would really make this easier IMHO.

	Arnd

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 5/7] media: v4l2: introduce two IOCTLs for face detection
  2011-12-06 12:55           ` Arnd Bergmann
@ 2011-12-06 13:11             ` Ming Lei
  2011-12-06 14:41               ` Arnd Bergmann
  0 siblings, 1 reply; 26+ messages in thread
From: Ming Lei @ 2011-12-06 13:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Dec 6, 2011 at 8:55 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Tuesday 06 December 2011, Ming Lei wrote:
>> diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
>> index 073eb4d..8aeaa1e 100644
>> --- a/include/linux/videodev2.h
>> +++ b/include/linux/videodev2.h
>> @@ -2214,7 +2214,12 @@ struct v4l2_fd_result {
>> ? ? ? ? __u32 ? buf_index;
>> ? ? ? ? __u32 ? face_cnt;
>> ? ? ? ? __u32 ? reserved[6];
>> - ? ? ? struct v4l2_fd_detection *fd;
>> +
>> + ? ? ? /*make 64/32 compatible*/
>> + ? ? ? union {
>> + ? ? ? ? ? ? ? struct v4l2_fd_detection *fd;
>> + ? ? ? ? ? ? ? __u64 ? dummy;
>> + ? ? ? };
>> ?};
>>
>
> That's not compatible, at least not on any big-endian architecture.
> If you want to have an indirect pointer, you have to cast it to the
> __u64 member in user space and back in kernel space.

Looks like it is a bit ugly.

>
> Using an array added to the end of the v4l2_fd_result structure
> rather than a pointer would really make this easier IMHO.

I have tried to do this, but video_usercopy needs a few changes
to handle array args if no indirect pointer is passed to kernel.

I am not sure if media guys are happy to accept the changes, :-)

thanks,
--
Ming Lei

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 5/7] media: v4l2: introduce two IOCTLs for face detection
  2011-12-06 13:11             ` Ming Lei
@ 2011-12-06 14:41               ` Arnd Bergmann
  2011-12-06 14:52                 ` Ming Lei
  0 siblings, 1 reply; 26+ messages in thread
From: Arnd Bergmann @ 2011-12-06 14:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday 06 December 2011, Ming Lei wrote:
> > Using an array added to the end of the v4l2_fd_result structure
> > rather than a pointer would really make this easier IMHO.
> 
> I have tried to do this, but video_usercopy needs a few changes
> to handle array args if no indirect pointer is passed to kernel.

Ah, I see. Or you would have to encode the array size into the
ioctl command, which is also ugly in a different way.

> I am not sure if media guys are happy to accept the changes, :-)

Maybe Mauro can comment on which solution he prefers then, given
the choice between:

1. adding another handler in drivers/media/video/v4l2-compat-ioctl32.c

2. passing a pointer that is casted to __u64 in user space an back
   in the kernel

3. extending video_usercopy in some way to make this work, preferably
   in a generic way.

4. using a variable command number like
   #define VIDIOC_G_FD_RESULT(num)	_IOC(_IOC_READ|_IOC_WRITE,'V', 95, \
		sizeof(struct v4l2_fd_result) + (num) * sizeof(struct v4l2_fd_detection)

5. requiring the interface to be simplified to return only a single
   struct v4l2_fd_detection at a time

I agree that none of these are nice. My preferred option would be last one,
but I don't know how performance critical the interface is or if it would
cause any races that you want to avoid.

	Arnd

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 5/7] media: v4l2: introduce two IOCTLs for face detection
  2011-12-06 14:41               ` Arnd Bergmann
@ 2011-12-06 14:52                 ` Ming Lei
  2011-12-06 15:45                   ` Ming Lei
  0 siblings, 1 reply; 26+ messages in thread
From: Ming Lei @ 2011-12-06 14:52 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Dec 6, 2011 at 10:41 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Tuesday 06 December 2011, Ming Lei wrote:
>> > Using an array added to the end of the v4l2_fd_result structure
>> > rather than a pointer would really make this easier IMHO.
>>
>> I have tried to do this, but video_usercopy needs a few changes
>> to handle array args if no indirect pointer is passed to kernel.
>
> Ah, I see. Or you would have to encode the array size into the
> ioctl command, which is also ugly in a different way.
>
>> I am not sure if media guys are happy to accept the changes, :-)
>
> Maybe Mauro can comment on which solution he prefers then, given
> the choice between:
>
> 1. adding another handler in drivers/media/video/v4l2-compat-ioctl32.c
>
> 2. passing a pointer that is casted to __u64 in user space an back
> ? in the kernel
>
> 3. extending video_usercopy in some way to make this work, preferably
> ? in a generic way.

Maybe this one is a good choice, and I think that it is worthy to
support the below kind of array parameter:

struct v4l2_fd_result {
	__u32   buf_index;
	__u32   face_cnt;
	__u32   reserved[6];
	struct v4l2_fd_detection fd[];
};

and it is not difficult to implement it in a generic way so that new
array parameters can be supported as 64/32 compatible.

> 4. using a variable command number like
> ? #define VIDIOC_G_FD_RESULT(num) ? ? ?_IOC(_IOC_READ|_IOC_WRITE,'V', 95, \
> ? ? ? ? ? ? ? ?sizeof(struct v4l2_fd_result) + (num) * sizeof(struct v4l2_fd_detection)
>
> 5. requiring the interface to be simplified to return only a single
> ? struct v4l2_fd_detection at a time

Maybe this one is not user friendly since other v4l2 interfaces provide
array parameters way, :-)

> I agree that none of these are nice. My preferred option would be last one,
> but I don't know how performance critical the interface is or if it would
> cause any races that you want to avoid.


thanks,
--
Ming Lei

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 5/7] media: v4l2: introduce two IOCTLs for face detection
  2011-12-06 14:52                 ` Ming Lei
@ 2011-12-06 15:45                   ` Ming Lei
  2011-12-06 20:59                     ` Arnd Bergmann
  0 siblings, 1 reply; 26+ messages in thread
From: Ming Lei @ 2011-12-06 15:45 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Tue, Dec 6, 2011 at 10:52 PM, Ming Lei <ming.lei@canonical.com> wrote:
> On Tue, Dec 6, 2011 at 10:41 PM, Arnd Bergmann <arnd@arndb.de> wrote:
>> 3. extending video_usercopy in some way to make this work, preferably
>> ? in a generic way.
>
> Maybe this one is a good choice, and I think that it is worthy to
> support the below kind of array parameter:
>
> struct v4l2_fd_result {
> ? ? ? ?__u32 ? buf_index;
> ? ? ? ?__u32 ? face_cnt;
> ? ? ? ?__u32 ? reserved[6];
> ? ? ? ?struct v4l2_fd_detection fd[];
> };
>
> and it is not difficult to implement it in a generic way so that new
> array parameters can be supported as 64/32 compatible.

How about the blow patch to support 64/32 compatible array parameter?

diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index e1da8fc..72c81f7 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -2239,6 +2239,26 @@ static int check_array_args(unsigned int cmd,
void *parg, size_t *array_size,
 	return ret;
 }

+static int is_64_32_array_args(unsigned int cmd, void *parg, int *extra_len)
+{
+	int ret = 0;
+
+	switch (cmd) {
+	case VIDIOC_G_FD_RESULT: {
+		struct v4l2_fd_result *fr = parg;
+
+		*extra_len = fr->faces_cnt *
+			sizeof(struct v4l2_fd_detection);
+		ret = 1;
+		break;
+	}
+	default:
+		break;
+	}
+
+	return ret;
+}
+
 long
 video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
 	       v4l2_kioctl func)
@@ -2251,6 +2271,7 @@ video_usercopy(struct file *file, unsigned int
cmd, unsigned long arg,
 	size_t  array_size = 0;
 	void __user *user_ptr = NULL;
 	void	**kernel_ptr = NULL;
+	int	extra = 0;

 	/*  Copy arguments into temp kernel buffer  */
 	if (_IOC_DIR(cmd) != _IOC_NONE) {
@@ -2280,9 +2301,29 @@ video_usercopy(struct file *file, unsigned int
cmd, unsigned long arg,
 		}
 	}

-	err = check_array_args(cmd, parg, &array_size, &user_ptr, &kernel_ptr);
+	if (is_64_32_array_args(cmd, parg, &extra)) {
+		int size;
+		void *old_mbuf;
+
+		err = 0;
+		if (!extra)
+			goto out_array_args;
+		old_mbuf = mbuf;
+		size = extra + _IOC_SIZE(cmd);
+		mbuf = kmalloc(size, GFP_KERNEL);
+		if (NULL == mbuf)
+			return -ENOMEM;
+		memcpy(mbuf, parg, _IOC_SIZE(cmd));
+		parg = mbuf;
+		kfree(old_mbuf);
+	} else {
+		err = check_array_args(cmd, parg, &array_size,
+				&user_ptr, &kernel_ptr);
+	}
+
 	if (err < 0)
 		goto out;
+out_array_args:
 	has_array_args = err;

 	if (has_array_args) {
@@ -2321,7 +2362,7 @@ out_array_args:
 	switch (_IOC_DIR(cmd)) {
 	case _IOC_READ:
 	case (_IOC_WRITE | _IOC_READ):
-		if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
+		if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd) + extra))
 			err = -EFAULT;
 		break;
 	}



thanks,
--
Ming Lei

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 5/7] media: v4l2: introduce two IOCTLs for face detection
  2011-12-06 15:45                   ` Ming Lei
@ 2011-12-06 20:59                     ` Arnd Bergmann
  0 siblings, 0 replies; 26+ messages in thread
From: Arnd Bergmann @ 2011-12-06 20:59 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday 06 December 2011 23:45:27 Ming Lei wrote:
> >
> > and it is not difficult to implement it in a generic way so that new
> > array parameters can be supported as 64/32 compatible.
> 
> How about the below patch to support 64/32 compatible array parameter?

Looks technically correct to me, if you replace the 'return -ENOMEM' with
'ret = -ENOMEM;\n goto out;'.

The video_usercopy function already has multiple micro-optimizations
(on-stack buffers, cmd_input_size) that make it more complex than
I'd hope, but your addition seems ok to me.

Let's see what Mauro thinks.

	Arnd

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [RFC PATCH v1 1/7] omap4: introduce fdif(face detect module) hwmod
  2011-12-02  9:12 ` [RFC PATCH v1 1/7] omap4: introduce fdif(face detect module) hwmod Ming Lei
@ 2011-12-13  2:42   ` Ming Lei
  0 siblings, 0 replies; 26+ messages in thread
From: Ming Lei @ 2011-12-13  2:42 UTC (permalink / raw)
  To: linux-arm-kernel

Hi guys,

Gentle ping on this patch, :-)

thanks,
--
Ming Lei

On Fri, Dec 2, 2011 at 5:12 PM, Ming Lei <ming.lei@canonical.com> wrote:
> Signed-off-by: Ming Lei <ming.lei@canonical.com>
> ---
> ?arch/arm/mach-omap2/omap_hwmod_44xx_data.c | ? 81 ++++++++++++++++++++++++++++
> ?1 files changed, 81 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
> index 6cf21ee..30db754 100644
> --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
> +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
> @@ -53,6 +53,7 @@ static struct omap_hwmod omap44xx_dmm_hwmod;
> ?static struct omap_hwmod omap44xx_dsp_hwmod;
> ?static struct omap_hwmod omap44xx_dss_hwmod;
> ?static struct omap_hwmod omap44xx_emif_fw_hwmod;
> +static struct omap_hwmod omap44xx_fdif_hwmod;
> ?static struct omap_hwmod omap44xx_hsi_hwmod;
> ?static struct omap_hwmod omap44xx_ipu_hwmod;
> ?static struct omap_hwmod omap44xx_iss_hwmod;
> @@ -354,6 +355,14 @@ static struct omap_hwmod_ocp_if omap44xx_dma_system__l3_main_2 = {
> ? ? ? ?.user ? ? ? ? ? = OCP_USER_MPU | OCP_USER_SDMA,
> ?};
>
> +/* fdif -> l3_main_2 */
> +static struct omap_hwmod_ocp_if omap44xx_fdif__l3_main_2 = {
> + ? ? ? .master ? ? ? ? = &omap44xx_fdif_hwmod,
> + ? ? ? .slave ? ? ? ? ?= &omap44xx_l3_main_2_hwmod,
> + ? ? ? .clk ? ? ? ? ? ?= "l3_div_ck",
> + ? ? ? .user ? ? ? ? ? = OCP_USER_MPU | OCP_USER_SDMA,
> +};
> +
> ?/* hsi -> l3_main_2 */
> ?static struct omap_hwmod_ocp_if omap44xx_hsi__l3_main_2 = {
> ? ? ? ?.master ? ? ? ? = &omap44xx_hsi_hwmod,
> @@ -5444,6 +5453,75 @@ static struct omap_hwmod omap44xx_wd_timer3_hwmod = {
> ? ? ? ?.slaves_cnt ? ? = ARRAY_SIZE(omap44xx_wd_timer3_slaves),
> ?};
>
> +/* 'fdif' class */
> +static struct omap_hwmod_class_sysconfig omap44xx_fdif_sysc = {
> + ? ? ? .rev_offs ? ? ? = 0x0000,
> + ? ? ? .sysc_offs ? ? ?= 0x0010,
> + ? ? ? .sysc_flags ? ? = (SYSC_HAS_MIDLEMODE | SYSC_HAS_RESET_STATUS |
> + ? ? ? ? ? ? ? ? ? ? ? ? ?SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
> + ? ? ? .idlemodes ? ? ?= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
> + ? ? ? ? ? ? ? ? ? ? ? ? ?MSTANDBY_FORCE | MSTANDBY_NO |
> + ? ? ? ? ? ? ? ? ? ? ? ? ?MSTANDBY_SMART),
> + ? ? ? .sysc_fields ? ?= &omap_hwmod_sysc_type2,
> +};
> +
> +static struct omap_hwmod_class omap44xx_fdif_hwmod_class = {
> + ? ? ? .name ? = "fdif",
> + ? ? ? .sysc ? = &omap44xx_fdif_sysc,
> +};
> +
> +/*fdif*/
> +static struct omap_hwmod_addr_space omap44xx_fdif_addrs[] = {
> + ? ? ? {
> + ? ? ? ? ? ? ? .pa_start ? ? ? = 0x4a10a000,
> + ? ? ? ? ? ? ? .pa_end ? ? ? ? = 0x4a10afff,
> + ? ? ? ? ? ? ? .flags ? ? ? ? ?= ADDR_TYPE_RT
> + ? ? ? },
> + ? ? ? { }
> +};
> +
> +/* l4_cfg -> fdif */
> +static struct omap_hwmod_ocp_if omap44xx_l4_cfg__fdif = {
> + ? ? ? .master ? ? ? ? = &omap44xx_l4_cfg_hwmod,
> + ? ? ? .slave ? ? ? ? ?= &omap44xx_fdif_hwmod,
> + ? ? ? .clk ? ? ? ? ? ?= "l4_div_ck",
> + ? ? ? .addr ? ? ? ? ? = omap44xx_fdif_addrs,
> + ? ? ? .user ? ? ? ? ? = OCP_USER_MPU | OCP_USER_SDMA,
> +};
> +
> +/* fdif slave ports */
> +static struct omap_hwmod_ocp_if *omap44xx_fdif_slaves[] = {
> + ? ? ? &omap44xx_l4_cfg__fdif,
> +};
> +static struct omap_hwmod_irq_info omap44xx_fdif_irqs[] = {
> + ? ? ? { .irq = 69 + OMAP44XX_IRQ_GIC_START },
> + ? ? ? { .irq = -1 }
> +};
> +
> +/* fdif master ports */
> +static struct omap_hwmod_ocp_if *omap44xx_fdif_masters[] = {
> + ? ? ? &omap44xx_fdif__l3_main_2,
> +};
> +
> +static struct omap_hwmod omap44xx_fdif_hwmod = {
> + ? ? ? .name ? ? ? ? ? = "fdif",
> + ? ? ? .class ? ? ? ? ?= &omap44xx_fdif_hwmod_class,
> + ? ? ? .clkdm_name ? ? = "iss_clkdm",
> + ? ? ? .mpu_irqs ? ? ? = omap44xx_fdif_irqs,
> + ? ? ? .main_clk ? ? ? = "fdif_fck",
> + ? ? ? .prcm = {
> + ? ? ? ? ? ? ? .omap4 = {
> + ? ? ? ? ? ? ? ? ? ? ? .clkctrl_offs = OMAP4_CM_CAM_FDIF_CLKCTRL_OFFSET,
> + ? ? ? ? ? ? ? ? ? ? ? .context_offs = OMAP4_RM_CAM_FDIF_CONTEXT_OFFSET,
> + ? ? ? ? ? ? ? ? ? ? ? .modulemode ? = MODULEMODE_SWCTRL,
> + ? ? ? ? ? ? ? },
> + ? ? ? },
> + ? ? ? .slaves ? ? ? ? = omap44xx_fdif_slaves,
> + ? ? ? .slaves_cnt ? ? = ARRAY_SIZE(omap44xx_fdif_slaves),
> + ? ? ? .masters ? ? ? ?= omap44xx_fdif_masters,
> + ? ? ? .masters_cnt ? ?= ARRAY_SIZE(omap44xx_fdif_masters),
> +};
> +
> ?static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
>
> ? ? ? ?/* dmm class */
> @@ -5593,6 +5671,9 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
> ? ? ? ?&omap44xx_wd_timer2_hwmod,
> ? ? ? ?&omap44xx_wd_timer3_hwmod,
>
> + ? ? ? /* fdif class */
> + ? ? ? &omap44xx_fdif_hwmod,
> +
> ? ? ? ?NULL,
> ?};

thanks,
--
Ming Lei

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2011-12-13  2:42 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-12-02  9:12 [RFC PATCH v1 0/7] media&omap4: introduce face detection(FD) driver Ming Lei
2011-12-02  9:12 ` [RFC PATCH v1 1/7] omap4: introduce fdif(face detect module) hwmod Ming Lei
2011-12-13  2:42   ` Ming Lei
2011-12-02  9:12 ` [RFC PATCH v1 2/7] omap4: build fdif omap device from hwmod Ming Lei
2011-12-02 12:10   ` Sergei Shtylyov
2011-12-05  4:25     ` Ming Lei
2011-12-02  9:12 ` [RFC PATCH v1 3/7] media: videobuf2: move out of setting pgprot_noncached from vb2_mmap_pfn_range Ming Lei
2011-12-02  9:12 ` [RFC PATCH v1 4/7] media: videobuf2: introduce VIDEOBUF2_PAGE memops Ming Lei
2011-12-02 16:35   ` Aguirre, Sergio
2011-12-05  2:16     ` Ming Lei
2011-12-02  9:12 ` [RFC PATCH v1 5/7] media: v4l2: introduce two IOCTLs for face detection Ming Lei
2011-12-02 12:33   ` Arnd Bergmann
2011-12-04 11:18     ` Ming Lei
2011-12-05 14:37       ` Arnd Bergmann
2011-12-06  6:30         ` Ming Lei
2011-12-06 12:55           ` Arnd Bergmann
2011-12-06 13:11             ` Ming Lei
2011-12-06 14:41               ` Arnd Bergmann
2011-12-06 14:52                 ` Ming Lei
2011-12-06 15:45                   ` Ming Lei
2011-12-06 20:59                     ` Arnd Bergmann
2011-12-02  9:12 ` [RFC PATCH v1 6/7] media: video: introduce face detection driver module Ming Lei
2011-12-02  9:12 ` [RFC PATCH v1 7/7] media: video: introduce omap4 face detection module driver Ming Lei
2011-12-02 10:28 ` [RFC PATCH v1 0/7] media&omap4: introduce face detection(FD) driver Sylwester Nawrocki
2011-12-02 14:59   ` Ming Lei
  -- strict thread matches above, loose matches on Subject: below --
2011-12-02 15:02 Ming Lei

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).