summaryrefslogtreecommitdiff
path: root/recipes/linux/linux-omap-2.6.31/dss2
diff options
context:
space:
mode:
authorKoen Kooi <koen@openembedded.org>2009-09-04 15:32:30 +0200
committerKoen Kooi <koen@openembedded.org>2009-09-04 15:32:30 +0200
commit881f92e3409f67f70cffd5cfaca0de8248729145 (patch)
tree49f15add251b6ded5b2c5efc29f5603b76619e0e /recipes/linux/linux-omap-2.6.31/dss2
parenteff28b3b4ec8309ac1d51d98b8bfc9f5d48ed43f (diff)
linux-omap git: another checkpoint
* add V4l2 interfaces to DSS2 * add back MADC driver * add zippy support for beagleboard * add DSS2 for omap3evm
Diffstat (limited to 'recipes/linux/linux-omap-2.6.31/dss2')
-rw-r--r--recipes/linux/linux-omap-2.6.31/dss2/0001-OMAP3-Enable-DSS2-for-OMAP3EVM-board.patch387
-rw-r--r--recipes/linux/linux-omap-2.6.31/dss2/0002-V4L2-Added-New-V4L2-CIDs-for-omap-devices-V4L2-IOCT.patch152
-rw-r--r--recipes/linux/linux-omap-2.6.31/dss2/0003-V4L2-Updated-v4l2_common-for-new-V4L2-CIDs.patch40
-rw-r--r--recipes/linux/linux-omap-2.6.31/dss2/0004-OMAP2-3-V4L2-Add-support-for-OMAP2-3-V4L2-driver-on.patch3248
4 files changed, 3827 insertions, 0 deletions
diff --git a/recipes/linux/linux-omap-2.6.31/dss2/0001-OMAP3-Enable-DSS2-for-OMAP3EVM-board.patch b/recipes/linux/linux-omap-2.6.31/dss2/0001-OMAP3-Enable-DSS2-for-OMAP3EVM-board.patch
new file mode 100644
index 0000000000..9a4ea8b9ad
--- /dev/null
+++ b/recipes/linux/linux-omap-2.6.31/dss2/0001-OMAP3-Enable-DSS2-for-OMAP3EVM-board.patch
@@ -0,0 +1,387 @@
+From 798f9b1bc478c7ded724fc190c65e413c2401314 Mon Sep 17 00:00:00 2001
+From: Vaibhav Hiremath <hvaibhav@ti.com>
+Date: Tue, 11 Aug 2009 15:52:04 +0530
+Subject: [PATCH 1/5] OMAP3: Enable DSS2 for OMAP3EVM board
+
+Tested -
+ - Validated all three outut interfaces (LCD, DVI and TV)
+TODO:
+ - Support for Backlight control range (0 - 100)
+ - Enable selection for both S-Video and Composite TV out
+ - DVI color (VPLL2_DEV_GRP should be equal to 0x7)
+
+Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
+---
+ arch/arm/configs/omap3_evm_defconfig | 51 +++++++-
+ arch/arm/mach-omap2/board-omap3evm.c | 234 ++++++++++++++++++++++++++++++++--
+ 2 files changed, 273 insertions(+), 12 deletions(-)
+
+diff --git a/arch/arm/configs/omap3_evm_defconfig b/arch/arm/configs/omap3_evm_defconfig
+index d5ff477..ba395a2 100644
+--- a/arch/arm/configs/omap3_evm_defconfig
++++ b/arch/arm/configs/omap3_evm_defconfig
+@@ -903,7 +903,56 @@ CONFIG_DAB=y
+ #
+ # CONFIG_VGASTATE is not set
+ CONFIG_VIDEO_OUTPUT_CONTROL=m
+-# CONFIG_FB is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++# CONFIG_FB_MODE_HELPERS is not set
++# CONFIG_FB_TILEBLITTING is not set
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_MB862XX is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
++CONFIG_OMAP2_VRAM=y
++CONFIG_OMAP2_VRFB=y
++CONFIG_OMAP2_DSS=y
++CONFIG_OMAP2_VRAM_SIZE=4
++# CONFIG_OMAP2_DSS_DEBUG_SUPPORT is not set
++# CONFIG_OMAP2_DSS_RFBI is not set
++CONFIG_OMAP2_DSS_VENC=y
++# CONFIG_OMAP2_DSS_SDI is not set
++# CONFIG_OMAP2_DSS_DSI is not set
++# CONFIG_OMAP2_DSS_FAKE_VSYNC is not set
++CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0
++CONFIG_FB_OMAP2=y
++# CONFIG_FB_OMAP2_DEBUG_SUPPORT is not set
++# CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE is not set
++CONFIG_FB_OMAP2_NUM_FBS=3
++
++#
++# OMAP2/3 Display Device Drivers
++#
++CONFIG_PANEL_GENERIC=y
++# CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C is not set
++CONFIG_PANEL_SHARP_LS037V7DW01=y
+ # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+ #
+diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
+index c0cb29d..0bc26b3 100644
+--- a/arch/arm/mach-omap2/board-omap3evm.c
++++ b/arch/arm/mach-omap2/board-omap3evm.c
+@@ -22,6 +22,7 @@
+ #include <linux/input.h>
+ #include <linux/leds.h>
+
++#include <linux/regulator/machine.h>
+ #include <linux/spi/spi.h>
+ #include <linux/spi/ads7846.h>
+ #include <linux/i2c/twl4030.h>
+@@ -38,6 +39,7 @@
+ #include <mach/common.h>
+ #include <mach/mcspi.h>
+ #include <mach/keypad.h>
++#include <mach/display.h>
+
+ #include "sdram-micron-mt46h32m32lf-6.h"
+ #include "mmc-twl4030.h"
+@@ -91,6 +93,174 @@ static inline void __init omap3evm_init_smc911x(void)
+
+ gpio_direction_input(OMAP3EVM_ETHR_GPIO_IRQ);
+ }
++/*
++ * OMAP3EVM LCD Panel control signals
++ */
++#define OMAP3EVM_LCD_PANEL_LR 2
++#define OMAP3EVM_LCD_PANEL_UD 3
++#define OMAP3EVM_LCD_PANEL_INI 152
++#define OMAP3EVM_LCD_PANEL_ENVDD 153
++#define OMAP3EVM_LCD_PANEL_QVGA 154
++#define OMAP3EVM_LCD_PANEL_RESB 155
++#define OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO 210
++#define OMAP3EVM_DVI_PANEL_EN_GPIO 199
++
++static int lcd_enabled;
++static int dvi_enabled;
++
++static void __init omap3_evm_display_init(void)
++{
++ int r;
++ r = gpio_request(OMAP3EVM_LCD_PANEL_RESB, "lcd_panel_resb");
++ if (r) {
++ printk(KERN_ERR "failed to get lcd_panel_resb\n");
++ return;
++ }
++ gpio_direction_output(OMAP3EVM_LCD_PANEL_RESB, 1);
++
++ r = gpio_request(OMAP3EVM_LCD_PANEL_INI, "lcd_panel_ini");
++ if (r) {
++ printk(KERN_ERR "failed to get lcd_panel_ini\n");
++ goto err_1;
++ }
++ gpio_direction_output(OMAP3EVM_LCD_PANEL_INI, 1);
++
++ r = gpio_request(OMAP3EVM_LCD_PANEL_QVGA, "lcd_panel_qvga");
++ if (r) {
++ printk(KERN_ERR "failed to get lcd_panel_qvga\n");
++ goto err_2;
++ }
++ gpio_direction_output(OMAP3EVM_LCD_PANEL_QVGA, 0);
++
++ r = gpio_request(OMAP3EVM_LCD_PANEL_LR, "lcd_panel_lr");
++ if (r) {
++ printk(KERN_ERR "failed to get lcd_panel_lr\n");
++ goto err_3;
++ }
++ gpio_direction_output(OMAP3EVM_LCD_PANEL_LR, 1);
++
++ r = gpio_request(OMAP3EVM_LCD_PANEL_UD, "lcd_panel_ud");
++ if (r) {
++ printk(KERN_ERR "failed to get lcd_panel_ud\n");
++ goto err_4;
++ }
++ gpio_direction_output(OMAP3EVM_LCD_PANEL_UD, 1);
++
++ r = gpio_request(OMAP3EVM_LCD_PANEL_ENVDD, "lcd_panel_envdd");
++ if (r) {
++ printk(KERN_ERR "failed to get lcd_panel_envdd\n");
++ goto err_5;
++ }
++
++ return;
++
++err_5:
++ gpio_free(OMAP3EVM_LCD_PANEL_UD);
++err_4:
++ gpio_free(OMAP3EVM_LCD_PANEL_LR);
++err_3:
++ gpio_free(OMAP3EVM_LCD_PANEL_QVGA);
++err_2:
++ gpio_free(OMAP3EVM_LCD_PANEL_INI);
++err_1:
++ gpio_free(OMAP3EVM_LCD_PANEL_RESB);
++
++}
++
++static int omap3_evm_enable_lcd(struct omap_dss_device *dssdev)
++{
++ if (dvi_enabled) {
++ printk(KERN_ERR "cannot enable LCD, DVI is enabled\n");
++ return -EINVAL;
++ }
++
++ gpio_set_value(OMAP3EVM_LCD_PANEL_ENVDD, 0);
++ gpio_set_value(OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO, 1);
++ lcd_enabled = 1;
++ return 0;
++}
++
++static void omap3_evm_disable_lcd(struct omap_dss_device *dssdev)
++{
++ gpio_set_value(OMAP3EVM_LCD_PANEL_ENVDD, 1);
++ gpio_set_value(OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO, 0);
++ lcd_enabled = 0;
++}
++
++static struct omap_dss_device omap3_evm_lcd_device = {
++ .type = OMAP_DISPLAY_TYPE_DPI,
++ .name = "lcd",
++ .driver_name = "sharp_ls_panel",
++ .phy.dpi.data_lines = 18,
++ .platform_enable = omap3_evm_enable_lcd,
++ .platform_disable = omap3_evm_disable_lcd,
++};
++
++static int omap3_evm_enable_tv(struct omap_dss_device *dssdev)
++{
++ return 0;
++}
++
++static void omap3_evm_disable_tv(struct omap_dss_device *dssdev)
++{
++}
++
++static struct omap_dss_device omap3_evm_tv_device = {
++ .type = OMAP_DISPLAY_TYPE_VENC,
++ .name = "tv",
++ .driver_name = "venc",
++ .phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO,
++ .platform_enable = omap3_evm_enable_tv,
++ .platform_disable = omap3_evm_disable_tv,
++};
++
++static int omap3_evm_enable_dvi(struct omap_dss_device *dssdev)
++{
++ if (lcd_enabled) {
++ printk(KERN_ERR "cannot enable DVI, LCD is enabled\n");
++ return -EINVAL;
++ }
++
++ gpio_set_value(OMAP3EVM_DVI_PANEL_EN_GPIO, 1);
++ dvi_enabled = 1;
++
++ return 0;
++}
++
++static void omap3_evm_disable_dvi(struct omap_dss_device *dssdev)
++{
++ gpio_set_value(OMAP3EVM_DVI_PANEL_EN_GPIO, 0);
++ dvi_enabled = 0;
++}
++
++static struct omap_dss_device omap3_evm_dvi_device = {
++ .type = OMAP_DISPLAY_TYPE_DPI,
++ .name = "dvi",
++ .driver_name = "generic_panel",
++ .phy.dpi.data_lines = 24,
++ .platform_enable = omap3_evm_enable_dvi,
++ .platform_disable = omap3_evm_disable_dvi,
++};
++
++static struct omap_dss_device *omap3_evm_dss_devices[] = {
++ &omap3_evm_lcd_device,
++ &omap3_evm_tv_device,
++ &omap3_evm_dvi_device,
++};
++
++static struct omap_dss_board_info omap3_evm_dss_data = {
++ .num_devices = ARRAY_SIZE(omap3_evm_dss_devices),
++ .devices = omap3_evm_dss_devices,
++ .default_device = &omap3_evm_lcd_device,
++};
++
++static struct platform_device omap3_evm_dss_device = {
++ .name = "omapdss",
++ .id = -1,
++ .dev = {
++ .platform_data = &omap3_evm_dss_data,
++ },
++};
+
+ static struct omap_uart_platform_data omap3_evm_uart_config __initdata = {
+ .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
+@@ -143,6 +313,14 @@ static int omap3evm_twl_gpio_setup(struct device *dev,
+ * the P2 connector; notably LEDA for the LCD backlight.
+ */
+
++ /* TWL4030_GPIO_MAX + 0 == ledA, LCD Backlight control */
++ gpio_request(gpio + TWL4030_GPIO_MAX, "EN_LCD_BKL");
++ gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0);
++
++ /* gpio + 7 == DVI Enable */
++ gpio_request(gpio + 7, "EN_DVI");
++ gpio_direction_output(gpio + 7, 0);
++
+ /* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
+ gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
+
+@@ -194,6 +372,47 @@ static struct twl4030_madc_platform_data omap3evm_madc_data = {
+ .irq_line = 1,
+ };
+
++static struct regulator_consumer_supply omap3_evm_vdda_dac_supply = {
++ .supply = "vdda_dac",
++ .dev = &omap3_evm_dss_device.dev,
++};
++
++/* VDAC for DSS driving S-Video */
++static struct regulator_init_data omap3_evm_vdac = {
++ .constraints = {
++ .min_uV = 1800000,
++ .max_uV = 1800000,
++ .apply_uV = true,
++ .valid_modes_mask = REGULATOR_MODE_NORMAL
++ | REGULATOR_MODE_STANDBY,
++ .valid_ops_mask = REGULATOR_CHANGE_MODE
++ | REGULATOR_CHANGE_STATUS,
++ },
++ .num_consumer_supplies = 1,
++ .consumer_supplies = &omap3_evm_vdda_dac_supply,
++};
++
++/* VPLL2 for digital video outputs */
++static struct regulator_consumer_supply omap3_evm_vpll2_supply = {
++ .supply = "vdvi",
++ .dev = &omap3_evm_lcd_device.dev,
++};
++
++static struct regulator_init_data omap3_evm_vpll2 = {
++ .constraints = {
++ .name = "VDVI",
++ .min_uV = 1800000,
++ .max_uV = 1800000,
++ .apply_uV = true,
++ .valid_modes_mask = REGULATOR_MODE_NORMAL
++ | REGULATOR_MODE_STANDBY,
++ .valid_ops_mask = REGULATOR_CHANGE_MODE
++ | REGULATOR_CHANGE_STATUS,
++ },
++ .num_consumer_supplies = 1,
++ .consumer_supplies = &omap3_evm_vpll2_supply,
++};
++
+ static struct twl4030_platform_data omap3evm_twldata = {
+ .irq_base = TWL4030_IRQ_BASE,
+ .irq_end = TWL4030_IRQ_END,
+@@ -203,6 +422,8 @@ static struct twl4030_platform_data omap3evm_twldata = {
+ .madc = &omap3evm_madc_data,
+ .usb = &omap3evm_usb_data,
+ .gpio = &omap3evm_gpio_data,
++ .vdac = &omap3_evm_vdac,
++ .vpll2 = &omap3_evm_vpll2,
+ };
+
+ static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
+@@ -223,15 +444,6 @@ static int __init omap3_evm_i2c_init(void)
+ return 0;
+ }
+
+-static struct platform_device omap3_evm_lcd_device = {
+- .name = "omap3evm_lcd",
+- .id = -1,
+-};
+-
+-static struct omap_lcd_config omap3_evm_lcd_config __initdata = {
+- .ctrl_name = "internal",
+-};
+-
+ static void ads7846_dev_init(void)
+ {
+ if (gpio_request(OMAP3_EVM_TS_GPIO, "ADS7846 pendown") < 0)
+@@ -287,11 +499,10 @@ static void __init omap3_evm_init_irq(void)
+ }
+
+ static struct omap_board_config_kernel omap3_evm_config[] __initdata = {
+- { OMAP_TAG_LCD, &omap3_evm_lcd_config },
+ };
+
+ static struct platform_device *omap3_evm_devices[] __initdata = {
+- &omap3_evm_lcd_device,
++ &omap3_evm_dss_device,
+ &omap3evm_smc911x_device,
+ };
+
+@@ -314,6 +525,7 @@ static void __init omap3_evm_init(void)
+ usb_musb_init();
+ usb_ehci_init(EHCI_HCD_OMAP_MODE_PHY, true, true, 57, 61);
+ ads7846_dev_init();
++ omap3_evm_display_init();
+ }
+
+ static void __init omap3_evm_map_io(void)
+--
+1.6.2.4
+
diff --git a/recipes/linux/linux-omap-2.6.31/dss2/0002-V4L2-Added-New-V4L2-CIDs-for-omap-devices-V4L2-IOCT.patch b/recipes/linux/linux-omap-2.6.31/dss2/0002-V4L2-Added-New-V4L2-CIDs-for-omap-devices-V4L2-IOCT.patch
new file mode 100644
index 0000000000..f05929088f
--- /dev/null
+++ b/recipes/linux/linux-omap-2.6.31/dss2/0002-V4L2-Added-New-V4L2-CIDs-for-omap-devices-V4L2-IOCT.patch
@@ -0,0 +1,152 @@
+From bcb3cd3f6dd8d80a4f7cc524b769d711addfc48d Mon Sep 17 00:00:00 2001
+From: Vaibhav Hiremath <hvaibhav@ti.com>
+Date: Wed, 22 Jul 2009 23:49:29 +0530
+Subject: [PATCH 2/5] V4L2: Added New V4L2 CIDs for omap devices V4L2 IOCTL
+
+Changes -
+ - Renamed V4L2_CID_ROTATION to V4L2_CID_ROTATE
+ - Implementationadded for VIDIOC_S/G_COLOR_SPACE_CONV
+
+Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
+---
+ drivers/media/video/v4l2-ioctl.c | 19 +++++++++++++++++++
+ include/linux/videodev2.h | 21 ++++++++++++++++++---
+ include/media/v4l2-ioctl.h | 4 ++++
+ 3 files changed, 41 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
+index f2afc4e..74d2ed9 100644
+--- a/drivers/media/video/v4l2-ioctl.c
++++ b/drivers/media/video/v4l2-ioctl.c
+@@ -278,6 +278,8 @@ static const char *v4l2_ioctls[] = {
+ [_IOC_NR(VIDIOC_DBG_G_CHIP_IDENT)] = "VIDIOC_DBG_G_CHIP_IDENT",
+ [_IOC_NR(VIDIOC_S_HW_FREQ_SEEK)] = "VIDIOC_S_HW_FREQ_SEEK",
+ #endif
++ [_IOC_NR(VIDIOC_S_COLOR_SPACE_CONV)] = "VIDIOC_S_COLOR_SPACE_CONV",
++ [_IOC_NR(VIDIOC_G_COLOR_SPACE_CONV)] = "VIDIOC_G_COLOR_SPACE_CONV",
+ };
+ #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
+
+@@ -1784,6 +1786,23 @@ static long __video_do_ioctl(struct file *file,
+ break;
+ }
+
++ /*---------------Color space conversion------------------------------*/
++ case VIDIOC_S_COLOR_SPACE_CONV:
++ {
++ struct v4l2_color_space_conversion *p = arg;
++ if (!ops->vidioc_s_color_space_conv)
++ break;
++ ret = ops->vidioc_s_color_space_conv(file, fh, p);
++ break;
++ }
++ case VIDIOC_G_COLOR_SPACE_CONV:
++ {
++ struct v4l2_color_space_conversion *p = arg;
++ if (!ops->vidioc_g_color_space_conv)
++ break;
++ ret = ops->vidioc_g_color_space_conv(file, fh, p);
++ break;
++ }
+ default:
+ {
+ if (!ops->vidioc_default)
+diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
+index 74f1687..78e8158 100644
+--- a/include/linux/videodev2.h
++++ b/include/linux/videodev2.h
+@@ -554,6 +554,7 @@ struct v4l2_framebuffer {
+ #define V4L2_FBUF_CAP_LOCAL_ALPHA 0x0010
+ #define V4L2_FBUF_CAP_GLOBAL_ALPHA 0x0020
+ #define V4L2_FBUF_CAP_LOCAL_INV_ALPHA 0x0040
++#define V4L2_FBUF_CAP_SRC_CHROMAKEY 0x0080
+ /* Flags for the 'flags' field. */
+ #define V4L2_FBUF_FLAG_PRIMARY 0x0001
+ #define V4L2_FBUF_FLAG_OVERLAY 0x0002
+@@ -561,6 +562,7 @@ struct v4l2_framebuffer {
+ #define V4L2_FBUF_FLAG_LOCAL_ALPHA 0x0008
+ #define V4L2_FBUF_FLAG_GLOBAL_ALPHA 0x0010
+ #define V4L2_FBUF_FLAG_LOCAL_INV_ALPHA 0x0020
++#define V4L2_FBUF_FLAG_SRC_CHROMAKEY 0x0040
+
+ struct v4l2_clip {
+ struct v4l2_rect c;
+@@ -902,6 +904,8 @@ enum v4l2_colorfx {
+
+ /* last CID + 1 */
+ #define V4L2_CID_LASTP1 (V4L2_CID_BASE+33)
++#define V4L2_CID_ROTATE (V4L2_CID_BASE+34)
++#define V4L2_CID_BG_COLOR (V4L2_CID_BASE+35)
+
+ /* MPEG-class control IDs defined by V4L2 */
+ #define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900)
+@@ -1213,6 +1217,18 @@ struct v4l2_hw_freq_seek {
+ };
+
+ /*
++ * Color conversion
++ * User needs to pass pointer to color conversion matrix
++ * defined by hardware
++ */
++struct v4l2_color_space_conversion {
++ __s32 coefficients[3][3];
++ __s32 const_factor;
++ __s32 input_offs[3];
++ __s32 output_offs[3];
++};
++
++/*
+ * A U D I O
+ */
+ struct v4l2_audio {
+@@ -1265,7 +1281,6 @@ struct v4l2_enc_idx {
+ struct v4l2_enc_idx_entry entry[V4L2_ENC_IDX_ENTRIES];
+ };
+
+-
+ #define V4L2_ENC_CMD_START (0)
+ #define V4L2_ENC_CMD_STOP (1)
+ #define V4L2_ENC_CMD_PAUSE (2)
+@@ -1286,7 +1301,6 @@ struct v4l2_encoder_cmd {
+
+ #endif
+
+-
+ /*
+ * D A T A S E R V I C E S ( V B I )
+ *
+@@ -1423,7 +1437,6 @@ struct v4l2_format {
+ } fmt;
+ };
+
+-
+ /* Stream type-dependent parameters
+ */
+ struct v4l2_streamparm {
+@@ -1551,6 +1564,8 @@ struct v4l2_dbg_chip_ident {
+ #endif
+
+ #define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek)
++#define VIDIOC_S_COLOR_SPACE_CONV _IOW('V', 83, struct v4l2_color_space_conversion)
++#define VIDIOC_G_COLOR_SPACE_CONV _IOR('V', 84, struct v4l2_color_space_conversion)
+ /* Reminder: when adding new ioctls please add support for them to
+ drivers/media/video/v4l2-compat-ioctl32.c as well! */
+
+diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
+index 7a4529d..6f46d09 100644
+--- a/include/media/v4l2-ioctl.h
++++ b/include/media/v4l2-ioctl.h
+@@ -242,6 +242,10 @@ struct v4l2_ioctl_ops {
+ /* For other private ioctls */
+ long (*vidioc_default) (struct file *file, void *fh,
+ int cmd, void *arg);
++ int (*vidioc_s_color_space_conv) (struct file *file, void *fh,
++ struct v4l2_color_space_conversion *a);
++ int (*vidioc_g_color_space_conv) (struct file *file, void *fh,
++ struct v4l2_color_space_conversion *a);
+ };
+
+
+--
+1.6.2.4
+
diff --git a/recipes/linux/linux-omap-2.6.31/dss2/0003-V4L2-Updated-v4l2_common-for-new-V4L2-CIDs.patch b/recipes/linux/linux-omap-2.6.31/dss2/0003-V4L2-Updated-v4l2_common-for-new-V4L2-CIDs.patch
new file mode 100644
index 0000000000..0fd8135bb1
--- /dev/null
+++ b/recipes/linux/linux-omap-2.6.31/dss2/0003-V4L2-Updated-v4l2_common-for-new-V4L2-CIDs.patch
@@ -0,0 +1,40 @@
+From 691a4534df820b6c90a37de1941197efbe86984a Mon Sep 17 00:00:00 2001
+From: Vaibhav Hiremath <hvaibhav@ti.com>
+Date: Fri, 21 Aug 2009 11:19:46 +0530
+Subject: [PATCH 3/5] V4L2: Updated v4l2_common for new V4L2 CIDs.
+
+Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
+---
+ drivers/media/video/v4l2-common.c | 9 +++++++++
+ 1 files changed, 9 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
+index b91d66a..5dae426 100644
+--- a/drivers/media/video/v4l2-common.c
++++ b/drivers/media/video/v4l2-common.c
+@@ -421,6 +421,8 @@ const char *v4l2_ctrl_get_name(u32 id)
+ case V4L2_CID_CHROMA_AGC: return "Chroma AGC";
+ case V4L2_CID_COLOR_KILLER: return "Color Killer";
+ case V4L2_CID_COLORFX: return "Color Effects";
++ case V4L2_CID_ROTATE: return "Rotate";
++ case V4L2_CID_BG_COLOR: return "Background color";
+
+ /* MPEG controls */
+ case V4L2_CID_MPEG_CLASS: return "MPEG Encoder Controls";
+@@ -546,6 +548,13 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
+ qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ min = max = step = def = 0;
+ break;
++ case V4L2_CID_BG_COLOR:
++ qctrl->type = V4L2_CTRL_TYPE_INTEGER;
++ step = 1;
++ min = 0;
++ /* Max is calculated as RGB888 that is 2^12*/
++ max = 0xFFFFFF;
++ break;
+ default:
+ qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ break;
+--
+1.6.2.4
+
diff --git a/recipes/linux/linux-omap-2.6.31/dss2/0004-OMAP2-3-V4L2-Add-support-for-OMAP2-3-V4L2-driver-on.patch b/recipes/linux/linux-omap-2.6.31/dss2/0004-OMAP2-3-V4L2-Add-support-for-OMAP2-3-V4L2-driver-on.patch
new file mode 100644
index 0000000000..5db9c65d41
--- /dev/null
+++ b/recipes/linux/linux-omap-2.6.31/dss2/0004-OMAP2-3-V4L2-Add-support-for-OMAP2-3-V4L2-driver-on.patch
@@ -0,0 +1,3248 @@
+From 2ae2dbacb82c5f0cb0fbcde7b49510d5cf2d45b5 Mon Sep 17 00:00:00 2001
+From: Vaibhav Hiremath <hvaibhav@ti.com>
+Date: Wed, 12 Aug 2009 19:38:30 +0530
+Subject: [PATCH 4/5] OMAP2/3 V4L2: Add support for OMAP2/3 V4L2 driver on top of DSS2
+
+Features Supported -
+ 1. Provides V4L2 user interface for the video pipelines of DSS
+ 2. Basic streaming working on LCD, DVI and TV.
+ 3. Works on latest DSS2 library from Tomi
+ 4. Support for various pixel formats like YUV, UYVY, RGB32, RGB24,
+ RGB565
+ 5. Supports Alpha blending.
+ 6. Supports Color keying both source and destination.
+ 7. Supports rotation.
+ 8. Supports cropping.
+ 9. Supports Background color setting.
+
+TODO:
+ 1. Complete Testing is pending, only basic test passed.
+
+Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
+---
+ arch/arm/plat-omap/devices.c | 29 +
+ drivers/media/video/Kconfig | 12 +
+ drivers/media/video/Makefile | 2 +
+ drivers/media/video/omap/Kconfig | 22 +
+ drivers/media/video/omap/Makefile | 2 +
+ drivers/media/video/omap/omap_vout.c | 2623 +++++++++++++++++++++++++++++++
+ drivers/media/video/omap/omap_voutdef.h | 148 ++
+ drivers/media/video/omap/omap_voutlib.c | 258 +++
+ drivers/media/video/omap/omap_voutlib.h | 34 +
+ 9 files changed, 3130 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/media/video/omap/Kconfig
+ create mode 100644 drivers/media/video/omap/Makefile
+ create mode 100644 drivers/media/video/omap/omap_vout.c
+ create mode 100644 drivers/media/video/omap/omap_voutdef.h
+ create mode 100644 drivers/media/video/omap/omap_voutlib.c
+ create mode 100644 drivers/media/video/omap/omap_voutlib.h
+
+diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
+index a64b692..8b6a9a0 100644
+--- a/arch/arm/plat-omap/devices.c
++++ b/arch/arm/plat-omap/devices.c
+@@ -357,6 +357,34 @@ static void omap_init_rng(void)
+ static inline void omap_init_rng(void) {}
+ #endif
+
++/*---------------------------------------------------------------------------*/
++
++#if defined(CONFIG_VIDEO_OMAP_VIDEOOUT) || \
++ defined(CONFIG_VIDEO_OMAP_VIDEOOUT_MODULE)
++#ifdef CONFIG_FB_OMAP2
++static struct resource omap3evm_vout_resource[3 - CONFIG_FB_OMAP2_NUM_FBS] = {
++};
++#else
++static struct resource omap3evm_vout_resource[2] = {
++};
++#endif
++
++static struct platform_device omap3evm_vout_device = {
++ .name = "omap_vout",
++ .num_resources = ARRAY_SIZE(omap3evm_vout_resource),
++ .resource = &omap3evm_vout_resource[0],
++ .id = -1,
++};
++static void omap_init_vout(void)
++{
++ (void) platform_device_register(&omap3evm_vout_device);
++}
++#else
++static inline void omap_init_vout(void) {}
++#endif
++
++/*---------------------------------------------------------------------------*/
++
+ /*
+ * This gets called after board-specific INIT_MACHINE, and initializes most
+ * on-chip peripherals accessible on this board (except for few like USB):
+@@ -387,6 +415,7 @@ static int __init omap_init_devices(void)
+ omap_init_uwire();
+ omap_init_wdt();
+ omap_init_rng();
++ omap_init_vout();
+ return 0;
+ }
+ arch_initcall(omap_init_devices);
+diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
+index dcf9fa9..afb4478 100644
+--- a/drivers/media/video/Kconfig
++++ b/drivers/media/video/Kconfig
+@@ -718,6 +718,18 @@ config VIDEO_CAFE_CCIC
+ CMOS camera controller. This is the controller found on first-
+ generation OLPC systems.
+
++config VIDEO_OMAP3
++ bool "OMAP2/OMAP3 Camera and V4L2-DSS drivers"
++ select VIDEOBUF_GEN
++ select VIDEOBUF_DMA_SG
++ select OMAP2_DSS
++ depends on VIDEO_DEV && (ARCH_OMAP24XX || ARCH_OMAP34XX)
++ default y
++ ---help---
++ V4L2 DSS and Camera driver support for OMAP2/3 based boards.
++
++source "drivers/media/video/omap/Kconfig"
++
+ config SOC_CAMERA
+ tristate "SoC camera support"
+ depends on VIDEO_V4L2 && HAS_DMA && I2C
+diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
+index 9f2e321..36040b9 100644
+--- a/drivers/media/video/Makefile
++++ b/drivers/media/video/Makefile
+@@ -117,6 +117,8 @@ obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
+
+ obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
+
++obj-$(CONFIG_VIDEO_OMAP3) += omap/
++
+ obj-$(CONFIG_USB_DABUSB) += dabusb.o
+ obj-$(CONFIG_USB_OV511) += ov511.o
+ obj-$(CONFIG_USB_SE401) += se401.o
+diff --git a/drivers/media/video/omap/Kconfig b/drivers/media/video/omap/Kconfig
+new file mode 100644
+index 0000000..5b86db3
+--- /dev/null
++++ b/drivers/media/video/omap/Kconfig
+@@ -0,0 +1,22 @@
++config VIDEO_OMAP_VIDEOOUT
++ tristate "OMAP Video out driver"
++ select VIDEOBUF_DMA_SG
++ select VIDEOBUF_GEN
++ depends on VIDEO_OMAP3
++ default VIDEO_OMAP3
++
++choice
++ prompt "TV Mode"
++ default NTSC_M
++
++config NTSC_M
++ bool "Use NTSC_M mode"
++ help
++ Select this option if you want NTSC_M mode on TV
++
++config PAL_BDGHI
++ bool "Use PAL_BDGHI mode"
++ help
++ Select this option if you want PAL_BDGHI mode on TV
++
++endchoice
+diff --git a/drivers/media/video/omap/Makefile b/drivers/media/video/omap/Makefile
+new file mode 100644
+index 0000000..18854c7
+--- /dev/null
++++ b/drivers/media/video/omap/Makefile
+@@ -0,0 +1,2 @@
++obj-$(CONFIG_VIDEO_OMAP_VIDEOOUT) += omap_vout.o omap_voutlib.o
++
+diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c
+new file mode 100644
+index 0000000..7e15db2
+--- /dev/null
++++ b/drivers/media/video/omap/omap_vout.c
+@@ -0,0 +1,2623 @@
++/*
++ * drivers/media/video/omap/omap_vout.c
++ *
++ * Copyright (C) 2005-2009 Texas Instruments.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ *
++ * Leveraged code from the OMAP2 camera driver
++ * Video-for-Linux (Version 2) camera capture driver for
++ * the OMAP24xx camera controller.
++ *
++ * Author: Andy Lowe (source@mvista.com)
++ *
++ * Copyright (C) 2004 MontaVista Software, Inc.
++ * Copyright (C) 2009 Texas Instruments.
++ *
++ * History:
++ * 20-APR-2006 Khasim Modified VRFB based Rotation,
++ * The image data is always read from 0 degree
++ * view and written
++ * to the virtual space of desired rotation angle
++ * 4-DEC-2006 Jian Changed to support better memory management
++ *
++ * 17-Nov-2008 Hardik Changed to used the new DSS paches by Tomi
++ * Changed driver to use video_ioctl2
++ *
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/fs.h>
++#include <linux/kernel.h>
++#include <linux/vmalloc.h>
++#include <linux/interrupt.h>
++#include <linux/kdev_t.h>
++#include <linux/types.h>
++#include <linux/wait.h>
++#include <linux/videodev2.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/irq.h>
++
++#include <media/videobuf-dma-sg.h>
++#include <media/v4l2-dev.h>
++#include <media/v4l2-ioctl.h>
++#include <media/v4l2-common.h>
++#include <media/v4l2-device.h>
++
++#include <asm/processor.h>
++#include <mach/dma.h>
++#include <mach/vram.h>
++#include <mach/vrfb.h>
++#include <mach/display.h>
++
++#include "omap_voutlib.h"
++#include "omap_voutdef.h"
++
++MODULE_AUTHOR("Texas Instruments.");
++MODULE_DESCRIPTION("OMAP Video for Linux Video out driver");
++MODULE_LICENSE("GPL");
++
++#define OMAP_VIDEO1 0
++#define OMAP_VIDEO2 1
++
++/* configuration macros */
++#define VOUT_NAME "omap_vout"
++
++#define QQVGA_WIDTH 160
++#define QQVGA_HEIGHT 120
++
++#define NUM_OF_VIDEO_CHANNELS 2
++
++#define VID_MAX_WIDTH 1280 /* Largest width */
++#define VID_MAX_HEIGHT 720/* Largest height */
++
++/* Mimimum requirement is 2x2 for DSS */
++#define VID_MIN_WIDTH 2
++#define VID_MIN_HEIGHT 2
++
++/* 2048 x 2048 is max res supported by OMAP display controller */
++#define DMA_CHAN_ALLOTED 1
++#define DMA_CHAN_NOT_ALLOTED 0
++#define MAX_PIXELS_PER_LINE 2048
++#define VRFB_TX_TIMEOUT 1000
++
++/* IRQ Bits mask of DSS */
++#define OMAP_VOUT_MAX_BUF_SIZE (VID_MAX_WIDTH*VID_MAX_HEIGHT*4)
++
++static struct videobuf_queue_ops video_vbq_ops;
++
++static u32 video1_numbuffers = 3;
++static u32 video2_numbuffers = 3;
++static u32 video1_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
++static u32 video2_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
++static u32 vid1_static_vrfb_alloc;
++static u32 vid2_static_vrfb_alloc;
++static int debug;
++
++/* Module parameters */
++module_param(video1_numbuffers, uint, S_IRUGO);
++MODULE_PARM_DESC(video1_numbuffers,
++ "Number of buffers to be allocated at init time for Video1 device.");
++
++module_param(video2_numbuffers, uint, S_IRUGO);
++MODULE_PARM_DESC(video2_numbuffers,
++ "Number of buffers to be allocated at init time for Video2 device.");
++
++module_param(video1_bufsize, uint, S_IRUGO);
++MODULE_PARM_DESC(video1_bufsize,
++ "Size of the buffer to be allocated for video1 device");
++
++module_param(video2_bufsize, uint, S_IRUGO);
++MODULE_PARM_DESC(video2_bufsize,
++ "Size of the buffer to be allocated for video2 device");
++
++module_param(vid1_static_vrfb_alloc, bool, S_IRUGO);
++MODULE_PARM_DESC(vid1_static_vrfb_alloc,
++ "Static allocation of the VRFB buffer for video1 device");
++
++module_param(vid2_static_vrfb_alloc, bool, S_IRUGO);
++MODULE_PARM_DESC(vid2_static_vrfb_alloc,
++ "Static allocation of the VRFB buffer for video2 device");
++
++module_param(debug, bool, S_IRUGO);
++MODULE_PARM_DESC(debug, "Debug level (0-1)");
++
++/* Local Helper functions */
++static void omap_vout_isr(void *arg, unsigned int irqstatus);
++static void omap_vout_cleanup_device(struct omap_vout_device *vout);
++/*
++ * Maximum amount of memory to use for rendering buffers.
++ * Default is enough to four (RGB24) DVI 720P buffers.
++ */
++#define MAX_ALLOWED_VIDBUFFERS 4
++
++/* list of image formats supported by OMAP2 video pipelines */
++const static struct v4l2_fmtdesc omap_formats[] = {
++ {
++ /* Note: V4L2 defines RGB565 as:
++ *
++ * Byte 0 Byte 1
++ * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3
++ *
++ * We interpret RGB565 as:
++ *
++ * Byte 0 Byte 1
++ * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3
++ */
++ .description = "RGB565, le",
++ .pixelformat = V4L2_PIX_FMT_RGB565,
++ },
++ {
++ /* Note: V4L2 defines RGB32 as: RGB-8-8-8-8 we use
++ * this for RGB24 unpack mode, the last 8 bits are ignored
++ * */
++ .description = "RGB32, le",
++ .pixelformat = V4L2_PIX_FMT_RGB32,
++ },
++ {
++ /* Note: V4L2 defines RGB24 as: RGB-8-8-8 we use
++ * this for RGB24 packed mode
++ *
++ */
++ .description = "RGB24, le",
++ .pixelformat = V4L2_PIX_FMT_RGB24,
++ },
++ {
++ .description = "YUYV (YUV 4:2:2), packed",
++ .pixelformat = V4L2_PIX_FMT_YUYV,
++ },
++ {
++ .description = "UYVY, packed",
++ .pixelformat = V4L2_PIX_FMT_UYVY,
++ },
++};
++
++#define NUM_OUTPUT_FORMATS (ARRAY_SIZE(omap_formats))
++
++/* Allocate buffers */
++static unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr)
++{
++ unsigned long virt_addr, addr;
++ u32 order, size;
++
++ size = PAGE_ALIGN(buf_size);
++ order = get_order(size);
++ virt_addr = __get_free_pages(GFP_KERNEL | GFP_DMA, order);
++ addr = virt_addr;
++
++ if (virt_addr) {
++ while (size > 0) {
++ SetPageReserved(virt_to_page(addr));
++ addr += PAGE_SIZE;
++ size -= PAGE_SIZE;
++ }
++ }
++ *phys_addr = (u32) virt_to_phys((void *) virt_addr);
++ return virt_addr;
++}
++
++/* Free buffers */
++static void omap_vout_free_buffer(unsigned long virtaddr, u32 phys_addr,
++ u32 buf_size)
++{
++ unsigned long addr = virtaddr;
++ u32 order, size;
++
++ size = PAGE_ALIGN(buf_size);
++ order = get_order(size);
++
++ while (size > 0) {
++ ClearPageReserved(virt_to_page(addr));
++ addr += PAGE_SIZE;
++ size -= PAGE_SIZE;
++ }
++ free_pages((unsigned long) virtaddr, order);
++}
++
++/* Function for allocating video buffers */
++static int omap_vout_allocate_vrfb_buffers(struct omap_vout_device *vout,
++ unsigned int *count, int startindex)
++{
++ int i, j;
++
++ for (i = 0; i < *count; i++) {
++ if (!vout->smsshado_virt_addr[i]) {
++ vout->smsshado_virt_addr[i] =
++ omap_vout_alloc_buffer(vout->smsshado_size,
++ &vout->smsshado_phy_addr[i]);
++ }
++ if (!vout->smsshado_virt_addr[i] && startindex != -1) {
++ if (V4L2_MEMORY_MMAP == vout->memory
++ && i >= startindex)
++ break;
++ }
++ if (!vout->smsshado_virt_addr[i]) {
++ for (j = 0; j < i; j++) {
++ omap_vout_free_buffer(
++ vout->smsshado_virt_addr[j],
++ vout->smsshado_phy_addr[j],
++ vout->smsshado_size);
++ vout->smsshado_virt_addr[j] = 0;
++ vout->smsshado_phy_addr[j] = 0;
++ }
++ *count = 0;
++ return -ENOMEM;
++ }
++ memset((void *) vout->smsshado_virt_addr[i], 0,
++ vout->smsshado_size);
++ }
++ return 0;
++}
++
++/* Try format */
++static int omap_vout_try_format(struct v4l2_pix_format *pix)
++{
++ int ifmt, bpp = 0;
++
++ pix->height = clamp(pix->height, (u32)VID_MIN_HEIGHT,
++ (u32)VID_MAX_HEIGHT);
++ pix->width = clamp(pix->width, (u32)VID_MIN_WIDTH, (u32)VID_MAX_WIDTH);
++
++ for (ifmt = 0; ifmt < NUM_OUTPUT_FORMATS; ifmt++) {
++ if (pix->pixelformat == omap_formats[ifmt].pixelformat)
++ break;
++ }
++
++ if (ifmt == NUM_OUTPUT_FORMATS)
++ ifmt = 0;
++
++ pix->pixelformat = omap_formats[ifmt].pixelformat;
++ pix->field = V4L2_FIELD_ANY;
++ pix->priv = 0;
++
++ switch (pix->pixelformat) {
++ case V4L2_PIX_FMT_YUYV:
++ case V4L2_PIX_FMT_UYVY:
++ default:
++ pix->colorspace = V4L2_COLORSPACE_JPEG;
++ bpp = YUYV_BPP;
++ break;
++ case V4L2_PIX_FMT_RGB565:
++ case V4L2_PIX_FMT_RGB565X:
++ pix->colorspace = V4L2_COLORSPACE_SRGB;
++ bpp = RGB565_BPP;
++ break;
++ case V4L2_PIX_FMT_RGB24:
++ pix->colorspace = V4L2_COLORSPACE_SRGB;
++ bpp = RGB24_BPP;
++ break;
++ case V4L2_PIX_FMT_RGB32:
++ case V4L2_PIX_FMT_BGR32:
++ pix->colorspace = V4L2_COLORSPACE_SRGB;
++ bpp = RGB32_BPP;
++ break;
++ }
++ pix->bytesperline = pix->width * bpp;
++ pix->sizeimage = pix->bytesperline * pix->height;
++ return bpp;
++}
++
++/*
++ * omap_vout_uservirt_to_phys: This inline function is used to convert user
++ * space virtual address to physical address.
++ */
++static inline u32 omap_vout_uservirt_to_phys(u32 virtp)
++{
++ unsigned long physp = 0;
++ struct mm_struct *mm = current->mm;
++ struct vm_area_struct *vma;
++
++ vma = find_vma(mm, virtp);
++ /* For kernel direct-mapped memory, take the easy way */
++ if (virtp >= PAGE_OFFSET) {
++ physp = virt_to_phys((void *) virtp);
++ } else if (vma && (vma->vm_flags & VM_IO)
++ && vma->vm_pgoff) {
++ /* this will catch, kernel-allocated,
++ mmaped-to-usermode addresses */
++ physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start);
++ } else {
++ /* otherwise, use get_user_pages() for general userland pages */
++ int res, nr_pages = 1;
++ struct page *pages;
++ down_read(&current->mm->mmap_sem);
++
++ res = get_user_pages(current, current->mm, virtp, nr_pages,
++ 1, 0, &pages, NULL);
++ up_read(&current->mm->mmap_sem);
++
++ if (res == nr_pages) {
++ physp = __pa(page_address(&pages[0]) +
++ (virtp & ~PAGE_MASK));
++ } else {
++ printk(KERN_WARNING VOUT_NAME
++ "get_user_pages failed\n");
++ return 0;
++ }
++ }
++
++ return physp;
++}
++
++/* This functions wakes up the application once
++ * the DMA transfer to VRFB space is completed. */
++static void omap_vout_vrfb_dma_tx_callback(int lch, u16 ch_status, void *data)
++{
++ struct vid_vrfb_dma *t = (struct vid_vrfb_dma *) data;
++
++ t->tx_status = 1;
++ wake_up_interruptible(&t->wait);
++}
++
++/* Release the VRFB context once the module exits */
++static void omap_vout_release_vrfb(struct omap_vout_device *vout)
++{
++ int i;
++
++ for (i = 0; i < 4; i++)
++ omap_vrfb_release_ctx(&vout->vrfb_context[i]);
++
++ if (vout->vrfb_dma_tx.req_status == DMA_CHAN_ALLOTED) {
++ vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
++ omap_free_dma(vout->vrfb_dma_tx.dma_ch);
++ }
++
++}
++
++/* Return true if rotation is 90 or 270 */
++static inline int rotate_90_or_270(const struct omap_vout_device *vout)
++{
++ return (vout->rotation == dss_rotation_90_degree ||
++ vout->rotation == dss_rotation_270_degree);
++}
++
++/* Return true if rotation is enabled */
++static inline int rotation_enabled(const struct omap_vout_device *vout)
++{
++ return vout->rotation || vout->mirror;
++}
++
++/* Reverse the rotation degree if mirroring is enabled */
++static inline int calc_rotation(const struct omap_vout_device *vout)
++{
++ if (!vout->mirror)
++ return vout->rotation;
++
++ switch (vout->rotation) {
++ case dss_rotation_90_degree:
++ return dss_rotation_270_degree;
++ case dss_rotation_270_degree:
++ return dss_rotation_90_degree;
++ case dss_rotation_180_degree:
++ return dss_rotation_0_degree;
++ default:
++ return dss_rotation_180_degree;
++ }
++}
++
++/* Free the V4L2 buffers */
++static void omap_vout_free_buffers(struct omap_vout_device *vout)
++{
++ int i, numbuffers;
++
++ /* Allocate memory for the buffers */
++ numbuffers = (vout->vid) ? video2_numbuffers : video1_numbuffers;
++ vout->buffer_size = (vout->vid) ? video2_bufsize : video1_bufsize;
++
++ for (i = 0; i < numbuffers; i++) {
++ omap_vout_free_buffer(vout->buf_virt_addr[i],
++ vout->buf_phy_addr[i], vout->buffer_size);
++ vout->buf_phy_addr[i] = 0;
++ vout->buf_virt_addr[i] = 0;
++ }
++}
++
++/* Free VRFB buffers */
++static void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout)
++{
++ int j;
++
++ for (j = 0; j < 4; j++) {
++ omap_vout_free_buffer(vout->smsshado_virt_addr[j],
++ vout->smsshado_phy_addr[j],
++ vout->smsshado_size);
++ vout->smsshado_virt_addr[j] = 0;
++ vout->smsshado_phy_addr[j] = 0;
++ }
++}
++
++/* Allocate the buffers for the VRFB space. Data is copied from V4L2
++ * buffers to the VRFB buffers using the DMA engine.*/
++static int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
++ unsigned int *count, unsigned int startindex)
++{
++ int i;
++ bool yuv_mode;
++
++ /* Allocate the VRFB buffers only if the buffers are not
++ * allocated during init time.
++ */
++ if ((rotation_enabled(vout)) &&
++ !vout->vrfb_static_allocation)
++ if (omap_vout_allocate_vrfb_buffers(vout, count, startindex))
++ return -ENOMEM;
++
++ if (vout->dss_mode == OMAP_DSS_COLOR_YUV2 ||
++ vout->dss_mode == OMAP_DSS_COLOR_UYVY)
++ yuv_mode = true;
++ else
++ yuv_mode = false;
++
++ for (i = 0; i < *count; i++) {
++ omap_vrfb_setup(&vout->vrfb_context[i],
++ vout->smsshado_phy_addr[i],
++ vout->pix.width, vout->pix.height,
++ vout->bpp, yuv_mode);
++ }
++ return 0;
++}
++
++/* Convert V4L2 rotation to DSS rotation
++ * V4L2 understand 0, 90, 180, 270.
++ * convert to 0, 1, 2 and 3 repsectively for DSS */
++static int v4l2_rot_to_dss_rot(int v4l2_rotation, enum dss_rotation *rotation,
++ bool mirror)
++{
++ switch (v4l2_rotation) {
++ case 90:
++ *rotation = dss_rotation_90_degree;
++ return 0;
++ case 180:
++ *rotation = dss_rotation_180_degree;
++ return 0;
++ case 270:
++ *rotation = dss_rotation_270_degree;
++ return 0;
++ case 0:
++ *rotation = dss_rotation_0_degree;
++ return 0;
++ default:
++ return -EINVAL;
++ }
++
++}
++
++/* Calculate the buffer offsets from which the streaming should
++ * start. This offset calculation is mainly required because of
++ * the VRFB 32 pixels alignment with rotation
++ */
++static int omap_vout_calculate_offset(struct omap_vout_device *vout)
++{
++ struct v4l2_pix_format *pix = &vout->pix;
++ struct v4l2_rect *crop = &vout->crop;
++ enum dss_rotation rotation;
++ bool mirroring = vout->mirror;
++ int vr_ps = 1, ps = 2, temp_ps = 2;
++ int offset = 0, ctop = 0, cleft = 0, line_length = 0;
++ struct omapvideo_info *ovid;
++ struct omap_overlay *ovl;
++ struct omap_dss_device *cur_display;
++ int *cropped_offset = &vout->cropped_offset;
++
++ ovid = &vout->vid_info;
++ ovl = ovid->overlays[0];
++ /* get the display device attached to the overlay */
++ if (!ovl->manager || !ovl->manager->device)
++ return -1;
++ cur_display = ovl->manager->device;
++
++ rotation = calc_rotation(vout);
++
++ if (V4L2_PIX_FMT_YUYV == pix->pixelformat ||
++ V4L2_PIX_FMT_UYVY == pix->pixelformat) {
++ if (rotation_enabled(vout)) {
++ /*
++ * ps - Actual pixel size for YUYV/UYVY for
++ * VRFB/Mirroring is 4 bytes
++ * vr_ps - Virtually pixel size for YUYV/UYVY is
++ * 2 bytes
++ */
++ ps = 4;
++ vr_ps = 2;
++ } else {
++ ps = 2; /* otherwise the pixel size is 2 byte */
++ }
++ } else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat) {
++ ps = 4;
++ } else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat) {
++ ps = 3;
++ }
++ vout->ps = ps;
++ vout->vr_ps = vr_ps;
++ if (rotation_enabled(vout)) {
++ line_length = MAX_PIXELS_PER_LINE;
++ ctop = (pix->height - crop->height) - crop->top;
++ cleft = (pix->width - crop->width) - crop->left;
++ } else {
++ line_length = pix->width;
++ }
++ vout->line_length = line_length;
++ switch (rotation) {
++ case dss_rotation_90_degree:
++ offset = vout->vrfb_context[0].yoffset *
++ vout->vrfb_context[0].bytespp;
++ temp_ps = ps / vr_ps;
++ if (mirroring == 0) {
++ *cropped_offset = offset + line_length *
++ temp_ps * cleft + crop->top * temp_ps;
++ } else {
++ *cropped_offset = offset + line_length * temp_ps *
++ cleft + crop->top * temp_ps + (line_length *
++ ((crop->width / (vr_ps)) - 1) * ps);
++ }
++ break;
++ case dss_rotation_180_degree:
++ offset = ((MAX_PIXELS_PER_LINE * vout->vrfb_context[0].yoffset *
++ vout->vrfb_context[0].bytespp) +
++ (vout->vrfb_context[0].xoffset *
++ vout->vrfb_context[0].bytespp));
++ if (mirroring == 0) {
++ *cropped_offset = offset + (line_length * ps * ctop) +
++ (cleft / vr_ps) * ps;
++
++ } else {
++ *cropped_offset = offset + (line_length * ps * ctop) +
++ (cleft / vr_ps) * ps + (line_length *
++ (crop->height - 1) * ps);
++ }
++ break;
++ case dss_rotation_270_degree:
++ offset = MAX_PIXELS_PER_LINE * vout->vrfb_context[0].xoffset *
++ vout->vrfb_context[0].bytespp;
++ temp_ps = ps / vr_ps;
++ if (mirroring == 0) {
++ *cropped_offset = offset + line_length *
++ temp_ps * crop->left + ctop * ps;
++ } else {
++ *cropped_offset = offset + line_length *
++ temp_ps * crop->left + ctop * ps +
++ (line_length * ((crop->width / vr_ps) - 1) *
++ ps);
++ }
++ break;
++ case dss_rotation_0_degree:
++ if (mirroring == 0) {
++ *cropped_offset = (line_length * ps) *
++ crop->top + (crop->left / vr_ps) * ps;
++ } else {
++ *cropped_offset = (line_length * ps) *
++ crop->top + (crop->left / vr_ps) * ps +
++ (line_length * (crop->height - 1) * ps);
++ }
++ break;
++ default:
++ *cropped_offset = (line_length * ps * crop->top) /
++ vr_ps + (crop->left * ps) / vr_ps +
++ ((crop->width / vr_ps) - 1) * ps;
++ break;
++ }
++ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
++ "%s Offset:%x\n", __func__, *cropped_offset);
++ return 0;
++}
++
++/* convert V4L2 pixel format to DSS pixel format */
++static enum omap_color_mode video_mode_to_dss_mode(struct omap_vout_device
++ *vout)
++{
++ struct omap_overlay *ovl;
++ struct omapvideo_info *ovid;
++ struct v4l2_pix_format *pix = &vout->pix;
++
++ ovid = &vout->vid_info;
++ ovl = ovid->overlays[0];
++
++ switch (pix->pixelformat) {
++ case 0:
++ break;
++ case V4L2_PIX_FMT_YUYV:
++ return OMAP_DSS_COLOR_YUV2;
++
++ case V4L2_PIX_FMT_UYVY:
++ return OMAP_DSS_COLOR_UYVY;
++
++ case V4L2_PIX_FMT_RGB565:
++ return OMAP_DSS_COLOR_RGB16;
++
++ case V4L2_PIX_FMT_RGB24:
++ return OMAP_DSS_COLOR_RGB24P;
++
++ case V4L2_PIX_FMT_RGB32:
++ return (ovl->id == OMAP_DSS_VIDEO1) ?
++ OMAP_DSS_COLOR_RGB24U : OMAP_DSS_COLOR_ARGB32;
++ case V4L2_PIX_FMT_BGR32:
++ return OMAP_DSS_COLOR_RGBX32;
++
++ default:
++ return -EINVAL;
++ }
++ return -EINVAL;
++}
++
++/* Setup the overlay */
++int omapvid_setup_overlay(struct omap_vout_device *vout,
++ struct omap_overlay *ovl, int posx, int posy, int outw,
++ int outh, u32 addr)
++{
++ int r = 0;
++ enum omap_color_mode mode = 0;
++ enum dss_rotation rotation;
++ bool mirror;
++ int cropheight, cropwidth, pixheight, pixwidth;
++ struct omap_overlay_info info;
++
++ if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0 &&
++ (outw != vout->pix.width || outh != vout->pix.height)) {
++ r = -EINVAL;
++ goto err;
++ }
++
++ vout->dss_mode = video_mode_to_dss_mode(vout);
++
++ if (mode == -EINVAL) {
++ r = -EINVAL;
++ goto err;
++ }
++
++ rotation = vout->rotation;
++ mirror = vout->mirror;
++
++ /* Setup the input plane parameters according to
++ * rotation value selected.
++ */
++ if (rotate_90_or_270(vout)) {
++ cropheight = vout->crop.width;
++ cropwidth = vout->crop.height;
++ pixheight = vout->pix.width;
++ pixwidth = vout->pix.height;
++ } else {
++ cropheight = vout->crop.height;
++ cropwidth = vout->crop.width;
++ pixheight = vout->pix.height;
++ pixwidth = vout->pix.width;
++ }
++
++ ovl->get_overlay_info(ovl, &info);
++ info.paddr = addr;
++ info.vaddr = NULL;
++ info.width = cropwidth;
++ info.height = cropheight;
++ info.color_mode = vout->dss_mode;
++ info.mirror = mirror;
++ info.pos_x = posx;
++ info.pos_y = posy;
++ info.out_width = outw;
++ info.out_height = outh;
++ info.global_alpha = vout->win.global_alpha;
++ if (!rotation_enabled(vout)) {
++ info.rotation = 0;
++ info.rotation_type = OMAP_DSS_ROT_DMA;
++ info.screen_width = pixwidth;
++ } else {
++ info.rotation = vout->rotation;
++ info.rotation_type = OMAP_DSS_ROT_VRFB;
++ info.screen_width = 2048;
++ }
++
++ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
++ "%s info.enable=%d info.addr=%x info.width=%d\n info.height=%d "
++ "info.color_mode=%d info.rotation=%d info.mirror=%d\n "
++ "info.posx=%d info.posy=%d info.out_width = %d info.out_height=%d\n "
++ "info.rotation_type=%d info.screen_width=%d\n", __func__, info.enabled,
++ info.paddr, info.width, info.height, info.color_mode, info.rotation,
++ info.mirror, info.pos_x, info.pos_y, info.out_width, info.out_height,
++ info.rotation_type, info.screen_width);
++
++ r = ovl->set_overlay_info(ovl, &info);
++ if (r)
++ goto err;
++
++ return 0;
++err:
++ printk(KERN_WARNING VOUT_NAME "setup_overlay failed\n");
++ return r;
++}
++
++/* Initialize the overlay structure */
++int omapvid_init(struct omap_vout_device *vout, u32 addr)
++{
++ int r = 0;
++ struct omapvideo_info *ovid = &vout->vid_info;
++ struct omap_overlay *ovl;
++ int posx, posy;
++ int outw, outh, temp, rotation;
++ int i;
++ struct v4l2_window *win;
++ struct omap_video_timings *timing;
++
++ win = &vout->win;
++ rotation = vout->rotation;
++ for (i = 0; i < ovid->num_overlays; i++) {
++ ovl = ovid->overlays[i];
++ if (!ovl->manager || !ovl->manager->device)
++ return -EINVAL;
++
++ timing = &ovl->manager->device->panel.timings;
++
++ outw = win->w.width;
++ outh = win->w.height;
++ switch (rotation) {
++ case dss_rotation_90_degree:
++ /* Invert the height and width for 90
++ * and 270 degree rotation
++ */
++ temp = outw;
++ outw = outh;
++ outh = temp;
++ posy = (timing->y_res - win->w.width)-
++ win->w.left;
++ posx = win->w.top;
++ break;
++
++ case dss_rotation_180_degree:
++ posx = (timing->x_res - win->w.width) -
++ win->w.left;
++ posy = (timing->y_res - win->w.height) -
++ win->w.top;
++ break;
++
++ case dss_rotation_270_degree:
++ temp = outw;
++ outw = outh;
++ outh = temp;
++ posy = win->w.left;
++ posx = (timing->x_res - win->w.height)
++ - win->w.top;
++ break;
++
++ default:
++ posx = win->w.left;
++ posy = win->w.top;
++ break;
++ }
++
++ r = omapvid_setup_overlay(vout, ovl, posx, posy, outw,
++ outh, addr);
++ if (r)
++ goto err;
++ }
++ return 0;
++err:
++ printk(KERN_WARNING VOUT_NAME "apply_changes failed\n");
++ return r;
++}
++
++/* Apply the changes set the go bit of DSS */
++int omapvid_apply_changes(struct omap_vout_device *vout)
++{
++ struct omapvideo_info *ovid = &vout->vid_info;
++ struct omap_overlay *ovl;
++ int i;
++
++ for (i = 0; i < ovid->num_overlays; i++) {
++ ovl = ovid->overlays[i];
++ if (!ovl->manager || !ovl->manager->device)
++ return -EINVAL;
++ ovl->manager->apply(ovl->manager);
++ }
++ return 0;
++
++}
++
++/* Video buffer call backs */
++
++/* Buffer setup function is called by videobuf layer when REQBUF ioctl is
++ * called. This is used to setup buffers and return size and count of
++ * buffers allocated. After the call to this buffer, videobuf layer will
++ * setup buffer queue depending on the size and count of buffers
++ */
++static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
++ unsigned int *size)
++{
++ struct omap_vout_device *vout = q->priv_data;
++ int startindex = 0, i, j;
++ u32 phy_addr = 0, virt_addr = 0;
++
++ if (!vout)
++ return -EINVAL;
++
++ if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type)
++ return -EINVAL;
++
++ startindex = (vout->vid == OMAP_VIDEO1) ?
++ video1_numbuffers : video2_numbuffers;
++ if (V4L2_MEMORY_MMAP == vout->memory && *count < startindex)
++ *count = startindex;
++
++ if ((rotation_enabled(vout))
++ && *count > 4)
++ *count = 4;
++
++ /* If rotation is enabled, allocate memory for VRFB space also */
++ if (rotation_enabled(vout)) {
++ if (omap_vout_vrfb_buffer_setup(vout, count, startindex))
++ return -ENOMEM;
++ }
++
++ if (V4L2_MEMORY_MMAP != vout->memory)
++ return 0;
++
++ /* Now allocated the V4L2 buffers */
++ *size = vout->buffer_size;
++ startindex = (vout->vid == OMAP_VIDEO1) ?
++ video1_numbuffers : video2_numbuffers;
++ for (i = startindex; i < *count; i++) {
++ vout->buffer_size = *size;
++
++ virt_addr = omap_vout_alloc_buffer(vout->buffer_size,
++ &phy_addr);
++ if (!virt_addr) {
++ if (!rotation_enabled(vout))
++ break;
++ /* Free the VRFB buffers if no space for V4L2 buffers */
++ for (j = i; j < *count; j++) {
++ omap_vout_free_buffer(
++ vout->smsshado_virt_addr[j],
++ vout->smsshado_phy_addr[j],
++ vout->smsshado_size);
++ vout->smsshado_virt_addr[j] = 0;
++ vout->smsshado_phy_addr[j] = 0;
++ }
++ }
++ vout->buf_virt_addr[i] = virt_addr;
++ vout->buf_phy_addr[i] = phy_addr;
++ }
++ *count = vout->buffer_allocated = i;
++ return 0;
++}
++
++/* Free the V4L2 buffers additionally allocated than default
++ * number of buffers and free all the VRFB buffers */
++static void omap_vout_free_allbuffers(struct omap_vout_device *vout)
++{
++ int num_buffers = 0, i;
++
++ num_buffers = (vout->vid == OMAP_VIDEO1) ?
++ video1_numbuffers : video2_numbuffers;
++ for (i = num_buffers; i < vout->buffer_allocated; i++) {
++ if (vout->buf_virt_addr[i]) {
++ omap_vout_free_buffer(vout->buf_virt_addr[i],
++ vout->buf_phy_addr[i], vout->buffer_size);
++ }
++ vout->buf_virt_addr[i] = 0;
++ vout->buf_phy_addr[i] = 0;
++ }
++ /* Free the VRFB buffers only if they are allocated
++ * during reqbufs. Don't free if init time allocated
++ */
++ if (!vout->vrfb_static_allocation) {
++ for (i = 0; i < 4; i++) {
++ if (vout->smsshado_virt_addr[i]) {
++ omap_vout_free_buffer(
++ vout->smsshado_virt_addr[i],
++ vout->smsshado_phy_addr[i],
++ vout->smsshado_size);
++ vout->smsshado_virt_addr[i] = 0;
++ vout->smsshado_phy_addr[i] = 0;
++ }
++ }
++ }
++ vout->buffer_allocated = num_buffers;
++}
++
++/* This function will be called when VIDIOC_QBUF ioctl is called.
++ * It prepare buffers before give out for the display. This function
++ * user space virtual address into physical address if userptr memory
++ * exchange mechanism is used. If rotation is enabled, it copies entire
++ * buffer into VRFB memory space before giving it to the DSS.
++ */
++static int omap_vout_buffer_prepare(struct videobuf_queue *q,
++ struct videobuf_buffer *vb,
++ enum v4l2_field field)
++{
++ struct omap_vout_device *vout = q->priv_data;
++ u32 dest_frame_index = 0, src_element_index = 0;
++ u32 dest_element_index = 0, src_frame_index = 0;
++ u32 elem_count = 0, frame_count = 0, pixsize = 2;
++ struct videobuf_dmabuf *dmabuf = NULL;
++ enum dss_rotation rotation;
++ struct vid_vrfb_dma *tx;
++
++ if (VIDEOBUF_NEEDS_INIT == vb->state) {
++ vb->width = vout->pix.width;
++ vb->height = vout->pix.height;
++ vb->size = vb->width * vb->height * vout->bpp;
++ vb->field = field;
++ }
++ vb->state = VIDEOBUF_PREPARED;
++ /* if user pointer memory mechanism is used, get the physical
++ * address of the buffer
++ */
++ if (V4L2_MEMORY_USERPTR == vb->memory) {
++ if (0 == vb->baddr)
++ return -EINVAL;
++ /* Virtual address */
++ /* priv points to struct videobuf_pci_sg_memory. But we went
++ * pointer to videobuf_dmabuf, which is member of
++ * videobuf_pci_sg_memory */
++ dmabuf = videobuf_to_dma(q->bufs[vb->i]);
++ dmabuf->vmalloc = (void *) vb->baddr;
++
++ /* Physical address */
++ dmabuf->bus_addr =
++ (dma_addr_t) omap_vout_uservirt_to_phys(vb->baddr);
++ }
++
++ if (!rotation_enabled(vout)) {
++ dmabuf = videobuf_to_dma(q->bufs[vb->i]);
++
++ vout->queued_buf_addr[vb->i] = (u8 *) dmabuf->bus_addr;
++ return 0;
++ }
++ dmabuf = videobuf_to_dma(q->bufs[vb->i]);
++ /* If rotation is enabled, copy input buffer into VRFB
++ * memory space using DMA. We are copying input buffer
++ * into VRFB memory space of desired angle and DSS will
++ * read image VRFB memory for 0 degree angle
++ */
++ pixsize = vout->bpp * vout->vrfb_bpp;
++ /*
++ * DMA transfer in double index mode
++ */
++
++ /* Frame index */
++ dest_frame_index = ((MAX_PIXELS_PER_LINE * pixsize) -
++ (vout->pix.width * vout->bpp)) + 1;
++
++ /* Source and destination parameters */
++ src_element_index = 0;
++ src_frame_index = 0;
++ dest_element_index = 1;
++ /* Number of elements per frame */
++ elem_count = vout->pix.width * vout->bpp;
++ frame_count = vout->pix.height;
++ tx = &vout->vrfb_dma_tx;
++ tx->tx_status = 0;
++ omap_set_dma_transfer_params(tx->dma_ch, OMAP_DMA_DATA_TYPE_S32,
++ (elem_count / 4), frame_count, OMAP_DMA_SYNC_ELEMENT,
++ tx->dev_id, 0x0);
++ /* src_port required only for OMAP1 */
++ omap_set_dma_src_params(tx->dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
++ dmabuf->bus_addr, src_element_index, src_frame_index);
++ /*set dma source burst mode for VRFB */
++ omap_set_dma_src_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16);
++ rotation = calc_rotation(vout);
++
++ /* dest_port required only for OMAP1 */
++ omap_set_dma_dest_params(tx->dma_ch, 0, OMAP_DMA_AMODE_DOUBLE_IDX,
++ vout->vrfb_context[vb->i].paddr[0], dest_element_index,
++ dest_frame_index);
++ /*set dma dest burst mode for VRFB */
++ omap_set_dma_dest_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16);
++ omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE, 0x20, 0);
++
++ omap_start_dma(tx->dma_ch);
++ interruptible_sleep_on_timeout(&tx->wait, VRFB_TX_TIMEOUT);
++
++ if (tx->tx_status == 0) {
++ omap_stop_dma(tx->dma_ch);
++ return -EINVAL;
++ }
++ /* Store buffers physical address into an array. Addresses
++ * from this array will be used to configure DSS */
++ vout->queued_buf_addr[vb->i] = (u8 *)
++ vout->vrfb_context[vb->i].paddr[rotation];
++ return 0;
++}
++
++/* Buffer queue funtion will be called from the videobuf layer when _QBUF
++ * ioctl is called. It is used to enqueue buffer, which is ready to be
++ * displayed. */
++static void omap_vout_buffer_queue(struct videobuf_queue *q,
++ struct videobuf_buffer *vb)
++{
++ struct omap_vout_device *vout = q->priv_data;
++
++ /* Driver is also maintainig a queue. So enqueue buffer in the driver
++ * queue */
++ list_add_tail(&vb->queue, &vout->dma_queue);
++
++ vb->state = VIDEOBUF_PREPARED;
++}
++
++/* Buffer release function is called from videobuf layer to release buffer
++ * which are already allocated */
++static void omap_vout_buffer_release(struct videobuf_queue *q,
++ struct videobuf_buffer *vb)
++{
++ struct omap_vout_device *vout = q->priv_data;
++
++ vb->state = VIDEOBUF_NEEDS_INIT;
++
++ if (V4L2_MEMORY_MMAP != vout->memory)
++ return;
++}
++
++/*
++ * File operations
++ */
++static void omap_vout_vm_open(struct vm_area_struct *vma)
++{
++ struct omap_vout_device *vout = vma->vm_private_data;
++
++ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
++ "vm_open [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
++ vout->mmap_count++;
++}
++
++static void omap_vout_vm_close(struct vm_area_struct *vma)
++{
++ struct omap_vout_device *vout = vma->vm_private_data;
++
++ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
++ "vm_close [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
++ vout->mmap_count--;
++}
++
++static struct vm_operations_struct omap_vout_vm_ops = {
++ .open = omap_vout_vm_open,
++ .close = omap_vout_vm_close,
++};
++
++static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ struct omap_vout_device *vout = file->private_data;
++ struct videobuf_queue *q = &vout->vbq;
++ unsigned long size = (vma->vm_end - vma->vm_start);
++ unsigned long start = vma->vm_start;
++ int i;
++ void *pos;
++ struct videobuf_dmabuf *dmabuf = NULL;
++
++ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
++ " %s pgoff=0x%lx, start=0x%lx, end=0x%lx\n", __func__,
++ vma->vm_pgoff, vma->vm_start, vma->vm_end);
++
++ /* look for the buffer to map */
++ for (i = 0; i < VIDEO_MAX_FRAME; i++) {
++ if (NULL == q->bufs[i])
++ continue;
++ if (V4L2_MEMORY_MMAP != q->bufs[i]->memory)
++ continue;
++ if (q->bufs[i]->boff == (vma->vm_pgoff << PAGE_SHIFT))
++ break;
++ }
++
++ if (VIDEO_MAX_FRAME == i) {
++ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
++ "offset invalid [offset=0x%lx]\n",
++ (vma->vm_pgoff << PAGE_SHIFT));
++ return -EINVAL;
++ }
++ q->bufs[i]->baddr = vma->vm_start;
++
++ vma->vm_flags |= VM_RESERVED;
++ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
++ vma->vm_ops = &omap_vout_vm_ops;
++ vma->vm_private_data = (void *) vout;
++ dmabuf = videobuf_to_dma(q->bufs[i]);
++ pos = dmabuf->vmalloc;
++ vma->vm_pgoff = virt_to_phys((void *)pos) >> PAGE_SHIFT;
++ while (size > 0) {
++ unsigned long pfn;
++ pfn = virt_to_phys((void *) pos) >> PAGE_SHIFT;
++ if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED))
++ return -EAGAIN;
++ start += PAGE_SIZE;
++ pos += PAGE_SIZE;
++ size -= PAGE_SIZE;
++ }
++ vout->mmap_count++;
++ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
++ return 0;
++}
++
++static int omap_vout_release(struct file *file)
++{
++
++ struct omap_vout_device *vout = file->private_data;
++ struct videobuf_queue *q;
++ unsigned int t;
++ struct omapvideo_info *ovid;
++ unsigned int r;
++
++ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__);
++ ovid = &vout->vid_info;
++
++ if (!vout)
++ return 0;
++ q = &vout->vbq;
++
++ /* Disable all the overlay managers connected with this interface */
++ for (t = 0; t < ovid->num_overlays; t++) {
++ struct omap_overlay *ovl = ovid->overlays[t];
++ if (ovl->manager && ovl->manager->device) {
++ struct omap_overlay_info info;
++ ovl->get_overlay_info(ovl, &info);
++ info.enabled = 0;
++ ovl->set_overlay_info(ovl, &info);
++ }
++
++ }
++ /* Turn off the pipeline */
++ r = omapvid_apply_changes(vout);
++ if (r)
++ printk(KERN_WARNING VOUT_NAME "Unable to apply changes\n");
++
++ /* Free all buffers */
++ omap_vout_free_allbuffers(vout);
++ videobuf_mmap_free(q);
++
++ /* Even if apply changes fails we should continue
++ freeing allocated memeory */
++ if (vout->streaming) {
++ u32 mask = 0;
++
++ mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN |
++ DISPC_IRQ_EVSYNC_ODD;
++ omap_dispc_unregister_isr(omap_vout_isr, vout, mask);
++ vout->streaming = 0;
++
++ videobuf_streamoff(q);
++ videobuf_queue_cancel(q);
++
++ }
++
++ if (vout->mmap_count != 0)
++ vout->mmap_count = 0;
++
++ vout->opened -= 1;
++ file->private_data = NULL;
++
++ if (vout->buffer_allocated)
++ videobuf_mmap_free(q);
++ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
++ return r;
++}
++
++static int omap_vout_open(struct file *file)
++{
++ struct omap_vout_device *vout = NULL;
++ struct videobuf_queue *q;
++
++ vout = video_drvdata(file);
++ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__);
++
++ if (vout == NULL)
++ return -ENODEV;
++
++ /* for now, we only support single open */
++ if (vout->opened)
++ return -EBUSY;
++
++ vout->opened += 1;
++
++ file->private_data = vout;
++ vout->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
++
++ q = &vout->vbq;
++ video_vbq_ops.buf_setup = omap_vout_buffer_setup;
++ video_vbq_ops.buf_prepare = omap_vout_buffer_prepare;
++ video_vbq_ops.buf_release = omap_vout_buffer_release;
++ video_vbq_ops.buf_queue = omap_vout_buffer_queue;
++ spin_lock_init(&vout->vbq_lock);
++
++ videobuf_queue_sg_init(q, &video_vbq_ops, NULL, &vout->vbq_lock,
++ vout->type, V4L2_FIELD_NONE, sizeof
++ (struct videobuf_buffer), vout);
++ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
++ return 0;
++}
++
++/* V4L2 ioctls */
++static int vidioc_querycap(struct file *file, void *fh,
++ struct v4l2_capability *cap)
++{
++ struct omap_vout_device *vout = fh;
++
++ strlcpy(cap->driver, VOUT_NAME,
++ sizeof(cap->driver));
++ strlcpy(cap->card, vout->vfd->name, sizeof(cap->card));
++ cap->bus_info[0] = '\0';
++ cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT;
++ return 0;
++}
++
++static int vidioc_enum_fmt_vid_out(struct file *file, void *fh,
++ struct v4l2_fmtdesc *fmt)
++{
++ int index = fmt->index;
++ enum v4l2_buf_type type = fmt->type;
++
++ fmt->index = index;
++ fmt->type = type;
++ if (index >= NUM_OUTPUT_FORMATS)
++ return -EINVAL;
++
++ fmt->flags = omap_formats[index].flags;
++ strlcpy(fmt->description, omap_formats[index].description,
++ sizeof(fmt->description));
++ fmt->pixelformat = omap_formats[index].pixelformat;
++ return 0;
++}
++
++static int vidioc_g_fmt_vid_out(struct file *file, void *fh,
++ struct v4l2_format *f)
++{
++ struct omap_vout_device *vout = fh;
++
++ f->fmt.pix = vout->pix;
++ return 0;
++
++}
++
++static int vidioc_try_fmt_vid_out(struct file *file, void *fh,
++ struct v4l2_format *f)
++{
++ struct omap_vout_device *vout = fh;
++ struct omapvideo_info *ovid;
++ struct omap_overlay *ovl;
++ struct omap_video_timings *timing;
++
++ if (vout->streaming)
++ return -EBUSY;
++
++ ovid = &vout->vid_info;
++ ovl = ovid->overlays[0];
++
++ if (!ovl->manager || !ovl->manager->device)
++ return -EINVAL;
++ /* get the display device attached to the overlay */
++ timing = &ovl->manager->device->panel.timings;
++
++ vout->fbuf.fmt.height = timing->y_res;
++ vout->fbuf.fmt.width = timing->x_res;
++
++ omap_vout_try_format(&f->fmt.pix);
++ return 0;
++}
++
++static int vidioc_s_fmt_vid_out(struct file *file, void *fh,
++ struct v4l2_format *f)
++{
++ struct omap_vout_device *vout = fh;
++ int bpp;
++ int r;
++ struct omapvideo_info *ovid;
++ struct omap_overlay *ovl;
++ struct omap_video_timings *timing;
++
++ if (vout->streaming)
++ return -EBUSY;
++
++ mutex_lock(&vout->lock);
++
++ ovid = &vout->vid_info;
++ ovl = ovid->overlays[0];
++
++ /* get the display device attached to the overlay */
++ if (!ovl->manager || !ovl->manager->device) {
++ mutex_unlock(&vout->lock);
++ return -EINVAL;
++ }
++ timing = &ovl->manager->device->panel.timings;
++
++ /* We dont support RGB24-packed mode if vrfb rotation
++ * is enabled*/
++ if ((rotation_enabled(vout)) &&
++ f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) {
++ mutex_unlock(&vout->lock);
++ return -EINVAL;
++ }
++
++ /* get the framebuffer parameters */
++
++ if (rotate_90_or_270(vout)) {
++ vout->fbuf.fmt.height = timing->x_res;
++ vout->fbuf.fmt.width = timing->y_res;
++ } else {
++ vout->fbuf.fmt.height = timing->y_res;
++ vout->fbuf.fmt.width = timing->x_res;
++ }
++
++ /* change to samller size is OK */
++
++ bpp = omap_vout_try_format(&f->fmt.pix);
++ f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height * bpp;
++
++ /* try & set the new output format */
++ vout->bpp = bpp;
++ vout->pix = f->fmt.pix;
++ vout->vrfb_bpp = 1;
++
++ /* If YUYV then vrfb bpp is 2, for others its 1 */
++ if (V4L2_PIX_FMT_YUYV == vout->pix.pixelformat ||
++ V4L2_PIX_FMT_UYVY == vout->pix.pixelformat)
++ vout->vrfb_bpp = 2;
++
++ /* set default crop and win */
++ omap_vout_new_format(&vout->pix, &vout->fbuf, &vout->crop, &vout->win);
++
++ /* Save the changes in the overlay strcuture */
++ r = omapvid_init(vout, 0);
++ if (r) {
++ printk(KERN_ERR VOUT_NAME "failed to change mode\n");
++ mutex_unlock(&vout->lock);
++ return -EINVAL;
++ }
++ mutex_unlock(&vout->lock);
++ return 0;
++}
++
++static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh,
++ struct v4l2_format *f)
++{
++ int err = -EINVAL;
++ struct omap_vout_device *vout = fh;
++ struct v4l2_window *win = &f->fmt.win;
++
++ err = omap_vout_try_window(&vout->fbuf, win);
++
++ if (err)
++ return err;
++
++ if (vout->vid == OMAP_VIDEO1)
++ win->global_alpha = 255;
++ else
++ win->global_alpha = f->fmt.win.global_alpha;
++
++ return 0;
++}
++
++static int vidioc_s_fmt_vid_overlay(struct file *file, void *fh,
++ struct v4l2_format *f)
++{
++ struct omap_vout_device *vout = fh;
++ int err = -EINVAL;
++ struct omap_overlay *ovl;
++ struct omapvideo_info *ovid;
++ struct v4l2_window *win = &f->fmt.win;
++
++ mutex_lock(&vout->lock);
++ ovid = &vout->vid_info;
++ ovl = ovid->overlays[0];
++
++ err = omap_vout_new_window(&vout->crop, &vout->win, &vout->fbuf, win);
++ if (err) {
++ mutex_unlock(&vout->lock);
++ return err;
++ }
++ /* Video1 plane does not support global alpha */
++ if (ovl->id == OMAP_DSS_VIDEO1)
++ vout->win.global_alpha = 255;
++ else
++ vout->win.global_alpha = f->fmt.win.global_alpha;
++
++ vout->win.chromakey = f->fmt.win.chromakey;
++ mutex_unlock(&vout->lock);
++ return 0;
++}
++
++static int vidioc_enum_fmt_vid_overlay(struct file *file, void *fh,
++ struct v4l2_fmtdesc *fmt)
++{
++ int index = fmt->index;
++ enum v4l2_buf_type type = fmt->type;
++
++ fmt->index = index;
++ fmt->type = type;
++ if (index >= NUM_OUTPUT_FORMATS)
++ return -EINVAL;
++
++ fmt->flags = omap_formats[index].flags;
++ strlcpy(fmt->description, omap_formats[index].description,
++ sizeof(fmt->description));
++ fmt->pixelformat = omap_formats[index].pixelformat;
++ return 0;
++}
++
++static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh,
++ struct v4l2_format *f)
++{
++ struct omap_vout_device *vout = fh;
++ struct omap_overlay *ovl;
++ struct omapvideo_info *ovid;
++ struct omap_overlay_manager_info info;
++ struct v4l2_window *win = &f->fmt.win;
++ u32 key_value = 0;
++
++ ovid = &vout->vid_info;
++ ovl = ovid->overlays[0];
++
++ win->w = vout->win.w;
++ win->field = vout->win.field;
++ win->global_alpha = vout->win.global_alpha;
++
++ if (ovl->manager && ovl->manager->get_manager_info) {
++ ovl->manager->get_manager_info(ovl->manager, &info);
++ key_value = info.trans_key;
++ }
++ win->chromakey = key_value;
++ return 0;
++}
++
++static int vidioc_cropcap(struct file *file, void *fh,
++ struct v4l2_cropcap *cropcap)
++{
++ struct omap_vout_device *vout = fh;
++ enum v4l2_buf_type type = cropcap->type;
++ struct v4l2_pix_format *pix = &vout->pix;
++
++ cropcap->type = type;
++ if (type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
++ return -EINVAL;
++
++ /* Width and height are always even */
++ cropcap->bounds.width = pix->width & ~1;
++ cropcap->bounds.height = pix->height & ~1;
++
++ omap_vout_default_crop(&vout->pix, &vout->fbuf, &cropcap->defrect);
++ cropcap->pixelaspect.numerator = 1;
++ cropcap->pixelaspect.denominator = 1;
++ return 0;
++}
++
++static int vidioc_g_crop(struct file *file, void *fh,
++ struct v4l2_crop *crop)
++{
++ struct omap_vout_device *vout = fh;
++
++ if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
++ return -EINVAL;
++ crop->c = vout->crop;
++ return 0;
++}
++
++static int vidioc_s_crop(struct file *file, void *fh,
++ struct v4l2_crop *crop)
++{
++ struct omap_vout_device *vout = fh;
++ int err = -EINVAL;
++ struct omapvideo_info *ovid;
++ struct omap_overlay *ovl;
++ struct omap_video_timings *timing;
++
++ if (vout->streaming)
++ return -EBUSY;
++
++ mutex_lock(&vout->lock);
++ ovid = &vout->vid_info;
++ ovl = ovid->overlays[0];
++
++ if (!ovl->manager || !ovl->manager->device) {
++ mutex_unlock(&vout->lock);
++ return -EINVAL;
++ }
++ /* get the display device attached to the overlay */
++ timing = &ovl->manager->device->panel.timings;
++
++ if (rotate_90_or_270(vout)) {
++ vout->fbuf.fmt.height = timing->x_res;
++ vout->fbuf.fmt.width = timing->y_res;
++ } else {
++ vout->fbuf.fmt.height = timing->y_res;
++ vout->fbuf.fmt.width = timing->x_res;
++ }
++
++ if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
++ err = omap_vout_new_crop(&vout->pix, &vout->crop, &vout->win,
++ &vout->fbuf, &crop->c);
++ mutex_unlock(&vout->lock);
++ return err;
++ } else {
++ mutex_unlock(&vout->lock);
++ return -EINVAL;
++ }
++}
++
++static int vidioc_queryctrl(struct file *file, void *fh,
++ struct v4l2_queryctrl *ctrl)
++{
++ switch (ctrl->id) {
++ case V4L2_CID_ROTATE:
++ v4l2_ctrl_query_fill(ctrl, 0, 270, 90, 0);
++ break;
++ case V4L2_CID_BG_COLOR:
++ v4l2_ctrl_query_fill(ctrl, 0, 0xFFFFFF, 1, 0);
++ break;
++ case V4L2_CID_VFLIP:
++ v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0);
++ default:
++ ctrl->name[0] = '\0';
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl)
++{
++ struct omap_vout_device *vout = fh;
++
++ switch (ctrl->id) {
++ case V4L2_CID_ROTATE:
++ ctrl->value = vout->control[0].value;
++ return 0;
++ case V4L2_CID_BG_COLOR:
++ {
++ struct omap_overlay_manager_info info;
++ struct omap_overlay *ovl;
++ ovl = vout->vid_info.overlays[0];
++
++ if (!ovl->manager || !ovl->manager->get_manager_info)
++ return -EINVAL;
++
++ ovl->manager->get_manager_info(ovl->manager, &info);
++ ctrl->value = info.default_color;
++ return 0;
++ }
++
++ case V4L2_CID_VFLIP:
++ ctrl->value = vout->control[2].value;
++ return 0;
++ default:
++ return -EINVAL;
++ }
++}
++
++static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
++{
++ struct omap_vout_device *vout = fh;
++
++ switch (a->id) {
++ case V4L2_CID_ROTATE:
++ {
++ int rotation = a->value;
++
++ mutex_lock(&vout->lock);
++
++ if (rotation &&
++ vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) {
++ mutex_unlock(&vout->lock);
++ return -EINVAL;
++ }
++
++ if ((v4l2_rot_to_dss_rot(rotation, &vout->rotation,
++ vout->mirror))) {
++ mutex_unlock(&vout->lock);
++ return -EINVAL;
++ }
++
++ vout->control[0].value = rotation;
++ mutex_unlock(&vout->lock);
++ return 0;
++ }
++ case V4L2_CID_BG_COLOR:
++ {
++ unsigned int color = a->value;
++ struct omap_overlay_manager_info info;
++ struct omap_overlay *ovl;
++ ovl = vout->vid_info.overlays[0];
++
++ mutex_lock(&vout->lock);
++ if (!ovl->manager || !ovl->manager->get_manager_info) {
++ mutex_unlock(&vout->lock);
++ return -EINVAL;
++ }
++
++ ovl->manager->get_manager_info(ovl->manager, &info);
++ info.default_color = color;
++ if (ovl->manager->set_manager_info(ovl->manager, &info)) {
++ mutex_unlock(&vout->lock);
++ return -EINVAL;
++ }
++
++ vout->control[1].value = color;
++ mutex_unlock(&vout->lock);
++ return 0;
++ }
++ case V4L2_CID_VFLIP:
++ {
++ unsigned int mirror = a->value;
++ struct omapvideo_info *ovid;
++ struct omap_overlay *ovl;
++ ovid = &vout->vid_info;
++ ovl = ovid->overlays[0];
++
++ mutex_lock(&vout->lock);
++
++ if (mirror && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) {
++ mutex_unlock(&vout->lock);
++ return -EINVAL;
++ }
++ vout->mirror = mirror;
++ vout->control[2].value = mirror;
++ mutex_unlock(&vout->lock);
++ return 0;
++ }
++
++ default:
++ return -EINVAL;
++ }
++
++}
++
++static int vidioc_reqbufs(struct file *file, void *fh,
++ struct v4l2_requestbuffers *req)
++{
++ struct omap_vout_device *vout = fh;
++ struct videobuf_queue *q = &vout->vbq;
++ unsigned int i, num_buffers = 0;
++ int ret = 0;
++ struct videobuf_dmabuf *dmabuf = NULL;
++
++ if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) || (req->count < 0))
++ return -EINVAL;
++ /* if memory is not mmp or userptr
++ return error */
++ if ((V4L2_MEMORY_MMAP != req->memory) &&
++ (V4L2_MEMORY_USERPTR != req->memory))
++ return -EINVAL;
++
++ mutex_lock(&vout->lock);
++ /* Cannot be requested when streaming is on */
++ if (vout->streaming) {
++ mutex_unlock(&vout->lock);
++ return -EBUSY;
++ }
++
++ /* If buffers are already allocated free them */
++ if (q->bufs[0] && (V4L2_MEMORY_MMAP == q->bufs[0]->memory)) {
++ if (vout->mmap_count) {
++ mutex_unlock(&vout->lock);
++ return -EBUSY;
++ }
++ num_buffers = (vout->vid == OMAP_VIDEO1) ?
++ video1_numbuffers : video2_numbuffers;
++ for (i = num_buffers; i < vout->buffer_allocated; i++) {
++ dmabuf = videobuf_to_dma(q->bufs[i]);
++ omap_vout_free_buffer((u32)dmabuf->vmalloc,
++ dmabuf->bus_addr, vout->buffer_size);
++ vout->buf_virt_addr[i] = 0;
++ vout->buf_phy_addr[i] = 0;
++ }
++ vout->buffer_allocated = num_buffers;
++ videobuf_mmap_free(q);
++ } else if (q->bufs[0] && (V4L2_MEMORY_USERPTR == q->bufs[0]->memory)) {
++ if (vout->buffer_allocated) {
++ videobuf_mmap_free(q);
++ for (i = 0; i < vout->buffer_allocated; i++) {
++ kfree(q->bufs[i]);
++ q->bufs[i] = NULL;
++ }
++ vout->buffer_allocated = 0;
++ }
++ }
++
++ /*store the memory type in data structure */
++ vout->memory = req->memory;
++
++ INIT_LIST_HEAD(&vout->dma_queue);
++
++ /* call videobuf_reqbufs api */
++ ret = videobuf_reqbufs(q, req);
++ if (ret < 0) {
++ mutex_unlock(&vout->lock);
++ return ret;
++ }
++
++ vout->buffer_allocated = req->count;
++ for (i = 0; i < req->count; i++) {
++ dmabuf = videobuf_to_dma(q->bufs[i]);
++ dmabuf->vmalloc = (void *) vout->buf_virt_addr[i];
++ dmabuf->bus_addr = (dma_addr_t) vout->buf_phy_addr[i];
++ dmabuf->sglen = 1;
++ }
++ mutex_unlock(&vout->lock);
++ return 0;
++}
++
++static int vidioc_querybuf(struct file *file, void *fh,
++ struct v4l2_buffer *b)
++{
++ struct omap_vout_device *vout = fh;
++
++ return videobuf_querybuf(&vout->vbq, b);
++}
++
++static int vidioc_qbuf(struct file *file, void *fh,
++ struct v4l2_buffer *buffer)
++{
++ struct omap_vout_device *vout = fh;
++ struct videobuf_queue *q = &vout->vbq;
++ int ret = 0;
++
++ if ((V4L2_BUF_TYPE_VIDEO_OUTPUT != buffer->type) ||
++ (buffer->index >= vout->buffer_allocated) ||
++ (q->bufs[buffer->index]->memory != buffer->memory)) {
++ return -EINVAL;
++ }
++ if (V4L2_MEMORY_USERPTR == buffer->memory) {
++ if ((buffer->length < vout->pix.sizeimage) ||
++ (0 == buffer->m.userptr)) {
++ return -EINVAL;
++ }
++ }
++
++ if ((rotation_enabled(vout)) &&
++ vout->vrfb_dma_tx.req_status == DMA_CHAN_NOT_ALLOTED) {
++ printk(KERN_WARNING VOUT_NAME
++ "DMA Channel not allocated for Rotation\n");
++ return -EINVAL;
++ }
++
++ ret = videobuf_qbuf(q, buffer);
++ return ret;
++}
++
++static int vidioc_dqbuf(struct file *file, void *fh,
++ struct v4l2_buffer *b)
++{
++ struct omap_vout_device *vout = fh;
++ struct videobuf_queue *q = &vout->vbq;
++ int ret = 0;
++
++ if (!vout->streaming)
++ return -EINVAL;
++
++ if (file->f_flags & O_NONBLOCK)
++ /* Call videobuf_dqbuf for non blocking mode */
++ ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 1);
++ else
++ /* Call videobuf_dqbuf for blocking mode */
++ ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0);
++ return ret;
++}
++
++static int vidioc_streamon(struct file *file, void *fh,
++ enum v4l2_buf_type i)
++{
++ struct omap_vout_device *vout = fh;
++ struct videobuf_queue *q = &vout->vbq;
++ u32 addr = 0;
++ int r = 0;
++ int t;
++ struct omapvideo_info *ovid = &vout->vid_info;
++ u32 mask = 0;
++
++ mutex_lock(&vout->lock);
++
++ if (vout->streaming) {
++ mutex_unlock(&vout->lock);
++ return -EBUSY;
++ }
++
++ r = videobuf_streamon(q);
++ if (r < 0) {
++ mutex_unlock(&vout->lock);
++ return r;
++ }
++
++ if (list_empty(&vout->dma_queue)) {
++ mutex_unlock(&vout->lock);
++ return -EIO;
++ }
++ /* Get the next frame from the buffer queue */
++ vout->next_frm = vout->cur_frm = list_entry(vout->dma_queue.next,
++ struct videobuf_buffer, queue);
++ /* Remove buffer from the buffer queue */
++ list_del(&vout->cur_frm->queue);
++ /* Mark state of the current frame to active */
++ vout->cur_frm->state = VIDEOBUF_ACTIVE;
++ /* Initialize field_id and started member */
++ vout->field_id = 0;
++
++ /* set flag here. Next QBUF will start DMA */
++ vout->streaming = 1;
++
++ vout->first_int = 1;
++
++ if (omap_vout_calculate_offset(vout)) {
++ mutex_unlock(&vout->lock);
++ return -EINVAL;
++ }
++ addr = (unsigned long) vout->queued_buf_addr[vout->cur_frm->i]
++ + vout->cropped_offset;
++
++ mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN |
++ DISPC_IRQ_EVSYNC_ODD;
++
++ omap_dispc_register_isr(omap_vout_isr, vout, mask);
++
++ for (t = 0; t < ovid->num_overlays; t++) {
++ struct omap_overlay *ovl = ovid->overlays[t];
++ if (ovl->manager && ovl->manager->device) {
++ struct omap_overlay_info info;
++ ovl->get_overlay_info(ovl, &info);
++ info.enabled = 1;
++ info.paddr = addr;
++ if (ovl->set_overlay_info(ovl, &info))
++ return -EINVAL;
++ }
++ }
++
++ /* First save the configuration in ovelray structure */
++ r = omapvid_init(vout, addr);
++ if (r)
++ printk(KERN_ERR VOUT_NAME "failed to set overlay info\n");
++ /* Enable the pipeline and set the Go bit */
++ r = omapvid_apply_changes(vout);
++ if (r)
++ printk(KERN_ERR VOUT_NAME "failed to change mode\n");
++
++ mutex_unlock(&vout->lock);
++ return r;
++}
++
++static int vidioc_streamoff(struct file *file, void *fh,
++ enum v4l2_buf_type i)
++{
++ struct omap_vout_device *vout = fh;
++ int t, r = 0;
++ struct omapvideo_info *ovid = &vout->vid_info;
++ u32 mask = 0;
++
++ if (!vout->streaming)
++ return -EINVAL;
++
++ vout->streaming = 0;
++ mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN |
++ DISPC_IRQ_EVSYNC_ODD;
++
++ omap_dispc_unregister_isr(omap_vout_isr, vout, mask);
++
++ for (t = 0; t < ovid->num_overlays; t++) {
++ struct omap_overlay *ovl = ovid->overlays[t];
++ if (ovl->manager && ovl->manager->device) {
++ struct omap_overlay_info info;
++
++ ovl->get_overlay_info(ovl, &info);
++ info.enabled = 0;
++ return ovl->set_overlay_info(ovl, &info);
++ }
++ }
++
++ /* Turn of the pipeline */
++ r = omapvid_apply_changes(vout);
++ if (r) {
++ printk(KERN_ERR VOUT_NAME "failed to change mode\n");
++ return r;
++ }
++ videobuf_streamoff(&vout->vbq);
++ videobuf_queue_cancel(&vout->vbq);
++ return 0;
++}
++
++static int vidioc_s_fbuf(struct file *file, void *fh,
++ struct v4l2_framebuffer *a)
++{
++ struct omap_vout_device *vout = fh;
++ struct omap_overlay_manager_info info;
++ struct omapvideo_info *ovid;
++ struct omap_overlay *ovl;
++ enum omap_dss_trans_key_type key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
++ int enable = 0;
++
++ ovid = &vout->vid_info;
++ ovl = ovid->overlays[0];
++
++ /* OMAP DSS doesn't support Source and Destination color
++ key together */
++ if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) &&
++ (a->flags & V4L2_FBUF_FLAG_CHROMAKEY))
++ return -EINVAL;
++ /* OMAP DSS Doesn't support the Destination color key
++ and alpha blending together */
++ if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY) &&
++ (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA))
++ return -EINVAL;
++
++ if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY)) {
++ vout->fbuf.flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY;
++ key_type = OMAP_DSS_COLOR_KEY_VID_SRC;
++ } else
++ vout->fbuf.flags &= ~V4L2_FBUF_FLAG_SRC_CHROMAKEY;
++
++ if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY)) {
++ vout->fbuf.flags |= V4L2_FBUF_FLAG_CHROMAKEY;
++ key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
++ } else
++ vout->fbuf.flags &= ~V4L2_FBUF_FLAG_CHROMAKEY;
++
++ if (a->flags & (V4L2_FBUF_FLAG_CHROMAKEY |
++ V4L2_FBUF_FLAG_SRC_CHROMAKEY))
++ enable = 1;
++ else
++ enable = 0;
++ if (ovl->manager && ovl->manager->get_manager_info &&
++ ovl->manager->set_manager_info) {
++
++ ovl->manager->get_manager_info(ovl->manager, &info);
++ info.trans_enabled = enable;
++ info.trans_key_type = key_type;
++ info.trans_key = vout->win.chromakey;
++
++ if (ovl->manager->set_manager_info(ovl->manager, &info))
++ return -EINVAL;
++ }
++ if (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) {
++ vout->fbuf.flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
++ enable = 1;
++ } else {
++ vout->fbuf.flags &= ~V4L2_FBUF_FLAG_LOCAL_ALPHA;
++ enable = 0;
++ }
++ if (ovl->manager && ovl->manager->get_manager_info &&
++ ovl->manager->set_manager_info) {
++ ovl->manager->get_manager_info(ovl->manager, &info);
++ info.alpha_enabled = enable;
++ if (ovl->manager->set_manager_info(ovl->manager, &info))
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int vidioc_g_fbuf(struct file *file, void *fh,
++ struct v4l2_framebuffer *a)
++{
++ struct omap_vout_device *vout = fh;
++ struct omap_overlay_manager_info info;
++ struct omapvideo_info *ovid;
++ struct omap_overlay *ovl;
++
++ ovid = &vout->vid_info;
++ ovl = ovid->overlays[0];
++
++ a->flags = 0x0;
++
++ a->capability = V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_CHROMAKEY
++ | V4L2_FBUF_CAP_SRC_CHROMAKEY;
++
++ if (ovl->manager && ovl->manager->get_manager_info) {
++ ovl->manager->get_manager_info(ovl->manager, &info);
++ if (info.trans_key_type == OMAP_DSS_COLOR_KEY_VID_SRC)
++ a->flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY;
++ if (info.trans_key_type == OMAP_DSS_COLOR_KEY_GFX_DST)
++ a->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
++ }
++ if (ovl->manager && ovl->manager->get_manager_info) {
++ ovl->manager->get_manager_info(ovl->manager, &info);
++ if (info.alpha_enabled)
++ a->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
++ }
++
++ return 0;
++}
++
++static const struct v4l2_ioctl_ops vout_ioctl_ops = {
++ .vidioc_querycap = vidioc_querycap,
++ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
++ .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
++ .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
++ .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
++ .vidioc_queryctrl = vidioc_queryctrl,
++ .vidioc_g_ctrl = vidioc_g_ctrl,
++ .vidioc_s_fbuf = vidioc_s_fbuf,
++ .vidioc_g_fbuf = vidioc_g_fbuf,
++ .vidioc_s_ctrl = vidioc_s_ctrl,
++ .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay,
++ .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay,
++ .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay,
++ .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay,
++ .vidioc_cropcap = vidioc_cropcap,
++ .vidioc_g_crop = vidioc_g_crop,
++ .vidioc_s_crop = vidioc_s_crop,
++ .vidioc_reqbufs = vidioc_reqbufs,
++ .vidioc_querybuf = vidioc_querybuf,
++ .vidioc_qbuf = vidioc_qbuf,
++ .vidioc_dqbuf = vidioc_dqbuf,
++ .vidioc_streamon = vidioc_streamon,
++ .vidioc_streamoff = vidioc_streamoff,
++};
++
++static const struct v4l2_file_operations omap_vout_fops = {
++ .owner = THIS_MODULE,
++ .ioctl = video_ioctl2,
++ .mmap = omap_vout_mmap,
++ .open = omap_vout_open,
++ .release = omap_vout_release,
++};
++
++/* Init functions used during driver intitalization */
++/* Initial setup of video_data */
++static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
++{
++ struct v4l2_pix_format *pix;
++ struct video_device *vfd;
++ struct v4l2_control *control;
++ struct omap_dss_device *display =
++ vout->vid_info.overlays[0]->manager->device;
++
++ /* set the default pix */
++ pix = &vout->pix;
++
++ /* Set the default picture of QVGA */
++ pix->width = QQVGA_WIDTH;
++ pix->height = QQVGA_HEIGHT;
++
++ /* Default pixel format is RGB 5-6-5 */
++ pix->pixelformat = V4L2_PIX_FMT_RGB565;
++ pix->field = V4L2_FIELD_ANY;
++ pix->bytesperline = pix->width * 2;
++ pix->sizeimage = pix->bytesperline * pix->height;
++ pix->priv = 0;
++ pix->colorspace = V4L2_COLORSPACE_JPEG;
++
++ vout->bpp = RGB565_BPP;
++ vout->fbuf.fmt.width = display->panel.timings.x_res;
++ vout->fbuf.fmt.height = display->panel.timings.y_res;
++
++ /* Set the data structures for the overlay parameters*/
++ vout->win.global_alpha = 255;
++ vout->fbuf.flags = 0;
++ vout->fbuf.capability = V4L2_FBUF_CAP_LOCAL_ALPHA |
++ V4L2_FBUF_CAP_SRC_CHROMAKEY | V4L2_FBUF_CAP_CHROMAKEY;
++ vout->win.chromakey = 0;
++
++ omap_vout_new_format(pix, &vout->fbuf, &vout->crop, &vout->win);
++
++ /*Initialize the control variables for
++ rotation, flipping and background color. */
++ control = vout->control;
++ control[0].id = V4L2_CID_ROTATE;
++ control[0].value = 0;
++ vout->rotation = 0;
++ vout->mirror = 0;
++ vout->control[2].id = V4L2_CID_HFLIP;
++ vout->control[2].value = 0;
++ vout->vrfb_bpp = 2;
++
++ control[1].id = V4L2_CID_BG_COLOR;
++ control[1].value = 0;
++
++ /* initialize the video_device struct */
++ vfd = vout->vfd = video_device_alloc();
++
++ if (!vfd) {
++ printk(KERN_ERR VOUT_NAME ": could not allocate"
++ " video device struct\n");
++ return -ENOMEM;
++ }
++ vfd->release = video_device_release;
++ vfd->ioctl_ops = &vout_ioctl_ops;
++
++ strlcpy(vfd->name, VOUT_NAME, sizeof(vfd->name));
++ vfd->vfl_type = VFL_TYPE_GRABBER;
++
++ /* need to register for a VID_HARDWARE_* ID in videodev.h */
++ vfd->fops = &omap_vout_fops;
++ mutex_init(&vout->lock);
++
++ vfd->minor = -1;
++ return 0;
++
++}
++
++/* Setup video buffers */
++static int __init omap_vout_setup_video_bufs(struct platform_device *pdev,
++ int vid_num)
++{
++ struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
++ struct omap2video_device *vid_dev = container_of(v4l2_dev, struct
++ omap2video_device, v4l2_dev);
++ struct omap_vout_device *vout;
++ int i, j, r = 0;
++ int image_width, image_height;
++ unsigned numbuffers;
++ struct video_device *vfd;
++ int static_vrfb_allocation = 0, vrfb_num_bufs = 4;
++
++ vout = vid_dev->vouts[vid_num];
++ vfd = vout->vfd;
++
++ numbuffers = (vid_num == 0) ? video1_numbuffers : video2_numbuffers;
++ vout->buffer_size = (vid_num == 0) ? video1_bufsize : video2_bufsize;
++ printk(KERN_INFO VOUT_NAME "Buffer Size = %d\n", vout->buffer_size);
++ for (i = 0; i < numbuffers; i++) {
++ vout->buf_virt_addr[i] =
++ omap_vout_alloc_buffer(vout->buffer_size,
++ (u32 *) &vout->buf_phy_addr[i]);
++ if (!vout->buf_virt_addr[i]) {
++ numbuffers = i;
++ r = -ENOMEM;
++ goto free_buffers;
++ }
++ }
++
++ for (i = 0; i < 4; i++) {
++ if (omap_vrfb_request_ctx(&vout->vrfb_context[i])) {
++ printk(KERN_INFO VOUT_NAME ": VRFB Region allocation "
++ "for rotation failed\n");
++ r = -ENOMEM;
++ break;
++ }
++ }
++ if (r == -ENOMEM) {
++ for (j = 0; j < i; j++)
++ omap_vrfb_release_ctx(&vout->vrfb_context[j]);
++
++ goto free_buffers;
++ }
++
++ vout->cropped_offset = 0;
++
++ /* Calculate VRFB memory size */
++ /* allocate for worst case size */
++ image_width = VID_MAX_WIDTH / TILE_SIZE;
++ if (VID_MAX_WIDTH % TILE_SIZE)
++ image_width++;
++
++ image_width = image_width * TILE_SIZE;
++ image_height = VID_MAX_HEIGHT / TILE_SIZE;
++
++ if (VID_MAX_HEIGHT % TILE_SIZE)
++ image_height++;
++
++ image_height = image_height * TILE_SIZE;
++ vout->smsshado_size = PAGE_ALIGN(image_width * image_height * 2 * 2);
++
++ /*
++ * Request and Initialize DMA, for DMA based VRFB transfer
++ */
++ vout->vrfb_dma_tx.dev_id = OMAP_DMA_NO_DEVICE;
++ vout->vrfb_dma_tx.dma_ch = -1;
++ vout->vrfb_dma_tx.req_status = DMA_CHAN_ALLOTED;
++ r = omap_request_dma(vout->vrfb_dma_tx.dev_id, "VRFB DMA TX",
++ omap_vout_vrfb_dma_tx_callback,
++ (void *) &vout->vrfb_dma_tx, &vout->vrfb_dma_tx.dma_ch);
++ if (r < 0) {
++ vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
++ printk(KERN_INFO VOUT_NAME ": DMA Channel not alloted "
++ "for video%d [v4l2]\n", vfd->minor);
++ }
++ init_waitqueue_head(&vout->vrfb_dma_tx.wait);
++
++ /* Allocate VRFB buffers if selected through bootargs */
++ static_vrfb_allocation = (vid_num == 0) ?
++ vid1_static_vrfb_alloc : vid2_static_vrfb_alloc;
++
++ /* statically allocated the VRFB buffer is done through
++ commands line aruments */
++ if (static_vrfb_allocation) {
++ if (omap_vout_allocate_vrfb_buffers(vout, &vrfb_num_bufs, -1)) {
++ r = -ENOMEM;
++ goto free_buffers;
++ }
++ vout->vrfb_static_allocation = 1;
++ }
++ return 0;
++
++free_buffers:
++ for (i = 0; i < numbuffers; i++) {
++ omap_vout_free_buffer(vout->buf_virt_addr[i],
++ vout->buf_phy_addr[i], vout->buffer_size);
++ vout->buf_virt_addr[i] = 0;
++ vout->buf_phy_addr[i] = 0;
++ }
++ return r;
++
++}
++
++/* Create video out devices */
++static int __init omap_vout_create_video_devices(struct platform_device *pdev)
++{
++ int r = 0, k;
++ struct omap_vout_device *vout;
++ struct video_device *vfd = NULL;
++ struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
++
++ struct omap2video_device *vid_dev = container_of(v4l2_dev, struct
++ omap2video_device, v4l2_dev);
++
++ for (k = 0; k < pdev->num_resources; k++) {
++
++ vout = kmalloc(sizeof(struct omap_vout_device), GFP_KERNEL);
++ if (!vout) {
++ printk(KERN_ERR VOUT_NAME
++ ": could not allocate memory\n");
++ return -ENOMEM;
++ }
++
++ memset(vout, 0, sizeof(struct omap_vout_device));
++
++ vout->vid = k;
++ vid_dev->vouts[k] = vout;
++ vout->vid_dev = vid_dev;
++ /* Select video2 if only 1 overlay is controlled by V4L2 */
++ if (pdev->num_resources == 1)
++ vout->vid_info.overlays[0] = vid_dev->overlays[k + 2];
++ else
++ /* Else select video1 and video2 one by one. */
++ vout->vid_info.overlays[0] = vid_dev->overlays[k + 1];
++ vout->vid_info.num_overlays = 1;
++ vout->vid_info.id = k + 1;
++ vid_dev->num_videos++;
++
++ /* Setup the default configuration for the video devices
++ */
++ if (omap_vout_setup_video_data(vout) != 0) {
++ r = -ENOMEM;
++ goto error;
++ }
++
++ /* Allocate default number of buffers for the video streaming
++ * and reserve the VRFB space for rotation
++ */
++ if (omap_vout_setup_video_bufs(pdev, k) != 0) {
++ r = -ENOMEM;
++ goto error1;
++ }
++
++ /* Register the Video device with V4L2
++ */
++ vfd = vout->vfd;
++ if (video_register_device(vfd, VFL_TYPE_GRABBER, k + 1) < 0) {
++ printk(KERN_ERR VOUT_NAME ": could not register "
++ "Video for Linux device\n");
++ vfd->minor = -1;
++ r = -ENODEV;
++ goto error2;
++ }
++ video_set_drvdata(vfd, vout);
++
++ /* Configure the overlay structure */
++ r = omapvid_init(vid_dev->vouts[k], 0);
++
++ if (r)
++ goto error2;
++ else
++ goto success;
++error2:
++ omap_vout_release_vrfb(vout);
++ omap_vout_free_buffers(vout);
++error1:
++ video_device_release(vfd);
++error:
++ kfree(vout);
++ return r;
++
++success:
++ printk(KERN_INFO VOUT_NAME ": registered and initialized "
++ "video device %d [v4l2]\n", vfd->minor);
++ if (k == (pdev->num_resources - 1))
++ return 0;
++ }
++ return -ENODEV;
++
++}
++/* Driver functions */
++static int omap_vout_remove(struct platform_device *pdev)
++{
++ struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
++ struct omap2video_device *vid_dev = container_of(v4l2_dev, struct
++ omap2video_device, v4l2_dev);
++ int k;
++
++ v4l2_device_unregister(v4l2_dev);
++ for (k = 0; k < pdev->num_resources; k++)
++ omap_vout_cleanup_device(vid_dev->vouts[k]);
++
++ for (k = 0; k < vid_dev->num_displays; k++) {
++ if (vid_dev->displays[k]->state != OMAP_DSS_DISPLAY_DISABLED)
++ vid_dev->displays[k]->disable(vid_dev->displays[k]);
++
++ omap_dss_put_device(vid_dev->displays[k]);
++ }
++ kfree(vid_dev);
++ return 0;
++}
++
++static int __init omap_vout_probe(struct platform_device *pdev)
++{
++ int r = 0, i;
++ struct omap2video_device *vid_dev = NULL;
++ struct omap_overlay *ovl;
++ struct omap_dss_device *def_display;
++ struct omap_dss_device *dssdev;
++
++ if (pdev->num_resources == 0) {
++ dev_err(&pdev->dev, "probed for an unknown device\n");
++ r = -ENODEV;
++ return r;
++ }
++
++ vid_dev = kzalloc(sizeof(struct omap2video_device), GFP_KERNEL);
++ if (vid_dev == NULL) {
++ r = -ENOMEM;
++ return r;
++ }
++
++ vid_dev->num_displays = 0;
++ dssdev = NULL;
++ for_each_dss_dev(dssdev) {
++ omap_dss_get_device(dssdev);
++ vid_dev->displays[vid_dev->num_displays++] = dssdev;
++ }
++
++ if (vid_dev->num_displays == 0) {
++ dev_err(&pdev->dev, "no displays\n");
++ r = -EINVAL;
++ goto error0;
++ }
++
++ vid_dev->num_overlays = omap_dss_get_num_overlays();
++ for (i = 0; i < vid_dev->num_overlays; i++)
++ vid_dev->overlays[i] = omap_dss_get_overlay(i);
++
++ vid_dev->num_managers = omap_dss_get_num_overlay_managers();
++ for (i = 0; i < vid_dev->num_managers; i++)
++ vid_dev->managers[i] = omap_dss_get_overlay_manager(i);
++
++ /* Get the Video1 overlay and video2 overlay.
++ * Setup the Display attached to that overlays
++ */
++ for (i = 1; i < 3; i++) {
++ ovl = omap_dss_get_overlay(i);
++ if (ovl->manager && ovl->manager->device) {
++ def_display = ovl->manager->device;
++ } else {
++ dev_warn(&pdev->dev, "cannot find display\n");
++ def_display = NULL;
++ }
++ if (def_display) {
++ r = def_display->enable(def_display);
++ if (r) {
++ /* Here we are not considering a error
++ * as display may be enabled by frame
++ * buffer driver
++ */
++ dev_warn(&pdev->dev,
++ "'%s' Display already enabled\n",
++ def_display->name);
++ }
++ /* set the update mode */
++ if (def_display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
++#ifdef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
++ if (def_display->enable_te)
++ def_display->enable_te(def_display, 1);
++ if (def_display->set_update_mode)
++ def_display->set_update_mode(def_display,
++ OMAP_DSS_UPDATE_AUTO);
++#else /* MANUAL_UPDATE */
++ if (def_display->enable_te)
++ def_display->enable_te(def_display, 0);
++ if (def_display->set_update_mode)
++ def_display->set_update_mode(def_display,
++ OMAP_DSS_UPDATE_MANUAL);
++#endif
++ } else {
++ if (def_display->set_update_mode)
++ def_display->set_update_mode(def_display,
++ OMAP_DSS_UPDATE_AUTO);
++ }
++ }
++ }
++
++ if (v4l2_device_register(&pdev->dev, &vid_dev->v4l2_dev) < 0) {
++ printk(KERN_ERR VOUT_NAME "v4l2_device_register failed\n");
++ return -ENODEV;
++ }
++
++ r = omap_vout_create_video_devices(pdev);
++ if (r)
++ goto error0;
++
++ for (i = 0; i < vid_dev->num_displays; i++) {
++ struct omap_dss_device *display = vid_dev->displays[i];
++
++ if (display->update)
++ display->update(display, 0, 0,
++ display->panel.timings.x_res,
++ display->panel.timings.y_res);
++ }
++ return 0;
++
++error0:
++ kfree(vid_dev);
++ return r;
++}
++
++static struct platform_driver omap_vout_driver = {
++ .driver = {
++ .name = VOUT_NAME,
++ },
++ .probe = omap_vout_probe,
++ .remove = omap_vout_remove,
++};
++
++void omap_vout_isr(void *arg, unsigned int irqstatus)
++{
++ int r;
++ struct timeval timevalue;
++ struct omap_vout_device *vout =
++ (struct omap_vout_device *) arg;
++ u32 addr, fid;
++ struct omapvideo_info *ovid;
++ struct omap_overlay *ovl;
++ struct omap_dss_device *cur_display;
++
++ if (!vout->streaming)
++ return;
++
++ ovid = &vout->vid_info;
++ ovl = ovid->overlays[0];
++ /* get the display device attached to the overlay */
++ if (!ovl->manager || !ovl->manager->device)
++ return;
++ cur_display = ovl->manager->device;
++
++ spin_lock(&vout->vbq_lock);
++ do_gettimeofday(&timevalue);
++ if (cur_display->type == OMAP_DISPLAY_TYPE_DPI) {
++ if (!(irqstatus & DISPC_IRQ_VSYNC))
++ return;
++ if (!vout->first_int && (vout->cur_frm != vout->next_frm)) {
++ vout->cur_frm->ts = timevalue;
++ vout->cur_frm->state = VIDEOBUF_DONE;
++ wake_up_interruptible(&vout->cur_frm->done);
++ vout->cur_frm = vout->next_frm;
++ }
++ vout->first_int = 0;
++ if (list_empty(&vout->dma_queue)) {
++ spin_unlock(&vout->vbq_lock);
++ return;
++ }
++
++ vout->next_frm = list_entry(vout->dma_queue.next,
++ struct videobuf_buffer, queue);
++ list_del(&vout->next_frm->queue);
++
++ vout->next_frm->state = VIDEOBUF_ACTIVE;
++
++ addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i]
++ + vout->cropped_offset;
++
++ /* First save the configuration in ovelray structure */
++ r = omapvid_init(vout, addr);
++ if (r)
++ printk(KERN_ERR VOUT_NAME "failed to set overlay info\n");
++ /* Enable the pipeline and set the Go bit */
++ r = omapvid_apply_changes(vout);
++ if (r)
++ printk(KERN_ERR VOUT_NAME "failed to change mode\n");
++ } else {
++
++ if (vout->first_int) {
++ vout->first_int = 0;
++ spin_unlock(&vout->vbq_lock);
++ return;
++ }
++ if (irqstatus & DISPC_IRQ_EVSYNC_ODD) {
++ fid = 1;
++ } else if (irqstatus & DISPC_IRQ_EVSYNC_EVEN) {
++ fid = 0;
++ } else {
++ spin_unlock(&vout->vbq_lock);
++ return;
++ }
++ vout->field_id ^= 1;
++ if (fid != vout->field_id) {
++ if (0 == fid)
++ vout->field_id = fid;
++
++ spin_unlock(&vout->vbq_lock);
++ return;
++ }
++ if (0 == fid) {
++ if (vout->cur_frm == vout->next_frm) {
++ spin_unlock(&vout->vbq_lock);
++ return;
++ }
++ vout->cur_frm->ts = timevalue;
++ vout->cur_frm->state = VIDEOBUF_DONE;
++ wake_up_interruptible(&vout->cur_frm->done);
++ vout->cur_frm = vout->next_frm;
++ } else if (1 == fid) {
++ if (list_empty(&vout->dma_queue) ||
++ (vout->cur_frm != vout->next_frm)) {
++ spin_unlock(&vout->vbq_lock);
++ return;
++ }
++ vout->next_frm = list_entry(vout->dma_queue.next,
++ struct videobuf_buffer, queue);
++ list_del(&vout->next_frm->queue);
++
++ vout->next_frm->state = VIDEOBUF_ACTIVE;
++ addr = (unsigned long)
++ vout->queued_buf_addr[vout->next_frm->i] +
++ vout->cropped_offset;
++ /* First save the configuration in ovelray structure */
++ r = omapvid_init(vout, addr);
++ if (r)
++ printk(KERN_ERR VOUT_NAME
++ "failed to set overlay info\n");
++ /* Enable the pipeline and set the Go bit */
++ r = omapvid_apply_changes(vout);
++ if (r)
++ printk(KERN_ERR VOUT_NAME
++ "failed to change mode\n");
++ }
++
++ }
++ spin_unlock(&vout->vbq_lock);
++}
++
++static void omap_vout_cleanup_device(struct omap_vout_device *vout)
++{
++ struct video_device *vfd;
++
++ if (!vout)
++ return;
++ vfd = vout->vfd;
++
++ if (vfd) {
++ if (vfd->minor == -1) {
++ /*
++ * The device was never registered, so release the
++ * video_device struct directly.
++ */
++ video_device_release(vfd);
++ } else {
++ /*
++ * The unregister function will release the video_device
++ * struct as well as unregistering it.
++ */
++ video_unregister_device(vfd);
++ }
++ }
++
++ omap_vout_release_vrfb(vout);
++
++ omap_vout_free_buffers(vout);
++ /* Free the VRFB buffer if allocated
++ * init time
++ */
++ if (vout->vrfb_static_allocation)
++ omap_vout_free_vrfb_buffers(vout);
++
++ kfree(vout);
++}
++
++static int __init omap_vout_init(void)
++{
++
++ if (platform_driver_register(&omap_vout_driver) != 0) {
++ printk(KERN_ERR VOUT_NAME ": could not register \
++ Video driver\n");
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static void omap_vout_cleanup(void)
++{
++ platform_driver_unregister(&omap_vout_driver);
++}
++
++late_initcall(omap_vout_init);
++module_exit(omap_vout_cleanup);
+diff --git a/drivers/media/video/omap/omap_voutdef.h b/drivers/media/video/omap/omap_voutdef.h
+new file mode 100644
+index 0000000..57743e5
+--- /dev/null
++++ b/drivers/media/video/omap/omap_voutdef.h
+@@ -0,0 +1,148 @@
++/*
++ * drivers/media/video/omap/omap_voutdef.h
++ *
++ * Copyright (C) 2009 Texas Instruments.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++
++#ifndef OMAP_VOUTDEF_H
++#define OMAP_VOUTDEF_H
++
++#include <mach/display.h>
++
++#define YUYV_BPP 2
++#define RGB565_BPP 2
++#define RGB24_BPP 3
++#define RGB32_BPP 4
++#define TILE_SIZE 32
++#define YUYV_VRFB_BPP 2
++#define RGB_VRFB_BPP 1
++#define MAX_CID 3
++#define MAC_VRFB_CTXS 4
++#define MAX_VOUT_DEV 2
++#define MAX_OVLS 3
++#define MAX_DISPLAYS 3
++#define MAX_MANAGERS 3
++
++/* Enum for Rotation
++ * DSS understands rotation in 0, 1, 2, 3 context
++ * while V4L2 driver understands it as 0, 90, 180, 270
++ */
++enum dss_rotation {
++ dss_rotation_0_degree = 0,
++ dss_rotation_90_degree = 1,
++ dss_rotation_180_degree = 2,
++ dss_rotation_270_degree = 3,
++};
++/*
++ * This structure is used to store the DMA transfer parameters
++ * for VRFB hidden buffer
++ */
++struct vid_vrfb_dma {
++ int dev_id;
++ int dma_ch;
++ int req_status;
++ int tx_status;
++ wait_queue_head_t wait;
++};
++
++struct omapvideo_info {
++ int id;
++ int num_overlays;
++ struct omap_overlay *overlays[MAX_OVLS];
++};
++
++struct omap2video_device {
++ struct mutex mtx;
++
++ int state;
++
++ struct v4l2_device v4l2_dev;
++ int num_videos;
++ struct omap_vout_device *vouts[MAX_VOUT_DEV];
++
++ int num_displays;
++ struct omap_dss_device *displays[MAX_DISPLAYS];
++ int num_overlays;
++ struct omap_overlay *overlays[MAX_OVLS];
++ int num_managers;
++ struct omap_overlay_manager *managers[MAX_MANAGERS];
++};
++
++/* per-device data structure */
++struct omap_vout_device {
++
++ struct omapvideo_info vid_info;
++ struct video_device *vfd;
++ struct omap2video_device *vid_dev;
++ int vid;
++ int opened;
++
++ /* we don't allow to change image fmt/size once buffer has
++ * been allocated
++ */
++ int buffer_allocated;
++ /* allow to reuse previously allocated buffer which is big enough */
++ int buffer_size;
++ /* keep buffer info across opens */
++ unsigned long buf_virt_addr[VIDEO_MAX_FRAME];
++ unsigned long buf_phy_addr[VIDEO_MAX_FRAME];
++ enum omap_color_mode dss_mode;
++
++ /* we don't allow to request new buffer when old buffers are
++ * still mmaped
++ */
++ int mmap_count;
++
++ spinlock_t vbq_lock; /* spinlock for videobuf queues */
++ unsigned long field_count; /* field counter for videobuf_buffer */
++
++ /* non-NULL means streaming is in progress. */
++ bool streaming;
++
++ struct v4l2_pix_format pix;
++ struct v4l2_rect crop;
++ struct v4l2_window win;
++ struct v4l2_framebuffer fbuf;
++
++ /* Lock to protect the shared data structures in ioctl */
++ struct mutex lock;
++
++ /* V4L2 control structure for different control id */
++ struct v4l2_control control[MAX_CID];
++ enum dss_rotation rotation;
++ bool mirror;
++ int flicker_filter;
++ /* V4L2 control structure for different control id */
++
++ int bpp; /* bytes per pixel */
++ int vrfb_bpp; /* bytes per pixel with respect to VRFB */
++
++ struct vid_vrfb_dma vrfb_dma_tx;
++ unsigned int smsshado_phy_addr[MAC_VRFB_CTXS];
++ unsigned int smsshado_virt_addr[MAC_VRFB_CTXS];
++ struct vrfb vrfb_context[MAC_VRFB_CTXS];
++ bool vrfb_static_allocation;
++ unsigned int smsshado_size;
++ unsigned char pos;
++
++ int ps, vr_ps, line_length, first_int, field_id;
++ enum v4l2_memory memory;
++ struct videobuf_buffer *cur_frm, *next_frm;
++ struct list_head dma_queue;
++ u8 *queued_buf_addr[VIDEO_MAX_FRAME];
++ u32 cropped_offset;
++ s32 tv_field1_offset;
++ void *isr_handle;
++
++ /* Buffer queue variables */
++ struct omap_vout_device *vout;
++ enum v4l2_buf_type type;
++ struct videobuf_queue vbq;
++ int io_allowed;
++
++};
++#endif /* ifndef OMAP_VOUTDEF_H */
+diff --git a/drivers/media/video/omap/omap_voutlib.c b/drivers/media/video/omap/omap_voutlib.c
+new file mode 100644
+index 0000000..bce5072
+--- /dev/null
++++ b/drivers/media/video/omap/omap_voutlib.c
+@@ -0,0 +1,258 @@
++/*
++ * drivers/media/video/omap/omap_voutlib.c
++ *
++ * Copyright (C) 2005-2009 Texas Instruments.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ *
++ * Based on the OMAP2 camera driver
++ * Video-for-Linux (Version 2) camera capture driver for
++ * the OMAP24xx camera controller.
++ *
++ * Author: Andy Lowe (source@mvista.com)
++ *
++ * Copyright (C) 2004 MontaVista Software, Inc.
++ * Copyright (C) 2009 Texas Instruments.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/videodev2.h>
++
++MODULE_AUTHOR("Texas Instruments.");
++MODULE_DESCRIPTION("OMAP Video library");
++MODULE_LICENSE("GPL");
++
++/* Return the default overlay cropping rectangle in crop given the image
++ * size in pix and the video display size in fbuf. The default
++ * cropping rectangle is the largest rectangle no larger than the capture size
++ * that will fit on the display. The default cropping rectangle is centered in
++ * the image. All dimensions and offsets are rounded down to even numbers.
++ */
++void omap_vout_default_crop(struct v4l2_pix_format *pix,
++ struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop)
++{
++ crop->width = (pix->width < fbuf->fmt.width) ?
++ pix->width : fbuf->fmt.width;
++ crop->height = (pix->height < fbuf->fmt.height) ?
++ pix->height : fbuf->fmt.height;
++ crop->width &= ~1;
++ crop->height &= ~1;
++ crop->left = ((pix->width - crop->width) >> 1) & ~1;
++ crop->top = ((pix->height - crop->height) >> 1) & ~1;
++}
++EXPORT_SYMBOL_GPL(omap_vout_default_crop);
++
++/* Given a new render window in new_win, adjust the window to the
++ * nearest supported configuration. The adjusted window parameters are
++ * returned in new_win.
++ * Returns zero if succesful, or -EINVAL if the requested window is
++ * impossible and cannot reasonably be adjusted.
++ */
++int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
++ struct v4l2_window *new_win)
++{
++ struct v4l2_rect try_win;
++
++ /* make a working copy of the new_win rectangle */
++ try_win = new_win->w;
++
++ /* adjust the preview window so it fits on the display by clipping any
++ * offscreen areas
++ */
++ if (try_win.left < 0) {
++ try_win.width += try_win.left;
++ try_win.left = 0;
++ }
++ if (try_win.top < 0) {
++ try_win.height += try_win.top;
++ try_win.top = 0;
++ }
++ try_win.width = (try_win.width < fbuf->fmt.width) ?
++ try_win.width : fbuf->fmt.width;
++ try_win.height = (try_win.height < fbuf->fmt.height) ?
++ try_win.height : fbuf->fmt.height;
++ if (try_win.left + try_win.width > fbuf->fmt.width)
++ try_win.width = fbuf->fmt.width - try_win.left;
++ if (try_win.top + try_win.height > fbuf->fmt.height)
++ try_win.height = fbuf->fmt.height - try_win.top;
++ try_win.width &= ~1;
++ try_win.height &= ~1;
++
++ if (try_win.width <= 0 || try_win.height <= 0)
++ return -EINVAL;
++
++ /* We now have a valid preview window, so go with it */
++ new_win->w = try_win;
++ new_win->field = V4L2_FIELD_ANY;
++ return 0;
++}
++EXPORT_SYMBOL_GPL(omap_vout_try_window);
++
++/* Given a new render window in new_win, adjust the window to the
++ * nearest supported configuration. The image cropping window in crop
++ * will also be adjusted if necessary. Preference is given to keeping the
++ * the window as close to the requested configuration as possible. If
++ * successful, new_win, vout->win, and crop are updated.
++ * Returns zero if succesful, or -EINVAL if the requested preview window is
++ * impossible and cannot reasonably be adjusted.
++ */
++int omap_vout_new_window(struct v4l2_rect *crop,
++ struct v4l2_window *win, struct v4l2_framebuffer *fbuf,
++ struct v4l2_window *new_win)
++{
++ int err;
++
++ err = omap_vout_try_window(fbuf, new_win);
++ if (err)
++ return err;
++
++ /* update our preview window */
++ win->w = new_win->w;
++ win->field = new_win->field;
++ win->chromakey = new_win->chromakey;
++
++ /* adjust the cropping window to allow for resizing limitations */
++ if ((crop->height/win->w.height) >= 4) {
++ /* The maximum vertical downsizing ratio is 4:1 */
++ crop->height = win->w.height * 4;
++ }
++ if ((crop->width/win->w.width) >= 4) {
++ /* The maximum horizontal downsizing ratio is 4:1 */
++ crop->width = win->w.width * 4;
++ }
++ return 0;
++}
++EXPORT_SYMBOL_GPL(omap_vout_new_window);
++
++/* Given a new cropping rectangle in new_crop, adjust the cropping rectangle to
++ * the nearest supported configuration. The image render window in win will
++ * also be adjusted if necessary. The preview window is adjusted such that the
++ * horizontal and vertical rescaling ratios stay constant. If the render
++ * window would fall outside the display boundaries, the cropping rectangle
++ * will also be adjusted to maintain the rescaling ratios. If successful, crop
++ * and win are updated.
++ * Returns zero if succesful, or -EINVAL if the requested cropping rectangle is
++ * impossible and cannot reasonably be adjusted.
++ */
++int omap_vout_new_crop(struct v4l2_pix_format *pix,
++ struct v4l2_rect *crop, struct v4l2_window *win,
++ struct v4l2_framebuffer *fbuf, const struct v4l2_rect *new_crop)
++{
++ struct v4l2_rect try_crop;
++ unsigned long vresize, hresize;
++
++ /* make a working copy of the new_crop rectangle */
++ try_crop = *new_crop;
++
++ /* adjust the cropping rectangle so it fits in the image */
++ if (try_crop.left < 0) {
++ try_crop.width += try_crop.left;
++ try_crop.left = 0;
++ }
++ if (try_crop.top < 0) {
++ try_crop.height += try_crop.top;
++ try_crop.top = 0;
++ }
++ try_crop.width = (try_crop.width < pix->width) ?
++ try_crop.width : pix->width;
++ try_crop.height = (try_crop.height < pix->height) ?
++ try_crop.height : pix->height;
++ if (try_crop.left + try_crop.width > pix->width)
++ try_crop.width = pix->width - try_crop.left;
++ if (try_crop.top + try_crop.height > pix->height)
++ try_crop.height = pix->height - try_crop.top;
++ try_crop.width &= ~1;
++ try_crop.height &= ~1;
++ if (try_crop.width <= 0 || try_crop.height <= 0)
++ return -EINVAL;
++
++ if (crop->height != win->w.height) {
++ /* If we're resizing vertically, we can't support a crop width
++ * wider than 768 pixels.
++ */
++ if (try_crop.width > 768)
++ try_crop.width = 768;
++ }
++ /* vertical resizing */
++ vresize = (1024 * crop->height) / win->w.height;
++ if (vresize > 4096)
++ vresize = 4096;
++ else if (vresize == 0)
++ vresize = 1;
++ win->w.height = ((1024 * try_crop.height) / vresize) & ~1;
++ if (win->w.height == 0)
++ win->w.height = 2;
++ if (win->w.height + win->w.top > fbuf->fmt.height) {
++ /* We made the preview window extend below the bottom of the
++ * display, so clip it to the display boundary and resize the
++ * cropping height to maintain the vertical resizing ratio.
++ */
++ win->w.height = (fbuf->fmt.height - win->w.top) & ~1;
++ if (try_crop.height == 0)
++ try_crop.height = 2;
++ }
++ /* horizontal resizing */
++ hresize = (1024 * crop->width) / win->w.width;
++ if (hresize > 4096)
++ hresize = 4096;
++ else if (hresize == 0)
++ hresize = 1;
++ win->w.width = ((1024 * try_crop.width) / hresize) & ~1;
++ if (win->w.width == 0)
++ win->w.width = 2;
++ if (win->w.width + win->w.left > fbuf->fmt.width) {
++ /* We made the preview window extend past the right side of the
++ * display, so clip it to the display boundary and resize the
++ * cropping width to maintain the horizontal resizing ratio.
++ */
++ win->w.width = (fbuf->fmt.width - win->w.left) & ~1;
++ if (try_crop.width == 0)
++ try_crop.width = 2;
++ }
++
++ /* Check for resizing constraints */
++ if ((try_crop.height/win->w.height) >= 4) {
++ /* The maximum vertical downsizing ratio is 4:1 */
++ try_crop.height = win->w.height * 4;
++ }
++ if ((try_crop.width/win->w.width) >= 4) {
++ /* The maximum horizontal downsizing ratio is 4:1 */
++ try_crop.width = win->w.width * 4;
++ }
++
++ /* update our cropping rectangle and we're done */
++ *crop = try_crop;
++ return 0;
++}
++EXPORT_SYMBOL_GPL(omap_vout_new_crop);
++
++/* Given a new format in pix and fbuf, crop and win
++ * structures are initialized to default values. crop
++ * is initialized to the largest window size that will fit on the display. The
++ * crop window is centered in the image. win is initialized to
++ * the same size as crop and is centered on the display.
++ * All sizes and offsets are constrained to be even numbers.
++ */
++void omap_vout_new_format(struct v4l2_pix_format *pix,
++ struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop,
++ struct v4l2_window *win)
++{
++ /* crop defines the preview source window in the image capture
++ * buffer
++ */
++ omap_vout_default_crop(pix, fbuf, crop);
++
++ /* win defines the preview target window on the display */
++ win->w.width = crop->width;
++ win->w.height = crop->height;
++ win->w.left = ((fbuf->fmt.width - win->w.width) >> 1) & ~1;
++ win->w.top = ((fbuf->fmt.height - win->w.height) >> 1) & ~1;
++}
++EXPORT_SYMBOL_GPL(omap_vout_new_format);
++
+diff --git a/drivers/media/video/omap/omap_voutlib.h b/drivers/media/video/omap/omap_voutlib.h
+new file mode 100644
+index 0000000..8ef6e25
+--- /dev/null
++++ b/drivers/media/video/omap/omap_voutlib.h
+@@ -0,0 +1,34 @@
++/*
++ * drivers/media/video/omap/omap_voutlib.h
++ *
++ * Copyright (C) 2009 Texas Instruments.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ *
++ */
++
++#ifndef OMAP_VOUTLIB_H
++#define OMAP_VOUTLIB_H
++
++extern void omap_vout_default_crop(struct v4l2_pix_format *pix,
++ struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop);
++
++extern int omap_vout_new_crop(struct v4l2_pix_format *pix,
++ struct v4l2_rect *crop, struct v4l2_window *win,
++ struct v4l2_framebuffer *fbuf,
++ const struct v4l2_rect *new_crop);
++
++extern int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
++ struct v4l2_window *new_win);
++
++extern int omap_vout_new_window(struct v4l2_rect *crop,
++ struct v4l2_window *win, struct v4l2_framebuffer *fbuf,
++ struct v4l2_window *new_win);
++
++extern void omap_vout_new_format(struct v4l2_pix_format *pix,
++ struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop,
++ struct v4l2_window *win);
++#endif /* #ifndef OMAP_LIB_H */
++
+--
+1.6.2.4
+