linux-omap 2.6.37: sync with OE .dev
authorKoen Kooi <koen@dominion.thruhere.net>
Thu, 10 Mar 2011 14:14:42 +0000 (15:14 +0100)
committerKoen Kooi <koen@dominion.thruhere.net>
Thu, 10 Mar 2011 14:14:42 +0000 (15:14 +0100)
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
48 files changed:
recipes-bsp/linux/linux-omap/0001-BeagleBoard-Adjust-USER-button-pin-for-xM.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/0001-beagleboard-hack-in-support-from-xM-rev-C.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/0001-omap3-allow-1GHz-mpurates.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/0001-xM-audio-fix-from-Ashok.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/beagleboard/defconfig
recipes-bsp/linux/linux-omap/media/0001-v4l-Share-code-between-video_usercopy-and-video_ioct.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0002-v4l-subdev-Don-t-require-core-operations.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0003-v4l-subdev-Merge-v4l2_i2c_new_subdev_cfg-and-v4l2_i2.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0004-v4l-subdev-Add-device-node-support.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0005-v4l-subdev-Uninline-the-v4l2_subdev_init-function.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0006-v4l-subdev-Control-ioctls-support.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0007-v4l-subdev-Events-support.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0008-media-Media-device-node-support.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0009-media-Media-device.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0010-media-Entities-pads-and-links.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0011-media-Entity-graph-traversal.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0012-media-Entity-use-count.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0013-media-Media-device-information-query.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0014-media-Entities-pads-and-links-enumeration.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0015-media-Links-setup.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0016-media-Pipelines-and-media-streams.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0017-v4l-Add-a-media_device-pointer-to-the-v4l2_device-st.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0018-v4l-Make-video_device-inherit-from-media_entity.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0019-v4l-Make-v4l2_subdev-inherit-from-media_entity.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0020-v4l-Move-the-media-v4l2-mediabus.h-header-to-include.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0021-v4l-Replace-enums-with-fixed-sized-fields-in-public-.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0022-v4l-Rename-V4L2_MBUS_FMT_GREY8_1X8-to-V4L2_MBUS_FMT_.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0023-v4l-Group-media-bus-pixel-codes-by-types-and-sort-th.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0024-v4l-Create-v4l2-subdev-file-handle-structure.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0025-v4l-subdev-Add-a-new-file-operations-class.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0026-v4l-v4l2_subdev-pad-level-operations.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0028-v4l-v4l2_subdev-userspace-format-API.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0029-v4l-v4l2_subdev-userspace-frame-interval-API.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0030-v4l-v4l2_subdev-userspace-crop-API.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0031-v4l-subdev-Generic-ioctl-support.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0032-v4l-Add-subdev-sensor-g_skip_frames-operation.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0033-v4l-Include-linux-videodev2.h-in-media-v4l2-ctrls.h.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0034-v4l-Fix-a-use-before-set-in-the-control-framework.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0035-v4l-Add-8-bit-YUYV-on-16-bit-bus-and-SGRBG10-media-b.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0036-v4l-Add-remaining-RAW10-patterns-w-DPCM-pixel-code-v.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0037-v4l-Add-missing-12-bits-bayer-media-bus-formats.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0038-v4l-Add-12-bits-bayer-pixel-formats.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0039-ARM-OMAP3-Update-Camera-ISP-definitions-for-OMAP3630.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0040-omap3-Remove-unusued-ISP-CBUFF-resource.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0041-omap3-Add-function-to-register-omap3isp-platform-dev.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0042-omap2-Fix-camera-resources-for-multiomap.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap/media/0043-OMAP3-ISP-driver.patch [new file with mode: 0644]
recipes-bsp/linux/linux-omap_2.6.37.bb

diff --git a/recipes-bsp/linux/linux-omap/0001-BeagleBoard-Adjust-USER-button-pin-for-xM.patch b/recipes-bsp/linux/linux-omap/0001-BeagleBoard-Adjust-USER-button-pin-for-xM.patch
new file mode 100644 (file)
index 0000000..44397d4
--- /dev/null
@@ -0,0 +1,29 @@
+From 3b1dc08ab568d1fdbc2a3731d7643cfeb48023e8 Mon Sep 17 00:00:00 2001
+From: Koen Kooi <koen@dominion.thruhere.net>
+Date: Thu, 10 Mar 2011 14:16:08 +0100
+Subject: [PATCH] BeagleBoard: Adjust USER button pin for xM
+
+Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c |    5 +++++
+ 1 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 731f4b5..fae3104 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -949,6 +949,11 @@ static void __init omap3_beagle_init(void)
+       omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+       omap3_beagle_init_rev();
+       omap3_beagle_i2c_init();
++
++      if (cpu_is_omap3630()) {
++              gpio_buttons[0].gpio = 4;
++      }
++
+       platform_add_devices(omap3_beagle_devices,
+                       ARRAY_SIZE(omap3_beagle_devices));
+       omap_serial_init();
+-- 
+1.7.0
+
diff --git a/recipes-bsp/linux/linux-omap/0001-beagleboard-hack-in-support-from-xM-rev-C.patch b/recipes-bsp/linux/linux-omap/0001-beagleboard-hack-in-support-from-xM-rev-C.patch
new file mode 100644 (file)
index 0000000..77c2928
--- /dev/null
@@ -0,0 +1,94 @@
+From d9c289c5f98bb109aa7a9e5a802638ba89639e70 Mon Sep 17 00:00:00 2001
+From: Koen Kooi <koen@dominion.thruhere.net>
+Date: Thu, 10 Mar 2011 13:15:38 +0100
+Subject: [PATCH] beagleboard: hack in support from xM rev C
+
+Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c |   20 +++++++++++++-------
+ 1 files changed, 13 insertions(+), 7 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 6abb79a..731f4b5 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -64,6 +64,7 @@
+  *    C4      = GPIO173, GPIO172, GPIO171: 1 0 1
+  *    XMA     = GPIO173, GPIO172, GPIO171: 0 0 0
+  *    XMB     = GPIO173, GPIO172, GPIO171: 0 0 1
++ *  XMC = GPIO173, GPIO172, GPIO171: 0 1 0
+  */
+ enum {
+       OMAP3BEAGLE_BOARD_UNKN = 0,
+@@ -71,6 +72,7 @@ enum {
+       OMAP3BEAGLE_BOARD_C1_3,
+       OMAP3BEAGLE_BOARD_C4,
+       OMAP3BEAGLE_BOARD_XM,
++      OMAP3BEAGLE_BOARD_XMC,
+ };
+ static u8 omap3_beagle_version;
+@@ -129,9 +131,13 @@ static void __init omap3_beagle_init_rev(void)
+               printk(KERN_INFO "OMAP3 Beagle Rev: xM B\n");
+               omap3_beagle_version = OMAP3BEAGLE_BOARD_XM;
+               break;
++      case 2:
++              printk(KERN_INFO "OMAP3 Beagle Rev: xM C\n");
++              omap3_beagle_version = OMAP3BEAGLE_BOARD_XMC;
++              break;
+       default:
+-              printk(KERN_INFO "OMAP3 Beagle Rev: unknown %hd\n", beagle_rev);
+-              omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN;
++              printk(KERN_INFO "OMAP3 Beagle Rev: unknown %hd, assuming xM C or newer\n", beagle_rev);
++              omap3_beagle_version = OMAP3BEAGLE_BOARD_XMC;
+       }
+       return;
+@@ -484,7 +490,7 @@ static int beagle_twl_gpio_setup(struct device *dev,
+ {
+       int r;
+-      if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
++      if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM || omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XMC) {
+               mmc[0].gpio_wp = -EINVAL;
+       } else if ((omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C1_3) ||
+               (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C4)) {
+@@ -517,7 +523,7 @@ static int beagle_twl_gpio_setup(struct device *dev,
+       /* REVISIT: need ehci-omap hooks for external VBUS
+        * power switch and overcurrent detect
+        */
+-      if (omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XM) {
++      if (omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XM && omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XMC) {
+               r = gpio_request(gpio + 1, "EHCI_nOC");
+               if (!r) {
+                       r = gpio_direction_input(gpio + 1);
+@@ -539,7 +545,7 @@ static int beagle_twl_gpio_setup(struct device *dev,
+               gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0);
+       /* DVI reset GPIO is different between beagle revisions */
+-      if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM)
++      if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM || omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XMC)
+               beagle_dvi_device.reset_gpio = 129;
+       else
+               beagle_dvi_device.reset_gpio = 170;
+@@ -553,7 +559,7 @@ static int beagle_twl_gpio_setup(struct device *dev,
+        * P7/P8 revisions(prototype): Camera EN
+        * A2+ revisions (production): LDO (supplies DVI, serial, led blocks)
+        */
+-      if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
++      if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM || omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XMC) {
+               r = gpio_request(gpio + 1, "nDVI_PWR_EN");
+               if (!r) {
+                       r = gpio_direction_output(gpio + 1, 0);
+@@ -899,7 +905,7 @@ static void __init beagle_opp_init(void)
+       }
+       /* Custom OPP enabled for XM */
+-      if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
++      if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM || omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XMC) {
+               struct omap_hwmod *mh = omap_hwmod_lookup("mpu");
+               struct omap_hwmod *dh = omap_hwmod_lookup("iva");
+               struct device *dev;
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/0001-omap3-allow-1GHz-mpurates.patch b/recipes-bsp/linux/linux-omap/0001-omap3-allow-1GHz-mpurates.patch
new file mode 100644 (file)
index 0000000..f84163c
--- /dev/null
@@ -0,0 +1,26 @@
+From 095749d8941257799eaf5b2509918373f1a08152 Mon Sep 17 00:00:00 2001
+From: Koen Kooi <koen@dominion.thruhere.net>
+Date: Thu, 10 Mar 2011 14:03:08 +0100
+Subject: [PATCH] omap3: allow 1GHz mpurates
+
+Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
+---
+ arch/arm/plat-omap/clock.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
+index fc62fb5..f3e3d29 100644
+--- a/arch/arm/plat-omap/clock.c
++++ b/arch/arm/plat-omap/clock.c
+@@ -181,7 +181,7 @@ static int __init omap_clk_setup(char *str)
+       if (!mpurate)
+               return 1;
+-      if (mpurate < 1000)
++      if (mpurate < 2000)
+               mpurate *= 1000000;
+       return 1;
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/0001-xM-audio-fix-from-Ashok.patch b/recipes-bsp/linux/linux-omap/0001-xM-audio-fix-from-Ashok.patch
new file mode 100644 (file)
index 0000000..1254c80
--- /dev/null
@@ -0,0 +1,27 @@
+From d53f988fc10fe22ec7e64457eac22f264bb72491 Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Thu, 13 Jan 2011 11:37:56 -0600
+Subject: [PATCH] xM audio fix from Ashok
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ sound/soc/omap/omap-mcbsp.c |    3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
+index 7e84f24..1038686 100644
+--- a/sound/soc/omap/omap-mcbsp.c
++++ b/sound/soc/omap/omap-mcbsp.c
+@@ -332,6 +332,9 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
+       } else if (cpu_is_omap343x()) {
+               dma = omap24xx_dma_reqs[bus_id][substream->stream];
+               port = omap34xx_mcbsp_port[bus_id][substream->stream];
++      } else if (cpu_is_omap3630()) {
++              dma = omap24xx_dma_reqs[bus_id][substream->stream];
++              port = omap34xx_mcbsp_port[bus_id][substream->stream];
+       } else {
+               return -ENODEV;
+       }
+-- 
+1.7.1
+
index cb21bec1f52a020bba3725d6185a96aa25d454e9..738d89496478ed624891d0f91eb97cc09afcb614 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux/arm 2.6.37 Kernel Configuration
-# Sun Jan 23 11:58:18 2011
+# Thu Jan 27 16:18:14 2011
 #
 CONFIG_ARM=y
 CONFIG_HAVE_PWM=y
@@ -286,6 +286,8 @@ CONFIG_OMAP_RESET_CLOCKS=y
 CONFIG_OMAP_MCBSP=y
 CONFIG_OMAP_MBOX_FWK=m
 CONFIG_OMAP_MBOX_KFIFO_SIZE=256
+CONFIG_OMAP_IOMMU=m
+CONFIG_OMAP_IOMMU_DEBUG=m
 # CONFIG_OMAP_MPU_TIMER is not set
 CONFIG_OMAP_32K_TIMER=y
 # CONFIG_OMAP3_L2_AUX_SECURE_SAVE_RESTORE is not set
@@ -1846,10 +1848,12 @@ CONFIG_MEDIA_SUPPORT=y
 #
 # Multimedia core support
 #
+CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
 CONFIG_VIDEO_V4L2_COMMON=y
 CONFIG_VIDEO_ALLOW_V4L1=y
 CONFIG_VIDEO_V4L1_COMPAT=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_DVB_CORE=m
 CONFIG_VIDEO_MEDIA=m
 
@@ -1991,6 +1995,8 @@ CONFIG_VIDEO_OMAP2_VOUT=y
 # CONFIG_VIDEO_CPIA2 is not set
 # CONFIG_VIDEO_AU0828 is not set
 CONFIG_VIDEO_SR030PC30=m
+CONFIG_VIDEO_OMAP3=y
+# CONFIG_VIDEO_OMAP3_DEBUG is not set
 # CONFIG_SOC_CAMERA is not set
 CONFIG_V4L_USB_DRIVERS=y
 CONFIG_USB_VIDEO_CLASS=m
diff --git a/recipes-bsp/linux/linux-omap/media/0001-v4l-Share-code-between-video_usercopy-and-video_ioct.patch b/recipes-bsp/linux/linux-omap/media/0001-v4l-Share-code-between-video_usercopy-and-video_ioct.patch
new file mode 100644 (file)
index 0000000..f212020
--- /dev/null
@@ -0,0 +1,297 @@
+From d71c2e533be956a95e4ddde8b87f657ada3c9de3 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Mon, 12 Jul 2010 16:09:41 +0200
+Subject: [PATCH 01/43] v4l: Share code between video_usercopy and video_ioctl2
+
+The two functions are mostly identical. They handle the copy_from_user
+and copy_to_user operations related with V4L2 ioctls and call the real
+ioctl handler.
+
+Create a __video_usercopy function that implements the core of
+video_usercopy and video_ioctl2, and call that function from both.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ drivers/media/video/v4l2-ioctl.c |  218 ++++++++++++-------------------------
+ 1 files changed, 71 insertions(+), 147 deletions(-)
+
+diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
+index dd9283f..1e01554 100644
+--- a/drivers/media/video/v4l2-ioctl.c
++++ b/drivers/media/video/v4l2-ioctl.c
+@@ -374,35 +374,62 @@ video_fix_command(unsigned int cmd)
+ }
+ #endif
+-/*
+- * Obsolete usercopy function - Should be removed soon
+- */
+-long
+-video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
++/* In some cases, only a few fields are used as input, i.e. when the app sets
++ * "index" and then the driver fills in the rest of the structure for the thing
++ * with that index.  We only need to copy up the first non-input field.  */
++static unsigned long cmd_input_size(unsigned int cmd)
++{
++      /* Size of structure up to and including 'field' */
++#define CMDINSIZE(cmd, type, field)                           \
++      case VIDIOC_##cmd:                                      \
++              return offsetof(struct v4l2_##type, field) +    \
++                      sizeof(((struct v4l2_##type *)0)->field);
++
++      switch (cmd) {
++              CMDINSIZE(ENUM_FMT,             fmtdesc,        type);
++              CMDINSIZE(G_FMT,                format,         type);
++              CMDINSIZE(QUERYBUF,             buffer,         type);
++              CMDINSIZE(G_PARM,               streamparm,     type);
++              CMDINSIZE(ENUMSTD,              standard,       index);
++              CMDINSIZE(ENUMINPUT,            input,          index);
++              CMDINSIZE(G_CTRL,               control,        id);
++              CMDINSIZE(G_TUNER,              tuner,          index);
++              CMDINSIZE(QUERYCTRL,            queryctrl,      id);
++              CMDINSIZE(QUERYMENU,            querymenu,      index);
++              CMDINSIZE(ENUMOUTPUT,           output,         index);
++              CMDINSIZE(G_MODULATOR,          modulator,      index);
++              CMDINSIZE(G_FREQUENCY,          frequency,      tuner);
++              CMDINSIZE(CROPCAP,              cropcap,        type);
++              CMDINSIZE(G_CROP,               crop,           type);
++              CMDINSIZE(ENUMAUDIO,            audio,          index);
++              CMDINSIZE(ENUMAUDOUT,           audioout,       index);
++              CMDINSIZE(ENCODER_CMD,          encoder_cmd,    flags);
++              CMDINSIZE(TRY_ENCODER_CMD,      encoder_cmd,    flags);
++              CMDINSIZE(G_SLICED_VBI_CAP,     sliced_vbi_cap, type);
++              CMDINSIZE(ENUM_FRAMESIZES,      frmsizeenum,    pixel_format);
++              CMDINSIZE(ENUM_FRAMEINTERVALS,  frmivalenum,    height);
++      default:
++              return _IOC_SIZE(cmd);
++      }
++}
++
++static long
++__video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+               v4l2_kioctl func)
+ {
+       char    sbuf[128];
+       void    *mbuf = NULL;
+-      void    *parg = NULL;
++      void    *parg = (void *)arg;
+       long    err  = -EINVAL;
+       int     is_ext_ctrl;
+       size_t  ctrls_size = 0;
+       void __user *user_ptr = NULL;
+-#ifdef __OLD_VIDIOC_
+-      cmd = video_fix_command(cmd);
+-#endif
+       is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
+                      cmd == VIDIOC_TRY_EXT_CTRLS);
+       /*  Copy arguments into temp kernel buffer  */
+-      switch (_IOC_DIR(cmd)) {
+-      case _IOC_NONE:
+-              parg = NULL;
+-              break;
+-      case _IOC_READ:
+-      case _IOC_WRITE:
+-      case (_IOC_WRITE | _IOC_READ):
++      if (_IOC_DIR(cmd) != _IOC_NONE) {
+               if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+                       parg = sbuf;
+               } else {
+@@ -414,11 +441,21 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+               }
+               err = -EFAULT;
+-              if (_IOC_DIR(cmd) & _IOC_WRITE)
+-                      if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
++              if (_IOC_DIR(cmd) & _IOC_WRITE) {
++                      unsigned long n = cmd_input_size(cmd);
++
++                      if (copy_from_user(parg, (void __user *)arg, n))
+                               goto out;
+-              break;
++
++                      /* zero out anything we don't copy from userspace */
++                      if (n < _IOC_SIZE(cmd))
++                              memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n);
++              } else {
++                      /* read-only ioctl */
++                      memset(parg, 0, _IOC_SIZE(cmd));
++              }
+       }
++
+       if (is_ext_ctrl) {
+               struct v4l2_ext_controls *p = parg;
+@@ -440,7 +477,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+               }
+       }
+-      /* call driver */
++      /* Handles IOCTL */
+       err = func(file, cmd, parg);
+       if (err == -ENOIOCTLCMD)
+               err = -EINVAL;
+@@ -469,6 +506,19 @@ out:
+       kfree(mbuf);
+       return err;
+ }
++
++/*
++ * Obsolete usercopy function - Should be removed soon
++ */
++long
++video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
++              v4l2_kioctl func)
++{
++#ifdef __OLD_VIDIOC_
++      cmd = video_fix_command(cmd);
++#endif
++      return __video_usercopy(file, cmd, arg, func);
++}
+ EXPORT_SYMBOL(video_usercopy);
+ static void dbgbuf(unsigned int cmd, struct video_device *vfd,
+@@ -2041,138 +2091,12 @@ static long __video_do_ioctl(struct file *file,
+       return ret;
+ }
+-/* In some cases, only a few fields are used as input, i.e. when the app sets
+- * "index" and then the driver fills in the rest of the structure for the thing
+- * with that index.  We only need to copy up the first non-input field.  */
+-static unsigned long cmd_input_size(unsigned int cmd)
+-{
+-      /* Size of structure up to and including 'field' */
+-#define CMDINSIZE(cmd, type, field)                           \
+-      case VIDIOC_##cmd:                                      \
+-              return offsetof(struct v4l2_##type, field) +    \
+-                      sizeof(((struct v4l2_##type *)0)->field);
+-
+-      switch (cmd) {
+-              CMDINSIZE(ENUM_FMT,             fmtdesc,        type);
+-              CMDINSIZE(G_FMT,                format,         type);
+-              CMDINSIZE(QUERYBUF,             buffer,         type);
+-              CMDINSIZE(G_PARM,               streamparm,     type);
+-              CMDINSIZE(ENUMSTD,              standard,       index);
+-              CMDINSIZE(ENUMINPUT,            input,          index);
+-              CMDINSIZE(G_CTRL,               control,        id);
+-              CMDINSIZE(G_TUNER,              tuner,          index);
+-              CMDINSIZE(QUERYCTRL,            queryctrl,      id);
+-              CMDINSIZE(QUERYMENU,            querymenu,      index);
+-              CMDINSIZE(ENUMOUTPUT,           output,         index);
+-              CMDINSIZE(G_MODULATOR,          modulator,      index);
+-              CMDINSIZE(G_FREQUENCY,          frequency,      tuner);
+-              CMDINSIZE(CROPCAP,              cropcap,        type);
+-              CMDINSIZE(G_CROP,               crop,           type);
+-              CMDINSIZE(ENUMAUDIO,            audio,          index);
+-              CMDINSIZE(ENUMAUDOUT,           audioout,       index);
+-              CMDINSIZE(ENCODER_CMD,          encoder_cmd,    flags);
+-              CMDINSIZE(TRY_ENCODER_CMD,      encoder_cmd,    flags);
+-              CMDINSIZE(G_SLICED_VBI_CAP,     sliced_vbi_cap, type);
+-              CMDINSIZE(ENUM_FRAMESIZES,      frmsizeenum,    pixel_format);
+-              CMDINSIZE(ENUM_FRAMEINTERVALS,  frmivalenum,    height);
+-      default:
+-              return _IOC_SIZE(cmd);
+-      }
+-}
+-
+ long video_ioctl2(struct file *file,
+              unsigned int cmd, unsigned long arg)
+ {
+-      char    sbuf[128];
+-      void    *mbuf = NULL;
+-      void    *parg = (void *)arg;
+-      long    err  = -EINVAL;
+-      int     is_ext_ctrl;
+-      size_t  ctrls_size = 0;
+-      void __user *user_ptr = NULL;
+-
+ #ifdef __OLD_VIDIOC_
+       cmd = video_fix_command(cmd);
+ #endif
+-      is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
+-                     cmd == VIDIOC_TRY_EXT_CTRLS);
+-
+-      /*  Copy arguments into temp kernel buffer  */
+-      if (_IOC_DIR(cmd) != _IOC_NONE) {
+-              if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+-                      parg = sbuf;
+-              } else {
+-                      /* too big to allocate from stack */
+-                      mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
+-                      if (NULL == mbuf)
+-                              return -ENOMEM;
+-                      parg = mbuf;
+-              }
+-
+-              err = -EFAULT;
+-              if (_IOC_DIR(cmd) & _IOC_WRITE) {
+-                      unsigned long n = cmd_input_size(cmd);
+-
+-                      if (copy_from_user(parg, (void __user *)arg, n))
+-                              goto out;
+-
+-                      /* zero out anything we don't copy from userspace */
+-                      if (n < _IOC_SIZE(cmd))
+-                              memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n);
+-              } else {
+-                      /* read-only ioctl */
+-                      memset(parg, 0, _IOC_SIZE(cmd));
+-              }
+-      }
+-
+-      if (is_ext_ctrl) {
+-              struct v4l2_ext_controls *p = parg;
+-
+-              /* In case of an error, tell the caller that it wasn't
+-                 a specific control that caused it. */
+-              p->error_idx = p->count;
+-              user_ptr = (void __user *)p->controls;
+-              if (p->count) {
+-                      ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
+-                      /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
+-                      mbuf = kmalloc(ctrls_size, GFP_KERNEL);
+-                      err = -ENOMEM;
+-                      if (NULL == mbuf)
+-                              goto out_ext_ctrl;
+-                      err = -EFAULT;
+-                      if (copy_from_user(mbuf, user_ptr, ctrls_size))
+-                              goto out_ext_ctrl;
+-                      p->controls = mbuf;
+-              }
+-      }
+-
+-      /* Handles IOCTL */
+-      err = __video_do_ioctl(file, cmd, parg);
+-      if (err == -ENOIOCTLCMD)
+-              err = -EINVAL;
+-      if (is_ext_ctrl) {
+-              struct v4l2_ext_controls *p = parg;
+-
+-              p->controls = (void *)user_ptr;
+-              if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
+-                      err = -EFAULT;
+-              goto out_ext_ctrl;
+-      }
+-      if (err < 0)
+-              goto out;
+-
+-out_ext_ctrl:
+-      /*  Copy results into user buffer  */
+-      switch (_IOC_DIR(cmd)) {
+-      case _IOC_READ:
+-      case (_IOC_WRITE | _IOC_READ):
+-              if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
+-                      err = -EFAULT;
+-              break;
+-      }
+-
+-out:
+-      kfree(mbuf);
+-      return err;
++      return __video_usercopy(file, cmd, arg, __video_do_ioctl);
+ }
+ EXPORT_SYMBOL(video_ioctl2);
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0002-v4l-subdev-Don-t-require-core-operations.patch b/recipes-bsp/linux/linux-omap/media/0002-v4l-subdev-Don-t-require-core-operations.patch
new file mode 100644 (file)
index 0000000..c53c18e
--- /dev/null
@@ -0,0 +1,31 @@
+From e501e49dfa290479eaf23fcc5bd0623102220e0c Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Mon, 31 May 2010 11:33:06 +0300
+Subject: [PATCH 02/43] v4l: subdev: Don't require core operations
+
+There's no reason to require subdevices to implement the core
+operations. Remove the check for non-NULL core operations when
+initializing the subdev.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ include/media/v4l2-subdev.h |    3 +--
+ 1 files changed, 1 insertions(+), 2 deletions(-)
+
+diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
+index b0316a7..b636444 100644
+--- a/include/media/v4l2-subdev.h
++++ b/include/media/v4l2-subdev.h
+@@ -466,8 +466,7 @@ static inline void v4l2_subdev_init(struct v4l2_subdev *sd,
+                                       const struct v4l2_subdev_ops *ops)
+ {
+       INIT_LIST_HEAD(&sd->list);
+-      /* ops->core MUST be set */
+-      BUG_ON(!ops || !ops->core);
++      BUG_ON(!ops);
+       sd->ops = ops;
+       sd->v4l2_dev = NULL;
+       sd->flags = 0;
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0003-v4l-subdev-Merge-v4l2_i2c_new_subdev_cfg-and-v4l2_i2.patch b/recipes-bsp/linux/linux-omap/media/0003-v4l-subdev-Merge-v4l2_i2c_new_subdev_cfg-and-v4l2_i2.patch
new file mode 100644 (file)
index 0000000..6cca7ea
--- /dev/null
@@ -0,0 +1,132 @@
+From 2c7009851d70caeb91ac806b133b7d77c5c2ca19 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Thu, 8 Jul 2010 12:01:09 +0200
+Subject: [PATCH 03/43] v4l: subdev: Merge v4l2_i2c_new_subdev_cfg and v4l2_i2c_new_subdev
+
+v4l2_i2c_new_subdev is a thin wrapper around v4l2_i2c_new_subdev_cfg,
+which is itself a wrapper around v4l2_i2c_new_subdev_board.
+
+The intermediate v4l2_i2c_new_subdev_cfg function is called directly by
+the ivtv and cafe-ccic drivers only. Merge it with v4l2_i2c_new_subdev
+and use v4l2_i2c_new_subdev_board in the ivtv and cafe-ccic drivers.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ drivers/media/video/cafe_ccic.c     |   11 +++++++++--
+ drivers/media/video/ivtv/ivtv-i2c.c |   11 +++++++++--
+ drivers/media/video/v4l2-common.c   |    7 ++-----
+ include/media/v4l2-common.h         |   13 +------------
+ 4 files changed, 21 insertions(+), 21 deletions(-)
+
+diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
+index 0dfff50..6e23add 100644
+--- a/drivers/media/video/cafe_ccic.c
++++ b/drivers/media/video/cafe_ccic.c
+@@ -1992,6 +1992,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
+ {
+       int ret;
+       struct cafe_camera *cam;
++      struct i2c_board_info info;
+       struct ov7670_config sensor_cfg = {
+               /* This controller only does SMBUS */
+               .use_smbus = true,
+@@ -2065,8 +2066,14 @@ static int cafe_pci_probe(struct pci_dev *pdev,
+               sensor_cfg.clock_speed = 45;
+       cam->sensor_addr = 0x42;
+-      cam->sensor = v4l2_i2c_new_subdev_cfg(&cam->v4l2_dev, &cam->i2c_adapter,
+-                      "ov7670", 0, &sensor_cfg, cam->sensor_addr, NULL);
++
++      memset(&info, 0, sizeof(info));
++      strlcpy(info.type, "ov7670", sizeof(info.type));
++      info.addr = cam->sensor_addr;
++      info.platform_data = &sensor_cfg;
++
++      cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev,
++                      &cam->i2c_adapter, &info, NULL);
+       if (cam->sensor == NULL) {
+               ret = -ENODEV;
+               goto out_smbus;
+diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
+index 665191c..6651a6c 100644
+--- a/drivers/media/video/ivtv/ivtv-i2c.c
++++ b/drivers/media/video/ivtv/ivtv-i2c.c
+@@ -267,10 +267,17 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
+                               adap, type, 0, I2C_ADDRS(hw_addrs[idx]));
+       } else if (hw == IVTV_HW_CX25840) {
+               struct cx25840_platform_data pdata;
++              struct i2c_board_info info;
+               pdata.pvr150_workaround = itv->pvr150_workaround;
+-              sd = v4l2_i2c_new_subdev_cfg(&itv->v4l2_dev,
+-                              adap, type, 0, &pdata, hw_addrs[idx], NULL);
++
++              memset(&info, 0, sizeof(info));
++              strlcpy(info.type, type, sizeof(info.type));
++              info.addr = hw_addrs[idx];
++              info.platform_data = &pdata;
++
++              sd = v4l2_i2c_new_subdev_board(&itv->v4l2_dev, adap, &info,
++                                             NULL);
+       } else {
+               sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
+                               adap, type, hw_addrs[idx], NULL);
+diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
+index b5eb1f3..e007e61 100644
+--- a/drivers/media/video/v4l2-common.c
++++ b/drivers/media/video/v4l2-common.c
+@@ -428,9 +428,8 @@ error:
+ }
+ EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board);
+-struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
++struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
+               struct i2c_adapter *adapter, const char *client_type,
+-              int irq, void *platform_data,
+               u8 addr, const unsigned short *probe_addrs)
+ {
+       struct i2c_board_info info;
+@@ -440,12 +439,10 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
+       memset(&info, 0, sizeof(info));
+       strlcpy(info.type, client_type, sizeof(info.type));
+       info.addr = addr;
+-      info.irq = irq;
+-      info.platform_data = platform_data;
+       return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, probe_addrs);
+ }
+-EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_cfg);
++EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev);
+ /* Return i2c client address of v4l2_subdev. */
+ unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd)
+diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
+index 239125a..565fb32 100644
+--- a/include/media/v4l2-common.h
++++ b/include/media/v4l2-common.h
+@@ -138,21 +138,10 @@ struct v4l2_subdev_ops;
+ /* Load an i2c module and return an initialized v4l2_subdev struct.
+    The client_type argument is the name of the chip that's on the adapter. */
+-struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
++struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
+               struct i2c_adapter *adapter, const char *client_type,
+-              int irq, void *platform_data,
+               u8 addr, const unsigned short *probe_addrs);
+-/* Load an i2c module and return an initialized v4l2_subdev struct.
+-   The client_type argument is the name of the chip that's on the adapter. */
+-static inline struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
+-              struct i2c_adapter *adapter, const char *client_type,
+-              u8 addr, const unsigned short *probe_addrs)
+-{
+-      return v4l2_i2c_new_subdev_cfg(v4l2_dev, adapter, client_type, 0, NULL,
+-                                     addr, probe_addrs);
+-}
+-
+ struct i2c_board_info;
+ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0004-v4l-subdev-Add-device-node-support.patch b/recipes-bsp/linux/linux-omap/media/0004-v4l-subdev-Add-device-node-support.patch
new file mode 100644 (file)
index 0000000..8fe2a9d
--- /dev/null
@@ -0,0 +1,615 @@
+From e5b8af4e36ca5e922dd2b881d6c215e9d4d30a6f Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:38:49 +0100
+Subject: [PATCH 04/43] v4l: subdev: Add device node support
+
+Create a device node named subdevX for every registered subdev.
+
+As the device node is registered before the subdev core::s_config
+function is called, return -EGAIN on open until initialization
+completes.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Vimarsh Zutshi <vimarsh.zutshi@nokia.com>
+---
+ Documentation/video4linux/v4l2-framework.txt |   18 +++++++
+ drivers/media/radio/radio-si4713.c           |    2 +-
+ drivers/media/video/Makefile                 |    2 +-
+ drivers/media/video/cafe_ccic.c              |    2 +-
+ drivers/media/video/davinci/vpfe_capture.c   |    2 +-
+ drivers/media/video/davinci/vpif_capture.c   |    2 +-
+ drivers/media/video/davinci/vpif_display.c   |    2 +-
+ drivers/media/video/ivtv/ivtv-i2c.c          |    2 +-
+ drivers/media/video/s5p-fimc/fimc-capture.c  |    2 +-
+ drivers/media/video/sh_vou.c                 |    2 +-
+ drivers/media/video/soc_camera.c             |    2 +-
+ drivers/media/video/v4l2-common.c            |   15 +++++-
+ drivers/media/video/v4l2-dev.c               |   27 ++++------
+ drivers/media/video/v4l2-device.c            |   24 +++++++++-
+ drivers/media/video/v4l2-ioctl.c             |    2 +-
+ drivers/media/video/v4l2-subdev.c            |   66 ++++++++++++++++++++++++++
+ include/media/v4l2-common.h                  |    5 +-
+ include/media/v4l2-dev.h                     |   18 ++++++-
+ include/media/v4l2-ioctl.h                   |    3 +
+ include/media/v4l2-subdev.h                  |   16 ++++++-
+ 20 files changed, 176 insertions(+), 38 deletions(-)
+ create mode 100644 drivers/media/video/v4l2-subdev.c
+
+diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
+index f22f35c..4c9185a 100644
+--- a/Documentation/video4linux/v4l2-framework.txt
++++ b/Documentation/video4linux/v4l2-framework.txt
+@@ -319,6 +319,24 @@ controlled through GPIO pins. This distinction is only relevant when setting
+ up the device, but once the subdev is registered it is completely transparent.
++V4L2 sub-device userspace API
++-----------------------------
++
++Beside exposing a kernel API through the v4l2_subdev_ops structure, V4L2
++sub-devices can also be controlled directly by userspace applications.
++
++When a sub-device is registered, a device node named v4l-subdevX can be created
++in /dev. If the sub-device supports direct userspace configuration it must set
++the V4L2_SUBDEV_FL_HAS_DEVNODE flag before being registered.
++
++For I2C and SPI sub-devices, the v4l2_device driver can disable registration of
++the device node if it wants to control the sub-device on its own. In that case
++it must set the v4l2_i2c_new_subdev_board or v4l2_spi_new_subdev enable_devnode
++argument to 0. Setting the argument to 1 will only enable device node
++registration if the sub-device driver has set the V4L2_SUBDEV_FL_HAS_DEVNODE
++flag.
++
++
+ I2C sub-device drivers
+ ----------------------
+diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c
+index 726d367..f7c942f 100644
+--- a/drivers/media/radio/radio-si4713.c
++++ b/drivers/media/radio/radio-si4713.c
+@@ -293,7 +293,7 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
+       }
+       sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter,
+-                                      pdata->subdev_board_info, NULL);
++                                      pdata->subdev_board_info, NULL, 0);
+       if (!sd) {
+               dev_err(&pdev->dev, "Cannot get v4l2 subdevice\n");
+               rval = -ENODEV;
+diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
+index af79d47..adc1bd5 100644
+--- a/drivers/media/video/Makefile
++++ b/drivers/media/video/Makefile
+@@ -11,7 +11,7 @@ stkwebcam-objs       :=      stk-webcam.o stk-sensor.o
+ omap2cam-objs :=      omap24xxcam.o omap24xxcam-dma.o
+ videodev-objs :=      v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
+-                      v4l2-event.o v4l2-ctrls.o
++                      v4l2-event.o v4l2-ctrls.o v4l2-subdev.o
+ # V4L2 core modules
+diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
+index 6e23add..f932da1 100644
+--- a/drivers/media/video/cafe_ccic.c
++++ b/drivers/media/video/cafe_ccic.c
+@@ -2073,7 +2073,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
+       info.platform_data = &sensor_cfg;
+       cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev,
+-                      &cam->i2c_adapter, &info, NULL);
++                      &cam->i2c_adapter, &info, NULL, 0);
+       if (cam->sensor == NULL) {
+               ret = -ENODEV;
+               goto out_smbus;
+diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c
+index 7333a9b..bfc2a47 100644
+--- a/drivers/media/video/davinci/vpfe_capture.c
++++ b/drivers/media/video/davinci/vpfe_capture.c
+@@ -1987,7 +1987,7 @@ static __init int vpfe_probe(struct platform_device *pdev)
+                       v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev,
+                                                 i2c_adap,
+                                                 &sdinfo->board_info,
+-                                                NULL);
++                                                NULL, 0);
+               if (vpfe_dev->sd[i]) {
+                       v4l2_info(&vpfe_dev->v4l2_dev,
+                                 "v4l2 sub device %s registered\n",
+diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c
+index 193abab..d2228e0 100644
+--- a/drivers/media/video/davinci/vpif_capture.c
++++ b/drivers/media/video/davinci/vpif_capture.c
+@@ -2014,7 +2014,7 @@ static __init int vpif_probe(struct platform_device *pdev)
+                       v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
+                                                 i2c_adap,
+                                                 &subdevdata->board_info,
+-                                                NULL);
++                                                NULL, 0);
+               if (!vpif_obj.sd[i]) {
+                       vpif_err("Error registering v4l2 subdevice\n");
+diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c
+index 412c65d..060c049 100644
+--- a/drivers/media/video/davinci/vpif_display.c
++++ b/drivers/media/video/davinci/vpif_display.c
+@@ -1555,7 +1555,7 @@ static __init int vpif_probe(struct platform_device *pdev)
+               vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
+                                               i2c_adap,
+                                               &subdevdata[i].board_info,
+-                                              NULL);
++                                              NULL, 0);
+               if (!vpif_obj.sd[i]) {
+                       vpif_err("Error registering v4l2 subdevice\n");
+                       goto probe_subdev_out;
+diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
+index 6651a6c..3d3b62d 100644
+--- a/drivers/media/video/ivtv/ivtv-i2c.c
++++ b/drivers/media/video/ivtv/ivtv-i2c.c
+@@ -277,7 +277,7 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
+               info.platform_data = &pdata;
+               sd = v4l2_i2c_new_subdev_board(&itv->v4l2_dev, adap, &info,
+-                                             NULL);
++                                             NULL, 0);
+       } else {
+               sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
+                               adap, type, hw_addrs[idx], NULL);
+diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
+index 2f50080..b237daa 100644
+--- a/drivers/media/video/s5p-fimc/fimc-capture.c
++++ b/drivers/media/video/s5p-fimc/fimc-capture.c
+@@ -44,7 +44,7 @@ static struct v4l2_subdev *fimc_subdev_register(struct fimc_dev *fimc,
+               return ERR_PTR(-ENOMEM);
+       sd = v4l2_i2c_new_subdev_board(&vid_cap->v4l2_dev, i2c_adap,
+-                                     isp_info->board_info, NULL);
++                                     isp_info->board_info, NULL, 0);
+       if (!sd) {
+               v4l2_err(&vid_cap->v4l2_dev, "failed to acquire subdev\n");
+               return NULL;
+diff --git a/drivers/media/video/sh_vou.c b/drivers/media/video/sh_vou.c
+index 07cf0c6..c50f0f5 100644
+--- a/drivers/media/video/sh_vou.c
++++ b/drivers/media/video/sh_vou.c
+@@ -1409,7 +1409,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev)
+               goto ereset;
+       subdev = v4l2_i2c_new_subdev_board(&vou_dev->v4l2_dev, i2c_adap,
+-                      vou_pdata->board_info, NULL);
++                      vou_pdata->board_info, NULL, 0);
+       if (!subdev) {
+               ret = -ENOMEM;
+               goto ei2cnd;
+diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
+index 052bd6d..5afb601 100644
+--- a/drivers/media/video/soc_camera.c
++++ b/drivers/media/video/soc_camera.c
+@@ -896,7 +896,7 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd,
+       icl->board_info->platform_data = icd;
+       subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
+-                              icl->board_info, NULL);
++                              icl->board_info, NULL, 0);
+       if (!subdev)
+               goto ei2cnd;
+diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
+index e007e61..ffee794 100644
+--- a/drivers/media/video/v4l2-common.c
++++ b/drivers/media/video/v4l2-common.c
+@@ -369,7 +369,7 @@ EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init);
+ /* Load an i2c sub-device. */
+ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
+               struct i2c_adapter *adapter, struct i2c_board_info *info,
+-              const unsigned short *probe_addrs)
++              const unsigned short *probe_addrs, int enable_devnode)
+ {
+       struct v4l2_subdev *sd = NULL;
+       struct i2c_client *client;
+@@ -399,9 +399,12 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
+       if (!try_module_get(client->driver->driver.owner))
+               goto error;
+       sd = i2c_get_clientdata(client);
++      if (!enable_devnode)
++              sd->flags &= ~V4L2_SUBDEV_FL_HAS_DEVNODE;
+       /* Register with the v4l2_device which increases the module's
+          use count as well. */
++      sd->initialized = 0;
+       if (v4l2_device_register_subdev(v4l2_dev, sd))
+               sd = NULL;
+       /* Decrease the module use count to match the first try_module_get. */
+@@ -416,6 +419,8 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
+               if (err && err != -ENOIOCTLCMD) {
+                       v4l2_device_unregister_subdev(sd);
+                       sd = NULL;
++              } else {
++                      sd->initialized = 1;
+               }
+       }
+@@ -440,7 +445,8 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
+       strlcpy(info.type, client_type, sizeof(info.type));
+       info.addr = addr;
+-      return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, probe_addrs);
++      return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, probe_addrs,
++                                       0);
+ }
+ EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev);
+@@ -510,7 +516,8 @@ void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi,
+ EXPORT_SYMBOL_GPL(v4l2_spi_subdev_init);
+ struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev,
+-              struct spi_master *master, struct spi_board_info *info)
++              struct spi_master *master, struct spi_board_info *info,
++              int enable_devnode)
+ {
+       struct v4l2_subdev *sd = NULL;
+       struct spi_device *spi = NULL;
+@@ -529,6 +536,8 @@ struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev,
+               goto error;
+       sd = spi_get_drvdata(spi);
++      if (!enable_devnode)
++              sd->flags &= ~V4L2_SUBDEV_FL_HAS_DEVNODE;
+       /* Register with the v4l2_device which increases the module's
+          use count as well. */
+diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
+index 359e232..f22bd41 100644
+--- a/drivers/media/video/v4l2-dev.c
++++ b/drivers/media/video/v4l2-dev.c
+@@ -408,13 +408,14 @@ static int get_index(struct video_device *vdev)
+ }
+ /**
+- *    video_register_device - register video4linux devices
++ *    __video_register_device - register video4linux devices
+  *    @vdev: video device structure we want to register
+  *    @type: type of device to register
+  *    @nr:   which device node number (0 == /dev/video0, 1 == /dev/video1, ...
+  *             -1 == first free)
+  *    @warn_if_nr_in_use: warn if the desired device node number
+  *           was already in use and another number was chosen instead.
++ *    @owner: module that owns the video device node
+  *
+  *    The registration code assigns minor numbers and device node numbers
+  *    based on the requested type and registers the new device node with
+@@ -431,9 +432,11 @@ static int get_index(struct video_device *vdev)
+  *    %VFL_TYPE_VBI - Vertical blank data (undecoded)
+  *
+  *    %VFL_TYPE_RADIO - A radio card
++ *
++ *    %VFL_TYPE_SUBDEV - A subdevice
+  */
+-static int __video_register_device(struct video_device *vdev, int type, int nr,
+-              int warn_if_nr_in_use)
++int __video_register_device(struct video_device *vdev, int type, int nr,
++              int warn_if_nr_in_use, struct module *owner)
+ {
+       int i = 0;
+       int ret;
+@@ -466,6 +469,9 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
+       case VFL_TYPE_RADIO:
+               name_base = "radio";
+               break;
++      case VFL_TYPE_SUBDEV:
++              name_base = "v4l-subdev";
++              break;
+       default:
+               printk(KERN_ERR "%s called with unknown type: %d\n",
+                      __func__, type);
+@@ -549,7 +555,7 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
+               goto cleanup;
+       }
+       vdev->cdev->ops = &v4l2_fops;
+-      vdev->cdev->owner = vdev->fops->owner;
++      vdev->cdev->owner = owner;
+       ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
+       if (ret < 0) {
+               printk(KERN_ERR "%s: cdev_add failed\n", __func__);
+@@ -598,18 +604,7 @@ cleanup:
+       vdev->minor = -1;
+       return ret;
+ }
+-
+-int video_register_device(struct video_device *vdev, int type, int nr)
+-{
+-      return __video_register_device(vdev, type, nr, 1);
+-}
+-EXPORT_SYMBOL(video_register_device);
+-
+-int video_register_device_no_warn(struct video_device *vdev, int type, int nr)
+-{
+-      return __video_register_device(vdev, type, nr, 0);
+-}
+-EXPORT_SYMBOL(video_register_device_no_warn);
++EXPORT_SYMBOL(__video_register_device);
+ /**
+  *    video_unregister_device - unregister a video4linux device
+diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
+index 7fe6f92..97e84df 100644
+--- a/drivers/media/video/v4l2-device.c
++++ b/drivers/media/video/v4l2-device.c
+@@ -117,24 +117,43 @@ EXPORT_SYMBOL_GPL(v4l2_device_unregister);
+ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
+                                               struct v4l2_subdev *sd)
+ {
++      struct video_device *vdev;
+       int err;
+       /* Check for valid input */
+       if (v4l2_dev == NULL || sd == NULL || !sd->name[0])
+               return -EINVAL;
++
+       /* Warn if we apparently re-register a subdev */
+       WARN_ON(sd->v4l2_dev != NULL);
++
+       if (!try_module_get(sd->owner))
+               return -ENODEV;
++
+       /* This just returns 0 if either of the two args is NULL */
+       err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler);
+       if (err)
+               return err;
++
+       sd->v4l2_dev = v4l2_dev;
+       spin_lock(&v4l2_dev->lock);
+       list_add_tail(&sd->list, &v4l2_dev->subdevs);
+       spin_unlock(&v4l2_dev->lock);
+-      return 0;
++
++      /* Register the device node. */
++      vdev = &sd->devnode;
++      strlcpy(vdev->name, sd->name, sizeof(vdev->name));
++      vdev->parent = v4l2_dev->dev;
++      vdev->fops = &v4l2_subdev_fops;
++      vdev->release = video_device_release_empty;
++      if (sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE) {
++              err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
++                                            sd->owner);
++              if (err < 0)
++                      v4l2_device_unregister_subdev(sd);
++      }
++
++      return err;
+ }
+ EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
+@@ -143,10 +162,13 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
+       /* return if it isn't registered */
+       if (sd == NULL || sd->v4l2_dev == NULL)
+               return;
++
+       spin_lock(&sd->v4l2_dev->lock);
+       list_del(&sd->list);
+       spin_unlock(&sd->v4l2_dev->lock);
+       sd->v4l2_dev = NULL;
++
+       module_put(sd->owner);
++      video_unregister_device(&sd->devnode);
+ }
+ EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);
+diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
+index 1e01554..4137e4c 100644
+--- a/drivers/media/video/v4l2-ioctl.c
++++ b/drivers/media/video/v4l2-ioctl.c
+@@ -413,7 +413,7 @@ static unsigned long cmd_input_size(unsigned int cmd)
+       }
+ }
+-static long
++long
+ __video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+               v4l2_kioctl func)
+ {
+diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
+new file mode 100644
+index 0000000..00bd4b1
+--- /dev/null
++++ b/drivers/media/video/v4l2-subdev.c
+@@ -0,0 +1,66 @@
++/*
++ *  V4L2 subdevice support.
++ *
++ *  Copyright (C) 2010 Nokia Corporation
++ *
++ *  Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#include <linux/types.h>
++#include <linux/ioctl.h>
++#include <linux/videodev2.h>
++
++#include <media/v4l2-device.h>
++#include <media/v4l2-ioctl.h>
++
++static int subdev_open(struct file *file)
++{
++      struct video_device *vdev = video_devdata(file);
++      struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
++
++      if (!sd->initialized)
++              return -EAGAIN;
++
++      return 0;
++}
++
++static int subdev_close(struct file *file)
++{
++      return 0;
++}
++
++static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
++{
++      switch (cmd) {
++      default:
++              return -ENOIOCTLCMD;
++      }
++
++      return 0;
++}
++
++static long subdev_ioctl(struct file *file, unsigned int cmd,
++      unsigned long arg)
++{
++      return __video_usercopy(file, cmd, arg, subdev_do_ioctl);
++}
++
++const struct v4l2_file_operations v4l2_subdev_fops = {
++      .owner = THIS_MODULE,
++      .open = subdev_open,
++      .unlocked_ioctl = subdev_ioctl,
++      .release = subdev_close,
++};
+diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
+index 565fb32..ef8965d 100644
+--- a/include/media/v4l2-common.h
++++ b/include/media/v4l2-common.h
+@@ -146,7 +146,7 @@ struct i2c_board_info;
+ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
+               struct i2c_adapter *adapter, struct i2c_board_info *info,
+-              const unsigned short *probe_addrs);
++              const unsigned short *probe_addrs, int enable_devnode);
+ /* Initialize an v4l2_subdev with data from an i2c_client struct */
+ void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
+@@ -179,7 +179,8 @@ struct spi_device;
+ /* Load an spi module and return an initialized v4l2_subdev struct.
+    The client_type argument is the name of the chip that's on the adapter. */
+ struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev,
+-              struct spi_master *master, struct spi_board_info *info);
++              struct spi_master *master, struct spi_board_info *info,
++              int enable_devnode);
+ /* Initialize an v4l2_subdev with data from an spi_device struct */
+ void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi,
+diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
+index 15802a0..4fe6831 100644
+--- a/include/media/v4l2-dev.h
++++ b/include/media/v4l2-dev.h
+@@ -21,7 +21,8 @@
+ #define VFL_TYPE_GRABBER      0
+ #define VFL_TYPE_VBI          1
+ #define VFL_TYPE_RADIO                2
+-#define VFL_TYPE_MAX          3
++#define VFL_TYPE_SUBDEV               3
++#define VFL_TYPE_MAX          4
+ struct v4l2_ioctl_callbacks;
+ struct video_device;
+@@ -102,15 +103,26 @@ struct video_device
+ /* dev to video-device */
+ #define to_video_device(cd) container_of(cd, struct video_device, dev)
++int __must_check __video_register_device(struct video_device *vdev, int type,
++              int nr, int warn_if_nr_in_use, struct module *owner);
++
+ /* Register video devices. Note that if video_register_device fails,
+    the release() callback of the video_device structure is *not* called, so
+    the caller is responsible for freeing any data. Usually that means that
+    you call video_device_release() on failure. */
+-int __must_check video_register_device(struct video_device *vdev, int type, int nr);
++static inline int __must_check video_register_device(struct video_device *vdev,
++              int type, int nr)
++{
++      return __video_register_device(vdev, type, nr, 1, vdev->fops->owner);
++}
+ /* Same as video_register_device, but no warning is issued if the desired
+    device node number was already in use. */
+-int __must_check video_register_device_no_warn(struct video_device *vdev, int type, int nr);
++static inline int __must_check video_register_device_no_warn(
++              struct video_device *vdev, int type, int nr)
++{
++      return __video_register_device(vdev, type, nr, 0, vdev->fops->owner);
++}
+ /* Unregister video devices. Will do nothing if vdev == NULL or
+    video_is_registered() returns false. */
+diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
+index 06daa6e..abb64d0 100644
+--- a/include/media/v4l2-ioctl.h
++++ b/include/media/v4l2-ioctl.h
+@@ -316,6 +316,9 @@ extern long v4l2_compat_ioctl32(struct file *file, unsigned int cmd,
+                               unsigned long arg);
+ #endif
++extern long __video_usercopy(struct file *file, unsigned int cmd,
++                              unsigned long arg, v4l2_kioctl func);
++
+ /* Include support for obsoleted stuff */
+ extern long video_usercopy(struct file *file, unsigned int cmd,
+                               unsigned long arg, v4l2_kioctl func);
+diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
+index b636444..de181db 100644
+--- a/include/media/v4l2-subdev.h
++++ b/include/media/v4l2-subdev.h
+@@ -22,6 +22,7 @@
+ #define _V4L2_SUBDEV_H
+ #include <media/v4l2-common.h>
++#include <media/v4l2-dev.h>
+ #include <media/v4l2-mediabus.h>
+ /* generic v4l2_device notify callback notification values */
+@@ -418,9 +419,11 @@ struct v4l2_subdev_ops {
+ #define V4L2_SUBDEV_NAME_SIZE 32
+ /* Set this flag if this subdev is a i2c device. */
+-#define V4L2_SUBDEV_FL_IS_I2C (1U << 0)
++#define V4L2_SUBDEV_FL_IS_I2C                 (1U << 0)
+ /* Set this flag if this subdev is a spi device. */
+-#define V4L2_SUBDEV_FL_IS_SPI (1U << 1)
++#define V4L2_SUBDEV_FL_IS_SPI                 (1U << 1)
++/* Set this flag if this subdev needs a device node. */
++#define V4L2_SUBDEV_FL_HAS_DEVNODE            (1U << 2)
+ /* Each instance of a subdev driver should create this struct, either
+    stand-alone or embedded in a larger struct.
+@@ -440,8 +443,16 @@ struct v4l2_subdev {
+       /* pointer to private data */
+       void *dev_priv;
+       void *host_priv;
++      /* subdev device node */
++      struct video_device devnode;
++      unsigned int initialized;
+ };
++#define vdev_to_v4l2_subdev(vdev) \
++      container_of(vdev, struct v4l2_subdev, devnode)
++
++extern const struct v4l2_file_operations v4l2_subdev_fops;
++
+ static inline void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p)
+ {
+       sd->dev_priv = p;
+@@ -474,6 +485,7 @@ static inline void v4l2_subdev_init(struct v4l2_subdev *sd,
+       sd->grp_id = 0;
+       sd->dev_priv = NULL;
+       sd->host_priv = NULL;
++      sd->initialized = 1;
+ }
+ /* Call an ops of a v4l2_subdev, doing the right checks against
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0005-v4l-subdev-Uninline-the-v4l2_subdev_init-function.patch b/recipes-bsp/linux/linux-omap/media/0005-v4l-subdev-Uninline-the-v4l2_subdev_init-function.patch
new file mode 100644 (file)
index 0000000..a4e45e6
--- /dev/null
@@ -0,0 +1,103 @@
+From 7acd77b0cdf013213a6513a75ee5bc2c3e92e1a1 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:38:52 +0100
+Subject: [PATCH 05/43] v4l: subdev: Uninline the v4l2_subdev_init function
+
+The function isn't small or performance sensitive enough to be inlined.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ drivers/media/video/v4l2-subdev.c |   42 +++++++++++++++++++++++++-----------
+ include/media/v4l2-subdev.h       |   16 +------------
+ 2 files changed, 31 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
+index 00bd4b1..0deff78 100644
+--- a/drivers/media/video/v4l2-subdev.c
++++ b/drivers/media/video/v4l2-subdev.c
+@@ -1,22 +1,23 @@
+ /*
+- *  V4L2 subdevice support.
++ * V4L2 sub-device
+  *
+- *  Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2010 Nokia Corporation
+  *
+- *  Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ *        Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+  *
+- *  This program is free software; you can redistribute it and/or modify
+- *  it under the terms of the GNU General Public License as published by
+- *  the Free Software Foundation.
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
+  *
+- *  This program is distributed in the hope that it will be useful,
+- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- *  GNU General Public License for more details.
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
+  *
+- *  You should have received a copy of the GNU General Public License
+- *  along with this program; if not, write to the Free Software
+- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  */
+ #include <linux/types.h>
+@@ -64,3 +65,18 @@ const struct v4l2_file_operations v4l2_subdev_fops = {
+       .unlocked_ioctl = subdev_ioctl,
+       .release = subdev_close,
+ };
++
++void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
++{
++      INIT_LIST_HEAD(&sd->list);
++      BUG_ON(!ops);
++      sd->ops = ops;
++      sd->v4l2_dev = NULL;
++      sd->flags = 0;
++      sd->name[0] = '\0';
++      sd->grp_id = 0;
++      sd->dev_priv = NULL;
++      sd->host_priv = NULL;
++      sd->initialized = 1;
++}
++EXPORT_SYMBOL(v4l2_subdev_init);
+diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
+index de181db..90022f5 100644
+--- a/include/media/v4l2-subdev.h
++++ b/include/media/v4l2-subdev.h
+@@ -473,20 +473,8 @@ static inline void *v4l2_get_subdev_hostdata(const struct v4l2_subdev *sd)
+       return sd->host_priv;
+ }
+-static inline void v4l2_subdev_init(struct v4l2_subdev *sd,
+-                                      const struct v4l2_subdev_ops *ops)
+-{
+-      INIT_LIST_HEAD(&sd->list);
+-      BUG_ON(!ops);
+-      sd->ops = ops;
+-      sd->v4l2_dev = NULL;
+-      sd->flags = 0;
+-      sd->name[0] = '\0';
+-      sd->grp_id = 0;
+-      sd->dev_priv = NULL;
+-      sd->host_priv = NULL;
+-      sd->initialized = 1;
+-}
++void v4l2_subdev_init(struct v4l2_subdev *sd,
++                    const struct v4l2_subdev_ops *ops);
+ /* Call an ops of a v4l2_subdev, doing the right checks against
+    NULL pointers.
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0006-v4l-subdev-Control-ioctls-support.patch b/recipes-bsp/linux/linux-omap/media/0006-v4l-subdev-Control-ioctls-support.patch
new file mode 100644 (file)
index 0000000..218f346
--- /dev/null
@@ -0,0 +1,88 @@
+From dd0b366441249eb10daa2275e968431507f8d0d5 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:39:54 +0100
+Subject: [PATCH 06/43] v4l: subdev: Control ioctls support
+
+Pass the control-related ioctls to the subdev driver through the control
+framework.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ Documentation/video4linux/v4l2-framework.txt |   16 ++++++++++++++++
+ drivers/media/video/v4l2-subdev.c            |   25 +++++++++++++++++++++++++
+ 2 files changed, 41 insertions(+), 0 deletions(-)
+
+diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
+index 4c9185a..f683f63 100644
+--- a/Documentation/video4linux/v4l2-framework.txt
++++ b/Documentation/video4linux/v4l2-framework.txt
+@@ -336,6 +336,22 @@ argument to 0. Setting the argument to 1 will only enable device node
+ registration if the sub-device driver has set the V4L2_SUBDEV_FL_HAS_DEVNODE
+ flag.
++The device node handles a subset of the V4L2 API.
++
++VIDIOC_QUERYCTRL
++VIDIOC_QUERYMENU
++VIDIOC_G_CTRL
++VIDIOC_S_CTRL
++VIDIOC_G_EXT_CTRLS
++VIDIOC_S_EXT_CTRLS
++VIDIOC_TRY_EXT_CTRLS
++
++      The controls ioctls are identical to the ones defined in V4L2. They
++      behave identically, with the only exception that they deal only with
++      controls implemented in the sub-device. Depending on the driver, those
++      controls can be also be accessed through one (or several) V4L2 device
++      nodes.
++
+ I2C sub-device drivers
+ ----------------------
+diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
+index 0deff78..fc57ce7 100644
+--- a/drivers/media/video/v4l2-subdev.c
++++ b/drivers/media/video/v4l2-subdev.c
+@@ -24,6 +24,7 @@
+ #include <linux/ioctl.h>
+ #include <linux/videodev2.h>
++#include <media/v4l2-ctrls.h>
+ #include <media/v4l2-device.h>
+ #include <media/v4l2-ioctl.h>
+@@ -45,7 +46,31 @@ static int subdev_close(struct file *file)
+ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+ {
++      struct video_device *vdev = video_devdata(file);
++      struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
++
+       switch (cmd) {
++      case VIDIOC_QUERYCTRL:
++              return v4l2_subdev_queryctrl(sd, arg);
++
++      case VIDIOC_QUERYMENU:
++              return v4l2_subdev_querymenu(sd, arg);
++
++      case VIDIOC_G_CTRL:
++              return v4l2_subdev_g_ctrl(sd, arg);
++
++      case VIDIOC_S_CTRL:
++              return v4l2_subdev_s_ctrl(sd, arg);
++
++      case VIDIOC_G_EXT_CTRLS:
++              return v4l2_subdev_g_ext_ctrls(sd, arg);
++
++      case VIDIOC_S_EXT_CTRLS:
++              return v4l2_subdev_s_ext_ctrls(sd, arg);
++
++      case VIDIOC_TRY_EXT_CTRLS:
++              return v4l2_subdev_try_ext_ctrls(sd, arg);
++
+       default:
+               return -ENOIOCTLCMD;
+       }
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0007-v4l-subdev-Events-support.patch b/recipes-bsp/linux/linux-omap/media/0007-v4l-subdev-Events-support.patch
new file mode 100644 (file)
index 0000000..cb02f49
--- /dev/null
@@ -0,0 +1,223 @@
+From 127fac73175e73c509ba203717be618a611294cd Mon Sep 17 00:00:00 2001
+From: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+Date: Wed, 3 Mar 2010 17:49:38 +0200
+Subject: [PATCH 07/43] v4l: subdev: Events support
+
+Provide v4l2_subdevs with v4l2_event support. Subdev drivers only need very
+little to support events.
+
+Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+Signed-off-by: David Cohen <david.cohen@nokia.com>
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ Documentation/video4linux/v4l2-framework.txt |   18 ++++++
+ drivers/media/video/v4l2-subdev.c            |   75 +++++++++++++++++++++++++-
+ include/media/v4l2-subdev.h                  |   10 ++++
+ 3 files changed, 102 insertions(+), 1 deletions(-)
+
+diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
+index f683f63..4db1def 100644
+--- a/Documentation/video4linux/v4l2-framework.txt
++++ b/Documentation/video4linux/v4l2-framework.txt
+@@ -352,6 +352,24 @@ VIDIOC_TRY_EXT_CTRLS
+       controls can be also be accessed through one (or several) V4L2 device
+       nodes.
++VIDIOC_DQEVENT
++VIDIOC_SUBSCRIBE_EVENT
++VIDIOC_UNSUBSCRIBE_EVENT
++
++      The events ioctls are identical to the ones defined in V4L2. They
++      behave identically, with the only exception that they deal only with
++      events generated by the sub-device. Depending on the driver, those
++      events can also be reported by one (or several) V4L2 device nodes.
++
++      Sub-device drivers that want to use events need to set the
++      V4L2_SUBDEV_USES_EVENTS v4l2_subdev::flags and initialize
++      v4l2_subdev::nevents to events queue depth before registering the
++      sub-device. After registration events can be queued as usual on the
++      v4l2_subdev::devnode device node.
++
++      To properly support events, the poll() file operation is also
++      implemented.
++
+ I2C sub-device drivers
+ ----------------------
+diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
+index fc57ce7..fbccefd 100644
+--- a/drivers/media/video/v4l2-subdev.c
++++ b/drivers/media/video/v4l2-subdev.c
+@@ -20,27 +20,69 @@
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  */
+-#include <linux/types.h>
+ #include <linux/ioctl.h>
++#include <linux/slab.h>
++#include <linux/types.h>
+ #include <linux/videodev2.h>
+ #include <media/v4l2-ctrls.h>
+ #include <media/v4l2-device.h>
+ #include <media/v4l2-ioctl.h>
++#include <media/v4l2-fh.h>
++#include <media/v4l2-event.h>
+ static int subdev_open(struct file *file)
+ {
+       struct video_device *vdev = video_devdata(file);
+       struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
++      struct v4l2_fh *vfh;
++      int ret;
+       if (!sd->initialized)
+               return -EAGAIN;
++      if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) {
++              vfh = kzalloc(sizeof(*vfh), GFP_KERNEL);
++              if (vfh == NULL)
++                      return -ENOMEM;
++
++              ret = v4l2_fh_init(vfh, vdev);
++              if (ret)
++                      goto err;
++
++              ret = v4l2_event_init(vfh);
++              if (ret)
++                      goto err;
++
++              ret = v4l2_event_alloc(vfh, sd->nevents);
++              if (ret)
++                      goto err;
++
++              v4l2_fh_add(vfh);
++              file->private_data = vfh;
++      }
++
+       return 0;
++
++err:
++      if (vfh != NULL) {
++              v4l2_fh_exit(vfh);
++              kfree(vfh);
++      }
++
++      return ret;
+ }
+ static int subdev_close(struct file *file)
+ {
++      struct v4l2_fh *vfh = file->private_data;
++
++      if (vfh != NULL) {
++              v4l2_fh_del(vfh);
++              v4l2_fh_exit(vfh);
++              kfree(vfh);
++      }
++
+       return 0;
+ }
+@@ -48,6 +90,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+ {
+       struct video_device *vdev = video_devdata(file);
+       struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
++      struct v4l2_fh *fh = file->private_data;
+       switch (cmd) {
+       case VIDIOC_QUERYCTRL:
+@@ -71,6 +114,18 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+       case VIDIOC_TRY_EXT_CTRLS:
+               return v4l2_subdev_try_ext_ctrls(sd, arg);
++      case VIDIOC_DQEVENT:
++              if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
++                      return -ENOIOCTLCMD;
++
++              return v4l2_event_dequeue(fh, arg, file->f_flags & O_NONBLOCK);
++
++      case VIDIOC_SUBSCRIBE_EVENT:
++              return v4l2_subdev_call(sd, core, subscribe_event, fh, arg);
++
++      case VIDIOC_UNSUBSCRIBE_EVENT:
++              return v4l2_subdev_call(sd, core, unsubscribe_event, fh, arg);
++
+       default:
+               return -ENOIOCTLCMD;
+       }
+@@ -84,11 +139,29 @@ static long subdev_ioctl(struct file *file, unsigned int cmd,
+       return __video_usercopy(file, cmd, arg, subdev_do_ioctl);
+ }
++static unsigned int subdev_poll(struct file *file, poll_table *wait)
++{
++      struct video_device *vdev = video_devdata(file);
++      struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
++      struct v4l2_fh *fh = file->private_data;
++
++      if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
++              return POLLERR;
++
++      poll_wait(file, &fh->events->wait, wait);
++
++      if (v4l2_event_pending(fh))
++              return POLLPRI;
++
++      return 0;
++}
++
+ const struct v4l2_file_operations v4l2_subdev_fops = {
+       .owner = THIS_MODULE,
+       .open = subdev_open,
+       .unlocked_ioctl = subdev_ioctl,
+       .release = subdev_close,
++      .poll = subdev_poll,
+ };
+ void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
+diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
+index 90022f5..68cbe48 100644
+--- a/include/media/v4l2-subdev.h
++++ b/include/media/v4l2-subdev.h
+@@ -37,6 +37,8 @@
+ struct v4l2_device;
+ struct v4l2_ctrl_handler;
++struct v4l2_event_subscription;
++struct v4l2_fh;
+ struct v4l2_subdev;
+ struct tuner_setup;
+@@ -165,6 +167,10 @@ struct v4l2_subdev_core_ops {
+       int (*s_power)(struct v4l2_subdev *sd, int on);
+       int (*interrupt_service_routine)(struct v4l2_subdev *sd,
+                                               u32 status, bool *handled);
++      int (*subscribe_event)(struct v4l2_subdev *sd, struct v4l2_fh *fh,
++                             struct v4l2_event_subscription *sub);
++      int (*unsubscribe_event)(struct v4l2_subdev *sd, struct v4l2_fh *fh,
++                               struct v4l2_event_subscription *sub);
+ };
+ /* s_mode: switch the tuner to a specific tuner mode. Replacement of s_radio.
+@@ -424,6 +430,8 @@ struct v4l2_subdev_ops {
+ #define V4L2_SUBDEV_FL_IS_SPI                 (1U << 1)
+ /* Set this flag if this subdev needs a device node. */
+ #define V4L2_SUBDEV_FL_HAS_DEVNODE            (1U << 2)
++/* Set this flag if this subdev generates events. */
++#define V4L2_SUBDEV_FL_HAS_EVENTS             (1U << 3)
+ /* Each instance of a subdev driver should create this struct, either
+    stand-alone or embedded in a larger struct.
+@@ -446,6 +454,8 @@ struct v4l2_subdev {
+       /* subdev device node */
+       struct video_device devnode;
+       unsigned int initialized;
++      /* number of events to be allocated on open */
++      unsigned int nevents;
+ };
+ #define vdev_to_v4l2_subdev(vdev) \
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0008-media-Media-device-node-support.patch b/recipes-bsp/linux/linux-omap/media/0008-media-Media-device-node-support.patch
new file mode 100644 (file)
index 0000000..fd8b495
--- /dev/null
@@ -0,0 +1,500 @@
+From 27c789f3ae1d24212355d10857efb2d406d0fedd Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:39:56 +0100
+Subject: [PATCH 08/43] media: Media device node support
+
+The media_devnode structure provides support for registering and
+unregistering character devices using a dynamic major number. Reference
+counting is handled internally, making device drivers easier to write
+without having to solve the open/disconnect race condition issue over
+and over again.
+
+The code is based on video/v4l2-dev.c.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ drivers/media/Kconfig         |   13 ++
+ drivers/media/Makefile        |   10 +-
+ drivers/media/media-devnode.c |  321 +++++++++++++++++++++++++++++++++++++++++
+ include/media/media-devnode.h |   97 +++++++++++++
+ 4 files changed, 439 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/media/media-devnode.c
+ create mode 100644 include/media/media-devnode.h
+
+diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
+index a28541b..6b946e6 100644
+--- a/drivers/media/Kconfig
++++ b/drivers/media/Kconfig
+@@ -14,6 +14,19 @@ if MEDIA_SUPPORT
+ comment "Multimedia core support"
+ #
++# Media controller
++#
++
++config MEDIA_CONTROLLER
++      bool "Media Controller API (EXPERIMENTAL)"
++      depends on EXPERIMENTAL
++      ---help---
++        Enable the media controller API used to query media devices internal
++        topology and configure it dynamically.
++
++        This API is mostly used by camera interfaces in embedded platforms.
++
++#
+ # V4L core and enabled API's
+ #
+diff --git a/drivers/media/Makefile b/drivers/media/Makefile
+index 499b081..3a08991 100644
+--- a/drivers/media/Makefile
++++ b/drivers/media/Makefile
+@@ -2,7 +2,13 @@
+ # Makefile for the kernel multimedia device drivers.
+ #
++media-objs    := media-devnode.o
++
++ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
++  obj-$(CONFIG_MEDIA_SUPPORT) += media.o
++endif
++
+ obj-y += common/ IR/ video/
+-obj-$(CONFIG_VIDEO_DEV) += radio/
+-obj-$(CONFIG_DVB_CORE)  += dvb/
++obj-$(CONFIG_VIDEO_DEV)               += radio/
++obj-$(CONFIG_DVB_CORE)                += dvb/
+diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
+new file mode 100644
+index 0000000..7804b70
+--- /dev/null
++++ b/drivers/media/media-devnode.c
+@@ -0,0 +1,321 @@
++/*
++ * Media device node
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ *
++ * Based on drivers/media/video/v4l2_dev.c code authored by
++ *    Mauro Carvalho Chehab <mchehab@infradead.org> (version 2)
++ *    Alan Cox, <alan@lxorguk.ukuu.org.uk> (version 1)
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ *         Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ * --
++ *
++ * Generic media device node infrastructure to register and unregister
++ * character devices using a dynamic major number and proper reference
++ * counting.
++ */
++
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/kmod.h>
++#include <linux/slab.h>
++#include <linux/mm.h>
++#include <linux/smp_lock.h>
++#include <linux/string.h>
++#include <linux/types.h>
++#include <linux/uaccess.h>
++#include <asm/system.h>
++
++#include <media/media-devnode.h>
++
++#define MEDIA_NUM_DEVICES     256
++#define MEDIA_NAME            "media"
++
++static dev_t media_dev_t;
++
++/*
++ *    Active devices
++ */
++static DEFINE_MUTEX(media_devnode_lock);
++static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES);
++
++/* Called when the last user of the media device exits. */
++static void media_devnode_release(struct device *cd)
++{
++      struct media_devnode *mdev = to_media_devnode(cd);
++
++      mutex_lock(&media_devnode_lock);
++
++      /* Delete the cdev on this minor as well */
++      cdev_del(&mdev->cdev);
++
++      /* Mark device node number as free */
++      clear_bit(mdev->minor, media_devnode_nums);
++
++      mutex_unlock(&media_devnode_lock);
++
++      /* Release media_devnode and perform other cleanups as needed. */
++      if (mdev->release)
++              mdev->release(mdev);
++}
++
++static struct bus_type media_bus_type = {
++      .name = MEDIA_NAME,
++};
++
++static ssize_t media_read(struct file *filp, char __user *buf,
++              size_t sz, loff_t *off)
++{
++      struct media_devnode *mdev = media_devnode_data(filp);
++
++      if (!mdev->fops->read)
++              return -EINVAL;
++      if (!media_devnode_is_registered(mdev))
++              return -EIO;
++      return mdev->fops->read(filp, buf, sz, off);
++}
++
++static ssize_t media_write(struct file *filp, const char __user *buf,
++              size_t sz, loff_t *off)
++{
++      struct media_devnode *mdev = media_devnode_data(filp);
++
++      if (!mdev->fops->write)
++              return -EINVAL;
++      if (!media_devnode_is_registered(mdev))
++              return -EIO;
++      return mdev->fops->write(filp, buf, sz, off);
++}
++
++static unsigned int media_poll(struct file *filp,
++                             struct poll_table_struct *poll)
++{
++      struct media_devnode *mdev = media_devnode_data(filp);
++
++      if (!media_devnode_is_registered(mdev))
++              return POLLERR | POLLHUP;
++      if (!mdev->fops->poll)
++              return DEFAULT_POLLMASK;
++      return mdev->fops->poll(filp, poll);
++}
++
++static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
++{
++      struct media_devnode *mdev = media_devnode_data(filp);
++
++      if (!mdev->fops->ioctl)
++              return -ENOTTY;
++
++      if (!media_devnode_is_registered(mdev))
++              return -EIO;
++
++      return mdev->fops->ioctl(filp, cmd, arg);
++}
++
++/* Override for the open function */
++static int media_open(struct inode *inode, struct file *filp)
++{
++      struct media_devnode *mdev;
++      int ret;
++
++      /* Check if the media device is available. This needs to be done with
++       * the media_devnode_lock held to prevent an open/unregister race:
++       * without the lock, the device could be unregistered and freed between
++       * the media_devnode_is_registered() and get_device() calls, leading to
++       * a crash.
++       */
++      mutex_lock(&media_devnode_lock);
++      mdev = container_of(inode->i_cdev, struct media_devnode, cdev);
++      /* return ENXIO if the media device has been removed
++         already or if it is not registered anymore. */
++      if (!media_devnode_is_registered(mdev)) {
++              mutex_unlock(&media_devnode_lock);
++              return -ENXIO;
++      }
++      /* and increase the device refcount */
++      get_device(&mdev->dev);
++      mutex_unlock(&media_devnode_lock);
++
++      filp->private_data = mdev;
++
++      if (mdev->fops->open) {
++              ret = mdev->fops->open(filp);
++              if (ret) {
++                      put_device(&mdev->dev);
++                      return ret;
++              }
++      }
++
++      return 0;
++}
++
++/* Override for the release function */
++static int media_release(struct inode *inode, struct file *filp)
++{
++      struct media_devnode *mdev = media_devnode_data(filp);
++      int ret = 0;
++
++      if (mdev->fops->release)
++              mdev->fops->release(filp);
++
++      /* decrease the refcount unconditionally since the release()
++         return value is ignored. */
++      put_device(&mdev->dev);
++      filp->private_data = NULL;
++      return ret;
++}
++
++static const struct file_operations media_devnode_fops = {
++      .owner = THIS_MODULE,
++      .read = media_read,
++      .write = media_write,
++      .open = media_open,
++      .unlocked_ioctl = media_ioctl,
++      .release = media_release,
++      .poll = media_poll,
++      .llseek = no_llseek,
++};
++
++/**
++ * media_devnode_register - register a media device node
++ * @mdev: media device node structure we want to register
++ *
++ * The registration code assigns minor numbers and registers the new device node
++ * with the kernel. An error is returned if no free minor number can be found,
++ * or if the registration of the device node fails.
++ *
++ * Zero is returned on success.
++ *
++ * Note that if the media_devnode_register call fails, the release() callback of
++ * the media_devnode structure is *not* called, so the caller is responsible for
++ * freeing any data.
++ */
++int __must_check media_devnode_register(struct media_devnode *mdev)
++{
++      int minor;
++      int ret;
++
++      /* Part 1: Find a free minor number */
++      mutex_lock(&media_devnode_lock);
++      minor = find_next_zero_bit(media_devnode_nums, 0, MEDIA_NUM_DEVICES);
++      if (minor == MEDIA_NUM_DEVICES) {
++              mutex_unlock(&media_devnode_lock);
++              printk(KERN_ERR "could not get a free minor\n");
++              return -ENFILE;
++      }
++
++      set_bit(mdev->minor, media_devnode_nums);
++      mutex_unlock(&media_devnode_lock);
++
++      mdev->minor = minor;
++
++      /* Part 2: Initialize and register the character device */
++      cdev_init(&mdev->cdev, &media_devnode_fops);
++      mdev->cdev.owner = mdev->fops->owner;
++
++      ret = cdev_add(&mdev->cdev, MKDEV(MAJOR(media_dev_t), mdev->minor), 1);
++      if (ret < 0) {
++              printk(KERN_ERR "%s: cdev_add failed\n", __func__);
++              goto error;
++      }
++
++      /* Part 3: Register the media device */
++      mdev->dev.bus = &media_bus_type;
++      mdev->dev.devt = MKDEV(MAJOR(media_dev_t), mdev->minor);
++      mdev->dev.release = media_devnode_release;
++      if (mdev->parent)
++              mdev->dev.parent = mdev->parent;
++      dev_set_name(&mdev->dev, "media%d", mdev->minor);
++      ret = device_register(&mdev->dev);
++      if (ret < 0) {
++              printk(KERN_ERR "%s: device_register failed\n", __func__);
++              goto error;
++      }
++
++      /* Part 4: Activate this minor. The char device can now be used. */
++      set_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
++
++      return 0;
++
++error:
++      cdev_del(&mdev->cdev);
++      clear_bit(mdev->minor, media_devnode_nums);
++      return ret;
++}
++
++/**
++ * media_devnode_unregister - unregister a media device node
++ * @mdev: the device node to unregister
++ *
++ * This unregisters the passed device. Future open calls will be met with
++ * errors.
++ *
++ * This function can safely be called if the device node has never been
++ * registered or has already been unregistered.
++ */
++void media_devnode_unregister(struct media_devnode *mdev)
++{
++      /* Check if mdev was ever registered at all */
++      if (!media_devnode_is_registered(mdev))
++              return;
++
++      mutex_lock(&media_devnode_lock);
++      clear_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
++      mutex_unlock(&media_devnode_lock);
++      device_unregister(&mdev->dev);
++}
++
++/*
++ *    Initialise media for linux
++ */
++static int __init media_devnode_init(void)
++{
++      int ret;
++
++      printk(KERN_INFO "Linux media interface: v0.10\n");
++      ret = alloc_chrdev_region(&media_dev_t, 0, MEDIA_NUM_DEVICES,
++                                MEDIA_NAME);
++      if (ret < 0) {
++              printk(KERN_WARNING "media: unable to allocate major\n");
++              return ret;
++      }
++
++      ret = bus_register(&media_bus_type);
++      if (ret < 0) {
++              unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
++              printk(KERN_WARNING "media: bus_register failed\n");
++              return -EIO;
++      }
++
++      return 0;
++}
++
++static void __exit media_devnode_exit(void)
++{
++      bus_unregister(&media_bus_type);
++      unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
++}
++
++module_init(media_devnode_init)
++module_exit(media_devnode_exit)
++
++MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
++MODULE_DESCRIPTION("Device node registration for media drivers");
++MODULE_LICENSE("GPL");
+diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h
+new file mode 100644
+index 0000000..01cd034
+--- /dev/null
++++ b/include/media/media-devnode.h
+@@ -0,0 +1,97 @@
++/*
++ * Media device node
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ *         Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ * --
++ *
++ * Common functions for media-related drivers to register and unregister media
++ * device nodes.
++ */
++
++#ifndef _MEDIA_DEVNODE_H
++#define _MEDIA_DEVNODE_H
++
++#include <linux/poll.h>
++#include <linux/fs.h>
++#include <linux/device.h>
++#include <linux/cdev.h>
++
++/*
++ * Flag to mark the media_devnode struct as registered. Drivers must not touch
++ * this flag directly, it will be set and cleared by media_devnode_register and
++ * media_devnode_unregister.
++ */
++#define MEDIA_FLAG_REGISTERED 0
++
++struct media_file_operations {
++      struct module *owner;
++      ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
++      ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
++      unsigned int (*poll) (struct file *, struct poll_table_struct *);
++      long (*ioctl) (struct file *, unsigned int, unsigned long);
++      int (*open) (struct file *);
++      int (*release) (struct file *);
++};
++
++/**
++ * struct media_devnode - Media device node
++ * @parent:   parent device
++ * @minor:    device node minor number
++ * @flags:    flags, combination of the MEDIA_FLAG_* constants
++ *
++ * This structure represents a media-related device node.
++ *
++ * The @parent is a physical device. It must be set by core or device drivers
++ * before registering the node.
++ */
++struct media_devnode {
++      /* device ops */
++      const struct media_file_operations *fops;
++
++      /* sysfs */
++      struct device dev;              /* media device */
++      struct cdev cdev;               /* character device */
++      struct device *parent;          /* device parent */
++
++      /* device info */
++      int minor;
++      unsigned long flags;            /* Use bitops to access flags */
++
++      /* callbacks */
++      void (*release)(struct media_devnode *mdev);
++};
++
++/* dev to media_devnode */
++#define to_media_devnode(cd) container_of(cd, struct media_devnode, dev)
++
++int __must_check media_devnode_register(struct media_devnode *mdev);
++void media_devnode_unregister(struct media_devnode *mdev);
++
++static inline struct media_devnode *media_devnode_data(struct file *filp)
++{
++      return filp->private_data;
++}
++
++static inline int media_devnode_is_registered(struct media_devnode *mdev)
++{
++      return test_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
++}
++
++#endif /* _MEDIA_DEVNODE_H */
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0009-media-Media-device.patch b/recipes-bsp/linux/linux-omap/media/0009-media-Media-device.patch
new file mode 100644 (file)
index 0000000..d82c798
--- /dev/null
@@ -0,0 +1,398 @@
+From 6bfbc237b86be01ad23b836ba047e76e23cc7a00 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:39:58 +0100
+Subject: [PATCH 09/43] media: Media device
+
+The media_device structure abstracts functions common to all kind of
+media devices (v4l2, dvb, alsa, ...). It manages media entities and
+offers a userspace API to discover and configure the media device
+internal topology.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ Documentation/ABI/testing/sysfs-bus-media      |    6 ++
+ Documentation/DocBook/media-entities.tmpl      |    2 +
+ Documentation/DocBook/media.tmpl               |    3 +
+ Documentation/DocBook/v4l/media-controller.xml |   56 +++++++++++++
+ Documentation/media-framework.txt              |   67 ++++++++++++++++
+ drivers/media/Makefile                         |    2 +-
+ drivers/media/media-device.c                   |  100 ++++++++++++++++++++++++
+ include/media/media-device.h                   |   69 ++++++++++++++++
+ 8 files changed, 304 insertions(+), 1 deletions(-)
+ create mode 100644 Documentation/ABI/testing/sysfs-bus-media
+ create mode 100644 Documentation/DocBook/v4l/media-controller.xml
+ create mode 100644 Documentation/media-framework.txt
+ create mode 100644 drivers/media/media-device.c
+ create mode 100644 include/media/media-device.h
+
+diff --git a/Documentation/ABI/testing/sysfs-bus-media b/Documentation/ABI/testing/sysfs-bus-media
+new file mode 100644
+index 0000000..7057e57
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-bus-media
+@@ -0,0 +1,6 @@
++What:         /sys/bus/media/devices/.../model
++Date:         January 2011
++Contact:      Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++              linux-media@vger.kernel.org
++Description:  Contains the device model name in UTF-8. The device version is
++              is not be appended to the model name.
+diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
+index be34dcb..61d6f11 100644
+--- a/Documentation/DocBook/media-entities.tmpl
++++ b/Documentation/DocBook/media-entities.tmpl
+@@ -321,6 +321,8 @@
+ <!ENTITY sub-media-entities SYSTEM "media-entities.tmpl">
+ <!ENTITY sub-media-indices SYSTEM "media-indices.tmpl">
++<!ENTITY sub-media-controller SYSTEM "v4l/media-controller.xml">
++
+ <!-- Function Reference -->
+ <!ENTITY close SYSTEM "v4l/func-close.xml">
+ <!ENTITY ioctl SYSTEM "v4l/func-ioctl.xml">
+diff --git a/Documentation/DocBook/media.tmpl b/Documentation/DocBook/media.tmpl
+index f11048d..73464b0 100644
+--- a/Documentation/DocBook/media.tmpl
++++ b/Documentation/DocBook/media.tmpl
+@@ -106,6 +106,9 @@ Foundation. A copy of the license is included in the chapter entitled
+ &sub-remote_controllers;
+ </chapter>
+ </part>
++<part id="media_common">
++&sub-media-controller;
++</part>
+ &sub-fdl-appendix;
+diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml
+new file mode 100644
+index 0000000..253ddb4
+--- /dev/null
++++ b/Documentation/DocBook/v4l/media-controller.xml
+@@ -0,0 +1,56 @@
++<partinfo>
++  <authorgroup>
++    <author>
++      <firstname>Laurent</firstname>
++      <surname>Pinchart</surname>
++      <affiliation><address><email>laurent.pinchart@ideasonboard.com</email></address></affiliation>
++      <contrib>Initial version.</contrib>
++    </author>
++  </authorgroup>
++  <copyright>
++    <year>2010</year>
++    <holder>Laurent Pinchart</holder>
++  </copyright>
++
++  <revhistory>
++    <!-- Put document revisions here, newest first. -->
++    <revision>
++      <revnumber>1.0.0</revnumber>
++      <date>2010-11-10</date>
++      <authorinitials>lp</authorinitials>
++      <revremark>Initial revision</revremark>
++    </revision>
++  </revhistory>
++</partinfo>
++
++<title>Media Controller API</title>
++
++<chapter id="media_controller">
++  <title>Media Controller</title>
++
++  <section id="media-controller-intro">
++    <title>Introduction</title>
++    <para>Media devices increasingly handle multiple related functions. Many USB
++    cameras include microphones, video capture hardware can also output video,
++    or SoC camera interfaces also perform memory-to-memory operations similar to
++    video codecs.</para>
++    <para>Independent functions, even when implemented in the same hardware, can
++    be modelled as separate devices. A USB camera with a microphone will be
++    presented to userspace applications as V4L2 and ALSA capture devices. The
++    devices' relationships (when using a webcam, end-users shouldn't have to
++    manually select the associated USB microphone), while not made available
++    directly to applications by the drivers, can usually be retrieved from
++    sysfs.</para>
++    <para>With more and more advanced SoC devices being introduced, the current
++    approach will not scale. Device topologies are getting increasingly complex
++    and can't always be represented by a tree structure. Hardware blocks are
++    shared between different functions, creating dependencies between seemingly
++    unrelated devices.</para>
++    <para>Kernel abstraction APIs such as V4L2 and ALSA provide means for
++    applications to access hardware parameters. As newer hardware expose an
++    increasingly high number of those parameters, drivers need to guess what
++    applications really require based on limited information, thereby
++    implementing policies that belong to userspace.</para>
++    <para>The media controller API aims at solving those problems.</para>
++  </section>
++</chapter>
+diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
+new file mode 100644
+index 0000000..1844c3f
+--- /dev/null
++++ b/Documentation/media-framework.txt
+@@ -0,0 +1,67 @@
++Linux kernel media framework
++============================
++
++This document describes the Linux kernel media framework, its data structures,
++functions and their usage.
++
++
++Introduction
++------------
++
++The media controller API is documented in DocBook format in
++Documentation/DocBook/v4l/media-controller.xml. This document will focus on
++the kernel-side implementation of the media framework.
++
++
++Media device
++------------
++
++A media device is represented by a struct media_device instance, defined in
++include/media/media-device.h. Allocation of the structure is handled by the
++media device driver, usually by embedding the media_device instance in a
++larger driver-specific structure.
++
++Drivers register media device instances by calling
++
++      media_device_register(struct media_device *mdev);
++
++The caller is responsible for initializing the media_device structure before
++registration. The following fields must be set:
++
++ - dev must point to the parent device (usually a pci_dev, usb_interface or
++   platform_device instance).
++
++ - model must be filled with the device model name as a NUL-terminated UTF-8
++   string. The device/model revision must not be stored in this field.
++
++The following fields are optional:
++
++ - serial is a unique serial number stored as a NUL-terminated ASCII string.
++   The field is big enough to store a GUID in text form. If the hardware
++   doesn't provide a unique serial number this field must be left empty.
++
++ - bus_info represents the location of the device in the system as a
++   NUL-terminated ASCII string. For PCI/PCIe devices bus_info must be set to
++   "PCI:" (or "PCIe:") followed by the value of pci_name(). For USB devices,
++   the usb_make_path() function must be used. This field is used by
++   applications to distinguish between otherwise identical devices that don't
++   provide a serial number.
++
++ - hw_revision is the hardware device revision in a driver-specific format.
++   When possible the revision should be formatted with the KERNEL_VERSION
++   macro.
++
++ - driver_version is formatted with the KERNEL_VERSION macro. The version
++   minor must be incremented when new features are added to the userspace API
++   without breaking binary compatibility. The version major must be
++   incremented when binary compatibility is broken.
++
++Upon successful registration a character device named media[0-9]+ is created.
++The device major and minor numbers are dynamic. The model name is exported as
++a sysfs attribute.
++
++Drivers unregister media device instances by calling
++
++      media_device_unregister(struct media_device *mdev);
++
++Unregistering a media device that hasn't been registered is *NOT* safe.
+diff --git a/drivers/media/Makefile b/drivers/media/Makefile
+index 3a08991..019d3e0 100644
+--- a/drivers/media/Makefile
++++ b/drivers/media/Makefile
+@@ -2,7 +2,7 @@
+ # Makefile for the kernel multimedia device drivers.
+ #
+-media-objs    := media-devnode.o
++media-objs    := media-device.o media-devnode.o
+ ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
+   obj-$(CONFIG_MEDIA_SUPPORT) += media.o
+diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
+new file mode 100644
+index 0000000..57a9c6b
+--- /dev/null
++++ b/drivers/media/media-device.c
+@@ -0,0 +1,100 @@
++/*
++ * Media device
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ *         Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#include <linux/types.h>
++#include <linux/ioctl.h>
++
++#include <media/media-device.h>
++#include <media/media-devnode.h>
++
++static const struct media_file_operations media_device_fops = {
++      .owner = THIS_MODULE,
++};
++
++/* -----------------------------------------------------------------------------
++ * sysfs
++ */
++
++static ssize_t show_model(struct device *cd,
++                        struct device_attribute *attr, char *buf)
++{
++      struct media_device *mdev = to_media_device(to_media_devnode(cd));
++
++      return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model);
++}
++
++static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
++
++/* -----------------------------------------------------------------------------
++ * Registration/unregistration
++ */
++
++static void media_device_release(struct media_devnode *mdev)
++{
++}
++
++/**
++ * media_device_register - register a media device
++ * @mdev:     The media device
++ *
++ * The caller is responsible for initializing the media device before
++ * registration. The following fields must be set:
++ *
++ * - dev must point to the parent device
++ * - model must be filled with the device model name
++ */
++int __must_check media_device_register(struct media_device *mdev)
++{
++      int ret;
++
++      if (WARN_ON(mdev->dev == NULL || mdev->model[0] == 0))
++              return -EINVAL;
++
++      /* Register the device node. */
++      mdev->devnode.fops = &media_device_fops;
++      mdev->devnode.parent = mdev->dev;
++      mdev->devnode.release = media_device_release;
++      ret = media_devnode_register(&mdev->devnode);
++      if (ret < 0)
++              return ret;
++
++      ret = device_create_file(&mdev->devnode.dev, &dev_attr_model);
++      if (ret < 0) {
++              media_devnode_unregister(&mdev->devnode);
++              return ret;
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(media_device_register);
++
++/**
++ * media_device_unregister - unregister a media device
++ * @mdev:     The media device
++ *
++ */
++void media_device_unregister(struct media_device *mdev)
++{
++      device_remove_file(&mdev->devnode.dev, &dev_attr_model);
++      media_devnode_unregister(&mdev->devnode);
++}
++EXPORT_SYMBOL_GPL(media_device_unregister);
+diff --git a/include/media/media-device.h b/include/media/media-device.h
+new file mode 100644
+index 0000000..e11f01a
+--- /dev/null
++++ b/include/media/media-device.h
+@@ -0,0 +1,69 @@
++/*
++ * Media device
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ *         Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#ifndef _MEDIA_DEVICE_H
++#define _MEDIA_DEVICE_H
++
++#include <linux/device.h>
++#include <linux/list.h>
++
++#include <media/media-devnode.h>
++
++/**
++ * struct media_device - Media device
++ * @dev:      Parent device
++ * @devnode:  Media device node
++ * @model:    Device model name
++ * @serial:   Device serial number (optional)
++ * @bus_info: Unique and stable device location identifier
++ * @hw_revision: Hardware device revision
++ * @driver_version: Device driver version
++ *
++ * This structure represents an abstract high-level media device. It allows easy
++ * access to entities and provides basic media device-level support. The
++ * structure can be allocated directly or embedded in a larger structure.
++ *
++ * The parent @dev is a physical device. It must be set before registering the
++ * media device.
++ *
++ * @model is a descriptive model name exported through sysfs. It doesn't have to
++ * be unique.
++ */
++struct media_device {
++      /* dev->driver_data points to this struct. */
++      struct device *dev;
++      struct media_devnode devnode;
++
++      char model[32];
++      char serial[40];
++      char bus_info[32];
++      u32 hw_revision;
++      u32 driver_version;
++};
++
++/* media_devnode to media_device */
++#define to_media_device(node) container_of(node, struct media_device, devnode)
++
++int __must_check media_device_register(struct media_device *mdev);
++void media_device_unregister(struct media_device *mdev);
++
++#endif
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0010-media-Entities-pads-and-links.patch b/recipes-bsp/linux/linux-omap/media/0010-media-Entities-pads-and-links.patch
new file mode 100644 (file)
index 0000000..be76233
--- /dev/null
@@ -0,0 +1,690 @@
+From b4697e5a8ad1e564ea378d435c2ce190318c1027 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:40:00 +0100
+Subject: [PATCH 10/43] media: Entities, pads and links
+
+As video hardware pipelines become increasingly complex and
+configurable, the current hardware description through v4l2 subdevices
+reaches its limits. In addition to enumerating and configuring
+subdevices, video camera drivers need a way to discover and modify at
+runtime how those subdevices are connected. This is done through new
+elements called entities, pads and links.
+
+An entity is a basic media hardware building block. It can correspond to
+a large variety of logical blocks such as physical hardware devices
+(CMOS sensor for instance), logical hardware devices (a building block
+in a System-on-Chip image processing pipeline), DMA channels or physical
+connectors.
+
+A pad is a connection endpoint through which an entity can interact with
+other entities. Data (not restricted to video) produced by an entity
+flows from the entity's output to one or more entity inputs. Pads should
+not be confused with physical pins at chip boundaries.
+
+A link is a point-to-point oriented connection between two pads, either
+on the same entity or on different entities. Data flows from a source
+pad to a sink pad.
+
+Links are stored in the source entity. To make backwards graph walk
+faster, a copy of all links is also stored in the sink entity. The copy
+is known as a backlink and is only used to help graph traversal.
+
+The entity API is made of three functions:
+
+- media_entity_init() initializes an entity. The caller must provide an
+array of pads as well as an estimated number of links. The links array
+is allocated dynamically and will be reallocated if it grows beyond the
+initial estimate.
+
+- media_entity_cleanup() frees resources allocated for an entity. It
+must be called during the cleanup phase after unregistering the entity
+and before freeing it.
+
+- media_entity_create_link() creates a link between two entities. An
+entry in the link array of each entity is allocated and stores pointers
+to source and sink pads.
+
+When a media device is unregistered, all its entities are unregistered
+automatically.
+
+The code is based on Hans Verkuil <hverkuil@xs4all.nl> initial work.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+---
+ Documentation/DocBook/v4l/media-controller.xml |   20 +++
+ Documentation/media-framework.txt              |  151 ++++++++++++++++++++++++
+ drivers/media/Makefile                         |    2 +-
+ drivers/media/media-device.c                   |   56 +++++++++
+ drivers/media/media-entity.c                   |  147 +++++++++++++++++++++++
+ include/media/media-device.h                   |   19 +++
+ include/media/media-entity.h                   |  122 +++++++++++++++++++
+ 7 files changed, 516 insertions(+), 1 deletions(-)
+ create mode 100644 drivers/media/media-entity.c
+ create mode 100644 include/media/media-entity.h
+
+diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml
+index 253ddb4..f89228d 100644
+--- a/Documentation/DocBook/v4l/media-controller.xml
++++ b/Documentation/DocBook/v4l/media-controller.xml
+@@ -53,4 +53,24 @@
+     implementing policies that belong to userspace.</para>
+     <para>The media controller API aims at solving those problems.</para>
+   </section>
++
++  <section id="media-controller-model">
++    <title>Media device model</title>
++    <para>Discovering a device internal topology, and configuring it at runtime,
++    is one of the goals of the media controller API. To achieve this, hardware
++    devices are modelled as an oriented graph of building blocks called entities
++    connected through pads.</para>
++    <para>An entity is a basic media hardware or software building block. It can
++    correspond to a large variety of logical blocks such as physical hardware
++    devices (CMOS sensor for instance), logical hardware devices (a building
++    block in a System-on-Chip image processing pipeline), DMA channels or
++    physical connectors.</para>
++    <para>A pad is a connection endpoint through which an entity can interact
++    with other entities. Data (not restricted to video) produced by an entity
++    flows from the entity's output to one or more entity inputs. Pads should not
++    be confused with physical pins at chip boundaries.</para>
++    <para>A link is a point-to-point oriented connection between two pads,
++    either on the same entity or on different entities. Data flows from a source
++    pad to a sink pad.</para>
++  </section>
+ </chapter>
+diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
+index 1844c3f..b252cf9 100644
+--- a/Documentation/media-framework.txt
++++ b/Documentation/media-framework.txt
+@@ -13,6 +13,30 @@ Documentation/DocBook/v4l/media-controller.xml. This document will focus on
+ the kernel-side implementation of the media framework.
++Abstract media device model
++---------------------------
++
++Discovering a device internal topology, and configuring it at runtime, is one
++of the goals of the media framework. To achieve this, hardware devices are
++modeled as an oriented graph of building blocks called entities connected
++through pads.
++
++An entity is a basic media hardware building block. It can correspond to
++a large variety of logical blocks such as physical hardware devices
++(CMOS sensor for instance), logical hardware devices (a building block
++in a System-on-Chip image processing pipeline), DMA channels or physical
++connectors.
++
++A pad is a connection endpoint through which an entity can interact with
++other entities. Data (not restricted to video) produced by an entity
++flows from the entity's output to one or more entity inputs. Pads should
++not be confused with physical pins at chip boundaries.
++
++A link is a point-to-point oriented connection between two pads, either
++on the same entity or on different entities. Data flows from a source
++pad to a sink pad.
++
++
+ Media device
+ ------------
+@@ -65,3 +89,130 @@ Drivers unregister media device instances by calling
+       media_device_unregister(struct media_device *mdev);
+ Unregistering a media device that hasn't been registered is *NOT* safe.
++
++
++Entities, pads and links
++------------------------
++
++- Entities
++
++Entities are represented by a struct media_entity instance, defined in
++include/media/media-entity.h. The structure is usually embedded into a
++higher-level structure, such as a v4l2_subdev or video_device instance,
++although drivers can allocate entities directly.
++
++Drivers initialize entities by calling
++
++      media_entity_init(struct media_entity *entity, u16 num_pads,
++                        struct media_pad *pads, u16 extra_links);
++
++The media_entity name, type, flags, revision and group_id fields can be
++initialized before or after calling media_entity_init. Entities embedded in
++higher-level standard structures can have some of those fields set by the
++higher-level framework.
++
++As the number of pads is known in advance, the pads array is not allocated
++dynamically but is managed by the entity driver. Most drivers will embed the
++pads array in a driver-specific structure, avoiding dynamic allocation.
++
++Drivers must set the direction of every pad in the pads array before calling
++media_entity_init. The function will initialize the other pads fields.
++
++Unlike the number of pads, the total number of links isn't always known in
++advance by the entity driver. As an initial estimate, media_entity_init
++pre-allocates a number of links equal to the number of pads plus an optional
++number of extra links. The links array will be reallocated if it grows beyond
++the initial estimate.
++
++Drivers register entities with a media device by calling
++
++      media_device_register_entity(struct media_device *mdev,
++                                   struct media_entity *entity);
++
++Entities are identified by a unique positive integer ID. Drivers can provide an
++ID by filling the media_entity id field prior to registration, or request the
++media controller framework to assign an ID automatically. Drivers that provide
++IDs manually must ensure that all IDs are unique. IDs are not guaranteed to be
++contiguous even when they are all assigned automatically by the framework.
++
++Drivers unregister entities by calling
++
++      media_device_unregister_entity(struct media_entity *entity);
++
++Unregistering an entity will not change the IDs of the other entities, and the
++ID will never be reused for a newly registered entity.
++
++When a media device is unregistered, all its entities are unregistered
++automatically. No manual entities unregistration is then required.
++
++Drivers free resources associated with an entity by calling
++
++      media_entity_cleanup(struct media_entity *entity);
++
++This function must be called during the cleanup phase after unregistering the
++entity. Note that the media_entity instance itself must be freed explicitly by
++the driver if required.
++
++Entities have flags that describe the entity capabilities and state.
++
++      MEDIA_ENT_FL_DEFAULT indicates the default entity for a given type.
++      This can be used to report the default audio and video devices or the
++      default camera sensor.
++
++Logical entity groups can be defined by setting the group ID of all member
++entities to the same non-zero value. An entity group serves no purpose in the
++kernel, but is reported to userspace during entities enumeration. The group_id
++field belongs to the media device driver and must not by touched by entity
++drivers.
++
++Media device drivers should define groups if several entities are logically
++bound together. Example usages include reporting
++
++      - ALSA, VBI and video nodes that carry the same media stream
++      - lens and flash controllers associated with a sensor
++
++- Pads
++
++Pads are represented by a struct media_pad instance, defined in
++include/media/media-entity.h. Each entity stores its pads in a pads array
++managed by the entity driver. Drivers usually embed the array in a
++driver-specific structure.
++
++Pads are identified by their entity and their 0-based index in the pads array.
++Both information are stored in the media_pad structure, making the media_pad
++pointer the canonical way to store and pass link references.
++
++Pads have flags that describe the pad capabilities and state.
++
++      MEDIA_PAD_FL_INPUT indicates that the pad supports sinking data.
++      MEDIA_PAD_FL_OUTPUT indicates that the pad supports sourcing data.
++
++One and only one of MEDIA_PAD_FL_INPUT and MEDIA_PAD_FL_OUTPUT must be set for
++each pad.
++
++- Links
++
++Links are represented by a struct media_link instance, defined in
++include/media/media-entity.h. Each entity stores all links originating at or
++targetting any of its pads in a links array. A given link is thus stored
++twice, once in the source entity and once in the target entity. The array is
++pre-allocated and grows dynamically as needed.
++
++Drivers create links by calling
++
++      media_entity_create_link(struct media_entity *source, u16 source_pad,
++                               struct media_entity *sink,   u16 sink_pad,
++                               u32 flags);
++
++An entry in the link array of each entity is allocated and stores pointers
++to source and sink pads.
++
++Links have flags that describe the link capabilities and state.
++
++      MEDIA_LNK_FL_ENABLED indicates that the link is enabled and can be used
++      to transfer media data. When two or more links target a sink pad, only
++      one of them can be enabled at a time.
++      MEDIA_LNK_FL_IMMUTABLE indicates that the link enabled state can't be
++      modified at runtime. If MEDIA_LNK_FL_IMMUTABLE is set, then
++      MEDIA_LNK_FL_ENABLED must also be set since an immutable link is always
++      enabled.
+diff --git a/drivers/media/Makefile b/drivers/media/Makefile
+index 019d3e0..b890248 100644
+--- a/drivers/media/Makefile
++++ b/drivers/media/Makefile
+@@ -2,7 +2,7 @@
+ # Makefile for the kernel multimedia device drivers.
+ #
+-media-objs    := media-device.o media-devnode.o
++media-objs    := media-device.o media-devnode.o media-entity.o
+ ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
+   obj-$(CONFIG_MEDIA_SUPPORT) += media.o
+diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
+index 57a9c6b..b8a3ace 100644
+--- a/drivers/media/media-device.c
++++ b/drivers/media/media-device.c
+@@ -25,6 +25,7 @@
+ #include <media/media-device.h>
+ #include <media/media-devnode.h>
++#include <media/media-entity.h>
+ static const struct media_file_operations media_device_fops = {
+       .owner = THIS_MODULE,
+@@ -69,6 +70,10 @@ int __must_check media_device_register(struct media_device *mdev)
+       if (WARN_ON(mdev->dev == NULL || mdev->model[0] == 0))
+               return -EINVAL;
++      mdev->entity_id = 1;
++      INIT_LIST_HEAD(&mdev->entities);
++      spin_lock_init(&mdev->lock);
++
+       /* Register the device node. */
+       mdev->devnode.fops = &media_device_fops;
+       mdev->devnode.parent = mdev->dev;
+@@ -94,7 +99,58 @@ EXPORT_SYMBOL_GPL(media_device_register);
+  */
+ void media_device_unregister(struct media_device *mdev)
+ {
++      struct media_entity *entity;
++      struct media_entity *next;
++
++      list_for_each_entry_safe(entity, next, &mdev->entities, list)
++              media_device_unregister_entity(entity);
++
+       device_remove_file(&mdev->devnode.dev, &dev_attr_model);
+       media_devnode_unregister(&mdev->devnode);
+ }
+ EXPORT_SYMBOL_GPL(media_device_unregister);
++
++/**
++ * media_device_register_entity - Register an entity with a media device
++ * @mdev:     The media device
++ * @entity:   The entity
++ */
++int __must_check media_device_register_entity(struct media_device *mdev,
++                                            struct media_entity *entity)
++{
++      /* Warn if we apparently re-register an entity */
++      WARN_ON(entity->parent != NULL);
++      entity->parent = mdev;
++
++      spin_lock(&mdev->lock);
++      if (entity->id == 0)
++              entity->id = mdev->entity_id++;
++      else
++              mdev->entity_id = max(entity->id + 1, mdev->entity_id);
++      list_add_tail(&entity->list, &mdev->entities);
++      spin_unlock(&mdev->lock);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(media_device_register_entity);
++
++/**
++ * media_device_unregister_entity - Unregister an entity
++ * @entity:   The entity
++ *
++ * If the entity has never been registered this function will return
++ * immediately.
++ */
++void media_device_unregister_entity(struct media_entity *entity)
++{
++      struct media_device *mdev = entity->parent;
++
++      if (mdev == NULL)
++              return;
++
++      spin_lock(&mdev->lock);
++      list_del(&entity->list);
++      spin_unlock(&mdev->lock);
++      entity->parent = NULL;
++}
++EXPORT_SYMBOL_GPL(media_device_unregister_entity);
+diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
+new file mode 100644
+index 0000000..e4ba2bc
+--- /dev/null
++++ b/drivers/media/media-entity.c
+@@ -0,0 +1,147 @@
++/*
++ * Media entity
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ *         Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <media/media-entity.h>
++
++/**
++ * media_entity_init - Initialize a media entity
++ *
++ * @num_pads: Total number of input and output pads.
++ * @extra_links: Initial estimate of the number of extra links.
++ * @pads: Array of 'num_pads' pads.
++ *
++ * The total number of pads is an intrinsic property of entities known by the
++ * entity driver, while the total number of links depends on hardware design
++ * and is an extrinsic property unknown to the entity driver. However, in most
++ * use cases the entity driver can guess the number of links which can safely
++ * be assumed to be equal to or larger than the number of pads.
++ *
++ * For those reasons the links array can be preallocated based on the entity
++ * driver guess and will be reallocated later if extra links need to be
++ * created.
++ *
++ * This function allocates a links array with enough space to hold at least
++ * 'num_pads' + 'extra_links' elements. The media_entity::max_links field will
++ * be set to the number of allocated elements.
++ *
++ * The pads array is managed by the entity driver and passed to
++ * media_entity_init() where its pointer will be stored in the entity structure.
++ */
++int
++media_entity_init(struct media_entity *entity, u16 num_pads,
++                struct media_pad *pads, u16 extra_links)
++{
++      struct media_link *links;
++      unsigned int max_links = num_pads + extra_links;
++      unsigned int i;
++
++      links = kzalloc(max_links * sizeof(links[0]), GFP_KERNEL);
++      if (links == NULL)
++              return -ENOMEM;
++
++      entity->group_id = 0;
++      entity->max_links = max_links;
++      entity->num_links = 0;
++      entity->num_backlinks = 0;
++      entity->num_pads = num_pads;
++      entity->pads = pads;
++      entity->links = links;
++
++      for (i = 0; i < num_pads; i++) {
++              pads[i].entity = entity;
++              pads[i].index = i;
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(media_entity_init);
++
++void
++media_entity_cleanup(struct media_entity *entity)
++{
++      kfree(entity->links);
++}
++EXPORT_SYMBOL_GPL(media_entity_cleanup);
++
++static struct media_link *media_entity_add_link(struct media_entity *entity)
++{
++      if (entity->num_links >= entity->max_links) {
++              struct media_link *links = entity->links;
++              unsigned int max_links = entity->max_links + 2;
++              unsigned int i;
++
++              links = krealloc(links, max_links * sizeof(*links), GFP_KERNEL);
++              if (links == NULL)
++                      return NULL;
++
++              for (i = 0; i < entity->num_links; i++)
++                      links[i].reverse->reverse = &links[i];
++
++              entity->max_links = max_links;
++              entity->links = links;
++      }
++
++      return &entity->links[entity->num_links++];
++}
++
++int
++media_entity_create_link(struct media_entity *source, u16 source_pad,
++                       struct media_entity *sink, u16 sink_pad, u32 flags)
++{
++      struct media_link *link;
++      struct media_link *backlink;
++
++      BUG_ON(source == NULL || sink == NULL);
++      BUG_ON(source_pad >= source->num_pads);
++      BUG_ON(sink_pad >= sink->num_pads);
++
++      link = media_entity_add_link(source);
++      if (link == NULL)
++              return -ENOMEM;
++
++      link->source = &source->pads[source_pad];
++      link->sink = &sink->pads[sink_pad];
++      link->flags = flags;
++
++      /* Create the backlink. Backlinks are used to help graph traversal and
++       * are not reported to userspace.
++       */
++      backlink = media_entity_add_link(sink);
++      if (backlink == NULL) {
++              source->num_links--;
++              return -ENOMEM;
++      }
++
++      backlink->source = &source->pads[source_pad];
++      backlink->sink = &sink->pads[sink_pad];
++      backlink->flags = flags;
++
++      link->reverse = backlink;
++      backlink->reverse = link;
++
++      sink->num_backlinks++;
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(media_entity_create_link);
+diff --git a/include/media/media-device.h b/include/media/media-device.h
+index e11f01a..0b1ecf5 100644
+--- a/include/media/media-device.h
++++ b/include/media/media-device.h
+@@ -25,8 +25,10 @@
+ #include <linux/device.h>
+ #include <linux/list.h>
++#include <linux/spinlock.h>
+ #include <media/media-devnode.h>
++#include <media/media-entity.h>
+ /**
+  * struct media_device - Media device
+@@ -37,6 +39,9 @@
+  * @bus_info: Unique and stable device location identifier
+  * @hw_revision: Hardware device revision
+  * @driver_version: Device driver version
++ * @entity_id:        ID of the next entity to be registered
++ * @entities: List of registered entities
++ * @lock:     Entities list lock
+  *
+  * This structure represents an abstract high-level media device. It allows easy
+  * access to entities and provides basic media device-level support. The
+@@ -58,6 +63,12 @@ struct media_device {
+       char bus_info[32];
+       u32 hw_revision;
+       u32 driver_version;
++
++      u32 entity_id;
++      struct list_head entities;
++
++      /* Protects the entities list */
++      spinlock_t lock;
+ };
+ /* media_devnode to media_device */
+@@ -66,4 +77,12 @@ struct media_device {
+ int __must_check media_device_register(struct media_device *mdev);
+ void media_device_unregister(struct media_device *mdev);
++int __must_check media_device_register_entity(struct media_device *mdev,
++                                            struct media_entity *entity);
++void media_device_unregister_entity(struct media_entity *entity);
++
++/* Iterate over all entities. */
++#define media_device_for_each_entity(entity, mdev)                    \
++      list_for_each_entry(entity, &(mdev)->entities, list)
++
+ #endif
+diff --git a/include/media/media-entity.h b/include/media/media-entity.h
+new file mode 100644
+index 0000000..7cf9135
+--- /dev/null
++++ b/include/media/media-entity.h
+@@ -0,0 +1,122 @@
++/*
++ * Media entity
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ *         Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#ifndef _MEDIA_ENTITY_H
++#define _MEDIA_ENTITY_H
++
++#include <linux/list.h>
++
++#define MEDIA_ENT_TYPE_SHIFT          16
++#define MEDIA_ENT_TYPE_MASK           0x00ff0000
++#define MEDIA_ENT_SUBTYPE_MASK                0x0000ffff
++
++#define MEDIA_ENT_T_DEVNODE           (1 << MEDIA_ENTITY_TYPE_SHIFT)
++#define MEDIA_ENT_T_DEVNODE_V4L               (MEDIA_ENTITY_T_DEVNODE + 1)
++#define MEDIA_ENT_T_DEVNODE_FB                (MEDIA_ENTITY_T_DEVNODE + 2)
++#define MEDIA_ENT_T_DEVNODE_ALSA      (MEDIA_ENTITY_T_DEVNODE + 3)
++#define MEDIA_ENT_T_DEVNODE_DVB               (MEDIA_ENTITY_T_DEVNODE + 4)
++
++#define MEDIA_ENT_T_V4L2_SUBDEV               (2 << MEDIA_ENTITY_TYPE_SHIFT)
++#define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR        (MEDIA_ENTITY_T_V4L2_SUBDEV + 1)
++#define MEDIA_ENT_T_V4L2_SUBDEV_FLASH (MEDIA_ENTITY_T_V4L2_SUBDEV + 2)
++#define MEDIA_ENT_T_V4L2_SUBDEV_LENS  (MEDIA_ENTITY_T_V4L2_SUBDEV + 3)
++
++#define MEDIA_ENT_FL_DEFAULT          (1 << 0)
++
++#define MEDIA_LNK_FL_ENABLED          (1 << 0)
++#define MEDIA_LNK_FL_IMMUTABLE                (1 << 1)
++
++#define MEDIA_PAD_FL_INPUT            (1 << 0)
++#define MEDIA_PAD_FL_OUTPUT           (1 << 1)
++
++struct media_link {
++      struct media_pad *source;       /* Source pad */
++      struct media_pad *sink;         /* Sink pad  */
++      struct media_link *reverse;     /* Link in the reverse direction */
++      unsigned long flags;            /* Link flags (MEDIA_LNK_FL_*) */
++};
++
++struct media_pad {
++      struct media_entity *entity;    /* Entity this pad belongs to */
++      u16 index;                      /* Pad index in the entity pads array */
++      unsigned long flags;            /* Pad flags (MEDIA_PAD_FL_*) */
++};
++
++struct media_entity {
++      struct list_head list;
++      struct media_device *parent;    /* Media device this entity belongs to*/
++      u32 id;                         /* Entity ID, unique in the parent media
++                                       * device context */
++      const char *name;               /* Entity name */
++      u32 type;                       /* Entity type (MEDIA_ENT_T_*) */
++      u32 revision;                   /* Entity revision, driver specific */
++      unsigned long flags;            /* Entity flags (MEDIA_ENT_FL_*) */
++      u32 group_id;                   /* Entity group ID */
++
++      u16 num_pads;                   /* Number of input and output pads */
++      u16 num_links;                  /* Number of existing links, both
++                                       * enabled and disabled */
++      u16 num_backlinks;              /* Number of backlinks */
++      u16 max_links;                  /* Maximum number of links */
++
++      struct media_pad *pads;         /* Pads array (num_pads elements) */
++      struct media_link *links;       /* Links array (max_links elements)*/
++
++      union {
++              /* Node specifications */
++              struct {
++                      u32 major;
++                      u32 minor;
++              } v4l;
++              struct {
++                      u32 major;
++                      u32 minor;
++              } fb;
++              struct {
++                      u32 card;
++                      u32 device;
++                      u32 subdevice;
++              } alsa;
++              int dvb;
++
++              /* Sub-device specifications */
++              /* Nothing needed yet */
++      };
++};
++
++static inline u32 media_entity_type(struct media_entity *entity)
++{
++      return entity->type & MEDIA_ENT_TYPE_MASK;
++}
++
++static inline u32 media_entity_subtype(struct media_entity *entity)
++{
++      return entity->type & MEDIA_ENT_SUBTYPE_MASK;
++}
++
++int media_entity_init(struct media_entity *entity, u16 num_pads,
++              struct media_pad *pads, u16 extra_links);
++void media_entity_cleanup(struct media_entity *entity);
++int media_entity_create_link(struct media_entity *source, u16 source_pad,
++              struct media_entity *sink, u16 sink_pad, u32 flags);
++
++#endif
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0011-media-Entity-graph-traversal.patch b/recipes-bsp/linux/linux-omap/media/0011-media-Entity-graph-traversal.patch
new file mode 100644 (file)
index 0000000..15fc612
--- /dev/null
@@ -0,0 +1,228 @@
+From 5b45472e8a692e6acea3cb6d601b44c17ea8d59e Mon Sep 17 00:00:00 2001
+From: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+Date: Sun, 7 Mar 2010 21:14:14 +0200
+Subject: [PATCH 11/43] media: Entity graph traversal
+
+Add media entity graph traversal. The traversal follows enabled links by
+depth first. Traversing graph backwards is prevented by comparing the next
+possible entity in the graph with the previous one. Multiply connected
+graphs are thus not supported.
+
+Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Vimarsh Zutshi <vimarsh.zutshi@nokia.com>
+---
+ Documentation/media-framework.txt |   42 +++++++++++++
+ drivers/media/media-entity.c      |  115 +++++++++++++++++++++++++++++++++++++
+ include/media/media-entity.h      |   15 +++++
+ 3 files changed, 172 insertions(+), 0 deletions(-)
+
+diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
+index b252cf9..88fe379 100644
+--- a/Documentation/media-framework.txt
++++ b/Documentation/media-framework.txt
+@@ -216,3 +216,45 @@ Links have flags that describe the link capabilities and state.
+       modified at runtime. If MEDIA_LNK_FL_IMMUTABLE is set, then
+       MEDIA_LNK_FL_ENABLED must also be set since an immutable link is always
+       enabled.
++
++
++Graph traversal
++---------------
++
++The media framework provides APIs to iterate over entities in a graph.
++
++To iterate over all entities belonging to a media device, drivers can use the
++media_device_for_each_entity macro, defined in include/media/media-device.h.
++
++      struct media_entity *entity;
++
++      media_device_for_each_entity(entity, mdev) {
++              /* entity will point to each entity in turn */
++              ...
++      }
++
++Drivers might also need to iterate over all entities in a graph that can be
++reached only through enabled links starting at a given entity. The media
++framework provides a depth-first graph traversal API for that purpose.
++
++Note that graphs with cycles (whether directed or undirected) are *NOT*
++supported by the graph traversal API. To prevent infinite loops, the graph
++traversal code limits the maximum depth to MEDIA_ENTITY_ENUM_MAX_DEPTH,
++currently defined as 16.
++
++Drivers initiate a graph traversal by calling
++
++      media_entity_graph_walk_start(struct media_entity_graph *graph,
++                                    struct media_entity *entity);
++
++The graph structure, provided by the caller, is initialized to start graph
++traversal at the given entity.
++
++Drivers can then retrieve the next entity by calling
++
++      media_entity_graph_walk_next(struct media_entity_graph *graph);
++
++When the graph traversal is complete the function will return NULL.
++
++Graph traversal can be interrupted at any moment. No cleanup function call is
++required and the graph structure can be freed normally.
+diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
+index e4ba2bc..a805f20 100644
+--- a/drivers/media/media-entity.c
++++ b/drivers/media/media-entity.c
+@@ -84,6 +84,121 @@ media_entity_cleanup(struct media_entity *entity)
+ }
+ EXPORT_SYMBOL_GPL(media_entity_cleanup);
++/* -----------------------------------------------------------------------------
++ * Graph traversal
++ */
++
++static struct media_entity *
++media_entity_other(struct media_entity *entity, struct media_link *link)
++{
++      if (link->source->entity == entity)
++              return link->sink->entity;
++      else
++              return link->source->entity;
++}
++
++/* push an entity to traversal stack */
++static void stack_push(struct media_entity_graph *graph,
++                     struct media_entity *entity)
++{
++      if (graph->top == MEDIA_ENTITY_ENUM_MAX_DEPTH - 1) {
++              WARN_ON(1);
++              return;
++      }
++      graph->top++;
++      graph->stack[graph->top].link = 0;
++      graph->stack[graph->top].entity = entity;
++}
++
++static struct media_entity *stack_pop(struct media_entity_graph *graph)
++{
++      struct media_entity *entity;
++
++      entity = graph->stack[graph->top].entity;
++      graph->top--;
++
++      return entity;
++}
++
++#define stack_peek(en)        ((en)->stack[(en)->top - 1].entity)
++#define link_top(en)  ((en)->stack[(en)->top].link)
++#define stack_top(en) ((en)->stack[(en)->top].entity)
++
++/**
++ * media_entity_graph_walk_start - Start walking the media graph at a given entity
++ * @graph: Media graph structure that will be used to walk the graph
++ * @entity: Starting entity
++ *
++ * This function initializes the graph traversal structure to walk the entities
++ * graph starting at the given entity. The traversal structure must not be
++ * modified by the caller during graph traversal. When done the structure can
++ * safely be freed.
++ */
++void media_entity_graph_walk_start(struct media_entity_graph *graph,
++                                 struct media_entity *entity)
++{
++      graph->top = 0;
++      graph->stack[graph->top].entity = NULL;
++      stack_push(graph, entity);
++}
++EXPORT_SYMBOL_GPL(media_entity_graph_walk_start);
++
++/**
++ * media_entity_graph_walk_next - Get the next entity in the graph
++ * @graph: Media graph structure
++ *
++ * Perform a depth-first traversal of the given media entities graph.
++ *
++ * The graph structure must have been previously initialized with a call to
++ * media_entity_graph_walk_start().
++ *
++ * Return the next entity in the graph or NULL if the whole graph have been
++ * traversed.
++ */
++struct media_entity *
++media_entity_graph_walk_next(struct media_entity_graph *graph)
++{
++      if (stack_top(graph) == NULL)
++              return NULL;
++
++      /*
++       * Depth first search. Push entity to stack and continue from
++       * top of the stack until no more entities on the level can be
++       * found.
++       */
++      while (link_top(graph) < stack_top(graph)->num_links) {
++              struct media_entity *entity = stack_top(graph);
++              struct media_link *link = &entity->links[link_top(graph)];
++              struct media_entity *next;
++
++              /* The link is not enabled so we do not follow. */
++              if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
++                      link_top(graph)++;
++                      continue;
++              }
++
++              /* Get the entity in the other end of the link . */
++              next = media_entity_other(entity, link);
++
++              /* Was it the entity we came here from? */
++              if (next == stack_peek(graph)) {
++                      link_top(graph)++;
++                      continue;
++              }
++
++              /* Push the new entity to stack and start over. */
++              link_top(graph)++;
++              stack_push(graph, next);
++      }
++
++      return stack_pop(graph);
++}
++EXPORT_SYMBOL_GPL(media_entity_graph_walk_next);
++
++/* -----------------------------------------------------------------------------
++ * Links management
++ */
++
+ static struct media_link *media_entity_add_link(struct media_entity *entity)
+ {
+       if (entity->num_links >= entity->max_links) {
+diff --git a/include/media/media-entity.h b/include/media/media-entity.h
+index 7cf9135..b82f824 100644
+--- a/include/media/media-entity.h
++++ b/include/media/media-entity.h
+@@ -113,10 +113,25 @@ static inline u32 media_entity_subtype(struct media_entity *entity)
+       return entity->type & MEDIA_ENT_SUBTYPE_MASK;
+ }
++#define MEDIA_ENTITY_ENUM_MAX_DEPTH   16
++
++struct media_entity_graph {
++      struct {
++              struct media_entity *entity;
++              int link;
++      } stack[MEDIA_ENTITY_ENUM_MAX_DEPTH];
++      int top;
++};
++
+ int media_entity_init(struct media_entity *entity, u16 num_pads,
+               struct media_pad *pads, u16 extra_links);
+ void media_entity_cleanup(struct media_entity *entity);
+ int media_entity_create_link(struct media_entity *source, u16 source_pad,
+               struct media_entity *sink, u16 sink_pad, u32 flags);
++void media_entity_graph_walk_start(struct media_entity_graph *graph,
++              struct media_entity *entity);
++struct media_entity *
++media_entity_graph_walk_next(struct media_entity_graph *graph);
++
+ #endif
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0012-media-Entity-use-count.patch b/recipes-bsp/linux/linux-omap/media/0012-media-Entity-use-count.patch
new file mode 100644 (file)
index 0000000..bc850e4
--- /dev/null
@@ -0,0 +1,176 @@
+From 3be6a2d10ff0cad0b240c65054da28395b014f82 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Sun, 7 Mar 2010 20:04:59 +0200
+Subject: [PATCH 12/43] media: Entity use count
+
+Due to the wide differences between drivers regarding power management
+needs, the media controller does not implement power management.
+However, the media_entity structure includes a use_count field that
+media drivers can use to track the number of users of every entity for
+power management needs.
+
+The use_count field is owned by media drivers and must not be touched by
+entity drivers. Access to the field must be protected by the media
+device graph_mutex lock.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ Documentation/media-framework.txt |   13 ++++++++++
+ drivers/media/media-device.c      |    1 +
+ drivers/media/media-entity.c      |   46 +++++++++++++++++++++++++++++++++++++
+ include/media/media-device.h      |    4 +++
+ include/media/media-entity.h      |    5 ++++
+ 5 files changed, 69 insertions(+), 0 deletions(-)
+
+diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
+index 88fe379..9017a41 100644
+--- a/Documentation/media-framework.txt
++++ b/Documentation/media-framework.txt
+@@ -258,3 +258,16 @@ When the graph traversal is complete the function will return NULL.
+ Graph traversal can be interrupted at any moment. No cleanup function call is
+ required and the graph structure can be freed normally.
++
++
++Use count and power handling
++----------------------------
++
++Due to the wide differences between drivers regarding power management needs,
++the media controller does not implement power management. However, the
++media_entity structure includes a use_count field that media drivers can use to
++track the number of users of every entity for power management needs.
++
++The use_count field is owned by media drivers and must not be touched by entity
++drivers. Access to the field must be protected by the media device graph_mutex
++lock.
+diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
+index b8a3ace..e4c2157 100644
+--- a/drivers/media/media-device.c
++++ b/drivers/media/media-device.c
+@@ -73,6 +73,7 @@ int __must_check media_device_register(struct media_device *mdev)
+       mdev->entity_id = 1;
+       INIT_LIST_HEAD(&mdev->entities);
+       spin_lock_init(&mdev->lock);
++      mutex_init(&mdev->graph_mutex);
+       /* Register the device node. */
+       mdev->devnode.fops = &media_device_fops;
+diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
+index a805f20..fe6bfd2 100644
+--- a/drivers/media/media-entity.c
++++ b/drivers/media/media-entity.c
+@@ -23,6 +23,7 @@
+ #include <linux/module.h>
+ #include <linux/slab.h>
+ #include <media/media-entity.h>
++#include <media/media-device.h>
+ /**
+  * media_entity_init - Initialize a media entity
+@@ -196,6 +197,51 @@ media_entity_graph_walk_next(struct media_entity_graph *graph)
+ EXPORT_SYMBOL_GPL(media_entity_graph_walk_next);
+ /* -----------------------------------------------------------------------------
++ * Module use count
++ */
++
++/*
++ * media_entity_get - Get a reference to the parent module
++ * @entity: The entity
++ *
++ * Get a reference to the parent media device module.
++ *
++ * The function will return immediately if @entity is NULL.
++ *
++ * Return a pointer to the entity on success or NULL on failure.
++ */
++struct media_entity *media_entity_get(struct media_entity *entity)
++{
++      if (entity == NULL)
++              return NULL;
++
++      if (entity->parent->dev &&
++          !try_module_get(entity->parent->dev->driver->owner))
++              return NULL;
++
++      return entity;
++}
++EXPORT_SYMBOL_GPL(media_entity_get);
++
++/*
++ * media_entity_put - Release the reference to the parent module
++ * @entity: The entity
++ *
++ * Release the reference count acquired by media_entity_get().
++ *
++ * The function will return immediately if @entity is NULL.
++ */
++void media_entity_put(struct media_entity *entity)
++{
++      if (entity == NULL)
++              return;
++
++      if (entity->parent->dev)
++              module_put(entity->parent->dev->driver->owner);
++}
++EXPORT_SYMBOL_GPL(media_entity_put);
++
++/* -----------------------------------------------------------------------------
+  * Links management
+  */
+diff --git a/include/media/media-device.h b/include/media/media-device.h
+index 0b1ecf5..260d59c 100644
+--- a/include/media/media-device.h
++++ b/include/media/media-device.h
+@@ -25,6 +25,7 @@
+ #include <linux/device.h>
+ #include <linux/list.h>
++#include <linux/mutex.h>
+ #include <linux/spinlock.h>
+ #include <media/media-devnode.h>
+@@ -42,6 +43,7 @@
+  * @entity_id:        ID of the next entity to be registered
+  * @entities: List of registered entities
+  * @lock:     Entities list lock
++ * @graph_mutex: Entities graph operation lock
+  *
+  * This structure represents an abstract high-level media device. It allows easy
+  * access to entities and provides basic media device-level support. The
+@@ -69,6 +71,8 @@ struct media_device {
+       /* Protects the entities list */
+       spinlock_t lock;
++      /* Serializes graph operations. */
++      struct mutex graph_mutex;
+ };
+ /* media_devnode to media_device */
+diff --git a/include/media/media-entity.h b/include/media/media-entity.h
+index b82f824..114541a 100644
+--- a/include/media/media-entity.h
++++ b/include/media/media-entity.h
+@@ -81,6 +81,8 @@ struct media_entity {
+       struct media_pad *pads;         /* Pads array (num_pads elements) */
+       struct media_link *links;       /* Links array (max_links elements)*/
++      int use_count;                  /* Use count for the entity. */
++
+       union {
+               /* Node specifications */
+               struct {
+@@ -129,6 +131,9 @@ void media_entity_cleanup(struct media_entity *entity);
+ int media_entity_create_link(struct media_entity *source, u16 source_pad,
+               struct media_entity *sink, u16 sink_pad, u32 flags);
++struct media_entity *media_entity_get(struct media_entity *entity);
++void media_entity_put(struct media_entity *entity);
++
+ void media_entity_graph_walk_start(struct media_entity_graph *graph,
+               struct media_entity *entity);
+ struct media_entity *
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0013-media-Media-device-information-query.patch b/recipes-bsp/linux/linux-omap/media/0013-media-Media-device-information-query.patch
new file mode 100644 (file)
index 0000000..bf9fcd9
--- /dev/null
@@ -0,0 +1,659 @@
+From cb6936ced565e168ac7f9be06dc3320733aac17f Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 18 Aug 2010 16:41:22 +0200
+Subject: [PATCH 13/43] media: Media device information query
+
+Create the following ioctl and implement it at the media device level to
+query device information.
+
+- MEDIA_IOC_DEVICE_INFO: Query media device information
+
+The ioctl and its data structure are defined in the new kernel header
+linux/media.h available to userspace applications.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ Documentation/DocBook/media-entities.tmpl          |   12 ++
+ Documentation/DocBook/v4l/media-controller.xml     |   10 ++
+ Documentation/DocBook/v4l/media-func-close.xml     |   59 +++++++++
+ Documentation/DocBook/v4l/media-func-ioctl.xml     |  116 +++++++++++++++++
+ Documentation/DocBook/v4l/media-func-open.xml      |   94 ++++++++++++++
+ .../DocBook/v4l/media-ioc-device-info.xml          |  132 ++++++++++++++++++++
+ drivers/media/media-device.c                       |   57 +++++++++
+ include/linux/Kbuild                               |    1 +
+ include/linux/media.h                              |   45 +++++++
+ 9 files changed, 526 insertions(+), 0 deletions(-)
+ create mode 100644 Documentation/DocBook/v4l/media-func-close.xml
+ create mode 100644 Documentation/DocBook/v4l/media-func-ioctl.xml
+ create mode 100644 Documentation/DocBook/v4l/media-func-open.xml
+ create mode 100644 Documentation/DocBook/v4l/media-ioc-device-info.xml
+ create mode 100644 include/linux/media.h
+
+diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
+index 61d6f11..6af3375 100644
+--- a/Documentation/DocBook/media-entities.tmpl
++++ b/Documentation/DocBook/media-entities.tmpl
+@@ -11,6 +11,10 @@
+ <!ENTITY func-select "<link linkend='func-select'><function>select()</function></link>">
+ <!ENTITY func-write "<link linkend='func-write'><function>write()</function></link>">
++<!ENTITY media-func-close "<link linkend='media-func-close'><function>close()</function></link>">
++<!ENTITY media-func-ioctl "<link linkend='media-func-ioctl'><function>ioctl()</function></link>">
++<!ENTITY media-func-open "<link linkend='media-func-open'><function>open()</function></link>">
++
+ <!-- Ioctls -->
+ <!ENTITY VIDIOC-CROPCAP "<link linkend='vidioc-cropcap'><constant>VIDIOC_CROPCAP</constant></link>">
+ <!ENTITY VIDIOC-DBG-G-CHIP-IDENT "<link linkend='vidioc-dbg-g-chip-ident'><constant>VIDIOC_DBG_G_CHIP_IDENT</constant></link>">
+@@ -87,6 +91,8 @@
+ <!ENTITY VIDIOC-TRY-FMT "<link linkend='vidioc-g-fmt'><constant>VIDIOC_TRY_FMT</constant></link>">
+ <!ENTITY VIDIOC-UNSUBSCRIBE-EVENT "<link linkend='vidioc-subscribe-event'><constant>VIDIOC_UNSUBSCRIBE_EVENT</constant></link>">
++<!ENTITY MEDIA-IOC-DEVICE-INFO "<link linkend='media-ioc-device-info'><constant>MEDIA_IOC_DEVICE_INFO</constant></link>">
++
+ <!-- Types -->
+ <!ENTITY v4l2-std-id "<link linkend='v4l2-std-id'>v4l2_std_id</link>">
+@@ -181,6 +187,8 @@
+ <!ENTITY v4l2-vbi-format "struct&nbsp;<link linkend='v4l2-vbi-format'>v4l2_vbi_format</link>">
+ <!ENTITY v4l2-window "struct&nbsp;<link linkend='v4l2-window'>v4l2_window</link>">
++<!ENTITY media-device-info "struct&nbsp;<link linkend='media-device-info'>media_device_info</link>">
++
+ <!-- Error Codes -->
+ <!ENTITY EACCES "<errorcode>EACCES</errorcode> error code">
+ <!ENTITY EAGAIN "<errorcode>EAGAIN</errorcode> error code">
+@@ -322,6 +330,10 @@
+ <!ENTITY sub-media-indices SYSTEM "media-indices.tmpl">
+ <!ENTITY sub-media-controller SYSTEM "v4l/media-controller.xml">
++<!ENTITY sub-media-open SYSTEM "v4l/media-func-open.xml">
++<!ENTITY sub-media-close SYSTEM "v4l/media-func-close.xml">
++<!ENTITY sub-media-ioctl SYSTEM "v4l/media-func-ioctl.xml">
++<!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml">
+ <!-- Function Reference -->
+ <!ENTITY close SYSTEM "v4l/func-close.xml">
+diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml
+index f89228d..a46b786 100644
+--- a/Documentation/DocBook/v4l/media-controller.xml
++++ b/Documentation/DocBook/v4l/media-controller.xml
+@@ -74,3 +74,13 @@
+     pad to a sink pad.</para>
+   </section>
+ </chapter>
++
++<appendix id="media-user-func">
++  <title>Function Reference</title>
++  <!-- Keep this alphabetically sorted. -->
++  &sub-media-open;
++  &sub-media-close;
++  &sub-media-ioctl;
++  <!-- All ioctls go here. -->
++  &sub-media-ioc-device-info;
++</appendix>
+diff --git a/Documentation/DocBook/v4l/media-func-close.xml b/Documentation/DocBook/v4l/media-func-close.xml
+new file mode 100644
+index 0000000..be149c8
+--- /dev/null
++++ b/Documentation/DocBook/v4l/media-func-close.xml
+@@ -0,0 +1,59 @@
++<refentry id="media-func-close">
++  <refmeta>
++    <refentrytitle>media close()</refentrytitle>
++    &manvol;
++  </refmeta>
++
++  <refnamediv>
++    <refname>media-close</refname>
++    <refpurpose>Close a media device</refpurpose>
++  </refnamediv>
++
++  <refsynopsisdiv>
++    <funcsynopsis>
++      <funcsynopsisinfo>#include &lt;unistd.h&gt;</funcsynopsisinfo>
++      <funcprototype>
++      <funcdef>int <function>close</function></funcdef>
++      <paramdef>int <parameter>fd</parameter></paramdef>
++      </funcprototype>
++    </funcsynopsis>
++  </refsynopsisdiv>
++
++  <refsect1>
++    <title>Arguments</title>
++
++    <variablelist>
++      <varlistentry>
++      <term><parameter>fd</parameter></term>
++      <listitem>
++        <para>&fd;</para>
++      </listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++
++  <refsect1>
++    <title>Description</title>
++
++    <para>Closes the media device. Resources associated with the file descriptor
++    are freed. The device configuration remain unchanged.</para>
++  </refsect1>
++
++  <refsect1>
++    <title>Return Value</title>
++
++    <para><function>close</function> returns 0 on success. On error, -1 is
++    returned, and <varname>errno</varname> is set appropriately. Possible error
++    codes are:</para>
++
++    <variablelist>
++      <varlistentry>
++      <term><errorcode>EBADF</errorcode></term>
++      <listitem>
++        <para><parameter>fd</parameter> is not a valid open file descriptor.
++        </para>
++      </listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++</refentry>
+diff --git a/Documentation/DocBook/v4l/media-func-ioctl.xml b/Documentation/DocBook/v4l/media-func-ioctl.xml
+new file mode 100644
+index 0000000..bda8604
+--- /dev/null
++++ b/Documentation/DocBook/v4l/media-func-ioctl.xml
+@@ -0,0 +1,116 @@
++<refentry id="media-func-ioctl">
++  <refmeta>
++    <refentrytitle>media ioctl()</refentrytitle>
++    &manvol;
++  </refmeta>
++
++  <refnamediv>
++    <refname>media-ioctl</refname>
++    <refpurpose>Control a media device</refpurpose>
++  </refnamediv>
++
++  <refsynopsisdiv>
++    <funcsynopsis>
++      <funcsynopsisinfo>#include &lt;sys/ioctl.h&gt;</funcsynopsisinfo>
++      <funcprototype>
++      <funcdef>int <function>ioctl</function></funcdef>
++      <paramdef>int <parameter>fd</parameter></paramdef>
++      <paramdef>int <parameter>request</parameter></paramdef>
++      <paramdef>void *<parameter>argp</parameter></paramdef>
++      </funcprototype>
++    </funcsynopsis>
++  </refsynopsisdiv>
++
++  <refsect1>
++    <title>Arguments</title>
++
++    <variablelist>
++      <varlistentry>
++      <term><parameter>fd</parameter></term>
++      <listitem>
++        <para>&fd;</para>
++      </listitem>
++      </varlistentry>
++      <varlistentry>
++      <term><parameter>request</parameter></term>
++      <listitem>
++        <para>Media ioctl request code as defined in the media.h header file,
++        for example MEDIA_IOC_SETUP_LINK.</para>
++      </listitem>
++      </varlistentry>
++      <varlistentry>
++      <term><parameter>argp</parameter></term>
++      <listitem>
++        <para>Pointer to a request-specific structure.</para>
++      </listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++
++  <refsect1>
++    <title>Description</title>
++    <para>The <function>ioctl()</function> function manipulates media device
++    parameters. The argument <parameter>fd</parameter> must be an open file
++    descriptor.</para>
++    <para>The ioctl <parameter>request</parameter> code specifies the media
++    function to be called. It has encoded in it whether the argument is an
++    input, output or read/write parameter, and the size of the argument
++    <parameter>argp</parameter> in bytes.</para>
++    <para>Macros and structures definitions specifying media ioctl requests and
++    their parameters are located in the media.h header file. All media ioctl
++    requests, their respective function and parameters are specified in
++    <xref linkend="media-user-func" />.</para>
++  </refsect1>
++
++  <refsect1>
++    <title>Return Value</title>
++
++    <para><function>ioctl()</function> returns <returnvalue>0</returnvalue> on
++    success. On failure, <returnvalue>-1</returnvalue> is returned, and the
++    <varname>errno</varname> variable is set appropriately. Generic error codes
++    are listed below, and request-specific error codes are listed in the
++    individual requests descriptions.</para>
++    <para>When an ioctl that takes an output or read/write parameter fails,
++    the parameter remains unmodified.</para>
++
++    <variablelist>
++      <varlistentry>
++      <term><errorcode>EBADF</errorcode></term>
++      <listitem>
++        <para><parameter>fd</parameter> is not a valid open file descriptor.
++        </para>
++      </listitem>
++      </varlistentry>
++      <varlistentry>
++      <term><errorcode>EFAULT</errorcode></term>
++      <listitem>
++        <para><parameter>argp</parameter> references an inaccessible memory
++        area.</para>
++      </listitem>
++      </varlistentry>
++      <varlistentry>
++      <term><errorcode>EINVAL</errorcode></term>
++      <listitem>
++        <para>The <parameter>request</parameter> or the data pointed to by
++        <parameter>argp</parameter> is not valid. This is a very common error
++        code, see the individual ioctl requests listed in
++        <xref linkend="media-user-func" /> for actual causes.</para>
++      </listitem>
++      </varlistentry>
++      <varlistentry>
++      <term><errorcode>ENOMEM</errorcode></term>
++      <listitem>
++        <para>Insufficient kernel memory was available to complete the
++        request.</para>
++      </listitem>
++      </varlistentry>
++      <varlistentry>
++      <term><errorcode>ENOTTY</errorcode></term>
++      <listitem>
++        <para><parameter>fd</parameter> is  not  associated  with  a character
++        special device.</para>
++      </listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++</refentry>
+diff --git a/Documentation/DocBook/v4l/media-func-open.xml b/Documentation/DocBook/v4l/media-func-open.xml
+new file mode 100644
+index 0000000..f7df034
+--- /dev/null
++++ b/Documentation/DocBook/v4l/media-func-open.xml
+@@ -0,0 +1,94 @@
++<refentry id="media-func-open">
++  <refmeta>
++    <refentrytitle>media open()</refentrytitle>
++    &manvol;
++  </refmeta>
++
++  <refnamediv>
++    <refname>media-open</refname>
++    <refpurpose>Open a media device</refpurpose>
++  </refnamediv>
++
++  <refsynopsisdiv>
++    <funcsynopsis>
++      <funcsynopsisinfo>#include &lt;fcntl.h&gt;</funcsynopsisinfo>
++      <funcprototype>
++      <funcdef>int <function>open</function></funcdef>
++      <paramdef>const char *<parameter>device_name</parameter></paramdef>
++      <paramdef>int <parameter>flags</parameter></paramdef>
++      </funcprototype>
++    </funcsynopsis>
++  </refsynopsisdiv>
++
++  <refsect1>
++    <title>Arguments</title>
++
++    <variablelist>
++      <varlistentry>
++      <term><parameter>device_name</parameter></term>
++      <listitem>
++        <para>Device to be opened.</para>
++      </listitem>
++      </varlistentry>
++      <varlistentry>
++      <term><parameter>flags</parameter></term>
++      <listitem>
++        <para>Open flags. Access mode must be either <constant>O_RDONLY</constant>
++        or <constant>O_RDWR</constant>. Other flags have no effect.</para>
++      </listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++  <refsect1>
++    <title>Description</title>
++    <para>To open a media device applications call <function>open()</function>
++    with the desired device name. The function has no side effects; the device
++    configuration remain unchanged.</para>
++    <para>When the device is opened in read-only mode, attemps to modify its
++    configuration will result in an error, and <varname>errno</varname> will be
++    set to <errorcode>EBADF</errorcode>.</para>
++  </refsect1>
++  <refsect1>
++    <title>Return Value</title>
++
++    <para><function>open</function> returns the new file descriptor on success.
++    On error, -1 is returned, and <varname>errno</varname> is set appropriately.
++    Possible error codes are:</para>
++
++    <variablelist>
++      <varlistentry>
++      <term><errorcode>EACCES</errorcode></term>
++      <listitem>
++        <para>The requested access to the file is not allowed.</para>
++      </listitem>
++      </varlistentry>
++      <varlistentry>
++      <term><errorcode>EMFILE</errorcode></term>
++      <listitem>
++        <para>The  process  already  has  the  maximum number of files open.
++        </para>
++      </listitem>
++      </varlistentry>
++      <varlistentry>
++      <term><errorcode>ENFILE</errorcode></term>
++      <listitem>
++        <para>The system limit on the total number of open files has been
++        reached.</para>
++      </listitem>
++      </varlistentry>
++      <varlistentry>
++      <term><errorcode>ENOMEM</errorcode></term>
++      <listitem>
++        <para>Insufficient kernel memory was available.</para>
++      </listitem>
++      </varlistentry>
++      <varlistentry>
++      <term><errorcode>ENXIO</errorcode></term>
++      <listitem>
++        <para>No device corresponding to this device special file exists.
++        </para>
++      </listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++</refentry>
+diff --git a/Documentation/DocBook/v4l/media-ioc-device-info.xml b/Documentation/DocBook/v4l/media-ioc-device-info.xml
+new file mode 100644
+index 0000000..278a312
+--- /dev/null
++++ b/Documentation/DocBook/v4l/media-ioc-device-info.xml
+@@ -0,0 +1,132 @@
++<refentry id="media-ioc-device-info">
++  <refmeta>
++    <refentrytitle>ioctl MEDIA_IOC_DEVICE_INFO</refentrytitle>
++    &manvol;
++  </refmeta>
++
++  <refnamediv>
++    <refname>MEDIA_IOC_DEVICE_INFO</refname>
++    <refpurpose>Query device information</refpurpose>
++  </refnamediv>
++
++  <refsynopsisdiv>
++    <funcsynopsis>
++      <funcprototype>
++      <funcdef>int <function>ioctl</function></funcdef>
++      <paramdef>int <parameter>fd</parameter></paramdef>
++      <paramdef>int <parameter>request</parameter></paramdef>
++      <paramdef>struct media_device_info *<parameter>argp</parameter></paramdef>
++      </funcprototype>
++    </funcsynopsis>
++  </refsynopsisdiv>
++
++  <refsect1>
++    <title>Arguments</title>
++
++    <variablelist>
++      <varlistentry>
++      <term><parameter>fd</parameter></term>
++      <listitem>
++        <para>&fd;</para>
++      </listitem>
++      </varlistentry>
++      <varlistentry>
++      <term><parameter>request</parameter></term>
++      <listitem>
++        <para>MEDIA_IOC_DEVICE_INFO</para>
++      </listitem>
++      </varlistentry>
++      <varlistentry>
++      <term><parameter>argp</parameter></term>
++      <listitem>
++        <para></para>
++      </listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++
++  <refsect1>
++    <title>Description</title>
++
++    <para>All media devices must support the <constant>MEDIA_IOC_DEVICE_INFO</constant>
++    ioctl. To query device information, applications call the ioctl with a
++    pointer to a &media-device-info;. The driver fills the structure and returns
++    the information to the application.
++    The ioctl never fails.</para>
++
++    <table pgwide="1" frame="none" id="media-device-info">
++      <title>struct <structname>media_device_info</structname></title>
++      <tgroup cols="3">
++      &cs-str;
++      <tbody valign="top">
++        <row>
++          <entry>char</entry>
++          <entry><structfield>driver</structfield>[16]</entry>
++          <entry><para>Name of the driver implementing the media API as a
++          NUL-terminated ASCII string. The driver version is stored in the
++          <structfield>driver_version</structfield> field.</para>
++          <para>Driver specific applications can use this information to
++          verify the driver identity. It is also useful to work around
++          known bugs, or to identify drivers in error reports.</para></entry>
++        </row>
++        <row>
++          <entry>char</entry>
++          <entry><structfield>model</structfield>[32]</entry>
++          <entry>Device model name as a NUL-terminated UTF-8 string. The
++          device version is stored in the <structfield>device_version</structfield>
++          field and is not be appended to the model name.</entry>
++        </row>
++        <row>
++          <entry>char</entry>
++          <entry><structfield>serial</structfield>[40]</entry>
++          <entry>Serial number as a NUL-terminated ASCII string.</entry>
++        </row>
++        <row>
++          <entry>char</entry>
++          <entry><structfield>bus_info</structfield>[32]</entry>
++          <entry>Location of the device in the system as a NUL-terminated
++          ASCII string. This includes the bus type name (PCI, USB, ...) and a
++          bus-specific identifier.</entry>
++        </row>
++        <row>
++          <entry>__u32</entry>
++          <entry><structfield>media_version</structfield></entry>
++          <entry>Media API version, formatted with the
++          <constant>KERNEL_VERSION()</constant> macro.</entry>
++        </row>
++        <row>
++          <entry>__u32</entry>
++          <entry><structfield>hw_revision</structfield></entry>
++          <entry>Hardware device revision in a driver-specific format.</entry>
++        </row>
++        <row>
++          <entry>__u32</entry>
++          <entry><structfield>media_version</structfield></entry>
++          <entry>Media device driver version, formatted with the
++          <constant>KERNEL_VERSION()</constant> macro. Together with the
++          <structfield>driver</structfield> field this identifies a particular
++          driver.</entry>
++        </row>
++        <row>
++          <entry>__u32</entry>
++          <entry><structfield>reserved</structfield>[31]</entry>
++          <entry>Reserved for future extensions. Drivers and applications must
++          set this array to zero.</entry>
++        </row>
++      </tbody>
++      </tgroup>
++    </table>
++    <para>The <structfield>serial</structfield> and <structfield>bus_info</structfield>
++    fields can be used to distinguish between multiple instances of otherwise
++    identical hardware. The serial number takes precedence when provided and can
++    be assumed to be unique. If the serial number is an empty string, the
++    <structfield>bus_info</structfield> field can be used instead. The
++    <structfield>bus_info</structfield> field is guaranteed to be unique, but
++    can vary across reboots or device unplug/replug.</para>
++  </refsect1>
++
++  <refsect1>
++    <title>Return value</title>
++    <para>This function doesn't return specific error codes.</para>
++  </refsect1>
++</refentry>
+diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
+index e4c2157..5c745be 100644
+--- a/drivers/media/media-device.c
++++ b/drivers/media/media-device.c
+@@ -22,13 +22,70 @@
+ #include <linux/types.h>
+ #include <linux/ioctl.h>
++#include <linux/media.h>
+ #include <media/media-device.h>
+ #include <media/media-devnode.h>
+ #include <media/media-entity.h>
++/* -----------------------------------------------------------------------------
++ * Userspace API
++ */
++
++static int media_device_open(struct file *filp)
++{
++      return 0;
++}
++
++static int media_device_close(struct file *filp)
++{
++      return 0;
++}
++
++static int media_device_get_info(struct media_device *dev,
++                               struct media_device_info __user *__info)
++{
++      struct media_device_info info;
++
++      memset(&info, 0, sizeof(info));
++
++      strlcpy(info.driver, dev->dev->driver->name, sizeof(info.driver));
++      strlcpy(info.model, dev->model, sizeof(info.model));
++      strlcpy(info.serial, dev->serial, sizeof(info.serial));
++      strlcpy(info.bus_info, dev->bus_info, sizeof(info.bus_info));
++
++      info.media_version = MEDIA_API_VERSION;
++      info.hw_revision = dev->hw_revision;
++      info.driver_version = dev->driver_version;
++
++      return copy_to_user(__info, &info, sizeof(*__info));
++}
++
++static long media_device_ioctl(struct file *filp, unsigned int cmd,
++                             unsigned long arg)
++{
++      struct media_devnode *devnode = media_devnode_data(filp);
++      struct media_device *dev = to_media_device(devnode);
++      long ret;
++
++      switch (cmd) {
++      case MEDIA_IOC_DEVICE_INFO:
++              ret = media_device_get_info(dev,
++                              (struct media_device_info __user *)arg);
++              break;
++
++      default:
++              ret = -ENOIOCTLCMD;
++      }
++
++      return ret;
++}
++
+ static const struct media_file_operations media_device_fops = {
+       .owner = THIS_MODULE,
++      .open = media_device_open,
++      .ioctl = media_device_ioctl,
++      .release = media_device_close,
+ };
+ /* -----------------------------------------------------------------------------
+diff --git a/include/linux/Kbuild b/include/linux/Kbuild
+index 97319a8..26e0a7f 100644
+--- a/include/linux/Kbuild
++++ b/include/linux/Kbuild
+@@ -228,6 +228,7 @@ header-y += magic.h
+ header-y += major.h
+ header-y += map_to_7segment.h
+ header-y += matroxfb.h
++header-y += media.h
+ header-y += mempolicy.h
+ header-y += meye.h
+ header-y += mii.h
+diff --git a/include/linux/media.h b/include/linux/media.h
+new file mode 100644
+index 0000000..4c52f08
+--- /dev/null
++++ b/include/linux/media.h
+@@ -0,0 +1,45 @@
++/*
++ * Multimedia device API
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ *         Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#ifndef __LINUX_MEDIA_H
++#define __LINUX_MEDIA_H
++
++#include <linux/ioctl.h>
++#include <linux/types.h>
++#include <linux/version.h>
++
++#define MEDIA_API_VERSION     KERNEL_VERSION(0, 1, 0)
++
++struct media_device_info {
++      char driver[16];
++      char model[32];
++      char serial[40];
++      char bus_info[32];
++      __u32 media_version;
++      __u32 hw_revision;
++      __u32 driver_version;
++      __u32 reserved[31];
++};
++
++#define MEDIA_IOC_DEVICE_INFO         _IOWR('M', 1, struct media_device_info)
++
++#endif /* __LINUX_MEDIA_H */
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0014-media-Entities-pads-and-links-enumeration.patch b/recipes-bsp/linux/linux-omap/media/0014-media-Entities-pads-and-links-enumeration.patch
new file mode 100644 (file)
index 0000000..cc9e876
--- /dev/null
@@ -0,0 +1,889 @@
+From d7784ca094970b836c99e5f2a6344811625753a3 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:40:01 +0100
+Subject: [PATCH 14/43] media: Entities, pads and links enumeration
+
+Create the following two ioctls and implement them at the media device
+level to enumerate entities, pads and links.
+
+- MEDIA_IOC_ENUM_ENTITIES: Enumerate entities and their properties
+- MEDIA_IOC_ENUM_LINKS: Enumerate all pads and links for a given entity
+
+Entity IDs can be non-contiguous. Userspace applications should
+enumerate entities using the MEDIA_ENT_ID_FLAG_NEXT flag. When the flag
+is set in the entity ID, the MEDIA_IOC_ENUM_ENTITIES will return the
+next entity with an ID bigger than the requested one.
+
+Only forward links that originate at one of the entity's source pads are
+returned during the enumeration process.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+---
+ Documentation/DocBook/media-entities.tmpl          |    8 +
+ Documentation/DocBook/v4l/media-controller.xml     |    2 +
+ .../DocBook/v4l/media-ioc-device-info.xml          |    3 +-
+ .../DocBook/v4l/media-ioc-enum-entities.xml        |  308 ++++++++++++++++++++
+ Documentation/DocBook/v4l/media-ioc-enum-links.xml |  202 +++++++++++++
+ drivers/media/media-device.c                       |  123 ++++++++
+ include/linux/media.h                              |   85 ++++++
+ include/media/media-entity.h                       |   24 +--
+ 8 files changed, 731 insertions(+), 24 deletions(-)
+ create mode 100644 Documentation/DocBook/v4l/media-ioc-enum-entities.xml
+ create mode 100644 Documentation/DocBook/v4l/media-ioc-enum-links.xml
+
+diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
+index 6af3375..6e7dae4 100644
+--- a/Documentation/DocBook/media-entities.tmpl
++++ b/Documentation/DocBook/media-entities.tmpl
+@@ -92,6 +92,8 @@
+ <!ENTITY VIDIOC-UNSUBSCRIBE-EVENT "<link linkend='vidioc-subscribe-event'><constant>VIDIOC_UNSUBSCRIBE_EVENT</constant></link>">
+ <!ENTITY MEDIA-IOC-DEVICE-INFO "<link linkend='media-ioc-device-info'><constant>MEDIA_IOC_DEVICE_INFO</constant></link>">
++<!ENTITY MEDIA-IOC-ENUM-ENTITIES "<link linkend='media-ioc-enum-entities'><constant>MEDIA_IOC_ENUM_ENTITIES</constant></link>">
++<!ENTITY MEDIA-IOC-ENUM-LINKS "<link linkend='media-ioc-enum-links'><constant>MEDIA_IOC_ENUM_LINKS</constant></link>">
+ <!-- Types -->
+ <!ENTITY v4l2-std-id "<link linkend='v4l2-std-id'>v4l2_std_id</link>">
+@@ -188,6 +190,10 @@
+ <!ENTITY v4l2-window "struct&nbsp;<link linkend='v4l2-window'>v4l2_window</link>">
+ <!ENTITY media-device-info "struct&nbsp;<link linkend='media-device-info'>media_device_info</link>">
++<!ENTITY media-entity-desc "struct&nbsp;<link linkend='media-entity-desc'>media_entity_desc</link>">
++<!ENTITY media-links-enum "struct&nbsp;<link linkend='media-links-enum'>media_links_enum</link>">
++<!ENTITY media-pad-desc "struct&nbsp;<link linkend='media-pad-desc'>media_pad_desc</link>">
++<!ENTITY media-link-desc "struct&nbsp;<link linkend='media-link-desc'>media_link_desc</link>">
+ <!-- Error Codes -->
+ <!ENTITY EACCES "<errorcode>EACCES</errorcode> error code">
+@@ -334,6 +340,8 @@
+ <!ENTITY sub-media-close SYSTEM "v4l/media-func-close.xml">
+ <!ENTITY sub-media-ioctl SYSTEM "v4l/media-func-ioctl.xml">
+ <!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml">
++<!ENTITY sub-media-ioc-enum-entities SYSTEM "v4l/media-ioc-enum-entities.xml">
++<!ENTITY sub-media-ioc-enum-links SYSTEM "v4l/media-ioc-enum-links.xml">
+ <!-- Function Reference -->
+ <!ENTITY close SYSTEM "v4l/func-close.xml">
+diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml
+index a46b786..2c4fd2b 100644
+--- a/Documentation/DocBook/v4l/media-controller.xml
++++ b/Documentation/DocBook/v4l/media-controller.xml
+@@ -83,4 +83,6 @@
+   &sub-media-ioctl;
+   <!-- All ioctls go here. -->
+   &sub-media-ioc-device-info;
++  &sub-media-ioc-enum-entities;
++  &sub-media-ioc-enum-links;
+ </appendix>
+diff --git a/Documentation/DocBook/v4l/media-ioc-device-info.xml b/Documentation/DocBook/v4l/media-ioc-device-info.xml
+index 278a312..1f32373 100644
+--- a/Documentation/DocBook/v4l/media-ioc-device-info.xml
++++ b/Documentation/DocBook/v4l/media-ioc-device-info.xml
+@@ -27,7 +27,8 @@
+       <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+-        <para>&fd;</para>
++        <para>File descriptor returned by
++        <link linkend='media-func-open'><function>open()</function></link>.</para>
+       </listitem>
+       </varlistentry>
+       <varlistentry>
+diff --git a/Documentation/DocBook/v4l/media-ioc-enum-entities.xml b/Documentation/DocBook/v4l/media-ioc-enum-entities.xml
+new file mode 100644
+index 0000000..13d0cc4
+--- /dev/null
++++ b/Documentation/DocBook/v4l/media-ioc-enum-entities.xml
+@@ -0,0 +1,308 @@
++<refentry id="media-ioc-enum-entities">
++  <refmeta>
++    <refentrytitle>ioctl MEDIA_IOC_ENUM_ENTITIES</refentrytitle>
++    &manvol;
++  </refmeta>
++
++  <refnamediv>
++    <refname>MEDIA_IOC_ENUM_ENTITIES</refname>
++    <refpurpose>Enumerate entities and their properties</refpurpose>
++  </refnamediv>
++
++  <refsynopsisdiv>
++    <funcsynopsis>
++      <funcprototype>
++      <funcdef>int <function>ioctl</function></funcdef>
++      <paramdef>int <parameter>fd</parameter></paramdef>
++      <paramdef>int <parameter>request</parameter></paramdef>
++      <paramdef>struct media_entity_desc *<parameter>argp</parameter></paramdef>
++      </funcprototype>
++    </funcsynopsis>
++  </refsynopsisdiv>
++
++  <refsect1>
++    <title>Arguments</title>
++
++    <variablelist>
++      <varlistentry>
++      <term><parameter>fd</parameter></term>
++      <listitem>
++        <para>File descriptor returned by
++        <link linkend='media-func-open'><function>open()</function></link>.</para>
++      </listitem>
++      </varlistentry>
++      <varlistentry>
++      <term><parameter>request</parameter></term>
++      <listitem>
++        <para>MEDIA_IOC_ENUM_ENTITIES</para>
++      </listitem>
++      </varlistentry>
++      <varlistentry>
++      <term><parameter>argp</parameter></term>
++      <listitem>
++        <para></para>
++      </listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++
++  <refsect1>
++    <title>Description</title>
++    <para>To query the attributes of an entity, applications set the id field
++    of a &media-entity-desc; structure and call the MEDIA_IOC_ENUM_ENTITIES
++    ioctl with a pointer to this structure. The driver fills the rest of the
++    structure or returns an &EINVAL; when the id is invalid.</para>
++    <para>Entities can be enumerated by or'ing the id with the
++    <constant>MEDIA_ENT_ID_FLAG_NEXT</constant> flag. The driver will return
++    information about the entity with the smallest id strictly larger than the
++    requested one ('next entity'), or the &EINVAL; if there is none.</para>
++    <para>Entity IDs can be non-contiguous. Applications must
++    <emphasis>not</emphasis> try to enumerate entities by calling
++    MEDIA_IOC_ENUM_ENTITIES with increasing id's until they get an error.</para>
++    <para>Two or more entities that share a common non-zero
++    <structfield>group_id</structfield> value are considered as logically
++    grouped. Groups are used to report
++    <itemizedlist>
++      <listitem>ALSA, VBI and video nodes that carry the same media
++      stream</listitem>
++      <listitem>lens and flash controllers associated with a sensor</listitem>
++    </itemizedlist>
++    </para>
++
++    <table pgwide="1" frame="none" id="media-entity-desc">
++      <title>struct <structname>media_entity_desc</structname></title>
++      <tgroup cols="5">
++      <colspec colname="c1" />
++      <colspec colname="c2" />
++      <colspec colname="c3" />
++      <colspec colname="c4" />
++      <colspec colname="c5" />
++      <tbody valign="top">
++        <row>
++          <entry>__u32</entry>
++          <entry><structfield>id</structfield></entry>
++          <entry></entry>
++          <entry></entry>
++          <entry>Entity id, set by the application. When the id is or'ed with
++          <constant>MEDIA_ENT_ID_FLAG_NEXT</constant>, the driver clears the
++          flag and returns the first entity with a larger id.</entry>
++        </row>
++        <row>
++          <entry>char</entry>
++          <entry><structfield>name</structfield>[32]</entry>
++          <entry></entry>
++          <entry></entry>
++          <entry>Entity name as an UTF-8 NULL-terminated string.</entry>
++        </row>
++        <row>
++          <entry>__u32</entry>
++          <entry><structfield>type</structfield></entry>
++          <entry></entry>
++          <entry></entry>
++          <entry>Entity type, see <xref linkend="media-entity-type" /> for details.</entry>
++        </row>
++        <row>
++          <entry>__u32</entry>
++          <entry><structfield>revision</structfield></entry>
++          <entry></entry>
++          <entry></entry>
++          <entry>Entity revision in a driver/hardware specific format.</entry>
++        </row>
++        <row>
++          <entry>__u32</entry>
++          <entry><structfield>flags</structfield></entry>
++          <entry></entry>
++          <entry></entry>
++          <entry>Entity flags, see <xref linkend="media-entity-flag" /> for details.</entry>
++        </row>
++        <row>
++          <entry>__u32</entry>
++          <entry><structfield>group_id</structfield></entry>
++          <entry></entry>
++          <entry></entry>
++          <entry>Entity group ID</entry>
++        </row>
++        <row>
++          <entry>__u16</entry>
++          <entry><structfield>pads</structfield></entry>
++          <entry></entry>
++          <entry></entry>
++          <entry>Number of pads</entry>
++        </row>
++        <row>
++          <entry>__u16</entry>
++          <entry><structfield>links</structfield></entry>
++          <entry></entry>
++          <entry></entry>
++          <entry>Total number of outbound links. Inbound links are not counted
++          in this field.</entry>
++        </row>
++        <row>
++          <entry>union</entry>
++        </row>
++        <row>
++          <entry></entry>
++          <entry>struct</entry>
++          <entry><structfield>v4l</structfield></entry>
++          <entry></entry>
++          <entry>Valid for V4L sub-devices and nodes only.</entry>
++        </row>
++        <row>
++          <entry></entry>
++          <entry></entry>
++          <entry>__u32</entry>
++          <entry><structfield>major</structfield></entry>
++          <entry>V4L device node major number. For V4L sub-devices with no
++          device node, set by the driver to 0.</entry>
++        </row>
++        <row>
++          <entry></entry>
++          <entry></entry>
++          <entry>__u32</entry>
++          <entry><structfield>minor</structfield></entry>
++          <entry>V4L device node minor number. For V4L sub-devices with no
++          device node, set by the driver to 0.</entry>
++        </row>
++        <row>
++          <entry></entry>
++          <entry>struct</entry>
++          <entry><structfield>fb</structfield></entry>
++          <entry></entry>
++          <entry>Valid for frame buffer nodes only.</entry>
++        </row>
++        <row>
++          <entry></entry>
++          <entry></entry>
++          <entry>__u32</entry>
++          <entry><structfield>major</structfield></entry>
++          <entry>Frame buffer device node major number.</entry>
++        </row>
++        <row>
++          <entry></entry>
++          <entry></entry>
++          <entry>__u32</entry>
++          <entry><structfield>minor</structfield></entry>
++          <entry>Frame buffer device node minor number.</entry>
++        </row>
++        <row>
++          <entry></entry>
++          <entry>struct</entry>
++          <entry><structfield>alsa</structfield></entry>
++          <entry></entry>
++          <entry>Valid for ALSA devices only.</entry>
++        </row>
++        <row>
++          <entry></entry>
++          <entry></entry>
++          <entry>__u32</entry>
++          <entry><structfield>card</structfield></entry>
++          <entry>ALSA card number</entry>
++        </row>
++        <row>
++          <entry></entry>
++          <entry></entry>
++          <entry>__u32</entry>
++          <entry><structfield>device</structfield></entry>
++          <entry>ALSA device number</entry>
++        </row>
++        <row>
++          <entry></entry>
++          <entry></entry>
++          <entry>__u32</entry>
++          <entry><structfield>subdevice</structfield></entry>
++          <entry>ALSA sub-device number</entry>
++        </row>
++        <row>
++          <entry></entry>
++          <entry>int</entry>
++          <entry><structfield>dvb</structfield></entry>
++          <entry></entry>
++          <entry>DVB card number</entry>
++        </row>
++        <row>
++          <entry></entry>
++          <entry>__u8</entry>
++          <entry><structfield>raw</structfield>[180]</entry>
++          <entry></entry>
++          <entry></entry>
++        </row>
++      </tbody>
++      </tgroup>
++    </table>
++
++    <table frame="none" pgwide="1" id="media-entity-type">
++      <title>Media entity types</title>
++      <tgroup cols="2">
++        <colspec colname="c1"/>
++        <colspec colname="c2"/>
++      <tbody valign="top">
++        <row>
++          <entry><constant>MEDIA_ENT_T_DEVNODE</constant></entry>
++          <entry>Unknown device node</entry>
++        </row>
++        <row>
++          <entry><constant>MEDIA_ENT_T_DEVNODE_V4L</constant></entry>
++          <entry>V4L video, radio or vbi device node</entry>
++        </row>
++        <row>
++          <entry><constant>MEDIA_ENT_T_DEVNODE_FB</constant></entry>
++          <entry>Frame buffer device node</entry>
++        </row>
++        <row>
++          <entry><constant>MEDIA_ENT_T_DEVNODE_ALSA</constant></entry>
++          <entry>ALSA card</entry>
++        </row>
++        <row>
++          <entry><constant>MEDIA_ENT_T_DEVNODE_DVB</constant></entry>
++          <entry>DVB card</entry>
++        </row>
++        <row>
++          <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV</constant></entry>
++          <entry>Unknown V4L sub-device</entry>
++        </row>
++        <row>
++          <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_SENSOR</constant></entry>
++          <entry>Video sensor</entry>
++        </row>
++        <row>
++          <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_FLASH</constant></entry>
++          <entry>Flash controller</entry>
++        </row>
++        <row>
++          <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_LENS</constant></entry>
++          <entry>Lens controller</entry>
++        </row>
++      </tbody>
++      </tgroup>
++    </table>
++
++    <table frame="none" pgwide="1" id="media-entity-flag">
++      <title>Media entity flags</title>
++      <tgroup cols="2">
++        <colspec colname="c1"/>
++        <colspec colname="c2"/>
++      <tbody valign="top">
++        <row>
++          <entry><constant>MEDIA_ENT_FL_DEFAULT</constant></entry>
++          <entry>Default entity for its type. Used to discover the default
++          audio, VBI and video devices, the default camera sensor, ...</entry>
++        </row>
++      </tbody>
++      </tgroup>
++    </table>
++  </refsect1>
++
++  <refsect1>
++    &return-value;
++
++    <variablelist>
++      <varlistentry>
++      <term><errorcode>EINVAL</errorcode></term>
++      <listitem>
++        <para>The &media-entity-desc; <structfield>id</structfield> references
++        a non-existing entity.</para>
++      </listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++</refentry>
+diff --git a/Documentation/DocBook/v4l/media-ioc-enum-links.xml b/Documentation/DocBook/v4l/media-ioc-enum-links.xml
+new file mode 100644
+index 0000000..daf0360
+--- /dev/null
++++ b/Documentation/DocBook/v4l/media-ioc-enum-links.xml
+@@ -0,0 +1,202 @@
++<refentry id="media-ioc-enum-links">
++  <refmeta>
++    <refentrytitle>ioctl MEDIA_IOC_ENUM_LINKS</refentrytitle>
++    &manvol;
++  </refmeta>
++
++  <refnamediv>
++    <refname>MEDIA_IOC_ENUM_LINKS</refname>
++    <refpurpose>Enumerate all pads and links for a given entity</refpurpose>
++  </refnamediv>
++
++  <refsynopsisdiv>
++    <funcsynopsis>
++      <funcprototype>
++      <funcdef>int <function>ioctl</function></funcdef>
++      <paramdef>int <parameter>fd</parameter></paramdef>
++      <paramdef>int <parameter>request</parameter></paramdef>
++      <paramdef>struct media_links_enum *<parameter>argp</parameter></paramdef>
++      </funcprototype>
++    </funcsynopsis>
++  </refsynopsisdiv>
++
++  <refsect1>
++    <title>Arguments</title>
++
++    <variablelist>
++      <varlistentry>
++      <term><parameter>fd</parameter></term>
++      <listitem>
++        <para>File descriptor returned by
++        <link linkend='media-func-open'><function>open()</function></link>.</para>
++      </listitem>
++      </varlistentry>
++      <varlistentry>
++      <term><parameter>request</parameter></term>
++      <listitem>
++        <para>MEDIA_IOC_ENUM_LINKS</para>
++      </listitem>
++      </varlistentry>
++      <varlistentry>
++      <term><parameter>argp</parameter></term>
++      <listitem>
++        <para></para>
++      </listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++
++  <refsect1>
++    <title>Description</title>
++
++    <para>To enumerate pads and/or links for a given entity, applications set
++    the entity field of a &media-links-enum; structure and initialize the
++    &media-pad-desc; and &media-link-desc; structure arrays pointed by the
++    <structfield>pads</structfield> and <structfield>links</structfield> fields.
++    They then call the MEDIA_IOC_ENUM_LINKS ioctl with a pointer to this
++    structure.</para>
++    <para>If the <structfield>pads</structfield> field is not NULL, the driver
++    fills the <structfield>pads</structfield> array with information about the
++    entity's pads. The array must have enough room to store all the entity's
++    pads. The number of pads can be retrieved with the &MEDIA-IOC-ENUM-ENTITIES;
++    ioctl.</para>
++    <para>If the <structfield>links</structfield> field is not NULL, the driver
++    fills the <structfield>links</structfield> array with information about the
++    entity's outbound links. The array must have enough room to store all the
++    entity's outbound links. The number of outbound links can be retrieved with
++    the &MEDIA-IOC-ENUM-ENTITIES; ioctl.</para>
++    <para>Only forward links that originate at one of the entity's source pads
++    are returned during the enumeration process.</para>
++
++    <table pgwide="1" frame="none" id="media-links-enum">
++      <title>struct <structname>media_links_enum</structname></title>
++      <tgroup cols="3">
++        &cs-str;
++      <tbody valign="top">
++        <row>
++          <entry>__u32</entry>
++          <entry><structfield>entity</structfield></entry>
++          <entry>Entity id, set by the application.</entry>
++        </row>
++        <row>
++          <entry>struct &media-pad-desc;</entry>
++          <entry>*<structfield>pads</structfield></entry>
++          <entry>Pointer to a pads array allocated by the application. Ignored
++          if NULL.</entry>
++        </row>
++        <row>
++          <entry>struct &media-link-desc;</entry>
++          <entry>*<structfield>links</structfield></entry>
++          <entry>Pointer to a links array allocated by the application. Ignored
++          if NULL.</entry>
++        </row>
++      </tbody>
++      </tgroup>
++    </table>
++
++    <table pgwide="1" frame="none" id="media-pad-desc">
++      <title>struct <structname>media_pad_desc</structname></title>
++      <tgroup cols="3">
++        &cs-str;
++      <tbody valign="top">
++        <row>
++          <entry>__u32</entry>
++          <entry><structfield>entity</structfield></entry>
++          <entry>ID of the entity this pad belongs to.</entry>
++        </row>
++        <row>
++          <entry>__u16</entry>
++          <entry><structfield>index</structfield></entry>
++          <entry>0-based pad index.</entry>
++        </row>
++        <row>
++          <entry>__u32</entry>
++          <entry><structfield>flags</structfield></entry>
++          <entry>Pad flags, see <xref linkend="media-pad-flag" /> for more details.</entry>
++        </row>
++      </tbody>
++      </tgroup>
++    </table>
++
++    <table frame="none" pgwide="1" id="media-pad-flag">
++      <title>Media pad flags</title>
++      <tgroup cols="2">
++        <colspec colname="c1"/>
++        <colspec colname="c2"/>
++      <tbody valign="top">
++        <row>
++          <entry><constant>MEDIA_PAD_FL_INPUT</constant></entry>
++          <entry>Input pad, relative to the entity. Input pads sink data and
++          are targets of links.</entry>
++        </row>
++        <row>
++          <entry><constant>MEDIA_PAD_FL_OUTPUT</constant></entry>
++          <entry>Output pad, relative to the entity. Output pads source data
++          and are origins of links.</entry>
++        </row>
++      </tbody>
++      </tgroup>
++    </table>
++
++    <table pgwide="1" frame="none" id="media-link-desc">
++      <title>struct <structname>media_links_enum</structname></title>
++      <tgroup cols="3">
++        &cs-str;
++      <tbody valign="top">
++        <row>
++          <entry>struct &media-pad-desc;</entry>
++          <entry><structfield>source</structfield></entry>
++          <entry>Pad at the origin of this link.</entry>
++        </row>
++        <row>
++          <entry>struct &media-pad-desc;</entry>
++          <entry><structfield>sink</structfield></entry>
++          <entry>Pad at the target of this link.</entry>
++        </row>
++        <row>
++          <entry>__u32</entry>
++          <entry><structfield>flags</structfield></entry>
++          <entry>Link flags, see <xref linkend="media-link-flag" /> for more details.</entry>
++        </row>
++      </tbody>
++      </tgroup>
++    </table>
++
++    <table frame="none" pgwide="1" id="media-link-flag">
++      <title>Media link flags</title>
++      <tgroup cols="2">
++        <colspec colname="c1"/>
++        <colspec colname="c2"/>
++      <tbody valign="top">
++        <row>
++          <entry><constant>MEDIA_LNK_FL_ENABLED</constant></entry>
++          <entry>The link is enabled and can be used to transfer media data.
++          When two or more links target a sink pad, only one of them can be
++          enabled at a time.</entry>
++        </row>
++        <row>
++          <entry><constant>MEDIA_LNK_FL_IMMUTABLE</constant></entry>
++          <entry>The link enabled state can't be modified at runtime. An
++          immutable link is always enabled.</entry>
++        </row>
++      </tbody>
++      </tgroup>
++    </table>
++    <para>One and only one of <constant>MEDIA_PAD_FL_INPUT</constant> and
++    <constant>MEDIA_PAD_FL_OUTPUT</constant> must be set for every pad.</para>
++  </refsect1>
++
++  <refsect1>
++    &return-value;
++
++    <variablelist>
++      <varlistentry>
++      <term><errorcode>EINVAL</errorcode></term>
++      <listitem>
++        <para>The &media-links-enum; <structfield>id</structfield> references
++        a non-existing entity.</para>
++      </listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++</refentry>
+diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
+index 5c745be..1f46acb 100644
+--- a/drivers/media/media-device.c
++++ b/drivers/media/media-device.c
+@@ -61,6 +61,117 @@ static int media_device_get_info(struct media_device *dev,
+       return copy_to_user(__info, &info, sizeof(*__info));
+ }
++static struct media_entity *find_entity(struct media_device *mdev, u32 id)
++{
++      struct media_entity *entity;
++      int next = id & MEDIA_ENT_ID_FLAG_NEXT;
++
++      id &= ~MEDIA_ENT_ID_FLAG_NEXT;
++
++      spin_lock(&mdev->lock);
++
++      media_device_for_each_entity(entity, mdev) {
++              if ((entity->id == id && !next) ||
++                  (entity->id > id && next)) {
++                      spin_unlock(&mdev->lock);
++                      return entity;
++              }
++      }
++
++      spin_unlock(&mdev->lock);
++
++      return NULL;
++}
++
++static long media_device_enum_entities(struct media_device *mdev,
++                                     struct media_entity_desc __user *uent)
++{
++      struct media_entity *ent;
++      struct media_entity_desc u_ent;
++
++      if (copy_from_user(&u_ent.id, &uent->id, sizeof(u_ent.id)))
++              return -EFAULT;
++
++      ent = find_entity(mdev, u_ent.id);
++
++      if (ent == NULL)
++              return -EINVAL;
++
++      u_ent.id = ent->id;
++      u_ent.name[0] = '\0';
++      if (ent->name)
++              strlcpy(u_ent.name, ent->name, sizeof(u_ent.name));
++      u_ent.type = ent->type;
++      u_ent.revision = ent->revision;
++      u_ent.flags = ent->flags;
++      u_ent.group_id = ent->group_id;
++      u_ent.pads = ent->num_pads;
++      u_ent.links = ent->num_links - ent->num_backlinks;
++      u_ent.v4l.major = ent->v4l.major;
++      u_ent.v4l.minor = ent->v4l.minor;
++      if (copy_to_user(uent, &u_ent, sizeof(u_ent)))
++              return -EFAULT;
++      return 0;
++}
++
++static void media_device_kpad_to_upad(const struct media_pad *kpad,
++                                    struct media_pad_desc *upad)
++{
++      upad->entity = kpad->entity->id;
++      upad->index = kpad->index;
++      upad->flags = kpad->flags;
++}
++
++static long media_device_enum_links(struct media_device *mdev,
++                                  struct media_links_enum __user *ulinks)
++{
++      struct media_entity *entity;
++      struct media_links_enum links;
++
++      if (copy_from_user(&links, ulinks, sizeof(links)))
++              return -EFAULT;
++
++      entity = find_entity(mdev, links.entity);
++      if (entity == NULL)
++              return -EINVAL;
++
++      if (links.pads) {
++              unsigned int p;
++
++              for (p = 0; p < entity->num_pads; p++) {
++                      struct media_pad_desc pad;
++                      media_device_kpad_to_upad(&entity->pads[p], &pad);
++                      if (copy_to_user(&links.pads[p], &pad, sizeof(pad)))
++                              return -EFAULT;
++              }
++      }
++
++      if (links.links) {
++              struct media_link_desc __user *ulink;
++              unsigned int l;
++
++              for (l = 0, ulink = links.links; l < entity->num_links; l++) {
++                      struct media_link_desc link;
++
++                      /* Ignore backlinks. */
++                      if (entity->links[l].source->entity != entity)
++                              continue;
++
++                      media_device_kpad_to_upad(entity->links[l].source,
++                                                &link.source);
++                      media_device_kpad_to_upad(entity->links[l].sink,
++                                                &link.sink);
++                      link.flags = entity->links[l].flags;
++                      if (copy_to_user(ulink, &link, sizeof(*ulink)))
++                              return -EFAULT;
++                      ulink++;
++              }
++      }
++      if (copy_to_user(ulinks, &links, sizeof(*ulinks)))
++              return -EFAULT;
++      return 0;
++}
++
+ static long media_device_ioctl(struct file *filp, unsigned int cmd,
+                              unsigned long arg)
+ {
+@@ -74,6 +185,18 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
+                               (struct media_device_info __user *)arg);
+               break;
++      case MEDIA_IOC_ENUM_ENTITIES:
++              ret = media_device_enum_entities(dev,
++                              (struct media_entity_desc __user *)arg);
++              break;
++
++      case MEDIA_IOC_ENUM_LINKS:
++              mutex_lock(&dev->graph_mutex);
++              ret = media_device_enum_links(dev,
++                              (struct media_links_enum __user *)arg);
++              mutex_unlock(&dev->graph_mutex);
++              break;
++
+       default:
+               ret = -ENOIOCTLCMD;
+       }
+diff --git a/include/linux/media.h b/include/linux/media.h
+index 4c52f08..64c0313 100644
+--- a/include/linux/media.h
++++ b/include/linux/media.h
+@@ -40,6 +40,91 @@ struct media_device_info {
+       __u32 reserved[31];
+ };
++#define MEDIA_ENT_ID_FLAG_NEXT                (1 << 31)
++
++#define MEDIA_ENT_TYPE_SHIFT          16
++#define MEDIA_ENT_TYPE_MASK           0x00ff0000
++#define MEDIA_ENT_SUBTYPE_MASK                0x0000ffff
++
++#define MEDIA_ENT_T_DEVNODE           (1 << MEDIA_ENT_TYPE_SHIFT)
++#define MEDIA_ENT_T_DEVNODE_V4L               (MEDIA_ENT_T_DEVNODE + 1)
++#define MEDIA_ENT_T_DEVNODE_FB                (MEDIA_ENT_T_DEVNODE + 2)
++#define MEDIA_ENT_T_DEVNODE_ALSA      (MEDIA_ENT_T_DEVNODE + 3)
++#define MEDIA_ENT_T_DEVNODE_DVB               (MEDIA_ENT_T_DEVNODE + 4)
++
++#define MEDIA_ENT_T_V4L2_SUBDEV               (2 << MEDIA_ENT_TYPE_SHIFT)
++#define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR        (MEDIA_ENT_T_V4L2_SUBDEV + 1)
++#define MEDIA_ENT_T_V4L2_SUBDEV_FLASH (MEDIA_ENT_T_V4L2_SUBDEV + 2)
++#define MEDIA_ENT_T_V4L2_SUBDEV_LENS  (MEDIA_ENT_T_V4L2_SUBDEV + 3)
++
++#define MEDIA_ENT_FL_DEFAULT          (1 << 0)
++
++struct media_entity_desc {
++      __u32 id;
++      char name[32];
++      __u32 type;
++      __u32 revision;
++      __u32 flags;
++      __u32 group_id;
++      __u16 pads;
++      __u16 links;
++
++      __u32 reserved[4];
++
++      union {
++              /* Node specifications */
++              struct {
++                      __u32 major;
++                      __u32 minor;
++              } v4l;
++              struct {
++                      __u32 major;
++                      __u32 minor;
++              } fb;
++              struct {
++                      __u32 card;
++                      __u32 device;
++                      __u32 subdevice;
++              } alsa;
++              int dvb;
++
++              /* Sub-device specifications */
++              /* Nothing needed yet */
++              __u8 raw[184];
++      };
++};
++
++#define MEDIA_PAD_FL_INPUT            (1 << 0)
++#define MEDIA_PAD_FL_OUTPUT           (1 << 1)
++
++struct media_pad_desc {
++      __u32 entity;           /* entity ID */
++      __u16 index;            /* pad index */
++      __u32 flags;            /* pad flags */
++      __u32 reserved[2];
++};
++
++#define MEDIA_LNK_FL_ENABLED          (1 << 0)
++#define MEDIA_LNK_FL_IMMUTABLE                (1 << 1)
++
++struct media_link_desc {
++      struct media_pad_desc source;
++      struct media_pad_desc sink;
++      __u32 flags;
++      __u32 reserved[2];
++};
++
++struct media_links_enum {
++      __u32 entity;
++      /* Should have enough room for pads elements */
++      struct media_pad_desc __user *pads;
++      /* Should have enough room for links elements */
++      struct media_link_desc __user *links;
++      __u32 reserved[4];
++};
++
+ #define MEDIA_IOC_DEVICE_INFO         _IOWR('M', 1, struct media_device_info)
++#define MEDIA_IOC_ENUM_ENTITIES               _IOWR('M', 2, struct media_entity_desc)
++#define MEDIA_IOC_ENUM_LINKS          _IOWR('M', 3, struct media_links_enum)
+ #endif /* __LINUX_MEDIA_H */
+diff --git a/include/media/media-entity.h b/include/media/media-entity.h
+index 114541a..0954490 100644
+--- a/include/media/media-entity.h
++++ b/include/media/media-entity.h
+@@ -24,29 +24,7 @@
+ #define _MEDIA_ENTITY_H
+ #include <linux/list.h>
+-
+-#define MEDIA_ENT_TYPE_SHIFT          16
+-#define MEDIA_ENT_TYPE_MASK           0x00ff0000
+-#define MEDIA_ENT_SUBTYPE_MASK                0x0000ffff
+-
+-#define MEDIA_ENT_T_DEVNODE           (1 << MEDIA_ENTITY_TYPE_SHIFT)
+-#define MEDIA_ENT_T_DEVNODE_V4L               (MEDIA_ENTITY_T_DEVNODE + 1)
+-#define MEDIA_ENT_T_DEVNODE_FB                (MEDIA_ENTITY_T_DEVNODE + 2)
+-#define MEDIA_ENT_T_DEVNODE_ALSA      (MEDIA_ENTITY_T_DEVNODE + 3)
+-#define MEDIA_ENT_T_DEVNODE_DVB               (MEDIA_ENTITY_T_DEVNODE + 4)
+-
+-#define MEDIA_ENT_T_V4L2_SUBDEV               (2 << MEDIA_ENTITY_TYPE_SHIFT)
+-#define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR        (MEDIA_ENTITY_T_V4L2_SUBDEV + 1)
+-#define MEDIA_ENT_T_V4L2_SUBDEV_FLASH (MEDIA_ENTITY_T_V4L2_SUBDEV + 2)
+-#define MEDIA_ENT_T_V4L2_SUBDEV_LENS  (MEDIA_ENTITY_T_V4L2_SUBDEV + 3)
+-
+-#define MEDIA_ENT_FL_DEFAULT          (1 << 0)
+-
+-#define MEDIA_LNK_FL_ENABLED          (1 << 0)
+-#define MEDIA_LNK_FL_IMMUTABLE                (1 << 1)
+-
+-#define MEDIA_PAD_FL_INPUT            (1 << 0)
+-#define MEDIA_PAD_FL_OUTPUT           (1 << 1)
++#include <linux/media.h>
+ struct media_link {
+       struct media_pad *source;       /* Source pad */
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0015-media-Links-setup.patch b/recipes-bsp/linux/linux-omap/media/0015-media-Links-setup.patch
new file mode 100644 (file)
index 0000000..4ea3974
--- /dev/null
@@ -0,0 +1,517 @@
+From 9991c219079532183cc33f16064f86680b80237c Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:40:03 +0100
+Subject: [PATCH 15/43] media: Links setup
+
+Create the following ioctl and implement it at the media device level to
+setup links.
+
+- MEDIA_IOC_SETUP_LINK: Modify the properties of a given link
+
+The only property that can currently be modified is the ENABLED link
+flag to enable/disable a link. Links marked with the IMMUTABLE link flag
+can not be enabled or disabled.
+
+Enabling or disabling a link has effects on entities' use count. Those
+changes are automatically propagated through the graph.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+---
+ Documentation/DocBook/media-entities.tmpl          |    2 +
+ Documentation/DocBook/v4l/media-controller.xml     |    1 +
+ Documentation/DocBook/v4l/media-ioc-setup-link.xml |   90 +++++++++++
+ Documentation/media-framework.txt                  |   42 ++++++
+ drivers/media/media-device.c                       |   45 ++++++
+ drivers/media/media-entity.c                       |  155 ++++++++++++++++++++
+ include/linux/media.h                              |    1 +
+ include/media/media-device.h                       |    3 +
+ include/media/media-entity.h                       |   17 ++
+ 9 files changed, 356 insertions(+), 0 deletions(-)
+ create mode 100644 Documentation/DocBook/v4l/media-ioc-setup-link.xml
+
+diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
+index 6e7dae4..679c585 100644
+--- a/Documentation/DocBook/media-entities.tmpl
++++ b/Documentation/DocBook/media-entities.tmpl
+@@ -94,6 +94,7 @@
+ <!ENTITY MEDIA-IOC-DEVICE-INFO "<link linkend='media-ioc-device-info'><constant>MEDIA_IOC_DEVICE_INFO</constant></link>">
+ <!ENTITY MEDIA-IOC-ENUM-ENTITIES "<link linkend='media-ioc-enum-entities'><constant>MEDIA_IOC_ENUM_ENTITIES</constant></link>">
+ <!ENTITY MEDIA-IOC-ENUM-LINKS "<link linkend='media-ioc-enum-links'><constant>MEDIA_IOC_ENUM_LINKS</constant></link>">
++<!ENTITY MEDIA-IOC-SETUP-LINK "<link linkend='media-ioc-setup-link'><constant>MEDIA_IOC_SETUP_LINK</constant></link>">
+ <!-- Types -->
+ <!ENTITY v4l2-std-id "<link linkend='v4l2-std-id'>v4l2_std_id</link>">
+@@ -342,6 +343,7 @@
+ <!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml">
+ <!ENTITY sub-media-ioc-enum-entities SYSTEM "v4l/media-ioc-enum-entities.xml">
+ <!ENTITY sub-media-ioc-enum-links SYSTEM "v4l/media-ioc-enum-links.xml">
++<!ENTITY sub-media-ioc-setup-link SYSTEM "v4l/media-ioc-setup-link.xml">
+ <!-- Function Reference -->
+ <!ENTITY close SYSTEM "v4l/func-close.xml">
+diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml
+index 2c4fd2b..2dc25e1 100644
+--- a/Documentation/DocBook/v4l/media-controller.xml
++++ b/Documentation/DocBook/v4l/media-controller.xml
+@@ -85,4 +85,5 @@
+   &sub-media-ioc-device-info;
+   &sub-media-ioc-enum-entities;
+   &sub-media-ioc-enum-links;
++  &sub-media-ioc-setup-link;
+ </appendix>
+diff --git a/Documentation/DocBook/v4l/media-ioc-setup-link.xml b/Documentation/DocBook/v4l/media-ioc-setup-link.xml
+new file mode 100644
+index 0000000..09ab3d2
+--- /dev/null
++++ b/Documentation/DocBook/v4l/media-ioc-setup-link.xml
+@@ -0,0 +1,90 @@
++<refentry id="media-ioc-setup-link">
++  <refmeta>
++    <refentrytitle>ioctl MEDIA_IOC_SETUP_LINK</refentrytitle>
++    &manvol;
++  </refmeta>
++
++  <refnamediv>
++    <refname>MEDIA_IOC_SETUP_LINK</refname>
++    <refpurpose>Modify the properties of a link</refpurpose>
++  </refnamediv>
++
++  <refsynopsisdiv>
++    <funcsynopsis>
++      <funcprototype>
++      <funcdef>int <function>ioctl</function></funcdef>
++      <paramdef>int <parameter>fd</parameter></paramdef>
++      <paramdef>int <parameter>request</parameter></paramdef>
++      <paramdef>struct media_link_desc *<parameter>argp</parameter></paramdef>
++      </funcprototype>
++    </funcsynopsis>
++  </refsynopsisdiv>
++
++  <refsect1>
++    <title>Arguments</title>
++
++    <variablelist>
++      <varlistentry>
++      <term><parameter>fd</parameter></term>
++      <listitem>
++        <para>File descriptor returned by
++        <link linkend='media-func-open'><function>open()</function></link>.</para>
++      </listitem>
++      </varlistentry>
++      <varlistentry>
++      <term><parameter>request</parameter></term>
++      <listitem>
++        <para>MEDIA_IOC_ENUM_LINKS</para>
++      </listitem>
++      </varlistentry>
++      <varlistentry>
++      <term><parameter>argp</parameter></term>
++      <listitem>
++        <para></para>
++      </listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++
++  <refsect1>
++    <title>Description</title>
++
++    <para>To change link properties applications fill a &media-link-desc; with
++    link identification information (source and sink pad) and the new requested
++    link flags. They then call the MEDIA_IOC_SETUP_LINK ioctl with a pointer to
++    that structure.</para>
++    <para>The only configurable property is the <constant>ENABLED</constant>
++    link flag to enable/disable a link. Links marked with the
++    <constant>IMMUTABLE</constant> link flag can not be enabled or disabled.
++    </para>
++    <para>Link configuration has no side effect on other links. If an enabled
++    link at the sink pad prevents the link from being enabled, the driver
++    returns with an &EBUSY;.</para>
++    <para>If the specified link can't be found the driver returns with an
++    &EINVAL;.</para>
++  </refsect1>
++
++  <refsect1>
++    &return-value;
++
++    <variablelist>
++      <varlistentry>
++      <term><errorcode>EBUSY</errorcode></term>
++      <listitem>
++        <para>The link properties can't be changed because the link is
++        currently busy. This can be caused, for instance, by an active media
++        stream (audio or video) on the link. The ioctl shouldn't be retried if
++        no other action is performed before to fix the problem.</para>
++      </listitem>
++      </varlistentry>
++      <varlistentry>
++      <term><errorcode>EINVAL</errorcode></term>
++      <listitem>
++        <para>The &media-link-desc; references a non-existing link, or the
++        link is immutable and an attempt to modify its configuration was made.
++        </para>
++      </listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++</refentry>
+diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
+index 9017a41..634845e 100644
+--- a/Documentation/media-framework.txt
++++ b/Documentation/media-framework.txt
+@@ -259,6 +259,16 @@ When the graph traversal is complete the function will return NULL.
+ Graph traversal can be interrupted at any moment. No cleanup function call is
+ required and the graph structure can be freed normally.
++Helper functions can be used to find a link between two given pads, or a pad
++connected to another pad through an enabled link
++
++      media_entity_find_link(struct media_pad *source,
++                             struct media_pad *sink);
++
++      media_entity_remote_source(struct media_pad *pad);
++
++Refer to the kerneldoc documentation for more information.
++
+ Use count and power handling
+ ----------------------------
+@@ -271,3 +281,35 @@ track the number of users of every entity for power management needs.
+ The use_count field is owned by media drivers and must not be touched by entity
+ drivers. Access to the field must be protected by the media device graph_mutex
+ lock.
++
++
++Links setup
++-----------
++
++Link properties can be modified at runtime by calling
++
++      media_entity_setup_link(struct media_link *link, u32 flags);
++
++The flags argument contains the requested new link flags.
++
++The only configurable property is the ENABLED link flag to enable/disable a
++link. Links marked with the IMMUTABLE link flag can not be enabled or disabled.
++
++When a link is enabled or disabled, the media framework calls the
++link_setup operation for the two entities at the source and sink of the link,
++in that order. If the second link_setup call fails, another link_setup call is
++made on the first entity to restore the original link flags.
++
++Media device drivers can be notified of link setup operations by setting the
++media_device::link_notify pointer to a callback function. If provided, the
++notification callback will be called before enabling and after disabling
++links.
++
++Entity drivers must implement the link_setup operation if any of their links
++is non-immutable. The operation must either configure the hardware or store
++the configuration information to be applied later.
++
++Link configuration must not have any side effect on other links. If an enabled
++link at a sink pad prevents another link at the same pad from being disabled,
++the link_setup operation must return -EBUSY and can't implicitly disable the
++first enabled link.
+diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
+index 1f46acb..719deba 100644
+--- a/drivers/media/media-device.c
++++ b/drivers/media/media-device.c
+@@ -172,6 +172,44 @@ static long media_device_enum_links(struct media_device *mdev,
+       return 0;
+ }
++static long media_device_setup_link(struct media_device *mdev,
++                                  struct media_link_desc __user *_ulink)
++{
++      struct media_link *link = NULL;
++      struct media_link_desc ulink;
++      struct media_entity *source;
++      struct media_entity *sink;
++      int ret;
++
++      if (copy_from_user(&ulink, _ulink, sizeof(ulink)))
++              return -EFAULT;
++
++      /* Find the source and sink entities and link.
++       */
++      source = find_entity(mdev, ulink.source.entity);
++      sink = find_entity(mdev, ulink.sink.entity);
++
++      if (source == NULL || sink == NULL)
++              return -EINVAL;
++
++      if (ulink.source.index >= source->num_pads ||
++          ulink.sink.index >= sink->num_pads)
++              return -EINVAL;
++
++      link = media_entity_find_link(&source->pads[ulink.source.index],
++                                    &sink->pads[ulink.sink.index]);
++      if (link == NULL)
++              return -EINVAL;
++
++      /* Setup the link on both entities. */
++      ret = __media_entity_setup_link(link, ulink.flags);
++
++      if (copy_to_user(_ulink, &ulink, sizeof(ulink)))
++              return -EFAULT;
++
++      return ret;
++}
++
+ static long media_device_ioctl(struct file *filp, unsigned int cmd,
+                              unsigned long arg)
+ {
+@@ -197,6 +235,13 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
+               mutex_unlock(&dev->graph_mutex);
+               break;
++      case MEDIA_IOC_SETUP_LINK:
++              mutex_lock(&dev->graph_mutex);
++              ret = media_device_setup_link(dev,
++                              (struct media_link_desc __user *)arg);
++              mutex_unlock(&dev->graph_mutex);
++              break;
++
+       default:
+               ret = -ENOIOCTLCMD;
+       }
+diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
+index fe6bfd2..d703ce8 100644
+--- a/drivers/media/media-entity.c
++++ b/drivers/media/media-entity.c
+@@ -306,3 +306,158 @@ media_entity_create_link(struct media_entity *source, u16 source_pad,
+       return 0;
+ }
+ EXPORT_SYMBOL_GPL(media_entity_create_link);
++
++static int __media_entity_setup_link_notify(struct media_link *link, u32 flags)
++{
++      const u32 mask = MEDIA_LNK_FL_ENABLED;
++      int ret;
++
++      /* Notify both entities. */
++      ret = media_entity_call(link->source->entity, link_setup,
++                              link->source, link->sink, flags);
++      if (ret < 0 && ret != -ENOIOCTLCMD)
++              return ret;
++
++      ret = media_entity_call(link->sink->entity, link_setup,
++                              link->sink, link->source, flags);
++      if (ret < 0 && ret != -ENOIOCTLCMD) {
++              media_entity_call(link->source->entity, link_setup,
++                                link->source, link->sink, link->flags);
++              return ret;
++      }
++
++      link->flags = (link->flags & ~mask) | (flags & mask);
++      link->reverse->flags = link->flags;
++
++      return 0;
++}
++
++/**
++ * __media_entity_setup_link - Configure a media link
++ * @link: The link being configured
++ * @flags: Link configuration flags
++ *
++ * The bulk of link setup is handled by the two entities connected through the
++ * link. This function notifies both entities of the link configuration change.
++ *
++ * If the link is immutable or if the current and new configuration are
++ * identical, return immediately.
++ *
++ * The user is expected to hold link->source->parent->mutex. If not,
++ * media_entity_setup_link() should be used instead.
++ */
++int __media_entity_setup_link(struct media_link *link, u32 flags)
++{
++      struct media_device *mdev;
++      struct media_entity *source, *sink;
++      int ret = -EBUSY;
++
++      if (link == NULL)
++              return -EINVAL;
++
++      if (link->flags & MEDIA_LNK_FL_IMMUTABLE)
++              return link->flags == flags ? 0 : -EINVAL;
++
++      if (link->flags == flags)
++              return 0;
++
++      source = link->source->entity;
++      sink = link->sink->entity;
++
++      mdev = source->parent;
++
++      if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) {
++              ret = mdev->link_notify(link->source, link->sink,
++                                      MEDIA_LNK_FL_ENABLED);
++              if (ret < 0)
++                      return ret;
++      }
++
++      ret = __media_entity_setup_link_notify(link, flags);
++      if (ret < 0)
++              goto err;
++
++      if (!(flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify)
++              mdev->link_notify(link->source, link->sink, 0);
++
++      return 0;
++
++err:
++      if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify)
++              mdev->link_notify(link->source, link->sink, 0);
++
++      return ret;
++}
++
++int media_entity_setup_link(struct media_link *link, u32 flags)
++{
++      int ret;
++
++      mutex_lock(&link->source->entity->parent->graph_mutex);
++      ret = __media_entity_setup_link(link, flags);
++      mutex_unlock(&link->source->entity->parent->graph_mutex);
++
++      return ret;
++}
++EXPORT_SYMBOL_GPL(media_entity_setup_link);
++
++/**
++ * media_entity_find_link - Find a link between two pads
++ * @source: Source pad
++ * @sink: Sink pad
++ *
++ * Return a pointer to the link between the two entities. If no such link
++ * exists, return NULL.
++ */
++struct media_link *
++media_entity_find_link(struct media_pad *source, struct media_pad *sink)
++{
++      struct media_link *link;
++      unsigned int i;
++
++      for (i = 0; i < source->entity->num_links; ++i) {
++              link = &source->entity->links[i];
++
++              if (link->source->entity == source->entity &&
++                  link->source->index == source->index &&
++                  link->sink->entity == sink->entity &&
++                  link->sink->index == sink->index)
++                      return link;
++      }
++
++      return NULL;
++}
++EXPORT_SYMBOL_GPL(media_entity_find_link);
++
++/**
++ * media_entity_remote_source - Find the source pad at the remote end of a link
++ * @pad: Sink pad at the local end of the link
++ *
++ * Search for a remote source pad connected to the given sink pad by iterating
++ * over all links originating or terminating at that pad until an enabled link
++ * is found.
++ *
++ * Return a pointer to the pad at the remote end of the first found enabled
++ * link, or NULL if no enabled link has been found.
++ */
++struct media_pad *media_entity_remote_source(struct media_pad *pad)
++{
++      unsigned int i;
++
++      for (i = 0; i < pad->entity->num_links; i++) {
++              struct media_link *link = &pad->entity->links[i];
++
++              if (!(link->flags & MEDIA_LNK_FL_ENABLED))
++                      continue;
++
++              if (link->source == pad)
++                      return link->sink;
++
++              if (link->sink == pad)
++                      return link->source;
++      }
++
++      return NULL;
++
++}
++EXPORT_SYMBOL_GPL(media_entity_remote_source);
+diff --git a/include/linux/media.h b/include/linux/media.h
+index 64c0313..2f67ed2 100644
+--- a/include/linux/media.h
++++ b/include/linux/media.h
+@@ -126,5 +126,6 @@ struct media_links_enum {
+ #define MEDIA_IOC_DEVICE_INFO         _IOWR('M', 1, struct media_device_info)
+ #define MEDIA_IOC_ENUM_ENTITIES               _IOWR('M', 2, struct media_entity_desc)
+ #define MEDIA_IOC_ENUM_LINKS          _IOWR('M', 3, struct media_links_enum)
++#define MEDIA_IOC_SETUP_LINK          _IOWR('M', 4, struct media_link_desc)
+ #endif /* __LINUX_MEDIA_H */
+diff --git a/include/media/media-device.h b/include/media/media-device.h
+index 260d59c..ad93e66 100644
+--- a/include/media/media-device.h
++++ b/include/media/media-device.h
+@@ -73,6 +73,9 @@ struct media_device {
+       spinlock_t lock;
+       /* Serializes graph operations. */
+       struct mutex graph_mutex;
++
++      int (*link_notify)(struct media_pad *source,
++                         struct media_pad *sink, u32 flags);
+ };
+ /* media_devnode to media_device */
+diff --git a/include/media/media-entity.h b/include/media/media-entity.h
+index 0954490..60fc7bd 100644
+--- a/include/media/media-entity.h
++++ b/include/media/media-entity.h
+@@ -39,6 +39,12 @@ struct media_pad {
+       unsigned long flags;            /* Pad flags (MEDIA_PAD_FL_*) */
+ };
++struct media_entity_operations {
++      int (*link_setup)(struct media_entity *entity,
++                        const struct media_pad *local,
++                        const struct media_pad *remote, u32 flags);
++};
++
+ struct media_entity {
+       struct list_head list;
+       struct media_device *parent;    /* Media device this entity belongs to*/
+@@ -59,6 +65,8 @@ struct media_entity {
+       struct media_pad *pads;         /* Pads array (num_pads elements) */
+       struct media_link *links;       /* Links array (max_links elements)*/
++      const struct media_entity_operations *ops;      /* Entity operations */
++
+       int use_count;                  /* Use count for the entity. */
+       union {
+@@ -108,6 +116,11 @@ int media_entity_init(struct media_entity *entity, u16 num_pads,
+ void media_entity_cleanup(struct media_entity *entity);
+ int media_entity_create_link(struct media_entity *source, u16 source_pad,
+               struct media_entity *sink, u16 sink_pad, u32 flags);
++int __media_entity_setup_link(struct media_link *link, u32 flags);
++int media_entity_setup_link(struct media_link *link, u32 flags);
++struct media_link *media_entity_find_link(struct media_pad *source,
++              struct media_pad *sink);
++struct media_pad *media_entity_remote_source(struct media_pad *pad);
+ struct media_entity *media_entity_get(struct media_entity *entity);
+ void media_entity_put(struct media_entity *entity);
+@@ -117,4 +130,8 @@ void media_entity_graph_walk_start(struct media_entity_graph *graph,
+ struct media_entity *
+ media_entity_graph_walk_next(struct media_entity_graph *graph);
++#define media_entity_call(entity, operation, args...)                 \
++      (((entity)->ops && (entity)->ops->operation) ?                  \
++       (entity)->ops->operation((entity) , ##args) : -ENOIOCTLCMD)
++
+ #endif
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0016-media-Pipelines-and-media-streams.patch b/recipes-bsp/linux/linux-omap/media/0016-media-Pipelines-and-media-streams.patch
new file mode 100644 (file)
index 0000000..969162f
--- /dev/null
@@ -0,0 +1,259 @@
+From 4e07e9ada1b3baaec6d4948eccf3c0499e3228df Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 25 Aug 2010 15:00:41 +0300
+Subject: [PATCH 16/43] media: Pipelines and media streams
+
+Drivers often need to associate pipeline objects to entities, and to
+take stream state into account when configuring entities and links. The
+pipeline API helps drivers manage that information.
+
+When starting streaming, drivers call media_entity_pipeline_start(). The
+function marks all entities connected to the given entity through
+enabled links, either directly or indirectly, as streaming. Similarly,
+when stopping the stream, drivers call media_entity_pipeline_stop().
+
+The media_entity_pipeline_start() function takes a pointer to a media
+pipeline and stores it in every entity in the graph. Drivers should
+embed the media_pipeline structure in higher-level pipeline structures
+and can then access the pipeline through the media_entity structure.
+
+Link configuration will fail with -EBUSY by default if either end of the
+link is a streaming entity, unless the link is marked with the
+MEDIA_LNK_FL_DYNAMIC flag.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ Documentation/DocBook/v4l/media-ioc-enum-links.xml |    5 ++
+ Documentation/DocBook/v4l/media-ioc-setup-link.xml |    3 +
+ Documentation/media-framework.txt                  |   38 ++++++++++
+ drivers/media/media-entity.c                       |   73 ++++++++++++++++++++
+ include/linux/media.h                              |    1 +
+ include/media/media-entity.h                       |   10 +++
+ 6 files changed, 130 insertions(+), 0 deletions(-)
+
+diff --git a/Documentation/DocBook/v4l/media-ioc-enum-links.xml b/Documentation/DocBook/v4l/media-ioc-enum-links.xml
+index daf0360..b204bfb 100644
+--- a/Documentation/DocBook/v4l/media-ioc-enum-links.xml
++++ b/Documentation/DocBook/v4l/media-ioc-enum-links.xml
+@@ -179,6 +179,11 @@
+           <entry>The link enabled state can't be modified at runtime. An
+           immutable link is always enabled.</entry>
+         </row>
++        <row>
++          <entry><constant>MEDIA_LNK_FL_DYNAMIC</constant></entry>
++          <entry>The link enabled state can be modified during streaming. This
++          flag is set by drivers and is read-only for applications.</entry>
++        </row>
+       </tbody>
+       </tgroup>
+     </table>
+diff --git a/Documentation/DocBook/v4l/media-ioc-setup-link.xml b/Documentation/DocBook/v4l/media-ioc-setup-link.xml
+index 09ab3d2..2331e76 100644
+--- a/Documentation/DocBook/v4l/media-ioc-setup-link.xml
++++ b/Documentation/DocBook/v4l/media-ioc-setup-link.xml
+@@ -60,6 +60,9 @@
+     <para>Link configuration has no side effect on other links. If an enabled
+     link at the sink pad prevents the link from being enabled, the driver
+     returns with an &EBUSY;.</para>
++    <para>Only links marked with the <constant>DYNAMIC</constant> link flag can
++    be enabled/disabled while streaming media data. Attempting to enable or
++    disable a streaming non-dynamic link will return an &EBUSY;.</para>
+     <para>If the specified link can't be found the driver returns with an
+     &EINVAL;.</para>
+   </refsect1>
+diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
+index 634845e..435d0c4 100644
+--- a/Documentation/media-framework.txt
++++ b/Documentation/media-framework.txt
+@@ -313,3 +313,41 @@ Link configuration must not have any side effect on other links. If an enabled
+ link at a sink pad prevents another link at the same pad from being disabled,
+ the link_setup operation must return -EBUSY and can't implicitly disable the
+ first enabled link.
++
++
++Pipelines and media streams
++---------------------------
++
++When starting streaming, drivers must notify all entities in the pipeline to
++prevent link states from being modified during streaming by calling
++
++      media_entity_pipeline_start(struct media_entity *entity,
++                                  struct media_pipeline *pipe);
++
++The function will mark all entities connected to the given entity through
++enabled links, either directly or indirectly, as streaming.
++
++The media_pipeline instance pointed to by the pipe argument will be stored in
++every entity in the pipeline. Drivers should embed the media_pipeline structure
++in higher-level pipeline structures and can then access the pipeline through
++the media_entity pipe field.
++
++Calls to media_entity_pipeline_start() can be nested. The pipeline pointer must
++be identical for all nested calls to the function.
++
++When stopping the stream, drivers must notify the entities with
++
++      media_entity_pipeline_stop(struct media_entity *entity);
++
++If multiple calls to media_entity_pipeline_start() have been made the same
++number of media_entity_pipeline_stop() calls are required to stop streaming. The
++media_entity pipe field is reset to NULL on the last nested stop call.
++
++Link configuration will fail with -EBUSY by default if either end of the link is
++a streaming entity. Links that can be modified while streaming must be marked
++with the MEDIA_LNK_FL_DYNAMIC flag.
++
++If other operations need to be disallowed on streaming entities (such as
++changing entities configuration parameters) drivers can explictly check the
++media_entity stream_count field to find out if an entity is streaming. This
++operation must be done with the media_device graph_mutex held.
+diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
+index d703ce8..e63e089 100644
+--- a/drivers/media/media-entity.c
++++ b/drivers/media/media-entity.c
+@@ -197,6 +197,75 @@ media_entity_graph_walk_next(struct media_entity_graph *graph)
+ EXPORT_SYMBOL_GPL(media_entity_graph_walk_next);
+ /* -----------------------------------------------------------------------------
++ * Pipeline management
++ */
++
++/**
++ * media_entity_pipeline_start - Mark a pipeline as streaming
++ * @entity: Starting entity
++ * @pipe: Media pipeline to be assigned to all entities in the pipeline.
++ *
++ * Mark all entities connected to a given entity through enabled links, either
++ * directly or indirectly, as streaming. The given pipeline object is assigned to
++ * every entity in the pipeline and stored in the media_entity pipe field.
++ *
++ * Calls to this function can be nested, in which case the same number of
++ * media_entity_pipeline_stop() calls will be required to stop streaming. The
++ * pipeline pointer must be identical for all nested calls to
++ * media_entity_pipeline_start().
++ */
++void media_entity_pipeline_start(struct media_entity *entity,
++                               struct media_pipeline *pipe)
++{
++      struct media_device *mdev = entity->parent;
++      struct media_entity_graph graph;
++
++      mutex_lock(&mdev->graph_mutex);
++
++      media_entity_graph_walk_start(&graph, entity);
++
++      while ((entity = media_entity_graph_walk_next(&graph))) {
++              entity->stream_count++;
++              WARN_ON(entity->pipe && entity->pipe != pipe);
++              entity->pipe = pipe;
++      }
++
++      mutex_unlock(&mdev->graph_mutex);
++}
++EXPORT_SYMBOL_GPL(media_entity_pipeline_start);
++
++/**
++ * media_entity_pipeline_stop - Mark a pipeline as not streaming
++ * @entity: Starting entity
++ *
++ * Mark all entities connected to a given entity through enabled links, either
++ * directly or indirectly, as not streaming. The media_entity pipe field is
++ * reset to NULL.
++ *
++ * If multiple calls to media_entity_pipeline_start() have been made, the same
++ * number of calls to this function are required to mark the pipeline as not
++ * streaming.
++ */
++void media_entity_pipeline_stop(struct media_entity *entity)
++{
++      struct media_device *mdev = entity->parent;
++      struct media_entity_graph graph;
++
++      mutex_lock(&mdev->graph_mutex);
++
++      media_entity_graph_walk_start(&graph, entity);
++
++      while ((entity = media_entity_graph_walk_next(&graph))) {
++              entity->stream_count--;
++              if (entity->stream_count == 0)
++                      entity->pipe = NULL;
++      }
++
++      mutex_unlock(&mdev->graph_mutex);
++}
++EXPORT_SYMBOL_GPL(media_entity_pipeline_stop);
++
++/* -----------------------------------------------------------------------------
+  * Module use count
+  */
+@@ -364,6 +433,10 @@ int __media_entity_setup_link(struct media_link *link, u32 flags)
+       source = link->source->entity;
+       sink = link->sink->entity;
++      if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) &&
++          (source->stream_count || sink->stream_count))
++              return -EBUSY;
++
+       mdev = source->parent;
+       if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) {
+diff --git a/include/linux/media.h b/include/linux/media.h
+index 2f67ed2..29039e8 100644
+--- a/include/linux/media.h
++++ b/include/linux/media.h
+@@ -106,6 +106,7 @@ struct media_pad_desc {
+ #define MEDIA_LNK_FL_ENABLED          (1 << 0)
+ #define MEDIA_LNK_FL_IMMUTABLE                (1 << 1)
++#define MEDIA_LNK_FL_DYNAMIC          (1 << 2)
+ struct media_link_desc {
+       struct media_pad_desc source;
+diff --git a/include/media/media-entity.h b/include/media/media-entity.h
+index 60fc7bd..450ba12 100644
+--- a/include/media/media-entity.h
++++ b/include/media/media-entity.h
+@@ -26,6 +26,9 @@
+ #include <linux/list.h>
+ #include <linux/media.h>
++struct media_pipeline {
++};
++
+ struct media_link {
+       struct media_pad *source;       /* Source pad */
+       struct media_pad *sink;         /* Sink pad  */
+@@ -67,8 +70,11 @@ struct media_entity {
+       const struct media_entity_operations *ops;      /* Entity operations */
++      int stream_count;               /* Stream count for the entity. */
+       int use_count;                  /* Use count for the entity. */
++      struct media_pipeline *pipe;    /* Pipeline this entity belongs to. */
++
+       union {
+               /* Node specifications */
+               struct {
+@@ -114,6 +120,7 @@ struct media_entity_graph {
+ int media_entity_init(struct media_entity *entity, u16 num_pads,
+               struct media_pad *pads, u16 extra_links);
+ void media_entity_cleanup(struct media_entity *entity);
++
+ int media_entity_create_link(struct media_entity *source, u16 source_pad,
+               struct media_entity *sink, u16 sink_pad, u32 flags);
+ int __media_entity_setup_link(struct media_link *link, u32 flags);
+@@ -129,6 +136,9 @@ void media_entity_graph_walk_start(struct media_entity_graph *graph,
+               struct media_entity *entity);
+ struct media_entity *
+ media_entity_graph_walk_next(struct media_entity_graph *graph);
++void media_entity_pipeline_start(struct media_entity *entity,
++              struct media_pipeline *pipe);
++void media_entity_pipeline_stop(struct media_entity *entity);
+ #define media_entity_call(entity, operation, args...)                 \
+       (((entity)->ops && (entity)->ops->operation) ?                  \
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0017-v4l-Add-a-media_device-pointer-to-the-v4l2_device-st.patch b/recipes-bsp/linux/linux-omap/media/0017-v4l-Add-a-media_device-pointer-to-the-v4l2_device-st.patch
new file mode 100644 (file)
index 0000000..714c5a3
--- /dev/null
@@ -0,0 +1,115 @@
+From 56e006c01032f98483195e572700e17fb8aaa8b1 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:40:05 +0100
+Subject: [PATCH 17/43] v4l: Add a media_device pointer to the v4l2_device structure
+
+The pointer will later be used to register/unregister media entities
+when registering/unregistering a v4l2_subdev or a video_device.
+
+With the introduction of media devices, device drivers need to store a
+pointer to a driver-specific structure in the device's drvdata.
+v4l2_device can't claim ownership of the drvdata anymore.
+
+To maintain compatibility with drivers that rely on v4l2_device storing
+a pointer to itself in the device's drvdata, v4l2_device_register() will
+keep doing so if the drvdata is NULL.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ Documentation/video4linux/v4l2-framework.txt |   17 ++++++++++++-----
+ drivers/media/video/v4l2-device.c            |   13 +++++++------
+ include/media/v4l2-device.h                  |    4 ++++
+ 3 files changed, 23 insertions(+), 11 deletions(-)
+
+diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
+index 4db1def..aeb2a22 100644
+--- a/Documentation/video4linux/v4l2-framework.txt
++++ b/Documentation/video4linux/v4l2-framework.txt
+@@ -83,11 +83,17 @@ You must register the device instance:
+       v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
+-Registration will initialize the v4l2_device struct and link dev->driver_data
+-to v4l2_dev. If v4l2_dev->name is empty then it will be set to a value derived
+-from dev (driver name followed by the bus_id, to be precise). If you set it
+-up before calling v4l2_device_register then it will be untouched. If dev is
+-NULL, then you *must* setup v4l2_dev->name before calling v4l2_device_register.
++Registration will initialize the v4l2_device struct. If the dev->driver_data
++field is NULL, it will be linked to v4l2_dev. Drivers that use the media
++device framework in addition to the V4L2 framework need to set
++dev->driver_data manually to point to the driver-specific device structure
++that embed the struct v4l2_device instance. This is achieved by a
++dev_set_drvdata() call before registering the V4L2 device instance.
++
++If v4l2_dev->name is empty then it will be set to a value derived from dev
++(driver name followed by the bus_id, to be precise). If you set it up before
++calling v4l2_device_register then it will be untouched. If dev is NULL, then
++you *must* setup v4l2_dev->name before calling v4l2_device_register.
+ You can use v4l2_device_set_name() to set the name based on a driver name and
+ a driver-global atomic_t instance. This will generate names like ivtv0, ivtv1,
+@@ -108,6 +114,7 @@ You unregister with:
+       v4l2_device_unregister(struct v4l2_device *v4l2_dev);
++If the dev->driver_data field points to v4l2_dev, it will be reset to NULL.
+ Unregistering will also automatically unregister all subdevs from the device.
+ If you have a hotpluggable device (e.g. a USB device), then when a disconnect
+diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
+index 97e84df..5c16a12 100644
+--- a/drivers/media/video/v4l2-device.c
++++ b/drivers/media/video/v4l2-device.c
+@@ -47,9 +47,8 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
+       if (!v4l2_dev->name[0])
+               snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s",
+                       dev->driver->name, dev_name(dev));
+-      if (dev_get_drvdata(dev))
+-              v4l2_warn(v4l2_dev, "Non-NULL drvdata on register\n");
+-      dev_set_drvdata(dev, v4l2_dev);
++      if (!dev_get_drvdata(dev))
++              dev_set_drvdata(dev, v4l2_dev);
+       return 0;
+ }
+ EXPORT_SYMBOL_GPL(v4l2_device_register);
+@@ -72,10 +71,12 @@ EXPORT_SYMBOL_GPL(v4l2_device_set_name);
+ void v4l2_device_disconnect(struct v4l2_device *v4l2_dev)
+ {
+-      if (v4l2_dev->dev) {
++      if (v4l2_dev->dev == NULL)
++              return;
++
++      if (dev_get_drvdata(v4l2_dev->dev) == v4l2_dev)
+               dev_set_drvdata(v4l2_dev->dev, NULL);
+-              v4l2_dev->dev = NULL;
+-      }
++      v4l2_dev->dev = NULL;
+ }
+ EXPORT_SYMBOL_GPL(v4l2_device_disconnect);
+diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h
+index b16f307..759db73 100644
+--- a/include/media/v4l2-device.h
++++ b/include/media/v4l2-device.h
+@@ -21,6 +21,7 @@
+ #ifndef _V4L2_DEVICE_H
+ #define _V4L2_DEVICE_H
++#include <media/media-device.h>
+ #include <media/v4l2-subdev.h>
+ /* Each instance of a V4L2 device should create the v4l2_device struct,
+@@ -39,6 +40,9 @@ struct v4l2_device {
+          Note: dev might be NULL if there is no parent device
+          as is the case with e.g. ISA devices. */
+       struct device *dev;
++#if defined(CONFIG_MEDIA_CONTROLLER)
++      struct media_device *mdev;
++#endif
+       /* used to keep track of the registered subdevs */
+       struct list_head subdevs;
+       /* lock this struct; can be used by the driver as well if this
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0018-v4l-Make-video_device-inherit-from-media_entity.patch b/recipes-bsp/linux/linux-omap/media/0018-v4l-Make-video_device-inherit-from-media_entity.patch
new file mode 100644 (file)
index 0000000..6417d1d
--- /dev/null
@@ -0,0 +1,234 @@
+From e31cb57c733341b49256a47f086fa4cc1c1c56ac Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:40:10 +0100
+Subject: [PATCH 18/43] v4l: Make video_device inherit from media_entity
+
+V4L2 devices are media entities. As such they need to inherit from
+(include) the media_entity structure.
+
+When registering/unregistering the device, the media entity is
+automatically registered/unregistered. The entity is acquired on device
+open and released on device close.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+---
+ Documentation/video4linux/v4l2-framework.txt |   38 ++++++++++++++++++--
+ drivers/media/video/v4l2-dev.c               |   49 +++++++++++++++++++++++--
+ include/media/v4l2-dev.h                     |    7 ++++
+ 3 files changed, 87 insertions(+), 7 deletions(-)
+
+diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
+index aeb2a22..f231bc2 100644
+--- a/Documentation/video4linux/v4l2-framework.txt
++++ b/Documentation/video4linux/v4l2-framework.txt
+@@ -71,6 +71,10 @@ sub-device instances, the video_device struct stores V4L2 device node data
+ and in the future a v4l2_fh struct will keep track of filehandle instances
+ (this is not yet implemented).
++The V4L2 framework also optionally integrates with the media framework. If a
++driver sets the struct v4l2_device mdev field, sub-devices and video nodes
++will automatically appear in the media framework as entities.
++
+ struct v4l2_device
+ ------------------
+@@ -84,11 +88,14 @@ You must register the device instance:
+       v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
+ Registration will initialize the v4l2_device struct. If the dev->driver_data
+-field is NULL, it will be linked to v4l2_dev. Drivers that use the media
+-device framework in addition to the V4L2 framework need to set
++field is NULL, it will be linked to v4l2_dev.
++
++Drivers that want integration with the media device framework need to set
+ dev->driver_data manually to point to the driver-specific device structure
+ that embed the struct v4l2_device instance. This is achieved by a
+-dev_set_drvdata() call before registering the V4L2 device instance.
++dev_set_drvdata() call before registering the V4L2 device instance. They must
++also set the struct v4l2_device mdev field to point to a properly initialized
++and registered media_device instance.
+ If v4l2_dev->name is empty then it will be set to a value derived from dev
+ (driver name followed by the bus_id, to be precise). If you set it up before
+@@ -532,6 +539,21 @@ If you use v4l2_ioctl_ops, then you should set either .unlocked_ioctl or
+ The v4l2_file_operations struct is a subset of file_operations. The main
+ difference is that the inode argument is omitted since it is never used.
++If integration with the media framework is needed, you must initialize the
++media_entity struct embedded in the video_device struct (entity field) by
++calling media_entity_init():
++
++      struct media_pad *pad = &my_vdev->pad;
++      int err;
++
++      err = media_entity_init(&vdev->entity, 1, pad, 0);
++
++The pads array must have been previously initialized. There is no need to
++manually set the struct media_entity type and name fields.
++
++A reference to the entity will be automatically acquired/released when the
++video device is opened/closed.
++
+ v4l2_file_operations and locking
+ --------------------------------
+@@ -561,6 +583,9 @@ for you.
+               return err;
+       }
++If the v4l2_device parent device has a non-NULL mdev field, the video device
++entity will be automatically registered with the media device.
++
+ Which device is registered depends on the type argument. The following
+ types exist:
+@@ -636,6 +661,13 @@ release, of course) will return an error as well.
+ When the last user of the video device node exits, then the vdev->release()
+ callback is called and you can do the final cleanup there.
++Don't forget to cleanup the media entity associated with the video device if
++it has been initialized:
++
++      media_entity_cleanup(&vdev->entity);
++
++This can be done from the release callback.
++
+ video_device helper functions
+ -----------------------------
+diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
+index f22bd41..f91348f 100644
+--- a/drivers/media/video/v4l2-dev.c
++++ b/drivers/media/video/v4l2-dev.c
+@@ -303,6 +303,9 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
+ static int v4l2_open(struct inode *inode, struct file *filp)
+ {
+       struct video_device *vdev;
++#if defined(CONFIG_MEDIA_CONTROLLER)
++      struct media_entity *entity = NULL;
++#endif
+       int ret = 0;
+       /* Check if the video device is available */
+@@ -316,6 +319,16 @@ static int v4l2_open(struct inode *inode, struct file *filp)
+       /* and increase the device refcount */
+       video_get(vdev);
+       mutex_unlock(&videodev_lock);
++#if defined(CONFIG_MEDIA_CONTROLLER)
++      if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) {
++              entity = media_entity_get(&vdev->entity);
++              if (!entity) {
++                      ret = -EBUSY;
++                      video_put(vdev);
++                      return ret;
++              }
++      }
++#endif
+       if (vdev->fops->open) {
+               if (vdev->lock && mutex_lock_interruptible(vdev->lock)) {
+                       ret = -ERESTARTSYS;
+@@ -331,8 +344,13 @@ static int v4l2_open(struct inode *inode, struct file *filp)
+ err:
+       /* decrease the refcount in case of an error */
+-      if (ret)
++      if (ret) {
++#if defined(CONFIG_MEDIA_CONTROLLER)
++              if (vdev->v4l2_dev && vdev->v4l2_dev->mdev)
++                      media_entity_put(entity);
++#endif
+               video_put(vdev);
++      }
+       return ret;
+ }
+@@ -349,7 +367,10 @@ static int v4l2_release(struct inode *inode, struct file *filp)
+               if (vdev->lock)
+                       mutex_unlock(vdev->lock);
+       }
+-
++#if defined(CONFIG_MEDIA_CONTROLLER)
++      if (vdev->v4l2_dev && vdev->v4l2_dev->mdev)
++              media_entity_put(&vdev->entity);
++#endif
+       /* decrease the refcount unconditionally since the release()
+          return value is ignored. */
+       video_put(vdev);
+@@ -586,12 +607,27 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
+       if (nr != -1 && nr != vdev->num && warn_if_nr_in_use)
+               printk(KERN_WARNING "%s: requested %s%d, got %s\n", __func__,
+                       name_base, nr, video_device_node_name(vdev));
+-
+-      /* Part 5: Activate this minor. The char device can now be used. */
++#if defined(CONFIG_MEDIA_CONTROLLER)
++      /* Part 5: Register the entity. */
++      if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) {
++              vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
++              vdev->entity.name = vdev->name;
++              vdev->entity.v4l.major = VIDEO_MAJOR;
++              vdev->entity.v4l.minor = vdev->minor;
++              ret = media_device_register_entity(vdev->v4l2_dev->mdev,
++                      &vdev->entity);
++              if (ret < 0)
++                      printk(KERN_WARNING
++                             "%s: media_device_register_entity failed\n",
++                             __func__);
++      }
++#endif
++      /* Part 6: Activate this minor. The char device can now be used. */
+       set_bit(V4L2_FL_REGISTERED, &vdev->flags);
+       mutex_lock(&videodev_lock);
+       video_device[vdev->minor] = vdev;
+       mutex_unlock(&videodev_lock);
++
+       return 0;
+ cleanup:
+@@ -619,6 +655,11 @@ void video_unregister_device(struct video_device *vdev)
+       if (!vdev || !video_is_registered(vdev))
+               return;
++#if defined(CONFIG_MEDIA_CONTROLLER)
++      if (vdev->v4l2_dev && vdev->v4l2_dev->mdev)
++              media_device_unregister_entity(&vdev->entity);
++#endif
++
+       mutex_lock(&videodev_lock);
+       /* This must be in a critical section to prevent a race with v4l2_open.
+        * Once this bit has been cleared video_get may never be called again.
+diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
+index 4fe6831..51b2c51 100644
+--- a/include/media/v4l2-dev.h
++++ b/include/media/v4l2-dev.h
+@@ -16,6 +16,8 @@
+ #include <linux/mutex.h>
+ #include <linux/videodev2.h>
++#include <media/media-entity.h>
++
+ #define VIDEO_MAJOR   81
+ #define VFL_TYPE_GRABBER      0
+@@ -55,6 +57,9 @@ struct v4l2_file_operations {
+ struct video_device
+ {
++#if defined(CONFIG_MEDIA_CONTROLLER)
++      struct media_entity entity;
++#endif
+       /* device ops */
+       const struct v4l2_file_operations *fops;
+@@ -100,6 +105,8 @@ struct video_device
+       struct mutex *lock;
+ };
++#define media_entity_to_video_device(entity) \
++      container_of(entity, struct video_device, entity)
+ /* dev to video-device */
+ #define to_video_device(cd) container_of(cd, struct video_device, dev)
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0019-v4l-Make-v4l2_subdev-inherit-from-media_entity.patch b/recipes-bsp/linux/linux-omap/media/0019-v4l-Make-v4l2_subdev-inherit-from-media_entity.patch
new file mode 100644 (file)
index 0000000..c7ae882
--- /dev/null
@@ -0,0 +1,265 @@
+From ab4bf9e43078f79ba2b287e6dd6d6871901d0341 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:40:08 +0100
+Subject: [PATCH 19/43] v4l: Make v4l2_subdev inherit from media_entity
+
+V4L2 subdevices are media entities. As such they need to inherit from
+(include) the media_entity structure.
+
+When registering/unregistering the subdevice, the media entity is
+automatically registered/unregistered. The entity is acquired on device
+open and released on device close.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+---
+ Documentation/video4linux/v4l2-framework.txt |   23 ++++++++++++++
+ drivers/media/video/v4l2-device.c            |   39 ++++++++++++++++++++----
+ drivers/media/video/v4l2-subdev.c            |   41 ++++++++++++++++++++++++-
+ include/media/v4l2-subdev.h                  |   10 ++++++
+ 4 files changed, 104 insertions(+), 9 deletions(-)
+
+diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
+index f231bc2..d0fb880 100644
+--- a/Documentation/video4linux/v4l2-framework.txt
++++ b/Documentation/video4linux/v4l2-framework.txt
+@@ -268,6 +268,26 @@ A sub-device driver initializes the v4l2_subdev struct using:
+ Afterwards you need to initialize subdev->name with a unique name and set the
+ module owner. This is done for you if you use the i2c helper functions.
++If integration with the media framework is needed, you must initialize the
++media_entity struct embedded in the v4l2_subdev struct (entity field) by
++calling media_entity_init():
++
++      struct media_pad *pads = &my_sd->pads;
++      int err;
++
++      err = media_entity_init(&sd->entity, npads, pads, 0);
++
++The pads array must have been previously initialized. There is no need to
++manually set the struct media_entity type and name fields, but the revision
++field must be initialized if needed.
++
++A reference to the entity will be automatically acquired/released when the
++subdev device node (if any) is opened/closed.
++
++Don't forget to cleanup the media entity before the sub-device is destroyed:
++
++      media_entity_cleanup(&sd->entity);
++
+ A device (bridge) driver needs to register the v4l2_subdev with the
+ v4l2_device:
+@@ -277,6 +297,9 @@ This can fail if the subdev module disappeared before it could be registered.
+ After this function was called successfully the subdev->dev field points to
+ the v4l2_device.
++If the v4l2_device parent device has a non-NULL mdev field, the sub-device
++entity will be automatically registered with the media device.
++
+ You can unregister a sub-device using:
+       v4l2_device_unregister_subdev(sd);
+diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
+index 5c16a12..69cb429 100644
+--- a/drivers/media/video/v4l2-device.c
++++ b/drivers/media/video/v4l2-device.c
+@@ -116,8 +116,11 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
+ EXPORT_SYMBOL_GPL(v4l2_device_unregister);
+ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
+-                                              struct v4l2_subdev *sd)
++                              struct v4l2_subdev *sd)
+ {
++#if defined(CONFIG_MEDIA_CONTROLLER)
++      struct media_entity *entity = &sd->entity;
++#endif
+       struct video_device *vdev;
+       int err;
+@@ -135,7 +138,16 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
+       err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler);
+       if (err)
+               return err;
+-
++#if defined(CONFIG_MEDIA_CONTROLLER)
++      /* Register the entity. */
++      if (v4l2_dev->mdev) {
++              err = media_device_register_entity(v4l2_dev->mdev, entity);
++              if (err < 0) {
++                      module_put(sd->owner);
++                      return err;
++              }
++      }
++#endif
+       sd->v4l2_dev = v4l2_dev;
+       spin_lock(&v4l2_dev->lock);
+       list_add_tail(&sd->list, &v4l2_dev->subdevs);
+@@ -150,26 +162,39 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
+       if (sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE) {
+               err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
+                                             sd->owner);
+-              if (err < 0)
++              if (err < 0) {
+                       v4l2_device_unregister_subdev(sd);
++                      return err;
++              }
+       }
+-
+-      return err;
++#if defined(CONFIG_MEDIA_CONTROLLER)
++      entity->v4l.major = VIDEO_MAJOR;
++      entity->v4l.minor = vdev->minor;
++#endif
++      return 0;
+ }
+ EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
+ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
+ {
++      struct v4l2_device *v4l2_dev;
++
+       /* return if it isn't registered */
+       if (sd == NULL || sd->v4l2_dev == NULL)
+               return;
+-      spin_lock(&sd->v4l2_dev->lock);
++      v4l2_dev = sd->v4l2_dev;
++
++      spin_lock(&v4l2_dev->lock);
+       list_del(&sd->list);
+-      spin_unlock(&sd->v4l2_dev->lock);
++      spin_unlock(&v4l2_dev->lock);
+       sd->v4l2_dev = NULL;
+       module_put(sd->owner);
++#if defined(CONFIG_MEDIA_CONTROLLER)
++      if (v4l2_dev->mdev)
++              media_device_unregister_entity(&sd->entity);
++#endif
+       video_unregister_device(&sd->devnode);
+ }
+ EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);
+diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
+index fbccefd..a49856a 100644
+--- a/drivers/media/video/v4l2-subdev.c
++++ b/drivers/media/video/v4l2-subdev.c
+@@ -35,7 +35,10 @@ static int subdev_open(struct file *file)
+ {
+       struct video_device *vdev = video_devdata(file);
+       struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+-      struct v4l2_fh *vfh;
++#if defined(CONFIG_MEDIA_CONTROLLER)
++      struct media_entity *entity;
++#endif
++      struct v4l2_fh *vfh = NULL;
+       int ret;
+       if (!sd->initialized)
+@@ -61,11 +64,20 @@ static int subdev_open(struct file *file)
+               v4l2_fh_add(vfh);
+               file->private_data = vfh;
+       }
+-
++#if defined(CONFIG_MEDIA_CONTROLLER)
++      if (sd->v4l2_dev->mdev) {
++              entity = media_entity_get(&sd->entity);
++              if (!entity) {
++                      ret = -EBUSY;
++                      goto err;
++              }
++      }
++#endif
+       return 0;
+ err:
+       if (vfh != NULL) {
++              v4l2_fh_del(vfh);
+               v4l2_fh_exit(vfh);
+               kfree(vfh);
+       }
+@@ -75,8 +87,16 @@ err:
+ static int subdev_close(struct file *file)
+ {
++#if defined(CONFIG_MEDIA_CONTROLLER)
++      struct video_device *vdev = video_devdata(file);
++      struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
++#endif
+       struct v4l2_fh *vfh = file->private_data;
++#if defined(CONFIG_MEDIA_CONTROLLER)
++      if (sd->v4l2_dev->mdev)
++              media_entity_put(&sd->entity);
++#endif
+       if (vfh != NULL) {
+               v4l2_fh_del(vfh);
+               v4l2_fh_exit(vfh);
+@@ -176,5 +196,22 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
+       sd->dev_priv = NULL;
+       sd->host_priv = NULL;
+       sd->initialized = 1;
++#if defined(CONFIG_MEDIA_CONTROLLER)
++      sd->entity.name = sd->name;
++      sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
++#endif
+ }
+ EXPORT_SYMBOL(v4l2_subdev_init);
++
++#if defined(CONFIG_MEDIA_CONTROLLER)
++int v4l2_subdev_set_power(struct media_entity *entity, int power)
++{
++      struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
++
++      dev_dbg(entity->parent->dev,
++              "%s power%s\n", entity->name, power ? "on" : "off");
++
++      return v4l2_subdev_call(sd, core, s_power, power);
++}
++EXPORT_SYMBOL_GPL(v4l2_subdev_set_power);
++#endif
+diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
+index 68cbe48..7d55b0c 100644
+--- a/include/media/v4l2-subdev.h
++++ b/include/media/v4l2-subdev.h
+@@ -21,6 +21,7 @@
+ #ifndef _V4L2_SUBDEV_H
+ #define _V4L2_SUBDEV_H
++#include <media/media-entity.h>
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-dev.h>
+ #include <media/v4l2-mediabus.h>
+@@ -437,6 +438,9 @@ struct v4l2_subdev_ops {
+    stand-alone or embedded in a larger struct.
+  */
+ struct v4l2_subdev {
++#if defined(CONFIG_MEDIA_CONTROLLER)
++      struct media_entity entity;
++#endif
+       struct list_head list;
+       struct module *owner;
+       u32 flags;
+@@ -458,6 +462,8 @@ struct v4l2_subdev {
+       unsigned int nevents;
+ };
++#define media_entity_to_v4l2_subdev(ent) \
++      container_of(ent, struct v4l2_subdev, entity)
+ #define vdev_to_v4l2_subdev(vdev) \
+       container_of(vdev, struct v4l2_subdev, devnode)
+@@ -486,6 +492,10 @@ static inline void *v4l2_get_subdev_hostdata(const struct v4l2_subdev *sd)
+ void v4l2_subdev_init(struct v4l2_subdev *sd,
+                     const struct v4l2_subdev_ops *ops);
++#if defined(CONFIG_MEDIA_CONTROLLER)
++int v4l2_subdev_set_power(struct media_entity *entity, int power);
++#endif
++
+ /* Call an ops of a v4l2_subdev, doing the right checks against
+    NULL pointers.
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0020-v4l-Move-the-media-v4l2-mediabus.h-header-to-include.patch b/recipes-bsp/linux/linux-omap/media/0020-v4l-Move-the-media-v4l2-mediabus.h-header-to-include.patch
new file mode 100644 (file)
index 0000000..302fe53
--- /dev/null
@@ -0,0 +1,205 @@
+From 0d2a2247733eca8f357f5a93fcc357edbb941ec1 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Mon, 15 Mar 2010 23:33:31 +0100
+Subject: [PATCH 20/43] v4l: Move the media/v4l2-mediabus.h header to include/linux
+
+The header defines the v4l2_mbus_framefmt structure which will be used
+by the V4L2 subdevs userspace API.
+
+Change the type of the v4l2_mbus_framefmt::code field to __u32, as enum
+sizes can differ between different ABIs on the same architectures.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ include/linux/Kbuild          |    1 +
+ include/linux/v4l2-mediabus.h |   78 +++++++++++++++++++++++++++++++++++++++++
+ include/media/soc_mediabus.h  |    3 +-
+ include/media/v4l2-mediabus.h |   61 +-------------------------------
+ 4 files changed, 81 insertions(+), 62 deletions(-)
+ create mode 100644 include/linux/v4l2-mediabus.h
+
+diff --git a/include/linux/Kbuild b/include/linux/Kbuild
+index 26e0a7f..796e1d8 100644
+--- a/include/linux/Kbuild
++++ b/include/linux/Kbuild
+@@ -366,6 +366,7 @@ header-y += unistd.h
+ header-y += usbdevice_fs.h
+ header-y += utime.h
+ header-y += utsname.h
++header-y += v4l2-mediabus.h
+ header-y += veth.h
+ header-y += vhost.h
+ header-y += videodev.h
+diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h
+new file mode 100644
+index 0000000..a62cd64
+--- /dev/null
++++ b/include/linux/v4l2-mediabus.h
+@@ -0,0 +1,78 @@
++/*
++ * Media Bus API header
++ *
++ * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef __LINUX_V4L2_MEDIABUS_H
++#define __LINUX_V4L2_MEDIABUS_H
++
++#include <linux/types.h>
++#include <linux/videodev2.h>
++
++/*
++ * These pixel codes uniquely identify data formats on the media bus. Mostly
++ * they correspond to similarly named V4L2_PIX_FMT_* formats, format 0 is
++ * reserved, V4L2_MBUS_FMT_FIXED shall be used by host-client pairs, where the
++ * data format is fixed. Additionally, "2X8" means that one pixel is transferred
++ * in two 8-bit samples, "BE" or "LE" specify in which order those samples are
++ * transferred over the bus: "LE" means that the least significant bits are
++ * transferred first, "BE" means that the most significant bits are transferred
++ * first, and "PADHI" and "PADLO" define which bits - low or high, in the
++ * incomplete high byte, are filled with padding bits.
++ */
++enum v4l2_mbus_pixelcode {
++      V4L2_MBUS_FMT_FIXED = 1,
++      V4L2_MBUS_FMT_YUYV8_2X8,
++      V4L2_MBUS_FMT_YVYU8_2X8,
++      V4L2_MBUS_FMT_UYVY8_2X8,
++      V4L2_MBUS_FMT_VYUY8_2X8,
++      V4L2_MBUS_FMT_YVYU10_2X10,
++      V4L2_MBUS_FMT_YUYV10_2X10,
++      V4L2_MBUS_FMT_YVYU10_1X20,
++      V4L2_MBUS_FMT_YUYV10_1X20,
++      V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
++      V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE,
++      V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
++      V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
++      V4L2_MBUS_FMT_RGB565_2X8_LE,
++      V4L2_MBUS_FMT_RGB565_2X8_BE,
++      V4L2_MBUS_FMT_BGR565_2X8_LE,
++      V4L2_MBUS_FMT_BGR565_2X8_BE,
++      V4L2_MBUS_FMT_SBGGR8_1X8,
++      V4L2_MBUS_FMT_SBGGR10_1X10,
++      V4L2_MBUS_FMT_GREY8_1X8,
++      V4L2_MBUS_FMT_Y10_1X10,
++      V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
++      V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
++      V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
++      V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
++      V4L2_MBUS_FMT_SGRBG8_1X8,
++      V4L2_MBUS_FMT_SBGGR12_1X12,
++      V4L2_MBUS_FMT_YUYV8_1_5X8,
++      V4L2_MBUS_FMT_YVYU8_1_5X8,
++      V4L2_MBUS_FMT_UYVY8_1_5X8,
++      V4L2_MBUS_FMT_VYUY8_1_5X8,
++};
++
++/**
++ * struct v4l2_mbus_framefmt - frame format on the media bus
++ * @width:    frame width
++ * @height:   frame height
++ * @code:     data format code
++ * @field:    used interlacing type
++ * @colorspace:       colorspace of the data
++ */
++struct v4l2_mbus_framefmt {
++      __u32                           width;
++      __u32                           height;
++      __u32                           code;
++      enum v4l2_field                 field;
++      enum v4l2_colorspace            colorspace;
++};
++
++#endif
+diff --git a/include/media/soc_mediabus.h b/include/media/soc_mediabus.h
+index 037cd7b..6243147 100644
+--- a/include/media/soc_mediabus.h
++++ b/include/media/soc_mediabus.h
+@@ -12,8 +12,7 @@
+ #define SOC_MEDIABUS_H
+ #include <linux/videodev2.h>
+-
+-#include <media/v4l2-mediabus.h>
++#include <linux/v4l2-mediabus.h>
+ /**
+  * enum soc_mbus_packing - data packing types on the media-bus
+diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h
+index 8e65598..971c7fa 100644
+--- a/include/media/v4l2-mediabus.h
++++ b/include/media/v4l2-mediabus.h
+@@ -11,66 +11,7 @@
+ #ifndef V4L2_MEDIABUS_H
+ #define V4L2_MEDIABUS_H
+-/*
+- * These pixel codes uniquely identify data formats on the media bus. Mostly
+- * they correspond to similarly named V4L2_PIX_FMT_* formats, format 0 is
+- * reserved, V4L2_MBUS_FMT_FIXED shall be used by host-client pairs, where the
+- * data format is fixed. Additionally, "2X8" means that one pixel is transferred
+- * in two 8-bit samples, "BE" or "LE" specify in which order those samples are
+- * transferred over the bus: "LE" means that the least significant bits are
+- * transferred first, "BE" means that the most significant bits are transferred
+- * first, and "PADHI" and "PADLO" define which bits - low or high, in the
+- * incomplete high byte, are filled with padding bits.
+- */
+-enum v4l2_mbus_pixelcode {
+-      V4L2_MBUS_FMT_FIXED = 1,
+-      V4L2_MBUS_FMT_YUYV8_2X8,
+-      V4L2_MBUS_FMT_YVYU8_2X8,
+-      V4L2_MBUS_FMT_UYVY8_2X8,
+-      V4L2_MBUS_FMT_VYUY8_2X8,
+-      V4L2_MBUS_FMT_YVYU10_2X10,
+-      V4L2_MBUS_FMT_YUYV10_2X10,
+-      V4L2_MBUS_FMT_YVYU10_1X20,
+-      V4L2_MBUS_FMT_YUYV10_1X20,
+-      V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+-      V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE,
+-      V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+-      V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
+-      V4L2_MBUS_FMT_RGB565_2X8_LE,
+-      V4L2_MBUS_FMT_RGB565_2X8_BE,
+-      V4L2_MBUS_FMT_BGR565_2X8_LE,
+-      V4L2_MBUS_FMT_BGR565_2X8_BE,
+-      V4L2_MBUS_FMT_SBGGR8_1X8,
+-      V4L2_MBUS_FMT_SBGGR10_1X10,
+-      V4L2_MBUS_FMT_GREY8_1X8,
+-      V4L2_MBUS_FMT_Y10_1X10,
+-      V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
+-      V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
+-      V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
+-      V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
+-      V4L2_MBUS_FMT_SGRBG8_1X8,
+-      V4L2_MBUS_FMT_SBGGR12_1X12,
+-      V4L2_MBUS_FMT_YUYV8_1_5X8,
+-      V4L2_MBUS_FMT_YVYU8_1_5X8,
+-      V4L2_MBUS_FMT_UYVY8_1_5X8,
+-      V4L2_MBUS_FMT_VYUY8_1_5X8,
+-};
+-
+-/**
+- * struct v4l2_mbus_framefmt - frame format on the media bus
+- * @width:    frame width
+- * @height:   frame height
+- * @code:     data format code
+- * @field:    used interlacing type
+- * @colorspace:       colorspace of the data
+- */
+-struct v4l2_mbus_framefmt {
+-      __u32                           width;
+-      __u32                           height;
+-      enum v4l2_mbus_pixelcode        code;
+-      enum v4l2_field                 field;
+-      enum v4l2_colorspace            colorspace;
+-};
++#include <linux/v4l2-mediabus.h>
+ static inline void v4l2_fill_pix_format(struct v4l2_pix_format *pix_fmt,
+                               const struct v4l2_mbus_framefmt *mbus_fmt)
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0021-v4l-Replace-enums-with-fixed-sized-fields-in-public-.patch b/recipes-bsp/linux/linux-omap/media/0021-v4l-Replace-enums-with-fixed-sized-fields-in-public-.patch
new file mode 100644 (file)
index 0000000..e04f4e2
--- /dev/null
@@ -0,0 +1,50 @@
+From fb1156d3125e36952f884b09afb9d0815ddeafd7 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 6 Oct 2010 08:30:26 +0200
+Subject: [PATCH 21/43] v4l: Replace enums with fixed-sized fields in public structure
+
+The v4l2_mbus_framefmt structure will be part of the public userspace
+API and used (albeit indirectly) as an ioctl argument. As such, its size
+must be fixed across userspace ABIs.
+
+Replace the v4l2_field and v4l2_colorspace enums by __u32 fields and add
+padding for future enhancements.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ include/linux/v4l2-mediabus.h |   17 +++++++++--------
+ 1 files changed, 9 insertions(+), 8 deletions(-)
+
+diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h
+index a62cd64..feeb88c 100644
+--- a/include/linux/v4l2-mediabus.h
++++ b/include/linux/v4l2-mediabus.h
+@@ -63,16 +63,17 @@ enum v4l2_mbus_pixelcode {
+  * struct v4l2_mbus_framefmt - frame format on the media bus
+  * @width:    frame width
+  * @height:   frame height
+- * @code:     data format code
+- * @field:    used interlacing type
+- * @colorspace:       colorspace of the data
++ * @code:     data format code (from enum v4l2_mbus_pixelcode)
++ * @field:    used interlacing type (from enum v4l2_field)
++ * @colorspace:       colorspace of the data (from enum v4l2_colorspace)
+  */
+ struct v4l2_mbus_framefmt {
+-      __u32                           width;
+-      __u32                           height;
+-      __u32                           code;
+-      enum v4l2_field                 field;
+-      enum v4l2_colorspace            colorspace;
++      __u32                   width;
++      __u32                   height;
++      __u32                   code;
++      __u32                   field;
++      __u32                   colorspace;
++      __u32                   reserved[7];
+ };
+ #endif
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0022-v4l-Rename-V4L2_MBUS_FMT_GREY8_1X8-to-V4L2_MBUS_FMT_.patch b/recipes-bsp/linux/linux-omap/media/0022-v4l-Rename-V4L2_MBUS_FMT_GREY8_1X8-to-V4L2_MBUS_FMT_.patch
new file mode 100644 (file)
index 0000000..ffffd26
--- /dev/null
@@ -0,0 +1,154 @@
+From 0be9c8b998cef9ce650e1e53d12bb5a6d772d151 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Tue, 28 Sep 2010 12:01:44 +0200
+Subject: [PATCH 22/43] v4l: Rename V4L2_MBUS_FMT_GREY8_1X8 to V4L2_MBUS_FMT_Y8_1X8
+
+For consistency with the V4L2_MBUS_FMT_Y10_1X10 format.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ drivers/media/video/mt9m001.c        |    2 +-
+ drivers/media/video/mt9v022.c        |    4 ++--
+ drivers/media/video/ov6650.c         |   10 +++++-----
+ drivers/media/video/sh_mobile_csi2.c |    6 +++---
+ drivers/media/video/soc_mediabus.c   |    2 +-
+ include/linux/v4l2-mediabus.h        |    2 +-
+ 6 files changed, 13 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
+index fcb4cd9..3aaedf6 100644
+--- a/drivers/media/video/mt9m001.c
++++ b/drivers/media/video/mt9m001.c
+@@ -79,7 +79,7 @@ static const struct mt9m001_datafmt mt9m001_colour_fmts[] = {
+ static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = {
+       /* Order important - see above */
+       {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
+-      {V4L2_MBUS_FMT_GREY8_1X8, V4L2_COLORSPACE_JPEG},
++      {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
+ };
+ struct mt9m001 {
+diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
+index b96171c..56dd4fc 100644
+--- a/drivers/media/video/mt9v022.c
++++ b/drivers/media/video/mt9v022.c
+@@ -95,7 +95,7 @@ static const struct mt9v022_datafmt mt9v022_colour_fmts[] = {
+ static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = {
+       /* Order important - see above */
+       {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
+-      {V4L2_MBUS_FMT_GREY8_1X8, V4L2_COLORSPACE_JPEG},
++      {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
+ };
+ struct mt9v022 {
+@@ -392,7 +392,7 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd,
+        * icd->try_fmt(), datawidth is from our supported format list
+        */
+       switch (mf->code) {
+-      case V4L2_MBUS_FMT_GREY8_1X8:
++      case V4L2_MBUS_FMT_Y8_1X8:
+       case V4L2_MBUS_FMT_Y10_1X10:
+               if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM)
+                       return -EINVAL;
+diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c
+index cf93de9..fe8e3eb 100644
+--- a/drivers/media/video/ov6650.c
++++ b/drivers/media/video/ov6650.c
+@@ -207,7 +207,7 @@ static enum v4l2_mbus_pixelcode ov6650_codes[] = {
+       V4L2_MBUS_FMT_YVYU8_2X8,
+       V4L2_MBUS_FMT_VYUY8_2X8,
+       V4L2_MBUS_FMT_SBGGR8_1X8,
+-      V4L2_MBUS_FMT_GREY8_1X8,
++      V4L2_MBUS_FMT_Y8_1X8,
+ };
+ static const struct v4l2_queryctrl ov6650_controls[] = {
+@@ -800,7 +800,7 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
+       /* select color matrix configuration for given color encoding */
+       switch (code) {
+-      case V4L2_MBUS_FMT_GREY8_1X8:
++      case V4L2_MBUS_FMT_Y8_1X8:
+               dev_dbg(&client->dev, "pixel format GREY8_1X8\n");
+               coma_mask |= COMA_RGB | COMA_WORD_SWAP | COMA_BYTE_SWAP;
+               coma_set |= COMA_BW;
+@@ -846,7 +846,7 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
+       }
+       priv->code = code;
+-      if (code == V4L2_MBUS_FMT_GREY8_1X8 ||
++      if (code == V4L2_MBUS_FMT_Y8_1X8 ||
+                       code == V4L2_MBUS_FMT_SBGGR8_1X8) {
+               coml_mask = COML_ONE_CHANNEL;
+               coml_set = 0;
+@@ -936,8 +936,8 @@ static int ov6650_try_fmt(struct v4l2_subdev *sd,
+       switch (mf->code) {
+       case V4L2_MBUS_FMT_Y10_1X10:
+-              mf->code = V4L2_MBUS_FMT_GREY8_1X8;
+-      case V4L2_MBUS_FMT_GREY8_1X8:
++              mf->code = V4L2_MBUS_FMT_Y8_1X8;
++      case V4L2_MBUS_FMT_Y8_1X8:
+       case V4L2_MBUS_FMT_YVYU8_2X8:
+       case V4L2_MBUS_FMT_YUYV8_2X8:
+       case V4L2_MBUS_FMT_VYUY8_2X8:
+diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c
+index 84a6468..dd1b81b 100644
+--- a/drivers/media/video/sh_mobile_csi2.c
++++ b/drivers/media/video/sh_mobile_csi2.c
+@@ -56,7 +56,7 @@ static int sh_csi2_try_fmt(struct v4l2_subdev *sd,
+               switch (mf->code) {
+               case V4L2_MBUS_FMT_UYVY8_2X8:           /* YUV422 */
+               case V4L2_MBUS_FMT_YUYV8_1_5X8:         /* YUV420 */
+-              case V4L2_MBUS_FMT_GREY8_1X8:           /* RAW8 */
++              case V4L2_MBUS_FMT_Y8_1X8:              /* RAW8 */
+               case V4L2_MBUS_FMT_SBGGR8_1X8:
+               case V4L2_MBUS_FMT_SGRBG8_1X8:
+                       break;
+@@ -67,7 +67,7 @@ static int sh_csi2_try_fmt(struct v4l2_subdev *sd,
+               break;
+       case SH_CSI2I:
+               switch (mf->code) {
+-              case V4L2_MBUS_FMT_GREY8_1X8:           /* RAW8 */
++              case V4L2_MBUS_FMT_Y8_1X8:              /* RAW8 */
+               case V4L2_MBUS_FMT_SBGGR8_1X8:
+               case V4L2_MBUS_FMT_SGRBG8_1X8:
+               case V4L2_MBUS_FMT_SBGGR10_1X10:        /* RAW10 */
+@@ -111,7 +111,7 @@ static int sh_csi2_s_fmt(struct v4l2_subdev *sd,
+       case V4L2_MBUS_FMT_RGB565_2X8_BE:
+               tmp |= 0x22;    /* RGB565 */
+               break;
+-      case V4L2_MBUS_FMT_GREY8_1X8:
++      case V4L2_MBUS_FMT_Y8_1X8:
+       case V4L2_MBUS_FMT_SBGGR8_1X8:
+       case V4L2_MBUS_FMT_SGRBG8_1X8:
+               tmp |= 0x2a;    /* RAW8 */
+diff --git a/drivers/media/video/soc_mediabus.c b/drivers/media/video/soc_mediabus.c
+index 9139121..d9c297d 100644
+--- a/drivers/media/video/soc_mediabus.c
++++ b/drivers/media/video/soc_mediabus.c
+@@ -88,7 +88,7 @@ static const struct soc_mbus_pixelfmt mbus_fmt[] = {
+               .packing                = SOC_MBUS_PACKING_EXTEND16,
+               .order                  = SOC_MBUS_ORDER_LE,
+       },
+-      [MBUS_IDX(GREY8_1X8)] = {
++      [MBUS_IDX(Y8_1X8)] = {
+               .fourcc                 = V4L2_PIX_FMT_GREY,
+               .name                   = "Grey",
+               .bits_per_sample        = 8,
+diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h
+index feeb88c..dc1d5c0 100644
+--- a/include/linux/v4l2-mediabus.h
++++ b/include/linux/v4l2-mediabus.h
+@@ -45,7 +45,7 @@ enum v4l2_mbus_pixelcode {
+       V4L2_MBUS_FMT_BGR565_2X8_BE,
+       V4L2_MBUS_FMT_SBGGR8_1X8,
+       V4L2_MBUS_FMT_SBGGR10_1X10,
+-      V4L2_MBUS_FMT_GREY8_1X8,
++      V4L2_MBUS_FMT_Y8_1X8,
+       V4L2_MBUS_FMT_Y10_1X10,
+       V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
+       V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0023-v4l-Group-media-bus-pixel-codes-by-types-and-sort-th.patch b/recipes-bsp/linux/linux-omap/media/0023-v4l-Group-media-bus-pixel-codes-by-types-and-sort-th.patch
new file mode 100644 (file)
index 0000000..aee5444
--- /dev/null
@@ -0,0 +1,112 @@
+From 9a13751e47503b4c966538e194a5027e5e7d9c5d Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 1 Sep 2010 17:58:22 +0200
+Subject: [PATCH 23/43] v4l: Group media bus pixel codes by types and sort them alphabetically
+
+Adding new pixel codes at the end of the enumeration will soon create a
+mess, so group the pixel codes by type and sort them by bus_width, bits
+per component, samples per pixel and order of subsamples.
+
+As the codes are part of the kernel ABI their value can't change when a
+new code is inserted in the enumeration, so they are given an explicit
+numerical value. When inserting a new pixel code developers must use and
+update the next free value.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ include/linux/v4l2-mediabus.h |   77 ++++++++++++++++++++++++----------------
+ 1 files changed, 46 insertions(+), 31 deletions(-)
+
+diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h
+index dc1d5c0..cccfa34 100644
+--- a/include/linux/v4l2-mediabus.h
++++ b/include/linux/v4l2-mediabus.h
+@@ -24,39 +24,54 @@
+  * transferred first, "BE" means that the most significant bits are transferred
+  * first, and "PADHI" and "PADLO" define which bits - low or high, in the
+  * incomplete high byte, are filled with padding bits.
++ *
++ * The pixel codes are grouped by type, bus_width, bits per component, samples
++ * per pixel and order of subsamples. Numerical values are sorted using generic
++ * numerical sort order (8 thus comes before 10).
++ *
++ * As their value can't change when a new pixel code is inserted in the
++ * enumeration, the pixel codes are explicitly given a numerical value. The next
++ * free values for each category are listed below, update them when inserting
++ * new pixel codes.
+  */
+ enum v4l2_mbus_pixelcode {
+-      V4L2_MBUS_FMT_FIXED = 1,
+-      V4L2_MBUS_FMT_YUYV8_2X8,
+-      V4L2_MBUS_FMT_YVYU8_2X8,
+-      V4L2_MBUS_FMT_UYVY8_2X8,
+-      V4L2_MBUS_FMT_VYUY8_2X8,
+-      V4L2_MBUS_FMT_YVYU10_2X10,
+-      V4L2_MBUS_FMT_YUYV10_2X10,
+-      V4L2_MBUS_FMT_YVYU10_1X20,
+-      V4L2_MBUS_FMT_YUYV10_1X20,
+-      V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+-      V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE,
+-      V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+-      V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
+-      V4L2_MBUS_FMT_RGB565_2X8_LE,
+-      V4L2_MBUS_FMT_RGB565_2X8_BE,
+-      V4L2_MBUS_FMT_BGR565_2X8_LE,
+-      V4L2_MBUS_FMT_BGR565_2X8_BE,
+-      V4L2_MBUS_FMT_SBGGR8_1X8,
+-      V4L2_MBUS_FMT_SBGGR10_1X10,
+-      V4L2_MBUS_FMT_Y8_1X8,
+-      V4L2_MBUS_FMT_Y10_1X10,
+-      V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
+-      V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
+-      V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
+-      V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
+-      V4L2_MBUS_FMT_SGRBG8_1X8,
+-      V4L2_MBUS_FMT_SBGGR12_1X12,
+-      V4L2_MBUS_FMT_YUYV8_1_5X8,
+-      V4L2_MBUS_FMT_YVYU8_1_5X8,
+-      V4L2_MBUS_FMT_UYVY8_1_5X8,
+-      V4L2_MBUS_FMT_VYUY8_1_5X8,
++      V4L2_MBUS_FMT_FIXED = 0x0001,
++
++      /* RGB - next is 0x1009 */
++      V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE = 0x1001,
++      V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE = 0x1002,
++      V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE = 0x1003,
++      V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE = 0x1004,
++      V4L2_MBUS_FMT_BGR565_2X8_BE = 0x1005,
++      V4L2_MBUS_FMT_BGR565_2X8_LE = 0x1006,
++      V4L2_MBUS_FMT_RGB565_2X8_BE = 0x1007,
++      V4L2_MBUS_FMT_RGB565_2X8_LE = 0x1008,
++
++      /* YUV (including grey) - next is 0x200f */
++      V4L2_MBUS_FMT_Y8_1X8 = 0x2001,
++      V4L2_MBUS_FMT_UYVY8_1_5X8 = 0x2002,
++      V4L2_MBUS_FMT_VYUY8_1_5X8 = 0x2003,
++      V4L2_MBUS_FMT_YUYV8_1_5X8 = 0x2004,
++      V4L2_MBUS_FMT_YVYU8_1_5X8 = 0x2005,
++      V4L2_MBUS_FMT_UYVY8_2X8 = 0x2006,
++      V4L2_MBUS_FMT_VYUY8_2X8 = 0x2007,
++      V4L2_MBUS_FMT_YUYV8_2X8 = 0x2008,
++      V4L2_MBUS_FMT_YVYU8_2X8 = 0x2009,
++      V4L2_MBUS_FMT_Y10_1X10 = 0x200a,
++      V4L2_MBUS_FMT_YUYV10_2X10 = 0x200b,
++      V4L2_MBUS_FMT_YVYU10_2X10 = 0x200c,
++      V4L2_MBUS_FMT_YUYV10_1X20 = 0x200d,
++      V4L2_MBUS_FMT_YVYU10_1X20 = 0x200e,
++
++      /* Bayer - next is 0x3009 */
++      V4L2_MBUS_FMT_SBGGR8_1X8 = 0x3001,
++      V4L2_MBUS_FMT_SGRBG8_1X8 = 0x3002,
++      V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE = 0x3003,
++      V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE = 0x3004,
++      V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE = 0x3005,
++      V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE = 0x3006,
++      V4L2_MBUS_FMT_SBGGR10_1X10 = 0x3007,
++      V4L2_MBUS_FMT_SBGGR12_1X12 = 0x3008,
+ };
+ /**
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0024-v4l-Create-v4l2-subdev-file-handle-structure.patch b/recipes-bsp/linux/linux-omap/media/0024-v4l-Create-v4l2-subdev-file-handle-structure.patch
new file mode 100644 (file)
index 0000000..726af5d
--- /dev/null
@@ -0,0 +1,243 @@
+From 47f7677adda05f6d85a35047c4aac940c46a123c Mon Sep 17 00:00:00 2001
+From: Stanimir Varbanov <svarbanov@mm-sol.com>
+Date: Fri, 21 May 2010 12:04:24 +0300
+Subject: [PATCH 24/43] v4l: Create v4l2 subdev file handle structure
+
+Used for storing subdev information per file handle and hold V4L2 file
+handle.
+
+Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
+Signed-off-by: Antti Koskipaa <antti.koskipaa@nokia.com>
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ drivers/media/Kconfig             |    9 ++++
+ drivers/media/video/v4l2-subdev.c |   85 +++++++++++++++++++++++++------------
+ include/media/v4l2-subdev.h       |   29 +++++++++++++
+ 3 files changed, 96 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
+index 6b946e6..eaf4734 100644
+--- a/drivers/media/Kconfig
++++ b/drivers/media/Kconfig
+@@ -82,6 +82,15 @@ config VIDEO_V4L1_COMPAT
+         If you are unsure as to whether this is required, answer Y.
++config VIDEO_V4L2_SUBDEV_API
++      bool "V4L2 sub-device userspace API (EXPERIMENTAL)"
++      depends on VIDEO_DEV && MEDIA_CONTROLLER && EXPERIMENTAL
++      ---help---
++        Enables the V4L2 sub-device pad-level userspace API used to configure
++        video format, size and frame rate between hardware blocks.
++
++        This API is mostly used by camera interfaces in embedded platforms.
++
+ #
+ # DVB Core
+ #
+diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
+index a49856a..15449fc 100644
+--- a/drivers/media/video/v4l2-subdev.c
++++ b/drivers/media/video/v4l2-subdev.c
+@@ -31,39 +31,69 @@
+ #include <media/v4l2-fh.h>
+ #include <media/v4l2-event.h>
++static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
++{
++#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
++      /* Allocate try format and crop in the same memory block */
++      fh->try_fmt = kzalloc((sizeof(*fh->try_fmt) + sizeof(*fh->try_crop))
++                            * sd->entity.num_pads, GFP_KERNEL);
++      if (fh->try_fmt == NULL)
++              return -ENOMEM;
++
++      fh->try_crop = (struct v4l2_rect *)
++              (fh->try_fmt + sd->entity.num_pads);
++#endif
++      return 0;
++}
++
++static void subdev_fh_free(struct v4l2_subdev_fh *fh)
++{
++#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
++      kfree(fh->try_fmt);
++      fh->try_fmt = NULL;
++      fh->try_crop = NULL;
++#endif
++}
++
+ static int subdev_open(struct file *file)
+ {
+       struct video_device *vdev = video_devdata(file);
+       struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
++      struct v4l2_subdev_fh *subdev_fh;
+ #if defined(CONFIG_MEDIA_CONTROLLER)
+       struct media_entity *entity;
+ #endif
+-      struct v4l2_fh *vfh = NULL;
+       int ret;
+       if (!sd->initialized)
+               return -EAGAIN;
+-      if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) {
+-              vfh = kzalloc(sizeof(*vfh), GFP_KERNEL);
+-              if (vfh == NULL)
+-                      return -ENOMEM;
++      subdev_fh = kzalloc(sizeof(*subdev_fh), GFP_KERNEL);
++      if (subdev_fh == NULL)
++              return -ENOMEM;
+-              ret = v4l2_fh_init(vfh, vdev);
+-              if (ret)
+-                      goto err;
++      ret = subdev_fh_init(subdev_fh, sd);
++      if (ret) {
++              kfree(subdev_fh);
++              return ret;
++      }
++
++      ret = v4l2_fh_init(&subdev_fh->vfh, vdev);
++      if (ret)
++              goto err;
+-              ret = v4l2_event_init(vfh);
++      if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) {
++              ret = v4l2_event_init(&subdev_fh->vfh);
+               if (ret)
+                       goto err;
+-              ret = v4l2_event_alloc(vfh, sd->nevents);
++              ret = v4l2_event_alloc(&subdev_fh->vfh, sd->nevents);
+               if (ret)
+                       goto err;
+-
+-              v4l2_fh_add(vfh);
+-              file->private_data = vfh;
+       }
++
++      v4l2_fh_add(&subdev_fh->vfh);
++      file->private_data = &subdev_fh->vfh;
+ #if defined(CONFIG_MEDIA_CONTROLLER)
+       if (sd->v4l2_dev->mdev) {
+               entity = media_entity_get(&sd->entity);
+@@ -73,14 +103,14 @@ static int subdev_open(struct file *file)
+               }
+       }
+ #endif
++
+       return 0;
+ err:
+-      if (vfh != NULL) {
+-              v4l2_fh_del(vfh);
+-              v4l2_fh_exit(vfh);
+-              kfree(vfh);
+-      }
++      v4l2_fh_del(&subdev_fh->vfh);
++      v4l2_fh_exit(&subdev_fh->vfh);
++      subdev_fh_free(subdev_fh);
++      kfree(subdev_fh);
+       return ret;
+ }
+@@ -92,16 +122,17 @@ static int subdev_close(struct file *file)
+       struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+ #endif
+       struct v4l2_fh *vfh = file->private_data;
++      struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh);
+ #if defined(CONFIG_MEDIA_CONTROLLER)
+       if (sd->v4l2_dev->mdev)
+               media_entity_put(&sd->entity);
+ #endif
+-      if (vfh != NULL) {
+-              v4l2_fh_del(vfh);
+-              v4l2_fh_exit(vfh);
+-              kfree(vfh);
+-      }
++      v4l2_fh_del(vfh);
++      v4l2_fh_exit(vfh);
++      subdev_fh_free(subdev_fh);
++      kfree(subdev_fh);
++      file->private_data = NULL;
+       return 0;
+ }
+@@ -110,7 +141,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+ {
+       struct video_device *vdev = video_devdata(file);
+       struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+-      struct v4l2_fh *fh = file->private_data;
++      struct v4l2_fh *vfh = file->private_data;
+       switch (cmd) {
+       case VIDIOC_QUERYCTRL:
+@@ -138,13 +169,13 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+               if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
+                       return -ENOIOCTLCMD;
+-              return v4l2_event_dequeue(fh, arg, file->f_flags & O_NONBLOCK);
++              return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK);
+       case VIDIOC_SUBSCRIBE_EVENT:
+-              return v4l2_subdev_call(sd, core, subscribe_event, fh, arg);
++              return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
+       case VIDIOC_UNSUBSCRIBE_EVENT:
+-              return v4l2_subdev_call(sd, core, unsubscribe_event, fh, arg);
++              return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
+       default:
+               return -ENOIOCTLCMD;
+diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
+index 7d55b0c..f8704ff 100644
+--- a/include/media/v4l2-subdev.h
++++ b/include/media/v4l2-subdev.h
+@@ -24,6 +24,7 @@
+ #include <media/media-entity.h>
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-dev.h>
++#include <media/v4l2-fh.h>
+ #include <media/v4l2-mediabus.h>
+ /* generic v4l2_device notify callback notification values */
+@@ -467,6 +468,34 @@ struct v4l2_subdev {
+ #define vdev_to_v4l2_subdev(vdev) \
+       container_of(vdev, struct v4l2_subdev, devnode)
++/*
++ * Used for storing subdev information per file handle
++ */
++struct v4l2_subdev_fh {
++      struct v4l2_fh vfh;
++#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
++      struct v4l2_mbus_framefmt *try_fmt;
++      struct v4l2_rect *try_crop;
++#endif
++};
++
++#define to_v4l2_subdev_fh(fh) \
++      container_of(fh, struct v4l2_subdev_fh, vfh)
++
++#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
++static inline struct v4l2_mbus_framefmt *
++v4l2_subdev_get_try_format(struct v4l2_subdev_fh *fh, unsigned int pad)
++{
++      return &fh->try_fmt[pad];
++}
++
++static inline struct v4l2_rect *
++v4l2_subdev_get_try_crop(struct v4l2_subdev_fh *fh, unsigned int pad)
++{
++      return &fh->try_crop[pad];
++}
++#endif
++
+ extern const struct v4l2_file_operations v4l2_subdev_fops;
+ static inline void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p)
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0025-v4l-subdev-Add-a-new-file-operations-class.patch b/recipes-bsp/linux/linux-omap/media/0025-v4l-subdev-Add-a-new-file-operations-class.patch
new file mode 100644 (file)
index 0000000..cf631c8
--- /dev/null
@@ -0,0 +1,93 @@
+From 4dc43ce10d8b66537a680635d4f2dbe0a1daa1d9 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Mon, 2 Aug 2010 00:05:09 +0200
+Subject: [PATCH 25/43] v4l: subdev: Add a new file operations class
+
+V4L2 sub-devices store pad formats and crop settings in the file handle.
+To let drivers initialize those settings properly, add a file::open
+operation that is called when the subdev is opened as well as a
+corresponding file::close operation.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ drivers/media/video/v4l2-subdev.c |   13 ++++++++++---
+ include/media/v4l2-subdev.h       |   10 ++++++++++
+ 2 files changed, 20 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
+index 15449fc..0f904e2 100644
+--- a/drivers/media/video/v4l2-subdev.c
++++ b/drivers/media/video/v4l2-subdev.c
+@@ -61,7 +61,7 @@ static int subdev_open(struct file *file)
+       struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+       struct v4l2_subdev_fh *subdev_fh;
+ #if defined(CONFIG_MEDIA_CONTROLLER)
+-      struct media_entity *entity;
++      struct media_entity *entity = NULL;
+ #endif
+       int ret;
+@@ -104,9 +104,17 @@ static int subdev_open(struct file *file)
+       }
+ #endif
++      ret = v4l2_subdev_call(sd, file, open, subdev_fh);
++      if (ret < 0 && ret != -ENOIOCTLCMD)
++              goto err;
++
+       return 0;
+ err:
++#if defined(CONFIG_MEDIA_CONTROLLER)
++      if (entity)
++              media_entity_put(entity);
++#endif
+       v4l2_fh_del(&subdev_fh->vfh);
+       v4l2_fh_exit(&subdev_fh->vfh);
+       subdev_fh_free(subdev_fh);
+@@ -117,13 +125,12 @@ err:
+ static int subdev_close(struct file *file)
+ {
+-#if defined(CONFIG_MEDIA_CONTROLLER)
+       struct video_device *vdev = video_devdata(file);
+       struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+-#endif
+       struct v4l2_fh *vfh = file->private_data;
+       struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh);
++      v4l2_subdev_call(sd, file, close, subdev_fh);
+ #if defined(CONFIG_MEDIA_CONTROLLER)
+       if (sd->v4l2_dev->mdev)
+               media_entity_put(&sd->entity);
+diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
+index f8704ff..af704df 100644
+--- a/include/media/v4l2-subdev.h
++++ b/include/media/v4l2-subdev.h
+@@ -175,6 +175,15 @@ struct v4l2_subdev_core_ops {
+                                struct v4l2_event_subscription *sub);
+ };
++/* open: called when the subdev device node is opened by an application.
++
++   close: called when the subdev device node is close.
++ */
++struct v4l2_subdev_file_ops {
++      int (*open)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);
++      int (*close)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);
++};
++
+ /* s_mode: switch the tuner to a specific tuner mode. Replacement of s_radio.
+    s_radio: v4l device was opened in Radio mode, to be replaced by s_mode.
+@@ -416,6 +425,7 @@ struct v4l2_subdev_ir_ops {
+ struct v4l2_subdev_ops {
+       const struct v4l2_subdev_core_ops       *core;
++      const struct v4l2_subdev_file_ops       *file;
+       const struct v4l2_subdev_tuner_ops      *tuner;
+       const struct v4l2_subdev_audio_ops      *audio;
+       const struct v4l2_subdev_video_ops      *video;
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0026-v4l-v4l2_subdev-pad-level-operations.patch b/recipes-bsp/linux/linux-omap/media/0026-v4l-v4l2_subdev-pad-level-operations.patch
new file mode 100644 (file)
index 0000000..6376245
--- /dev/null
@@ -0,0 +1,49 @@
+From 7a089b741d5c2ca3881d61e81971a1a0e464aa27 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:39:52 +0100
+Subject: [PATCH 26/43] v4l: v4l2_subdev pad-level operations
+
+Add a v4l2_subdev_pad_ops structure for the operations that need to be
+performed at the pad level such as format-related operations.
+
+Pad format-related operations use v4l2_mbus_framefmt instead of
+v4l2_format.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ include/media/v4l2-subdev.h |    5 +++++
+ 1 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
+index af704df..4f6ddba 100644
+--- a/include/media/v4l2-subdev.h
++++ b/include/media/v4l2-subdev.h
+@@ -42,6 +42,7 @@ struct v4l2_ctrl_handler;
+ struct v4l2_event_subscription;
+ struct v4l2_fh;
+ struct v4l2_subdev;
++struct v4l2_subdev_fh;
+ struct tuner_setup;
+ /* decode_vbi_line */
+@@ -423,6 +424,9 @@ struct v4l2_subdev_ir_ops {
+                               struct v4l2_subdev_ir_parameters *params);
+ };
++struct v4l2_subdev_pad_ops {
++};
++
+ struct v4l2_subdev_ops {
+       const struct v4l2_subdev_core_ops       *core;
+       const struct v4l2_subdev_file_ops       *file;
+@@ -432,6 +436,7 @@ struct v4l2_subdev_ops {
+       const struct v4l2_subdev_vbi_ops        *vbi;
+       const struct v4l2_subdev_ir_ops         *ir;
+       const struct v4l2_subdev_sensor_ops     *sensor;
++      const struct v4l2_subdev_pad_ops        *pad;
+ };
+ #define V4L2_SUBDEV_NAME_SIZE 32
+-- 
+1.6.6.1
+
diff --git a/recipes-bsp/linux/linux-omap/media/0028-v4l-v4l2_subdev-userspace-format-API.patch b/recipes-bsp/linux/linux-omap/media/0028-v4l-v4l2_subdev-userspace-format-API.patch
new file mode 100644 (file)
index 0000000..2b851d6
--- /dev/null
@@ -0,0 +1,3546 @@
+From 58fa3ca8af541e6704ac11703fc3091d856e0700 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Tue, 16 Mar 2010 00:26:04 +0100
+Subject: [PATCH 28/43] v4l: v4l2_subdev userspace format API
+
+Add a userspace API to get, set and enumerate the media format on a
+subdev pad.
+
+The format at the output of a subdev usually depends on the format at
+its input(s). The try format operation is thus not suitable for probing
+format at individual pads, as it can't modify the device state and thus
+can't remember the format tried at the input to compute the output
+format.
+
+To fix the problem, pass an extra argument to the get/set format
+operations to select the 'try' or 'active' format.
+
+The try format is used when probing the subdev. Setting the try format
+must not change the device configuration but can store data for later
+reuse. Data storage is provided at the file-handle level so applications
+probing the subdev concurently won't interfere with each other.
+
+The active format is used when configuring the subdev. It's identical to
+the format handled by the usual get/set operations.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+---
+ Documentation/DocBook/Makefile                     |    5 +-
+ Documentation/DocBook/media-entities.tmpl          |   16 +
+ Documentation/DocBook/v4l/dev-subdev.xml           |  274 +++
+ Documentation/DocBook/v4l/subdev-formats.xml       | 2416 ++++++++++++++++++++
+ Documentation/DocBook/v4l/v4l2.xml                 |    4 +
+ Documentation/DocBook/v4l/vidioc-streamon.xml      |    9 +
+ .../DocBook/v4l/vidioc-subdev-enum-frame-size.xml  |  148 ++
+ .../DocBook/v4l/vidioc-subdev-enum-mbus-code.xml   |  113 +
+ Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml  |  174 ++
+ drivers/media/video/v4l2-subdev.c                  |   49 +
+ include/linux/Kbuild                               |    1 +
+ include/linux/v4l2-subdev.h                        |   90 +
+ include/media/v4l2-subdev.h                        |   10 +
+ 13 files changed, 3308 insertions(+), 1 deletions(-)
+ create mode 100644 Documentation/DocBook/v4l/dev-subdev.xml
+ create mode 100644 Documentation/DocBook/v4l/subdev-formats.xml
+ create mode 100644 Documentation/DocBook/v4l/vidioc-subdev-enum-frame-size.xml
+ create mode 100644 Documentation/DocBook/v4l/vidioc-subdev-enum-mbus-code.xml
+ create mode 100644 Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml
+ create mode 100644 include/linux/v4l2-subdev.h
+
+diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
+index 8b6e00a..2deb069 100644
+--- a/Documentation/DocBook/Makefile
++++ b/Documentation/DocBook/Makefile
+@@ -53,7 +53,10 @@ MAN := $(patsubst %.xml, %.9, $(BOOKS))
+ mandocs: $(MAN)
+ build_images = mkdir -p $(objtree)/Documentation/DocBook/media/ && \
+-             cp $(srctree)/Documentation/DocBook/dvb/*.png $(srctree)/Documentation/DocBook/v4l/*.gif $(objtree)/Documentation/DocBook/media/
++             cp $(srctree)/Documentation/DocBook/dvb/*.png \
++                $(srctree)/Documentation/DocBook/v4l/*.gif \
++                $(srctree)/Documentation/DocBook/v4l/*.png \
++                $(objtree)/Documentation/DocBook/media/
+ xmldoclinks:
+ ifneq ($(objtree),$(srctree))
+diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
+index 679c585..538f8fe 100644
+--- a/Documentation/DocBook/media-entities.tmpl
++++ b/Documentation/DocBook/media-entities.tmpl
+@@ -86,6 +86,10 @@
+ <!ENTITY VIDIOC-S-PRIORITY "<link linkend='vidioc-g-priority'><constant>VIDIOC_S_PRIORITY</constant></link>">
+ <!ENTITY VIDIOC-S-STD "<link linkend='vidioc-g-std'><constant>VIDIOC_S_STD</constant></link>">
+ <!ENTITY VIDIOC-S-TUNER "<link linkend='vidioc-g-tuner'><constant>VIDIOC_S_TUNER</constant></link>">
++<!ENTITY VIDIOC-SUBDEV-ENUM-FRAME-SIZE "<link linkend='vidioc-subdev-enum-frame-size'><constant>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</constant></link>">
++<!ENTITY VIDIOC-SUBDEV-ENUM-MBUS-CODE "<link linkend='vidioc-subdev-enum-mbus-code'><constant>VIDIOC_SUBDEV_ENUM_MBUS_CODE</constant></link>">
++<!ENTITY VIDIOC-SUBDEV-G-FMT "<link linkend='vidioc-subdev-g-fmt'><constant>VIDIOC_SUBDEV_G_FMT</constant></link>">
++<!ENTITY VIDIOC-SUBDEV-S-FMT "<link linkend='vidioc-subdev-g-fmt'><constant>VIDIOC_SUBDEV_S_FMT</constant></link>">
+ <!ENTITY VIDIOC-TRY-ENCODER-CMD "<link linkend='vidioc-encoder-cmd'><constant>VIDIOC_TRY_ENCODER_CMD</constant></link>">
+ <!ENTITY VIDIOC-TRY-EXT-CTRLS "<link linkend='vidioc-g-ext-ctrls'><constant>VIDIOC_TRY_EXT_CTRLS</constant></link>">
+ <!ENTITY VIDIOC-TRY-FMT "<link linkend='vidioc-g-fmt'><constant>VIDIOC_TRY_FMT</constant></link>">
+@@ -107,6 +111,7 @@
+ <!ENTITY v4l2-field "enum&nbsp;<link linkend='v4l2-field'>v4l2_field</link>">
+ <!ENTITY v4l2-frmivaltypes "enum&nbsp;<link linkend='v4l2-frmivaltypes'>v4l2_frmivaltypes</link>">
+ <!ENTITY v4l2-frmsizetypes "enum&nbsp;<link linkend='v4l2-frmsizetypes'>v4l2_frmsizetypes</link>">
++<!ENTITY v4l2-mbus-pixelcode "enum&nbsp;<link linkend='v4l2-mbus-pixelcode'>v4l2_mbus_pixelcode</link>">
+ <!ENTITY v4l2-memory "enum&nbsp;<link linkend='v4l2-memory'>v4l2_memory</link>">
+ <!ENTITY v4l2-mpeg-audio-ac3-bitrate "enum&nbsp;<link linkend='v4l2-mpeg-audio-ac3-bitrate'>v4l2_mpeg_audio_ac3_bitrate</link>">
+ <!ENTITY v4l2-mpeg-audio-crc "enum&nbsp;<link linkend='v4l2-mpeg-audio-crc'>v4l2_mpeg_audio_crc</link>">
+@@ -130,6 +135,7 @@
+ <!ENTITY v4l2-mpeg-video-encoding "enum&nbsp;<link linkend='v4l2-mpeg-video-encoding'>v4l2_mpeg_video_encoding</link>">
+ <!ENTITY v4l2-power-line-frequency "enum&nbsp;<link linkend='v4l2-power-line-frequency'>v4l2_power_line_frequency</link>">
+ <!ENTITY v4l2-priority "enum&nbsp;<link linkend='v4l2-priority'>v4l2_priority</link>">
++<!ENTITY v4l2-subdev-format-whence "enum&nbsp;<link linkend='v4l2-subdev-format-whence'>v4l2_subdev_format_whence</link>">
+ <!ENTITY v4l2-tuner-type "enum&nbsp;<link linkend='v4l2-tuner-type'>v4l2_tuner_type</link>">
+ <!ENTITY v4l2-preemphasis "enum&nbsp;<link linkend='v4l2-preemphasis'>v4l2_preemphasis</link>">
+@@ -171,6 +177,7 @@
+ <!ENTITY v4l2-hw-freq-seek "struct&nbsp;<link linkend='v4l2-hw-freq-seek'>v4l2_hw_freq_seek</link>">
+ <!ENTITY v4l2-input "struct&nbsp;<link linkend='v4l2-input'>v4l2_input</link>">
+ <!ENTITY v4l2-jpegcompression "struct&nbsp;<link linkend='v4l2-jpegcompression'>v4l2_jpegcompression</link>">
++<!ENTITY v4l2-mbus-framefmt "struct&nbsp;<link linkend='v4l2-mbus-framefmt'>v4l2_mbus_framefmt</link>">
+ <!ENTITY v4l2-modulator "struct&nbsp;<link linkend='v4l2-modulator'>v4l2_modulator</link>">
+ <!ENTITY v4l2-mpeg-vbi-fmt-ivtv "struct&nbsp;<link linkend='v4l2-mpeg-vbi-fmt-ivtv'>v4l2_mpeg_vbi_fmt_ivtv</link>">
+ <!ENTITY v4l2-output "struct&nbsp;<link linkend='v4l2-output'>v4l2_output</link>">
+@@ -183,6 +190,9 @@
+ <!ENTITY v4l2-sliced-vbi-cap "struct&nbsp;<link linkend='v4l2-sliced-vbi-cap'>v4l2_sliced_vbi_cap</link>">
+ <!ENTITY v4l2-sliced-vbi-data "struct&nbsp;<link linkend='v4l2-sliced-vbi-data'>v4l2_sliced_vbi_data</link>">
+ <!ENTITY v4l2-sliced-vbi-format "struct&nbsp;<link linkend='v4l2-sliced-vbi-format'>v4l2_sliced_vbi_format</link>">
++<!ENTITY v4l2-subdev-frame-size-enum "struct&nbsp;<link linkend='v4l2-subdev-frame-size-enum'>v4l2_subdev_frame_size_enum</link>">
++<!ENTITY v4l2-subdev-format "struct&nbsp;<link linkend='v4l2-subdev-format'>v4l2_subdev_format</link>">
++<!ENTITY v4l2-subdev-mbus-code-enum "struct&nbsp;<link linkend='v4l2-subdev-mbus-code-enum'>v4l2_subdev_mbus_code_enum</link>">
+ <!ENTITY v4l2-standard "struct&nbsp;<link linkend='v4l2-standard'>v4l2_standard</link>">
+ <!ENTITY v4l2-streamparm "struct&nbsp;<link linkend='v4l2-streamparm'>v4l2_streamparm</link>">
+ <!ENTITY v4l2-timecode "struct&nbsp;<link linkend='v4l2-timecode'>v4l2_timecode</link>">
+@@ -212,6 +222,7 @@
+ <!ENTITY ENXIO "<errorcode>ENXIO</errorcode> error code">
+ <!ENTITY EMFILE "<errorcode>EMFILE</errorcode> error code">
+ <!ENTITY EPERM "<errorcode>EPERM</errorcode> error code">
++<!ENTITY EPIPE "<errorcode>EPIPE</errorcode> error code">
+ <!ENTITY ERANGE "<errorcode>ERANGE</errorcode> error code">
+ <!-- Subsections -->
+@@ -230,6 +241,7 @@
+ <!ENTITY sub-dev-raw-vbi SYSTEM "v4l/dev-raw-vbi.xml">
+ <!ENTITY sub-dev-rds SYSTEM "v4l/dev-rds.xml">
+ <!ENTITY sub-dev-sliced-vbi SYSTEM "v4l/dev-sliced-vbi.xml">
++<!ENTITY sub-dev-subdev SYSTEM "v4l/dev-subdev.xml">
+ <!ENTITY sub-dev-teletext SYSTEM "v4l/dev-teletext.xml">
+ <!ENTITY sub-driver SYSTEM "v4l/driver.xml">
+ <!ENTITY sub-libv4l SYSTEM "v4l/libv4l.xml">
+@@ -313,6 +325,10 @@
+ <!ENTITY sub-reqbufs SYSTEM "v4l/vidioc-reqbufs.xml">
+ <!ENTITY sub-s-hw-freq-seek SYSTEM "v4l/vidioc-s-hw-freq-seek.xml">
+ <!ENTITY sub-streamon SYSTEM "v4l/vidioc-streamon.xml">
++<!ENTITY sub-subdev-enum-frame-size SYSTEM "v4l/vidioc-subdev-enum-frame-size.xml">
++<!ENTITY sub-subdev-enum-mbus-code SYSTEM "v4l/vidioc-subdev-enum-mbus-code.xml">
++<!ENTITY sub-subdev-formats SYSTEM "v4l/subdev-formats.xml">
++<!ENTITY sub-subdev-g-fmt SYSTEM "v4l/vidioc-subdev-g-fmt.xml">
+ <!ENTITY sub-capture-c SYSTEM "v4l/capture.c.xml">
+ <!ENTITY sub-keytable-c SYSTEM "v4l/keytable.c.xml">
+ <!ENTITY sub-v4l2grab-c SYSTEM "v4l/v4l2grab.c.xml">
+diff --git a/Documentation/DocBook/v4l/dev-subdev.xml b/Documentation/DocBook/v4l/dev-subdev.xml
+new file mode 100644
+index 0000000..12fdca4
+--- /dev/null
++++ b/Documentation/DocBook/v4l/dev-subdev.xml
+@@ -0,0 +1,274 @@
++  <title>Sub-device Interface</title>
++
++  <para>The complex nature of V4L2 devices, where hardware is often made of
++  several integrated circuits that need to interact with each other in a
++  controlled way, leads to complex V4L2 drivers. The drivers usually reflect
++  the hardware model in software, and model the different hardware components
++  as software blocks called sub-devices.</para>
++
++  <para>V4L2 sub-devices are usually kernel-only objects. If the V4L2 driver
++  implements the media device API, they will automatically inherit from media
++  entities. Applications will be able to enumerate the sub-devices and discover
++  the hardware topology using the media entities, pads and links enumeration
++  API.</para>
++
++  <para>In addition to make sub-devices discoverable, drivers can also choose
++  to make them directly configurable by applications. When both the sub-device
++  driver and the V4L2 device driver support this, sub-devices will feature a
++  character device node on which ioctls can be called to
++  <itemizedlist>
++    <listitem>query, read and write sub-devices controls</listitem>
++    <listitem>subscribe and unsubscribe to events and retrieve them</listitem>
++    <listitem>negotiate image formats on individual pads</listitem>
++  </itemizedlist>
++  </para>
++
++  <para>Sub-device character device nodes, conventionally named
++  <filename>/dev/v4l-subdev*</filename>, use major number 81.</para>
++
++  <section>
++    <title>Controls</title>
++    <para>Most V4L2 controls are implemented by sub-device hardware. Drivers
++    usually merge all controls and expose them through video device nodes.
++    Applications can control all sub-devices through a single interface.</para>
++
++    <para>Complex devices sometimes implement the same control in different
++    pieces of hardware. This situation is common in embedded platforms, where
++    both sensors and image processing hardware implement identical functions,
++    such as contrast adjustment, white balance or faulty pixels correction. As
++    the V4L2 controls API doesn't support several identical controls in a single
++    device, all but one of the identical controls are hidden.</para>
++
++    <para>Applications can access those hidden controls through the sub-device
++    node with the V4L2 control API described in <xref linkend="control" />. The
++    ioctls behave identically as when issued on V4L2 device nodes, with the
++    exception that they deal only with controls implemented in the sub-device.
++    </para>
++
++    <para>Depending on the driver, those controls might also be exposed through
++    one (or several) V4L2 device nodes.</para>
++  </section>
++
++  <section>
++    <title>Events</title>
++    <para>V4L2 sub-devices can notify applications of events as described in
++    <xref linkend="event" />. The API behaves identically as when used on V4L2
++    device nodes, with the exception that it only deals with events generated by
++    the sub-device. Depending on the driver, those events might also be reported
++    on one (or several) V4L2 device nodes.</para>
++  </section>
++
++  <section id="pad-level-formats">
++    <title>Pad-level Formats</title>
++
++    <warning>Pad-level formats are only applicable to very complex device that
++    need to expose low-level format configuration to user space. Generic V4L2
++    applications do <emphasis>not</emphasis> need to use the API described in
++    this section.</warning>
++
++    <note>For the purpose of this section, the term
++    <wordasword>format</wordasword> means the combination of media bus data
++    format, frame width and frame height.</note>
++
++    <para>Image formats are typically negotiated on video capture and output
++    devices using the <link linkend="crop">cropping and scaling</link> ioctls.
++    The driver is responsible for configuring every block in the video pipeline
++    according to the requested format at the pipeline input and/or
++    output.</para>
++
++    <para>For complex devices, such as often found in embedded systems,
++    identical image sizes at the output of a pipeline can be achieved using
++    different hardware configurations. One such exemple is shown on
++    <xref linkend="pipeline-scaling" xrefstyle="template: Figure %n" />, where
++    image scaling can be performed on both the video sensor and the host image
++    processing hardware.</para>
++
++    <figure id="pipeline-scaling">
++      <title>Image Format Negotation on Pipelines</title>
++      <mediaobject>
++      <imageobject>
++        <imagedata fileref="pipeline.pdf" format="PS" />
++      </imageobject>
++      <imageobject>
++        <imagedata fileref="pipeline.png" format="PNG" />
++      </imageobject>
++      <textobject>
++        <phrase>High quality and high speed pipeline configuration</phrase>
++      </textobject>
++      </mediaobject>
++    </figure>
++
++    <para>The sensor scaler is usually of less quality than the host scaler, but
++    scaling on the sensor is required to achieve higher frame rates. Depending
++    on the use case (quality vs. speed), the pipeline must be configured
++    differently. Applications need to configure the formats at every point in
++    the pipeline explicitly.</para>
++
++    <para>Drivers that implement the <link linkend="media-controller-intro">media
++    API</link> can expose pad-level image format configuration to applications.
++    When they do, applications can use the &VIDIOC-SUBDEV-G-FMT; and
++    &VIDIOC-SUBDEV-S-FMT; ioctls. to negotiate formats on a per-pad basis.</para>
++
++    <para>Applications are responsible for configuring coherent parameters on
++    the whole pipeline and making sure that connected pads have compatible
++    formats. The pipeline is checked for formats mismatch at &VIDIOC-STREAMON;
++    time, and an &EPIPE; is then returned if the configuration is
++    invalid.</para>
++
++    <para>Pad-level image format configuration support can be tested by calling
++    the &VIDIOC-SUBDEV-G-FMT; ioctl on pad 0. If the driver returns an &EINVAL;
++    pad-level format configuration is not supported by the sub-device.</para>
++
++    <section>
++      <title>Format Negotiation</title>
++
++      <para>Acceptable formats on pads can (and usually do) depend on a number
++      of external parameters, such as formats on other pads, active links, or
++      even controls. Finding a combination of formats on all pads in a video
++      pipeline, acceptable to both application and driver, can't rely on formats
++      enumeration only. A format negotiation mechanism is required.</para>
++
++      <para>Central to the format negotiation mechanism are the get/set format
++      operations. When called with the <structfield>which</structfield> argument
++      set to <constant>V4L2_SUBDEV_FORMAT_TRY</constant>, the
++      &VIDIOC-SUBDEV-G-FMT; and &VIDIOC-SUBDEV-S-FMT; ioctls operate on a set of
++      formats parameters that are not connected to the hardware configuration.
++      Modifying those 'try' formats leaves the device state untouched (this
++      applies to both the software state stored in the driver and the hardware
++      state stored in the device itself).</para>
++
++      <para>While not kept as part of the device state, try formats are stored
++      in the sub-device file handles. A &VIDIOC-SUBDEV-G-FMT; call will return
++      the last try format set <emphasis>on the same sub-device file
++      handle</emphasis>. Several applications querying the same sub-device at
++      the same time will thus not interact with each other.</para>
++
++      <para>To find out whether a particular format is supported by the device,
++      applications use the &VIDIOC-SUBDEV-S-FMT; ioctl. Drivers verify and, if
++      needed, change the requested <structfield>format</structfield> based on
++      device requirements and return the possibly modified value. Applications
++      can then choose to try a different format or accept the returned value and
++      continue.</para>
++
++      <para>Formats returned by the driver during a negotiation iteration are
++      guaranteed to be supported by the device. In particular, drivers guarantee
++      that a returned format will not be further changed if passed to an
++      &VIDIOC-SUBDEV-S-FMT; call as-is (as long as external parameters, such as
++      formats on other pads or links' configuration are not changed).</para>
++
++      <para>Drivers automatically propagate formats inside sub-devices. When a
++      try or active format is set on a pad, corresponding formats on other pads
++      of the same sub-device can be modified by the driver. Drivers are free to
++      modify formats as required by the device. However, they should comply with
++      the following rules when possible:
++      <itemizedlist>
++        <listitem>Formats should be propagated from sink pads to source pads.
++      Modifying a format on a source pad should not modify the format on any
++      sink pad.</listitem>
++        <listitem>Sub-devices that scale frames using variable scaling factors
++      should reset the scale factors to default values when sink pads formats
++      are modified. If the 1:1 scaling ratio is supported, this means that
++      source pads formats should be reset to the sink pads formats.</listitem>
++      </itemizedlist>
++      </para>
++
++      <para>Formats are not propagated across links, as that would involve
++      propagating them from one sub-device file handle to another. Applications
++      must then take care to configure both ends of every link explicitly with
++      compatible formats. Identical formats on the two ends of a link are
++      guaranteed to be compatible. Drivers are free to accept different formats
++      matching device requirements as being compatible.</para>
++
++      <para><xref linkend="sample-pipeline-config" xrefstyle="template:Table %n"/>
++      shows a sample configuration sequence for the pipeline described in
++      <xref linkend="pipeline-scaling" xrefstyle="template:Figure %n"/> (table
++      columns list entity names and pad numbers).</para>
++
++      <table pgwide="0" frame="none" id="sample-pipeline-config">
++      <title>Sample Pipeline Configuration</title>
++      <tgroup cols="3">
++        <colspec colname="what"/>
++        <colspec colname="sensor-0" />
++        <colspec colname="frontend-0" />
++        <colspec colname="frontend-1" />
++        <colspec colname="scaler-0" />
++        <colspec colname="scaler-1" />
++        <thead>
++          <row>
++            <entry></entry>
++            <entry>Sensor/0</entry>
++            <entry>Frontend/0</entry>
++            <entry>Frontend/1</entry>
++            <entry>Scaler/0</entry>
++            <entry>Scaler/1</entry>
++          </row>
++        </thead>
++        <tbody valign="top">
++          <row>
++            <entry>Initial state</entry>
++            <entry>2048x1536</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++          </row>
++          <row>
++            <entry>Configure frontend input</entry>
++            <entry>2048x1536</entry>
++            <entry><emphasis>2048x1536</emphasis></entry>
++            <entry><emphasis>2046x1534</emphasis></entry>
++            <entry>-</entry>
++            <entry>-</entry>
++          </row>
++          <row>
++            <entry>Configure scaler input</entry>
++            <entry>2048x1536</entry>
++            <entry>2048x1536</entry>
++            <entry>2046x1534</entry>
++            <entry><emphasis>2046x1534</emphasis></entry>
++            <entry><emphasis>2046x1534</emphasis></entry>
++          </row>
++          <row>
++            <entry>Configure scaler output</entry>
++            <entry>2048x1536</entry>
++            <entry>2048x1536</entry>
++            <entry>2046x1534</entry>
++            <entry>2046x1534</entry>
++            <entry><emphasis>1280x960</emphasis></entry>
++          </row>
++        </tbody>
++      </tgroup>
++      </table>
++
++      <para>
++      <orderedlist>
++      <listitem>Initial state. The sensor output is set to its native 3MP
++      resolution. Resolutions on the host frontend and scaler input and output
++      pads are undefined.</listitem>
++      <listitem>The application configures the frontend input pad resolution to
++      2048x1536. The driver propagates the format to the frontend output pad.
++      Note that the propagated output format can be different, as in this case,
++      than the input format, as the hardware might need to crop pixels (for
++      instance when converting a Bayer filter pattern to RGB or YUV).</listitem>
++      <listitem>The application configures the scaler input pad resolution to
++      2046x1534 to match the frontend output resolution. The driver propagates
++      the format to the scaler output pad.</listitem>
++      <listitem>The application configures the scaler output pad resolution to
++      1280x960.</listitem>
++      </orderedlist>
++      </para>
++
++      <para>When satisfied with the try results, applications can set the active
++      formats by setting the <structfield>which</structfield> argument to
++      <constant>V4L2_SUBDEV_FORMAT_TRY</constant>. Active formats are changed
++      exactly as try formats by drivers. To avoid modifying the hardware state
++      during format negotiation, applications should negotiate try formats first
++      and then modify the active settings using the try formats returned during
++      the last negotiation iteration. This guarantees that the active format
++      will be applied as-is by the driver without being modified.
++      </para>
++    </section>
++
++  </section>
++
++  &sub-subdev-formats;
+diff --git a/Documentation/DocBook/v4l/subdev-formats.xml b/Documentation/DocBook/v4l/subdev-formats.xml
+new file mode 100644
+index 0000000..0cae572
+--- /dev/null
++++ b/Documentation/DocBook/v4l/subdev-formats.xml
+@@ -0,0 +1,2416 @@
++<section id="v4l2-mbus-format">
++  <title>Media Bus Formats</title>
++
++  <table pgwide="1" frame="none" id="v4l2-mbus-framefmt">
++    <title>struct <structname>v4l2_mbus_framefmt</structname></title>
++    <tgroup cols="3">
++      &cs-str;
++      <tbody valign="top">
++      <row>
++        <entry>__u32</entry>
++        <entry><structfield>width</structfield></entry>
++        <entry>Image width, in pixels.</entry>
++      </row>
++      <row>
++        <entry>__u32</entry>
++        <entry><structfield>height</structfield></entry>
++        <entry>Image height, in pixels.</entry>
++      </row>
++      <row>
++        <entry>__u32</entry>
++        <entry><structfield>code</structfield></entry>
++        <entry>Format code, from &v4l2-mbus-pixelcode;.</entry>
++      </row>
++      <row>
++        <entry>__u32</entry>
++        <entry><structfield>field</structfield></entry>
++        <entry>Field order, from &v4l2-field;. See
++        <xref linkend="field-order" /> for details.</entry>
++      </row>
++      <row>
++        <entry>__u32</entry>
++        <entry><structfield>colorspace</structfield></entry>
++        <entry>Image colorspace, from &v4l2-colorspace;. See
++        <xref linkend="colorspaces" /> for details.</entry>
++      </row>
++      <row>
++        <entry>__u32</entry>
++        <entry><structfield>reserved</structfield>[7]</entry>
++        <entry>Reserved for future extensions. Applications and drivers must
++        set the array to zero.</entry>
++      </row>
++      </tbody>
++    </tgroup>
++  </table>
++
++  <section id="v4l2-mbus-pixelcode">
++    <title>Media Bus Pixel Codes</title>
++
++    <para>The media bus pixel codes describe image formats as flowing over
++    physical busses (both between separate physical components and inside SoC
++    devices). This should not be confused with the V4L2 pixel formats that
++    describe, using four character codes, image formats as stored in memory.
++    </para>
++
++    <para>While there is a relationship between image formats on busses and
++    image formats in memory (a raw Bayer image won't be magically converted to
++    JPEG just by storing it to memory), there is no one-to-one correspondance
++    between them.</para>
++
++    <section>
++      <title>Packed RGB Formats</title>
++
++      <para>Those formats transfer pixel data as red, green and blue components.
++      The format code is made of the following information.
++      <itemizedlist>
++      <listitem>The red, green and blue components order code, as encoded in a
++      pixel sample. Possible values are RGB and BGR.</listitem>
++      <listitem>The number of bits per component, for each component. The values
++      can be different for all components. Common values are 555 and 565.
++      </listitem>
++      <listitem>The number of bus samples per pixel. Pixels that are wider than
++      the bus width must be transferred in multiple samples. Common values are
++      1 and 2.</listitem>
++      <listitem>The bus width.</listitem>
++      <listitem>For formats where the total number of bits per pixel is smaller
++      than the number of bus samples per pixel times the bus width, a padding
++      value stating if the bytes are padded in their most high order bits
++      (PADHI) or low order bits (PADLO).</listitem>
++      <listitem>For formats where the number of bus samples per pixel is larger
++      than 1, an endianness value stating if the pixel is transferred MSB first
++      (BE) or LSB first (LE).</listitem>
++      </itemizedlist>
++      </para>
++
++      <para>For instance, a format where pixels are encoded as 5-bits red, 5-bits
++      green and 5-bit blue values padded on the high bit, transferred as 2 8-bit
++      samples per pixel with the most significant bits (padding, red and half of
++      the green value) transferred first will be named
++      <constant>V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE</constant>.
++      </para>
++
++      <para>The following tables list existing packet RGB formats.</para>
++
++      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-rgb">
++      <title>RGB formats</title>
++      <tgroup cols="11">
++        <colspec colname="id" align="left" />
++        <colspec colname="code" align="center"/>
++        <colspec colname="bit" />
++        <colspec colnum="4" colname="b07" align="center" />
++        <colspec colnum="5" colname="b06" align="center" />
++        <colspec colnum="6" colname="b05" align="center" />
++        <colspec colnum="7" colname="b04" align="center" />
++        <colspec colnum="8" colname="b03" align="center" />
++        <colspec colnum="9" colname="b02" align="center" />
++        <colspec colnum="10" colname="b01" align="center" />
++        <colspec colnum="11" colname="b00" align="center" />
++        <spanspec namest="b07" nameend="b00" spanname="b0" />
++        <thead>
++          <row>
++            <entry>Identifier</entry>
++            <entry>Code</entry>
++            <entry></entry>
++            <entry spanname="b0">Data organization</entry>
++          </row>
++          <row>
++            <entry></entry>
++            <entry></entry>
++            <entry>Bit</entry>
++            <entry>7</entry>
++            <entry>6</entry>
++            <entry>5</entry>
++            <entry>4</entry>
++            <entry>3</entry>
++            <entry>2</entry>
++            <entry>1</entry>
++            <entry>0</entry>
++          </row>
++        </thead>
++        <tbody valign="top">
++          <row id="V4L2-MBUS-FMT-RGB444-2X8-PADHI-BE">
++            <entry>V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE</entry>
++            <entry>0x1001</entry>
++            <entry></entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>r<subscript>3</subscript></entry>
++            <entry>r<subscript>2</subscript></entry>
++            <entry>r<subscript>1</subscript></entry>
++            <entry>r<subscript>0</subscript></entry>
++          </row>
++          <row>
++            <entry></entry>
++            <entry></entry>
++            <entry></entry>
++            <entry>g<subscript>3</subscript></entry>
++            <entry>g<subscript>2</subscript></entry>
++            <entry>g<subscript>1</subscript></entry>
++            <entry>g<subscript>0</subscript></entry>
++            <entry>b<subscript>3</subscript></entry>
++            <entry>b<subscript>2</subscript></entry>
++            <entry>b<subscript>1</subscript></entry>
++            <entry>b<subscript>0</subscript></entry>
++          </row>
++          <row id="V4L2-MBUS-FMT-RGB444-2X8-PADHI-LE">
++            <entry>V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE</entry>
++            <entry>0x1002</entry>
++            <entry></entry>
++            <entry>g<subscript>3</subscript></entry>
++            <entry>g<subscript>2</subscript></entry>
++            <entry>g<subscript>1</subscript></entry>
++            <entry>g<subscript>0</subscript></entry>
++            <entry>b<subscript>3</subscript></entry>
++            <entry>b<subscript>2</subscript></entry>
++            <entry>b<subscript>1</subscript></entry>
++            <entry>b<subscript>0</subscript></entry>
++          </row>
++          <row>
++            <entry></entry>
++            <entry></entry>
++            <entry></entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>r<subscript>3</subscript></entry>
++            <entry>r<subscript>2</subscript></entry>
++            <entry>r<subscript>1</subscript></entry>
++            <entry>r<subscript>0</subscript></entry>
++          </row>
++          <row id="V4L2-MBUS-FMT-RGB555-2X8-PADHI-BE">
++            <entry>V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE</entry>
++            <entry>0x1003</entry>
++            <entry></entry>
++            <entry>0</entry>
++            <entry>r<subscript>4</subscript></entry>
++            <entry>r<subscript>3</subscript></entry>
++            <entry>r<subscript>2</subscript></entry>
++            <entry>r<subscript>1</subscript></entry>
++            <entry>r<subscript>0</subscript></entry>
++            <entry>g<subscript>4</subscript></entry>
++            <entry>g<subscript>3</subscript></entry>
++          </row>
++          <row>
++            <entry></entry>
++            <entry></entry>
++            <entry></entry>
++            <entry>g<subscript>2</subscript></entry>
++            <entry>g<subscript>1</subscript></entry>
++            <entry>g<subscript>0</subscript></entry>
++            <entry>b<subscript>4</subscript></entry>
++            <entry>b<subscript>3</subscript></entry>
++            <entry>b<subscript>2</subscript></entry>
++            <entry>b<subscript>1</subscript></entry>
++            <entry>b<subscript>0</subscript></entry>
++          </row>
++          <row id="V4L2-MBUS-FMT-RGB555-2X8-PADHI-LE">
++            <entry>V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE</entry>
++            <entry>0x1004</entry>
++            <entry></entry>
++            <entry>g<subscript>2</subscript></entry>
++            <entry>g<subscript>1</subscript></entry>
++            <entry>g<subscript>0</subscript></entry>
++            <entry>b<subscript>4</subscript></entry>
++            <entry>b<subscript>3</subscript></entry>
++            <entry>b<subscript>2</subscript></entry>
++            <entry>b<subscript>1</subscript></entry>
++            <entry>b<subscript>0</subscript></entry>
++          </row>
++          <row>
++            <entry></entry>
++            <entry></entry>
++            <entry></entry>
++            <entry>0</entry>
++            <entry>r<subscript>4</subscript></entry>
++            <entry>r<subscript>3</subscript></entry>
++            <entry>r<subscript>2</subscript></entry>
++            <entry>r<subscript>1</subscript></entry>
++            <entry>r<subscript>0</subscript></entry>
++            <entry>g<subscript>4</subscript></entry>
++            <entry>g<subscript>3</subscript></entry>
++          </row>
++          <row id="V4L2-MBUS-FMT-BGR565-2X8-BE">
++            <entry>V4L2_MBUS_FMT_BGR565_2X8_BE</entry>
++            <entry>0x1005</entry>
++            <entry></entry>
++            <entry>b<subscript>4</subscript></entry>
++            <entry>b<subscript>3</subscript></entry>
++            <entry>b<subscript>2</subscript></entry>
++            <entry>b<subscript>1</subscript></entry>
++            <entry>b<subscript>0</subscript></entry>
++            <entry>g<subscript>5</subscript></entry>
++            <entry>g<subscript>4</subscript></entry>
++            <entry>g<subscript>3</subscript></entry>
++          </row>
++          <row>
++            <entry></entry>
++            <entry></entry>
++            <entry></entry>
++            <entry>g<subscript>2</subscript></entry>
++            <entry>g<subscript>1</subscript></entry>
++            <entry>g<subscript>0</subscript></entry>
++            <entry>r<subscript>4</subscript></entry>
++            <entry>r<subscript>3</subscript></entry>
++            <entry>r<subscript>2</subscript></entry>
++            <entry>r<subscript>1</subscript></entry>
++            <entry>r<subscript>0</subscript></entry>
++          </row>
++          <row id="V4L2-MBUS-FMT-BGR565-2X8-LE">
++            <entry>V4L2_MBUS_FMT_BGR565_2X8_LE</entry>
++            <entry>0x1006</entry>
++            <entry></entry>
++            <entry>g<subscript>2</subscript></entry>
++            <entry>g<subscript>1</subscript></entry>
++            <entry>g<subscript>0</subscript></entry>
++            <entry>r<subscript>4</subscript></entry>
++            <entry>r<subscript>3</subscript></entry>
++            <entry>r<subscript>2</subscript></entry>
++            <entry>r<subscript>1</subscript></entry>
++            <entry>r<subscript>0</subscript></entry>
++          </row>
++          <row>
++            <entry></entry>
++            <entry></entry>
++            <entry></entry>
++            <entry>b<subscript>4</subscript></entry>
++            <entry>b<subscript>3</subscript></entry>
++            <entry>b<subscript>2</subscript></entry>
++            <entry>b<subscript>1</subscript></entry>
++            <entry>b<subscript>0</subscript></entry>
++            <entry>g<subscript>5</subscript></entry>
++            <entry>g<subscript>4</subscript></entry>
++            <entry>g<subscript>3</subscript></entry>
++          </row>
++          <row id="V4L2-MBUS-FMT-RGB565-2X8-BE">
++            <entry>V4L2_MBUS_FMT_RGB565_2X8_BE</entry>
++            <entry>0x1007</entry>
++            <entry></entry>
++            <entry>r<subscript>4</subscript></entry>
++            <entry>r<subscript>3</subscript></entry>
++            <entry>r<subscript>2</subscript></entry>
++            <entry>r<subscript>1</subscript></entry>
++            <entry>r<subscript>0</subscript></entry>
++            <entry>g<subscript>5</subscript></entry>
++            <entry>g<subscript>4</subscript></entry>
++            <entry>g<subscript>3</subscript></entry>
++          </row>
++          <row>
++            <entry></entry>
++            <entry></entry>
++            <entry></entry>
++            <entry>g<subscript>2</subscript></entry>
++            <entry>g<subscript>1</subscript></entry>
++            <entry>g<subscript>0</subscript></entry>
++            <entry>b<subscript>4</subscript></entry>
++            <entry>b<subscript>3</subscript></entry>
++            <entry>b<subscript>2</subscript></entry>
++            <entry>b<subscript>1</subscript></entry>
++            <entry>b<subscript>0</subscript></entry>
++          </row>
++          <row id="V4L2-MBUS-FMT-RGB565-2X8-LE">
++            <entry>V4L2_MBUS_FMT_RGB565_2X8_LE</entry>
++            <entry>0x1008</entry>
++            <entry></entry>
++            <entry>g<subscript>2</subscript></entry>
++            <entry>g<subscript>1</subscript></entry>
++            <entry>g<subscript>0</subscript></entry>
++            <entry>b<subscript>4</subscript></entry>
++            <entry>b<subscript>3</subscript></entry>
++            <entry>b<subscript>2</subscript></entry>
++            <entry>b<subscript>1</subscript></entry>
++            <entry>b<subscript>0</subscript></entry>
++          </row>
++          <row>
++            <entry></entry>
++            <entry></entry>
++            <entry></entry>
++            <entry>r<subscript>4</subscript></entry>
++            <entry>r<subscript>3</subscript></entry>
++            <entry>r<subscript>2</subscript></entry>
++            <entry>r<subscript>1</subscript></entry>
++            <entry>r<subscript>0</subscript></entry>
++            <entry>g<subscript>5</subscript></entry>
++            <entry>g<subscript>4</subscript></entry>
++            <entry>g<subscript>3</subscript></entry>
++          </row>
++        </tbody>
++      </tgroup>
++      </table>
++    </section>
++
++    <section>
++      <title>Bayer Formats</title>
++
++      <para>Those formats transfer pixel data as red, green and blue components.
++      The format code is made of the following information.
++      <itemizedlist>
++      <listitem>The red, green and blue components order code, as encoded in a
++      pixel sample. The possible values are shown in <xref
++      linkend="bayer-patterns" />.</listitem>
++      <listitem>The number of bits per pixel component. All components are
++      transferred on the same number of bits. Common values are 8, 10 and 12.
++      </listitem>
++      <listitem>If the pixel components are DPCM-compressed, a mention of the
++      DPCM compression and the number of bits per compressed pixel component.
++      </listitem>
++      <listitem>The number of bus samples per pixel. Pixels that are wider than
++      the bus width must be transferred in multiple samples. Common values are
++      1 and 2.</listitem>
++      <listitem>The bus width.</listitem>
++      <listitem>For formats where the total number of bits per pixel is smaller
++      than the number of bus samples per pixel times the bus width, a padding
++      value stating if the bytes are padded in their most high order bits
++      (PADHI) or low order bits (PADLO).</listitem>
++      <listitem>For formats where the number of bus samples per pixel is larger
++      than 1, an endianness value stating if the pixel is transferred MSB first
++      (BE) or LSB first (LE).</listitem>
++      </itemizedlist>
++      </para>
++
++      <para>For instance, a format with uncompressed 10-bit Bayer components
++      arranged in a red, green, green, blue pattern transferred as 2 8-bit
++      samples per pixel with the least significant bits transferred first will
++      be named <constant>V4L2_MBUS_FMT_SRGGB10_2X8_PADHI_LE</constant>.
++      </para>
++
++      <figure id="bayer-patterns">
++      <title>Bayer Patterns</title>
++      <mediaobject>
++        <imageobject>
++          <imagedata fileref="bayer.pdf" format="PS" />
++        </imageobject>
++        <imageobject>
++          <imagedata fileref="bayer.png" format="PNG" />
++        </imageobject>
++        <textobject>
++          <phrase>Bayer filter color patterns</phrase>
++        </textobject>
++      </mediaobject>
++      </figure>
++
++      <para>The following table lists existing packet Bayer formats. The data
++      organization is given as an example for the first pixel only.</para>
++
++      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-bayer">
++      <title>Bayer Formats</title>
++      <tgroup cols="15">
++        <colspec colname="id" align="left" />
++        <colspec colname="code" align="center"/>
++        <colspec colname="bit" />
++        <colspec colnum="4" colname="b11" align="center" />
++        <colspec colnum="5" colname="b10" align="center" />
++        <colspec colnum="6" colname="b09" align="center" />
++        <colspec colnum="7" colname="b08" align="center" />
++        <colspec colnum="8" colname="b07" align="center" />
++        <colspec colnum="9" colname="b06" align="center" />
++        <colspec colnum="10" colname="b05" align="center" />
++        <colspec colnum="11" colname="b04" align="center" />
++        <colspec colnum="12" colname="b03" align="center" />
++        <colspec colnum="13" colname="b02" align="center" />
++        <colspec colnum="14" colname="b01" align="center" />
++        <colspec colnum="15" colname="b00" align="center" />
++        <spanspec namest="b11" nameend="b00" spanname="b0" />
++        <thead>
++          <row>
++            <entry>Identifier</entry>
++            <entry>Code</entry>
++            <entry></entry>
++            <entry spanname="b0">Data organization</entry>
++          </row>
++          <row>
++            <entry></entry>
++            <entry></entry>
++            <entry>Bit</entry>
++            <entry>11</entry>
++            <entry>10</entry>
++            <entry>9</entry>
++            <entry>8</entry>
++            <entry>7</entry>
++            <entry>6</entry>
++            <entry>5</entry>
++            <entry>4</entry>
++            <entry>3</entry>
++            <entry>2</entry>
++            <entry>1</entry>
++            <entry>0</entry>
++          </row>
++        </thead>
++        <tbody valign="top">
++          <row id="V4L2-MBUS-FMT-SBGGR8-1X8">
++            <entry>V4L2_MBUS_FMT_SBGGR8_1X8</entry>
++            <entry>0x3001</entry>
++            <entry></entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>b<subscript>7</subscript></entry>
++            <entry>b<subscript>6</subscript></entry>
++            <entry>b<subscript>5</subscript></entry>
++            <entry>b<subscript>4</subscript></entry>
++            <entry>b<subscript>3</subscript></entry>
++            <entry>b<subscript>2</subscript></entry>
++            <entry>b<subscript>1</subscript></entry>
++            <entry>b<subscript>0</subscript></entry>
++          </row>
++          <row id="V4L2-MBUS-FMT-SGRBG8-1X8">
++            <entry>V4L2_MBUS_FMT_SGRBG8_1X8</entry>
++            <entry>0x3002</entry>
++            <entry></entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>g<subscript>7</subscript></entry>
++            <entry>g<subscript>6</subscript></entry>
++            <entry>g<subscript>5</subscript></entry>
++            <entry>g<subscript>4</subscript></entry>
++            <entry>g<subscript>3</subscript></entry>
++            <entry>g<subscript>2</subscript></entry>
++            <entry>g<subscript>1</subscript></entry>
++            <entry>g<subscript>0</subscript></entry>
++          </row>
++          <row id="V4L2-MBUS-FMT-SBGGR10-DPCM8-1X8">
++            <entry>V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8</entry>
++            <entry>0x300b</entry>
++            <entry></entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>b<subscript>7</subscript></entry>
++            <entry>b<subscript>6</subscript></entry>
++            <entry>b<subscript>5</subscript></entry>
++            <entry>b<subscript>4</subscript></entry>
++            <entry>b<subscript>3</subscript></entry>
++            <entry>b<subscript>2</subscript></entry>
++            <entry>b<subscript>1</subscript></entry>
++            <entry>b<subscript>0</subscript></entry>
++          </row>
++          <row id="V4L2-MBUS-FMT-SGBRG10-DPCM8-1X8">
++            <entry>V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8</entry>
++            <entry>0x300c</entry>
++            <entry></entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>g<subscript>7</subscript></entry>
++            <entry>g<subscript>6</subscript></entry>
++            <entry>g<subscript>5</subscript></entry>
++            <entry>g<subscript>4</subscript></entry>
++            <entry>g<subscript>3</subscript></entry>
++            <entry>g<subscript>2</subscript></entry>
++            <entry>g<subscript>1</subscript></entry>
++            <entry>g<subscript>0</subscript></entry>
++          </row>
++          <row id="V4L2-MBUS-FMT-SGRBG10-DPCM8-1X8">
++            <entry>V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8</entry>
++            <entry>0x3009</entry>
++            <entry></entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>g<subscript>7</subscript></entry>
++            <entry>g<subscript>6</subscript></entry>
++            <entry>g<subscript>5</subscript></entry>
++            <entry>g<subscript>4</subscript></entry>
++            <entry>g<subscript>3</subscript></entry>
++            <entry>g<subscript>2</subscript></entry>
++            <entry>g<subscript>1</subscript></entry>
++            <entry>g<subscript>0</subscript></entry>
++          </row>
++          <row id="V4L2-MBUS-FMT-SRGGB10-DPCM8-1X8">
++            <entry>V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8</entry>
++            <entry>0x300d</entry>
++            <entry></entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>r<subscript>7</subscript></entry>
++            <entry>r<subscript>6</subscript></entry>
++            <entry>r<subscript>5</subscript></entry>
++            <entry>r<subscript>4</subscript></entry>
++            <entry>r<subscript>3</subscript></entry>
++            <entry>r<subscript>2</subscript></entry>
++            <entry>r<subscript>1</subscript></entry>
++            <entry>r<subscript>0</subscript></entry>
++          </row>
++          <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADHI-BE">
++            <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE</entry>
++            <entry>0x3003</entry>
++            <entry></entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>b<subscript>9</subscript></entry>
++            <entry>b<subscript>8</subscript></entry>
++          </row>
++          <row>
++            <entry></entry>
++            <entry></entry>
++            <entry></entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>b<subscript>7</subscript></entry>
++            <entry>b<subscript>6</subscript></entry>
++            <entry>b<subscript>5</subscript></entry>
++            <entry>b<subscript>4</subscript></entry>
++            <entry>b<subscript>3</subscript></entry>
++            <entry>b<subscript>2</subscript></entry>
++            <entry>b<subscript>1</subscript></entry>
++            <entry>b<subscript>0</subscript></entry>
++          </row>
++          <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADHI-LE">
++            <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE</entry>
++            <entry>0x3004</entry>
++            <entry></entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>b<subscript>7</subscript></entry>
++            <entry>b<subscript>6</subscript></entry>
++            <entry>b<subscript>5</subscript></entry>
++            <entry>b<subscript>4</subscript></entry>
++            <entry>b<subscript>3</subscript></entry>
++            <entry>b<subscript>2</subscript></entry>
++            <entry>b<subscript>1</subscript></entry>
++            <entry>b<subscript>0</subscript></entry>
++          </row>
++          <row>
++            <entry></entry>
++            <entry></entry>
++            <entry></entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>b<subscript>9</subscript></entry>
++            <entry>b<subscript>8</subscript></entry>
++          </row>
++          <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADLO-BE">
++            <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE</entry>
++            <entry>0x3005</entry>
++            <entry></entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>b<subscript>9</subscript></entry>
++            <entry>b<subscript>8</subscript></entry>
++            <entry>b<subscript>7</subscript></entry>
++            <entry>b<subscript>6</subscript></entry>
++            <entry>b<subscript>5</subscript></entry>
++            <entry>b<subscript>4</subscript></entry>
++            <entry>b<subscript>3</subscript></entry>
++            <entry>b<subscript>2</subscript></entry>
++          </row>
++          <row>
++            <entry></entry>
++            <entry></entry>
++            <entry></entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>b<subscript>1</subscript></entry>
++            <entry>b<subscript>0</subscript></entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>0</entry>
++          </row>
++          <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADLO-LE">
++            <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE</entry>
++            <entry>0x3006</entry>
++            <entry></entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>b<subscript>1</subscript></entry>
++            <entry>b<subscript>0</subscript></entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>0</entry>
++            <entry>0</entry>
++          </row>
++          <row>
++            <entry></entry>
++            <entry></entry>
++            <entry></entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>b<subscript>9</subscript></entry>
++            <entry>b<subscript>8</subscript></entry>
++            <entry>b<subscript>7</subscript></entry>
++            <entry>b<subscript>6</subscript></entry>
++            <entry>b<subscript>5</subscript></entry>
++            <entry>b<subscript>4</subscript></entry>
++            <entry>b<subscript>3</subscript></entry>
++            <entry>b<subscript>2</subscript></entry>
++          </row>
++          <row id="V4L2-MBUS-FMT-SBGGR10-1X10">
++            <entry>V4L2_MBUS_FMT_SBGGR10_1X10</entry>
++            <entry>0x3007</entry>
++            <entry></entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>b<subscript>9</subscript></entry>
++            <entry>b<subscript>8</subscript></entry>
++            <entry>b<subscript>7</subscript></entry>
++            <entry>b<subscript>6</subscript></entry>
++          &