All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [Ksummit-2010-discuss] [v2] Remaining BKL users, what to do
From: Arnd Bergmann @ 2010-10-20  6:50 UTC (permalink / raw)
  To: Dave Young
  Cc: Greg KH, Oliver Neukum, Valdis.Kletnieks, Dave Airlie, codalist,
	ksummit-2010-discuss, autofs, Jan Harkes, Samuel Ortiz, Jan Kara,
	Arnaldo Carvalho de Melo, netdev, Anders Larsen, linux-kernel,
	dri-devel, Bryan Schumaker, Christoph Hellwig, Petr Vandrovec,
	Mikulas Patocka, linux-fsdevel, Evgeniy Dushistov, Ingo Molnar,
	Andrew Hendry, linux-media
In-Reply-To: <AANLkTimRFxKT5p1K=Rd1MxXZymonx_t6rHKBhn=8CsW=@mail.gmail.com>

On Wednesday 20 October 2010, Dave Young wrote:
> be curious, why can't just fix the lock_kernel logic of i810? Fixing
> is too hard?
> 
> Find a i810 hardware should be possible, even if the hardware does not
> support SMP, can't we test the fix with preemption?

Yes, that should work too. My usual approach for removing the BKL without
having the hardware myself was to make locking stricter, i.e. replace
the BKL with a new spinlock or mutex. This way all the code would still
be serialized and if I did something wrong, lockdep would complain about
it, but there would be no risk of silent data corruption.

In case of i810, locking across DRM is rather complicated and there is no
way of doing this without making changes to other DRM code.

In fact, the only critical section that is actually protected by the BKL
are the few lines in i810_mmap_buffers. They look like they might not even
need the BKL to start with and we can just remove it even on SMP/PREEMPT,
except for perhaps the assignment to buf_priv->currently_mapped.
Someone who understands more about the driver than I do can probably figure
this out easily, but I couldn't come up with a way that doesn't risk
breaking in corner cases.

	Arnd

^ permalink raw reply

* [U-Boot] [Patch V2] update board EB+CPUx9K2
From: Andreas Bießmann @ 2010-10-20  6:48 UTC (permalink / raw)
  To: u-boot
In-Reply-To: <4CBDE3B7.6020403@emk-elektronik.de>

Dear Reinhard Meyer,

Am 19.10.2010 um 20:30 schrieb Reinhard Meyer:
>> +#define CONFIG_SYS_TEXT_BASE 		0x00000000
> How does this work with a text base of 0? Am I missing something?

This should work when booting from NOR. The first MiB (0x00000000-0x00100000) is mapped to internal SRAM, internal ROM _or_ NOR on CS0 depending on 'BMS' Pin and REMAP command -> datasheet at91rm9200 p17. Nevertheless I would prefer to explicitly address NOR flash on CS0 with 0x10000000.

regards

Andreas Bie?mann

^ permalink raw reply

* RE: [PATCH 0/4] ARM: S5PV310: Add support S5PV310/S5PC210 CPUFREQ
From: Kukjin Kim @ 2010-10-20  6:48 UTC (permalink / raw)
  To: 'Kukjin Kim', linux-arm-kernel, linux-samsung-soc; +Cc: ben-linux
In-Reply-To: <1284777916-23257-1-git-send-email-kgene.kim@samsung.com>

Kukjin Kim wrote:
> 
> This patch adds support CPUFREQ driver for S5PV310 and S5PC210.
> 
> NOTE: This patch dependes on following.
> - ARM: S5PV310: Fix clkset_moutcore_list
> - ARM: S5PV210: Add DMC map_desc table for supporting DMC access
> 
> [PATCH 1/4] ARM: S5PV310: Update CMU registers for CPUFREQ
> [PATCH 2/4] ARM: S5PV310: Add DMC registers and map_desc
> [PATCH 3/4] ARM: S5PV310: Add support CPUFREQ
> [PATCH 4/4] ARM: S5PV310: Update Kconfig and Makefile for supporting
CPUFREQ
> --
> To unsubscribe from this list: send the line "unsubscribe
linux-samsung-soc"
> in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

Hi,

Basically, this CPUFREQ functionality has no problem, however, now
ARCH_S5PV310 uses ARM private timer(localtimer) as event tick on each CPU
core.
It means that we need some handling on localtimer or anywhere about ARM
clock changing by CPUFREQ driver...now it is not implemented..so I will drop
this patches for -next...I think we can do it at 37-rc.

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.

^ permalink raw reply

* [PATCH 0/4] ARM: S5PV310: Add support S5PV310/S5PC210 CPUFREQ
From: Kukjin Kim @ 2010-10-20  6:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1284777916-23257-1-git-send-email-kgene.kim@samsung.com>

Kukjin Kim wrote:
> 
> This patch adds support CPUFREQ driver for S5PV310 and S5PC210.
> 
> NOTE: This patch dependes on following.
> - ARM: S5PV310: Fix clkset_moutcore_list
> - ARM: S5PV210: Add DMC map_desc table for supporting DMC access
> 
> [PATCH 1/4] ARM: S5PV310: Update CMU registers for CPUFREQ
> [PATCH 2/4] ARM: S5PV310: Add DMC registers and map_desc
> [PATCH 3/4] ARM: S5PV310: Add support CPUFREQ
> [PATCH 4/4] ARM: S5PV310: Update Kconfig and Makefile for supporting
CPUFREQ
> --
> To unsubscribe from this list: send the line "unsubscribe
linux-samsung-soc"
> in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

Hi,

Basically, this CPUFREQ functionality has no problem, however, now
ARCH_S5PV310 uses ARM private timer(localtimer) as event tick on each CPU
core.
It means that we need some handling on localtimer or anywhere about ARM
clock changing by CPUFREQ driver...now it is not implemented..so I will drop
this patches for -next...I think we can do it at 37-rc.

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.

^ permalink raw reply

* Re: [PATCH v5] usb: usb3.0 ch9 definitions
From: tlinder @ 2010-10-20  6:48 UTC (permalink / raw)
  To: tlinder
  Cc: Matthew Wilcox, Tatyana Brokhman, linux-usb, linux-arm-msm,
	Greg Kroah-Hartman, Sarah Sharp, linux-kernel
In-Reply-To: <874c7b4e0f4fcbc99d074b23595454e5.squirrel@www.codeaurora.org>

Hi Matthew

Bellow is the reply we received from Intel regarding this issue:

"Errata 10.007 in the “Q1-09 USB3_Errata.pdf” file defines a correction of
the SuperSpeed USB Device Capability structure in section 10.13.1 that
changes bLength from 12 to 10 bytes, and bFunctionalitySupport from 8 to
3."

Best Regards
Tanya Brokhman

> Hi Matthew
>
> Page 10-57 you're referring to defines the SuperSpeed USB Device
> Capability descriptor for Hub Class. The descriptor itself is defined in
> ch9 section 9.6.2.2 and the wReserved is not defined there. Thus the total
> length of the descriptor is 10 bytes and not 12.
> IMO we should follow the definition in ch9. It seems that ch 10 has a typo
> in it. You're right about the errata. I found no reference to this issue
> either.
> I'll contact USB-IF regarding this issue.
> Thanks for bringing this up!
>
> Best regards
> Tanya Brokhman
>
>> On Sat, Oct 09, 2010 at 04:46:12PM +0200, Tatyana Brokhman wrote:
>>> +/*
>>> + * SuperSpeed USB Capability descriptor: Defines the set of SuperSpeed
>>> USB
>>> + * specific device level capabilities
>>> + */
>>> +#define		USB_SS_CAP_TYPE		3
>>> +struct usb_ss_cap_descriptor {		/* Link Power Management */
>>> +	__u8  bLength;
>>> +	__u8  bDescriptorType;
>>> +	__u8  bDevCapabilityType;
>>> +	__u8  bmAttributes;
>>> +#define USB_LTM_SUPPORT			(1 << 1) /* supports LTM */
>>> +	__le16 wSpeedSupported;
>>> +#define USB_LOW_SPEED_OPERATION		(1)	 /* Low speed operation */
>>> +#define USB_FULL_SPEED_OPERATION	(1 << 1) /* Full speed operation */
>>> +#define USB_HIGH_SPEED_OPERATION	(1 << 2) /* High speed operation */
>>> +#define USB_5GBPS_OPERATION		(1 << 3) /* Operation at 5Gbps */
>>> +	__u8  bFunctionalitySupport;
>>> +	__u8  bU1devExitLat;
>>> +	__le16 bU2DevExitLat;
>>> +} __attribute__((packed));
>>> +
>>> +#define USB_DT_USB_SS_CAP_SIZE	10
>>
>> Hang on, if we're looking at page 10-57 of "USB 3 0
>> (11132008)-final.pdf",
>> it's 12 bytes long with the last two bytes being wReserved.  Is there
>> an erratum that changes this?  I just looked through
>> "USB3_Errata [June 2010].pdf" and don't see any errata that look
>> germane.
>>
>>
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>



^ permalink raw reply

* Re: [PATCH v5] usb: usb3.0 ch9 definitions
From: tlinder @ 2010-10-20  6:48 UTC (permalink / raw)
  To: tlinder
  Cc: Matthew Wilcox, linux-usb, linux-arm-msm, Greg Kroah-Hartman,
	Sarah Sharp, linux-kernel
In-Reply-To: <874c7b4e0f4fcbc99d074b23595454e5.squirrel@www.codeaurora.org>

Hi Matthew

Bellow is the reply we received from Intel regarding this issue:

"Errata 10.007 in the “Q1-09 USB3_Errata.pdf” file defines a correction of
the SuperSpeed USB Device Capability structure in section 10.13.1 that
changes bLength from 12 to 10 bytes, and bFunctionalitySupport from 8 to
3."

Best Regards
Tanya Brokhman

> Hi Matthew
>
> Page 10-57 you're referring to defines the SuperSpeed USB Device
> Capability descriptor for Hub Class. The descriptor itself is defined in
> ch9 section 9.6.2.2 and the wReserved is not defined there. Thus the total
> length of the descriptor is 10 bytes and not 12.
> IMO we should follow the definition in ch9. It seems that ch 10 has a typo
> in it. You're right about the errata. I found no reference to this issue
> either.
> I'll contact USB-IF regarding this issue.
> Thanks for bringing this up!
>
> Best regards
> Tanya Brokhman
>
>> On Sat, Oct 09, 2010 at 04:46:12PM +0200, Tatyana Brokhman wrote:
>>> +/*
>>> + * SuperSpeed USB Capability descriptor: Defines the set of SuperSpeed
>>> USB
>>> + * specific device level capabilities
>>> + */
>>> +#define		USB_SS_CAP_TYPE		3
>>> +struct usb_ss_cap_descriptor {		/* Link Power Management */
>>> +	__u8  bLength;
>>> +	__u8  bDescriptorType;
>>> +	__u8  bDevCapabilityType;
>>> +	__u8  bmAttributes;
>>> +#define USB_LTM_SUPPORT			(1 << 1) /* supports LTM */
>>> +	__le16 wSpeedSupported;
>>> +#define USB_LOW_SPEED_OPERATION		(1)	 /* Low speed operation */
>>> +#define USB_FULL_SPEED_OPERATION	(1 << 1) /* Full speed operation */
>>> +#define USB_HIGH_SPEED_OPERATION	(1 << 2) /* High speed operation */
>>> +#define USB_5GBPS_OPERATION		(1 << 3) /* Operation at 5Gbps */
>>> +	__u8  bFunctionalitySupport;
>>> +	__u8  bU1devExitLat;
>>> +	__le16 bU2DevExitLat;
>>> +} __attribute__((packed));
>>> +
>>> +#define USB_DT_USB_SS_CAP_SIZE	10
>>
>> Hang on, if we're looking at page 10-57 of "USB 3 0
>> (11132008)-final.pdf",
>> it's 12 bytes long with the last two bytes being wReserved.  Is there
>> an erratum that changes this?  I just looked through
>> "USB3_Errata [June 2010].pdf" and don't see any errata that look
>> germane.
>>
>>
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>



^ permalink raw reply

* [U-Boot] [PATCH 01/17] XPedite5500 board support
From: Kumar Gala @ 2010-10-20  6:46 UTC (permalink / raw)
  To: u-boot
In-Reply-To: <1285787156-6005-1-git-send-email-ptyser@xes-inc.com>


On Sep 29, 2010, at 2:05 PM, Peter Tyser wrote:

> From: John Schmoller <jschmoller@xes-inc.com>
> 
> Initial support for Extreme Engineering Solutions XPedite5500 -
> a P2020-based PMC/XMC single board computer.
> 
> Signed-off-by: John Schmoller <jschmoller@xes-inc.com>
> Signed-off-by: Peter Tyser <ptyser@xes-inc.com>
> CC: Kumar Gala <galak@kernel.crashing.org>
> ---
> Some of the changes in this series touch both common and X-ES-specific
> code so I put them in one series and tried to CC the proper custodian.

This sequence needs a bit of updating to apply to top of tree, also some of these patches need acks from other people (like Wolfgang since the impact things beyond 86xx/85xx arch code).  Also, it would have been nice to have all the cleanup happen before introducing the new XPedite5500 support (so its patch is clean).

I've pulled in the ones I could at this point.

- k

^ permalink raw reply

* [U-Boot] [PATCH 05/17] ppc: Don't initialize write protected NOR flashes
From: Kumar Gala @ 2010-10-20  6:46 UTC (permalink / raw)
  To: u-boot
In-Reply-To: <1285787156-6005-5-git-send-email-ptyser@xes-inc.com>


On Sep 29, 2010, at 2:05 PM, Peter Tyser wrote:

> From: John Schmoller <jschmoller@xes-inc.com>
> 
> If a NOR flash is write protected it can not be initialized/detected so
> add the ability for boards to skip NOR initialization on bootup.  A
> board can skip NOR initialization by implementing the
> board_flash_wp_on() function.
> 
> Signed-off-by: John Schmoller <jschmoller@xes-inc.com>
> Signed-off-by: Peter Tyser <ptyser@xes-inc.com>
> CC: sr at denx.de
> ---
> arch/powerpc/lib/board.c |   16 +++++++++++++++-
> 1 files changed, 15 insertions(+), 1 deletions(-)

Needs a Wolfgang or Stefan ack.

- k

^ permalink raw reply

* [U-Boot] [PATCH 04/17] pci: Add ability to re-enumerate PCI buses
From: Kumar Gala @ 2010-10-20  6:45 UTC (permalink / raw)
  To: u-boot
In-Reply-To: <1285787156-6005-4-git-send-email-ptyser@xes-inc.com>


On Sep 29, 2010, at 2:05 PM, Peter Tyser wrote:

> From: John Schmoller <jschmoller@xes-inc.com>
> 
> Add a new 'pci enum' command which re-enumerates the PCI buses.  This
> command is enabled via the CONFIG_CMD_PCI_ENUM define and can be useful
> in boards with FPGAs connected via PCI/PCIe, boards that support PCI
> hot-plugging, or during PCI debug.
> 
> Also enable the 'pci enum' command for X-ES's Freescale-based boards.
> 
> Signed-off-by: John Schmoller <jschmoller@xes-inc.com>
> Signed-off-by: Peter Tyser <ptyser@xes-inc.com>
> ---
> common/cmd_pci.c              |   13 +++++++++++++
> drivers/pci/fsl_pci_init.c    |    3 +++
> drivers/pci/pci.c             |    4 +++-
> include/configs/XPEDITE5170.h |    1 +
> include/configs/XPEDITE5200.h |    1 +
> include/configs/XPEDITE5370.h |    1 +
> include/configs/XPEDITE5500.h |    1 +
> 7 files changed, 23 insertions(+), 1 deletions(-)

Need a Wolfgang Ack. looks good to me.

Acked-by: Kumar Gala <galak@kernel.crashing.org>

- k

^ permalink raw reply

* Re: rtl2832u support
From: Hans Verkuil @ 2010-10-20  6:44 UTC (permalink / raw)
  To: Devin Heitmueller; +Cc: Damjan Marion, linux-media
In-Reply-To: <AANLkTimk9kP5pb4yy+L0Zu0Om0siLnsDUzDZ2AmZkHMd@mail.gmail.com>

On Tuesday, October 19, 2010 23:28:49 Devin Heitmueller wrote:
> On Tue, Oct 19, 2010 at 4:27 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> > Bullshit.
> 
> Not exactly the level of mutual respect for your peers that I would
> expect of you, Hans.

You I right, that could have been phrased more diplomatically. So I'm human
after all :-)

> > First of all these rules are those of the kernel community
> > as a whole and *not* linuxtv as such, and secondly you can upstream such
> > drivers in the staging tree. If you want to move it out of staging, then
> > it will take indeed more work since the quality requirements are higher
> > there.
> 
> You are correct - while I indeed say it was the position of the
> LinuxTV developers, I didn't intend to single them out from the rest
> of the Linux kernel community.  The problem I described is systemic to
> working with the Linux kernel community in general.
> 
> > Them's the rules for kernel development.
> >
> > I've done my share of coding style cleanups. I never understand why people
> > dislike doing that. In my experience it always greatly improves the code
> > (i.e. I can actually understand it) and it tends to highlight the remaining
> > problematic areas in the driver.
> 
> Because it's additional work.  I agree that *sometimes* it can be
> useful.  And yet many times it's a bunch of changes that provide
> little actual value and only make it harder to keep the Linux driver
> in sync with the upstream source (in many cases, the GPL driver is
> derived from some Windows driver or other source).

Yes, it is additional work, but there is a big payout at the end: once the
driver is merged in the mainline, then your maintenance level falls down
to just bug fixing. That is a *huge* cost saving.

I also have to say that in my experience most driver code made this way
(i.e. OS independent) tends to be truly awful code.
 
> Alex makes a point that I think it's worth expanding on a bit:
> 
> The Linux kernel developers' goals are different than those of the
> product/chipset vendor.  The product/chipset vendor typically wants
> consistency across operating systems.  This usually involves some sort
> of OS portability layer to abstract out the OS specific parts (which
> is usually done as a combination of OS specific header files and C
> macros).  This reduces the maintenance cost for the author as it makes
> it easier to be confident that changes to the core will basically
> "just work" on other operating systems.

Been there, done that.
 
> The Linux kernel developer wants consistency across Linux drivers
> regardless of who wrote them.  This makes sense for the Linux kernel
> community in that it makes it easier to work on drivers that you
> didn't necessarily write.  However it also means that all of the
> portability code and macros are seen as "crap which has to be stripped
> out".  The net effect is a driver that looks little like the original
> platform independent driver, making it easier for the Linux kernel
> community to maintain but harder for the original author to provide
> updates to.

Ah, and there is the crucial phrase: "making it easier for the Linux kernel
community to maintain". That's the pay-off: once it is in you no longer have
to care about maintaining it besides bug fixes. The maintenance level of
out-of-tree drivers seems quite low in the beginning but over time it can
skyrocket. Particularly in a subsystem like v4l which is undergoing a lot
of change.

> I can appreciate why the Linux development community chose this route,
> but let's not pretend that it doesn't come at a significant cost.

It's the difference between 'high initial cost, low or no cost afterwards'
and 'low initial cost, ever increasing cost afterwards'. In my experience,
the first option has always a (much) lower total cost compared to the
second option. Not to mention a much higher code quality. But it can be
very hard to convince companies of that, particularly when they just start
out doing linux work.

A special case is when the hardware needs to support a new feature for which
a new public API is needed. There the initial cost can be very high indeed.

For small companies that can be prohibitive. I have no real solution for this
at the moment. But it does make me appreciate companies like TI, Samsung and
Nokia who are willing to take the long road, hopefully with a big payout at
the end.

> Kind of like how the Git move has resulted in developers who want to
> build drivers on a known-stable kernel (as opposed to the bleeding
> edge) being treated as second class citizens.

That's a typical example of having limited resources. I also would like to
see better support for building against stable kernels (and I have to test
Mauro's new approach one of these days), but there is only so much time
(and money) available.

Regards,

	Hans

-- 
Hans Verkuil - video4linux developer - sponsored by TANDBERG, part of Cisco

^ permalink raw reply

* [PATCH 2/2] mtd-utils: nanddump: add 64-bit support, utilize libmtd
From: Brian Norris @ 2010-10-20  6:45 UTC (permalink / raw)
  To: linux-mtd; +Cc: Brian Norris, David Woodhouse, Mike Frysinger, Artem Bityutskiy
In-Reply-To: <1287557125-2672-1-git-send-email-computersforpeace@gmail.com>

Adds support for 64-bit offsets (i.e., devices larger than 4GB).
Calls to ioctls are mostly replaced by libmtd interfaces; however,
a few remain and probably should be handled with more robust
interfaces, as some of these ioctls are considered "legacy."

Similar updates to nandwrite will come shortly.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
 nanddump.c  |  117 +++++++++++++++++++++++++++++------------------------------
 nandwrite.c |    7 ++--
 2 files changed, 60 insertions(+), 64 deletions(-)

diff --git a/nanddump.c b/nanddump.c
index 6428bc4..55dbd37 100644
--- a/nanddump.c
+++ b/nanddump.c
@@ -33,6 +33,7 @@
 #include <asm/types.h>
 #include <mtd/mtd-user.h>
 #include "common.h"
+#include <libmtd.h>
 
 static struct nand_oobinfo none_oobinfo = {
 	.useecc = MTD_NANDECC_OFF,
@@ -77,18 +78,18 @@ static void display_version(void)
 
 // Option variables
 
-static bool		pretty_print = false;	// print nice
-static bool		noecc = false;		// don't error correct
-static bool		noskipbad = false;	// don't skip bad blocks
-static bool		omitoob = false;	// omit oob data
-static unsigned long	start_addr;		// start address
-static unsigned long	length;			// dump length
-static const char	*mtddev;		// mtd device name
-static const char	*dumpfile;		// dump file name
-static bool		omitbad = false;
-static bool		quiet = false;		// suppress diagnostic output
-static bool		canonical = false;	// print nice + ascii
-static bool		forcebinary = false;	// force printing binary to tty
+static bool			pretty_print = false;	// print nice
+static bool			noecc = false;		// don't error correct
+static bool			noskipbad = false;	// don't skip bad blocks
+static bool			omitoob = false;	// omit oob data
+static unsigned long long	start_addr;		// start address
+static unsigned long		length;			// dump length
+static const char		*mtddev;		// mtd device name
+static const char		*dumpfile;		// dump file name
+static bool			omitbad = false;
+static bool			quiet = false;		// suppress diagnostic output
+static bool			canonical = false;	// print nice + ascii
+static bool			forcebinary = false;	// force printing binary to tty
 
 static void process_options(int argc, char * const argv[])
 {
@@ -135,7 +136,7 @@ static void process_options(int argc, char * const argv[])
 				omitbad = true;
 				break;
 			case 's':
-				start_addr = strtol(optarg, NULL, 0);
+				start_addr = strtoull(optarg, NULL, 0);
 				break;
 			case 'f':
 				if (!(dumpfile = strdup(optarg))) {
@@ -221,18 +222,16 @@ static void process_options(int argc, char * const argv[])
  */
 static void pretty_dump_to_buffer(const unsigned char *buf, size_t len,
 		char *linebuf, size_t linebuflen, bool pagedump, bool ascii,
-		unsigned int prefix)
+		unsigned long long prefix)
 {
 	static const char hex_asc[] = "0123456789abcdef";
 	unsigned char ch;
-	int j, lx = 0;
-	int ascii_column;
+	unsigned int j, lx = 0, ascii_column;
 
 	if (pagedump)
-		sprintf(linebuf, "0x%.8x: ", prefix);
+		lx += sprintf(linebuf, "0x%.8llx: ", prefix);
 	else
-		sprintf(linebuf, "  OOB Data: ");
-	lx += 12;
+		lx += sprintf(linebuf, "  OOB Data: ");
 
 	if (!len)
 		goto nil;
@@ -253,8 +252,10 @@ static void pretty_dump_to_buffer(const unsigned char *buf, size_t len,
 	if (!ascii)
 		goto nil;
 
-	while (lx < (linebuflen - 1) && lx < (ascii_column - 1))
+	do {
 		linebuf[lx++] = ' ';
+	} while (lx < (linebuflen - 1) && lx < (ascii_column - 1));
+
 	linebuf[lx++] = '|';
 	for (j = 0; (j < len) && (lx + 2) < linebuflen; j++)
 		linebuf[lx++] = (isascii(buf[j]) && isprint(buf[j])) ? buf[j]
@@ -271,20 +272,25 @@ nil:
  */
 int main(int argc, char * const argv[])
 {
-	unsigned long ofs, end_addr = 0;
+	unsigned long long ofs, end_addr = 0;
 	unsigned long long blockstart = 1;
 	int ret, i, fd, ofd = 0, bs, badblock = 0;
-	struct mtd_oob_buf oob;
-	mtd_info_t meminfo;
+	struct mtd_dev_info mtd;
 	char pretty_buf[PRETTY_BUF_LEN];
 	int oobinfochanged = 0, firstblock = 1;
 	struct nand_oobinfo old_oobinfo;
 	struct mtd_ecc_stats stat1, stat2;
 	bool eccstats = false;
 	unsigned char *readbuf = NULL, *oobbuf = NULL;
+	libmtd_t mtd_desc;
 
 	process_options(argc, argv);
 
+	/* Initialize libmtd */
+	mtd_desc = libmtd_open();
+	if (!mtd_desc)
+		return errmsg("can't initialize libmtd");
+
 	/* Open MTD device */
 	if ((fd = open(mtddev, O_RDONLY)) == -1) {
 		perror(mtddev);
@@ -292,20 +298,12 @@ int main(int argc, char * const argv[])
 	}
 
 	/* Fill in MTD device capability structure */
-	if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
-		perror("MEMGETINFO");
-		close(fd);
-		exit(EXIT_FAILURE);
-	}
+	if (mtd_get_dev_info(mtd_desc, mtddev, &mtd) < 0)
+		return errmsg("mtd_get_dev_info failed");
 
 	/* Allocate buffers */
-	oobbuf = xmalloc(sizeof(oobbuf) * meminfo.oobsize);
-	readbuf = xmalloc(sizeof(readbuf) * meminfo.writesize);
-
-	/* Fill in oob info */
-	oob.start = 0;
-	oob.length = meminfo.oobsize;
-	oob.ptr = oobbuf;
+	oobbuf = xmalloc(sizeof(oobbuf) * mtd.oob_size);
+	readbuf = xmalloc(sizeof(readbuf) * mtd.min_io_size);
 
 	if (noecc)  {
 		ret = ioctl(fd, MTDFILEMODE, (void *)MTD_MODE_RAW);
@@ -359,27 +357,27 @@ int main(int argc, char * const argv[])
 	}
 
 	/* Initialize start/end addresses and block size */
-	if (start_addr & (meminfo.writesize - 1)) {
+	if (start_addr & (mtd.min_io_size - 1)) {
 		fprintf(stderr, "WARNING: The start address is not page-aligned !\n"
 				"The pagesize of this NAND Flash is 0x%x.\n"
 				"nandwrite doesn't allow writes starting at this location.\n"
 				"Future versions of nanddump will fail here.\n",
-				meminfo.writesize);
+				mtd.min_io_size);
 	}
 	if (length)
 		end_addr = start_addr + length;
-	if (!length || end_addr > meminfo.size)
-		end_addr = meminfo.size;
+	if (!length || end_addr > mtd.size)
+		end_addr = mtd.size;
 
-	bs = meminfo.writesize;
+	bs = mtd.min_io_size;
 
 	/* Print informative message */
 	if (!quiet) {
 		fprintf(stderr, "Block size %u, page size %u, OOB size %u\n",
-				meminfo.erasesize, meminfo.writesize, meminfo.oobsize);
+				mtd.eb_size, mtd.min_io_size, mtd.oob_size);
 		fprintf(stderr,
-				"Dumping data starting at 0x%08x and ending at 0x%08x...\n",
-				(unsigned int)start_addr, (unsigned int)end_addr);
+				"Dumping data starting at 0x%08llx and ending at 0x%08llx...\n",
+				start_addr, end_addr);
 	}
 
 	/* Dump the flash contents */
@@ -387,12 +385,12 @@ int main(int argc, char * const argv[])
 		/* Check for bad block */
 		if (noskipbad) {
 			badblock = 0;
-		} else if (blockstart != (ofs & (~meminfo.erasesize + 1)) ||
+		} else if (blockstart != (ofs & (~mtd.eb_size + 1)) ||
 				firstblock) {
-			blockstart = ofs & (~meminfo.erasesize + 1);
+			blockstart = ofs & (~mtd.eb_size + 1);
 			firstblock = 0;
-			if ((badblock = ioctl(fd, MEMGETBADBLOCK, &blockstart)) < 0) {
-				perror("ioctl(MEMGETBADBLOCK)");
+			if ((badblock = mtd_is_bad(&mtd, fd, ofs / mtd.eb_size)) < 0) {
+				errmsg("libmtd: mtd_is_bad");
 				goto closeall;
 			}
 		}
@@ -403,8 +401,8 @@ int main(int argc, char * const argv[])
 			memset(readbuf, 0xff, bs);
 		} else {
 			/* Read page data and exit on failure */
-			if (pread(fd, readbuf, bs, ofs) != bs) {
-				perror("pread");
+			if (mtd_read(&mtd, fd, ofs / mtd.eb_size, ofs % mtd.eb_size, readbuf, bs)) {
+				errmsg("mtd_read");
 				goto closeall;
 			}
 		}
@@ -417,11 +415,11 @@ int main(int argc, char * const argv[])
 			}
 			if (stat1.failed != stat2.failed)
 				fprintf(stderr, "ECC: %d uncorrectable bitflip(s)"
-						" at offset 0x%08lx\n",
+						" at offset 0x%08llx\n",
 						stat2.failed - stat1.failed, ofs);
 			if (stat1.corrected != stat2.corrected)
 				fprintf(stderr, "ECC: %d corrected bitflip(s) at"
-						" offset 0x%08lx\n",
+						" offset 0x%08llx\n",
 						stat2.corrected - stat1.corrected, ofs);
 			stat1 = stat2;
 		}
@@ -429,8 +427,8 @@ int main(int argc, char * const argv[])
 		/* Write out page data */
 		if (pretty_print) {
 			for (i = 0; i < bs; i += PRETTY_ROW_SIZE) {
-				pretty_dump_to_buffer(readbuf+i, PRETTY_ROW_SIZE,
-						pretty_buf, PRETTY_BUF_LEN, true, canonical, ofs+i);
+				pretty_dump_to_buffer(readbuf + i, PRETTY_ROW_SIZE,
+						pretty_buf, PRETTY_BUF_LEN, true, canonical, ofs + i);
 				write(ofd, pretty_buf, strlen(pretty_buf));
 			}
 		} else
@@ -440,25 +438,24 @@ int main(int argc, char * const argv[])
 			continue;
 
 		if (badblock) {
-			memset(oobbuf, 0xff, meminfo.oobsize);
+			memset(oobbuf, 0xff, mtd.oob_size);
 		} else {
 			/* Read OOB data and exit on failure */
-			oob.start = ofs;
-			if (ioctl(fd, MEMREADOOB, &oob) != 0) {
-				perror("ioctl(MEMREADOOB)");
+			if (mtd_read_oob(mtd_desc, &mtd, fd, ofs, mtd.oob_size, oobbuf)) {
+				errmsg("libmtd: mtd_read_oob");
 				goto closeall;
 			}
 		}
 
 		/* Write out OOB data */
 		if (pretty_print) {
-			for (i = 0; i < meminfo.oobsize; i += 16) {
-				pretty_dump_to_buffer(oobbuf+i, meminfo.oobsize-i,
+			for (i = 0; i < mtd.oob_size; i += 16) {
+				pretty_dump_to_buffer(oobbuf + i, mtd.oob_size - i,
 						pretty_buf, PRETTY_BUF_LEN, false, canonical, 0);
 				write(ofd, pretty_buf, strlen(pretty_buf));
 			}
 		} else
-			write(ofd, oobbuf, meminfo.oobsize);
+			write(ofd, oobbuf, mtd.oob_size);
 	}
 
 	/* reset oobinfo */
diff --git a/nandwrite.c b/nandwrite.c
index fe03115..9eb63a4 100644
--- a/nandwrite.c
+++ b/nandwrite.c
@@ -108,7 +108,7 @@ static void display_version(void)
 
 static const char	*standard_input = "-";
 static const char	*mtd_device, *img;
-static int		mtdoffset = 0;
+static unsigned int	mtdoffset = 0;
 static bool		quiet = false;
 static bool		writeoob = false;
 static bool		rawoob = false;
@@ -200,7 +200,7 @@ static void process_options(int argc, char * const argv[])
 				writeoob = true;
 				break;
 			case 's':
-				mtdoffset = strtol(optarg, NULL, 0);
+				mtdoffset = strtoul(optarg, NULL, 0);
 				break;
 			case 'b':
 				blockalign = atoi(optarg);
@@ -318,7 +318,6 @@ int main(int argc, char * const argv[])
 
 		// autoplace ECC ?
 		if (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE) {
-
 			if (ioctl(fd, MEMSETOOBSEL, &autoplace_oobinfo) != 0) {
 				perror("MEMSETOOBSEL");
 				close(fd);
@@ -480,7 +479,7 @@ int main(int argc, char * const argv[])
 			if (noskipbad)
 				continue;
 			do {
-				if ((ret = ioctl(fd, MEMGETBADBLOCK, &offs)) < 0) {
+				if ((ret = 0 /*ioctl(fd, MEMGETBADBLOCK, &offs)*/) < 0) {
 					perror("ioctl(MEMGETBADBLOCK)");
 					goto closeall;
 				}
-- 
1.7.0.4

^ permalink raw reply related

* [PATCH 1/2] mtd-utils: more style fixups
From: Brian Norris @ 2010-10-20  6:45 UTC (permalink / raw)
  To: linux-mtd; +Cc: Brian Norris, David Woodhouse, Mike Frysinger, Artem Bityutskiy

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
 nanddump.c  |    7 +++----
 nandwrite.c |    6 +++---
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/nanddump.c b/nanddump.c
index bb649da..6428bc4 100644
--- a/nanddump.c
+++ b/nanddump.c
@@ -308,7 +308,7 @@ int main(int argc, char * const argv[])
 	oob.ptr = oobbuf;
 
 	if (noecc)  {
-		ret = ioctl(fd, MTDFILEMODE, (void *) MTD_MODE_RAW);
+		ret = ioctl(fd, MTDFILEMODE, (void *)MTD_MODE_RAW);
 		if (ret == 0) {
 			oobinfochanged = 2;
 		} else {
@@ -330,7 +330,6 @@ int main(int argc, char * const argv[])
 			}
 		}
 	} else {
-
 		/* check if we can read ecc stats */
 		if (!ioctl(fd, ECCGETSTATS, &stat1)) {
 			eccstats = true;
@@ -375,7 +374,6 @@ int main(int argc, char * const argv[])
 	bs = meminfo.writesize;
 
 	/* Print informative message */
-
 	if (!quiet) {
 		fprintf(stderr, "Block size %u, page size %u, OOB size %u\n",
 				meminfo.erasesize, meminfo.writesize, meminfo.oobsize);
@@ -383,6 +381,7 @@ int main(int argc, char * const argv[])
 				"Dumping data starting at 0x%08x and ending at 0x%08x...\n",
 				(unsigned int)start_addr, (unsigned int)end_addr);
 	}
+
 	/* Dump the flash contents */
 	for (ofs = start_addr; ofs < end_addr; ofs += bs) {
 		/* Check for bad block */
@@ -401,7 +400,7 @@ int main(int argc, char * const argv[])
 		if (badblock) {
 			if (omitbad)
 				continue;
-			memset (readbuf, 0xff, bs);
+			memset(readbuf, 0xff, bs);
 		} else {
 			/* Read page data and exit on failure */
 			if (pread(fd, readbuf, bs, ofs) != bs) {
diff --git a/nandwrite.c b/nandwrite.c
index b5745b9..fe03115 100644
--- a/nandwrite.c
+++ b/nandwrite.c
@@ -592,14 +592,14 @@ int main(int argc, char * const argv[])
 				int i, start, len;
 				int tags_pos = 0;
 				/*
-				 *  We use autoplacement and have the oobinfo with the autoplacement
+				 * We use autoplacement and have the oobinfo with the autoplacement
 				 * information from the kernel available
 				 *
 				 * Modified to support out of order oobfree segments,
 				 * such as the layout used by diskonchip.c
 				 */
 				if (!oobinfochanged && (old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE)) {
-					for (i = 0;old_oobinfo.oobfree[i][1]; i++) {
+					for (i = 0; old_oobinfo.oobfree[i][1]; i++) {
 						/* Set the reserved bytes to 0xff */
 						start = old_oobinfo.oobfree[i][0];
 						len = old_oobinfo.oobfree[i][1];
@@ -620,7 +620,7 @@ int main(int argc, char * const argv[])
 							len);
 				}
 			}
-			/* Write OOB data first, as ecc will be placed in there*/
+			/* Write OOB data first, as ecc will be placed in there */
 			oob.start = mtdoffset;
 			if (ioctl(fd, MEMWRITEOOB, &oob) != 0) {
 				perror("ioctl(MEMWRITEOOB)");
-- 
1.7.0.4

^ permalink raw reply related

* Re: [PATCH] x86: fix CFI macro invocations to deal with shortcomings in gas
From: Jan Beulich @ 2010-10-20  6:43 UTC (permalink / raw)
  To: Alexander van Heukelum
  Cc: Ingo Molnar, Thomas Gleixner, Andrew Morton, linux-kernel,
	H. Peter Anvin
In-Reply-To: <1287522205.14378.1400906413@webmail.messagingengine.com>

>>> On 19.10.10 at 23:03, "Alexander van Heukelum" <heukelum@fastmail.fm> wrote:
>> -       pushl_cfi (TI_sysenter_return-THREAD_SIZE+8+4*4)(%esp)
>> +       pushl_cfi TI_sysenter_return-THREAD_SIZE_asm+8+4*4(%esp)
> 
> This expands to:
>     pushl_cfi (60)-(8192)+8+4*4(%esp)
> 
> I'm sorry to say that Ubuntu 6.06's gas (2.16.91 20060118) still chokes
> with "too many positional arguments" on this line.

It escapes me where it would split the obviously single argument, and
I know I checked all official versions from 2.15 onwards. Could you
try whether that specific gas would be okay with

     pushl_cfi ((60)-(8192)+8+4*4)(%esp)

I had intentionally removed the surrounding parentheses since
those are considered by newer gas when determining arguments,
and thus I could expose eventual problems with older gas even
on newer versions.

Further, could you experiment (or ideally debug) where is splits
the argument. Something like

.macro m arg1 arg2=0
	.long	\arg1, \arg2
.endm

.data
_start:
	m	(60)-(8192)+8+4*4

might be handy - assembling with -alm=<filename> should allow
you to inspect where the argument got split.

Thanks, Jan


^ permalink raw reply

* [Bug 30960] [r300g][glsl] Texture corruption in Xonotic with lightmaps
From: bugzilla-daemon @ 2010-10-20  6:42 UTC (permalink / raw)
  To: dri-devel
In-Reply-To: <bug-30960-502@http.bugs.freedesktop.org/>

https://bugs.freedesktop.org/show_bug.cgi?id=30960

--- Comment #26 from Tom Stellard <tstellar@gmail.com> 2010-10-19 23:42:04 PDT ---
Does running with RADEON_DEBUG=noopt fix the problem?  If it does, can out post
the output of RADEON_DEBUG=vp,fp,noopt?  You can just post the stderr output, I
don't need any more screenshots.

-- 
Configure bugmail: https://bugs.freedesktop.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug.

^ permalink raw reply

* [U-Boot] [PATCH 02/17] mpc8640: Update the io_sel fields for PCI Express
From: Kumar Gala @ 2010-10-20  6:41 UTC (permalink / raw)
  To: u-boot
In-Reply-To: <1285787156-6005-2-git-send-email-ptyser@xes-inc.com>


On Sep 29, 2010, at 2:05 PM, Peter Tyser wrote:

> Previously io_sel=0xe incorrect stated PCIE1 was enabled.  Also add
> support for the mpc8640's PCIE2 interface.
> 
> Signed-off-by: Peter Tyser <ptyser@xes-inc.com>
> CC: Kumar Gala <galak@kernel.crashing.org>
> ---
> arch/powerpc/cpu/mpc8xxx/pci_cfg.c |    5 ++++-
> 1 files changed, 4 insertions(+), 1 deletions(-)

applied to 85xx since it does fix a bug, even if I want this removed.

- k

^ permalink raw reply

* [PATCH 1/7] v4l: add videobuf2 Video for Linux 2 driver framework
From: Marek Szyprowski @ 2010-10-20  6:41 UTC (permalink / raw)
  To: linux-media; +Cc: m.szyprowski, pawel, kyungmin.park
In-Reply-To: <1287556873-23179-1-git-send-email-m.szyprowski@samsung.com>

From: Pawel Osciak <p.osciak@samsung.com>

Videobuf2 is a Video for Linux 2 API-compatible driver framework for
multimedia devices. It acts as an intermediate layer between userspace
applications and device drivers. It also provides low-level, modular
memory management functions for drivers.

Videobuf2 eases driver development, reduces drivers' code size and aids in
proper and consistent implementation of V4L2 API in drivers.

Videobuf2 memory management backend is fully modular. This allows custom
memory management routines for devices and platforms with non-standard
memory management requirements to be plugged in, without changing the
high-level buffer management functions and API.

The framework provides:
- implementations of streaming I/O V4L2 ioctls and file operations
- high-level video buffer, video queue and state management functions
- video buffer memory allocation and management

Signed-off-by: Pawel Osciak <p.osciak@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
CC: Pawel Osciak <pawel@osciak.com>
---
 drivers/media/video/Kconfig          |    3 +
 drivers/media/video/Makefile         |    2 +
 drivers/media/video/videobuf2-core.c | 1440 ++++++++++++++++++++++++++++++++++
 include/media/videobuf2-core.h       |  371 +++++++++
 4 files changed, 1816 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/videobuf2-core.c
 create mode 100644 include/media/videobuf2-core.h

diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index f6e4d04..9bf2fe1 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -49,6 +49,9 @@ config V4L2_MEM2MEM_DEV
 	tristate
 	depends on VIDEOBUF_GEN
 
+config VIDEOBUF2_CORE
+	tristate
+
 #
 # Multimedia Video device configuration
 #
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 40f98fb..e66f53b 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -117,6 +117,8 @@ obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o
 obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
 obj-$(CONFIG_VIDEO_BTCX)  += btcx-risc.o
 
+obj-$(CONFIG_VIDEOBUF2_CORE)		+= videobuf2-core.o
+
 obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o
 
 obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c
new file mode 100644
index 0000000..4a29c49
--- /dev/null
+++ b/drivers/media/video/videobuf2-core.c
@@ -0,0 +1,1440 @@
+/*
+ * videobuf2-core.c - V4L2 driver helper framework
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <p.osciak@samsung.com>
+ *	   Marek Szyprowski <m.szyprowski@samsung.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/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/poll.h>
+
+#include <media/videobuf2-core.h>
+
+static int debug;
+module_param(debug, int, 0644);
+
+#define dprintk(level, fmt, arg...)					\
+	do {								\
+		if (debug >= level)					\
+			printk(KERN_DEBUG "vb2: " fmt, ## arg);		\
+	} while (0)
+
+#define mem_ops(q, plane) ((q)->alloc_ctx[plane]->mem_ops)
+
+#define call_memop(q, plane, op, args...)				\
+	(((q)->alloc_ctx[plane]->mem_ops->op) ?				\
+		((q)->alloc_ctx[plane]->mem_ops->op(args)) : 0)
+
+/**
+ * __vb2_buf_mem_alloc() - allocate video memory for the given buffer
+ */
+static int __vb2_buf_mem_alloc(struct vb2_buffer *vb,
+				unsigned long *plane_sizes)
+{
+	struct vb2_queue *q = vb->vb2_queue;
+	void *mem_priv;
+	int plane;
+
+	/* Allocate memory for all planes in this buffer */
+	for (plane = 0; plane < vb->num_planes; ++plane) {
+		mem_priv = call_memop(q, plane, alloc, q->alloc_ctx[plane],
+					plane_sizes[plane]);
+		if (!mem_priv)
+			goto free;
+
+		/* Associate allocator private data with this plane */
+		vb->planes[plane].mem_priv = mem_priv;
+		vb->v4l2_planes[plane].length = plane_sizes[plane];
+	}
+
+	return 0;
+free:
+	/* Free already allocated memory if one of the allocations failed */
+	for (; plane > 0; --plane)
+		call_memop(q, plane, put, vb->planes[plane - 1].mem_priv);
+
+	return -ENOMEM;
+}
+
+/**
+ * __vb2_buf_mem_free() - free memory of the given buffer
+ */
+static void __vb2_buf_mem_free(struct vb2_buffer *vb)
+{
+	struct vb2_queue *q = vb->vb2_queue;
+	unsigned int plane;
+
+	for (plane = 0; plane < vb->num_planes; ++plane) {
+		call_memop(q, plane, put, vb->planes[plane].mem_priv);
+		dprintk(3, "Freed plane %d of buffer %d\n",
+				plane, vb->v4l2_buf.index);
+	}
+}
+
+/**
+ * __vb2_buf_userptr_put() - release userspace memory associated associated
+ * with a USERPTR buffer
+ */
+static void __vb2_buf_userptr_put(struct vb2_buffer *vb)
+{
+	struct vb2_queue *q = vb->vb2_queue;
+	unsigned int plane;
+
+	for (plane = 0; plane < vb->num_planes; ++plane) {
+		call_memop(q, plane, put_userptr, vb->planes[plane].mem_priv);
+		vb->planes[plane].mem_priv = NULL;
+	}
+}
+
+/**
+ * __setup_offsets() - setup unique offsets ("cookies") for every plane in
+ * every buffer on the queue
+ */
+static void __setup_offsets(struct vb2_queue *q)
+{
+	unsigned int buffer, plane;
+	struct vb2_buffer *vb;
+	unsigned long off = 0;
+
+	for (buffer = 0; buffer < q->num_buffers; ++buffer) {
+		vb = q->bufs[buffer];
+		if (!vb)
+			continue;
+
+		for (plane = 0; plane < vb->num_planes; ++plane) {
+			vb->v4l2_planes[plane].m.mem_offset = off;
+
+			dprintk(3, "Buffer %d, plane %d offset 0x%08lx\n",
+					buffer, plane, off);
+
+			off += vb->v4l2_planes[plane].length;
+			off = PAGE_ALIGN(off);
+		}
+	}
+}
+
+/**
+ * __vb2_queue_alloc() - allocate videobuf buffer structures and (for MMAP type)
+ * video buffer memory for all buffers/planes on the queue and initializes the
+ * queue
+ *
+ * Returns the number of buffers successfully allocated.
+ */
+static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory,
+			     unsigned int num_buffers, unsigned int num_planes)
+{
+	unsigned long plane_sizes[VIDEO_MAX_PLANES];
+	unsigned int buffer, plane;
+	struct vb2_buffer *vb;
+	int ret;
+
+	/* Get requested plane sizes from the driver */
+	for (plane = 0; plane < num_planes; ++plane) {
+		ret = q->ops->plane_setup(q, plane, &plane_sizes[plane]);
+		if (ret) {
+			dprintk(1, "Plane setup failed\n");
+			return ret;
+		}
+	}
+
+	for (buffer = 0; buffer < num_buffers; ++buffer) {
+		/* Allocate videobuf buffer structures */
+		vb = kzalloc(sizeof(struct vb2_buffer), GFP_KERNEL);
+		if (!vb) {
+			dprintk(1, "Memory alloc for buffer struct failed\n");
+			break;
+		}
+
+		/* Length stores number of planes for multiplanar buffers */
+		if (V4L2_TYPE_IS_MULTIPLANAR(q->type))
+			vb->v4l2_buf.length = num_planes;
+
+		vb->state = VB2_BUF_STATE_DEQUEUED;
+		vb->vb2_queue = q;
+		vb->num_planes = num_planes;
+		vb->v4l2_buf.index = buffer;
+		vb->v4l2_buf.type = q->type;
+		vb->v4l2_buf.memory = memory;
+
+		/* Allocate video buffer memory for the MMAP type */
+		if (memory == V4L2_MEMORY_MMAP) {
+			ret = __vb2_buf_mem_alloc(vb, plane_sizes);
+			if (ret) {
+				dprintk(1, "Failed allocating memory for "
+						"buffer %d\n", buffer);
+				kfree(vb);
+				break;
+			}
+			/*
+			 * Call the driver-provided buffer initialization
+			 * callback, if given. An error in initialization
+			 * results in queue setup failure.
+			 */
+			if (q->ops->buf_init) {
+				ret = q->ops->buf_init(vb);
+				if (ret) {
+					dprintk(1, "Buffer %d %p initialization"
+						" failed\n", buffer, vb);
+					__vb2_buf_mem_free(vb);
+					kfree(vb);
+					break;
+				}
+			}
+		}
+
+		q->bufs[buffer] = vb;
+	}
+
+	q->num_buffers = buffer;
+
+	__setup_offsets(q);
+
+	dprintk(1, "Allocated %d buffers, %d plane(s) each\n",
+			q->num_buffers, num_planes);
+
+	return buffer;
+}
+
+/**
+ * __vb2_free_mem() - release all video buffer memory for a given queue
+ */
+static void __vb2_free_mem(struct vb2_queue *q)
+{
+	unsigned int buffer;
+	struct vb2_buffer *vb;
+
+	for (buffer = 0; buffer < q->num_buffers; ++buffer) {
+		vb = q->bufs[buffer];
+		if (!vb)
+			continue;
+
+		/* Free MMAP buffers or release USERPTR buffers */
+		if (q->memory == V4L2_MEMORY_MMAP)
+			__vb2_buf_mem_free(vb);
+		else
+			__vb2_buf_userptr_put(vb);
+	}
+}
+
+/**
+ * __vb2_queue_free() - free the queue - video memory and related information
+ * and return the queue to an uninitialized state
+ */
+static int __vb2_queue_free(struct vb2_queue *q)
+{
+	unsigned int buffer;
+
+	/* Call driver-provided cleanup function for each buffer, if provided */
+	if (q->ops->buf_cleanup) {
+		for (buffer = 0; buffer < q->num_buffers; ++buffer) {
+			if (NULL == q->bufs[buffer])
+				continue;
+			q->ops->buf_cleanup(q->bufs[buffer]);
+		}
+	}
+
+	/* Release video buffer memory */
+	__vb2_free_mem(q);
+
+	/* Free videobuf buffers */
+	for (buffer = 0; buffer < q->num_buffers; ++buffer) {
+		if (NULL == q->bufs[buffer])
+			continue;
+		kfree(q->bufs[buffer]);
+		q->bufs[buffer] = NULL;
+	}
+
+	q->num_buffers = 0;
+	q->memory = 0;
+
+	return 0;
+}
+
+/**
+ * __verify_planes_array() - verify that the planes array passed in struct
+ * v4l2_buffer from userspace can be safely used
+ */
+static int __verify_planes_array(struct vb2_buffer *vb, struct v4l2_buffer *b)
+{
+	/* Is memory for copying plane information present? */
+	if (NULL == b->m.planes) {
+		dprintk(1, "Multi-planar buffer passed but "
+			   "planes array not provided\n");
+		return -EINVAL;
+	}
+
+	if (b->length < vb->num_planes || b->length > VIDEO_MAX_PLANES) {
+		dprintk(1, "Incorrect planes array length, "
+			   "expected %d, got %d\n", vb->num_planes, b->length);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be
+ * returned to userspace
+ */
+static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
+{
+	struct vb2_queue *q = vb->vb2_queue;
+	int ret = 0;
+
+	/* Copy back data such as timestamp, input, etc. */
+	memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m));
+	b->input = vb->v4l2_buf.input;
+	b->reserved = vb->v4l2_buf.reserved;
+
+	if (V4L2_TYPE_IS_MULTIPLANAR(q->type)) {
+		ret = __verify_planes_array(vb, b);
+		if (ret)
+			return ret;
+
+		/*
+		 * Fill in plane-related data if userspace provided an array
+		 * for it. The memory and size is verified above.
+		 */
+		memcpy(b->m.planes, vb->v4l2_planes,
+			b->length * sizeof(struct v4l2_plane));
+	} else {
+		/*
+		 * We use length and offset in v4l2_planes array even for
+		 * single-planar buffers, but userspace does not.
+		 */
+		b->length = vb->v4l2_planes[0].length;
+		if (q->memory == V4L2_MEMORY_MMAP)
+			b->m.offset = vb->v4l2_planes[0].m.mem_offset;
+	}
+
+	b->flags = 0;
+
+	switch (vb->state) {
+	case VB2_BUF_STATE_QUEUED:
+	case VB2_BUF_STATE_ACTIVE:
+		b->flags |= V4L2_BUF_FLAG_QUEUED;
+		break;
+	case VB2_BUF_STATE_ERROR:
+		b->flags |= V4L2_BUF_FLAG_ERROR;
+		/* fall through */
+	case VB2_BUF_STATE_DONE:
+		b->flags |= V4L2_BUF_FLAG_DONE;
+		break;
+	case VB2_BUF_STATE_DEQUEUED:
+		/* nothing */
+		break;
+	}
+
+	if (vb->num_planes_mapped == vb->num_planes)
+		b->flags |= V4L2_BUF_FLAG_MAPPED;
+
+	return ret;
+}
+
+/**
+ * vb2_querybuf() - query video buffer information
+ * @q:		videobuf queue
+ * @b:		buffer struct passed from userspace to vidioc_querybuf handler
+ *		in driver
+ *
+ * Should be called from vidioc_querybuf ioctl handler in driver.
+ * This function will verify the passed v4l2_buffer structure and fill the
+ * relevant information for the userspace.
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_querybuf handler in driver.
+ */
+int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
+{
+	struct vb2_buffer *vb;
+	int ret = -EINVAL;
+
+	mutex_lock(&q->vb_lock);
+
+	if (b->type != q->type) {
+		dprintk(1, "querybuf: wrong buffer type\n");
+		goto done;
+	}
+
+	if (b->index >= q->num_buffers) {
+		dprintk(1, "querybuf: buffer index out of range\n");
+		goto done;
+	}
+	vb = q->bufs[b->index];
+	if (NULL == vb) {
+		/* Should never happen */
+		dprintk(1, "querybuf: no such buffer\n");
+		goto done;
+	}
+
+	ret = __fill_v4l2_buffer(vb, b);
+done:
+	mutex_unlock(&q->vb_lock);
+	return ret;
+}
+EXPORT_SYMBOL(vb2_querybuf);
+
+/**
+ * __verify_userptr_ops() - verify that all memory operations required for
+ * USERPTR queue type have been provided
+ */
+static int __verify_userptr_ops(struct vb2_queue *q, unsigned int num_planes)
+{
+	unsigned int i;
+
+	for (i = 0; i < num_planes; ++i)
+		if (!mem_ops(q, i)->get_userptr || !mem_ops(q, i)->put_userptr)
+			return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * __verify_mmap_ops() - verify that all memory operations required for
+ * MMAP queue type have been provided
+ */
+static int __verify_mmap_ops(struct vb2_queue *q, unsigned int num_planes)
+{
+	unsigned int i;
+
+	for (i = 0; i < num_planes; ++i)
+		if (!mem_ops(q, i)->alloc || !mem_ops(q, i)->put
+				|| !mem_ops(q, i)->mmap)
+			return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * __buffers_in_use() - return true if any buffers on the queue are in use and
+ * the queue cannot be freed (by the means of REQBUFS(0)) call
+ */
+static bool __buffers_in_use(struct vb2_queue *q)
+{
+	unsigned int buffer, plane;
+	struct vb2_buffer *vb;
+
+	for (buffer = 0; buffer < q->num_buffers; ++buffer) {
+		vb = q->bufs[buffer];
+		for (plane = 0; plane < vb->num_planes; ++plane) {
+			/*
+			 * If num_users() has not been provided, apparently
+			 * nobody cares.
+			 */
+			if (!mem_ops(q, plane)->num_users)
+				continue;
+
+			/*
+			 * If num_users() returns more than 1, we are not the
+			 * only user of the plane's memory.
+			 */
+			if (call_memop(q, plane, num_users,
+					vb->planes[plane].mem_priv) > 1)
+				return true;
+		}
+	}
+
+	return false;
+}
+
+/**
+ * vb2_reqbufs() - Initiate streaming
+ * @q:		videobuf2 queue
+ * @req:	struct passed from userspace to vidioc_reqbufs handler in driver
+ *
+ * Should be called from vidioc_reqbufs ioctl handler of a driver.
+ * This function:
+ * 1) verifies streaming parameters passed from the userspace,
+ * 2) sets up the queue,
+ * 3) negotiates number of buffers and planes per buffer with the driver
+ *    to be used during streaming,
+ * 4) allocates internal buffer structures (struct vb2_buffer), according to
+ *    the agreed parameters,
+ * 5) for MMAP memory type, allocates actual video memory, using the
+ *    memory handling/allocation routines provided during queue initialization
+ *
+ * If req->count is 0, all the memory will be freed instead.
+ * If the queue has been allocated previously (by a previous vb2_reqbufs) call
+ * and the queue is not busy, memory will be reallocated.
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_reqbufs handler in driver.
+ */
+int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
+{
+	unsigned int num_buffers, num_planes;
+	int ret = 0;
+
+	if (req->memory != V4L2_MEMORY_MMAP
+			&& req->memory != V4L2_MEMORY_USERPTR) {
+		dprintk(1, "reqbufs: unsupported memory type\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&q->vb_lock);
+
+	if (req->type != q->type) {
+		dprintk(1, "reqbufs: queue type invalid\n");
+		ret = -EINVAL;
+		goto end;
+	}
+
+	if (q->streaming) {
+		dprintk(1, "reqbufs: streaming active\n");
+		ret = -EBUSY;
+		goto end;
+	}
+
+	if (req->count == 0) {
+		/* Free/release memory for count = 0, but only if unused */
+		if (q->memory == V4L2_MEMORY_MMAP && __buffers_in_use(q)) {
+			dprintk(1, "reqbufs: memory in use, cannot free\n");
+			ret = -EBUSY;
+			goto end;
+		}
+
+		ret = __vb2_queue_free(q);
+		goto end;
+	}
+
+	if (q->num_buffers != 0) {
+		/*
+		 * We already have buffers allocated, so a reallocation is
+		 * required, but only if the buffers are not in use.
+		 */
+		if (q->memory == V4L2_MEMORY_MMAP && __buffers_in_use(q)) {
+			dprintk(1, "reqbufs: memory in use, "
+					"cannot reallocate\n");
+			ret = -EBUSY;
+			goto end;
+		}
+
+		ret = __vb2_queue_free(q);
+		if (ret)
+			goto end;
+	}
+
+	num_buffers = min_t(unsigned int, req->count, VIDEO_MAX_FRAME);
+
+	/* Ask the driver how many buffers and planes per buffer it requires */
+	ret = q->ops->queue_negotiate(q, &num_buffers, &num_planes);
+	if (ret)
+		goto end;
+
+	/*
+	 * Make sure all the required memory ops for given memory type
+	 * are available.
+	 */
+	if (req->memory == V4L2_MEMORY_MMAP
+			&& __verify_mmap_ops(q, num_planes)) {
+		dprintk(1, "reqbufs: MMAP for current setup unsupported\n");
+		ret = -EINVAL;
+		goto end;
+	} else if (req->memory == V4L2_MEMORY_USERPTR
+			&& __verify_userptr_ops(q, num_planes)) {
+		dprintk(1, "reqbufs: USERPTR for current setup unsupported\n");
+		ret = -EINVAL;
+		goto end;
+	}
+
+	/* Finally, allocate buffers and video memory */
+	ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes);
+	if (ret < 0) {
+		dprintk(1, "Memory allocation failed with error: %d\n", ret);
+	} else {
+		/*
+		 * Return the number of successfully allocated buffers
+		 * to the userspace.
+		 */
+		req->count = ret;
+		ret = 0;
+	}
+
+	q->memory = req->memory;
+
+end:
+	mutex_unlock(&q->vb_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(vb2_reqbufs);
+
+/**
+ * vb2_plane_vaddr() - Return a kernel virtual address of a given plane
+ * @vb:		vb2_buffer to which the plane in question belongs to
+ * @plane_no:	plane number for which the address is to be returned
+ *
+ * This function returns a kernel virtual address of a given plane if
+ * such a mapping exist, NULL otherwise.
+ */
+void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no)
+{
+	struct vb2_queue *q = vb->vb2_queue;
+
+	if (plane_no > vb->num_planes)
+		return NULL;
+
+	return call_memop(q, plane_no, vaddr, vb->planes[plane_no].mem_priv);
+
+}
+EXPORT_SYMBOL_GPL(vb2_plane_vaddr);
+
+/**
+ * vb2_plane_paddr() - Return the physical address of a given plane
+ * @vb:		vb2_buffer to which the plane in question belongs to
+ * @plane_no:	plane number for which the address is to be returned
+ *
+ * This function returns a physical address of a given plane if available,
+ * NULL otherwise.
+ */
+unsigned long vb2_plane_paddr(struct vb2_buffer *vb, unsigned int plane_no)
+{
+	struct vb2_queue *q = vb->vb2_queue;
+
+	if (plane_no > vb->num_planes)
+		return 0UL;
+
+	return call_memop(q, plane_no, paddr, vb->planes[plane_no].mem_priv);
+}
+EXPORT_SYMBOL_GPL(vb2_plane_paddr);
+
+/**
+ * vb2_buffer_done() - inform videobuf that an operation on a buffer is finished
+ * @vb:		vb2_buffer returned from the driver
+ * @state:	either VB2_BUF_STATE_DONE if the operation finished successfully
+ *		or VB2_BUF_STATE_ERROR if the operation finished with an error
+ *
+ * This function should be called by the driver after a hardware operation on
+ * a buffer is finished and the buffer may be returned to userspace. The driver
+ * cannot use this buffer anymore until it is queued back to it by videobuf
+ * by the means of buf_queue callback. Only buffers previously queued to the
+ * driver by buf_queue can be passed to this function.
+ */
+void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
+{
+	struct vb2_queue *q = vb->vb2_queue;
+	unsigned long flags;
+
+	if (vb->state != VB2_BUF_STATE_ACTIVE)
+		return;
+
+	if (state != VB2_BUF_STATE_DONE && state != VB2_BUF_STATE_ERROR)
+		return;
+
+	dprintk(4, "Done processing on buffer %d, state: %d\n",
+			vb->v4l2_buf.index, vb->state);
+
+	/* Add the buffer to the done buffers list */
+	spin_lock_irqsave(&q->done_lock, flags);
+	vb->state = state;
+	list_add_tail(&vb->done_entry, &q->done_list);
+	spin_unlock_irqrestore(&q->done_lock, flags);
+
+	/* Inform any processes that may be waiting for buffers */
+	wake_up(&q->done_wq);
+}
+EXPORT_SYMBOL_GPL(vb2_buffer_done);
+
+/**
+ * __fill_vb2_buffer() - fill a vb2_buffer with information provided in
+ * a v4l2_buffer by the userspace
+ */
+static int __fill_vb2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b,
+				struct v4l2_plane *v4l2_planes)
+{
+	unsigned int plane;
+	int ret;
+
+	if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
+		/*
+		 * Verify that the userspace gave us a valid array for
+		 * plane information.
+		 */
+		ret = __verify_planes_array(vb, b);
+		if (ret)
+			return ret;
+
+		/* Fill in driver-provided information for OUTPUT types */
+		if (V4L2_TYPE_IS_OUTPUT(b->type)) {
+			/*
+			 * Will have to go up to b->length when API starts
+			 * accepting variable number of planes.
+			 */
+			for (plane = 0; plane < vb->num_planes; ++plane) {
+				v4l2_planes[plane].bytesused =
+					b->m.planes[plane].bytesused;
+				v4l2_planes[plane].data_offset =
+					b->m.planes[plane].data_offset;
+			}
+		}
+
+		if (b->memory == V4L2_MEMORY_USERPTR) {
+			for (plane = 0; plane < vb->num_planes; ++plane) {
+				v4l2_planes[plane].m.userptr =
+					b->m.planes[plane].m.userptr;
+				v4l2_planes[plane].length =
+					b->m.planes[plane].length;
+			}
+		}
+	} else {
+		/*
+		 * Single-planar buffers do not use planes array,
+		 * so fill in relevant v4l2_buffer struct fields instead.
+		 * In videobuf we use our internal V4l2_planes struct for
+		 * single-planar buffers as well, for simplicity.
+		 */
+		if (V4L2_TYPE_IS_OUTPUT(b->type))
+			v4l2_planes[0].bytesused = b->bytesused;
+
+		if (b->memory == V4L2_MEMORY_USERPTR) {
+			v4l2_planes[0].m.userptr = b->m.userptr;
+			v4l2_planes[0].length = b->length;
+		}
+	}
+
+	vb->v4l2_buf.field = b->field;
+	vb->v4l2_buf.timestamp = b->timestamp;
+
+	return 0;
+}
+
+/**
+ * __qbuf_userptr() - handle qbuf of a USERPTR buffer
+ */
+static int __qbuf_userptr(struct vb2_buffer *vb, struct v4l2_buffer *b)
+{
+	struct v4l2_plane planes[VIDEO_MAX_PLANES];
+	struct vb2_queue *q = vb->vb2_queue;
+	void *mem_priv = NULL;
+	unsigned int plane;
+	int ret;
+
+	/* Verify and copy relevant information provided by the userspace */
+	ret = __fill_vb2_buffer(vb, b, planes);
+	if (ret)
+		return ret;
+
+	for (plane = 0; plane < vb->num_planes; ++plane) {
+		/* Skip the plane if already verified */
+		if (vb->v4l2_planes[plane].m.userptr == planes[plane].m.userptr
+		    && vb->v4l2_planes[plane].length == planes[plane].length)
+			continue;
+
+		dprintk(3, "qbuf: userspace address for plane %d changed, "
+				"reacquiring memory\n", plane);
+
+		/* Release previously acquired memory if present */
+		if (vb->planes[plane].mem_priv)
+			call_memop(q, plane, put_userptr,
+					vb->planes[plane].mem_priv);
+
+		vb->planes[plane].mem_priv = NULL;
+
+		/* Acquire each plane's memory */
+		if (mem_ops(q, plane)->get_userptr) {
+			mem_priv = mem_ops(q, plane)->get_userptr(
+							planes[plane].m.userptr,
+							planes[plane].length);
+			if (IS_ERR(mem_priv)) {
+				dprintk(1, "qbuf: failed acquiring userspace "
+						"memory for plane %d\n", plane);
+				goto err;
+			}
+
+			vb->planes[plane].mem_priv = mem_priv;
+		}
+	}
+
+	/*
+	 * Call driver-specific initialization on the newly acquired buffer,
+	 * if provided.
+	 */
+	if (q->ops->buf_init) {
+		ret = q->ops->buf_init(vb);
+		if (ret) {
+			dprintk(1, "qbuf: buffer initialization failed\n");
+			goto err;
+		}
+	}
+
+	/*
+	 * Now that everything is in order, copy relevant information
+	 * provided by userspace.
+	 */
+	for (plane = 0; plane < vb->num_planes; ++plane)
+		vb->v4l2_planes[plane] = planes[plane];
+
+	return 0;
+err:
+	/* In case of errors, release planes that were already acquired */
+	for (; plane > 0; --plane) {
+		call_memop(q, plane, put_userptr,
+				vb->planes[plane - 1].mem_priv);
+		vb->planes[plane - 1].mem_priv = NULL;
+	}
+
+	return ret;
+}
+
+/**
+ * __qbuf_mmap() - handle qbuf of an MMAP buffer
+ */
+static int __qbuf_mmap(struct vb2_buffer *vb, struct v4l2_buffer *b)
+{
+	return __fill_vb2_buffer(vb, b, vb->v4l2_planes);
+}
+
+/**
+ * __enqueue_in_driver() - enqueue a vb2_buffer in driver for processing
+ */
+static void __enqueue_in_driver(struct vb2_buffer *vb)
+{
+	struct vb2_queue *q = vb->vb2_queue;
+	vb->state = VB2_BUF_STATE_ACTIVE;
+	q->ops->buf_queue(vb);
+}
+
+/**
+ * vb2_qbuf() - Queue a buffer from userspace
+ * @q:		videobuf2 queue
+ * @b:		buffer structure passed from userspace to vidioc_qbuf handler
+ *		in driver
+ *
+ * Should be called from vidioc_qbuf ioctl handler of a driver.
+ * This function:
+ * 1) verifies the passed buffer,
+ * 2) calls buf_prepare callback in the driver (if provided), in which
+ *    driver-specific buffer initialization can be performed,
+ * 3) if streaming is on, queues the buffer in driver by the means of buf_queue
+ *    callback for processing.
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_qbuf handler in driver.
+ */
+int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
+{
+	struct vb2_buffer *vb;
+	int ret;
+
+	mutex_lock(&q->vb_lock);
+
+	ret = -EINVAL;
+	if (b->type != q->type) {
+		dprintk(1, "qbuf: invalid buffer type\n");
+		goto done;
+	}
+	if (b->index >= q->num_buffers) {
+		dprintk(1, "qbuf: buffer index out of range\n");
+		goto done;
+	}
+
+	vb = q->bufs[b->index];
+	if (NULL == vb) {
+		/* Should never happen */
+		dprintk(1, "qbuf: buffer is NULL\n");
+		goto done;
+	}
+
+	if (b->memory != q->memory) {
+		dprintk(1, "qbuf: invalid memory type\n");
+		goto done;
+	}
+
+	if (vb->state != VB2_BUF_STATE_DEQUEUED) {
+		dprintk(1, "qbuf: buffer already in use\n");
+		goto done;
+	}
+
+	if (q->memory == V4L2_MEMORY_MMAP)
+		ret = __qbuf_mmap(vb, b);
+	else if (q->memory == V4L2_MEMORY_USERPTR)
+		ret = __qbuf_userptr(vb, b);
+	if (ret)
+		goto done;
+
+	if (q->ops->buf_prepare) {
+		ret = q->ops->buf_prepare(vb);
+		if (ret) {
+			dprintk(1, "qbuf: buffer preparation failed\n");
+			goto done;
+		}
+	}
+
+	/*
+	 * Add to the queued buffers list, a buffer will stay on it until
+	 * dequeued in dqbuf.
+	 */
+	list_add_tail(&vb->queued_entry, &q->queued_list);
+	vb->state = VB2_BUF_STATE_QUEUED;
+
+	/*
+	 * If already streaming, give the buffer to driver for processing.
+	 * If not, the buffer will be given to driver on next streamon.
+	 */
+	if (q->streaming)
+		__enqueue_in_driver(vb);
+
+	dprintk(1, "qbuf of buffer %d succeeded\n", vb->v4l2_buf.index);
+	ret = 0;
+done:
+	mutex_unlock(&q->vb_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(vb2_qbuf);
+
+/**
+ * __vb2_wait_for_done_vb() - wait for a buffer to become available
+ * for dequeuing
+ *
+ * Will sleep if required for nonblocking == false.
+ */
+static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking)
+{
+checks:
+	if (!q->streaming) {
+		dprintk(1, "Streaming off, will not wait for buffers\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Buffers may be added to vb_done_list without holding the vb_lock,
+	 * but removal is performed only while holding both vb_lock and the
+	 * vb_done_lock spinlock. Thus we can be sure that as long as we hold
+	 * vb_lock, the list will remain not empty if this check succeeds.
+	 */
+	if (list_empty(&q->done_list)) {
+		int retval;
+		if (nonblocking) {
+			dprintk(1, "Nonblocking and no buffers to dequeue, "
+					"will not wait\n");
+			return -EAGAIN;
+		}
+
+		/*
+		 * We are streaming and nonblocking, wait for another buffer to
+		 * become ready or for streamoff. vb_lock is released to allow
+		 * streamoff or qbuf to be called while waiting.
+		 */
+		mutex_unlock(&q->vb_lock);
+		/*
+		 * Although the mutex is released here, we will be reevaluating
+		 * both conditions again after reacquiring it.
+		 */
+		dprintk(3, "Will sleep waiting for buffers\n");
+		retval = wait_event_interruptible(q->done_wq,
+				!list_empty(&q->done_list) || !q->streaming);
+		mutex_lock(&q->vb_lock);
+
+		if (retval)
+			return -EINTR;
+
+		goto checks;
+	}
+	return 0;
+}
+
+/**
+ * __vb2_get_done_vb() - get a buffer ready for dequeuing
+ *
+ * Will sleep if required for nonblocking == false.
+ */
+static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb,
+				int nonblocking)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	/*
+	 * Wait for at least one buffer to become available on the done_list.
+	 */
+	ret = __vb2_wait_for_done_vb(q, nonblocking);
+	if (ret)
+		goto end;
+
+	/*
+	 * vb_lock has been held since we last verified that done_list is
+	 * not empty, so no need for another list_empty(done_list) check.
+	 */
+	spin_lock_irqsave(&q->done_lock, flags);
+	*vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry);
+	list_del(&(*vb)->done_entry);
+	spin_unlock_irqrestore(&q->done_lock, flags);
+
+end:
+	return ret;
+}
+
+
+/**
+ * vb2_dqbuf() - Dequeue a buffer to the userspace
+ * @q:		videobuf2 queue
+ * @b:		buffer structure passed from userspace to vidioc_dqbuf handler
+ *		in driver
+ * @nonblocking: if true, this call will not sleep waiting for a buffer if no
+ *		 buffers ready for dequeuing are present. Normally the driver
+ *		 would be passing (file->f_flags & O_NONBLOCK) here
+ *
+ * Should be called from vidioc_dqbuf ioctl handler of a driver.
+ * This function:
+ * 1) verifies the passed buffer,
+ * 2) calls buf_finish callback in the driver (if provided), in which
+ *    driver can perform any additional operations that may be required before
+ *    returning the buffer to userspace, such as cache sync,
+ * 3) the buffer struct members are filled with relevant information for
+ *    the userspace.
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_dqbuf handler in driver.
+ */
+int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
+{
+	struct vb2_buffer *vb = NULL;
+	int ret;
+
+	mutex_lock(&q->vb_lock);
+
+	if (b->type != q->type) {
+		dprintk(1, "dqbuf: invalid buffer type\n");
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = __vb2_get_done_vb(q, &vb, nonblocking);
+	if (ret < 0) {
+		dprintk(1, "dqbuf: error getting next done buffer\n");
+		goto done;
+	}
+
+	if (q->ops->buf_finish) {
+		ret = q->ops->buf_finish(vb);
+		if (ret) {
+			dprintk(1, "dqbuf: buffer finish failed\n");
+			goto done;
+		}
+	}
+
+	switch (vb->state) {
+	case VB2_BUF_STATE_DONE:
+		dprintk(3, "dqbuf: Returning done buffer\n");
+		break;
+	case VB2_BUF_STATE_ERROR:
+		dprintk(3, "dqbuf: Returning done buffer with errors\n");
+		break;
+	default:
+		dprintk(1, "dqbuf: Invalid buffer state\n");
+		ret = -EINVAL;
+		goto done;
+	}
+
+	/* Fill buffer information for the userspace */
+	__fill_v4l2_buffer(vb, b);
+	/* Remove from videobuf queue */
+	list_del(&vb->queued_entry);
+
+	dprintk(1, "dqbuf of buffer %d, with state %d\n",
+			vb->v4l2_buf.index, vb->state);
+
+	vb->state = VB2_BUF_STATE_DEQUEUED;
+
+done:
+	mutex_unlock(&q->vb_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(vb2_dqbuf);
+
+/**
+ * vb2_streamon - start streaming
+ * @q:		videobuf2 queue
+ * @type:	type argument passed from userspace to vidioc_streamon handler
+ *
+ * Should be called from vidioc_streamon handler of a driver.
+ * This function:
+ * 1) verifies current state
+ * 2) starts streaming and passes any previously queued buffers to the driver
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_streamon handler in the driver.
+ */
+int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
+{
+	struct vb2_buffer *vb;
+	int ret = 0;
+
+	mutex_lock(&q->vb_lock);
+
+	if (type != q->type) {
+		dprintk(1, "streamon: invalid stream type\n");
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if (q->streaming) {
+		dprintk(1, "streamon: already streaming\n");
+		ret = -EBUSY;
+		goto done;
+	}
+
+	/*
+	 * Cannot start streaming on an OUTPUT device if no buffers have
+	 * been queued yet.
+	 */
+	if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+		if (list_empty(&q->queued_list)) {
+			dprintk(1, "streamon: no output buffers queued\n");
+			ret = -EINVAL;
+			goto done;
+		}
+	}
+
+	q->streaming = 1;
+
+	/*
+	 * Let driver notice that streaming state has been enabled.
+	 */
+	if (q->ops->start_streaming)
+		q->ops->start_streaming(q);
+
+	/*
+	 * If any buffers were queued before streamon,
+	 * we can now pass them to driver for processing.
+	 */
+	list_for_each_entry(vb, &q->queued_list, queued_entry)
+		__enqueue_in_driver(vb);
+
+	dprintk(3, "Streamon successful\n");
+done:
+	mutex_unlock(&q->vb_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(vb2_streamon);
+
+/**
+ * __vb2_queue_cancel() - cancel and stop (pause) streaming
+ *
+ * Removes all queued buffers from driver's queue and all buffers queued by
+ * userspace from videobuf's queue. Returns to state after reqbufs.
+ */
+static void __vb2_queue_cancel(struct vb2_queue *q)
+{
+	/*
+	 * Tell driver to stop all dma transactions and release all queued
+	 * buffers
+	 */
+	if (q->streaming && q->ops->stop_streaming)
+		q->ops->stop_streaming(q);
+	q->streaming = 0;
+
+	/*
+	 * Remove all buffers from videobuf's list...
+	 */
+	INIT_LIST_HEAD(&q->queued_list);
+	/*
+	 * ...and done list; userspace will not receive any buffers it
+	 * has not already dequeued before initiating cancel.
+	 */
+	INIT_LIST_HEAD(&q->done_list);
+	wake_up_all(&q->done_wq);
+}
+
+/**
+ * vb2_streamoff - stop streaming
+ * @q:		videobuf2 queue
+ * @type:	type argument passed from userspace to vidioc_streamoff handler
+ *
+ * Should be called from vidioc_streamoff handler of a driver.
+ * This function:
+ * 1) verifies current state,
+ * 2) stop streaming and dequeues any queued buffers, including those previously
+ *    passed to the driver (after waiting for the driver to finish).
+ *
+ * This call can be used for pausing playback.
+ * The return values from this function are intended to be directly returned
+ * from vidioc_streamoff handler in the driver
+ */
+int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
+{
+	int ret = 0;
+
+	mutex_lock(&q->vb_lock);
+
+	if (type != q->type) {
+		dprintk(1, "streamoff: invalid stream type\n");
+		ret = -EINVAL;
+		goto end;
+	}
+
+	if (!q->streaming) {
+		dprintk(1, "streamoff: not streaming\n");
+		ret = -EINVAL;
+		goto end;
+	}
+
+	/*
+	 * Cancel will pause streaming and remove all buffers from the driver
+	 * and videobuf, effectively returning control over them to userspace.
+	 */
+	__vb2_queue_cancel(q);
+
+	dprintk(3, "Streamoff successful\n");
+end:
+	mutex_unlock(&q->vb_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(vb2_streamoff);
+
+/**
+ * __find_plane_by_off() - find plane associated with the given offset off
+ */
+int __find_plane_by_off(struct vb2_queue *q, unsigned long off,
+			unsigned int *_buffer, unsigned int *_plane)
+{
+	struct vb2_buffer *vb;
+	unsigned int buffer, plane;
+
+	/*
+	 * Go over all buffers and their planes, comparing the given offset
+	 * with an offset assigned to each plane. If a match is found,
+	 * return its buffer and plane numbers.
+	 */
+	for (buffer = 0; buffer < q->num_buffers; ++buffer) {
+		vb = q->bufs[buffer];
+
+		for (plane = 0; plane < vb->num_planes; ++plane) {
+			if (vb->v4l2_planes[plane].m.mem_offset == off) {
+				*_buffer = buffer;
+				*_plane = plane;
+				return 0;
+			}
+		}
+	}
+
+	return -EINVAL;
+}
+
+/**
+ * vb2_mmap() - map video buffers into application address space
+ * @q:		videobuf2 queue
+ * @vma:	vma passed to the mmap file operation handler in the driver
+ *
+ * Should be called from mmap file operation handler of a driver.
+ * This function maps one plane of one of the available video buffers to
+ * userspace. To map whole video memory allocated on reqbufs, this function
+ * has to be called once per each plane per each buffer previously allocated.
+ *
+ * When the userspace application calls mmap, it passes to it an offset returned
+ * to it earlier by the means of vidioc_querybuf handler. That offset acts as
+ * a "cookie", which is then used to identify the plane to be mapped.
+ * This function finds a plane with a matching offset and a mapping is performed
+ * by the means of a provided memory operation.
+ *
+ * The return values from this function are intended to be directly returned
+ * from the mmap handler in driver.
+ */
+int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
+{
+	unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
+	struct vb2_plane *vb_plane;
+	struct vb2_buffer *vb;
+	unsigned int buffer, plane;
+	int ret = -EINVAL;
+
+	if (q->memory != V4L2_MEMORY_MMAP) {
+		dprintk(1, "Queue is not currently set up for mmap\n");
+		return ret;
+	}
+
+	if (V4L2_TYPE_IS_OUTPUT(q->type) &&
+	   (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))) {
+		dprintk(1, "Invalid vma flags (need VM_WRITE | VM_SHARED)\n");
+		return ret;
+	} else if (!(vma->vm_flags & VM_READ) || !(vma->vm_flags & VM_SHARED)) {
+		dprintk(1, "Invalid vma flags (need VM_READ | VM_SHARED)\n");
+		return ret;
+	}
+
+	mutex_lock(&q->vb_lock);
+
+	/*
+	 * Find the plane corresponding to the offset passed by userspace.
+	 */
+	ret = __find_plane_by_off(q, off, &buffer, &plane);
+	if (ret)
+		goto end;
+
+	vb = q->bufs[buffer];
+	vb_plane = &vb->planes[plane];
+
+	if (vb_plane->mapped) {
+		dprintk(1, "Plane already mapped\n");
+		goto end;
+	}
+
+	if (!mem_ops(q, plane)->mmap) {
+		dprintk(1, "mmap not supported\n");
+		goto end;
+	}
+
+	ret = mem_ops(q, plane)->mmap(vb_plane->mem_priv, vma);
+	if (ret)
+		goto end;
+
+	vb_plane->mapped = 1;
+	vb->num_planes_mapped++;
+
+	dprintk(3, "Buffer %d, plane %d successfully mapped\n", buffer, plane);
+end:
+	mutex_unlock(&q->vb_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(vb2_mmap);
+
+/**
+ * vb2_has_consumers() - return true if the userspace is waiting for a buffer
+ * @q:		videobuf2 queue
+ *
+ * This function returns true if a userspace application is waiting for a buffer
+ * to be ready to dequeue (on which a hardware operation has been finished).
+ */
+bool vb2_has_consumers(struct vb2_queue *q)
+{
+	return waitqueue_active(&q->done_wq);
+}
+EXPORT_SYMBOL_GPL(vb2_has_consumers);
+
+/**
+ * vb2_poll() - implements poll userspace operation
+ * @q:		videobuf2 queue
+ * @file:	file argument passed to the poll file operation handler
+ * @wait:	wait argument passed to the poll file operation handler
+ *
+ * This function implements poll file operation handler for a driver.
+ * For CAPTURE queues, if a buffer is ready to be dequeued, the userspace will
+ * be informed that the file descriptor of a video device is available for
+ * reading.
+ * For OUTPUT queues, if a buffer is ready to be dequeued, the file descriptor
+ * will be reported as available for writing.
+ *
+ * The return values from this function are intended to be directly returned
+ * from poll handler in driver.
+ */
+unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait)
+{
+	unsigned long flags = 0;
+	unsigned int ret = 0;
+	struct vb2_buffer *vb = NULL;
+
+	mutex_lock(&q->vb_lock);
+
+	/*
+	 * There is nothing to wait for if no buffers have already been queued.
+	 */
+	if (list_empty(&q->queued_list)) {
+		ret = POLLERR;
+		goto end;
+	}
+
+	poll_wait(file, &q->done_wq, wait);
+
+	/*
+	 * Take first buffer available for dequeuing.
+	 */
+	spin_lock_irqsave(&q->done_lock, flags);
+	if (!list_empty(&q->done_list))
+		vb = list_first_entry(&q->done_list, struct vb2_buffer,
+					done_entry);
+	spin_unlock_irqrestore(&q->done_lock, flags);
+
+	if (!vb)
+		goto end;
+
+	if (vb->state == VB2_BUF_STATE_DONE
+			|| vb->state == VB2_BUF_STATE_ERROR) {
+		if (V4L2_TYPE_IS_OUTPUT(q->type))
+			ret = POLLOUT | POLLWRNORM;
+		else
+			ret = POLLIN | POLLRDNORM;
+	}
+end:
+	mutex_unlock(&q->vb_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(vb2_poll);
+
+/**
+ * vb2_queue_init() - initialize a videobuf2 queue
+ * @q:		videobuf2 queue; this structure should be allocated in driver
+ * @ops:	driver-specific callbacks
+ * @alloc_ctx:	memory handler/allocator-specific context to be used;
+ *		the given context will be used for memory allocation on all
+ *		planes and buffers; it is possible to assign different contexts
+ *		per plane, use vb2_set_alloc_ctx() for that
+ * @type:	queue type
+ * @drv_priv:	driver private data, may be NULL; it can be used by driver in
+ *		driver-specific callbacks when issued
+ */
+int vb2_queue_init(struct vb2_queue *q, const struct vb2_ops *ops,
+			const struct vb2_alloc_ctx *alloc_ctx,
+			enum v4l2_buf_type type, void *drv_priv)
+{
+	unsigned int i;
+
+	BUG_ON(!q);
+	BUG_ON(!ops);
+	BUG_ON(!ops->queue_negotiate);
+	BUG_ON(!ops->plane_setup);
+	BUG_ON(!ops->buf_queue);
+
+	BUG_ON(!alloc_ctx);
+	BUG_ON(!alloc_ctx->mem_ops);
+
+	memset(q, 0, sizeof *q);
+	q->ops = ops;
+
+	for (i = 0; i < VIDEO_MAX_PLANES; ++i)
+		q->alloc_ctx[i] = alloc_ctx;
+
+	q->type = type;
+	q->drv_priv = drv_priv;
+
+	mutex_init(&q->vb_lock);
+	INIT_LIST_HEAD(&q->queued_list);
+	INIT_LIST_HEAD(&q->done_list);
+	spin_lock_init(&q->done_lock);
+	init_waitqueue_head(&q->done_wq);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_queue_init);
+
+/**
+ * vb2_queue_release() - stop streaming, release the queue and free memory
+ * @q:		videobuf2 queue
+ *
+ * This function stops streaming and performs necessary clean ups, including
+ * freeing video buffer memory. The driver is responsible for freeing
+ * the vb2_queue structure itself.
+ */
+void vb2_queue_release(struct vb2_queue *q)
+{
+	mutex_lock(&q->vb_lock);
+
+	__vb2_queue_cancel(q);
+	__vb2_queue_free(q);
+
+	mutex_unlock(&q->vb_lock);
+}
+EXPORT_SYMBOL_GPL(vb2_queue_release);
+
+MODULE_DESCRIPTION("Driver helper framework for Video for Linux 2");
+MODULE_AUTHOR("Pawel Osciak");
+MODULE_LICENSE("GPL");
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
new file mode 100644
index 0000000..76d0b4e
--- /dev/null
+++ b/include/media/videobuf2-core.h
@@ -0,0 +1,371 @@
+/*
+ * videobuf2-core.h - V4L2 driver helper framework
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <p.osciak@samsung.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_CORE_H
+#define _MEDIA_VIDEOBUF2_CORE_H
+
+#include <linux/mutex.h>
+#include <linux/mm_types.h>
+#include <linux/videodev2.h>
+#include <linux/poll.h>
+
+struct vb2_alloc_ctx;
+
+/**
+ * struct vb2_mem_ops - memory handling/memory allocator operations
+ * @alloc:	allocate video memory and, optionally, allocator private data,
+ *		return NULL on failure or a pointer to allocator private,
+ *		per-buffer data on success, NULL on failure; the returned
+ *		private structure will then be passed as buf_priv argument
+ *		to other ops in this structure
+ * @put:	inform the allocator that the buffer will no longer be used;
+ *		usually will result in the allocator freeing the buffer (if
+ *		no other users of this buffer are present); the buf_priv
+ *		argument is the allocator private per-buffer structure
+ *		previously returned from the alloc callback
+ * @get_userptr: acquire userspace memory for a hardware operation; used for
+ *		 USERPTR memory types; vaddr is the address passed to the
+ *		 videobuf layer when queuing a video buffer of USERPTR type;
+ *		 should return an allocator private per-buffer structure
+ *		 associated with the buffer on success, NULL on failure;
+ *		 the returned private structure will then be passed as buf_priv
+ *		 argument to other ops in this structure
+ * @put_userptr: inform the allocator that a USERPTR buffer will no longer
+ *		 be used
+ * @vaddr:	return a kernel virtual address to a given memory buffer
+ *		associated with the passed private structure or NULL if no
+ *		such mapping exists
+ * @paddr:	return a physical address to a given memory buffer associated
+ *		with the passed private structure or NULL if not available
+ * @num_users:	return the current number of users of a memory buffer;
+ *		return 1 if the videobuf layer (or actually the driver using
+ *		it) is the only user
+ * @mmap:	setup a userspace mapping for a given memory buffer under
+ *		the provided virtual memory region
+ *
+ * Required ops for USERPTR types: get_userptr, put_userptr.
+ * Required ops for MMAP types: alloc, put, num_users, mmap.
+ */
+struct vb2_mem_ops {
+	void		*(*alloc)(const struct vb2_alloc_ctx *alloc_ctx,
+					unsigned long size);
+	void		(*put)(void *buf_priv);
+
+	void		*(*get_userptr)(unsigned long vaddr,
+						unsigned long size);
+	void		(*put_userptr)(void *buf_priv);
+
+	void		*(*vaddr)(void *buf_priv);
+	unsigned long	(*paddr)(void *buf_priv);
+	unsigned int	(*num_users)(void *buf_priv);
+
+	int		(*mmap)(void *buf_priv, struct vm_area_struct *vma);
+};
+
+/**
+ * struct vb2_alloc_ctx - allocator/memory handler-specific context
+ * @mem_ops:	memory operations used by the current context
+ *
+ * This structure is passed to the alloc() call and can be used to store
+ * additional allocator private data. In such case it can be embedded in
+ * a allocator private structure as its first member.
+ * In more complicated cases, separate contexts can be assigned to each plane,
+ * if required. This would allow separate memory allocation/handling strategies
+ * for each plane, which is useful for drivers requiring different memory types
+ * and/or handling for each plane.
+ *
+ * See videobuf2-vmalloc.c and videobuf2-dma-coherent.c for example usage.
+ */
+struct vb2_alloc_ctx {
+	const struct vb2_mem_ops	*mem_ops;
+};
+
+struct vb2_plane {
+	void			*mem_priv;
+	int			mapped:1;
+};
+
+/**
+ * enum vb2_buffer_state - current video buffer state
+ * @VB2_BUF_STATE_DEQUEUED:	buffer under userspace control
+ * @VB2_BUF_STATE_QUEUED:	buffer queued in videobuf, but not in driver
+ * @VB2_BUF_STATE_ACTIVE:	buffer queued in driver and possibly used
+ *				in a hardware operation
+ * @VB2_BUF_STATE_DONE:		buffer returned from driver to videobuf, but
+ *				not yet dequeued to userspace
+ * @VB2_BUF_STATE_ERROR:	same as above, but the operation on the buffer
+ *				has ended with an error, which will be reported
+ *				to the userspace when it is dequeued
+ */
+enum vb2_buffer_state {
+	VB2_BUF_STATE_DEQUEUED,
+	VB2_BUF_STATE_QUEUED,
+	VB2_BUF_STATE_ACTIVE,
+	VB2_BUF_STATE_DONE,
+	VB2_BUF_STATE_ERROR,
+};
+
+struct vb2_queue;
+
+/**
+ * struct vb2_buffer - represents a video buffer
+ * @v4l2_buf:		struct v4l2_buffer associated with this buffer; can
+ *			be read by the driver and relevant entries can be
+ *			changed by the driver in case of CAPTURE types
+ *			(such as timestamp)
+ * @v4l2_planes:	struct v4l2_planes associated with this buffer; can
+ *			be read by the driver and relevant entries can be
+ *			changed by the driver in case of CAPTURE types
+ *			(such as bytesused); NOTE that even for single-planar
+ *			types, the v4l2_planes[0] struct should be used
+ *			instead of v4l2_buf for filling bytesused - drivers
+ *			should use the vb2_set_plane_payload() function for that
+ * @vb2_queue:		the queue to which this driver belongs
+ * @drv_entry:		list entry to be used by driver for storing the buffer
+ * @num_planes:		number of planes in the buffer
+ *			on an internal driver queue
+ * @state:		current buffer state; do not change
+ * @queued_entry:	entry on the queued buffers list, which holds all
+ *			buffers queued from userspace
+ * @done_entry:		entry on the list that stores all buffers ready to
+ *			be dequeued to userspace
+ * @planes:		private per-plane information; do not change
+ * @num_planes_mapped:	number of mapped planes; do not change
+ */
+struct vb2_buffer {
+	struct v4l2_buffer	v4l2_buf;
+	struct v4l2_plane	v4l2_planes[VIDEO_MAX_PLANES];
+
+	struct vb2_queue	*vb2_queue;
+
+	unsigned int		num_planes;
+
+/* Private: internal use only */
+	enum vb2_buffer_state	state;
+
+	struct list_head	queued_entry;
+	struct list_head	done_entry;
+
+	struct vb2_plane	planes[VIDEO_MAX_PLANES];
+	unsigned int		num_planes_mapped;
+};
+
+/**
+ * struct vb2_ops - driver-specific callbacks
+ *
+ * @queue_negotiate:	called from a VIDIOC_REQBUFS handler, before
+ *			memory allocation; driver should return the required
+ *			number of buffers in num_buffers and the required number
+ *			of planes per buffer in num_planes
+ * @plane_setup:	called before memory allocation num_planes times;
+ *			driver should return the required size of plane number
+ *			plane_no
+ * @buf_init:		called once after allocating a buffer (in MMAP case)
+ *			or after acquiring a new USERPTR buffer; drivers may
+ *			perform additional buffer-related initialization;
+ *			initialization failure (return != 0) will prevent
+ *			queue setup from completing successfully; optional
+ * @buf_prepare:	called every time the buffer is queued from userspace;
+ *			drivers may perform any initialization required before
+ *			each hardware operation in this callback;
+ *			if an error is returned, the buffer will not be queued
+ *			in driver; optional
+ * @buf_finish:		called before every dequeue of the buffer back to
+ *			userspace; drivers may perform any operations required
+ *			before userspace accesses the buffer; optional
+ * @buf_cleanup:	called once before the buffer is freed; drivers may
+ *			perform any additional cleanup; optional
+ * @start_streaming:	called once before entering 'streaming' state; enables
+ *			driver to recieve buffers over buf_queue() callback
+ * @stop_streaming:	called when 'streaming' state must be disabled; driver
+ *			should stop any dma transactions or wait until they
+ *			finish and give back all buffers it got from buf_queue()
+ *			callback
+ * @buf_queue:		passes buffer vb to the driver; driver may start
+ *			hardware operation on this buffer; driver should give
+ *			the buffer back by calling vb2_buffer_done() function
+ */
+struct vb2_ops {
+	int (*queue_negotiate)(struct vb2_queue *q, unsigned int *num_buffers,
+				unsigned int *num_planes);
+	int (*plane_setup)(struct vb2_queue *q,
+			   unsigned int plane_no, unsigned long *plane_size);
+
+	int (*buf_init)(struct vb2_buffer *vb);
+	int (*buf_prepare)(struct vb2_buffer *vb);
+	int (*buf_finish)(struct vb2_buffer *vb);
+	void (*buf_cleanup)(struct vb2_buffer *vb);
+
+	int (*start_streaming)(struct vb2_queue *q);
+	int (*stop_streaming)(struct vb2_queue *q);
+	void (*buf_queue)(struct vb2_buffer *vb);
+};
+
+/**
+ * struct vb2_queue - a videobuf queue
+ *
+ * @type:	current queue type
+ * @memory:	current memory type used
+ * @drv_priv:	driver private data, passed on vb2_queue_init
+ * @bufs:	videobuf buffer structures
+ * @num_buffers: number of allocated/used buffers
+ * @vb_lock:	for ioctl handler and queue state changes synchronization
+ * @queued_list: list of buffers currently queued from userspace
+ * @done_list:	list of buffers ready to be dequeued to userspace
+ * @done_lock:	lock to protect done_list list
+ * @done_wq:	waitqueue for processes waiting for buffers ready to be dequeued
+ * @ops:	driver-specific callbacks
+ * @alloc_ctx:	memory type/allocator-specific callbacks
+ * @streaming:	current streaming state
+ * @userptr_supported: true if queue supports USERPTR types
+ * @mmap_supported: true if queue supports MMAP types
+ */
+struct vb2_queue {
+	enum v4l2_buf_type		type;
+	enum v4l2_memory		memory;
+	void				*drv_priv;
+
+/* private: internal use only */
+	struct vb2_buffer		*bufs[VIDEO_MAX_FRAME];
+	unsigned int			num_buffers;
+
+	struct mutex			vb_lock;
+	struct list_head		queued_list;
+
+	struct list_head		done_list;
+	spinlock_t			done_lock;
+	wait_queue_head_t		done_wq;
+
+	const struct vb2_ops		*ops;
+	const struct vb2_alloc_ctx	*alloc_ctx[VIDEO_MAX_PLANES];
+
+	int				streaming:1;
+	int				userptr_supported:1;
+	int				mmap_supported:1;
+};
+
+void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no);
+unsigned long vb2_plane_paddr(struct vb2_buffer *vb, unsigned int plane_no);
+void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state);
+bool vb2_has_consumers(struct vb2_queue *q);
+
+int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b);
+int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req);
+
+int vb2_queue_init(struct vb2_queue *q, const struct vb2_ops *ops,
+			const struct vb2_alloc_ctx *alloc_ctx,
+			enum v4l2_buf_type type, void *drv_priv);
+void vb2_queue_release(struct vb2_queue *q);
+
+int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b);
+int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking);
+
+int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type);
+int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type);
+
+int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma);
+unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait);
+
+/**
+ * vb2_is_streaming() - return streaming status of the queue
+ * @q:		videobuf queue
+ */
+static inline bool vb2_is_streaming(struct vb2_queue *q)
+{
+	return q->streaming;
+}
+
+/**
+ * vb2_lock() - lock the queue
+ * @q:		videobuf queue
+ *
+ * This function can be used to obtain internal vb2 lock and block any
+ * concurrent calls to vb2. Usefull for implementing S_FMT and similar
+ * operations that requires exclusive access to driver and it's queue.
+ */
+static inline void vb2_lock(struct vb2_queue *q)
+{
+	mutex_lock(&q->vb_lock);
+}
+
+/**
+ * vb2_unlock() - unlock the queue
+ * @q:		videobuf queue
+ *
+ * This function can be used to release internal vb2 lock and let it
+ * any pending calls to vb2.
+ */
+static inline void vb2_unlock(struct vb2_queue *q)
+{
+	mutex_unlock(&q->vb_lock);
+}
+
+/**
+ * vb2_get_drv_priv() - return driver private data associated with the queue
+ * @q:		videobuf queue
+ */
+static inline void *vb2_get_drv_priv(struct vb2_queue *q)
+{
+	return q->drv_priv;
+}
+
+/**
+ * vb2_set_plane_payload() - set bytesused for the plane plane_no
+ * @vb:		buffer for which plane payload should be set
+ * @plane_no:	plane number for which payload should be set
+ * @size:	payload in bytes
+ */
+static inline void vb2_set_plane_payload(struct vb2_buffer *vb,
+				 unsigned int plane_no, unsigned long size)
+{
+	if (!V4L2_TYPE_IS_MULTIPLANAR(vb->vb2_queue->type) && plane_no == 0)
+		vb->v4l2_buf.bytesused = size;
+	else
+		vb->v4l2_planes[plane_no].bytesused = size;
+}
+
+/**
+ * vb2_plane_size() - return plane size in bytes
+ * @vb:		buffer for which plane size should be returned
+ * @plane_no:	plane number for which size should be returned
+ */
+static inline unsigned long
+vb2_plane_size(struct vb2_buffer *vb, unsigned int plane_no)
+{
+	if (plane_no < vb->num_planes)
+		return vb->v4l2_planes[plane_no].length;
+	else
+		return 0;
+}
+
+/**
+ * vb2_set_alloc_ctx() - use to assign a allocator context for a plane
+ * @q:		videobuf queue
+ * @alloc_ctx:	allocator context to be assigned
+ * @plane_no:	plane number to which the context is to be assigned
+ *
+ * This function can be used to assign additional allocator contexts
+ * on a per-plane basis, if a driver requires such feature.
+ * When a driver passes an allocator context to the vb2_queue_init call,
+ * it is initially assigned to all planes. Driver can then use this call
+ * to selectively assign additional contexts to particular planes.
+ * A context assigned to plane_no will be used for memory operations
+ * on plane number plane_no for all buffers.
+ */
+static inline void
+vb2_set_alloc_ctx(struct vb2_queue *q, struct vb2_alloc_ctx *alloc_ctx,
+			unsigned int plane_no)
+{
+	if (plane_no < VIDEO_MAX_PLANES)
+		q->alloc_ctx[plane_no] = alloc_ctx;
+}
+
+#endif /* _MEDIA_VIDEOBUF2_CORE_H */
-- 
1.7.1.569.g6f426


^ permalink raw reply related

* [PATCH 6/7] v4l: vivi: port to videobuf2
From: Marek Szyprowski @ 2010-10-20  6:41 UTC (permalink / raw)
  To: linux-media; +Cc: m.szyprowski, pawel, kyungmin.park
In-Reply-To: <1287556873-23179-1-git-send-email-m.szyprowski@samsung.com>

From: Pawel Osciak <p.osciak@samsung.com>

Make vivi use videobuf2 in place of videobuf.

Signed-off-by: Pawel Osciak <p.osciak@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
CC: Pawel Osciak <pawel@osciak.com>
---
 drivers/media/video/Kconfig |    2 +-
 drivers/media/video/vivi.c  |  348 +++++++++++++++++++++++--------------------
 2 files changed, 186 insertions(+), 164 deletions(-)

diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 2143112..4dd14c2 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -557,7 +557,7 @@ config VIDEO_VIVI
 	depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
 	depends on (FRAMEBUFFER_CONSOLE || STI_CONSOLE) && FONTS
 	select FONT_8x16
-	select VIDEOBUF_VMALLOC
+	select VIDEOBUF2_VMALLOC
 	default n
 	---help---
 	  Enables a virtual video driver. This device shows a color bar
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index e17b6fe..662de4f 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -7,6 +7,9 @@
  *      John Sokol <sokol--a.t--videotechnology.com>
  *      http://v4l.videotechnology.com/
  *
+ *      Conversion to videobuf2 by Pawel Osciak & Marek Szyprowski
+ *      Copyright (c) 2010 Samsung Electronics
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the BSD Licence, GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the
@@ -23,10 +26,8 @@
 #include <linux/mutex.h>
 #include <linux/videodev2.h>
 #include <linux/kthread.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
 #include <linux/freezer.h>
-#endif
-#include <media/videobuf-vmalloc.h>
+#include <media/videobuf2-vmalloc.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-common.h>
@@ -42,7 +43,7 @@
 #define MAX_HEIGHT 1200
 
 #define VIVI_MAJOR_VERSION 0
-#define VIVI_MINOR_VERSION 7
+#define VIVI_MINOR_VERSION 8
 #define VIVI_RELEASE 0
 #define VIVI_VERSION \
 	KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
@@ -70,6 +71,9 @@ MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
 /* Global font descriptor */
 static const u8 *font8x16;
 
+/* Videobuf2 allocator/memory handler context */
+static struct vb2_alloc_ctx *alloc_ctx;
+
 #define dprintk(dev, level, fmt, arg...) \
 	v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
 
@@ -133,16 +137,11 @@ static struct vivi_fmt *get_format(struct v4l2_format *f)
 	return &formats[k];
 }
 
-struct sg_to_addr {
-	int pos;
-	struct scatterlist *sg;
-};
-
 /* buffer for one video frame */
 struct vivi_buffer {
 	/* common v4l buffer stuff -- must be first */
-	struct videobuf_buffer vb;
-
+	struct vb2_buffer	vb;
+	struct list_head	list;
 	struct vivi_fmt        *fmt;
 };
 
@@ -190,9 +189,11 @@ struct vivi_dev {
 	/* video capture */
 	struct vivi_fmt            *fmt;
 	unsigned int               width, height;
-	struct videobuf_queue      vb_vidq;
+	struct vb2_queue	   vb_vidq;
+	enum v4l2_field		   field;
+	unsigned int		   field_count;
 
-	unsigned long 		   generating;
+	atomic_t		   open_count;
 	u8 			   bars[9][3];
 	u8 			   line[MAX_WIDTH * 4];
 };
@@ -443,10 +444,10 @@ static void gen_text(struct vivi_dev *dev, char *basep,
 
 static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
 {
-	int hmax = buf->vb.height;
-	int wmax = buf->vb.width;
+	int wmax = dev->width;
+	int hmax = dev->height;
 	struct timeval ts;
-	void *vbuf = videobuf_to_vmalloc(&buf->vb);
+	void *vbuf = vb2_plane_vaddr(&buf->vb, 0);
 	unsigned ms;
 	char str[100];
 	int h, line = 1;
@@ -483,11 +484,11 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
 
 	dev->mv_count += 2;
 
-	/* Advice that buffer was filled */
-	buf->vb.field_count++;
+	buf->vb.v4l2_buf.field = dev->field;
+	dev->field_count++;
+	buf->vb.v4l2_buf.sequence = dev->field_count >> 1;
 	do_gettimeofday(&ts);
-	buf->vb.ts = ts;
-	buf->vb.state = VIDEOBUF_DONE;
+	buf->vb.v4l2_buf.timestamp = ts;
 }
 
 static void vivi_thread_tick(struct vivi_dev *dev)
@@ -504,23 +505,21 @@ static void vivi_thread_tick(struct vivi_dev *dev)
 		goto unlock;
 	}
 
-	buf = list_entry(dma_q->active.next,
-			 struct vivi_buffer, vb.queue);
-
-	/* Nobody is waiting on this buffer, return */
-	if (!waitqueue_active(&buf->vb.done))
+	/* If nobody is waiting for a buffer, return */
+	if (!vb2_has_consumers(&dev->vb_vidq))
 		goto unlock;
 
-	list_del(&buf->vb.queue);
+	buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
+	list_del(&buf->list);
 
-	do_gettimeofday(&buf->vb.ts);
+	do_gettimeofday(&buf->vb.v4l2_buf.timestamp);
 
 	/* Fill buffer */
 	vivi_fillbuff(dev, buf);
 	dprintk(dev, 1, "filled buffer %p\n", buf);
 
-	wake_up(&buf->vb.done);
-	dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i);
+	vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
+	dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
 unlock:
 	spin_unlock_irqrestore(&dev->slock, flags);
 }
@@ -571,17 +570,12 @@ static int vivi_thread(void *data)
 	return 0;
 }
 
-static void vivi_start_generating(struct file *file)
+static int vivi_start_generating(struct vivi_dev *dev)
 {
-	struct vivi_dev *dev = video_drvdata(file);
 	struct vivi_dmaqueue *dma_q = &dev->vidq;
 
 	dprintk(dev, 1, "%s\n", __func__);
 
-	if (test_and_set_bit(0, &dev->generating))
-		return;
-	file->private_data = dev;
-
 	/* Resets frame counters */
 	dev->ms = 0;
 	dev->mv_count = 0;
@@ -593,146 +587,182 @@ static void vivi_start_generating(struct file *file)
 
 	if (IS_ERR(dma_q->kthread)) {
 		v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
-		clear_bit(0, &dev->generating);
-		return;
+		return PTR_ERR(dma_q->kthread);
 	}
 	/* Wakes thread */
 	wake_up_interruptible(&dma_q->wq);
 
 	dprintk(dev, 1, "returning from %s\n", __func__);
+	return 0;
 }
 
-static void vivi_stop_generating(struct file *file)
+static void vivi_stop_generating(struct vivi_dev *dev)
 {
-	struct vivi_dev *dev = video_drvdata(file);
 	struct vivi_dmaqueue *dma_q = &dev->vidq;
 
 	dprintk(dev, 1, "%s\n", __func__);
 
-	if (!file->private_data)
-		return;
-	if (!test_and_clear_bit(0, &dev->generating))
-		return;
-
 	/* shutdown control thread */
 	if (dma_q->kthread) {
 		kthread_stop(dma_q->kthread);
 		dma_q->kthread = NULL;
 	}
-	videobuf_stop(&dev->vb_vidq);
-	videobuf_mmap_free(&dev->vb_vidq);
-}
 
-static int vivi_is_generating(struct vivi_dev *dev)
-{
-	return test_bit(0, &dev->generating);
+	/*
+	 * Typical driver might need to wait here until dma engine stops.
+	 * In this case we can abort imiedetly, so it's just a noop.
+	 */
+
+	/* Release all active buffers */
+	while (!list_empty(&dma_q->active)) {
+		struct vivi_buffer *buf;
+		buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
+		list_del(&buf->list);
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+		dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
+	}
 }
-
 /* ------------------------------------------------------------------
 	Videobuf operations
    ------------------------------------------------------------------*/
-static int
-buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+static int queue_negotiate(struct vb2_queue *vq, unsigned int *num_buffers,
+				unsigned int *num_planes)
 {
-	struct vivi_dev *dev = vq->priv_data;
+	struct vivi_dev *dev = vb2_get_drv_priv(vq);
+	unsigned long size;
 
-	*size = dev->width * dev->height * 2;
+	size = dev->width * dev->height * 2;
 
-	if (0 == *count)
-		*count = 32;
+	if (0 == *num_buffers)
+		*num_buffers = 32;
 
-	while (*size * *count > vid_limit * 1024 * 1024)
-		(*count)--;
+	while (size * *num_buffers > vid_limit * 1024 * 1024)
+		(*num_buffers)--;
 
-	dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__,
-		*count, *size);
+	*num_planes = 1;
+
+	dprintk(dev, 1, "%s, count=%d, size=%ld\n", __func__,
+		*num_buffers, size);
 
 	return 0;
 }
 
-static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
+static int plane_setup(struct vb2_queue *vq, unsigned int plane_no,
+			unsigned long *plane_size)
 {
-	struct vivi_dev *dev = vq->priv_data;
+	struct vivi_dev *dev = vb2_get_drv_priv(vq);
+
+	if (plane_no > 0)
+		return -EINVAL;
 
-	dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state);
+	*plane_size = dev->width * dev->height * 2;
 
-	videobuf_vmalloc_free(&buf->vb);
-	dprintk(dev, 1, "free_buffer: freed\n");
-	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+	dprintk(dev, 1, "%s: plane: %d, size: %ld\n",
+			__func__, plane_no, *plane_size);
+
+	return 0;
 }
 
-static int
-buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
-						enum v4l2_field field)
+static int buffer_init(struct vb2_buffer *vb)
 {
-	struct vivi_dev *dev = vq->priv_data;
+	struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+
+	BUG_ON(NULL == dev->fmt);
+
+	/*
+	 * 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.
+	 */
+
+	return 0;
+}
+
+static int buffer_prepare(struct vb2_buffer *vb)
+{
+	struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
 	struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
-	int rc;
+	unsigned long size;
 
-	dprintk(dev, 1, "%s, field=%d\n", __func__, field);
+	dprintk(dev, 1, "%s, field=%d\n", __func__, vb->v4l2_buf.field);
 
 	BUG_ON(NULL == dev->fmt);
 
+	/*
+	 * Theses properties only change when queue is idle, see s_fmt.
+	 * The below checks should not be performed here, on each
+	 * buffer_prepare (i.e. on each qbuf). Most of the code in this function
+	 * should thus be moved to buffer_init and s_fmt.
+	 */
 	if (dev->width  < 48 || dev->width  > MAX_WIDTH ||
 	    dev->height < 32 || dev->height > MAX_HEIGHT)
 		return -EINVAL;
 
-	buf->vb.size = dev->width * dev->height * 2;
-	if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+	size = dev->width * dev->height * 2;
+	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);
 
-	/* These properties only change when queue is idle, see s_fmt */
-	buf->fmt       = dev->fmt;
-	buf->vb.width  = dev->width;
-	buf->vb.height = dev->height;
-	buf->vb.field  = field;
+	buf->fmt = dev->fmt;
 
 	precalculate_bars(dev);
 	precalculate_line(dev);
 
-	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-		rc = videobuf_iolock(vq, &buf->vb, NULL);
-		if (rc < 0)
-			goto fail;
-	}
-
-	buf->vb.state = VIDEOBUF_PREPARED;
 	return 0;
-
-fail:
-	free_buffer(vq, buf);
-	return rc;
 }
 
-static void
-buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+static void buffer_queue(struct vb2_buffer *vb)
 {
-	struct vivi_dev *dev = vq->priv_data;
+	struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
 	struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
 	struct vivi_dmaqueue *vidq = &dev->vidq;
+	unsigned long flags = 0;
 
 	dprintk(dev, 1, "%s\n", __func__);
 
-	buf->vb.state = VIDEOBUF_QUEUED;
-	list_add_tail(&buf->vb.queue, &vidq->active);
+	spin_lock_irqsave(&dev->slock, flags);
+	list_add_tail(&buf->list, &vidq->active);
+	spin_unlock_irqrestore(&dev->slock, flags);
 }
 
-static void buffer_release(struct videobuf_queue *vq,
-			   struct videobuf_buffer *vb)
+static int start_streaming(struct vb2_queue *vq)
 {
-	struct vivi_dev *dev = vq->priv_data;
-	struct vivi_buffer *buf  = container_of(vb, struct vivi_buffer, vb);
-
+	struct vivi_dev *dev = vb2_get_drv_priv(vq);
 	dprintk(dev, 1, "%s\n", __func__);
+	return vivi_start_generating(dev);
+}
 
-	free_buffer(vq, buf);
+/* abort streaming and wait for last buffer */
+static int stop_streaming(struct vb2_queue *vq)
+{
+	struct vivi_dev *dev = vb2_get_drv_priv(vq);
+	dprintk(dev, 1, "%s\n", __func__);
+	vivi_stop_generating(dev);
+	return 0;
 }
 
-static struct videobuf_queue_ops vivi_video_qops = {
-	.buf_setup      = buffer_setup,
-	.buf_prepare    = buffer_prepare,
-	.buf_queue      = buffer_queue,
-	.buf_release    = buffer_release,
+static struct vb2_ops vivi_video_qops = {
+	.queue_negotiate	= queue_negotiate,
+	.plane_setup		= plane_setup,
+	.buf_init		= buffer_init,
+	.buf_prepare		= buffer_prepare,
+	.buf_queue		= buffer_queue,
+	.start_streaming	= start_streaming,
+	.stop_streaming		= stop_streaming,
+};
+
+static struct vb2_read_ctx vivi_read_ctx = {
+	.num_bufs		= 2,
 };
 
 /* ------------------------------------------------------------------
@@ -774,7 +804,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 
 	f->fmt.pix.width        = dev->width;
 	f->fmt.pix.height       = dev->height;
-	f->fmt.pix.field        = dev->vb_vidq.field;
+	f->fmt.pix.field        = dev->field;
 	f->fmt.pix.pixelformat  = dev->fmt->fourcc;
 	f->fmt.pix.bytesperline =
 		(f->fmt.pix.width * dev->fmt->depth) >> 3;
@@ -820,15 +850,15 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 					struct v4l2_format *f)
 {
 	struct vivi_dev *dev = video_drvdata(file);
-	struct videobuf_queue *q = &dev->vb_vidq;
+	struct vb2_queue *q = &dev->vb_vidq;
 
 	int ret = vidioc_try_fmt_vid_cap(file, priv, f);
 	if (ret < 0)
 		return ret;
 
-	mutex_lock(&q->vb_lock);
+	vb2_lock(q);
 
-	if (vivi_is_generating(dev)) {
+	if (vb2_is_streaming(q)) {
 		dprintk(dev, 1, "%s device busy\n", __func__);
 		ret = -EBUSY;
 		goto out;
@@ -837,10 +867,10 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 	dev->fmt = get_format(f);
 	dev->width = f->fmt.pix.width;
 	dev->height = f->fmt.pix.height;
-	dev->vb_vidq.field = f->fmt.pix.field;
+	dev->field = f->fmt.pix.field;
 	ret = 0;
 out:
-	mutex_unlock(&q->vb_lock);
+	vb2_unlock(q);
 	return ret;
 }
 
@@ -849,66 +879,42 @@ static int vidioc_reqbufs(struct file *file, void *priv,
 {
 	struct vivi_dev *dev = video_drvdata(file);
 
-	return videobuf_reqbufs(&dev->vb_vidq, p);
+	return vb2_reqbufs(&dev->vb_vidq, p);
 }
 
 static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
 	struct vivi_dev *dev = video_drvdata(file);
 
-	return videobuf_querybuf(&dev->vb_vidq, p);
+	return vb2_querybuf(&dev->vb_vidq, p);
 }
 
 static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
 	struct vivi_dev *dev = video_drvdata(file);
 
-	return videobuf_qbuf(&dev->vb_vidq, p);
+	return vb2_qbuf(&dev->vb_vidq, p);
 }
 
 static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
 	struct vivi_dev *dev = video_drvdata(file);
 
-	return videobuf_dqbuf(&dev->vb_vidq, p,
-				file->f_flags & O_NONBLOCK);
+	return vb2_dqbuf(&dev->vb_vidq, p, file->f_flags & O_NONBLOCK);
 }
 
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
-{
-	struct vivi_dev *dev = video_drvdata(file);
-
-	return videobuf_cgmbuf(&dev->vb_vidq, mbuf, 8);
-}
-#endif
-
 static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 {
 	struct vivi_dev *dev = video_drvdata(file);
-	int ret;
-
-	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-	ret = videobuf_streamon(&dev->vb_vidq);
-	if (ret)
-		return ret;
 
-	vivi_start_generating(file);
-	return 0;
+	return vb2_streamon(&dev->vb_vidq, i);
 }
 
 static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
 {
 	struct vivi_dev *dev = video_drvdata(file);
-	int ret;
 
-	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-	ret = videobuf_streamoff(&dev->vb_vidq);
-	if (!ret)
-		vivi_stop_generating(file);
-	return ret;
+	return vb2_streamoff(&dev->vb_vidq, i);
 }
 
 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
@@ -1031,26 +1037,25 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 	File operations for the device
    ------------------------------------------------------------------*/
 
-static ssize_t
-vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+static int vivi_open(struct file *file)
 {
 	struct vivi_dev *dev = video_drvdata(file);
 
-	vivi_start_generating(file);
-	return videobuf_read_stream(&dev->vb_vidq, data, count, ppos, 0,
-					file->f_flags & O_NONBLOCK);
+	dprintk(dev, 1, "%s, %p\n", __func__, file);
+
+	atomic_inc(&dev->open_count);
+	return 0;
 }
 
 static unsigned int
 vivi_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct vivi_dev *dev = video_drvdata(file);
-	struct videobuf_queue *q = &dev->vb_vidq;
+	struct vb2_queue *q = &dev->vb_vidq;
 
 	dprintk(dev, 1, "%s\n", __func__);
 
-	vivi_start_generating(file);
-	return videobuf_poll_stream(file, q, wait);
+	return vb2_poll(q, file, wait);
 }
 
 static int vivi_close(struct file *file)
@@ -1058,10 +1063,11 @@ static int vivi_close(struct file *file)
 	struct video_device  *vdev = video_devdata(file);
 	struct vivi_dev *dev = video_drvdata(file);
 
-	vivi_stop_generating(file);
+	dprintk(dev, 1, "close called (dev=%s), file %p\n",
+		video_device_node_name(vdev), file);
 
-	dprintk(dev, 1, "close called (dev=%s)\n",
-		video_device_node_name(vdev));
+	if (atomic_dec_and_test(&dev->open_count))
+		vb2_queue_release(&dev->vb_vidq);
 	return 0;
 }
 
@@ -1072,7 +1078,7 @@ static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
 
 	dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
 
-	ret = videobuf_mmap_mapper(&dev->vb_vidq, vma);
+	ret = vb2_mmap(&dev->vb_vidq, vma);
 
 	dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n",
 		(unsigned long)vma->vm_start,
@@ -1081,13 +1087,25 @@ static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
 	return ret;
 }
 
+static ssize_t vivi_read(struct file *file, char __user *buf, size_t count,
+			    loff_t *ppos)
+{
+	struct vivi_dev *dev = video_drvdata(file);
+
+	dprintk(dev, 1, "read called\n");
+
+	return vb2_read(&dev->vb_vidq, buf, count, ppos,
+					file->f_flags & O_NONBLOCK);
+}
+
 static const struct v4l2_file_operations vivi_fops = {
 	.owner		= THIS_MODULE,
+	.open		= vivi_open,
 	.release        = vivi_close,
-	.read           = vivi_read,
 	.poll		= vivi_poll,
 	.ioctl          = video_ioctl2, /* V4L2 ioctl handler */
 	.mmap           = vivi_mmap,
+	.read           = vivi_read,
 };
 
 static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
@@ -1109,9 +1127,6 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
 	.vidioc_queryctrl     = vidioc_queryctrl,
 	.vidioc_g_ctrl        = vidioc_g_ctrl,
 	.vidioc_s_ctrl        = vidioc_s_ctrl,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf          = vidiocgmbuf,
-#endif
 };
 
 static struct video_device vivi_template = {
@@ -1145,6 +1160,8 @@ static int vivi_release(void)
 		kfree(dev);
 	}
 
+	vb2_vmalloc_cleanup(alloc_ctx);
+
 	return 0;
 }
 
@@ -1173,10 +1190,8 @@ static int __init vivi_create_instance(int inst)
 	dev->saturation = 127;
 	dev->hue = 0;
 
-	videobuf_queue_vmalloc_init(&dev->vb_vidq, &vivi_video_qops,
-			NULL, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
-			V4L2_FIELD_INTERLACED,
-			sizeof(struct vivi_buffer), dev);
+	vb2_queue_init(&dev->vb_vidq, &vivi_video_qops, alloc_ctx,
+		       &vivi_read_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE, dev);
 
 	/* init video dma queues */
 	INIT_LIST_HEAD(&dev->vidq.active);
@@ -1238,6 +1253,13 @@ static int __init vivi_init(void)
 	}
 	font8x16 = font->data;
 
+	/* Initialize vmalloc allocator */
+	alloc_ctx = vb2_vmalloc_init();
+	if (IS_ERR(alloc_ctx)) {
+		printk(KERN_ERR "vivi: allocator init failed\n");
+		return PTR_ERR(alloc_ctx);
+	}
+
 	if (n_devs <= 0)
 		n_devs = 1;
 
-- 
1.7.1.569.g6f426


^ permalink raw reply related

* [PATCH/RFC v3 0/7] Videobuf2 framework
From: Marek Szyprowski @ 2010-10-20  6:41 UTC (permalink / raw)
  To: linux-media; +Cc: m.szyprowski, pawel, kyungmin.park

Hello,

As I promissed I continue the development of the VideoBuf2 at Samsung
until Pawel finds some spare time to help us. This is a third version of
the framework. Besides the minor bugfixes here and there I've added a
complete read() callback emulator. This emulator provides 2 types of
read() operation - 'streaming' and 'one shot'. It is suitable to replace
both videobuf_read_stream() and videobuf_read_one() methods from the old
videobuf.

Taking into account the size of the patches and the number of lines I've
changed, I've decided to keep the Pawel signed-off attribute and
authorship to correctly credit him. If this is against kernel rules,
feel free to let me know.

Best regards
--
Marek Szyprowski
Samsung Poland R&D Center


Changes since V2:
=================
- added read() emulator (see patch #5/7)
- fixed lack of parentheses in macro definitions (caused side effects
  in some places)
- added a separate check for VM_READ or VM_WRITE in vb2_mmap()
- added vb2_is_streaming(), vb2_lock and vb2_unlock inlines
- updated vivi driver with the new read() emulator 

Changes since V1:
=================
- removed drv_lock, added start_streaming and stop_streaming callbacks


Here is the original Videobuf2 introduction prepared by Pawel:
=======================================================================

These patches add a new driver framework for Video for Linux 2 driver
- Videobuf2.

Videobuf2 is intended as a replacement for videobuf, the current driver
framework, which will be referred to as "videobuf1" for the remainder
of this document.

================================
What is videobuf2?
================================
Videobuf2 is a Video for Linux 2 API-compatible driver framework for
multimedia devices. It acts as an intermediate layer between userspace
applications and device drivers. It also provides low-level, modular
memory management functions for drivers.

Videobuf2 eases driver development, reduces drivers' code size and aids in
proper and consistent implementation of V4L2 API in drivers.

Videobuf2 memory management backend is fully modular. This allows custom
memory management routines for devices and platforms with non-standard
memory management requirements to be plugged in, without changing the
high-level buffer management functions and API.

The framework provides:
- implementations of streaming I/O V4L2 ioctls and file operations
- high-level video buffer, video queue and state management functions
- video buffer memory allocation and management

================================
Why a new framework?
================================
There have been many discussions in the V4L2 community about the feasibility
of writing a new framework, as opposed to fixing the existing one. It has been
agreed though that:
- videobuf1 has major flaws and an attempt to fix it would end up in rewriting
most of the code
- many drivers depend on videobuf1 and since the changes would be major,
an effort to adapt and test them all would not be realistically possible

Due to the problems with videobuf most new drivers cannot use it. This leads
to code replication and overcomplicated drivers.

================================
What is wrong with videobuf1?
================================
There are many problems with the current videobuf implementation. During a V4L2
mini-summit in Helsinki in June 2010, two presentations were delivered
on this topic:
- Laurent Pinchart "videobuf - the good, the bad and the ugly"
http://linuxtv.org/downloads/presentations/summit_jun_2010/20100614-v4l2_summit-videobuf.pdf
- Pawel Osciak "Future of the videobuf framework"
http://linuxtv.org/downloads/presentations/summit_jun_2010/Videobuf_Helsinki_June2010.pdf

These presentations highlighted many problems with videobuf. The most prominent
include:

- V4L2 API violations and wrong memory management design
  - it is impossible to pause streaming (buffers are freed on streamoff)
  - VIDIOC_REQBUFS(0) does not free memory
  - it is impossible to reallocate memory with VIDIOC_REQBUFS
  - video memory is allocated on mmap, qbuf or even on page fault,
    freed on unmap, streamoff or explicitly by drivers
  - per-buffer waitqueues
- not extensible enough and thus not ready for new platforms and uses,
  especially considering embedded multimedia devices
  - very hard to add new memory handling routines and custom memory allocators
  - no or poor support for handling cache coherency, IOMMUs, 
  - poor flexibility - only one do-it-all function for handling memory pinning,
    cache, sg-list creation, etc...
- unused fields, code duplication, vague/inconsistent naming, obscure usage in
  some places...

Many driver authors expressed their frustration with videobuf. Developers
acknowledge its merits and would like to use it, but due mostly to its
inflexible memory allocation schemes they are unable to do so.

================================
Main goals of the redesign
================================
- correct V4L2 API implementation, fixing videobuf1 problems and shortcomings
- full separation between queue management and memory management
- fully flexible, pluggable memory allocators and memory handling routines
- more specialized driver callbacks, called at different points
- support for new V4L2 API extensions, such as multi-planar video buffers

================================
Driver callbacks
================================
Driver callbacks have been redesigned for symmetry:
- buf_init - called once, after memory is allocated or after a new USERPTR
  buffer is queued; can be used e.g. to pin pages, verify contiguity, set up
  IOMMU mappings, etc.
- buf_prepare - called on each QBUF; can be used e.g. for cache sync, copying
  to bounce buffers, etc.
- buf_finish - called on each DQBUF; can be used e.g. for cache sync, copying
  back from bounce buffers, etc.
- buf_cleanup - called before freeing/releasing memory; can be used e.g. for
  unmapping memory, etc.

The remaining driver callbacks have been slightly redesigned:
- queue_negotiate - now incorporates multi-planar extensions; drivers return
  required number of buffers and planes per buffer
- plane_setup - drivers return plane sizes
Those two callbacks replace the old buf_setup.

- buf_queue - basically stays the same

================================
Memory allocators and handling
================================
Memory handling has been designed to allow more customization than in the
original videobuf. For this memory allocation ops have been slightly redesigned,
and have become fully replaceable and an allocator context struct have been
introduced.

Allocator context is intended to provide memory operations to videobuf and also
for storing allocator private data, if required, although simpler allocators
do not have to use this feature. Private data can be added by embedding the
context struct inside their own structures:

struct vb2_alloc_ctx {
        const struct vb2_mem_ops        *mem_ops;
};

struct vb2_foo_alloc_conf {
        struct vb2_alloc_ctx    alloc_ctx;                          
	/* Allocator private data here */
};

Moreover, a buffer context structure concept has been introduced. Allocators
return their own, custom, per-buffer structures on every allocation. This
structure is then used as a "cookie" and passed to other memory handling
methods called for its corresponding buffer.

Memory operations, stored in the allocator context, can be replaced if
needed by drivers on a per-function basis and functions from other allocators
or drivers can be reused as well. A full list with documentation can be found
in the videobuf2-core.h file.

It is also possible, although not required, to assign different contexts per
plane. This may be useful for drivers that need to use different memory types
for different planes. An example may be a driver that stores video data in the
first plane, which has to be allocated from a device-accessible memory area,
and metadata in the second plane, which does not have to be stored in
a device-accessible memory.

An good example of integrating a more advanced allocator, the recently discussed
on this list CMA (contiguous memory allocator), can be found in videobuf2-cma.*.

================================
Other changes
================================
The changes described above are the main changes in videobuf2. Most of the core
API has remained the same or very similar, although its implementation has been
fully rewritten. Some more visible changes include:

- Memory is now properly allocated on REQBUFS and can be freed and reallocated
  there as well.
- It is now possible to pause and resume streaming with streamon/streamoff,
  without freeing the buffers.
- V4L2 API-related, userspace-visible metadata, such as inputs, timestamps, etc.
  are no longer stored in videobuf buffer structure, but in an actual
  v4l2_buffer struct (idea borrowed from Laurent Pinchart). I felt that driver
  authors would prefer to use V4L2 API-based structures of videobuf custom
  structures where possible. It also eases copying v4l2_buffer-related data
  from/to userspace.
- Buffers do not include waitqueues anymore. One, global, per-queue waitqueue
  for done buffers has been introduced instead. Per-buffer waitqueues were not
  very useful and introduced additional complications in code.
  With this, drivers have gained the ability of dequeuing buffers out-of-order
  as well.
- Buffer states are not handled jointly by both videobuf and driver anymore,
  I felt it was not required and confusing for driver authors
- Some fields that were less useful have been removed and naming of others
  have been changed to better reflect their function.
- Other then reqbufs, ioctl implementations have remained almost the same
  and behave in the same way, 
  

Please see documentation in videobuf2-core.c and videobuf2-core.h for more
details and the patch porting vivi to videobuf2 for how to port existing
drivers to videobuf2.

This is a preliminary version intended for review, but has already been tested
for multiple drivers and different memory handling implementations. DMA-SG
implementation is not included yet.

The CMA allocator patches are attached for reference, to show how a more
complicated allocator can be integrated into the framework.

Any comments will be very much appreciated!

Best regards,
Pawel Osciak
Linux Platform Group
Samsung Poland R&D Center 

=======================================================================

Patch summary:

Pawel Osciak (6):
  v4l: add videobuf2 Video for Linux 2 driver framework
  v4l: videobuf2: add generic memory handling routines
  v4l: videobuf2: add vmalloc allocator
  v4l: videobuf2: add DMA coherent allocator
  v4l: vivi: port to videobuf2
  v4l: videobuf2: add CMA allocator

Marek Szyprowski (1):
  v4l: videobuf2: add read() emulator

 drivers/media/video/Kconfig                  |   23 +-
 drivers/media/video/Makefile                 |    6 +
 drivers/media/video/videobuf2-cma.c          |  250 ++++
 drivers/media/video/videobuf2-core.c         | 1726 ++++++++++++++++++++++++++
 drivers/media/video/videobuf2-dma-coherent.c |  208 ++++
 drivers/media/video/videobuf2-memops.c       |  199 +++
 drivers/media/video/videobuf2-vmalloc.c      |  177 +++
 drivers/media/video/vivi.c                   |  348 +++---
 include/media/videobuf2-cma.h                |   25 +
 include/media/videobuf2-core.h               |  392 ++++++
 include/media/videobuf2-dma-coherent.h       |   21 +
 include/media/videobuf2-memops.h             |   31 +
 include/media/videobuf2-vmalloc.h            |   16 +
 13 files changed, 3258 insertions(+), 164 deletions(-)
 create mode 100644 drivers/media/video/videobuf2-cma.c
 create mode 100644 drivers/media/video/videobuf2-core.c
 create mode 100644 drivers/media/video/videobuf2-dma-coherent.c
 create mode 100644 drivers/media/video/videobuf2-memops.c
 create mode 100644 drivers/media/video/videobuf2-vmalloc.c
 create mode 100644 include/media/videobuf2-cma.h
 create mode 100644 include/media/videobuf2-core.h
 create mode 100644 include/media/videobuf2-dma-coherent.h
 create mode 100644 include/media/videobuf2-memops.h
 create mode 100644 include/media/videobuf2-vmalloc.h

-- 
1.7.1.569.g6f426


^ permalink raw reply

* [PATCH 2/7] v4l: videobuf2: add generic memory handling routines
From: Marek Szyprowski @ 2010-10-20  6:41 UTC (permalink / raw)
  To: linux-media; +Cc: m.szyprowski, pawel, kyungmin.park
In-Reply-To: <1287556873-23179-1-git-send-email-m.szyprowski@samsung.com>

From: Pawel Osciak <p.osciak@samsung.com>

Add generic memory handling routines for userspace pointer handling,
contiguous memory verification and mapping.

Signed-off-by: Pawel Osciak <p.osciak@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
CC: Pawel Osciak <pawel@osciak.com>
---
 drivers/media/video/Kconfig            |    3 +
 drivers/media/video/Makefile           |    1 +
 drivers/media/video/videobuf2-memops.c |  199 ++++++++++++++++++++++++++++++++
 include/media/videobuf2-memops.h       |   31 +++++
 4 files changed, 234 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/videobuf2-memops.c
 create mode 100644 include/media/videobuf2-memops.h

diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 9bf2fe1..2acb0f8 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -52,6 +52,9 @@ config V4L2_MEM2MEM_DEV
 config VIDEOBUF2_CORE
 	tristate
 
+config VIDEOBUF2_MEMOPS
+	tristate
+
 #
 # Multimedia Video device configuration
 #
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index e66f53b..77cc798 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -118,6 +118,7 @@ obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
 obj-$(CONFIG_VIDEO_BTCX)  += btcx-risc.o
 
 obj-$(CONFIG_VIDEOBUF2_CORE)		+= videobuf2-core.o
+obj-$(CONFIG_VIDEOBUF2_MEMOPS)		+= videobuf2-memops.o
 
 obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o
 
diff --git a/drivers/media/video/videobuf2-memops.c b/drivers/media/video/videobuf2-memops.c
new file mode 100644
index 0000000..67ebdff
--- /dev/null
+++ b/drivers/media/video/videobuf2-memops.c
@@ -0,0 +1,199 @@
+/*
+ * videobuf2-memops.c - generic memory handling routines for videobuf2
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <p.osciak@samsung.com>
+ *	   Marek Szyprowski <m.szyprowski@samsung.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/slab.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <linux/cma.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/file.h>
+
+#include <media/videobuf2-core.h>
+
+/**
+ * vb2_contig_verify_userptr() - verify contiguity of a userspace-mapped memory
+ * @vma:	virtual memory region which maps the physical memory
+ *		to be verified
+ * @vaddr:	starting virtual address of the area to be verified
+ * @size:	size of the area to be verified
+ * @paddr:	will return physical address for the given vaddr
+ *
+ * This function will go through memory area of size size mapped at vaddr and
+ * verify that the underlying physical pages are contiguous.
+ *
+ * Returns 0 on success and a physical address to the memory pointed
+ * to by vaddr in paddr.
+ */
+int vb2_contig_verify_userptr(struct vm_area_struct *vma,
+				unsigned long vaddr, unsigned long size,
+				unsigned long *paddr)
+{
+	struct mm_struct *mm = current->mm;
+	unsigned long offset;
+	unsigned long vma_size;
+	unsigned long curr_pfn, prev_pfn;
+	unsigned long num_pages;
+	int ret = -EINVAL;
+	unsigned int i;
+
+	offset = vaddr & ~PAGE_MASK;
+
+	down_read(&mm->mmap_sem);
+
+	vma = find_vma(mm, vaddr);
+	if (!vma) {
+		printk(KERN_ERR "Invalid userspace address\n");
+		goto done;
+	}
+
+	vma_size = vma->vm_end - vma->vm_start;
+
+	if (size > vma_size - offset) {
+		printk(KERN_ERR "Region too small\n");
+		goto done;
+	}
+	num_pages = (size + offset) >> PAGE_SHIFT;
+
+	ret = follow_pfn(vma, vaddr, &curr_pfn);
+	if (ret) {
+		printk(KERN_ERR "Invalid userspace address\n");
+		goto done;
+	}
+
+	*paddr = (curr_pfn << PAGE_SHIFT) + offset;
+
+	for (i = 1; i < num_pages; ++i) {
+		prev_pfn = curr_pfn;
+		vaddr += PAGE_SIZE;
+
+		ret = follow_pfn(vma, vaddr, &curr_pfn);
+		if (ret || curr_pfn != prev_pfn + 1) {
+			printk(KERN_ERR "Invalid userspace address\n");
+			ret = -EINVAL;
+			break;
+		}
+	}
+
+done:
+	up_read(&mm->mmap_sem);
+	return ret;
+}
+
+/**
+ * vb2_mmap_pfn_range() - map physical pages to userspace
+ * @vma:	virtual memory region for the mapping
+ * @paddr:	starting physical address of the memory to be mapped
+ * @size:	size of the memory to be mapped
+ * @vm_ops:	vm operations to be assigned to the created area
+ * @priv:	private data to be associated with the area
+ *
+ * Returns 0 on success.
+ */
+int vb2_mmap_pfn_range(struct vm_area_struct *vma, unsigned long paddr,
+				unsigned long size,
+				const struct vm_operations_struct *vm_ops,
+				void *priv)
+{
+	int ret;
+
+	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) {
+		printk(KERN_ERR "Remapping memory failed, error: %d\n", ret);
+		return ret;
+	}
+
+	vma->vm_flags		|= VM_DONTEXPAND | VM_RESERVED;
+	vma->vm_private_data	= priv;
+	vma->vm_ops		= vm_ops;
+
+	vm_ops->open(vma);
+
+	printk(KERN_DEBUG "%s: mapped paddr 0x%08lx at 0x%08lx, size %ld\n",
+			__func__, paddr, vma->vm_start, size);
+
+	return 0;
+}
+
+/**
+ * vb2_get_userptr() - acquire an area pointed to by userspace addres vaddr
+ * @vaddr:	virtual userspace address to the given area
+ *
+ * This function attempts to acquire an area mapped in the userspace for
+ * the duration of a hardware operation.
+ *
+ * Returns a virtual memory region associated with the given vaddr on success
+ * or NULL.
+ */
+struct vm_area_struct *vb2_get_userptr(unsigned long vaddr)
+{
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *vma;
+	struct vm_area_struct *vma_copy;
+
+	vma_copy = kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
+	if (vma_copy == NULL)
+		return NULL;
+
+	down_read(&mm->mmap_sem);
+
+	vma = find_vma(mm, vaddr);
+	if (!vma)
+		goto done;
+
+	if (vma->vm_ops && vma->vm_ops->open)
+		vma->vm_ops->open(vma);
+
+	if (vma->vm_file)
+		get_file(vma->vm_file);
+
+	memcpy(vma_copy, vma, sizeof(*vma));
+done:
+	up_read(&mm->mmap_sem);
+
+	vma_copy->vm_mm = NULL;
+	vma_copy->vm_next = NULL;
+	vma_copy->vm_prev = NULL;
+
+	return vma_copy;
+}
+
+/**
+ * vb2_put_userptr() - release a userspace memory area
+ * @vma:	virtual memory region associated with the area to be released
+ *
+ * This function releases the previously acquired memory area after a hardware
+ * operation.
+ */
+void vb2_put_userptr(struct vm_area_struct *vma)
+{
+	if (!vma)
+		return;
+
+	if (vma->vm_file)
+		fput(vma->vm_file);
+
+	if (vma->vm_ops && vma->vm_ops->close)
+		vma->vm_ops->close(vma);
+
+	kfree(vma);
+}
+
+MODULE_DESCRIPTION("common memory handling routines for videobuf2");
+MODULE_AUTHOR("Pawel Osciak");
+MODULE_LICENSE("GPL");
diff --git a/include/media/videobuf2-memops.h b/include/media/videobuf2-memops.h
new file mode 100644
index 0000000..3257411
--- /dev/null
+++ b/include/media/videobuf2-memops.h
@@ -0,0 +1,31 @@
+/*
+ * videobuf2-memops.h - generic memory handling routines for videobuf2
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <p.osciak@samsung.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_MEMOPS_H
+#define _MEDIA_VIDEOBUF2_MEMOPS_H
+
+#include <media/videobuf2-core.h>
+
+int vb2_contig_verify_userptr(struct vm_area_struct *vma,
+				unsigned long vaddr, unsigned long size,
+				unsigned long *paddr);
+
+int vb2_mmap_pfn_range(struct vm_area_struct *vma, unsigned long paddr,
+				unsigned long size,
+				const struct vm_operations_struct *vm_ops,
+				void *priv);
+
+struct vm_area_struct *vb2_get_userptr(unsigned long vaddr);
+
+void vb2_put_userptr(struct vm_area_struct *vma);
+
+#endif
-- 
1.7.1.569.g6f426


^ permalink raw reply related

* [PATCH 5/7] v4l: videobuf2: add read() emulator
From: Marek Szyprowski @ 2010-10-20  6:41 UTC (permalink / raw)
  To: linux-media; +Cc: m.szyprowski, pawel, kyungmin.park
In-Reply-To: <1287556873-23179-1-git-send-email-m.szyprowski@samsung.com>

Add a generic read() emulator for videobuf2. It uses MMAP memory type
buffers and generic vb2 calls: req_bufs, qbuf and dqbuf. Video date is
being copied from mmap buffers to userspace with standard copy_to_user()
function. To add read() support to the driver, only one additional
structure should be provides which defines the default number of buffers
used by emulator and detemines the style of read() emulation
('streaming' or 'one shot').

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
CC: Pawel Osciak <pawel@osciak.com>
---
 drivers/media/video/videobuf2-core.c |  322 ++++++++++++++++++++++++++++++++--
 include/media/videobuf2-core.h       |   21 +++
 2 files changed, 325 insertions(+), 18 deletions(-)

diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c
index 4a29c49..ab00246 100644
--- a/drivers/media/video/videobuf2-core.c
+++ b/drivers/media/video/videobuf2-core.c
@@ -471,7 +471,7 @@ static bool __buffers_in_use(struct vb2_queue *q)
  * The return values from this function are intended to be directly returned
  * from vidioc_reqbufs handler in driver.
  */
-int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
+static int __vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
 {
 	unsigned int num_buffers, num_planes;
 	int ret = 0;
@@ -482,8 +482,6 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
 		return -EINVAL;
 	}
 
-	mutex_lock(&q->vb_lock);
-
 	if (req->type != q->type) {
 		dprintk(1, "reqbufs: queue type invalid\n");
 		ret = -EINVAL;
@@ -567,6 +565,15 @@ end:
 	mutex_unlock(&q->vb_lock);
 	return ret;
 }
+
+int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
+{
+	int ret = 0;
+	mutex_lock(&q->vb_lock);
+	ret = (q->read_data) ? -EBUSY : __vb2_reqbufs(q, req);
+	mutex_unlock(&q->vb_lock);
+	return ret;
+}
 EXPORT_SYMBOL_GPL(vb2_reqbufs);
 
 /**
@@ -821,14 +828,11 @@ static void __enqueue_in_driver(struct vb2_buffer *vb)
  * The return values from this function are intended to be directly returned
  * from vidioc_qbuf handler in driver.
  */
-int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
+static int __vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
 {
 	struct vb2_buffer *vb;
-	int ret;
-
-	mutex_lock(&q->vb_lock);
+	int ret = -EINVAL;
 
-	ret = -EINVAL;
 	if (b->type != q->type) {
 		dprintk(1, "qbuf: invalid buffer type\n");
 		goto done;
@@ -887,6 +891,14 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
 	dprintk(1, "qbuf of buffer %d succeeded\n", vb->v4l2_buf.index);
 	ret = 0;
 done:
+	return ret;
+}
+
+int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
+{
+	int ret = 0;
+	mutex_lock(&q->vb_lock);
+	ret = (q->read_data) ? -EBUSY : __vb2_qbuf(q, b);
 	mutex_unlock(&q->vb_lock);
 	return ret;
 }
@@ -996,13 +1008,11 @@ end:
  * The return values from this function are intended to be directly returned
  * from vidioc_dqbuf handler in driver.
  */
-int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
+static int __vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
 {
 	struct vb2_buffer *vb = NULL;
 	int ret;
 
-	mutex_lock(&q->vb_lock);
-
 	if (b->type != q->type) {
 		dprintk(1, "dqbuf: invalid buffer type\n");
 		ret = -EINVAL;
@@ -1047,6 +1057,14 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
 	vb->state = VB2_BUF_STATE_DEQUEUED;
 
 done:
+	return ret;
+}
+
+int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
+{
+	int ret;
+	mutex_lock(&q->vb_lock);
+	ret = (q->read_data) ? -EBUSY : __vb2_dqbuf(q, b, nonblocking);
 	mutex_unlock(&q->vb_lock);
 	return ret;
 }
@@ -1065,13 +1083,11 @@ EXPORT_SYMBOL_GPL(vb2_dqbuf);
  * The return values from this function are intended to be directly returned
  * from vidioc_streamon handler in the driver.
  */
-int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
+static int __vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
 {
 	struct vb2_buffer *vb;
 	int ret = 0;
 
-	mutex_lock(&q->vb_lock);
-
 	if (type != q->type) {
 		dprintk(1, "streamon: invalid stream type\n");
 		ret = -EINVAL;
@@ -1113,6 +1129,14 @@ int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
 
 	dprintk(3, "Streamon successful\n");
 done:
+	return ret;
+}
+
+int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
+{
+	int ret;
+	mutex_lock(&q->vb_lock);
+	ret = (q->read_data) ? -EBUSY : __vb2_streamon(q, type);
 	mutex_unlock(&q->vb_lock);
 	return ret;
 }
@@ -1161,12 +1185,10 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
  * The return values from this function are intended to be directly returned
  * from vidioc_streamoff handler in the driver
  */
-int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
+static int __vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
 {
 	int ret = 0;
 
-	mutex_lock(&q->vb_lock);
-
 	if (type != q->type) {
 		dprintk(1, "streamoff: invalid stream type\n");
 		ret = -EINVAL;
@@ -1187,6 +1209,14 @@ int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
 
 	dprintk(3, "Streamoff successful\n");
 end:
+	return ret;
+}
+
+int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
+{
+	int ret;
+	mutex_lock(&q->vb_lock);
+	ret = (q->read_data) ? -EBUSY : __vb2_streamoff(q, type);
 	mutex_unlock(&q->vb_lock);
 	return ret;
 }
@@ -1311,6 +1341,9 @@ bool vb2_has_consumers(struct vb2_queue *q)
 }
 EXPORT_SYMBOL_GPL(vb2_has_consumers);
 
+static int __vb2_init_read(struct vb2_queue *q);
+static int __vb2_cleanup_read(struct vb2_queue *q);
+
 /**
  * vb2_poll() - implements poll userspace operation
  * @q:		videobuf2 queue
@@ -1336,6 +1369,15 @@ unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait)
 	mutex_lock(&q->vb_lock);
 
 	/*
+	 * Start read() emulator if streaming api has not been used yet.
+	 */
+	if (q->num_buffers == 0 && q->read_data == NULL && q->read_ctx) {
+		ret = __vb2_init_read(q);
+		if (ret)
+			goto end;
+	}
+
+	/*
 	 * There is nothing to wait for if no buffers have already been queued.
 	 */
 	if (list_empty(&q->queued_list)) {
@@ -1378,12 +1420,15 @@ EXPORT_SYMBOL_GPL(vb2_poll);
  *		the given context will be used for memory allocation on all
  *		planes and buffers; it is possible to assign different contexts
  *		per plane, use vb2_set_alloc_ctx() for that
+ * @read_ctx:	parameters for read() api to be used; can be NULL if no read
+ *		callback is used
  * @type:	queue type
  * @drv_priv:	driver private data, may be NULL; it can be used by driver in
  *		driver-specific callbacks when issued
  */
 int vb2_queue_init(struct vb2_queue *q, const struct vb2_ops *ops,
 			const struct vb2_alloc_ctx *alloc_ctx,
+			const struct vb2_read_ctx *read_ctx,
 			enum v4l2_buf_type type, void *drv_priv)
 {
 	unsigned int i;
@@ -1403,6 +1448,7 @@ int vb2_queue_init(struct vb2_queue *q, const struct vb2_ops *ops,
 	for (i = 0; i < VIDEO_MAX_PLANES; ++i)
 		q->alloc_ctx[i] = alloc_ctx;
 
+	q->read_ctx = read_ctx;
 	q->type = type;
 	q->drv_priv = drv_priv;
 
@@ -1428,6 +1474,7 @@ void vb2_queue_release(struct vb2_queue *q)
 {
 	mutex_lock(&q->vb_lock);
 
+	__vb2_cleanup_read(q);
 	__vb2_queue_cancel(q);
 	__vb2_queue_free(q);
 
@@ -1435,6 +1482,245 @@ void vb2_queue_release(struct vb2_queue *q)
 }
 EXPORT_SYMBOL_GPL(vb2_queue_release);
 
+/**
+ * struct vb2_read_data - internal structure used by read() emulator
+ *
+ * vb2 provides a compatibility layer and emulator of read() calls on top
+ * of streaming api. For proper operation it required this structure to
+ * save the driver state between each call of the read function.
+ */
+struct vb2_read_data {
+	struct v4l2_requestbuffers req;
+	struct v4l2_buffer b;
+	void *buff_vaddr[VIDEO_MAX_FRAME];
+	unsigned cur_offset;
+	unsigned cur_bufsize;
+	unsigned read_offset;
+	int cur_buffer;
+	int buffer_count;
+};
+
+/**
+ * __vb2_init_read() - initialize read() emulator
+ * @q:		videobuf2 queue
+ */
+static int __vb2_init_read(struct vb2_queue *q)
+{
+	struct vb2_read_data *rd;
+	int i, ret;
+
+	if (!q->read_ctx)
+		BUG();
+
+	/*
+	 * Check if device supports mapping buffers to kernel virtual space
+	 */
+	if (!q->alloc_ctx[0]->mem_ops->vaddr)
+		return -EBUSY;
+
+	/*
+	 * Check if steaming api has not been already activated.
+	 */
+	if (q->streaming || q->num_buffers > 0)
+		return -EBUSY;
+
+	/*
+	 * Basic checks done, lets try to set up read emulator
+	 */
+	dprintk(3, "setting up read() emulator\n");
+
+	q->read_data = kmalloc(sizeof(struct vb2_read_data), GFP_KERNEL);
+	if (q->read_data == NULL)
+		return -ENOMEM;
+
+	memset(q->read_data, 0, sizeof(*q->read_data));
+	rd = q->read_data;
+
+	/*
+	 * Request buffers and use MMAP type to force driver
+	 * to allocate buffers by itself.
+	 */
+	rd->req.count = q->read_ctx->num_bufs;
+	rd->req.memory = V4L2_MEMORY_MMAP;
+	rd->req.type = q->type;
+	ret = __vb2_reqbufs(q, &rd->req);
+	if (ret)
+		goto err_kfree;
+
+	/*
+	 * Check if plane_count is correct
+	 * (multiplane buffers are not supported).
+	 */
+	if (q->bufs[0]->num_planes != 1) {
+		rd->req.count = 0;
+		ret = -EBUSY;
+		goto err_reqbufs;
+	}
+
+	/*
+	 * Get kernel address of each buffer.
+	 */
+	for (i = 0; i < q->num_buffers; i++)
+		rd->buff_vaddr[i] = vb2_plane_vaddr(q->bufs[i], 0);
+
+	/*
+	 * Queue all buffers.
+	 */
+	for (i = 0; i < q->num_buffers; i++) {
+		memset(&rd->b, 0, sizeof(rd->b));
+		rd->b.type = q->type;
+		rd->b.memory = q->memory;
+		rd->b.index = i;
+		ret = __vb2_qbuf(q, &rd->b);
+		if (ret)
+			goto err_reqbufs;
+	}
+
+	/*
+	 * Start streaming.
+	 */
+	ret = __vb2_streamon(q, q->type);
+	if (ret)
+		goto err_reqbufs;
+
+	return ret;
+
+err_reqbufs:
+	__vb2_reqbufs(q, &rd->req);
+
+err_kfree:
+	kfree(q->read_data);
+	return ret;
+}
+
+/**
+ * __vb2_cleanup_read() - free resourced used by read() emulator
+ * @q:		videobuf2 queue
+ */
+static int __vb2_cleanup_read(struct vb2_queue *q)
+{
+	struct vb2_read_data *rd = q->read_data;
+	if (rd) {
+		__vb2_streamoff(q, q->type);
+		rd->req.count = 0;
+		__vb2_reqbufs(q, &rd->req);
+		kfree(rd);
+		q->read_data = NULL;
+		dprintk(3, "read() emulator released\n");
+	}
+	return 0;
+}
+
+size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
+		loff_t *ppos, int nonblocking)
+{
+	struct vb2_read_data *rd;
+	int ret;
+
+	dprintk(3, "read: offset %ld, count %d, %sblocking\n", (long)*ppos,
+		count, nonblocking ? "non" : "");
+
+	if (!data)
+		return -EINVAL;
+
+	mutex_lock(&q->vb_lock);
+
+	/*
+	 * Initialize emulator on first read() call.
+	 */
+	if (!q->read_data) {
+		ret = __vb2_init_read(q);
+		dprintk(3, "read: vb2_init_read result: %d\n", ret);
+		if (ret)
+			goto end;
+	}
+
+	rd = q->read_data;
+
+	/*
+	 * Current buffer is empty...
+	 */
+	if (rd->cur_offset == 0 && rd->cur_bufsize == 0) {
+		/*
+		 * ... check if this was the last buffer to read.
+		 */
+		if (q->read_ctx->read_once &&
+		    rd->buffer_count == q->read_ctx->num_bufs) {
+			ret = __vb2_cleanup_read(q);
+			goto end;
+		}
+
+		/*
+		 * ... or call vb2_dqbuf to get next buffer with data.
+		 */
+		memset(&rd->b, 0, sizeof(rd->b));
+		rd->b.type = q->type;
+		rd->b.memory = q->memory;
+		rd->b.index = rd->cur_buffer;
+		ret = __vb2_dqbuf(q, &rd->b, nonblocking);
+		dprintk(5, "read: vb2_dqbuf result: %d\n", ret);
+		if (ret)
+			goto end;
+		rd->buffer_count += 1;
+		rd->cur_bufsize = rd->b.length;
+	}
+
+	/*
+	 * Limit count on last few bytes of the buffer.
+	 */
+	if (count + rd->cur_offset > rd->cur_bufsize) {
+		count = rd->cur_bufsize - rd->cur_offset;
+		dprintk(5, "reducing read count: %d\n", count);
+	}
+
+	/*
+	 * Transfer data to userspace.
+	 */
+	dprintk(3, "read: copying %d data from buffer %d (offset %d bytes)\n",
+		count, rd->cur_buffer, rd->cur_offset);
+	if (copy_to_user(data,
+			 rd->buff_vaddr[rd->cur_buffer] + rd->cur_offset,
+			 count)) {
+		dprintk(3, "read: error copying data\n");
+		ret = -EFAULT;
+		goto end;
+	}
+
+	/*
+	 * Update counters.
+	 */
+	rd->cur_offset += count;
+	rd->read_offset += count;
+	*ppos += count;
+
+	/*
+	 * Queue next buffer if required.
+	 */
+	if (rd->cur_offset == rd->cur_bufsize) {
+		memset(&rd->b, 0, sizeof(rd->b));
+		rd->b.type = q->type;
+		rd->b.memory = q->memory;
+		rd->b.index = rd->cur_buffer;
+		ret = __vb2_qbuf(q, &rd->b);
+		dprintk(5, "read: vb2_dbuf result: %d\n", ret);
+		if (ret)
+			goto end;
+		rd->cur_buffer = (rd->cur_buffer + 1) % q->num_buffers;
+		rd->cur_offset = 0;
+		rd->cur_bufsize = 0;
+	}
+
+	/*
+	 * Return proper number of bytes read.
+	 */
+	if (ret == 0)
+		ret = count;
+end:
+	mutex_unlock(&q->vb_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(vb2_read);
+
 MODULE_DESCRIPTION("Driver helper framework for Video for Linux 2");
-MODULE_AUTHOR("Pawel Osciak");
+MODULE_AUTHOR("Pawel Osciak, Marek Szyprowski");
 MODULE_LICENSE("GPL");
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index 76d0b4e..8c1ce06 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -18,6 +18,7 @@
 #include <linux/poll.h>
 
 struct vb2_alloc_ctx;
+struct vb2_read_data;
 
 /**
  * struct vb2_mem_ops - memory handling/memory allocator operations
@@ -210,6 +211,18 @@ struct vb2_ops {
 };
 
 /**
+ * struct vb2_read_ctx - defaults for read() callback emulator
+ *
+ * @num_bufs:	number of buffers used by the emulator
+ * @read_once:	determines weather read emulator return EOF after processing
+ *		@num_bufs or queues buffer again for new data
+ */
+struct vb2_read_ctx {
+	int	num_bufs;
+	int	read_once;
+};
+
+/**
  * struct vb2_queue - a videobuf queue
  *
  * @type:	current queue type
@@ -227,6 +240,8 @@ struct vb2_ops {
  * @streaming:	current streaming state
  * @userptr_supported: true if queue supports USERPTR types
  * @mmap_supported: true if queue supports MMAP types
+ * @read_ctx:	defaults for read() emulator, can be NULL
+ * @read_data:	read() emulator internal data, used only if emulator is active
  */
 struct vb2_queue {
 	enum v4l2_buf_type		type;
@@ -250,6 +265,9 @@ struct vb2_queue {
 	int				streaming:1;
 	int				userptr_supported:1;
 	int				mmap_supported:1;
+
+	const struct vb2_read_ctx	*read_ctx;
+	struct vb2_read_data		*read_data;
 };
 
 void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no);
@@ -262,6 +280,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req);
 
 int vb2_queue_init(struct vb2_queue *q, const struct vb2_ops *ops,
 			const struct vb2_alloc_ctx *alloc_ctx,
+			const struct vb2_read_ctx *read_ctx,
 			enum v4l2_buf_type type, void *drv_priv);
 void vb2_queue_release(struct vb2_queue *q);
 
@@ -273,6 +292,8 @@ int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type);
 
 int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma);
 unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait);
+size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
+		loff_t *ppos, int nonblocking);
 
 /**
  * vb2_is_streaming() - return streaming status of the queue
-- 
1.7.1.569.g6f426


^ permalink raw reply related

* [PATCH 4/7] v4l: videobuf2: add DMA coherent allocator
From: Marek Szyprowski @ 2010-10-20  6:41 UTC (permalink / raw)
  To: linux-media; +Cc: m.szyprowski, pawel, kyungmin.park
In-Reply-To: <1287556873-23179-1-git-send-email-m.szyprowski@samsung.com>

From: Pawel Osciak <p.osciak@samsung.com>

Add an implementation of DMA coherent memory allocator and handling
routines for videobuf2, implemented on top of dma_alloc_coherent() call.

Signed-off-by: Pawel Osciak <p.osciak@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
CC: Pawel Osciak <pawel@osciak.com>
---
 drivers/media/video/Kconfig                  |    5 +
 drivers/media/video/Makefile                 |    1 +
 drivers/media/video/videobuf2-dma-coherent.c |  208 ++++++++++++++++++++++++++
 include/media/videobuf2-dma-coherent.h       |   21 +++
 4 files changed, 235 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/videobuf2-dma-coherent.c
 create mode 100644 include/media/videobuf2-dma-coherent.h

diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 83d49a7..2143112 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -55,6 +55,11 @@ config VIDEOBUF2_CORE
 config VIDEOBUF2_MEMOPS
 	tristate
 
+config VIDEOBUF2_DMA_COHERENT
+	select VIDEOBUF2_CORE
+	select VIDEOBUF2_MEMOPS
+	tristate
+
 config VIDEOBUF2_VMALLOC
 	select VIDEOBUF2_CORE
 	select VIDEOBUF2_MEMOPS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 18f68fc..b3ae7d4 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -120,6 +120,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_DMA_COHERENT)	+= videobuf2-dma_coherent.o
 
 obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o
 
diff --git a/drivers/media/video/videobuf2-dma-coherent.c b/drivers/media/video/videobuf2-dma-coherent.c
new file mode 100644
index 0000000..761f366
--- /dev/null
+++ b/drivers/media/video/videobuf2-dma-coherent.c
@@ -0,0 +1,208 @@
+/*
+ * videobuf2-dma-coherent.c - DMA coherent memory allocator for videobuf2
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <p.osciak@samsung.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/dma-mapping.h>
+
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-memops.h>
+
+struct vb2_dc_conf {
+	struct vb2_alloc_ctx	alloc_ctx;
+	struct device		*dev;
+};
+
+struct vb2_dc_buf {
+	struct vb2_dc_conf	*conf;
+	void			*vaddr;
+	dma_addr_t		paddr;
+	unsigned long		size;
+	unsigned int		refcount;
+	struct vm_area_struct	*vma;
+};
+
+struct vb2_alloc_ctx *vb2_dma_coherent_init(struct device *dev)
+{
+	struct vb2_dc_conf *conf;
+
+	conf = kzalloc(sizeof *conf, GFP_KERNEL);
+	if (!conf)
+		return ERR_PTR(-ENOMEM);
+
+	conf->dev = dev;
+
+	return &conf->alloc_ctx;
+}
+EXPORT_SYMBOL_GPL(vb2_dma_coherent_init);
+
+void vb2_dma_coherent_cleanup(struct vb2_alloc_ctx *alloc_ctx)
+{
+	struct vb2_dc_conf *conf =
+		container_of(alloc_ctx, struct vb2_dc_conf, alloc_ctx);
+
+	kfree(conf);
+}
+EXPORT_SYMBOL_GPL(vb2_dma_coherent_cleanup);
+
+static void *vb2_dma_coherent_alloc(const struct vb2_alloc_ctx *alloc_ctx,
+					unsigned long size)
+{
+	struct vb2_dc_conf *conf =
+		container_of(alloc_ctx, struct vb2_dc_conf, alloc_ctx);
+	struct vb2_dc_buf *buf;
+
+	buf = kzalloc(sizeof *buf, GFP_KERNEL);
+	if (!buf)
+		return ERR_PTR(-ENOMEM);
+
+	buf->vaddr = dma_alloc_coherent(conf->dev, buf->size,
+					&buf->paddr, GFP_KERNEL);
+	if (!buf->vaddr) {
+		dev_err(conf->dev, "dma_alloc_coherent of size %ld failed\n",
+			buf->size);
+		kfree(buf);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	buf->conf = conf;
+	buf->size = size;
+
+	return buf;
+}
+
+static void vb2_dma_coherent_put(void *buf_priv)
+{
+	struct vb2_dc_buf *buf = buf_priv;
+
+	buf->refcount--;
+
+	if (0 == buf->refcount) {
+		dma_free_coherent(buf->conf->dev, buf->size, buf->vaddr,
+					buf->paddr);
+		kfree(buf);
+	}
+}
+
+static unsigned long vb2_dma_coherent_paddr(void *buf_priv)
+{
+	struct vb2_dc_buf *buf = buf_priv;
+
+	return buf->paddr;
+}
+
+static unsigned int vb2_dma_coherent_num_users(void *buf_priv)
+{
+	struct vb2_dc_buf *buf = buf_priv;
+
+	return buf->refcount;
+}
+
+static void vb2_dma_coherent_vm_open(struct vm_area_struct *vma)
+{
+	struct vb2_dc_buf *buf = vma->vm_private_data;
+
+	printk(KERN_DEBUG "%s cma_priv: %p, refcount: %d, "
+			"vma: %08lx-%08lx\n", __func__, buf, buf->refcount,
+			vma->vm_start, vma->vm_end);
+
+	buf->refcount++;
+}
+
+static void vb2_dma_coherent_vm_close(struct vm_area_struct *vma)
+{
+	struct vb2_dc_buf *buf = vma->vm_private_data;
+
+	printk(KERN_DEBUG "%s cma_priv: %p, refcount: %d, "
+			"vma: %08lx-%08lx\n", __func__, buf, buf->refcount,
+			vma->vm_start, vma->vm_end);
+
+	vb2_dma_coherent_put(buf);
+}
+
+static const struct vm_operations_struct vb2_dma_coherent_vm_ops = {
+	.open = vb2_dma_coherent_vm_open,
+	.close = vb2_dma_coherent_vm_close,
+};
+
+static int vb2_dma_coherent_mmap(void *buf_priv, struct vm_area_struct *vma)
+{
+	struct vb2_dc_buf *buf = buf_priv;
+
+	if (!buf) {
+		printk(KERN_ERR "No memory to map\n");
+		return -EINVAL;
+	}
+
+	return vb2_mmap_pfn_range(vma, buf->paddr, buf->size,
+					&vb2_dma_coherent_vm_ops, buf);
+}
+
+static void *vb2_dma_coherent_get_userptr(unsigned long vaddr,
+						unsigned long size)
+{
+	struct vb2_dc_buf *buf;
+	unsigned long paddr = 0;
+	int ret;
+
+	buf = kzalloc(sizeof *buf, GFP_KERNEL);
+	if (!buf)
+		return ERR_PTR(-ENOMEM);
+
+	buf->vma = vb2_get_userptr(vaddr);
+	if (!buf->vma) {
+		printk(KERN_ERR "Failed acquiring VMA for vaddr 0x%08lx\n",
+				vaddr);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = vb2_contig_verify_userptr(buf->vma, vaddr, size, &paddr);
+	if (ret) {
+		vb2_put_userptr(buf->vma);
+		goto done;
+	}
+
+	buf->size = size;
+	buf->paddr = paddr;
+
+	return buf;
+
+done:
+	kfree(buf);
+	return ERR_PTR(ret);
+}
+
+static void vb2_dma_coherent_put_userptr(void *mem_priv)
+{
+	struct vb2_dc_buf *buf = mem_priv;
+
+	if (!buf)
+		return;
+
+	vb2_put_userptr(buf->vma);
+	kfree(buf);
+}
+
+const struct vb2_mem_ops vb2_dma_coherent_ops = {
+	.alloc		= vb2_dma_coherent_alloc,
+	.put		= vb2_dma_coherent_put,
+	.paddr		= vb2_dma_coherent_paddr,
+	.mmap		= vb2_dma_coherent_mmap,
+	.get_userptr	= vb2_dma_coherent_get_userptr,
+	.put_userptr	= vb2_dma_coherent_put_userptr,
+	.num_users	= vb2_dma_coherent_num_users,
+};
+
+MODULE_DESCRIPTION("DMA-coherent memory handling routines for videobuf2");
+MODULE_AUTHOR("Pawel Osciak");
+MODULE_LICENSE("GPL");
+
diff --git a/include/media/videobuf2-dma-coherent.h b/include/media/videobuf2-dma-coherent.h
new file mode 100644
index 0000000..102b1a7
--- /dev/null
+++ b/include/media/videobuf2-dma-coherent.h
@@ -0,0 +1,21 @@
+/*
+ * videobuf2-dma-coherent.h - DMA coherent memory allocator for videobuf2
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <p.osciak@samsung.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_DMA_COHERENT_H
+#define _MEDIA_VIDEOBUF2_DMA_COHERENT_H
+
+#include <media/videobuf2-core.h>
+
+void *vb2_dma_coherent_init(struct device *dev);
+void vb2_dma_coherent_cleanup(struct vb2_alloc_ctx *alloc_ctx);
+
+#endif
-- 
1.7.1.569.g6f426


^ permalink raw reply related

* [PATCH 7/7] v4l: videobuf2: add CMA allocator
From: Marek Szyprowski @ 2010-10-20  6:41 UTC (permalink / raw)
  To: linux-media; +Cc: m.szyprowski, pawel, kyungmin.park
In-Reply-To: <1287556873-23179-1-git-send-email-m.szyprowski@samsung.com>

From: Pawel Osciak <p.osciak@samsung.com>

Add support for the CMA contiguous memory allocator to videobuf2.

Signed-off-by: Pawel Osciak <p.osciak@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
CC: Pawel Osciak <pawel@osciak.com>
---
 drivers/media/video/Kconfig         |    5 +
 drivers/media/video/Makefile        |    1 +
 drivers/media/video/videobuf2-cma.c |  250 +++++++++++++++++++++++++++++++++++
 include/media/videobuf2-cma.h       |   25 ++++
 4 files changed, 281 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/videobuf2-cma.c
 create mode 100644 include/media/videobuf2-cma.h

diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 4dd14c2..2da9254 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -65,6 +65,11 @@ config VIDEOBUF2_VMALLOC
 	select VIDEOBUF2_MEMOPS
 	tristate
 
+config VIDEOBUF2_CMA
+	depends on CMA
+	select VIDEOBUF2_CORE
+	select VIDEOBUF2_MEMOPS
+	tristate
 #
 # Multimedia Video device configuration
 #
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index b3ae7d4..d1fc8cf 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -121,6 +121,7 @@ obj-$(CONFIG_VIDEOBUF2_CORE)		+= videobuf2-core.o
 obj-$(CONFIG_VIDEOBUF2_MEMOPS)		+= videobuf2-memops.o
 obj-$(CONFIG_VIDEOBUF2_VMALLOC)		+= videobuf2-vmalloc.o
 obj-$(CONFIG_VIDEOBUF2_DMA_COHERENT)	+= videobuf2-dma_coherent.o
+obj-$(CONFIG_VIDEOBUF2_CMA)		+= videobuf2-cma.o
 
 obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o
 
diff --git a/drivers/media/video/videobuf2-cma.c b/drivers/media/video/videobuf2-cma.c
new file mode 100644
index 0000000..d949c25
--- /dev/null
+++ b/drivers/media/video/videobuf2-cma.c
@@ -0,0 +1,250 @@
+/*
+ * videobuf2-cma.c - CMA memory allocator for videobuf2
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <p.osciak@samsung.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/slab.h>
+#include <linux/cma.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/file.h>
+
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-memops.h>
+
+struct vb2_cma_conf {
+	struct vb2_alloc_ctx	alloc_ctx;
+	struct device		*dev;
+	const char		*type;
+	unsigned long		alignment;
+};
+
+struct vb2_cma_buf {
+	struct vb2_cma_conf	*conf;
+	dma_addr_t		paddr;
+	unsigned long		size;
+	unsigned int		refcount;
+	struct vm_area_struct	*vma;
+};
+
+static void *vb2_cma_alloc(const struct vb2_alloc_ctx *alloc_ctx,
+				unsigned long size)
+{
+	struct vb2_cma_conf *conf =
+		container_of(alloc_ctx, struct vb2_cma_conf, alloc_ctx);
+	struct vb2_cma_buf *buf;
+
+	buf = kzalloc(sizeof *buf, GFP_KERNEL);
+	if (!buf)
+		return ERR_PTR(-ENOMEM);
+
+	buf->paddr = cma_alloc(conf->dev, conf->type, size, conf->alignment);
+	if (IS_ERR((void *)buf->paddr)) {
+		printk(KERN_ERR "cma_alloc of size %ld failed\n", size);
+		kfree(buf);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	buf->conf = conf;
+	buf->size = size;
+	buf->refcount++;
+
+	printk(KERN_DEBUG "Allocated cma mem of size %ld at paddr=0x%08x\n",
+			buf->size, buf->paddr);
+
+	return buf;
+}
+
+static void vb2_cma_put(void *buf_priv)
+{
+	struct vb2_cma_buf *buf = buf_priv;
+
+	buf->refcount--;
+
+	if (0 == buf->refcount) {
+		cma_free(buf->paddr);
+		kfree(buf);
+	}
+}
+
+static unsigned long vb2_cma_paddr(void *buf_priv)
+{
+	struct vb2_cma_buf *buf = buf_priv;
+
+	return buf->paddr;
+}
+
+static unsigned int vb2_cma_num_users(void *buf_priv)
+{
+	struct vb2_cma_buf *buf = buf_priv;
+
+	return buf->refcount;
+}
+
+static void vb2_cma_vm_open(struct vm_area_struct *vma)
+{
+	struct vb2_cma_buf *buf = vma->vm_private_data;
+
+	printk(KERN_DEBUG "%s cma_priv: %p, refcount: %d, "
+			"vma: %08lx-%08lx\n", __func__, buf, buf->refcount,
+			vma->vm_start, vma->vm_end);
+
+	buf->refcount++;
+}
+
+static void vb2_cma_vm_close(struct vm_area_struct *vma)
+{
+	struct vb2_cma_buf *buf = vma->vm_private_data;
+
+	printk(KERN_DEBUG "%s cma_priv: %p, refcount: %d, "
+			"vma: %08lx-%08lx\n", __func__, buf, buf->refcount,
+			vma->vm_start, vma->vm_end);
+
+	vb2_cma_put(buf);
+}
+
+static const struct vm_operations_struct vb2_cma_vm_ops = {
+	.open = vb2_cma_vm_open,
+	.close = vb2_cma_vm_close,
+};
+
+static int vb2_cma_mmap(void *buf_priv, struct vm_area_struct *vma)
+{
+	struct vb2_cma_buf *buf = buf_priv;
+
+	if (!buf) {
+		printk(KERN_ERR "No memory to map\n");
+		return -EINVAL;
+	}
+
+	return vb2_mmap_pfn_range(vma, buf->paddr, buf->size,
+					&vb2_cma_vm_ops, buf);
+}
+
+static void *vb2_cma_get_userptr(unsigned long vaddr, unsigned long size)
+{
+	struct vb2_cma_buf *buf;
+	unsigned long paddr = 0;
+	int ret;
+
+	buf = kzalloc(sizeof *buf, GFP_KERNEL);
+	if (!buf)
+		return ERR_PTR(-ENOMEM);
+
+	buf->vma = vb2_get_userptr(vaddr);
+	if (!buf->vma) {
+		printk(KERN_ERR "Failed acquiring VMA for vaddr 0x%08lx\n",
+				vaddr);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = vb2_contig_verify_userptr(buf->vma, vaddr, size, &paddr);
+	if (ret) {
+		vb2_put_userptr(buf->vma);
+		goto done;
+	}
+
+	buf->size = size;
+	buf->paddr = paddr;
+
+	return buf;
+
+done:
+	kfree(buf);
+	return ERR_PTR(ret);
+}
+
+static void vb2_cma_put_userptr(void *mem_priv)
+{
+	struct vb2_cma_buf *buf = mem_priv;
+
+	if (!buf)
+		return;
+
+	vb2_put_userptr(buf->vma);
+	kfree(buf);
+}
+
+static const struct vb2_mem_ops vb2_cma_ops = {
+	.alloc		= vb2_cma_alloc,
+	.put		= vb2_cma_put,
+	.paddr		= vb2_cma_paddr,
+	.mmap		= vb2_cma_mmap,
+	.get_userptr	= vb2_cma_get_userptr,
+	.put_userptr	= vb2_cma_put_userptr,
+	.num_users	= vb2_cma_num_users,
+};
+
+struct vb2_alloc_ctx *vb2_cma_init(struct device *dev, const char *type,
+					unsigned long alignment)
+{
+	struct vb2_cma_conf *conf;
+
+	conf = kzalloc(sizeof *conf, GFP_KERNEL);
+	if (!conf)
+		return ERR_PTR(-ENOMEM);
+
+	conf->dev = dev;
+	conf->type = type;
+	conf->alignment = alignment;
+	conf->alloc_ctx.mem_ops = &vb2_cma_ops;
+
+	return &conf->alloc_ctx;
+}
+EXPORT_SYMBOL_GPL(vb2_cma_init);
+
+void vb2_cma_cleanup(struct vb2_alloc_ctx *alloc_ctx)
+{
+	struct vb2_cma_conf *conf =
+		container_of(alloc_ctx, struct vb2_cma_conf, alloc_ctx);
+
+	kfree(conf);
+}
+EXPORT_SYMBOL_GPL(vb2_cma_cleanup);
+
+struct vb2_alloc_ctx **vb2_cma_init_multi(struct device *dev,
+					  unsigned int num_planes,
+					  const char *types[],
+					  unsigned long alignments[])
+{
+	struct vb2_alloc_ctx	**alloc_ctxes;
+	struct vb2_cma_conf	*cma_conf;
+	unsigned int i;
+
+	alloc_ctxes = kzalloc((sizeof *alloc_ctxes + sizeof *cma_conf)
+				* num_planes, GFP_KERNEL);
+	if (!alloc_ctxes)
+		return ERR_PTR(-ENOMEM);
+
+	cma_conf = (void *)(alloc_ctxes + num_planes);
+
+	for (i = 0; i < num_planes; ++i, ++cma_conf) {
+		alloc_ctxes[i] = &cma_conf->alloc_ctx;
+		cma_conf->dev = dev;
+		cma_conf->type = types[i];
+		cma_conf->alignment = alignments[i];
+		cma_conf->alloc_ctx.mem_ops = &vb2_cma_ops;
+	}
+
+	return alloc_ctxes;
+}
+EXPORT_SYMBOL_GPL(vb2_cma_init_multi);
+
+void vb2_cma_cleanup_multi(struct vb2_alloc_ctx **alloc_ctxes)
+{
+	kfree(alloc_ctxes);
+}
+EXPORT_SYMBOL_GPL(vb2_cma_cleanup_multi);
+
+MODULE_DESCRIPTION("CMA allocator handling routines for videobuf2");
+MODULE_AUTHOR("Pawel Osciak");
+MODULE_LICENSE("GPL");
diff --git a/include/media/videobuf2-cma.h b/include/media/videobuf2-cma.h
new file mode 100644
index 0000000..557eeb0
--- /dev/null
+++ b/include/media/videobuf2-cma.h
@@ -0,0 +1,25 @@
+/*
+ * videobuf2-cma.h - CMA memory allocator for videobuf2
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <p.osciak@samsung.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.
+ */
+
+struct vb2_alloc_ctx *vb2_cma_init(struct device *dev, const char *type,
+					unsigned long alignment);
+void vb2_cma_cleanup(struct vb2_alloc_ctx *alloc_ctx);
+
+struct vb2_alloc_ctx **vb2_cma_init_multi(struct device *dev,
+				  unsigned int num_planes, const char *types[],
+				  unsigned long alignments[]);
+void vb2_cma_cleanup_multi(struct vb2_alloc_ctx **alloc_ctxes);
+
+struct vb2_alloc_ctx *vb2_cma_init(struct device *dev, const char *type,
+					unsigned long alignment);
+void vb2_cma_cleanup(struct vb2_alloc_ctx *alloc_ctx);
+
-- 
1.7.1.569.g6f426


^ permalink raw reply related

* [PATCH 3/7] v4l: videobuf2: add vmalloc allocator
From: Marek Szyprowski @ 2010-10-20  6:41 UTC (permalink / raw)
  To: linux-media; +Cc: m.szyprowski, pawel, kyungmin.park
In-Reply-To: <1287556873-23179-1-git-send-email-m.szyprowski@samsung.com>

From: Pawel Osciak <p.osciak@samsung.com>

Add an implementation of contiguous virtual memory allocator and handling
routines for videobuf2, implemented on top of vmalloc()/vfree() calls.

Signed-off-by: Pawel Osciak <p.osciak@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
CC: Pawel Osciak <pawel@osciak.com>
---
 drivers/media/video/Kconfig             |    5 +
 drivers/media/video/Makefile            |    1 +
 drivers/media/video/videobuf2-vmalloc.c |  177 +++++++++++++++++++++++++++++++
 include/media/videobuf2-vmalloc.h       |   16 +++
 4 files changed, 199 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/videobuf2-vmalloc.c
 create mode 100644 include/media/videobuf2-vmalloc.h

diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 2acb0f8..83d49a7 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -55,6 +55,11 @@ config VIDEOBUF2_CORE
 config VIDEOBUF2_MEMOPS
 	tristate
 
+config VIDEOBUF2_VMALLOC
+	select VIDEOBUF2_CORE
+	select VIDEOBUF2_MEMOPS
+	tristate
+
 #
 # Multimedia Video device configuration
 #
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 77cc798..18f68fc 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -119,6 +119,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_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o
 
diff --git a/drivers/media/video/videobuf2-vmalloc.c b/drivers/media/video/videobuf2-vmalloc.c
new file mode 100644
index 0000000..3310900
--- /dev/null
+++ b/drivers/media/video/videobuf2-vmalloc.c
@@ -0,0 +1,177 @@
+/*
+ * videobuf2-vmalloc.c - vmalloc memory allocator for videobuf2
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <p.osciak@samsung.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 <linux/vmalloc.h>
+
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-memops.h>
+
+struct vb2_vmalloc_conf {
+	struct vb2_alloc_ctx	alloc_ctx;
+};
+
+struct vb2_vmalloc_buf {
+	void			*vaddr;
+	unsigned long		size;
+	unsigned int		refcount;
+};
+
+static void *vb2_vmalloc_alloc(const struct vb2_alloc_ctx *alloc_ctx,
+				unsigned long size)
+{
+	struct vb2_vmalloc_buf *buf;
+
+	buf = kzalloc(sizeof *buf, GFP_KERNEL);
+	if (!buf)
+		return NULL;
+
+	buf->size = size;
+	buf->vaddr = vmalloc_user(buf->size);
+	if (!buf->vaddr) {
+		printk(KERN_ERR "vmalloc of size %ld failed\n", buf->size);
+		kfree(buf);
+		return NULL;
+	}
+
+	buf->refcount++;
+	printk(KERN_DEBUG "Allocated vmalloc buffer of size %ld at vaddr=%p\n",
+			buf->size, buf->vaddr);
+
+	return buf;
+}
+
+static void vb2_vmalloc_put(void *buf_priv)
+{
+	struct vb2_vmalloc_buf *buf = buf_priv;
+
+	buf->refcount--;
+
+	if (0 == buf->refcount) {
+		printk(KERN_DEBUG "%s: Freeing vmalloc mem at vaddr=%p\n",
+			__func__, buf->vaddr);
+		vfree(buf->vaddr);
+		kfree(buf);
+	}
+}
+
+static void *vb2_vmalloc_vaddr(void *buf_priv)
+{
+	struct vb2_vmalloc_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_vmalloc_num_users(void *buf_priv)
+{
+	struct vb2_vmalloc_buf *buf = buf_priv;
+
+	return buf->refcount;
+}
+
+/* TODO generalize and extract to core as much as possible */
+static void vb2_vmalloc_vm_open(struct vm_area_struct *vma)
+{
+	struct vb2_vmalloc_buf *buf = vma->vm_private_data;
+
+	printk(KERN_DEBUG "%s vmalloc_priv: %p, refcount: %d, "
+			"vma: %08lx-%08lx\n", __func__, buf, buf->refcount,
+			vma->vm_start, vma->vm_end);
+
+	buf->refcount++;
+}
+
+static void vb2_vmalloc_vm_close(struct vm_area_struct *vma)
+{
+	struct vb2_vmalloc_buf *buf = vma->vm_private_data;
+
+	printk(KERN_DEBUG "%s vmalloc_priv: %p, refcount: %d, "
+			"vma: %08lx-%08lx\n", __func__, buf, buf->refcount,
+			vma->vm_start, vma->vm_end);
+
+	vb2_vmalloc_put(buf);
+}
+
+static const struct vm_operations_struct vb2_vmalloc_vm_ops = {
+	.open = vb2_vmalloc_vm_open,
+	.close = vb2_vmalloc_vm_close,
+};
+
+static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma)
+{
+	struct vb2_vmalloc_buf *buf = buf_priv;
+	int ret;
+
+	if (!buf) {
+		printk(KERN_ERR "No memory to map\n");
+		return -EINVAL;
+	}
+
+	ret = remap_vmalloc_range(vma, buf->vaddr, 0);
+	if (ret) {
+		printk(KERN_ERR "Remapping vmalloc memory, error: %d\n", ret);
+		return ret;
+	}
+
+	vma->vm_flags		|= VM_DONTEXPAND | VM_RESERVED;
+	vma->vm_private_data	= buf;
+	vma->vm_ops		= &vb2_vmalloc_vm_ops;
+
+	vb2_vmalloc_vm_open(vma);
+
+	return 0;
+}
+
+static const struct vb2_mem_ops vb2_vmalloc_ops = {
+	.alloc		= vb2_vmalloc_alloc,
+	.put		= vb2_vmalloc_put,
+	.vaddr		= vb2_vmalloc_vaddr,
+	.mmap		= vb2_vmalloc_mmap,
+	.num_users	= vb2_vmalloc_num_users,
+};
+
+struct vb2_alloc_ctx *vb2_vmalloc_init(void)
+{
+	struct vb2_vmalloc_conf *conf;
+
+	conf = kzalloc(sizeof *conf, GFP_KERNEL);
+	if (!conf)
+		return ERR_PTR(-ENOMEM);
+
+	conf->alloc_ctx.mem_ops = &vb2_vmalloc_ops;
+
+	return &conf->alloc_ctx;
+}
+EXPORT_SYMBOL_GPL(vb2_vmalloc_init);
+
+void vb2_vmalloc_cleanup(struct vb2_alloc_ctx *alloc_ctx)
+{
+	struct vb2_vmalloc_conf *conf =
+		container_of(alloc_ctx, struct vb2_vmalloc_conf, alloc_ctx);
+
+	kfree(conf);
+}
+EXPORT_SYMBOL_GPL(vb2_vmalloc_cleanup);
+
+MODULE_DESCRIPTION("vmalloc memory handling routines for videobuf2");
+MODULE_AUTHOR("Pawel Osciak");
+MODULE_LICENSE("GPL");
diff --git a/include/media/videobuf2-vmalloc.h b/include/media/videobuf2-vmalloc.h
new file mode 100644
index 0000000..7612f9f
--- /dev/null
+++ b/include/media/videobuf2-vmalloc.h
@@ -0,0 +1,16 @@
+/*
+ * videobuf2-vmalloc.h - vmalloc memory allocator for videobuf2
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <p.osciak@samsung.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 <media/videobuf2-core.h>
+
+struct vb2_alloc_ctx *vb2_vmalloc_init(void);
+void vb2_vmalloc_cleanup(struct vb2_alloc_ctx *alloc_ctx);
-- 
1.7.1.569.g6f426


^ permalink raw reply related

* Re: [PATCH] diff: handle lines containing only whitespace better
From: Kevin Ballard @ 2010-10-20  6:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vzku9wfrp.fsf@alter.siamese.dyndns.org>

On Oct 19, 2010, at 11:16 PM, Junio C Hamano wrote:

> Hmm, tests?

I checked, there seem to be no existing tests for the whitespace highlighting output. All the tests just use `git diff --check` to see if it was caught. And given that the problem only occurs when it's emitting the colored highlighting, I wasn't sure how to go about adding tests for this as I'd need to create an expect file that contains all the same ansi color codes, and I thought that might be a bit fragile or hard to do correctly.

Incidentally, I just realized the description of the patch is slightly wrong. The problem only occurs when the line contains at least one tab. Should I resend the patch with an updated description? I can also attempt to write tests if you can give me some guidance on how to deal with the need for ansi color codes.

-Kevin Ballard

^ permalink raw reply

* [PATCH]qemu-xen: let xenfb_guest_copy() handle depth=32 case
From: Chun Yan Liu @ 2010-10-20  6:38 UTC (permalink / raw)
  To: xen-devel


[-- Attachment #1.1: Type: text/plain, Size: 1814 bytes --]

In hw/xenfb.c, xenfb_guest_copy() function doesn't handle xenfb->depth=32 case. When xenfb->depth=32, it will report error and won't copy data from the guest framebuffer region into QEMU's displaysurface, thus when enter CTRL+ALT+2 to qemu monitor console then CTRL+ALT+1 back to guest X window, the screen cannot be restored.

This patch adds two things:
1. when xenfb->depth equals destination bpp, do not need data translation, simply copy data from guest framebuffer into QEMU's displaysurface.
2. when xenfb->depth and destination bpp differs, add processing for xenfb->depth=32 case.

Signed-off by Chunyan Liu <cyliu@novell.com>
 
diff -r e4f337bb97f7 tools/ioemu-qemu-xen/hw/xenfb.c
--- a/hw/xenfb.c Wed Oct 20 19:39:28 2010 +0800
+++ b/hw/xenfb.c Wed Oct 20 21:42:37 2010 +0800
@@ -612,6 +612,12 @@
     uint8_t *data = ds_get_data(xenfb->c.ds);
 
     if (!is_buffer_shared(xenfb->c.ds->surface)) {
+        if (xenfb->depth == bpp) { 
+                for (line = y; line < (y+h); line++) {
+                        memcpy (data + (line * linesize) + (x * bpp / 8), xenfb->pixels + xenfb->offset + (line * xenfb->row_stride) + (x * xenfb->depth / 8), w * xenfb->depth / 8);
+                }
+        }
+        else{
         switch (xenfb->depth) {
         case 8:
             if (bpp == 16) {
@@ -631,9 +637,17 @@
                 oops = 1;
             }
             break;
+        case 32:
+            if (bpp == 16) {
+                BLT(uint32_t, uint16_t,  8, 8, 8,   5, 6, 5);
+            } else {
+                oops = 1;
+            }
+            break; 
         default:
             oops = 1;
  }
+        }
     }
     if (oops) /* should not happen */
         xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",

[-- Attachment #1.2: Type: text/html, Size: 3683 bytes --]

[-- Attachment #2: xenfb_32bpp.PATCH --]
[-- Type: text/plain, Size: 1168 bytes --]

diff -r e4f337bb97f7 tools/ioemu-qemu-xen/hw/xenfb.c
--- a/hw/xenfb.c	Wed Oct 20 19:39:28 2010 +0800
+++ b/hw/xenfb.c	Wed Oct 20 21:42:37 2010 +0800
@@ -612,6 +612,12 @@
     uint8_t *data = ds_get_data(xenfb->c.ds);
 
     if (!is_buffer_shared(xenfb->c.ds->surface)) {
+        if (xenfb->depth == bpp) { 
+                for (line = y; line < (y+h); line++) {
+                        memcpy (data + (line * linesize) + (x * bpp / 8), xenfb->pixels + xenfb->offset + (line * xenfb->row_stride) + (x * xenfb->depth / 8), w * xenfb->depth / 8);
+                }
+        }
+        else{
         switch (xenfb->depth) {
         case 8:
             if (bpp == 16) {
@@ -631,9 +637,17 @@
                 oops = 1;
             }
             break;
+        case 32:
+            if (bpp == 16) {
+                BLT(uint32_t, uint16_t,  8, 8, 8,   5, 6, 5);
+            } else {
+                oops = 1;
+            }
+            break; 
         default:
             oops = 1;
 	}
+        }
     }
     if (oops) /* should not happen */
         xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply


This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.