Merge tag 'media/v4.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 19 May 2016 00:03:51 +0000 (17:03 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 19 May 2016 00:03:51 +0000 (17:03 -0700)
Pull media updates from Mauro Carvalho Chehab:
 - added support for Intersil/Techwell TW686x-based video capture cards
 - v4l PCI skeleton driver moved to samples directory
 - Documentation cleanups and improvements
 - RC: reduced the memory footprint for IR raw events
 - tpg: Export the tpg code from vivid as a module
 - adv7180: Add device tree binding documentation
 - lots of driver improvements and fixes

* tag 'media/v4.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (173 commits)
  [media] exynos-gsc: avoid build warning without CONFIG_OF
  [media] samples: v4l: from Documentation to samples directory
  [media] dib0700: add USB ID for another STK8096-PVR ref design based card
  [media] tvp5150: propagate I2C write error in .s_register callback
  [media] tvp5150: return I2C write operation failure to callers
  [media] em28xx: add support for Hauppauge WinTV-dualHD DVB tuner
  [media] em28xx: add missing USB IDs
  [media] update cx23885 and em28xx cardlists
  [media] media: au0828 fix au0828_v4l2_device_register() to not unlock and free
  [media] c8sectpfe: Rework firmware loading mechanism
  [media] c8sectpfe: Demote print to dev_dbg
  [media] c8sectpfe: Fix broken circular buffer wp management
  [media] media-device: Simplify compat32 logic
  [media] media: i2c: ths7303: remove redundant assignment on bt
  [media] dvb-usb: hide unused functions
  [media] xilinx-vipp: remove unnecessary of_node_put
  [media] drivers/media/media-devnode: clear private_data before put_device()
  [media] drivers/media/media-device: move debug log before _devnode_unregister()
  [media] drivers/media/rc: postpone kfree(rc_dev)
  [media] media/dvb-core: forward media_create_pad_links() return value
  ...

198 files changed:
Documentation/DocBook/device-drivers.tmpl
Documentation/DocBook/media/dvb/net.xml
Documentation/DocBook/media/v4l/compat.xml
Documentation/DocBook/media/v4l/controls.xml
Documentation/DocBook/media/v4l/dev-sdr.xml
Documentation/DocBook/media/v4l/dev-subdev.xml
Documentation/DocBook/media/v4l/io.xml
Documentation/DocBook/media/v4l/selection-api.xml
Documentation/DocBook/media/v4l/subdev-formats.xml
Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml
Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml
Documentation/DocBook/media/v4l/vidioc-enum-freq-bands.xml
Documentation/DocBook/media/v4l/vidioc-expbuf.xml
Documentation/DocBook/media/v4l/vidioc-g-edid.xml
Documentation/DocBook/media/v4l/vidioc-g-selection.xml
Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
Documentation/DocBook/media/v4l/vidioc-query-dv-timings.xml
Documentation/DocBook/media/v4l/vidioc-streamon.xml
Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-interval.xml
Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-size.xml
Documentation/DocBook/media/v4l/vidioc-subdev-enum-mbus-code.xml
Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml
Documentation/DocBook/media/v4l/vidioc-subdev-g-frame-interval.xml
Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
Documentation/Makefile
Documentation/devicetree/bindings/media/i2c/adv7180.txt [new file with mode: 0644]
Documentation/devicetree/bindings/media/rcar_vin.txt
Documentation/devicetree/bindings/media/xilinx/video.txt
Documentation/video4linux/CARDLIST.cx23885
Documentation/video4linux/CARDLIST.em28xx
Documentation/video4linux/Makefile [deleted file]
Documentation/video4linux/v4l2-framework.txt
Documentation/video4linux/v4l2-pci-skeleton.c [deleted file]
Documentation/video4linux/vivid.txt
MAINTAINERS
drivers/media/common/Kconfig
drivers/media/common/Makefile
drivers/media/common/v4l2-tpg/Kconfig [new file with mode: 0644]
drivers/media/common/v4l2-tpg/Makefile [new file with mode: 0644]
drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c [new file with mode: 0644]
drivers/media/common/v4l2-tpg/v4l2-tpg-core.c [new file with mode: 0644]
drivers/media/dvb-core/dvb-usb-ids.h
drivers/media/dvb-core/dvbdev.c
drivers/media/dvb-frontends/dib0090.c
drivers/media/dvb-frontends/ds3000.c
drivers/media/dvb-frontends/m88ds3103_priv.h
drivers/media/dvb-frontends/zl10353.c
drivers/media/i2c/ad9389b.c
drivers/media/i2c/adp1653.c
drivers/media/i2c/adv7180.c
drivers/media/i2c/adv7511.c
drivers/media/i2c/adv7604.c
drivers/media/i2c/adv7842.c
drivers/media/i2c/m5mols/m5mols_controls.c
drivers/media/i2c/saa7115.c
drivers/media/i2c/smiapp/smiapp-core.c
drivers/media/i2c/smiapp/smiapp.h
drivers/media/i2c/tc358743.c
drivers/media/i2c/ths7303.c
drivers/media/i2c/tvp5150.c
drivers/media/media-device.c
drivers/media/media-devnode.c
drivers/media/media-entity.c
drivers/media/pci/Kconfig
drivers/media/pci/Makefile
drivers/media/pci/cobalt/Kconfig
drivers/media/pci/cx18/cx18-driver.h
drivers/media/pci/cx23885/cx23885-av.c
drivers/media/pci/ivtv/ivtv-driver.h
drivers/media/pci/smipcie/smipcie-ir.c
drivers/media/pci/smipcie/smipcie-main.c
drivers/media/pci/smipcie/smipcie.h
drivers/media/pci/sta2x11/sta2x11_vip.c
drivers/media/pci/tw686x/Kconfig [new file with mode: 0644]
drivers/media/pci/tw686x/Makefile [new file with mode: 0644]
drivers/media/pci/tw686x/tw686x-audio.c [new file with mode: 0644]
drivers/media/pci/tw686x/tw686x-core.c [new file with mode: 0644]
drivers/media/pci/tw686x/tw686x-regs.h [new file with mode: 0644]
drivers/media/pci/tw686x/tw686x-video.c [new file with mode: 0644]
drivers/media/pci/tw686x/tw686x.h [new file with mode: 0644]
drivers/media/pci/zoran/videocodec.c
drivers/media/platform/Kconfig
drivers/media/platform/am437x/am437x-vpfe.c
drivers/media/platform/exynos-gsc/gsc-core.c
drivers/media/platform/exynos-gsc/gsc-core.h
drivers/media/platform/exynos4-is/fimc-core.c
drivers/media/platform/exynos4-is/media-dev.c
drivers/media/platform/exynos4-is/mipi-csis.c
drivers/media/platform/omap3isp/ispvideo.c
drivers/media/platform/s5p-g2d/g2d.c
drivers/media/platform/s5p-g2d/g2d.h
drivers/media/platform/s5p-jpeg/jpeg-core.c
drivers/media/platform/s5p-mfc/s5p_mfc.c
drivers/media/platform/s5p-tv/mixer.h
drivers/media/platform/s5p-tv/mixer_grp_layer.c
drivers/media/platform/s5p-tv/mixer_video.c
drivers/media/platform/s5p-tv/mixer_vp_layer.c
drivers/media/platform/soc_camera/Kconfig
drivers/media/platform/soc_camera/rcar_vin.c
drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c
drivers/media/platform/vivid/Kconfig
drivers/media/platform/vivid/Makefile
drivers/media/platform/vivid/vivid-core.c
drivers/media/platform/vivid/vivid-core.h
drivers/media/platform/vivid/vivid-kthread-cap.c
drivers/media/platform/vivid/vivid-rds-gen.c
drivers/media/platform/vivid/vivid-tpg-colors.c [deleted file]
drivers/media/platform/vivid/vivid-tpg-colors.h [deleted file]
drivers/media/platform/vivid/vivid-tpg.c [deleted file]
drivers/media/platform/vivid/vivid-tpg.h [deleted file]
drivers/media/platform/vivid/vivid-vid-cap.c
drivers/media/platform/vivid/vivid-vid-common.c
drivers/media/platform/vivid/vivid-vid-common.h
drivers/media/platform/vivid/vivid-vid-out.c
drivers/media/platform/vsp1/vsp1.h
drivers/media/platform/vsp1/vsp1_bru.c
drivers/media/platform/vsp1/vsp1_bru.h
drivers/media/platform/vsp1/vsp1_dl.c
drivers/media/platform/vsp1/vsp1_dl.h
drivers/media/platform/vsp1/vsp1_drm.c
drivers/media/platform/vsp1/vsp1_drm.h
drivers/media/platform/vsp1/vsp1_drv.c
drivers/media/platform/vsp1/vsp1_entity.c
drivers/media/platform/vsp1/vsp1_entity.h
drivers/media/platform/vsp1/vsp1_hsit.c
drivers/media/platform/vsp1/vsp1_lif.c
drivers/media/platform/vsp1/vsp1_lut.c
drivers/media/platform/vsp1/vsp1_lut.h
drivers/media/platform/vsp1/vsp1_pipe.c
drivers/media/platform/vsp1/vsp1_pipe.h
drivers/media/platform/vsp1/vsp1_regs.h
drivers/media/platform/vsp1/vsp1_rpf.c
drivers/media/platform/vsp1/vsp1_rwpf.c
drivers/media/platform/vsp1/vsp1_rwpf.h
drivers/media/platform/vsp1/vsp1_sru.c
drivers/media/platform/vsp1/vsp1_sru.h
drivers/media/platform/vsp1/vsp1_uds.c
drivers/media/platform/vsp1/vsp1_uds.h
drivers/media/platform/vsp1/vsp1_video.c
drivers/media/platform/vsp1/vsp1_video.h
drivers/media/platform/vsp1/vsp1_wpf.c
drivers/media/platform/xilinx/xilinx-vipp.c
drivers/media/rc/ati_remote.c
drivers/media/rc/mceusb.c
drivers/media/rc/rc-main.c
drivers/media/tuners/qm1d1c0042.c
drivers/media/tuners/si2157.c
drivers/media/tuners/si2157_priv.h
drivers/media/usb/au0828/au0828-core.c
drivers/media/usb/au0828/au0828-video.c
drivers/media/usb/au0828/au0828.h
drivers/media/usb/cx231xx/cx231xx-417.c
drivers/media/usb/cx231xx/cx231xx-core.c
drivers/media/usb/dvb-usb-v2/af9035.h
drivers/media/usb/dvb-usb/az6027.c
drivers/media/usb/dvb-usb/dib0700_devices.c
drivers/media/usb/dvb-usb/dibusb-common.c
drivers/media/usb/dvb-usb/dw2102.c
drivers/media/usb/dvb-usb/pctv452e.c
drivers/media/usb/em28xx/Kconfig
drivers/media/usb/em28xx/em28xx-cards.c
drivers/media/usb/em28xx/em28xx-dvb.c
drivers/media/usb/em28xx/em28xx-reg.h
drivers/media/usb/em28xx/em28xx.h
drivers/media/usb/go7007/go7007-v4l2.c
drivers/media/usb/pvrusb2/pvrusb2-hdw.c
drivers/media/v4l2-core/v4l2-compat-ioctl32.c
drivers/media/v4l2-core/v4l2-dev.c
drivers/media/v4l2-core/v4l2-ioctl.c
drivers/media/v4l2-core/v4l2-mc.c
drivers/media/v4l2-core/v4l2-subdev.c
drivers/staging/media/Kconfig
drivers/staging/media/Makefile
drivers/staging/media/bcm2048/radio-bcm2048.c
drivers/staging/media/davinci_vpfe/vpfe_video.c
drivers/staging/media/omap4iss/iss_video.c
drivers/staging/media/tw686x-kh/Kconfig [new file with mode: 0644]
drivers/staging/media/tw686x-kh/Makefile [new file with mode: 0644]
drivers/staging/media/tw686x-kh/TODO [new file with mode: 0644]
drivers/staging/media/tw686x-kh/tw686x-kh-core.c [new file with mode: 0644]
drivers/staging/media/tw686x-kh/tw686x-kh-regs.h [new file with mode: 0644]
drivers/staging/media/tw686x-kh/tw686x-kh-video.c [new file with mode: 0644]
drivers/staging/media/tw686x-kh/tw686x-kh.h [new file with mode: 0644]
include/media/media-device.h
include/media/media-entity.h
include/media/rc-core.h
include/media/v4l2-dev.h
include/media/v4l2-device.h
include/media/v4l2-rect.h [new file with mode: 0644]
include/media/v4l2-subdev.h
include/media/v4l2-tpg-colors.h [new file with mode: 0644]
include/media/v4l2-tpg.h [new file with mode: 0644]
include/media/vsp1.h
include/uapi/linux/videodev2.h
samples/Makefile
samples/v4l/Makefile [new file with mode: 0644]
samples/v4l/v4l2-pci-skeleton.c [new file with mode: 0644]

index 184f3c7..893b2ca 100644 (file)
@@ -233,6 +233,7 @@ X!Isound/sound_firmware.c
 !Iinclude/media/v4l2-mediabus.h
 !Iinclude/media/v4l2-mem2mem.h
 !Iinclude/media/v4l2-of.h
+!Iinclude/media/v4l2-rect.h
 !Iinclude/media/v4l2-subdev.h
 !Iinclude/media/videobuf2-core.h
 !Iinclude/media/videobuf2-v4l2.h
index d2e44b7..da095ed 100644 (file)
@@ -15,7 +15,7 @@
     that are present on the transport stream. This is done through
     <constant>/dev/dvb/adapter?/net?</constant> device node.
     The data will be available via virtual <constant>dvb?_?</constant>
-    network interfaces, and will be controled/routed via the standard
+    network interfaces, and will be controlled/routed via the standard
     ip tools (like ip, route, netstat, ifconfig, etc).</para>
 <para> Data types and and ioctl definitions are defined via
     <constant>linux/dvb/net.h</constant> header.</para>
index 5399e89..82fa328 100644 (file)
@@ -2685,10 +2685,6 @@ hardware may support both.</para>
 and may change in the future.</para>
 
       <itemizedlist>
-        <listitem>
-         <para>Video Output Overlay (OSD) Interface, <xref
-           linkend="osd" />.</para>
-        </listitem>
         <listitem>
          <para>&VIDIOC-DBG-G-REGISTER; and &VIDIOC-DBG-S-REGISTER;
 ioctls.</para>
@@ -2696,40 +2692,6 @@ ioctls.</para>
         <listitem>
          <para>&VIDIOC-DBG-G-CHIP-INFO; ioctl.</para>
         </listitem>
-        <listitem>
-         <para>&VIDIOC-ENUM-DV-TIMINGS;, &VIDIOC-QUERY-DV-TIMINGS; and
-         &VIDIOC-DV-TIMINGS-CAP; ioctls.</para>
-        </listitem>
-        <listitem>
-         <para>Flash API. <xref linkend="flash-controls" /></para>
-        </listitem>
-        <listitem>
-         <para>&VIDIOC-CREATE-BUFS; and &VIDIOC-PREPARE-BUF; ioctls.</para>
-        </listitem>
-        <listitem>
-         <para>Selection API. <xref linkend="selection-api" /></para>
-        </listitem>
-        <listitem>
-         <para>Sub-device selection API: &VIDIOC-SUBDEV-G-SELECTION;
-         and &VIDIOC-SUBDEV-S-SELECTION; ioctls.</para>
-        </listitem>
-        <listitem>
-         <para>Support for frequency band enumeration: &VIDIOC-ENUM-FREQ-BANDS; ioctl.</para>
-        </listitem>
-        <listitem>
-         <para>Vendor and device specific media bus pixel formats.
-           <xref linkend="v4l2-mbus-vendor-spec-fmts" />.</para>
-        </listitem>
-        <listitem>
-         <para>Importing DMABUF file descriptors as a new IO method described
-         in <xref linkend="dmabuf" />.</para>
-        </listitem>
-        <listitem>
-         <para>Exporting DMABUF files using &VIDIOC-EXPBUF; ioctl.</para>
-        </listitem>
-        <listitem>
-         <para>Software Defined Radio (SDR) Interface, <xref linkend="sdr" />.</para>
-        </listitem>
       </itemizedlist>
     </section>
 
index 361040e..81efa88 100644 (file)
@@ -4272,13 +4272,6 @@ manually or automatically if set to zero. Unit, range and step are driver-specif
     <section id="flash-controls">
       <title>Flash Control Reference</title>
 
-      <note>
-       <title>Experimental</title>
-
-       <para>This is an <link linkend="experimental">experimental</link>
-interface and may change in the future.</para>
-      </note>
-
       <para>
        The V4L2 flash controls are intended to provide generic access
        to flash controller devices. Flash controller devices are
@@ -4743,14 +4736,6 @@ interface and may change in the future.</para>
     <section id="image-source-controls">
       <title>Image Source Control Reference</title>
 
-      <note>
-       <title>Experimental</title>
-
-       <para>This is an <link
-       linkend="experimental">experimental</link> interface and may
-       change in the future.</para>
-      </note>
-
       <para>
        The Image Source control class is intended for low-level
        control of image source devices such as image sensors. The
@@ -4862,14 +4847,6 @@ interface and may change in the future.</para>
     <section id="image-process-controls">
       <title>Image Process Control Reference</title>
 
-      <note>
-       <title>Experimental</title>
-
-       <para>This is an <link
-       linkend="experimental">experimental</link> interface and may
-       change in the future.</para>
-      </note>
-
       <para>
        The Image Process control class is intended for low-level control of
        image processing functions. Unlike
@@ -4955,14 +4932,6 @@ interface and may change in the future.</para>
     <section id="dv-controls">
       <title>Digital Video Control Reference</title>
 
-      <note>
-       <title>Experimental</title>
-
-       <para>This is an <link
-       linkend="experimental">experimental</link> interface and may
-       change in the future.</para>
-      </note>
-
       <para>
        The Digital Video control class is intended to control receivers
        and transmitters for <ulink url="http://en.wikipedia.org/wiki/Vga">VGA</ulink>,
index a659771..6da1157 100644 (file)
@@ -1,11 +1,5 @@
   <title>Software Defined Radio Interface (SDR)</title>
 
-  <note>
-    <title>Experimental</title>
-    <para>This is an <link linkend="experimental"> experimental </link>
-    interface and may change in the future.</para>
-  </note>
-
   <para>
 SDR is an abbreviation of Software Defined Radio, the radio device
 which uses application software for modulation or demodulation. This interface
index 4f0ba58..f4bc27a 100644 (file)
@@ -1,11 +1,5 @@
   <title>Sub-device Interface</title>
 
-  <note>
-    <title>Experimental</title>
-    <para>This is an <link linkend="experimental">experimental</link>
-    interface and may change in the future.</para>
-  </note>
-
   <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
index 144158b..e09025d 100644 (file)
@@ -475,12 +475,6 @@ rest should be evident.</para>
   <section id="dmabuf">
     <title>Streaming I/O (DMA buffer importing)</title>
 
-    <note>
-      <title>Experimental</title>
-      <para>This is an <link linkend="experimental">experimental</link>
-      interface and may change in the future.</para>
-    </note>
-
 <para>The DMABUF framework provides a generic method for sharing buffers
 between multiple devices. Device drivers that support DMABUF can export a DMA
 buffer to userspace as a file descriptor (known as the exporter role), import a
index 28cbded..b764cba 100644 (file)
@@ -1,13 +1,6 @@
 <section id="selection-api">
 
-  <title>Experimental API for cropping, composing and scaling</title>
-
-      <note>
-       <title>Experimental</title>
-
-       <para>This is an <link linkend="experimental">experimental</link>
-interface and may change in the future.</para>
-      </note>
+  <title>API for cropping, composing and scaling</title>
 
   <section>
     <title>Introduction</title>
index 4e73345..199c84e 100644 (file)
@@ -4002,12 +4002,6 @@ see <xref linkend="colorspaces" />.</entry>
     <section id="v4l2-mbus-vendor-spec-fmts">
       <title>Vendor and Device Specific Formats</title>
 
-      <note>
-       <title>Experimental</title>
-       <para>This is an <link linkend="experimental">experimental</link>
-interface and may change in the future.</para>
-      </note>
-
       <para>This section lists complex data formats that are either vendor or
        device specific.
       </para>
index d81fa0d..6528e97 100644 (file)
   <refsect1>
     <title>Description</title>
 
-    <note>
-      <title>Experimental</title>
-      <para>This is an <link linkend="experimental"> experimental </link>
-      interface and may change in the future.</para>
-    </note>
-
     <para>This ioctl is used to create buffers for <link linkend="mmap">memory
 mapped</link> or <link linkend="userp">user pointer</link> or <link
 linkend="dmabuf">DMA buffer</link> I/O. It can be used as an alternative or in
index a2017bf..ca9ffce 100644 (file)
   <refsect1>
     <title>Description</title>
 
-    <note>
-      <title>Experimental</title>
-      <para>This is an <link linkend="experimental"> experimental </link>
-      interface and may change in the future.</para>
-    </note>
-
-    <para>To query the capabilities of the DV receiver/transmitter applications
-can call the <constant>VIDIOC_DV_TIMINGS_CAP</constant> ioctl on a video node
+    <para>To query the capabilities of the DV receiver/transmitter applications initialize the
+<structfield>pad</structfield> field to 0, zero the reserved array of &v4l2-dv-timings-cap;
+and call the <constant>VIDIOC_DV_TIMINGS_CAP</constant> ioctl on a video node
 and the driver will fill in the structure. Note that drivers may return
 different values after switching the video input or output.</para>
 
@@ -65,8 +60,8 @@ queried by calling the <constant>VIDIOC_SUBDEV_DV_TIMINGS_CAP</constant> ioctl
 directly on a subdevice node. The capabilities are specific to inputs (for DV
 receivers) or outputs (for DV transmitters), applications must specify the
 desired pad number in the &v4l2-dv-timings-cap; <structfield>pad</structfield>
-field. Attempts to query capabilities on a pad that doesn't support them will
-return an &EINVAL;.</para>
+field and zero the <structfield>reserved</structfield> array. Attempts to query
+capabilities on a pad that doesn't support them will return an &EINVAL;.</para>
 
     <table pgwide="1" frame="none" id="v4l2-bt-timings-cap">
       <title>struct <structname>v4l2_bt_timings_cap</structname></title>
@@ -145,7 +140,8 @@ return an &EINVAL;.</para>
          <row>
            <entry>__u32</entry>
            <entry><structfield>reserved</structfield>[2]</entry>
-           <entry>Reserved for future extensions. Drivers must set the array to zero.</entry>
+           <entry>Reserved for future extensions. Drivers and applications must
+           set the array to zero.</entry>
          </row>
          <row>
            <entry>union</entry>
index 6e3cadd..9b3d420 100644 (file)
   <refsect1>
     <title>Description</title>
 
-    <note>
-      <title>Experimental</title>
-      <para>This is an <link linkend="experimental"> experimental </link>
-      interface and may change in the future.</para>
-    </note>
-
     <para>While some DV receivers or transmitters support a wide range of timings, others
 support only a limited number of timings. With this ioctl applications can enumerate a list
 of known supported timings. Call &VIDIOC-DV-TIMINGS-CAP; to check if it also supports other
 standards or even custom timings that are not in this list.</para>
 
     <para>To query the available timings, applications initialize the
-<structfield>index</structfield> field and zero the reserved array of &v4l2-enum-dv-timings;
-and call the <constant>VIDIOC_ENUM_DV_TIMINGS</constant> ioctl on a video node with a
+<structfield>index</structfield> field, set the <structfield>pad</structfield> field to 0,
+zero the reserved array of &v4l2-enum-dv-timings; and call the
+<constant>VIDIOC_ENUM_DV_TIMINGS</constant> ioctl on a video node with a
 pointer to this structure. Drivers fill the rest of the structure or return an
 &EINVAL; when the index is out of bounds. To enumerate all supported DV timings,
 applications shall begin at index zero, incrementing by one until the
index 4e8ea65..a0608ab 100644 (file)
   <refsect1>
     <title>Description</title>
 
-    <note>
-      <title>Experimental</title>
-      <para>This is an <link linkend="experimental"> experimental </link>
-      interface and may change in the future.</para>
-    </note>
-
     <para>Enumerates the frequency bands that a tuner or modulator supports.
 To do this applications initialize the <structfield>tuner</structfield>,
 <structfield>type</structfield> and <structfield>index</structfield> fields,
index 0ae0b6a..a6558a6 100644 (file)
   <refsect1>
     <title>Description</title>
 
-    <note>
-      <title>Experimental</title>
-      <para>This is an <link linkend="experimental"> experimental </link>
-      interface and may change in the future.</para>
-    </note>
-
 <para>This ioctl is an extension to the <link linkend="mmap">memory
 mapping</link> I/O method, therefore it is available only for
 <constant>V4L2_MEMORY_MMAP</constant> buffers.  It can be used to export a
index 2702536..b7602d3 100644 (file)
@@ -1,6 +1,6 @@
 <refentry id="vidioc-g-edid">
   <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_EDID, VIDIOC_S_EDID</refentrytitle>
+    <refentrytitle>ioctl VIDIOC_G_EDID, VIDIOC_S_EDID, VIDIOC_SUBDEV_G_EDID, VIDIOC_SUBDEV_S_EDID</refentrytitle>
     &manvol;
   </refmeta>
 
@@ -71,7 +71,8 @@
 
     <para>To get the EDID data the application has to fill in the <structfield>pad</structfield>,
     <structfield>start_block</structfield>, <structfield>blocks</structfield> and <structfield>edid</structfield>
-    fields and call <constant>VIDIOC_G_EDID</constant>. The current EDID from block
+    fields, zero the <structfield>reserved</structfield> array and call
+    <constant>VIDIOC_G_EDID</constant>. The current EDID from block
     <structfield>start_block</structfield> and of size <structfield>blocks</structfield>
     will be placed in the memory <structfield>edid</structfield> points to. The <structfield>edid</structfield>
     pointer must point to memory at least <structfield>blocks</structfield>&nbsp;*&nbsp;128 bytes
@@ -92,8 +93,9 @@
     the driver will set <structfield>blocks</structfield> to 0 and it returns 0.</para>
 
     <para>To set the EDID blocks of a receiver the application has to fill in the <structfield>pad</structfield>,
-    <structfield>blocks</structfield> and <structfield>edid</structfield> fields and set
-    <structfield>start_block</structfield> to 0. It is not possible to set part of an EDID,
+    <structfield>blocks</structfield> and <structfield>edid</structfield> fields, set
+    <structfield>start_block</structfield> to 0 and zero the <structfield>reserved</structfield> array.
+    It is not possible to set part of an EDID,
     it is always all or nothing. Setting the EDID data is only valid for receivers as it makes
     no sense for a transmitter.</para>
 
index 7865351..9523bc5 100644 (file)
   <refsect1>
     <title>Description</title>
 
-    <note>
-      <title>Experimental</title>
-      <para>This is an <link linkend="experimental"> experimental </link>
-      interface and may change in the future.</para>
-    </note>
-
     <para>The ioctls are used to query and configure selection rectangles.</para>
 
 <para>To query the cropping (composing) rectangle set &v4l2-selection;
index fa7ad7e..7bde698 100644 (file)
   <refsect1>
     <title>Description</title>
 
-    <note>
-      <title>Experimental</title>
-      <para>This is an <link linkend="experimental"> experimental </link>
-      interface and may change in the future.</para>
-    </note>
-
     <para>Applications can optionally call the
 <constant>VIDIOC_PREPARE_BUF</constant> ioctl to pass ownership of the buffer
 to the driver before actually enqueuing it, using the
index 0c93677..d41bf47 100644 (file)
@@ -50,12 +50,6 @@ input</refpurpose>
   <refsect1>
     <title>Description</title>
 
-    <note>
-      <title>Experimental</title>
-      <para>This is an <link linkend="experimental"> experimental </link>
-      interface and may change in the future.</para>
-    </note>
-
     <para>The hardware may be able to detect the current DV timings
 automatically, similar to sensing the video standard. To do so, applications
 call <constant>VIDIOC_QUERY_DV_TIMINGS</constant> with a pointer to a
index df2c63d..89fd7ce 100644 (file)
@@ -123,6 +123,14 @@ synchronize with other events.</para>
          </para>
        </listitem>
       </varlistentry>
+      <varlistentry>
+       <term><errorcode>ENOLINK</errorcode></term>
+       <listitem>
+         <para>The driver implements Media Controller interface and
+         the pipeline link configuration is invalid.
+         </para>
+       </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 </refentry>
index cff59f5..9d0251a 100644 (file)
   <refsect1>
     <title>Description</title>
 
-    <note>
-      <title>Experimental</title>
-      <para>This is an <link linkend="experimental">experimental</link>
-      interface and may change in the future.</para>
-    </note>
-
     <para>This ioctl lets applications enumerate available frame intervals on a
     given sub-device pad. Frame intervals only makes sense for sub-devices that
     can control the frame period on their own. This includes, for instance,
index abd545e..9b91b83 100644 (file)
   <refsect1>
     <title>Description</title>
 
-    <note>
-      <title>Experimental</title>
-      <para>This is an <link linkend="experimental">experimental</link>
-      interface and may change in the future.</para>
-    </note>
-
     <para>This ioctl allows applications to enumerate all frame sizes
     supported by a sub-device on the given pad for the given media bus format.
     Supported formats can be retrieved with the &VIDIOC-SUBDEV-ENUM-MBUS-CODE;
index 0bcb278..c67256a 100644 (file)
   <refsect1>
     <title>Description</title>
 
-    <note>
-      <title>Experimental</title>
-      <para>This is an <link linkend="experimental">experimental</link>
-      interface and may change in the future.</para>
-    </note>
-
     <para>To enumerate media bus formats available at a given sub-device pad
     applications initialize the <structfield>pad</structfield>, <structfield>which</structfield>
     and <structfield>index</structfield> fields of &v4l2-subdev-mbus-code-enum; and
index a67cde6..781089c 100644 (file)
   <refsect1>
     <title>Description</title>
 
-    <note>
-      <title>Experimental</title>
-      <para>This is an <link linkend="experimental">experimental</link>
-      interface and may change in the future.</para>
-    </note>
-
     <para>These ioctls are used to negotiate the frame format at specific
     subdev pads in the image pipeline.</para>
 
index 0bc3ea2..848ec78 100644 (file)
   <refsect1>
     <title>Description</title>
 
-    <note>
-      <title>Experimental</title>
-      <para>This is an <link linkend="experimental">experimental</link>
-      interface and may change in the future.</para>
-    </note>
-
     <para>These ioctls are used to get and set the frame interval at specific
     subdev pads in the image pipeline. The frame interval only makes sense for
     sub-devices that can control the frame period on their own. This includes,
index c62a736..8346b2e 100644 (file)
   <refsect1>
     <title>Description</title>
 
-    <note>
-      <title>Experimental</title>
-      <para>This is an <link linkend="experimental">experimental</link>
-      interface and may change in the future.</para>
-    </note>
-
     <para>The selections are used to configure various image
     processing functionality performed by the subdevs which affect the
     image size. This currently includes cropping, scaling and
index 1207d79..f3b04d2 100644 (file)
@@ -1,4 +1,3 @@
 subdir-y := accounting auxdisplay blackfin connector \
        filesystems filesystems ia64 laptops mic misc-devices \
-       networking pcmcia prctl ptp timers vDSO video4linux \
-       watchdog
+       networking pcmcia prctl ptp timers vDSO watchdog
diff --git a/Documentation/devicetree/bindings/media/i2c/adv7180.txt b/Documentation/devicetree/bindings/media/i2c/adv7180.txt
new file mode 100644 (file)
index 0000000..0d50115
--- /dev/null
@@ -0,0 +1,29 @@
+* Analog Devices ADV7180 analog video decoder family
+
+The adv7180 family devices are used to capture analog video to different
+digital interfaces like MIPI CSI-2 or parallel video.
+
+Required Properties :
+- compatible : value must be one of
+               "adi,adv7180"
+               "adi,adv7182"
+               "adi,adv7280"
+               "adi,adv7280-m"
+               "adi,adv7281"
+               "adi,adv7281-m"
+               "adi,adv7281-ma"
+               "adi,adv7282"
+               "adi,adv7282-m"
+
+Example:
+
+       i2c0@1c22000 {
+               ...
+               ...
+               adv7180@21 {
+                       compatible = "adi,adv7180";
+                       reg = <0x21>;
+               };
+               ...
+       };
+
index 619193c..6a4e61c 100644 (file)
@@ -5,14 +5,22 @@ The rcar_vin device provides video input capabilities for the Renesas R-Car
 family of devices. The current blocks are always slaves and suppot one input
 channel which can be either RGB, YUYV or BT656.
 
- - compatible: Must be one of the following
+ - compatible: Must be one or more of the following
    - "renesas,vin-r8a7795" for the R8A7795 device
    - "renesas,vin-r8a7794" for the R8A7794 device
    - "renesas,vin-r8a7793" for the R8A7793 device
+   - "renesas,vin-r8a7792" for the R8A7792 device
    - "renesas,vin-r8a7791" for the R8A7791 device
    - "renesas,vin-r8a7790" for the R8A7790 device
    - "renesas,vin-r8a7779" for the R8A7779 device
    - "renesas,vin-r8a7778" for the R8A7778 device
+   - "renesas,rcar-gen2-vin" for a generic R-Car Gen2 compatible device.
+   - "renesas,rcar-gen3-vin" for a generic R-Car Gen3 compatible device.
+
+   When compatible with the generic version nodes must list the
+   SoC-specific version corresponding to the platform first
+   followed by the generic version.
+
  - reg: the register base and size for the device registers
  - interrupts: the interrupt for the device
  - clocks: Reference to the parent clock
@@ -37,7 +45,7 @@ Device node example
        };
 
         vin0: vin@0xe6ef0000 {
-                compatible = "renesas,vin-r8a7790";
+                compatible = "renesas,vin-r8a7790", "renesas,rcar-gen2-vin";
                 clocks = <&mstp8_clks R8A7790_CLK_VIN0>;
                 reg = <0 0xe6ef0000 0 0x1000>;
                 interrupts = <0 188 IRQ_TYPE_LEVEL_HIGH>;
index cbd46fa..68ac210 100644 (file)
@@ -20,7 +20,7 @@ The following properties are common to all Xilinx video IP cores.
 - xlnx,video-format: This property represents a video format transmitted on an
   AXI bus between video IP cores, using its VF code as defined in "AXI4-Stream
   Video IP and System Design Guide" [UG934]. How the format relates to the IP
-  core is decribed in the IP core bindings documentation.
+  core is described in the IP core bindings documentation.
 
 - xlnx,video-width: This property qualifies the video format with the sample
   width expressed as a number of bits per pixel component. All components must
index 44a4cfb..85a8fdc 100644 (file)
@@ -52,3 +52,5 @@
  51 -> DVBSky T982                                         [4254:0982]
  52 -> Hauppauge WinTV-HVR5525                             [0070:f038]
  53 -> Hauppauge WinTV Starburst                           [0070:c12a]
+ 54 -> ViewCast 260e                                       [1576:0260]
+ 55 -> ViewCast 460e                                       [1576:0460]
index 6720999..6784220 100644 (file)
@@ -76,9 +76,9 @@
  75 -> Dikom DK300                              (em2882)
  76 -> KWorld PlusTV 340U or UB435-Q (ATSC)     (em2870)        [1b80:a340]
  77 -> EM2874 Leadership ISDBT                  (em2874)
- 78 -> PCTV nanoStick T2 290e                   (em28174)
+ 78 -> PCTV nanoStick T2 290e                   (em28174)       [2013:024f]
  79 -> Terratec Cinergy H5                      (em2884)        [eb1a:2885,0ccd:10a2,0ccd:10ad,0ccd:10b6]
- 80 -> PCTV DVB-S2 Stick (460e)                 (em28174)
+ 80 -> PCTV DVB-S2 Stick (460e)                 (em28174)       [2013:024c]
  81 -> Hauppauge WinTV HVR 930C                 (em2884)        [2040:1605]
  82 -> Terratec Cinergy HTC Stick               (em2884)        [0ccd:00b2]
  83 -> Honestech Vidbox NW03                    (em2860)        [eb1a:5006]
  89 -> Delock 61959                             (em2874)        [1b80:e1cc]
  90 -> KWorld USB ATSC TV Stick UB435-Q V2      (em2874)        [1b80:e346]
  91 -> SpeedLink Vicious And Devine Laplace webcam (em2765)        [1ae7:9003,1ae7:9004]
- 92 -> PCTV DVB-S2 Stick (461e)                 (em28178)
+ 92 -> PCTV DVB-S2 Stick (461e)                 (em28178)       [2013:0258]
  93 -> KWorld USB ATSC TV Stick UB435-Q V3      (em2874)        [1b80:e34c]
- 94 -> PCTV tripleStick (292e)                  (em28178)
+ 94 -> PCTV tripleStick (292e)                  (em28178)       [2013:025f,2040:0264]
  95 -> Leadtek VC100                            (em2861)        [0413:6f07]
- 96 -> Terratec Cinergy T2 Stick HD             (em28178)
+ 96 -> Terratec Cinergy T2 Stick HD             (em28178)       [eb1a:8179]
  97 -> Elgato EyeTV Hybrid 2008 INT             (em2884)        [0fd9:0018]
+ 98 -> PLEX PX-BCUD                             (em28178)       [3275:0085]
+ 99 -> Hauppauge WinTV-dualHD DVB               (em28174)       [2040:0265]
diff --git a/Documentation/video4linux/Makefile b/Documentation/video4linux/Makefile
deleted file mode 100644 (file)
index 65a351d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_VIDEO_PCI_SKELETON) := v4l2-pci-skeleton.o
index fa41608..cbefc79 100644 (file)
@@ -35,7 +35,7 @@ need and this same framework should make it much easier to refactor
 common code into utility functions shared by all drivers.
 
 A good example to look at as a reference is the v4l2-pci-skeleton.c
-source that is available in this directory. It is a skeleton driver for
+source that is available in samples/v4l/. It is a skeleton driver for
 a PCI capture card, and demonstrates how to use the V4L2 driver
 framework. It can be used as a template for real PCI video capture driver.
 
diff --git a/Documentation/video4linux/v4l2-pci-skeleton.c b/Documentation/video4linux/v4l2-pci-skeleton.c
deleted file mode 100644 (file)
index 79af0c0..0000000
+++ /dev/null
@@ -1,923 +0,0 @@
-/*
- * This is a V4L2 PCI Skeleton Driver. It gives an initial skeleton source
- * for use with other PCI drivers.
- *
- * This skeleton PCI driver assumes that the card has an S-Video connector as
- * input 0 and an HDMI connector as input 1.
- *
- * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kmod.h>
-#include <linux/mutex.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/videodev2.h>
-#include <linux/v4l2-dv-timings.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-dev.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-dv-timings.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-event.h>
-#include <media/videobuf2-v4l2.h>
-#include <media/videobuf2-dma-contig.h>
-
-MODULE_DESCRIPTION("V4L2 PCI Skeleton Driver");
-MODULE_AUTHOR("Hans Verkuil");
-MODULE_LICENSE("GPL v2");
-
-/**
- * struct skeleton - All internal data for one instance of device
- * @pdev: PCI device
- * @v4l2_dev: top-level v4l2 device struct
- * @vdev: video node structure
- * @ctrl_handler: control handler structure
- * @lock: ioctl serialization mutex
- * @std: current SDTV standard
- * @timings: current HDTV timings
- * @format: current pix format
- * @input: current video input (0 = SDTV, 1 = HDTV)
- * @queue: vb2 video capture queue
- * @alloc_ctx: vb2 contiguous DMA context
- * @qlock: spinlock controlling access to buf_list and sequence
- * @buf_list: list of buffers queued for DMA
- * @sequence: frame sequence counter
- */
-struct skeleton {
-       struct pci_dev *pdev;
-       struct v4l2_device v4l2_dev;
-       struct video_device vdev;
-       struct v4l2_ctrl_handler ctrl_handler;
-       struct mutex lock;
-       v4l2_std_id std;
-       struct v4l2_dv_timings timings;
-       struct v4l2_pix_format format;
-       unsigned input;
-
-       struct vb2_queue queue;
-       struct vb2_alloc_ctx *alloc_ctx;
-
-       spinlock_t qlock;
-       struct list_head buf_list;
-       unsigned field;
-       unsigned sequence;
-};
-
-struct skel_buffer {
-       struct vb2_buffer vb;
-       struct list_head list;
-};
-
-static inline struct skel_buffer *to_skel_buffer(struct vb2_buffer *vb2)
-{
-       return container_of(vb2, struct skel_buffer, vb);
-}
-
-static const struct pci_device_id skeleton_pci_tbl[] = {
-       /* { PCI_DEVICE(PCI_VENDOR_ID_, PCI_DEVICE_ID_) }, */
-       { 0, }
-};
-MODULE_DEVICE_TABLE(pci, skeleton_pci_tbl);
-
-/*
- * HDTV: this structure has the capabilities of the HDTV receiver.
- * It is used to constrain the huge list of possible formats based
- * upon the hardware capabilities.
- */
-static const struct v4l2_dv_timings_cap skel_timings_cap = {
-       .type = V4L2_DV_BT_656_1120,
-       /* keep this initialization for compatibility with GCC < 4.4.6 */
-       .reserved = { 0 },
-       V4L2_INIT_BT_TIMINGS(
-               720, 1920,              /* min/max width */
-               480, 1080,              /* min/max height */
-               27000000, 74250000,     /* min/max pixelclock*/
-               V4L2_DV_BT_STD_CEA861,  /* Supported standards */
-               /* capabilities */
-               V4L2_DV_BT_CAP_INTERLACED | V4L2_DV_BT_CAP_PROGRESSIVE
-       )
-};
-
-/*
- * Supported SDTV standards. This does the same job as skel_timings_cap, but
- * for standard TV formats.
- */
-#define SKEL_TVNORMS V4L2_STD_ALL
-
-/*
- * Interrupt handler: typically interrupts happen after a new frame has been
- * captured. It is the job of the handler to remove the new frame from the
- * internal list and give it back to the vb2 framework, updating the sequence
- * counter, field and timestamp at the same time.
- */
-static irqreturn_t skeleton_irq(int irq, void *dev_id)
-{
-#ifdef TODO
-       struct skeleton *skel = dev_id;
-
-       /* handle interrupt */
-
-       /* Once a new frame has been captured, mark it as done like this: */
-       if (captured_new_frame) {
-               ...
-               spin_lock(&skel->qlock);
-               list_del(&new_buf->list);
-               spin_unlock(&skel->qlock);
-               v4l2_get_timestamp(&new_buf->vb.v4l2_buf.timestamp);
-               new_buf->vb.v4l2_buf.sequence = skel->sequence++;
-               new_buf->vb.v4l2_buf.field = skel->field;
-               if (skel->format.field == V4L2_FIELD_ALTERNATE) {
-                       if (skel->field == V4L2_FIELD_BOTTOM)
-                               skel->field = V4L2_FIELD_TOP;
-                       else if (skel->field == V4L2_FIELD_TOP)
-                               skel->field = V4L2_FIELD_BOTTOM;
-               }
-               vb2_buffer_done(&new_buf->vb, VB2_BUF_STATE_DONE);
-       }
-#endif
-       return IRQ_HANDLED;
-}
-
-/*
- * Setup the constraints of the queue: besides setting the number of planes
- * per buffer and the size and allocation context of each plane, it also
- * checks if sufficient buffers have been allocated. Usually 3 is a good
- * minimum number: many DMA engines need a minimum of 2 buffers in the
- * queue and you need to have another available for userspace processing.
- */
-static int queue_setup(struct vb2_queue *vq,
-                      unsigned int *nbuffers, unsigned int *nplanes,
-                      unsigned int sizes[], void *alloc_ctxs[])
-{
-       struct skeleton *skel = vb2_get_drv_priv(vq);
-
-       skel->field = skel->format.field;
-       if (skel->field == V4L2_FIELD_ALTERNATE) {
-               /*
-                * You cannot use read() with FIELD_ALTERNATE since the field
-                * information (TOP/BOTTOM) cannot be passed back to the user.
-                */
-               if (vb2_fileio_is_active(vq))
-                       return -EINVAL;
-               skel->field = V4L2_FIELD_TOP;
-       }
-
-       if (vq->num_buffers + *nbuffers < 3)
-               *nbuffers = 3 - vq->num_buffers;
-       alloc_ctxs[0] = skel->alloc_ctx;
-
-       if (*nplanes)
-               return sizes[0] < skel->format.sizeimage ? -EINVAL : 0;
-       *nplanes = 1;
-       sizes[0] = skel->format.sizeimage;
-       return 0;
-}
-
-/*
- * Prepare the buffer for queueing to the DMA engine: check and set the
- * payload size.
- */
-static int buffer_prepare(struct vb2_buffer *vb)
-{
-       struct skeleton *skel = vb2_get_drv_priv(vb->vb2_queue);
-       unsigned long size = skel->format.sizeimage;
-
-       if (vb2_plane_size(vb, 0) < size) {
-               dev_err(&skel->pdev->dev, "buffer too small (%lu < %lu)\n",
-                        vb2_plane_size(vb, 0), size);
-               return -EINVAL;
-       }
-
-       vb2_set_plane_payload(vb, 0, size);
-       return 0;
-}
-
-/*
- * Queue this buffer to the DMA engine.
- */
-static void buffer_queue(struct vb2_buffer *vb)
-{
-       struct skeleton *skel = vb2_get_drv_priv(vb->vb2_queue);
-       struct skel_buffer *buf = to_skel_buffer(vb);
-       unsigned long flags;
-
-       spin_lock_irqsave(&skel->qlock, flags);
-       list_add_tail(&buf->list, &skel->buf_list);
-
-       /* TODO: Update any DMA pointers if necessary */
-
-       spin_unlock_irqrestore(&skel->qlock, flags);
-}
-
-static void return_all_buffers(struct skeleton *skel,
-                              enum vb2_buffer_state state)
-{
-       struct skel_buffer *buf, *node;
-       unsigned long flags;
-
-       spin_lock_irqsave(&skel->qlock, flags);
-       list_for_each_entry_safe(buf, node, &skel->buf_list, list) {
-               vb2_buffer_done(&buf->vb, state);
-               list_del(&buf->list);
-       }
-       spin_unlock_irqrestore(&skel->qlock, flags);
-}
-
-/*
- * Start streaming. First check if the minimum number of buffers have been
- * queued. If not, then return -ENOBUFS and the vb2 framework will call
- * this function again the next time a buffer has been queued until enough
- * buffers are available to actually start the DMA engine.
- */
-static int start_streaming(struct vb2_queue *vq, unsigned int count)
-{
-       struct skeleton *skel = vb2_get_drv_priv(vq);
-       int ret = 0;
-
-       skel->sequence = 0;
-
-       /* TODO: start DMA */
-
-       if (ret) {
-               /*
-                * In case of an error, return all active buffers to the
-                * QUEUED state
-                */
-               return_all_buffers(skel, VB2_BUF_STATE_QUEUED);
-       }
-       return ret;
-}
-
-/*
- * Stop the DMA engine. Any remaining buffers in the DMA queue are dequeued
- * and passed on to the vb2 framework marked as STATE_ERROR.
- */
-static void stop_streaming(struct vb2_queue *vq)
-{
-       struct skeleton *skel = vb2_get_drv_priv(vq);
-
-       /* TODO: stop DMA */
-
-       /* Release all active buffers */
-       return_all_buffers(skel, VB2_BUF_STATE_ERROR);
-}
-
-/*
- * The vb2 queue ops. Note that since q->lock is set we can use the standard
- * vb2_ops_wait_prepare/finish helper functions. If q->lock would be NULL,
- * then this driver would have to provide these ops.
- */
-static struct vb2_ops skel_qops = {
-       .queue_setup            = queue_setup,
-       .buf_prepare            = buffer_prepare,
-       .buf_queue              = buffer_queue,
-       .start_streaming        = start_streaming,
-       .stop_streaming         = stop_streaming,
-       .wait_prepare           = vb2_ops_wait_prepare,
-       .wait_finish            = vb2_ops_wait_finish,
-};
-
-/*
- * Required ioctl querycap. Note that the version field is prefilled with
- * the version of the kernel.
- */
-static int skeleton_querycap(struct file *file, void *priv,
-                            struct v4l2_capability *cap)
-{
-       struct skeleton *skel = video_drvdata(file);
-
-       strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
-       strlcpy(cap->card, "V4L2 PCI Skeleton", sizeof(cap->card));
-       snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
-                pci_name(skel->pdev));
-       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
-                          V4L2_CAP_STREAMING;
-       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-       return 0;
-}
-
-/*
- * Helper function to check and correct struct v4l2_pix_format. It's used
- * not only in VIDIOC_TRY/S_FMT, but also elsewhere if changes to the SDTV
- * standard, HDTV timings or the video input would require updating the
- * current format.
- */
-static void skeleton_fill_pix_format(struct skeleton *skel,
-                                    struct v4l2_pix_format *pix)
-{
-       pix->pixelformat = V4L2_PIX_FMT_YUYV;
-       if (skel->input == 0) {
-               /* S-Video input */
-               pix->width = 720;
-               pix->height = (skel->std & V4L2_STD_525_60) ? 480 : 576;
-               pix->field = V4L2_FIELD_INTERLACED;
-               pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
-       } else {
-               /* HDMI input */
-               pix->width = skel->timings.bt.width;
-               pix->height = skel->timings.bt.height;
-               if (skel->timings.bt.interlaced) {
-                       pix->field = V4L2_FIELD_ALTERNATE;
-                       pix->height /= 2;
-               } else {
-                       pix->field = V4L2_FIELD_NONE;
-               }
-               pix->colorspace = V4L2_COLORSPACE_REC709;
-       }
-
-       /*
-        * The YUYV format is four bytes for every two pixels, so bytesperline
-        * is width * 2.
-        */
-       pix->bytesperline = pix->width * 2;
-       pix->sizeimage = pix->bytesperline * pix->height;
-       pix->priv = 0;
-}
-
-static int skeleton_try_fmt_vid_cap(struct file *file, void *priv,
-                                   struct v4l2_format *f)
-{
-       struct skeleton *skel = video_drvdata(file);
-       struct v4l2_pix_format *pix = &f->fmt.pix;
-
-       /*
-        * Due to historical reasons providing try_fmt with an unsupported
-        * pixelformat will return -EINVAL for video receivers. Webcam drivers,
-        * however, will silently correct the pixelformat. Some video capture
-        * applications rely on this behavior...
-        */
-       if (pix->pixelformat != V4L2_PIX_FMT_YUYV)
-               return -EINVAL;
-       skeleton_fill_pix_format(skel, pix);
-       return 0;
-}
-
-static int skeleton_s_fmt_vid_cap(struct file *file, void *priv,
-                                 struct v4l2_format *f)
-{
-       struct skeleton *skel = video_drvdata(file);
-       int ret;
-
-       ret = skeleton_try_fmt_vid_cap(file, priv, f);
-       if (ret)
-               return ret;
-
-       /*
-        * It is not allowed to change the format while buffers for use with
-        * streaming have already been allocated.
-        */
-       if (vb2_is_busy(&skel->queue))
-               return -EBUSY;
-
-       /* TODO: change format */
-       skel->format = f->fmt.pix;
-       return 0;
-}
-
-static int skeleton_g_fmt_vid_cap(struct file *file, void *priv,
-                                 struct v4l2_format *f)
-{
-       struct skeleton *skel = video_drvdata(file);
-
-       f->fmt.pix = skel->format;
-       return 0;
-}
-
-static int skeleton_enum_fmt_vid_cap(struct file *file, void *priv,
-                                    struct v4l2_fmtdesc *f)
-{
-       if (f->index != 0)
-               return -EINVAL;
-
-       f->pixelformat = V4L2_PIX_FMT_YUYV;
-       return 0;
-}
-
-static int skeleton_s_std(struct file *file, void *priv, v4l2_std_id std)
-{
-       struct skeleton *skel = video_drvdata(file);
-
-       /* S_STD is not supported on the HDMI input */
-       if (skel->input)
-               return -ENODATA;
-
-       /*
-        * No change, so just return. Some applications call S_STD again after
-        * the buffers for streaming have been set up, so we have to allow for
-        * this behavior.
-        */
-       if (std == skel->std)
-               return 0;
-
-       /*
-        * Changing the standard implies a format change, which is not allowed
-        * while buffers for use with streaming have already been allocated.
-        */
-       if (vb2_is_busy(&skel->queue))
-               return -EBUSY;
-
-       /* TODO: handle changing std */
-
-       skel->std = std;
-
-       /* Update the internal format */
-       skeleton_fill_pix_format(skel, &skel->format);
-       return 0;
-}
-
-static int skeleton_g_std(struct file *file, void *priv, v4l2_std_id *std)
-{
-       struct skeleton *skel = video_drvdata(file);
-
-       /* G_STD is not supported on the HDMI input */
-       if (skel->input)
-               return -ENODATA;
-
-       *std = skel->std;
-       return 0;
-}
-
-/*
- * Query the current standard as seen by the hardware. This function shall
- * never actually change the standard, it just detects and reports.
- * The framework will initially set *std to tvnorms (i.e. the set of
- * supported standards by this input), and this function should just AND
- * this value. If there is no signal, then *std should be set to 0.
- */
-static int skeleton_querystd(struct file *file, void *priv, v4l2_std_id *std)
-{
-       struct skeleton *skel = video_drvdata(file);
-
-       /* QUERY_STD is not supported on the HDMI input */
-       if (skel->input)
-               return -ENODATA;
-
-#ifdef TODO
-       /*
-        * Query currently seen standard. Initial value of *std is
-        * V4L2_STD_ALL. This function should look something like this:
-        */
-       get_signal_info();
-       if (no_signal) {
-               *std = 0;
-               return 0;
-       }
-       /* Use signal information to reduce the number of possible standards */
-       if (signal_has_525_lines)
-               *std &= V4L2_STD_525_60;
-       else
-               *std &= V4L2_STD_625_50;
-#endif
-       return 0;
-}
-
-static int skeleton_s_dv_timings(struct file *file, void *_fh,
-                                struct v4l2_dv_timings *timings)
-{
-       struct skeleton *skel = video_drvdata(file);
-
-       /* S_DV_TIMINGS is not supported on the S-Video input */
-       if (skel->input == 0)
-               return -ENODATA;
-
-       /* Quick sanity check */
-       if (!v4l2_valid_dv_timings(timings, &skel_timings_cap, NULL, NULL))
-               return -EINVAL;
-
-       /* Check if the timings are part of the CEA-861 timings. */
-       if (!v4l2_find_dv_timings_cap(timings, &skel_timings_cap,
-                                     0, NULL, NULL))
-               return -EINVAL;
-
-       /* Return 0 if the new timings are the same as the current timings. */
-       if (v4l2_match_dv_timings(timings, &skel->timings, 0, false))
-               return 0;
-
-       /*
-        * Changing the timings implies a format change, which is not allowed
-        * while buffers for use with streaming have already been allocated.
-        */
-       if (vb2_is_busy(&skel->queue))
-               return -EBUSY;
-
-       /* TODO: Configure new timings */
-
-       /* Save timings */
-       skel->timings = *timings;
-
-       /* Update the internal format */
-       skeleton_fill_pix_format(skel, &skel->format);
-       return 0;
-}
-
-static int skeleton_g_dv_timings(struct file *file, void *_fh,
-                                struct v4l2_dv_timings *timings)
-{
-       struct skeleton *skel = video_drvdata(file);
-
-       /* G_DV_TIMINGS is not supported on the S-Video input */
-       if (skel->input == 0)
-               return -ENODATA;
-
-       *timings = skel->timings;
-       return 0;
-}
-
-static int skeleton_enum_dv_timings(struct file *file, void *_fh,
-                                   struct v4l2_enum_dv_timings *timings)
-{
-       struct skeleton *skel = video_drvdata(file);
-
-       /* ENUM_DV_TIMINGS is not supported on the S-Video input */
-       if (skel->input == 0)
-               return -ENODATA;
-
-       return v4l2_enum_dv_timings_cap(timings, &skel_timings_cap,
-                                       NULL, NULL);
-}
-
-/*
- * Query the current timings as seen by the hardware. This function shall
- * never actually change the timings, it just detects and reports.
- * If no signal is detected, then return -ENOLINK. If the hardware cannot
- * lock to the signal, then return -ENOLCK. If the signal is out of range
- * of the capabilities of the system (e.g., it is possible that the receiver
- * can lock but that the DMA engine it is connected to cannot handle
- * pixelclocks above a certain frequency), then -ERANGE is returned.
- */
-static int skeleton_query_dv_timings(struct file *file, void *_fh,
-                                    struct v4l2_dv_timings *timings)
-{
-       struct skeleton *skel = video_drvdata(file);
-
-       /* QUERY_DV_TIMINGS is not supported on the S-Video input */
-       if (skel->input == 0)
-               return -ENODATA;
-
-#ifdef TODO
-       /*
-        * Query currently seen timings. This function should look
-        * something like this:
-        */
-       detect_timings();
-       if (no_signal)
-               return -ENOLINK;
-       if (cannot_lock_to_signal)
-               return -ENOLCK;
-       if (signal_out_of_range_of_capabilities)
-               return -ERANGE;
-
-       /* Useful for debugging */
-       v4l2_print_dv_timings(skel->v4l2_dev.name, "query_dv_timings:",
-                       timings, true);
-#endif
-       return 0;
-}
-
-static int skeleton_dv_timings_cap(struct file *file, void *fh,
-                                  struct v4l2_dv_timings_cap *cap)
-{
-       struct skeleton *skel = video_drvdata(file);
-
-       /* DV_TIMINGS_CAP is not supported on the S-Video input */
-       if (skel->input == 0)
-               return -ENODATA;
-       *cap = skel_timings_cap;
-       return 0;
-}
-
-static int skeleton_enum_input(struct file *file, void *priv,
-                              struct v4l2_input *i)
-{
-       if (i->index > 1)
-               return -EINVAL;
-
-       i->type = V4L2_INPUT_TYPE_CAMERA;
-       if (i->index == 0) {
-               i->std = SKEL_TVNORMS;
-               strlcpy(i->name, "S-Video", sizeof(i->name));
-               i->capabilities = V4L2_IN_CAP_STD;
-       } else {
-               i->std = 0;
-               strlcpy(i->name, "HDMI", sizeof(i->name));
-               i->capabilities = V4L2_IN_CAP_DV_TIMINGS;
-       }
-       return 0;
-}
-
-static int skeleton_s_input(struct file *file, void *priv, unsigned int i)
-{
-       struct skeleton *skel = video_drvdata(file);
-
-       if (i > 1)
-               return -EINVAL;
-
-       /*
-        * Changing the input implies a format change, which is not allowed
-        * while buffers for use with streaming have already been allocated.
-        */
-       if (vb2_is_busy(&skel->queue))
-               return -EBUSY;
-
-       skel->input = i;
-       /*
-        * Update tvnorms. The tvnorms value is used by the core to implement
-        * VIDIOC_ENUMSTD so it has to be correct. If tvnorms == 0, then
-        * ENUMSTD will return -ENODATA.
-        */
-       skel->vdev.tvnorms = i ? 0 : SKEL_TVNORMS;
-
-       /* Update the internal format */
-       skeleton_fill_pix_format(skel, &skel->format);
-       return 0;
-}
-
-static int skeleton_g_input(struct file *file, void *priv, unsigned int *i)
-{
-       struct skeleton *skel = video_drvdata(file);
-
-       *i = skel->input;
-       return 0;
-}
-
-/* The control handler. */
-static int skeleton_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-       /*struct skeleton *skel =
-               container_of(ctrl->handler, struct skeleton, ctrl_handler);*/
-
-       switch (ctrl->id) {
-       case V4L2_CID_BRIGHTNESS:
-               /* TODO: set brightness to ctrl->val */
-               break;
-       case V4L2_CID_CONTRAST:
-               /* TODO: set contrast to ctrl->val */
-               break;
-       case V4L2_CID_SATURATION:
-               /* TODO: set saturation to ctrl->val */
-               break;
-       case V4L2_CID_HUE:
-               /* TODO: set hue to ctrl->val */
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-/* ------------------------------------------------------------------
-       File operations for the device
-   ------------------------------------------------------------------*/
-
-static const struct v4l2_ctrl_ops skel_ctrl_ops = {
-       .s_ctrl = skeleton_s_ctrl,
-};
-
-/*
- * The set of all supported ioctls. Note that all the streaming ioctls
- * use the vb2 helper functions that take care of all the locking and
- * that also do ownership tracking (i.e. only the filehandle that requested
- * the buffers can call the streaming ioctls, all other filehandles will
- * receive -EBUSY if they attempt to call the same streaming ioctls).
- *
- * The last three ioctls also use standard helper functions: these implement
- * standard behavior for drivers with controls.
- */
-static const struct v4l2_ioctl_ops skel_ioctl_ops = {
-       .vidioc_querycap = skeleton_querycap,
-       .vidioc_try_fmt_vid_cap = skeleton_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap = skeleton_s_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap = skeleton_g_fmt_vid_cap,
-       .vidioc_enum_fmt_vid_cap = skeleton_enum_fmt_vid_cap,
-
-       .vidioc_g_std = skeleton_g_std,
-       .vidioc_s_std = skeleton_s_std,
-       .vidioc_querystd = skeleton_querystd,
-
-       .vidioc_s_dv_timings = skeleton_s_dv_timings,
-       .vidioc_g_dv_timings = skeleton_g_dv_timings,
-       .vidioc_enum_dv_timings = skeleton_enum_dv_timings,
-       .vidioc_query_dv_timings = skeleton_query_dv_timings,
-       .vidioc_dv_timings_cap = skeleton_dv_timings_cap,
-
-       .vidioc_enum_input = skeleton_enum_input,
-       .vidioc_g_input = skeleton_g_input,
-       .vidioc_s_input = skeleton_s_input,
-
-       .vidioc_reqbufs = vb2_ioctl_reqbufs,
-       .vidioc_create_bufs = vb2_ioctl_create_bufs,
-       .vidioc_querybuf = vb2_ioctl_querybuf,
-       .vidioc_qbuf = vb2_ioctl_qbuf,
-       .vidioc_dqbuf = vb2_ioctl_dqbuf,
-       .vidioc_expbuf = vb2_ioctl_expbuf,
-       .vidioc_streamon = vb2_ioctl_streamon,
-       .vidioc_streamoff = vb2_ioctl_streamoff,
-
-       .vidioc_log_status = v4l2_ctrl_log_status,
-       .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
-       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-/*
- * The set of file operations. Note that all these ops are standard core
- * helper functions.
- */
-static const struct v4l2_file_operations skel_fops = {
-       .owner = THIS_MODULE,
-       .open = v4l2_fh_open,
-       .release = vb2_fop_release,
-       .unlocked_ioctl = video_ioctl2,
-       .read = vb2_fop_read,
-       .mmap = vb2_fop_mmap,
-       .poll = vb2_fop_poll,
-};
-
-/*
- * The initial setup of this device instance. Note that the initial state of
- * the driver should be complete. So the initial format, standard, timings
- * and video input should all be initialized to some reasonable value.
- */
-static int skeleton_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-       /* The initial timings are chosen to be 720p60. */
-       static const struct v4l2_dv_timings timings_def =
-               V4L2_DV_BT_CEA_1280X720P60;
-       struct skeleton *skel;
-       struct video_device *vdev;
-       struct v4l2_ctrl_handler *hdl;
-       struct vb2_queue *q;
-       int ret;
-
-       /* Enable PCI */
-       ret = pci_enable_device(pdev);
-       if (ret)
-               return ret;
-       ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-       if (ret) {
-               dev_err(&pdev->dev, "no suitable DMA available.\n");
-               goto disable_pci;
-       }
-
-       /* Allocate a new instance */
-       skel = devm_kzalloc(&pdev->dev, sizeof(struct skeleton), GFP_KERNEL);
-       if (!skel)
-               return -ENOMEM;
-
-       /* Allocate the interrupt */
-       ret = devm_request_irq(&pdev->dev, pdev->irq,
-                              skeleton_irq, 0, KBUILD_MODNAME, skel);
-       if (ret) {
-               dev_err(&pdev->dev, "request_irq failed\n");
-               goto disable_pci;
-       }
-       skel->pdev = pdev;
-
-       /* Fill in the initial format-related settings */
-       skel->timings = timings_def;
-       skel->std = V4L2_STD_625_50;
-       skeleton_fill_pix_format(skel, &skel->format);
-
-       /* Initialize the top-level structure */
-       ret = v4l2_device_register(&pdev->dev, &skel->v4l2_dev);
-       if (ret)
-               goto disable_pci;
-
-       mutex_init(&skel->lock);
-
-       /* Add the controls */
-       hdl = &skel->ctrl_handler;
-       v4l2_ctrl_handler_init(hdl, 4);
-       v4l2_ctrl_new_std(hdl, &skel_ctrl_ops,
-                         V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
-       v4l2_ctrl_new_std(hdl, &skel_ctrl_ops,
-                         V4L2_CID_CONTRAST, 0, 255, 1, 16);
-       v4l2_ctrl_new_std(hdl, &skel_ctrl_ops,
-                         V4L2_CID_SATURATION, 0, 255, 1, 127);
-       v4l2_ctrl_new_std(hdl, &skel_ctrl_ops,
-                         V4L2_CID_HUE, -128, 127, 1, 0);
-       if (hdl->error) {
-               ret = hdl->error;
-               goto free_hdl;
-       }
-       skel->v4l2_dev.ctrl_handler = hdl;
-
-       /* Initialize the vb2 queue */
-       q = &skel->queue;
-       q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
-       q->drv_priv = skel;
-       q->buf_struct_size = sizeof(struct skel_buffer);
-       q->ops = &skel_qops;
-       q->mem_ops = &vb2_dma_contig_memops;
-       q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
-       /*
-        * Assume that this DMA engine needs to have at least two buffers
-        * available before it can be started. The start_streaming() op
-        * won't be called until at least this many buffers are queued up.
-        */
-       q->min_buffers_needed = 2;
-       /*
-        * The serialization lock for the streaming ioctls. This is the same
-        * as the main serialization lock, but if some of the non-streaming
-        * ioctls could take a long time to execute, then you might want to
-        * have a different lock here to prevent VIDIOC_DQBUF from being
-        * blocked while waiting for another action to finish. This is
-        * generally not needed for PCI devices, but USB devices usually do
-        * want a separate lock here.
-        */
-       q->lock = &skel->lock;
-       /*
-        * Since this driver can only do 32-bit DMA we must make sure that
-        * the vb2 core will allocate the buffers in 32-bit DMA memory.
-        */
-       q->gfp_flags = GFP_DMA32;
-       ret = vb2_queue_init(q);
-       if (ret)
-               goto free_hdl;
-
-       skel->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
-       if (IS_ERR(skel->alloc_ctx)) {
-               dev_err(&pdev->dev, "Can't allocate buffer context");
-               ret = PTR_ERR(skel->alloc_ctx);
-               goto free_hdl;
-       }
-       INIT_LIST_HEAD(&skel->buf_list);
-       spin_lock_init(&skel->qlock);
-
-       /* Initialize the video_device structure */
-       vdev = &skel->vdev;
-       strlcpy(vdev->name, KBUILD_MODNAME, sizeof(vdev->name));
-       /*
-        * There is nothing to clean up, so release is set to an empty release
-        * function. The release callback must be non-NULL.
-        */
-       vdev->release = video_device_release_empty;
-       vdev->fops = &skel_fops,
-       vdev->ioctl_ops = &skel_ioctl_ops,
-       /*
-        * The main serialization lock. All ioctls are serialized by this
-        * lock. Exception: if q->lock is set, then the streaming ioctls
-        * are serialized by that separate lock.
-        */
-       vdev->lock = &skel->lock;
-       vdev->queue = q;
-       vdev->v4l2_dev = &skel->v4l2_dev;
-       /* Supported SDTV standards, if any */
-       vdev->tvnorms = SKEL_TVNORMS;
-       video_set_drvdata(vdev, skel);
-
-       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
-       if (ret)
-               goto free_ctx;
-
-       dev_info(&pdev->dev, "V4L2 PCI Skeleton Driver loaded\n");
-       return 0;
-
-free_ctx:
-       vb2_dma_contig_cleanup_ctx(skel->alloc_ctx);
-free_hdl:
-       v4l2_ctrl_handler_free(&skel->ctrl_handler);
-       v4l2_device_unregister(&skel->v4l2_dev);
-disable_pci:
-       pci_disable_device(pdev);
-       return ret;
-}
-
-static void skeleton_remove(struct pci_dev *pdev)
-{
-       struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
-       struct skeleton *skel = container_of(v4l2_dev, struct skeleton, v4l2_dev);
-
-       video_unregister_device(&skel->vdev);
-       v4l2_ctrl_handler_free(&skel->ctrl_handler);
-       vb2_dma_contig_cleanup_ctx(skel->alloc_ctx);
-       v4l2_device_unregister(&skel->v4l2_dev);
-       pci_disable_device(skel->pdev);
-}
-
-static struct pci_driver skeleton_driver = {
-       .name = KBUILD_MODNAME,
-       .probe = skeleton_probe,
-       .remove = skeleton_remove,
-       .id_table = skeleton_pci_tbl,
-};
-
-module_pci_driver(skeleton_driver);
index e35d376..8da5d2a 100644 (file)
@@ -294,7 +294,7 @@ the result will be.
 
 These inputs support all combinations of the field setting. Special care has
 been taken to faithfully reproduce how fields are handled for the different
-TV standards. This is particularly noticable when generating a horizontally
+TV standards. This is particularly noticeable when generating a horizontally
 moving image so the temporal effect of using interlaced formats becomes clearly
 visible. For 50 Hz standards the top field is the oldest and the bottom field
 is the newest in time. For 60 Hz standards that is reversed: the bottom field
@@ -313,7 +313,7 @@ will be SMPTE-170M.
 The pixel aspect ratio will depend on the TV standard. The video aspect ratio
 can be selected through the 'Standard Aspect Ratio' Vivid control.
 Choices are '4x3', '16x9' which will give letterboxed widescreen video and
-'16x9 Anomorphic' which will give full screen squashed anamorphic widescreen
+'16x9 Anamorphic' which will give full screen squashed anamorphic widescreen
 video that will need to be scaled accordingly.
 
 The TV 'tuner' supports a frequency range of 44-958 MHz. Channels are available
@@ -862,7 +862,7 @@ RDS Radio Text:
 RDS Stereo:
 RDS Artificial Head:
 RDS Compressed:
-RDS Dymanic PTY:
+RDS Dynamic PTY:
 RDS Traffic Announcement:
 RDS Traffic Program:
 RDS Music: these are all controls that set the RDS data that is transmitted by
index c7dd1a3..add406a 100644 (file)
@@ -11338,6 +11338,14 @@ W:     https://linuxtv.org
 S:     Odd Fixes
 F:     drivers/media/pci/tw68/
 
+TW686X VIDEO4LINUX DRIVER
+M:     Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
+L:     linux-media@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+W:     http://linuxtv.org
+S:     Maintained
+F:     drivers/media/pci/tw686x/
+
 TPM DEVICE DRIVER
 M:     Peter Huewe <peterhuewe@gmx.de>
 M:     Marcel Selhorst <tpmdd@selhorst.net>
index 21154dd..326df0a 100644 (file)
@@ -19,3 +19,4 @@ config CYPRESS_FIRMWARE
 source "drivers/media/common/b2c2/Kconfig"
 source "drivers/media/common/saa7146/Kconfig"
 source "drivers/media/common/siano/Kconfig"
+source "drivers/media/common/v4l2-tpg/Kconfig"
index 89b795d..2d1b0a0 100644 (file)
@@ -1,4 +1,4 @@
-obj-y += b2c2/ saa7146/ siano/
+obj-y += b2c2/ saa7146/ siano/ v4l2-tpg/
 obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
 obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
 obj-$(CONFIG_CYPRESS_FIRMWARE) += cypress_firmware.o
diff --git a/drivers/media/common/v4l2-tpg/Kconfig b/drivers/media/common/v4l2-tpg/Kconfig
new file mode 100644 (file)
index 0000000..7456fc1
--- /dev/null
@@ -0,0 +1,2 @@
+config VIDEO_V4L2_TPG
+       tristate
diff --git a/drivers/media/common/v4l2-tpg/Makefile b/drivers/media/common/v4l2-tpg/Makefile
new file mode 100644 (file)
index 0000000..f588df4
--- /dev/null
@@ -0,0 +1,3 @@
+v4l2-tpg-objs := v4l2-tpg-core.o v4l2-tpg-colors.o
+
+obj-$(CONFIG_VIDEO_V4L2_TPG) += v4l2-tpg.o
diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c
new file mode 100644 (file)
index 0000000..9bcbd31
--- /dev/null
@@ -0,0 +1,1415 @@
+/*
+ * v4l2-tpg-colors.c - A table that converts colors to various colorspaces
+ *
+ * The test pattern generator uses the tpg_colors for its test patterns.
+ * For testing colorspaces the first 8 colors of that table need to be
+ * converted to their equivalent in the target colorspace.
+ *
+ * The tpg_csc_colors[] table is the result of that conversion and since
+ * it is precalculated the colorspace conversion is just a simple table
+ * lookup.
+ *
+ * This source also contains the code used to generate the tpg_csc_colors
+ * table. Run the following command to compile it:
+ *
+ *     gcc v4l2-tpg-colors.c -DCOMPILE_APP -o gen-colors -lm
+ *
+ * and run the utility.
+ *
+ * Note that the converted colors are in the range 0x000-0xff0 (so times 16)
+ * in order to preserve precision.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/videodev2.h>
+#include <media/v4l2-tpg-colors.h>
+
+/* sRGB colors with range [0-255] */
+const struct color tpg_colors[TPG_COLOR_MAX] = {
+       /*
+        * Colors to test colorspace conversion: converting these colors
+        * to other colorspaces will never lead to out-of-gamut colors.
+        */
+       { 191, 191, 191 }, /* TPG_COLOR_CSC_WHITE */
+       { 191, 191,  50 }, /* TPG_COLOR_CSC_YELLOW */
+       {  50, 191, 191 }, /* TPG_COLOR_CSC_CYAN */
+       {  50, 191,  50 }, /* TPG_COLOR_CSC_GREEN */
+       { 191,  50, 191 }, /* TPG_COLOR_CSC_MAGENTA */
+       { 191,  50,  50 }, /* TPG_COLOR_CSC_RED */
+       {  50,  50, 191 }, /* TPG_COLOR_CSC_BLUE */
+       {  50,  50,  50 }, /* TPG_COLOR_CSC_BLACK */
+
+       /* 75% colors */
+       { 191, 191,   0 }, /* TPG_COLOR_75_YELLOW */
+       {   0, 191, 191 }, /* TPG_COLOR_75_CYAN */
+       {   0, 191,   0 }, /* TPG_COLOR_75_GREEN */
+       { 191,   0, 191 }, /* TPG_COLOR_75_MAGENTA */
+       { 191,   0,   0 }, /* TPG_COLOR_75_RED */
+       {   0,   0, 191 }, /* TPG_COLOR_75_BLUE */
+
+       /* 100% colors */
+       { 255, 255, 255 }, /* TPG_COLOR_100_WHITE */
+       { 255, 255,   0 }, /* TPG_COLOR_100_YELLOW */
+       {   0, 255, 255 }, /* TPG_COLOR_100_CYAN */
+       {   0, 255,   0 }, /* TPG_COLOR_100_GREEN */
+       { 255,   0, 255 }, /* TPG_COLOR_100_MAGENTA */
+       { 255,   0,   0 }, /* TPG_COLOR_100_RED */
+       {   0,   0, 255 }, /* TPG_COLOR_100_BLUE */
+       {   0,   0,   0 }, /* TPG_COLOR_100_BLACK */
+
+       {   0,   0,   0 }, /* TPG_COLOR_RANDOM placeholder */
+};
+
+#ifndef COMPILE_APP
+
+/* Generated table */
+const unsigned short tpg_rec709_to_linear[255 * 16 + 1] = {
+          0,    0,    0,    1,    1,    1,    1,    2,    2,    2,    2,    2,    3,    3,    3,    3,
+          4,    4,    4,    4,    4,    5,    5,    5,    5,    6,    6,    6,    6,    6,    7,    7,
+          7,    7,    8,    8,    8,    8,    8,    9,    9,    9,    9,   10,   10,   10,   10,   10,
+         11,   11,   11,   11,   12,   12,   12,   12,   12,   13,   13,   13,   13,   14,   14,   14,
+         14,   14,   15,   15,   15,   15,   16,   16,   16,   16,   16,   17,   17,   17,   17,   18,
+         18,   18,   18,   18,   19,   19,   19,   19,   20,   20,   20,   20,   20,   21,   21,   21,
+         21,   22,   22,   22,   22,   22,   23,   23,   23,   23,   24,   24,   24,   24,   24,   25,
+         25,   25,   25,   26,   26,   26,   26,   26,   27,   27,   27,   27,   28,   28,   28,   28,
+         28,   29,   29,   29,   29,   30,   30,   30,   30,   30,   31,   31,   31,   31,   32,   32,
+         32,   32,   32,   33,   33,   33,   33,   34,   34,   34,   34,   34,   35,   35,   35,   35,
+         36,   36,   36,   36,   36,   37,   37,   37,   37,   38,   38,   38,   38,   38,   39,   39,
+         39,   39,   40,   40,   40,   40,   40,   41,   41,   41,   41,   42,   42,   42,   42,   42,
+         43,   43,   43,   43,   44,   44,   44,   44,   44,   45,   45,   45,   45,   46,   46,   46,
+         46,   46,   47,   47,   47,   47,   48,   48,   48,   48,   48,   49,   49,   49,   49,   50,
+         50,   50,   50,   50,   51,   51,   51,   51,   52,   52,   52,   52,   52,   53,   53,   53,
+         53,   54,   54,   54,   54,   54,   55,   55,   55,   55,   56,   56,   56,   56,   56,   57,
+         57,   57,   57,   58,   58,   58,   58,   58,   59,   59,   59,   59,   60,   60,   60,   60,
+         60,   61,   61,   61,   61,   62,   62,   62,   62,   62,   63,   63,   63,   63,   64,   64,
+         64,   64,   64,   65,   65,   65,   65,   66,   66,   66,   66,   66,   67,   67,   67,   67,
+         68,   68,   68,   68,   68,   69,   69,   69,   69,   70,   70,   70,   70,   70,   71,   71,
+         71,   71,   72,   72,   72,   72,   72,   73,   73,   73,   73,   73,   74,   74,   74,   74,
+         74,   75,   75,   75,   75,   76,   76,   76,   76,   76,   77,   77,   77,   77,   78,   78,
+         78,   78,   79,   79,   79,   79,   79,   80,   80,   80,   80,   81,   81,   81,   81,   82,
+         82,   82,   82,   82,   83,   83,   83,   83,   84,   84,   84,   84,   85,   85,   85,   85,
+         86,   86,   86,   86,   87,   87,   87,   87,   88,   88,   88,   88,   89,   89,   89,   89,
+         90,   90,   90,   90,   91,   91,   91,   91,   92,   92,   92,   92,   93,   93,   93,   93,
+         94,   94,   94,   94,   95,   95,   95,   95,   96,   96,   96,   96,   97,   97,   97,   97,
+         98,   98,   98,   98,   99,   99,   99,   99,  100,  100,  100,  101,  101,  101,  101,  102,
+        102,  102,  102,  103,  103,  103,  103,  104,  104,  104,  105,  105,  105,  105,  106,  106,
+        106,  106,  107,  107,  107,  107,  108,  108,  108,  109,  109,  109,  109,  110,  110,  110,
+        111,  111,  111,  111,  112,  112,  112,  112,  113,  113,  113,  114,  114,  114,  114,  115,
+        115,  115,  116,  116,  116,  116,  117,  117,  117,  118,  118,  118,  118,  119,  119,  119,
+        120,  120,  120,  120,  121,  121,  121,  122,  122,  122,  123,  123,  123,  123,  124,  124,
+        124,  125,  125,  125,  125,  126,  126,  126,  127,  127,  127,  128,  128,  128,  128,  129,
+        129,  129,  130,  130,  130,  131,  131,  131,  132,  132,  132,  132,  133,  133,  133,  134,
+        134,  134,  135,  135,  135,  136,  136,  136,  136,  137,  137,  137,  138,  138,  138,  139,
+        139,  139,  140,  140,  140,  141,  141,  141,  142,  142,  142,  142,  143,  143,  143,  144,
+        144,  144,  145,  145,  145,  146,  146,  146,  147,  147,  147,  148,  148,  148,  149,  149,
+        149,  150,  150,  150,  151,  151,  151,  152,  152,  152,  153,  153,  153,  154,  154,  154,
+        155,  155,  155,  156,  156,  156,  157,  157,  157,  158,  158,  158,  159,  159,  159,  160,
+        160,  160,  161,  161,  161,  162,  162,  162,  163,  163,  163,  164,  164,  164,  165,  165,
+        165,  166,  166,  167,  167,  167,  168,  168,  168,  169,  169,  169,  170,  170,  170,  171,
+        171,  171,  172,  172,  172,  173,  173,  174,  174,  174,  175,  175,  175,  176,  176,  176,
+        177,  177,  177,  178,  178,  179,  179,  179,  180,  180,  180,  181,  181,  181,  182,  182,
+        183,  183,  183,  184,  184,  184,  185,  185,  186,  186,  186,  187,  187,  187,  188,  188,
+        188,  189,  189,  190,  190,  190,  191,  191,  191,  192,  192,  193,  193,  193,  194,  194,
+        194,  195,  195,  196,  196,  196,  197,  197,  198,  198,  198,  199,  199,  199,  200,  200,
+        201,  201,  201,  202,  202,  203,  203,  203,  204,  204,  204,  205,  205,  206,  206,  206,
+        207,  207,  208,  208,  208,  209,  209,  210,  210,  210,  211,  211,  212,  212,  212,  213,
+        213,  214,  214,  214,  215,  215,  216,  216,  216,  217,  217,  218,  218,  218,  219,  219,
+        220,  220,  220,  221,  221,  222,  222,  222,  223,  223,  224,  224,  224,  225,  225,  226,
+        226,  227,  227,  227,  228,  228,  229,  229,  229,  230,  230,  231,  231,  232,  232,  232,
+        233,  233,  234,  234,  234,  235,  235,  236,  236,  237,  237,  237,  238,  238,  239,  239,
+        240,  240,  240,  241,  241,  242,  242,  243,  243,  243,  244,  244,  245,  245,  246,  246,
+        246,  247,  247,  248,  248,  249,  249,  249,  250,  250,  251,  251,  252,  252,  252,  253,
+        253,  254,  254,  255,  255,  256,  256,  256,  257,  257,  258,  258,  259,  259,  260,  260,
+        260,  261,  261,  262,  262,  263,  263,  264,  264,  264,  265,  265,  266,  266,  267,  267,
+        268,  268,  269,  269,  269,  270,  270,  271,  271,  272,  272,  273,  273,  274,  274,  274,
+        275,  275,  276,  276,  277,  277,  278,  278,  279,  279,  279,  280,  280,  281,  281,  282,
+        282,  283,  283,  284,  284,  285,  285,  286,  286,  286,  287,  287,  288,  288,  289,  289,
+        290,  290,  291,  291,  292,  292,  293,  293,  294,  294,  295,  295,  295,  296,  296,  297,
+        297,  298,  298,  299,  299,  300,  300,  301,  301,  302,  302,  303,  303,  304,  304,  305,
+        305,  306,  306,  307,  307,  308,  308,  309,  309,  309,  310,  310,  311,  311,  312,  312,
+        313,  313,  314,  314,  315,  315,  316,  316,  317,  317,  318,  318,  319,  319,  320,  320,
+        321,  321,  322,  322,  323,  323,  324,  324,  325,  325,  326,  326,  327,  327,  328,  328,
+        329,  329,  330,  330,  331,  331,  332,  332,  333,  333,  334,  335,  335,  336,  336,  337,
+        337,  338,  338,  339,  339,  340,  340,  341,  341,  342,  342,  343,  343,  344,  344,  345,
+        345,  346,  346,  347,  347,  348,  348,  349,  349,  350,  351,  351,  352,  352,  353,  353,
+        354,  354,  355,  355,  356,  356,  357,  357,  358,  358,  359,  360,  360,  361,  361,  362,
+        362,  363,  363,  364,  364,  365,  365,  366,  366,  367,  368,  368,  369,  369,  370,  370,
+        371,  371,  372,  372,  373,  373,  374,  375,  375,  376,  376,  377,  377,  378,  378,  379,
+        379,  380,  381,  381,  382,  382,  383,  383,  384,  384,  385,  386,  386,  387,  387,  388,
+        388,  389,  389,  390,  391,  391,  392,  392,  393,  393,  394,  394,  395,  396,  396,  397,
+        397,  398,  398,  399,  399,  400,  401,  401,  402,  402,  403,  403,  404,  405,  405,  406,
+        406,  407,  407,  408,  409,  409,  410,  410,  411,  411,  412,  413,  413,  414,  414,  415,
+        415,  416,  417,  417,  418,  418,  419,  419,  420,  421,  421,  422,  422,  423,  424,  424,
+        425,  425,  426,  426,  427,  428,  428,  429,  429,  430,  431,  431,  432,  432,  433,  433,
+        434,  435,  435,  436,  436,  437,  438,  438,  439,  439,  440,  441,  441,  442,  442,  443,
+        444,  444,  445,  445,  446,  447,  447,  448,  448,  449,  450,  450,  451,  451,  452,  453,
+        453,  454,  454,  455,  456,  456,  457,  457,  458,  459,  459,  460,  460,  461,  462,  462,
+        463,  463,  464,  465,  465,  466,  467,  467,  468,  468,  469,  470,  470,  471,  471,  472,
+        473,  473,  474,  475,  475,  476,  476,  477,  478,  478,  479,  480,  480,  481,  481,  482,
+        483,  483,  484,  485,  485,  486,  486,  487,  488,  488,  489,  490,  490,  491,  491,  492,
+        493,  493,  494,  495,  495,  496,  497,  497,  498,  498,  499,  500,  500,  501,  502,  502,
+        503,  504,  504,  505,  505,  506,  507,  507,  508,  509,  509,  510,  511,  511,  512,  513,
+        513,  514,  514,  515,  516,  516,  517,  518,  518,  519,  520,  520,  521,  522,  522,  523,
+        524,  524,  525,  526,  526,  527,  528,  528,  529,  529,  530,  531,  531,  532,  533,  533,
+        534,  535,  535,  536,  537,  537,  538,  539,  539,  540,  541,  541,  542,  543,  543,  544,
+        545,  545,  546,  547,  547,  548,  549,  549,  550,  551,  551,  552,  553,  553,  554,  555,
+        555,  556,  557,  557,  558,  559,  560,  560,  561,  562,  562,  563,  564,  564,  565,  566,
+        566,  567,  568,  568,  569,  570,  570,  571,  572,  572,  573,  574,  575,  575,  576,  577,
+        577,  578,  579,  579,  580,  581,  581,  582,  583,  584,  584,  585,  586,  586,  587,  588,
+        588,  589,  590,  590,  591,  592,  593,  593,  594,  595,  595,  596,  597,  598,  598,  599,
+        600,  600,  601,  602,  602,  603,  604,  605,  605,  606,  607,  607,  608,  609,  610,  610,
+        611,  612,  612,  613,  614,  615,  615,  616,  617,  617,  618,  619,  620,  620,  621,  622,
+        622,  623,  624,  625,  625,  626,  627,  627,  628,  629,  630,  630,  631,  632,  632,  633,
+        634,  635,  635,  636,  637,  638,  638,  639,  640,  640,  641,  642,  643,  643,  644,  645,
+        646,  646,  647,  648,  649,  649,  650,  651,  652,  652,  653,  654,  654,  655,  656,  657,
+        657,  658,  659,  660,  660,  661,  662,  663,  663,  664,  665,  666,  666,  667,  668,  669,
+        669,  670,  671,  672,  672,  673,  674,  675,  675,  676,  677,  678,  678,  679,  680,  681,
+        681,  682,  683,  684,  684,  685,  686,  687,  687,  688,  689,  690,  690,  691,  692,  693,
+        694,  694,  695,  696,  697,  697,  698,  699,  700,  700,  701,  702,  703,  703,  704,  705,
+        706,  707,  707,  708,  709,  710,  710,  711,  712,  713,  714,  714,  715,  716,  717,  717,
+        718,  719,  720,  720,  721,  722,  723,  724,  724,  725,  726,  727,  728,  728,  729,  730,
+        731,  731,  732,  733,  734,  735,  735,  736,  737,  738,  739,  739,  740,  741,  742,  742,
+        743,  744,  745,  746,  746,  747,  748,  749,  750,  750,  751,  752,  753,  754,  754,  755,
+        756,  757,  758,  758,  759,  760,  761,  762,  762,  763,  764,  765,  766,  766,  767,  768,
+        769,  770,  771,  771,  772,  773,  774,  775,  775,  776,  777,  778,  779,  779,  780,  781,
+        782,  783,  783,  784,  785,  786,  787,  788,  788,  789,  790,  791,  792,  793,  793,  794,
+        795,  796,  797,  797,  798,  799,  800,  801,  802,  802,  803,  804,  805,  806,  807,  807,
+        808,  809,  810,  811,  812,  812,  813,  814,  815,  816,  817,  817,  818,  819,  820,  821,
+        822,  822,  823,  824,  825,  826,  827,  827,  828,  829,  830,  831,  832,  832,  833,  834,
+        835,  836,  837,  838,  838,  839,  840,  841,  842,  843,  843,  844,  845,  846,  847,  848,
+        849,  849,  850,  851,  852,  853,  854,  855,  855,  856,  857,  858,  859,  860,  861,  861,
+        862,  863,  864,  865,  866,  867,  867,  868,  869,  870,  871,  872,  873,  873,  874,  875,
+        876,  877,  878,  879,  880,  880,  881,  882,  883,  884,  885,  886,  887,  887,  888,  889,
+        890,  891,  892,  893,  894,  894,  895,  896,  897,  898,  899,  900,  901,  901,  902,  903,
+        904,  905,  906,  907,  908,  909,  909,  910,  911,  912,  913,  914,  915,  916,  916,  917,
+        918,  919,  920,  921,  922,  923,  924,  925,  925,  926,  927,  928,  929,  930,  931,  932,
+        933,  933,  934,  935,  936,  937,  938,  939,  940,  941,  942,  942,  943,  944,  945,  946,
+        947,  948,  949,  950,  951,  952,  952,  953,  954,  955,  956,  957,  958,  959,  960,  961,
+        962,  962,  963,  964,  965,  966,  967,  968,  969,  970,  971,  972,  973,  973,  974,  975,
+        976,  977,  978,  979,  980,  981,  982,  983,  984,  985,  985,  986,  987,  988,  989,  990,
+        991,  992,  993,  994,  995,  996,  997,  998,  998,  999, 1000, 1001, 1002, 1003, 1004, 1005,
+       1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020,
+       1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1030, 1031, 1032, 1033, 1034, 1035,
+       1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1050,
+       1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066,
+       1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1078, 1079, 1080, 1081,
+       1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097,
+       1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113,
+       1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129,
+       1130, 1131, 1132, 1133, 1134, 1135, 1136, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145,
+       1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161,
+       1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, 1177,
+       1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1193, 1194,
+       1195, 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1210,
+       1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1223, 1224, 1225, 1226, 1227,
+       1228, 1229, 1230, 1231, 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, 1241, 1242, 1243,
+       1245, 1246, 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, 1259, 1260,
+       1261, 1262, 1264, 1265, 1266, 1267, 1268, 1269, 1270, 1271, 1272, 1273, 1274, 1275, 1276, 1277,
+       1278, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1291, 1292, 1293, 1295,
+       1296, 1297, 1298, 1299, 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1309, 1310, 1311, 1312,
+       1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329,
+       1330, 1331, 1332, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341, 1342, 1343, 1345, 1346, 1347,
+       1348, 1349, 1350, 1351, 1352, 1353, 1354, 1356, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1364,
+       1365, 1367, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1375, 1377, 1378, 1379, 1380, 1381, 1382,
+       1383, 1384, 1385, 1387, 1388, 1389, 1390, 1391, 1392, 1393, 1394, 1396, 1397, 1398, 1399, 1400,
+       1401, 1402, 1403, 1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412, 1414, 1415, 1416, 1417, 1418,
+       1419, 1420, 1421, 1423, 1424, 1425, 1426, 1427, 1428, 1429, 1431, 1432, 1433, 1434, 1435, 1436,
+       1437, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1448, 1449, 1450, 1451, 1452, 1453, 1455,
+       1456, 1457, 1458, 1459, 1460, 1461, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1471, 1472, 1473,
+       1474, 1475, 1476, 1478, 1479, 1480, 1481, 1482, 1483, 1484, 1486, 1487, 1488, 1489, 1490, 1491,
+       1493, 1494, 1495, 1496, 1497, 1498, 1500, 1501, 1502, 1503, 1504, 1505, 1507, 1508, 1509, 1510,
+       1511, 1512, 1514, 1515, 1516, 1517, 1518, 1519, 1521, 1522, 1523, 1524, 1525, 1527, 1528, 1529,
+       1530, 1531, 1532, 1534, 1535, 1536, 1537, 1538, 1540, 1541, 1542, 1543, 1544, 1545, 1547, 1548,
+       1549, 1550, 1551, 1553, 1554, 1555, 1556, 1557, 1559, 1560, 1561, 1562, 1563, 1564, 1566, 1567,
+       1568, 1569, 1570, 1572, 1573, 1574, 1575, 1576, 1578, 1579, 1580, 1581, 1582, 1584, 1585, 1586,
+       1587, 1588, 1590, 1591, 1592, 1593, 1594, 1596, 1597, 1598, 1599, 1601, 1602, 1603, 1604, 1605,
+       1607, 1608, 1609, 1610, 1611, 1613, 1614, 1615, 1616, 1617, 1619, 1620, 1621, 1622, 1624, 1625,
+       1626, 1627, 1628, 1630, 1631, 1632, 1633, 1635, 1636, 1637, 1638, 1639, 1641, 1642, 1643, 1644,
+       1646, 1647, 1648, 1649, 1650, 1652, 1653, 1654, 1655, 1657, 1658, 1659, 1660, 1662, 1663, 1664,
+       1665, 1667, 1668, 1669, 1670, 1671, 1673, 1674, 1675, 1676, 1678, 1679, 1680, 1681, 1683, 1684,
+       1685, 1686, 1688, 1689, 1690, 1691, 1693, 1694, 1695, 1696, 1698, 1699, 1700, 1701, 1703, 1704,
+       1705, 1706, 1708, 1709, 1710, 1711, 1713, 1714, 1715, 1716, 1718, 1719, 1720, 1721, 1723, 1724,
+       1725, 1726, 1728, 1729, 1730, 1731, 1733, 1734, 1735, 1737, 1738, 1739, 1740, 1742, 1743, 1744,
+       1745, 1747, 1748, 1749, 1750, 1752, 1753, 1754, 1756, 1757, 1758, 1759, 1761, 1762, 1763, 1764,
+       1766, 1767, 1768, 1770, 1771, 1772, 1773, 1775, 1776, 1777, 1778, 1780, 1781, 1782, 1784, 1785,
+       1786, 1787, 1789, 1790, 1791, 1793, 1794, 1795, 1796, 1798, 1799, 1800, 1802, 1803, 1804, 1806,
+       1807, 1808, 1809, 1811, 1812, 1813, 1815, 1816, 1817, 1818, 1820, 1821, 1822, 1824, 1825, 1826,
+       1828, 1829, 1830, 1831, 1833, 1834, 1835, 1837, 1838, 1839, 1841, 1842, 1843, 1844, 1846, 1847,
+       1848, 1850, 1851, 1852, 1854, 1855, 1856, 1858, 1859, 1860, 1862, 1863, 1864, 1865, 1867, 1868,
+       1869, 1871, 1872, 1873, 1875, 1876, 1877, 1879, 1880, 1881, 1883, 1884, 1885, 1887, 1888, 1889,
+       1891, 1892, 1893, 1894, 1896, 1897, 1898, 1900, 1901, 1902, 1904, 1905, 1906, 1908, 1909, 1910,
+       1912, 1913, 1914, 1916, 1917, 1918, 1920, 1921, 1922, 1924, 1925, 1926, 1928, 1929, 1930, 1932,
+       1933, 1935, 1936, 1937, 1939, 1940, 1941, 1943, 1944, 1945, 1947, 1948, 1949, 1951, 1952, 1953,
+       1955, 1956, 1957, 1959, 1960, 1961, 1963, 1964, 1965, 1967, 1968, 1970, 1971, 1972, 1974, 1975,
+       1976, 1978, 1979, 1980, 1982, 1983, 1984, 1986, 1987, 1989, 1990, 1991, 1993, 1994, 1995, 1997,
+       1998, 1999, 2001, 2002, 2004, 2005, 2006, 2008, 2009, 2010, 2012, 2013, 2015, 2016, 2017, 2019,
+       2020, 2021, 2023, 2024, 2026, 2027, 2028, 2030, 2031, 2032, 2034, 2035, 2037, 2038, 2039, 2041,
+       2042, 2043, 2045, 2046, 2048, 2049, 2050, 2052, 2053, 2055, 2056, 2057, 2059, 2060, 2061, 2063,
+       2064, 2066, 2067, 2068, 2070, 2071, 2073, 2074, 2075, 2077, 2078, 2080, 2081, 2082, 2084, 2085,
+       2087, 2088, 2089, 2091, 2092, 2094, 2095, 2096, 2098, 2099, 2101, 2102, 2103, 2105, 2106, 2108,
+       2109, 2110, 2112, 2113, 2115, 2116, 2117, 2119, 2120, 2122, 2123, 2124, 2126, 2127, 2129, 2130,
+       2132, 2133, 2134, 2136, 2137, 2139, 2140, 2141, 2143, 2144, 2146, 2147, 2149, 2150, 2151, 2153,
+       2154, 2156, 2157, 2159, 2160, 2161, 2163, 2164, 2166, 2167, 2169, 2170, 2171, 2173, 2174, 2176,
+       2177, 2179, 2180, 2181, 2183, 2184, 2186, 2187, 2189, 2190, 2191, 2193, 2194, 2196, 2197, 2199,
+       2200, 2202, 2203, 2204, 2206, 2207, 2209, 2210, 2212, 2213, 2214, 2216, 2217, 2219, 2220, 2222,
+       2223, 2225, 2226, 2228, 2229, 2230, 2232, 2233, 2235, 2236, 2238, 2239, 2241, 2242, 2243, 2245,
+       2246, 2248, 2249, 2251, 2252, 2254, 2255, 2257, 2258, 2260, 2261, 2262, 2264, 2265, 2267, 2268,
+       2270, 2271, 2273, 2274, 2276, 2277, 2279, 2280, 2282, 2283, 2284, 2286, 2287, 2289, 2290, 2292,
+       2293, 2295, 2296, 2298, 2299, 2301, 2302, 2304, 2305, 2307, 2308, 2310, 2311, 2312, 2314, 2315,
+       2317, 2318, 2320, 2321, 2323, 2324, 2326, 2327, 2329, 2330, 2332, 2333, 2335, 2336, 2338, 2339,
+       2341, 2342, 2344, 2345, 2347, 2348, 2350, 2351, 2353, 2354, 2356, 2357, 2359, 2360, 2362, 2363,
+       2365, 2366, 2368, 2369, 2371, 2372, 2374, 2375, 2377, 2378, 2380, 2381, 2383, 2384, 2386, 2387,
+       2389, 2390, 2392, 2393, 2395, 2396, 2398, 2399, 2401, 2402, 2404, 2405, 2407, 2408, 2410, 2411,
+       2413, 2414, 2416, 2417, 2419, 2420, 2422, 2423, 2425, 2426, 2428, 2429, 2431, 2433, 2434, 2436,
+       2437, 2439, 2440, 2442, 2443, 2445, 2446, 2448, 2449, 2451, 2452, 2454, 2455, 2457, 2458, 2460,
+       2462, 2463, 2465, 2466, 2468, 2469, 2471, 2472, 2474, 2475, 2477, 2478, 2480, 2481, 2483, 2485,
+       2486, 2488, 2489, 2491, 2492, 2494, 2495, 2497, 2498, 2500, 2502, 2503, 2505, 2506, 2508, 2509,
+       2511, 2512, 2514, 2515, 2517, 2519, 2520, 2522, 2523, 2525, 2526, 2528, 2529, 2531, 2533, 2534,
+       2536, 2537, 2539, 2540, 2542, 2543, 2545, 2547, 2548, 2550, 2551, 2553, 2554, 2556, 2557, 2559,
+       2561, 2562, 2564, 2565, 2567, 2568, 2570, 2572, 2573, 2575, 2576, 2578, 2579, 2581, 2583, 2584,
+       2586, 2587, 2589, 2590, 2592, 2594, 2595, 2597, 2598, 2600, 2601, 2603, 2605, 2606, 2608, 2609,
+       2611, 2613, 2614, 2616, 2617, 2619, 2620, 2622, 2624, 2625, 2627, 2628, 2630, 2632, 2633, 2635,
+       2636, 2638, 2640, 2641, 2643, 2644, 2646, 2647, 2649, 2651, 2652, 2654, 2655, 2657, 2659, 2660,
+       2662, 2663, 2665, 2667, 2668, 2670, 2671, 2673, 2675, 2676, 2678, 2679, 2681, 2683, 2684, 2686,
+       2687, 2689, 2691, 2692, 2694, 2696, 2697, 2699, 2700, 2702, 2704, 2705, 2707, 2708, 2710, 2712,
+       2713, 2715, 2716, 2718, 2720, 2721, 2723, 2725, 2726, 2728, 2729, 2731, 2733, 2734, 2736, 2738,
+       2739, 2741, 2742, 2744, 2746, 2747, 2749, 2751, 2752, 2754, 2755, 2757, 2759, 2760, 2762, 2764,
+       2765, 2767, 2769, 2770, 2772, 2773, 2775, 2777, 2778, 2780, 2782, 2783, 2785, 2787, 2788, 2790,
+       2791, 2793, 2795, 2796, 2798, 2800, 2801, 2803, 2805, 2806, 2808, 2810, 2811, 2813, 2814, 2816,
+       2818, 2819, 2821, 2823, 2824, 2826, 2828, 2829, 2831, 2833, 2834, 2836, 2838, 2839, 2841, 2843,
+       2844, 2846, 2848, 2849, 2851, 2853, 2854, 2856, 2857, 2859, 2861, 2862, 2864, 2866, 2867, 2869,
+       2871, 2872, 2874, 2876, 2877, 2879, 2881, 2882, 2884, 2886, 2888, 2889, 2891, 2893, 2894, 2896,
+       2898, 2899, 2901, 2903, 2904, 2906, 2908, 2909, 2911, 2913, 2914, 2916, 2918, 2919, 2921, 2923,
+       2924, 2926, 2928, 2929, 2931, 2933, 2935, 2936, 2938, 2940, 2941, 2943, 2945, 2946, 2948, 2950,
+       2951, 2953, 2955, 2956, 2958, 2960, 2962, 2963, 2965, 2967, 2968, 2970, 2972, 2973, 2975, 2977,
+       2979, 2980, 2982, 2984, 2985, 2987, 2989, 2990, 2992, 2994, 2996, 2997, 2999, 3001, 3002, 3004,
+       3006, 3008, 3009, 3011, 3013, 3014, 3016, 3018, 3020, 3021, 3023, 3025, 3026, 3028, 3030, 3032,
+       3033, 3035, 3037, 3038, 3040, 3042, 3044, 3045, 3047, 3049, 3050, 3052, 3054, 3056, 3057, 3059,
+       3061, 3063, 3064, 3066, 3068, 3069, 3071, 3073, 3075, 3076, 3078, 3080, 3082, 3083, 3085, 3087,
+       3089, 3090, 3092, 3094, 3095, 3097, 3099, 3101, 3102, 3104, 3106, 3108, 3109, 3111, 3113, 3115,
+       3116, 3118, 3120, 3122, 3123, 3125, 3127, 3129, 3130, 3132, 3134, 3136, 3137, 3139, 3141, 3143,
+       3144, 3146, 3148, 3150, 3151, 3153, 3155, 3157, 3158, 3160, 3162, 3164, 3165, 3167, 3169, 3171,
+       3172, 3174, 3176, 3178, 3179, 3181, 3183, 3185, 3187, 3188, 3190, 3192, 3194, 3195, 3197, 3199,
+       3201, 3202, 3204, 3206, 3208, 3209, 3211, 3213, 3215, 3217, 3218, 3220, 3222, 3224, 3225, 3227,
+       3229, 3231, 3233, 3234, 3236, 3238, 3240, 3241, 3243, 3245, 3247, 3249, 3250, 3252, 3254, 3256,
+       3258, 3259, 3261, 3263, 3265, 3266, 3268, 3270, 3272, 3274, 3275, 3277, 3279, 3281, 3283, 3284,
+       3286, 3288, 3290, 3292, 3293, 3295, 3297, 3299, 3301, 3302, 3304, 3306, 3308, 3310, 3311, 3313,
+       3315, 3317, 3319, 3320, 3322, 3324, 3326, 3328, 3329, 3331, 3333, 3335, 3337, 3338, 3340, 3342,
+       3344, 3346, 3348, 3349, 3351, 3353, 3355, 3357, 3358, 3360, 3362, 3364, 3366, 3368, 3369, 3371,
+       3373, 3375, 3377, 3378, 3380, 3382, 3384, 3386, 3388, 3389, 3391, 3393, 3395, 3397, 3399, 3400,
+       3402, 3404, 3406, 3408, 3410, 3411, 3413, 3415, 3417, 3419, 3421, 3422, 3424, 3426, 3428, 3430,
+       3432, 3433, 3435, 3437, 3439, 3441, 3443, 3444, 3446, 3448, 3450, 3452, 3454, 3455, 3457, 3459,
+       3461, 3463, 3465, 3467, 3468, 3470, 3472, 3474, 3476, 3478, 3480, 3481, 3483, 3485, 3487, 3489,
+       3491, 3492, 3494, 3496, 3498, 3500, 3502, 3504, 3506, 3507, 3509, 3511, 3513, 3515, 3517, 3519,
+       3520, 3522, 3524, 3526, 3528, 3530, 3532, 3533, 3535, 3537, 3539, 3541, 3543, 3545, 3547, 3548,
+       3550, 3552, 3554, 3556, 3558, 3560, 3562, 3563, 3565, 3567, 3569, 3571, 3573, 3575, 3577, 3578,
+       3580, 3582, 3584, 3586, 3588, 3590, 3592, 3594, 3595, 3597, 3599, 3601, 3603, 3605, 3607, 3609,
+       3611, 3612, 3614, 3616, 3618, 3620, 3622, 3624, 3626, 3628, 3629, 3631, 3633, 3635, 3637, 3639,
+       3641, 3643, 3645, 3647, 3648, 3650, 3652, 3654, 3656, 3658, 3660, 3662, 3664, 3666, 3667, 3669,
+       3671, 3673, 3675, 3677, 3679, 3681, 3683, 3685, 3687, 3688, 3690, 3692, 3694, 3696, 3698, 3700,
+       3702, 3704, 3706, 3708, 3710, 3711, 3713, 3715, 3717, 3719, 3721, 3723, 3725, 3727, 3729, 3731,
+       3733, 3735, 3736, 3738, 3740, 3742, 3744, 3746, 3748, 3750, 3752, 3754, 3756, 3758, 3760, 3762,
+       3764, 3765, 3767, 3769, 3771, 3773, 3775, 3777, 3779, 3781, 3783, 3785, 3787, 3789, 3791, 3793,
+       3795, 3796, 3798, 3800, 3802, 3804, 3806, 3808, 3810, 3812, 3814, 3816, 3818, 3820, 3822, 3824,
+       3826, 3828, 3830, 3832, 3833, 3835, 3837, 3839, 3841, 3843, 3845, 3847, 3849, 3851, 3853, 3855,
+       3857, 3859, 3861, 3863, 3865, 3867, 3869, 3871, 3873, 3875, 3877, 3879, 3881, 3883, 3884, 3886,
+       3888, 3890, 3892, 3894, 3896, 3898, 3900, 3902, 3904, 3906, 3908, 3910, 3912, 3914, 3916, 3918,
+       3920, 3922, 3924, 3926, 3928, 3930, 3932, 3934, 3936, 3938, 3940, 3942, 3944, 3946, 3948, 3950,
+       3952, 3954, 3956, 3958, 3960, 3962, 3964, 3966, 3968, 3970, 3972, 3974, 3976, 3978, 3980, 3982,
+       3984, 3986, 3988, 3990, 3992, 3994, 3996, 3998, 4000, 4002, 4004, 4006, 4008, 4010, 4012, 4014,
+       4016, 4018, 4020, 4022, 4024, 4026, 4028, 4030, 4032, 4034, 4036, 4038, 4040, 4042, 4044, 4046,
+       4048, 4050, 4052, 4054, 4056, 4058, 4060, 4062, 4064, 4066, 4068, 4070, 4072, 4074, 4076, 4078,
+       4080,
+};
+
+/* Generated table */
+const unsigned short tpg_linear_to_rec709[255 * 16 + 1] = {
+          0,    5,    9,   14,   18,   22,   27,   32,   36,   41,   45,   50,   54,   59,   63,   68,
+         72,   77,   81,   86,   90,   95,   99,  104,  108,  113,  117,  122,  126,  131,  135,  139,
+        144,  149,  153,  158,  162,  167,  171,  176,  180,  185,  189,  194,  198,  203,  207,  212,
+        216,  221,  225,  230,  234,  239,  243,  248,  252,  257,  261,  266,  270,  275,  279,  284,
+        288,  293,  297,  302,  306,  311,  315,  320,  324,  328,  334,  338,  343,  347,  352,  356,
+        360,  365,  369,  373,  377,  381,  386,  390,  394,  398,  402,  406,  410,  414,  418,  422,
+        426,  430,  433,  437,  441,  445,  449,  452,  456,  460,  464,  467,  471,  475,  478,  482,
+        485,  489,  492,  496,  499,  503,  506,  510,  513,  517,  520,  524,  527,  530,  534,  537,
+        540,  544,  547,  550,  554,  557,  560,  563,  566,  570,  573,  576,  579,  582,  586,  589,
+        592,  595,  598,  601,  604,  607,  610,  613,  616,  619,  622,  625,  628,  631,  634,  637,
+        640,  643,  646,  649,  652,  655,  658,  660,  663,  666,  669,  672,  675,  677,  680,  683,
+        686,  689,  691,  694,  697,  700,  702,  705,  708,  711,  713,  716,  719,  721,  724,  727,
+        729,  732,  735,  737,  740,  743,  745,  748,  750,  753,  756,  758,  761,  763,  766,  768,
+        771,  773,  776,  779,  781,  784,  786,  789,  791,  794,  796,  799,  801,  803,  806,  808,
+        811,  813,  816,  818,  821,  823,  825,  828,  830,  833,  835,  837,  840,  842,  844,  847,
+        849,  851,  854,  856,  858,  861,  863,  865,  868,  870,  872,  875,  877,  879,  881,  884,
+        886,  888,  891,  893,  895,  897,  900,  902,  904,  906,  908,  911,  913,  915,  917,  919,
+        922,  924,  926,  928,  930,  933,  935,  937,  939,  941,  943,  946,  948,  950,  952,  954,
+        956,  958,  960,  963,  965,  967,  969,  971,  973,  975,  977,  979,  981,  984,  986,  988,
+        990,  992,  994,  996,  998, 1000, 1002, 1004, 1006, 1008, 1010, 1012, 1014, 1016, 1018, 1020,
+       1022, 1024, 1026, 1028, 1030, 1032, 1034, 1036, 1038, 1040, 1042, 1044, 1046, 1048, 1050, 1052,
+       1054, 1056, 1058, 1060, 1062, 1064, 1066, 1068, 1069, 1071, 1073, 1075, 1077, 1079, 1081, 1083,
+       1085, 1087, 1089, 1090, 1092, 1094, 1096, 1098, 1100, 1102, 1104, 1106, 1107, 1109, 1111, 1113,
+       1115, 1117, 1119, 1120, 1122, 1124, 1126, 1128, 1130, 1131, 1133, 1135, 1137, 1139, 1141, 1142,
+       1144, 1146, 1148, 1150, 1151, 1153, 1155, 1157, 1159, 1160, 1162, 1164, 1166, 1168, 1169, 1171,
+       1173, 1175, 1176, 1178, 1180, 1182, 1184, 1185, 1187, 1189, 1191, 1192, 1194, 1196, 1198, 1199,
+       1201, 1203, 1204, 1206, 1208, 1210, 1211, 1213, 1215, 1217, 1218, 1220, 1222, 1223, 1225, 1227,
+       1228, 1230, 1232, 1234, 1235, 1237, 1239, 1240, 1242, 1244, 1245, 1247, 1249, 1250, 1252, 1254,
+       1255, 1257, 1259, 1260, 1262, 1264, 1265, 1267, 1269, 1270, 1272, 1274, 1275, 1277, 1279, 1280,
+       1282, 1283, 1285, 1287, 1288, 1290, 1292, 1293, 1295, 1296, 1298, 1300, 1301, 1303, 1305, 1306,
+       1308, 1309, 1311, 1313, 1314, 1316, 1317, 1319, 1321, 1322, 1324, 1325, 1327, 1328, 1330, 1332,
+       1333, 1335, 1336, 1338, 1339, 1341, 1343, 1344, 1346, 1347, 1349, 1350, 1352, 1354, 1355, 1357,
+       1358, 1360, 1361, 1363, 1364, 1366, 1367, 1369, 1371, 1372, 1374, 1375, 1377, 1378, 1380, 1381,
+       1383, 1384, 1386, 1387, 1389, 1390, 1392, 1393, 1395, 1396, 1398, 1399, 1401, 1402, 1404, 1405,
+       1407, 1408, 1410, 1411, 1413, 1414, 1416, 1417, 1419, 1420, 1422, 1423, 1425, 1426, 1428, 1429,
+       1431, 1432, 1434, 1435, 1437, 1438, 1440, 1441, 1442, 1444, 1445, 1447, 1448, 1450, 1451, 1453,
+       1454, 1456, 1457, 1458, 1460, 1461, 1463, 1464, 1466, 1467, 1469, 1470, 1471, 1473, 1474, 1476,
+       1477, 1479, 1480, 1481, 1483, 1484, 1486, 1487, 1489, 1490, 1491, 1493, 1494, 1496, 1497, 1498,
+       1500, 1501, 1503, 1504, 1505, 1507, 1508, 1510, 1511, 1512, 1514, 1515, 1517, 1518, 1519, 1521,
+       1522, 1524, 1525, 1526, 1528, 1529, 1531, 1532, 1533, 1535, 1536, 1537, 1539, 1540, 1542, 1543,
+       1544, 1546, 1547, 1548, 1550, 1551, 1553, 1554, 1555, 1557, 1558, 1559, 1561, 1562, 1563, 1565,
+       1566, 1567, 1569, 1570, 1571, 1573, 1574, 1576, 1577, 1578, 1580, 1581, 1582, 1584, 1585, 1586,
+       1588, 1589, 1590, 1592, 1593, 1594, 1596, 1597, 1598, 1600, 1601, 1602, 1603, 1605, 1606, 1607,
+       1609, 1610, 1611, 1613, 1614, 1615, 1617, 1618, 1619, 1621, 1622, 1623, 1624, 1626, 1627, 1628,
+       1630, 1631, 1632, 1634, 1635, 1636, 1637, 1639, 1640, 1641, 1643, 1644, 1645, 1647, 1648, 1649,
+       1650, 1652, 1653, 1654, 1655, 1657, 1658, 1659, 1661, 1662, 1663, 1664, 1666, 1667, 1668, 1670,
+       1671, 1672, 1673, 1675, 1676, 1677, 1678, 1680, 1681, 1682, 1683, 1685, 1686, 1687, 1688, 1690,
+       1691, 1692, 1693, 1695, 1696, 1697, 1698, 1700, 1701, 1702, 1703, 1705, 1706, 1707, 1708, 1710,
+       1711, 1712, 1713, 1715, 1716, 1717, 1718, 1720, 1721, 1722, 1723, 1724, 1726, 1727, 1728, 1729,
+       1731, 1732, 1733, 1734, 1736, 1737, 1738, 1739, 1740, 1742, 1743, 1744, 1745, 1746, 1748, 1749,
+       1750, 1751, 1753, 1754, 1755, 1756, 1757, 1759, 1760, 1761, 1762, 1763, 1765, 1766, 1767, 1768,
+       1769, 1771, 1772, 1773, 1774, 1775, 1777, 1778, 1779, 1780, 1781, 1783, 1784, 1785, 1786, 1787,
+       1788, 1790, 1791, 1792, 1793, 1794, 1796, 1797, 1798, 1799, 1800, 1801, 1803, 1804, 1805, 1806,
+       1807, 1809, 1810, 1811, 1812, 1813, 1814, 1816, 1817, 1818, 1819, 1820, 1821, 1823, 1824, 1825,
+       1826, 1827, 1828, 1829, 1831, 1832, 1833, 1834, 1835, 1836, 1838, 1839, 1840, 1841, 1842, 1843,
+       1845, 1846, 1847, 1848, 1849, 1850, 1851, 1853, 1854, 1855, 1856, 1857, 1858, 1859, 1861, 1862,
+       1863, 1864, 1865, 1866, 1867, 1868, 1870, 1871, 1872, 1873, 1874, 1875, 1876, 1878, 1879, 1880,
+       1881, 1882, 1883, 1884, 1885, 1887, 1888, 1889, 1890, 1891, 1892, 1893, 1894, 1896, 1897, 1898,
+       1899, 1900, 1901, 1902, 1903, 1904, 1906, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914, 1916,
+       1917, 1918, 1919, 1920, 1921, 1922, 1923, 1924, 1925, 1927, 1928, 1929, 1930, 1931, 1932, 1933,
+       1934, 1935, 1936, 1938, 1939, 1940, 1941, 1942, 1943, 1944, 1945, 1946, 1947, 1948, 1950, 1951,
+       1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960, 1961, 1963, 1964, 1965, 1966, 1967, 1968,
+       1969, 1970, 1971, 1972, 1973, 1974, 1975, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985,
+       1986, 1987, 1988, 1989, 1990, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+       2003, 2004, 2005, 2006, 2007, 2008, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
+       2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2031, 2032, 2033, 2034, 2035, 2036,
+       2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050, 2051, 2052,
+       2053, 2054, 2055, 2056, 2057, 2058, 2060, 2061, 2062, 2063, 2064, 2065, 2066, 2067, 2068, 2069,
+       2070, 2071, 2072, 2073, 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2085,
+       2086, 2087, 2088, 2089, 2090, 2091, 2092, 2093, 2094, 2095, 2096, 2097, 2098, 2099, 2100, 2101,
+       2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2114, 2115, 2116, 2117,
+       2118, 2119, 2120, 2121, 2122, 2123, 2124, 2125, 2126, 2127, 2128, 2129, 2130, 2131, 2132, 2133,
+       2134, 2135, 2136, 2137, 2138, 2139, 2140, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2149,
+       2150, 2151, 2152, 2153, 2154, 2155, 2156, 2157, 2158, 2159, 2160, 2161, 2162, 2163, 2164, 2165,
+       2166, 2167, 2168, 2169, 2170, 2171, 2172, 2173, 2173, 2174, 2175, 2176, 2177, 2178, 2179, 2180,
+       2181, 2182, 2183, 2184, 2185, 2186, 2187, 2188, 2189, 2190, 2191, 2192, 2193, 2194, 2195, 2196,
+       2197, 2198, 2199, 2200, 2201, 2202, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2210, 2211,
+       2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2221, 2222, 2223, 2224, 2224, 2225, 2226,
+       2227, 2228, 2229, 2230, 2231, 2232, 2233, 2234, 2235, 2236, 2237, 2238, 2239, 2240, 2241, 2241,
+       2242, 2243, 2244, 2245, 2246, 2247, 2248, 2249, 2250, 2251, 2252, 2253, 2254, 2255, 2256, 2257,
+       2257, 2258, 2259, 2260, 2261, 2262, 2263, 2264, 2265, 2266, 2267, 2268, 2269, 2270, 2271, 2271,
+       2272, 2273, 2274, 2275, 2276, 2277, 2278, 2279, 2280, 2281, 2282, 2283, 2283, 2284, 2285, 2286,
+       2287, 2288, 2289, 2290, 2291, 2292, 2293, 2294, 2295, 2295, 2296, 2297, 2298, 2299, 2300, 2301,
+       2302, 2303, 2304, 2305, 2306, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2315, 2316,
+       2317, 2317, 2318, 2319, 2320, 2321, 2322, 2323, 2324, 2325, 2326, 2327, 2327, 2328, 2329, 2330,
+       2331, 2332, 2333, 2334, 2335, 2336, 2336, 2337, 2338, 2339, 2340, 2341, 2342, 2343, 2344, 2345,
+       2345, 2346, 2347, 2348, 2349, 2350, 2351, 2352, 2353, 2354, 2354, 2355, 2356, 2357, 2358, 2359,
+       2360, 2361, 2362, 2363, 2363, 2364, 2365, 2366, 2367, 2368, 2369, 2370, 2371, 2371, 2372, 2373,
+       2374, 2375, 2376, 2377, 2378, 2379, 2379, 2380, 2381, 2382, 2383, 2384, 2385, 2386, 2386, 2387,
+       2388, 2389, 2390, 2391, 2392, 2393, 2394, 2394, 2395, 2396, 2397, 2398, 2399, 2400, 2401, 2401,
+       2402, 2403, 2404, 2405, 2406, 2407, 2408, 2408, 2409, 2410, 2411, 2412, 2413, 2414, 2415, 2415,
+       2416, 2417, 2418, 2419, 2420, 2421, 2422, 2422, 2423, 2424, 2425, 2426, 2427, 2428, 2428, 2429,
+       2430, 2431, 2432, 2433, 2434, 2435, 2435, 2436, 2437, 2438, 2439, 2440, 2441, 2441, 2442, 2443,
+       2444, 2445, 2446, 2447, 2447, 2448, 2449, 2450, 2451, 2452, 2453, 2453, 2454, 2455, 2456, 2457,
+       2458, 2459, 2459, 2460, 2461, 2462, 2463, 2464, 2465, 2465, 2466, 2467, 2468, 2469, 2470, 2471,
+       2471, 2472, 2473, 2474, 2475, 2476, 2477, 2477, 2478, 2479, 2480, 2481, 2482, 2482, 2483, 2484,
+       2485, 2486, 2487, 2488, 2488, 2489, 2490, 2491, 2492, 2493, 2493, 2494, 2495, 2496, 2497, 2498,
+       2499, 2499, 2500, 2501, 2502, 2503, 2504, 2504, 2505, 2506, 2507, 2508, 2509, 2509, 2510, 2511,
+       2512, 2513, 2514, 2514, 2515, 2516, 2517, 2518, 2519, 2519, 2520, 2521, 2522, 2523, 2524, 2524,
+       2525, 2526, 2527, 2528, 2529, 2529, 2530, 2531, 2532, 2533, 2534, 2534, 2535, 2536, 2537, 2538,
+       2539, 2539, 2540, 2541, 2542, 2543, 2544, 2544, 2545, 2546, 2547, 2548, 2548, 2549, 2550, 2551,
+       2552, 2553, 2553, 2554, 2555, 2556, 2557, 2558, 2558, 2559, 2560, 2561, 2562, 2562, 2563, 2564,
+       2565, 2566, 2567, 2567, 2568, 2569, 2570, 2571, 2571, 2572, 2573, 2574, 2575, 2576, 2576, 2577,
+       2578, 2579, 2580, 2580, 2581, 2582, 2583, 2584, 2584, 2585, 2586, 2587, 2588, 2589, 2589, 2590,
+       2591, 2592, 2593, 2593, 2594, 2595, 2596, 2597, 2597, 2598, 2599, 2600, 2601, 2601, 2602, 2603,
+       2604, 2605, 2605, 2606, 2607, 2608, 2609, 2610, 2610, 2611, 2612, 2613, 2614, 2614, 2615, 2616,
+       2617, 2618, 2618, 2619, 2620, 2621, 2622, 2622, 2623, 2624, 2625, 2626, 2626, 2627, 2628, 2629,
+       2630, 2630, 2631, 2632, 2633, 2634, 2634, 2635, 2636, 2637, 2637, 2638, 2639, 2640, 2641, 2641,
+       2642, 2643, 2644, 2645, 2645, 2646, 2647, 2648, 2649, 2649, 2650, 2651, 2652, 2653, 2653, 2654,
+       2655, 2656, 2656, 2657, 2658, 2659, 2660, 2660, 2661, 2662, 2663, 2664, 2664, 2665, 2666, 2667,
+       2668, 2668, 2669, 2670, 2671, 2671, 2672, 2673, 2674, 2675, 2675, 2676, 2677, 2678, 2678, 2679,
+       2680, 2681, 2682, 2682, 2683, 2684, 2685, 2686, 2686, 2687, 2688, 2689, 2689, 2690, 2691, 2692,
+       2693, 2693, 2694, 2695, 2696, 2696, 2697, 2698, 2699, 2700, 2700, 2701, 2702, 2703, 2703, 2704,
+       2705, 2706, 2706, 2707, 2708, 2709, 2710, 2710, 2711, 2712, 2713, 2713, 2714, 2715, 2716, 2717,
+       2717, 2718, 2719, 2720, 2720, 2721, 2722, 2723, 2723, 2724, 2725, 2726, 2727, 2727, 2728, 2729,
+       2730, 2730, 2731, 2732, 2733, 2733, 2734, 2735, 2736, 2736, 2737, 2738, 2739, 2740, 2740, 2741,
+       2742, 2743, 2743, 2744, 2745, 2746, 2746, 2747, 2748, 2749, 2749, 2750, 2751, 2752, 2752, 2753,
+       2754, 2755, 2755, 2756, 2757, 2758, 2759, 2759, 2760, 2761, 2762, 2762, 2763, 2764, 2765, 2765,
+       2766, 2767, 2768, 2768, 2769, 2770, 2771, 2771, 2772, 2773, 2774, 2774, 2775, 2776, 2777, 2777,
+       2778, 2779, 2780, 2780, 2781, 2782, 2783, 2783, 2784, 2785, 2786, 2786, 2787, 2788, 2789, 2789,
+       2790, 2791, 2792, 2792, 2793, 2794, 2795, 2795, 2796, 2797, 2798, 2798, 2799, 2800, 2801, 2801,
+       2802, 2803, 2804, 2804, 2805, 2806, 2807, 2807, 2808, 2809, 2810, 2810, 2811, 2812, 2813, 2813,
+       2814, 2815, 2815, 2816, 2817, 2818, 2818, 2819, 2820, 2821, 2821, 2822, 2823, 2824, 2824, 2825,
+       2826, 2827, 2827, 2828, 2829, 2830, 2830, 2831, 2832, 2832, 2833, 2834, 2835, 2835, 2836, 2837,
+       2838, 2838, 2839, 2840, 2841, 2841, 2842, 2843, 2844, 2844, 2845, 2846, 2846, 2847, 2848, 2849,
+       2849, 2850, 2851, 2852, 2852, 2853, 2854, 2855, 2855, 2856, 2857, 2857, 2858, 2859, 2860, 2860,
+       2861, 2862, 2863, 2863, 2864, 2865, 2865, 2866, 2867, 2868, 2868, 2869, 2870, 2871, 2871, 2872,
+       2873, 2873, 2874, 2875, 2876, 2876, 2877, 2878, 2879, 2879, 2880, 2881, 2881, 2882, 2883, 2884,
+       2884, 2885, 2886, 2886, 2887, 2888, 2889, 2889, 2890, 2891, 2892, 2892, 2893, 2894, 2894, 2895,
+       2896, 2897, 2897, 2898, 2899, 2899, 2900, 2901, 2902, 2902, 2903, 2904, 2904, 2905, 2906, 2907,
+       2907, 2908, 2909, 2909, 2910, 2911, 2912, 2912, 2913, 2914, 2914, 2915, 2916, 2917, 2917, 2918,
+       2919, 2919, 2920, 2921, 2922, 2922, 2923, 2924, 2924, 2925, 2926, 2927, 2927, 2928, 2929, 2929,
+       2930, 2931, 2932, 2932, 2933, 2934, 2934, 2935, 2936, 2937, 2937, 2938, 2939, 2939, 2940, 2941,
+       2941, 2942, 2943, 2944, 2944, 2945, 2946, 2946, 2947, 2948, 2949, 2949, 2950, 2951, 2951, 2952,
+       2953, 2953, 2954, 2955, 2956, 2956, 2957, 2958, 2958, 2959, 2960, 2961, 2961, 2962, 2963, 2963,
+       2964, 2965, 2965, 2966, 2967, 2968, 2968, 2969, 2970, 2970, 2971, 2972, 2972, 2973, 2974, 2975,
+       2975, 2976, 2977, 2977, 2978, 2979, 2979, 2980, 2981, 2982, 2982, 2983, 2984, 2984, 2985, 2986,
+       2986, 2987, 2988, 2988, 2989, 2990, 2991, 2991, 2992, 2993, 2993, 2994, 2995, 2995, 2996, 2997,
+       2998, 2998, 2999, 3000, 3000, 3001, 3002, 3002, 3003, 3004, 3004, 3005, 3006, 3006, 3007, 3008,
+       3009, 3009, 3010, 3011, 3011, 3012, 3013, 3013, 3014, 3015, 3015, 3016, 3017, 3018, 3018, 3019,
+       3020, 3020, 3021, 3022, 3022, 3023, 3024, 3024, 3025, 3026, 3026, 3027, 3028, 3029, 3029, 3030,
+       3031, 3031, 3032, 3033, 3033, 3034, 3035, 3035, 3036, 3037, 3037, 3038, 3039, 3039, 3040, 3041,
+       3042, 3042, 3043, 3044, 3044, 3045, 3046, 3046, 3047, 3048, 3048, 3049, 3050, 3050, 3051, 3052,
+       3052, 3053, 3054, 3054, 3055, 3056, 3056, 3057, 3058, 3059, 3059, 3060, 3061, 3061, 3062, 3063,
+       3063, 3064, 3065, 3065, 3066, 3067, 3067, 3068, 3069, 3069, 3070, 3071, 3071, 3072, 3073, 3073,
+       3074, 3075, 3075, 3076, 3077, 3077, 3078, 3079, 3079, 3080, 3081, 3081, 3082, 3083, 3084, 3084,
+       3085, 3086, 3086, 3087, 3088, 3088, 3089, 3090, 3090, 3091, 3092, 3092, 3093, 3094, 3094, 3095,
+       3096, 3096, 3097, 3098, 3098, 3099, 3100, 3100, 3101, 3102, 3102, 3103, 3104, 3104, 3105, 3106,
+       3106, 3107, 3108, 3108, 3109, 3110, 3110, 3111, 3112, 3112, 3113, 3114, 3114, 3115, 3116, 3116,
+       3117, 3118, 3118, 3119, 3120, 3120, 3121, 3122, 3122, 3123, 3124, 3124, 3125, 3126, 3126, 3127,
+       3128, 3128, 3129, 3130, 3130, 3131, 3132, 3132, 3133, 3134, 3134, 3135, 3135, 3136, 3137, 3137,
+       3138, 3139, 3139, 3140, 3141, 3141, 3142, 3143, 3143, 3144, 3145, 3145, 3146, 3147, 3147, 3148,
+       3149, 3149, 3150, 3151, 3151, 3152, 3153, 3153, 3154, 3155, 3155, 3156, 3157, 3157, 3158, 3159,
+       3159, 3160, 3160, 3161, 3162, 3162, 3163, 3164, 3164, 3165, 3166, 3166, 3167, 3168, 3168, 3169,
+       3170, 3170, 3171, 3172, 3172, 3173, 3174, 3174, 3175, 3175, 3176, 3177, 3177, 3178, 3179, 3179,
+       3180, 3181, 3181, 3182, 3183, 3183, 3184, 3185, 3185, 3186, 3187, 3187, 3188, 3188, 3189, 3190,
+       3190, 3191, 3192, 3192, 3193, 3194, 3194, 3195, 3196, 3196, 3197, 3198, 3198, 3199, 3199, 3200,
+       3201, 3201, 3202, 3203, 3203, 3204, 3205, 3205, 3206, 3207, 3207, 3208, 3209, 3209, 3210, 3210,
+       3211, 3212, 3212, 3213, 3214, 3214, 3215, 3216, 3216, 3217, 3218, 3218, 3219, 3219, 3220, 3221,
+       3221, 3222, 3223, 3223, 3224, 3225, 3225, 3226, 3227, 3227, 3228, 3228, 3229, 3230, 3230, 3231,
+       3232, 3232, 3233, 3234, 3234, 3235, 3235, 3236, 3237, 3237, 3238, 3239, 3239, 3240, 3241, 3241,
+       3242, 3242, 3243, 3244, 3244, 3245, 3246, 3246, 3247, 3248, 3248, 3249, 3249, 3250, 3251, 3251,
+       3252, 3253, 3253, 3254, 3255, 3255, 3256, 3256, 3257, 3258, 3258, 3259, 3260, 3260, 3261, 3262,
+       3262, 3263, 3263, 3264, 3265, 3265, 3266, 3267, 3267, 3268, 3268, 3269, 3270, 3270, 3271, 3272,
+       3272, 3273, 3274, 3274, 3275, 3275, 3276, 3277, 3277, 3278, 3279, 3279, 3280, 3280, 3281, 3282,
+       3282, 3283, 3284, 3284, 3285, 3285, 3286, 3287, 3287, 3288, 3289, 3289, 3290, 3290, 3291, 3292,
+       3292, 3293, 3294, 3294, 3295, 3295, 3296, 3297, 3297, 3298, 3299, 3299, 3300, 3300, 3301, 3302,
+       3302, 3303, 3304, 3304, 3305, 3305, 3306, 3307, 3307, 3308, 3309, 3309, 3310, 3310, 3311, 3312,
+       3312, 3313, 3314, 3314, 3315, 3315, 3316, 3317, 3317, 3318, 3319, 3319, 3320, 3320, 3321, 3322,
+       3322, 3323, 3323, 3324, 3325, 3325, 3326, 3327, 3327, 3328, 3328, 3329, 3330, 3330, 3331, 3332,
+       3332, 3333, 3333, 3334, 3335, 3335, 3336, 3336, 3337, 3338, 3338, 3339, 3340, 3340, 3341, 3341,
+       3342, 3343, 3343, 3344, 3345, 3345, 3346, 3346, 3347, 3348, 3348, 3349, 3349, 3350, 3351, 3351,
+       3352, 3352, 3353, 3354, 3354, 3355, 3356, 3356, 3357, 3357, 3358, 3359, 3359, 3360, 3360, 3361,
+       3362, 3362, 3363, 3364, 3364, 3365, 3365, 3366, 3367, 3367, 3368, 3368, 3369, 3370, 3370, 3371,
+       3371, 3372, 3373, 3373, 3374, 3375, 3375, 3376, 3376, 3377, 3378, 3378, 3379, 3379, 3380, 3381,
+       3381, 3382, 3382, 3383, 3384, 3384, 3385, 3385, 3386, 3387, 3387, 3388, 3389, 3389, 3390, 3390,
+       3391, 3392, 3392, 3393, 3393, 3394, 3395, 3395, 3396, 3396, 3397, 3398, 3398, 3399, 3399, 3400,
+       3401, 3401, 3402, 3402, 3403, 3404, 3404, 3405, 3405, 3406, 3407, 3407, 3408, 3408, 3409, 3410,
+       3410, 3411, 3411, 3412, 3413, 3413, 3414, 3414, 3415, 3416, 3416, 3417, 3418, 3418, 3419, 3419,
+       3420, 3421, 3421, 3422, 3422, 3423, 3424, 3424, 3425, 3425, 3426, 3427, 3427, 3428, 3428, 3429,
+       3430, 3430, 3431, 3431, 3432, 3433, 3433, 3434, 3434, 3435, 3435, 3436, 3437, 3437, 3438, 3438,
+       3439, 3440, 3440, 3441, 3441, 3442, 3443, 3443, 3444, 3444, 3445, 3446, 3446, 3447, 3447, 3448,
+       3449, 3449, 3450, 3450, 3451, 3452, 3452, 3453, 3453, 3454, 3455, 3455, 3456, 3456, 3457, 3458,
+       3458, 3459, 3459, 3460, 3461, 3461, 3462, 3462, 3463, 3463, 3464, 3465, 3465, 3466, 3466, 3467,
+       3468, 3468, 3469, 3469, 3470, 3471, 3471, 3472, 3472, 3473, 3474, 3474, 3475, 3475, 3476, 3476,
+       3477, 3478, 3478, 3479, 3479, 3480, 3481, 3481, 3482, 3482, 3483, 3484, 3484, 3485, 3485, 3486,
+       3486, 3487, 3488, 3488, 3489, 3489, 3490, 3491, 3491, 3492, 3492, 3493, 3494, 3494, 3495, 3495,
+       3496, 3496, 3497, 3498, 3498, 3499, 3499, 3500, 3501, 3501, 3502, 3502, 3503, 3504, 3504, 3505,
+       3505, 3506, 3506, 3507, 3508, 3508, 3509, 3509, 3510, 3511, 3511, 3512, 3512, 3513, 3513, 3514,
+       3515, 3515, 3516, 3516, 3517, 3518, 3518, 3519, 3519, 3520, 3520, 3521, 3522, 3522, 3523, 3523,
+       3524, 3525, 3525, 3526, 3526, 3527, 3527, 3528, 3529, 3529, 3530, 3530, 3531, 3531, 3532, 3533,
+       3533, 3534, 3534, 3535, 3536, 3536, 3537, 3537, 3538, 3538, 3539, 3540, 3540, 3541, 3541, 3542,
+       3542, 3543, 3544, 3544, 3545, 3545, 3546, 3547, 3547, 3548, 3548, 3549, 3549, 3550, 3551, 3551,
+       3552, 3552, 3553, 3553, 3554, 3555, 3555, 3556, 3556, 3557, 3557, 3558, 3559, 3559, 3560, 3560,
+       3561, 3561, 3562, 3563, 3563, 3564, 3564, 3565, 3566, 3566, 3567, 3567, 3568, 3568, 3569, 3570,
+       3570, 3571, 3571, 3572, 3572, 3573, 3574, 3574, 3575, 3575, 3576, 3576, 3577, 3578, 3578, 3579,
+       3579, 3580, 3580, 3581, 3582, 3582, 3583, 3583, 3584, 3584, 3585, 3586, 3586, 3587, 3587, 3588,
+       3588, 3589, 3590, 3590, 3591, 3591, 3592, 3592, 3593, 3594, 3594, 3595, 3595, 3596, 3596, 3597,
+       3597, 3598, 3599, 3599, 3600, 3600, 3601, 3601, 3602, 3603, 3603, 3604, 3604, 3605, 3605, 3606,
+       3607, 3607, 3608, 3608, 3609, 3609, 3610, 3611, 3611, 3612, 3612, 3613, 3613, 3614, 3615, 3615,
+       3616, 3616, 3617, 3617, 3618, 3618, 3619, 3620, 3620, 3621, 3621, 3622, 3622, 3623, 3624, 3624,
+       3625, 3625, 3626, 3626, 3627, 3627, 3628, 3629, 3629, 3630, 3630, 3631, 3631, 3632, 3633, 3633,
+       3634, 3634, 3635, 3635, 3636, 3636, 3637, 3638, 3638, 3639, 3639, 3640, 3640, 3641, 3642, 3642,
+       3643, 3643, 3644, 3644, 3645, 3645, 3646, 3647, 3647, 3648, 3648, 3649, 3649, 3650, 3650, 3651,
+       3652, 3652, 3653, 3653, 3654, 3654, 3655, 3656, 3656, 3657, 3657, 3658, 3658, 3659, 3659, 3660,
+       3661, 3661, 3662, 3662, 3663, 3663, 3664, 3664, 3665, 3666, 3666, 3667, 3667, 3668, 3668, 3669,
+       3669, 3670, 3671, 3671, 3672, 3672, 3673, 3673, 3674, 3674, 3675, 3676, 3676, 3677, 3677, 3678,
+       3678, 3679, 3679, 3680, 3681, 3681, 3682, 3682, 3683, 3683, 3684, 3684, 3685, 3686, 3686, 3687,
+       3687, 3688, 3688, 3689, 3689, 3690, 3691, 3691, 3692, 3692, 3693, 3693, 3694, 3694, 3695, 3695,
+       3696, 3697, 3697, 3698, 3698, 3699, 3699, 3700, 3700, 3701, 3702, 3702, 3703, 3703, 3704, 3704,
+       3705, 3705, 3706, 3707, 3707, 3708, 3708, 3709, 3709, 3710, 3710, 3711, 3711, 3712, 3713, 3713,
+       3714, 3714, 3715, 3715, 3716, 3716, 3717, 3717, 3718, 3719, 3719, 3720, 3720, 3721, 3721, 3722,
+       3722, 3723, 3724, 3724, 3725, 3725, 3726, 3726, 3727, 3727, 3728, 3728, 3729, 3730, 3730, 3731,
+       3731, 3732, 3732, 3733, 3733, 3734, 3734, 3735, 3736, 3736, 3737, 3737, 3738, 3738, 3739, 3739,
+       3740, 3740, 3741, 3742, 3742, 3743, 3743, 3744, 3744, 3745, 3745, 3746, 3746, 3747, 3748, 3748,
+       3749, 3749, 3750, 3750, 3751, 3751, 3752, 3752, 3753, 3753, 3754, 3755, 3755, 3756, 3756, 3757,
+       3757, 3758, 3758, 3759, 3759, 3760, 3761, 3761, 3762, 3762, 3763, 3763, 3764, 3764, 3765, 3765,
+       3766, 3766, 3767, 3768, 3768, 3769, 3769, 3770, 3770, 3771, 3771, 3772, 3772, 3773, 3773, 3774,
+       3775, 3775, 3776, 3776, 3777, 3777, 3778, 3778, 3779, 3779, 3780, 3781, 3781, 3782, 3782, 3783,
+       3783, 3784, 3784, 3785, 3785, 3786, 3786, 3787, 3787, 3788, 3789, 3789, 3790, 3790, 3791, 3791,
+       3792, 3792, 3793, 3793, 3794, 3794, 3795, 3796, 3796, 3797, 3797, 3798, 3798, 3799, 3799, 3800,
+       3800, 3801, 3801, 3802, 3802, 3803, 3804, 3804, 3805, 3805, 3806, 3806, 3807, 3807, 3808, 3808,
+       3809, 3809, 3810, 3811, 3811, 3812, 3812, 3813, 3813, 3814, 3814, 3815, 3815, 3816, 3816, 3817,
+       3817, 3818, 3819, 3819, 3820, 3820, 3821, 3821, 3822, 3822, 3823, 3823, 3824, 3824, 3825, 3825,
+       3826, 3826, 3827, 3828, 3828, 3829, 3829, 3830, 3830, 3831, 3831, 3832, 3832, 3833, 3833, 3834,
+       3834, 3835, 3835, 3836, 3837, 3837, 3838, 3838, 3839, 3839, 3840, 3840, 3841, 3841, 3842, 3842,
+       3843, 3843, 3844, 3844, 3845, 3846, 3846, 3847, 3847, 3848, 3848, 3849, 3849, 3850, 3850, 3851,
+       3851, 3852, 3852, 3853, 3853, 3854, 3855, 3855, 3856, 3856, 3857, 3857, 3858, 3858, 3859, 3859,
+       3860, 3860, 3861, 3861, 3862, 3862, 3863, 3863, 3864, 3864, 3865, 3866, 3866, 3867, 3867, 3868,
+       3868, 3869, 3869, 3870, 3870, 3871, 3871, 3872, 3872, 3873, 3873, 3874, 3874, 3875, 3876, 3876,
+       3877, 3877, 3878, 3878, 3879, 3879, 3880, 3880, 3881, 3881, 3882, 3882, 3883, 3883, 3884, 3884,
+       3885, 3885, 3886, 3886, 3887, 3888, 3888, 3889, 3889, 3890, 3890, 3891, 3891, 3892, 3892, 3893,
+       3893, 3894, 3894, 3895, 3895, 3896, 3896, 3897, 3897, 3898, 3898, 3899, 3900, 3900, 3901, 3901,
+       3902, 3902, 3903, 3903, 3904, 3904, 3905, 3905, 3906, 3906, 3907, 3907, 3908, 3908, 3909, 3909,
+       3910, 3910, 3911, 3911, 3912, 3912, 3913, 3914, 3914, 3915, 3915, 3916, 3916, 3917, 3917, 3918,
+       3918, 3919, 3919, 3920, 3920, 3921, 3921, 3922, 3922, 3923, 3923, 3924, 3924, 3925, 3925, 3926,
+       3926, 3927, 3927, 3928, 3929, 3929, 3930, 3930, 3931, 3931, 3932, 3932, 3933, 3933, 3934, 3934,
+       3935, 3935, 3936, 3936, 3937, 3937, 3938, 3938, 3939, 3939, 3940, 3940, 3941, 3941, 3942, 3942,
+       3943, 3943, 3944, 3944, 3945, 3945, 3946, 3947, 3947, 3948, 3948, 3949, 3949, 3950, 3950, 3951,
+       3951, 3952, 3952, 3953, 3953, 3954, 3954, 3955, 3955, 3956, 3956, 3957, 3957, 3958, 3958, 3959,
+       3959, 3960, 3960, 3961, 3961, 3962, 3962, 3963, 3963, 3964, 3964, 3965, 3965, 3966, 3966, 3967,
+       3967, 3968, 3969, 3969, 3970, 3970, 3971, 3971, 3972, 3972, 3973, 3973, 3974, 3974, 3975, 3975,
+       3976, 3976, 3977, 3977, 3978, 3978, 3979, 3979, 3980, 3980, 3981, 3981, 3982, 3982, 3983, 3983,
+       3984, 3984, 3985, 3985, 3986, 3986, 3987, 3987, 3988, 3988, 3989, 3989, 3990, 3990, 3991, 3991,
+       3992, 3992, 3993, 3993, 3994, 3994, 3995, 3995, 3996, 3996, 3997, 3997, 3998, 3998, 3999, 3999,
+       4000, 4001, 4001, 4002, 4002, 4003, 4003, 4004, 4004, 4005, 4005, 4006, 4006, 4007, 4007, 4008,
+       4008, 4009, 4009, 4010, 4010, 4011, 4011, 4012, 4012, 4013, 4013, 4014, 4014, 4015, 4015, 4016,
+       4016, 4017, 4017, 4018, 4018, 4019, 4019, 4020, 4020, 4021, 4021, 4022, 4022, 4023, 4023, 4024,
+       4024, 4025, 4025, 4026, 4026, 4027, 4027, 4028, 4028, 4029, 4029, 4030, 4030, 4031, 4031, 4032,
+       4032, 4033, 4033, 4034, 4034, 4035, 4035, 4036, 4036, 4037, 4037, 4038, 4038, 4039, 4039, 4040,
+       4040, 4041, 4041, 4042, 4042, 4043, 4043, 4044, 4044, 4045, 4045, 4046, 4046, 4047, 4047, 4048,
+       4048, 4049, 4049, 4050, 4050, 4051, 4051, 4052, 4052, 4053, 4053, 4054, 4054, 4055, 4055, 4056,
+       4056, 4057, 4057, 4058, 4058, 4059, 4059, 4060, 4060, 4061, 4061, 4062, 4062, 4063, 4063, 4064,
+       4064, 4065, 4065, 4066, 4066, 4067, 4067, 4068, 4068, 4069, 4069, 4070, 4070, 4071, 4071, 4072,
+       4072, 4073, 4073, 4074, 4074, 4075, 4075, 4076, 4076, 4077, 4077, 4078, 4078, 4079, 4079, 4080,
+       4080,
+};
+
+/* Generated table */
+const struct color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFER_FUNC_SMPTE2084 + 1][TPG_COLOR_CSC_BLACK + 1] = {
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][1] = { 2953, 2963, 586 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][2] = { 0, 2967, 2937 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][3] = { 88, 2990, 575 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][4] = { 3016, 259, 2933 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][5] = { 3030, 405, 558 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][6] = { 478, 428, 2931 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][1] = { 3068, 3077, 838 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][2] = { 0, 3081, 3053 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][3] = { 241, 3102, 828 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][4] = { 3126, 504, 3050 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][5] = { 3138, 657, 810 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][6] = { 731, 680, 3048 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][7] = { 800, 799, 800 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][1] = { 3046, 3054, 886 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][2] = { 0, 3058, 3031 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][3] = { 360, 3079, 877 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][4] = { 3103, 587, 3027 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][5] = { 3116, 723, 861 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][6] = { 789, 744, 3025 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][1] = { 2941, 2950, 546 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][2] = { 0, 2954, 2924 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][3] = { 78, 2978, 536 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][4] = { 3004, 230, 2920 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][5] = { 3018, 363, 518 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][6] = { 437, 387, 2918 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][1] = { 2145, 2159, 142 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][2] = { 0, 2164, 2122 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][3] = { 19, 2198, 138 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][4] = { 2236, 57, 2116 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][5] = { 2256, 90, 133 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][6] = { 110, 96, 2113 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_DCI_P3][0] = { 3175, 3175, 3175 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_DCI_P3][1] = { 3186, 3194, 1121 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_DCI_P3][2] = { 0, 3197, 3173 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_DCI_P3][3] = { 523, 3216, 1112 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_DCI_P3][4] = { 3237, 792, 3169 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_DCI_P3][5] = { 3248, 944, 1094 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_DCI_P3][6] = { 1017, 967, 3168 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][1] = { 3802, 3805, 2602 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][2] = { 0, 3806, 3797 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][3] = { 1780, 3812, 2592 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][4] = { 3820, 2215, 3796 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][5] = { 3824, 2409, 2574 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][6] = { 2491, 2435, 3795 },
+       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][1] = { 2953, 2963, 586 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][2] = { 0, 2967, 2937 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][3] = { 88, 2990, 575 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][4] = { 3016, 259, 2933 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][5] = { 3030, 405, 558 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][6] = { 478, 428, 2931 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][1] = { 3068, 3077, 838 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][2] = { 0, 3081, 3053 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][3] = { 241, 3102, 828 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][4] = { 3126, 504, 3050 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][5] = { 3138, 657, 810 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][6] = { 731, 680, 3048 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][7] = { 800, 799, 800 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][1] = { 3046, 3054, 886 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][2] = { 0, 3058, 3031 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][3] = { 360, 3079, 877 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][4] = { 3103, 587, 3027 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][5] = { 3116, 723, 861 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][6] = { 789, 744, 3025 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][1] = { 2941, 2950, 546 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][2] = { 0, 2954, 2924 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][3] = { 78, 2978, 536 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][4] = { 3004, 230, 2920 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][5] = { 3018, 363, 518 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][6] = { 437, 387, 2918 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][1] = { 2145, 2159, 142 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][2] = { 0, 2164, 2122 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][3] = { 19, 2198, 138 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][4] = { 2236, 57, 2116 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][5] = { 2256, 90, 133 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][6] = { 110, 96, 2113 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_DCI_P3][0] = { 3175, 3175, 3175 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_DCI_P3][1] = { 3186, 3194, 1121 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_DCI_P3][2] = { 0, 3197, 3173 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_DCI_P3][3] = { 523, 3216, 1112 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_DCI_P3][4] = { 3237, 792, 3169 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_DCI_P3][5] = { 3248, 944, 1094 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_DCI_P3][6] = { 1017, 967, 3168 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][1] = { 3802, 3805, 2602 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][2] = { 0, 3806, 3797 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][3] = { 1780, 3812, 2592 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][4] = { 3820, 2215, 3796 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][5] = { 3824, 2409, 2574 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][6] = { 2491, 2435, 3795 },
+       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][1] = { 2939, 2939, 547 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][2] = { 547, 2939, 2939 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][3] = { 547, 2939, 547 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][4] = { 2939, 547, 2939 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][5] = { 2939, 547, 547 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][6] = { 547, 547, 2939 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][1] = { 3056, 3056, 800 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][2] = { 800, 3056, 3056 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][3] = { 800, 3056, 800 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][4] = { 3056, 800, 3056 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][5] = { 3056, 800, 800 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][6] = { 800, 800, 3056 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 800 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][1] = { 3033, 3033, 851 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][2] = { 851, 3033, 3033 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][3] = { 851, 3033, 851 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][4] = { 3033, 851, 3033 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][5] = { 3033, 851, 851 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][6] = { 851, 851, 3033 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][1] = { 2926, 2926, 507 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][2] = { 507, 2926, 2926 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][3] = { 507, 2926, 507 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][4] = { 2926, 507, 2926 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][5] = { 2926, 507, 507 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][6] = { 507, 507, 2926 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][1] = { 2125, 2125, 130 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][2] = { 130, 2125, 2125 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][3] = { 130, 2125, 130 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][4] = { 2125, 130, 2125 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][5] = { 2125, 130, 130 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][6] = { 130, 130, 2125 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_DCI_P3][0] = { 3175, 3175, 3175 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_DCI_P3][1] = { 3175, 3175, 1084 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_DCI_P3][2] = { 1084, 3175, 3175 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_DCI_P3][3] = { 1084, 3175, 1084 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_DCI_P3][4] = { 3175, 1084, 3175 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_DCI_P3][5] = { 3175, 1084, 1084 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_DCI_P3][6] = { 1084, 1084, 3175 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][1] = { 3798, 3798, 2563 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][2] = { 2563, 3798, 3798 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][3] = { 2563, 3798, 2563 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][4] = { 3798, 2563, 3798 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][5] = { 3798, 2563, 2563 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][6] = { 2563, 2563, 3798 },
+       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][1] = { 2892, 3034, 910 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][2] = { 1715, 2916, 2914 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][3] = { 1631, 3012, 828 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][4] = { 2497, 119, 2867 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][5] = { 2440, 649, 657 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][6] = { 740, 0, 2841 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3055, 3056 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][1] = { 3013, 3142, 1157 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][2] = { 1926, 3034, 3032 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][3] = { 1847, 3121, 1076 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][4] = { 2651, 304, 2990 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][5] = { 2599, 901, 909 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][6] = { 991, 0, 2966 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][7] = { 800, 799, 800 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][1] = { 2989, 3120, 1180 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][2] = { 1913, 3011, 3009 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][3] = { 1836, 3099, 1105 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][4] = { 2627, 413, 2966 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][5] = { 2576, 943, 951 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][6] = { 1026, 0, 2942 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][1] = { 2879, 3022, 874 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][2] = { 1688, 2903, 2901 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][3] = { 1603, 2999, 791 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][4] = { 2479, 106, 2853 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][5] = { 2422, 610, 618 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][6] = { 702, 0, 2827 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][1] = { 2059, 2262, 266 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][2] = { 771, 2092, 2089 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][3] = { 705, 2229, 231 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][4] = { 1550, 26, 2024 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][5] = { 1484, 163, 165 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][6] = { 196, 0, 1988 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_DCI_P3][0] = { 3175, 3175, 3175 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_DCI_P3][1] = { 3136, 3251, 1429 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_DCI_P3][2] = { 2150, 3156, 3154 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_DCI_P3][3] = { 2077, 3233, 1352 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_DCI_P3][4] = { 2812, 589, 3116 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_DCI_P3][5] = { 2765, 1182, 1190 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_DCI_P3][6] = { 1270, 0, 3094 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][1] = { 3784, 3825, 2879 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][2] = { 3351, 3791, 3790 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][3] = { 3311, 3819, 2815 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][4] = { 3659, 1900, 3777 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][5] = { 3640, 2662, 2669 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][6] = { 2743, 0, 3769 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][1] = { 2939, 2939, 464 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][2] = { 786, 2939, 2939 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][3] = { 786, 2939, 464 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][4] = { 2879, 547, 2956 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][5] = { 2879, 547, 547 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][6] = { 547, 547, 2956 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][1] = { 3056, 3056, 717 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][2] = { 1036, 3056, 3056 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][3] = { 1036, 3056, 717 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][4] = { 3001, 800, 3071 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][5] = { 3001, 800, 799 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][6] = { 800, 800, 3071 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 799 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][1] = { 3033, 3033, 776 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][2] = { 1068, 3033, 3033 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][3] = { 1068, 3033, 776 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][4] = { 2977, 851, 3048 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][5] = { 2977, 851, 851 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][6] = { 851, 851, 3048 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][1] = { 2926, 2926, 423 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][2] = { 749, 2926, 2926 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][3] = { 749, 2926, 423 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][4] = { 2865, 507, 2943 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][5] = { 2865, 507, 507 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][6] = { 507, 507, 2943 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][1] = { 2125, 2125, 106 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][2] = { 214, 2125, 2125 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][3] = { 214, 2125, 106 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][4] = { 2041, 130, 2149 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][5] = { 2041, 130, 130 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][6] = { 130, 130, 2149 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_DCI_P3][0] = { 3175, 3175, 3175 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_DCI_P3][1] = { 3175, 3175, 1003 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_DCI_P3][2] = { 1313, 3175, 3175 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_DCI_P3][3] = { 1313, 3175, 1003 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_DCI_P3][4] = { 3126, 1084, 3188 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_DCI_P3][5] = { 3126, 1084, 1084 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_DCI_P3][6] = { 1084, 1084, 3188 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][1] = { 3798, 3798, 2476 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][2] = { 2782, 3798, 3798 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][3] = { 2782, 3798, 2476 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][4] = { 3780, 2563, 3803 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][5] = { 3780, 2563, 2563 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][6] = { 2563, 2563, 3803 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][1] = { 2939, 2939, 547 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][2] = { 547, 2939, 2939 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][3] = { 547, 2939, 547 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][4] = { 2939, 547, 2939 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][5] = { 2939, 547, 547 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][6] = { 547, 547, 2939 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][1] = { 3056, 3056, 800 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][2] = { 800, 3056, 3056 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][3] = { 800, 3056, 800 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][4] = { 3056, 800, 3056 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][5] = { 3056, 800, 800 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][6] = { 800, 800, 3056 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 800 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][1] = { 3033, 3033, 851 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][2] = { 851, 3033, 3033 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][3] = { 851, 3033, 851 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][4] = { 3033, 851, 3033 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][5] = { 3033, 851, 851 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][6] = { 851, 851, 3033 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][1] = { 2926, 2926, 507 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][2] = { 507, 2926, 2926 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][3] = { 507, 2926, 507 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][4] = { 2926, 507, 2926 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][5] = { 2926, 507, 507 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][6] = { 507, 507, 2926 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][1] = { 2125, 2125, 130 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][2] = { 130, 2125, 2125 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][3] = { 130, 2125, 130 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][4] = { 2125, 130, 2125 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][5] = { 2125, 130, 130 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][6] = { 130, 130, 2125 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_DCI_P3][0] = { 3175, 3175, 3175 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_DCI_P3][1] = { 3175, 3175, 1084 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_DCI_P3][2] = { 1084, 3175, 3175 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_DCI_P3][3] = { 1084, 3175, 1084 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_DCI_P3][4] = { 3175, 1084, 3175 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_DCI_P3][5] = { 3175, 1084, 1084 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_DCI_P3][6] = { 1084, 1084, 3175 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][1] = { 3798, 3798, 2563 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][2] = { 2563, 3798, 3798 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][3] = { 2563, 3798, 2563 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][4] = { 3798, 2563, 3798 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][5] = { 3798, 2563, 2563 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][6] = { 2563, 2563, 3798 },
+       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][1] = { 2939, 2939, 781 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][2] = { 1622, 2939, 2939 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][3] = { 1622, 2939, 781 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][4] = { 2502, 547, 2881 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][5] = { 2502, 547, 547 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][6] = { 547, 547, 2881 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][1] = { 3056, 3056, 1031 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][2] = { 1838, 3056, 3056 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][3] = { 1838, 3056, 1031 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][4] = { 2657, 800, 3002 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][5] = { 2657, 800, 800 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][6] = { 800, 800, 3002 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 800 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][1] = { 3033, 3033, 1063 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][2] = { 1828, 3033, 3033 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][3] = { 1828, 3033, 1063 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][4] = { 2633, 851, 2979 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][5] = { 2633, 851, 851 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][6] = { 851, 851, 2979 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][1] = { 2926, 2926, 744 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][2] = { 1594, 2926, 2926 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][3] = { 1594, 2926, 744 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][4] = { 2484, 507, 2867 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][5] = { 2484, 507, 507 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][6] = { 507, 507, 2867 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][1] = { 2125, 2125, 212 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][2] = { 698, 2125, 2125 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][3] = { 698, 2125, 212 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][4] = { 1557, 130, 2043 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][5] = { 1557, 130, 130 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][6] = { 130, 130, 2043 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][0] = { 3175, 3175, 3175 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][1] = { 3175, 3175, 1308 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][2] = { 2069, 3175, 3175 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][3] = { 2069, 3175, 1308 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][4] = { 2816, 1084, 3127 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][5] = { 2816, 1084, 1084 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][6] = { 1084, 1084, 3127 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][1] = { 3798, 3798, 2778 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][2] = { 3306, 3798, 3798 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][3] = { 3306, 3798, 2778 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][4] = { 3661, 2563, 3781 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][5] = { 3661, 2563, 2563 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][6] = { 2563, 2563, 3781 },
+       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][1] = { 2877, 2923, 1058 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][2] = { 1837, 2840, 2916 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][3] = { 1734, 2823, 993 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][4] = { 2427, 961, 2812 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][5] = { 2351, 912, 648 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][6] = { 792, 618, 2788 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][1] = { 2999, 3041, 1301 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][2] = { 2040, 2965, 3034 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][3] = { 1944, 2950, 1238 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][4] = { 2587, 1207, 2940 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][5] = { 2517, 1159, 900 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][6] = { 1042, 870, 2917 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 800 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][1] = { 2976, 3018, 1315 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][2] = { 2024, 2942, 3011 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][3] = { 1930, 2926, 1256 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][4] = { 2563, 1227, 2916 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][5] = { 2494, 1183, 943 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][6] = { 1073, 916, 2894 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][1] = { 2864, 2910, 1024 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][2] = { 1811, 2826, 2903 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][3] = { 1707, 2809, 958 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][4] = { 2408, 926, 2798 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][5] = { 2331, 876, 609 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][6] = { 755, 579, 2773 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][1] = { 2039, 2102, 338 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][2] = { 873, 1987, 2092 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][3] = { 787, 1965, 305 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][4] = { 1468, 290, 1949 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][5] = { 1382, 268, 162 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][6] = { 216, 152, 1917 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_DCI_P3][0] = { 3175, 3175, 3175 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_DCI_P3][1] = { 3124, 3161, 1566 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_DCI_P3][2] = { 2255, 3094, 3156 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_DCI_P3][3] = { 2166, 3080, 1506 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_DCI_P3][4] = { 2754, 1477, 3071 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_DCI_P3][5] = { 2690, 1431, 1182 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_DCI_P3][6] = { 1318, 1153, 3051 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][1] = { 3780, 3793, 2984 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][2] = { 3406, 3768, 3791 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][3] = { 3359, 3763, 2939 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][4] = { 3636, 2916, 3760 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][5] = { 3609, 2880, 2661 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][6] = { 2786, 2633, 3753 },
+       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_709][1] = { 2936, 2934, 992 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_709][2] = { 1159, 2890, 2916 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_709][3] = { 1150, 2885, 921 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_709][4] = { 2751, 766, 2837 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_709][5] = { 2747, 747, 650 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_709][6] = { 563, 570, 2812 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3055 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SRGB][1] = { 3052, 3051, 1237 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SRGB][2] = { 1397, 3011, 3034 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SRGB][3] = { 1389, 3006, 1168 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SRGB][4] = { 2884, 1016, 2962 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SRGB][5] = { 2880, 998, 902 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SRGB][6] = { 816, 823, 2940 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 799 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][1] = { 3029, 3028, 1255 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][2] = { 1406, 2988, 3011 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][3] = { 1398, 2983, 1190 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][4] = { 2860, 1050, 2939 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][5] = { 2857, 1033, 945 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][6] = { 866, 873, 2916 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE240M][1] = { 2923, 2921, 957 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE240M][2] = { 1125, 2877, 2902 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE240M][3] = { 1116, 2871, 885 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE240M][4] = { 2736, 729, 2823 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE240M][5] = { 2732, 710, 611 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE240M][6] = { 523, 531, 2798 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_NONE][1] = { 2120, 2118, 305 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_NONE][2] = { 392, 2056, 2092 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_NONE][3] = { 387, 2049, 271 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_NONE][4] = { 1868, 206, 1983 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_NONE][5] = { 1863, 199, 163 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_NONE][6] = { 135, 137, 1950 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_DCI_P3][0] = { 3175, 3175, 3175 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_DCI_P3][1] = { 3172, 3170, 1505 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_DCI_P3][2] = { 1657, 3135, 3155 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_DCI_P3][3] = { 1649, 3130, 1439 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_DCI_P3][4] = { 3021, 1294, 3091 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_DCI_P3][5] = { 3018, 1276, 1184 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_DCI_P3][6] = { 1100, 1107, 3071 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][1] = { 3797, 3796, 2938 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][2] = { 3049, 3783, 3791 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][3] = { 3044, 3782, 2887 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][4] = { 3741, 2765, 3768 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][5] = { 3740, 2749, 2663 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][6] = { 2580, 2587, 3760 },
+       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 },
+};
+
+#else
+
+/* This code generates the table above */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static const double rec709_to_ntsc1953[3][3] = {
+       /*
+        * This transform uses the Bradford method to compensate for
+        * the different whitepoints.
+        */
+       { 0.6785011, 0.2883441, 0.0331548 },
+       { 0.0165284, 1.0518725, -0.0684009 },
+       { 0.0179230, 0.0506096, 0.9314674 }
+};
+
+static const double rec709_to_ebu[3][3] = {
+       { 0.9578221, 0.0421779, -0.0000000 },
+       { -0.0000000, 1.0000000, 0.0000000 },
+       { -0.0000000, -0.0119367, 1.0119367 }
+};
+
+static const double rec709_to_170m[3][3] = {
+       { 1.0653640, -0.0553900, -0.0099740 },
+       { -0.0196361, 1.0363630, -0.0167269 },
+       { 0.0016327, 0.0044133, 0.9939540 },
+};
+
+static const double rec709_to_240m[3][3] = {
+       { 1.0653640, -0.0553900, -0.0099740 },
+       { -0.0196361, 1.0363630, -0.0167269 },
+       { 0.0016327, 0.0044133, 0.9939540 },
+};
+
+static const double rec709_to_adobergb[3][3] = {
+       { 0.7151627, 0.2848373, -0.0000000 },
+       { 0.0000000, 1.0000000, 0.0000000 },
+       { -0.0000000, 0.0411705, 0.9588295 },
+};
+
+static const double rec709_to_bt2020[3][3] = {
+       { 0.6274524, 0.3292485, 0.0432991 },
+       { 0.0691092, 0.9195311, 0.0113597 },
+       { 0.0163976, 0.0880301, 0.8955723 },
+};
+
+static const double rec709_to_dcip3[3][3] = {
+       /*
+        * This transform uses the Bradford method to compensate for
+        * the different whitepoints.
+        */
+       { 0.8686648, 0.1288456, 0.0024896 },
+       { 0.0345479, 0.9618084, 0.0036437 },
+       { 0.0167785, 0.0710559, 0.9121655 }
+};
+
+static void mult_matrix(double *r, double *g, double *b, const double m[3][3])
+{
+       double ir, ig, ib;
+
+       ir = m[0][0] * (*r) + m[0][1] * (*g) + m[0][2] * (*b);
+       ig = m[1][0] * (*r) + m[1][1] * (*g) + m[1][2] * (*b);
+       ib = m[2][0] * (*r) + m[2][1] * (*g) + m[2][2] * (*b);
+       *r = ir;
+       *g = ig;
+       *b = ib;
+}
+
+static double transfer_srgb_to_rgb(double v)
+{
+       if (v < -0.04045)
+               return pow((-v + 0.055) / 1.055, 2.4);
+       return (v <= 0.04045) ? v / 12.92 : pow((v + 0.055) / 1.055, 2.4);
+}
+
+static double transfer_rgb_to_srgb(double v)
+{
+       if (v <= -0.0031308)
+               return -1.055 * pow(-v, 1.0 / 2.4) + 0.055;
+       if (v <= 0.0031308)
+               return v * 12.92;
+       return 1.055 * pow(v, 1.0 / 2.4) - 0.055;
+}
+
+static double transfer_rgb_to_smpte240m(double v)
+{
+       return (v <= 0.0228) ? v * 4.0 : 1.1115 * pow(v, 0.45) - 0.1115;
+}
+
+static double transfer_rgb_to_rec709(double v)
+{
+       if (v <= -0.018)
+               return -1.099 * pow(-v, 0.45) + 0.099;
+       return (v < 0.018) ? v * 4.5 : 1.099 * pow(v, 0.45) - 0.099;
+}
+
+static double transfer_rec709_to_rgb(double v)
+{
+       return (v < 0.081) ? v / 4.5 : pow((v + 0.099) / 1.099, 1.0 / 0.45);
+}
+
+static double transfer_rgb_to_adobergb(double v)
+{
+       return pow(v, 1.0 / 2.19921875);
+}
+
+static double transfer_rgb_to_dcip3(double v)
+{
+       return pow(v, 1.0 / 2.6);
+}
+
+static double transfer_rgb_to_smpte2084(double v)
+{
+       const double m1 = (2610.0 / 4096.0) / 4.0;
+       const double m2 = 128.0 * 2523.0 / 4096.0;
+       const double c1 = 3424.0 / 4096.0;
+       const double c2 = 32.0 * 2413.0 / 4096.0;
+       const double c3 = 32.0 * 2392.0 / 4096.0;
+
+       v = pow(v, m1);
+       return pow((c1 + c2 * v) / (1 + c3 * v), m2);
+}
+
+static double transfer_srgb_to_rec709(double v)
+{
+       return transfer_rgb_to_rec709(transfer_srgb_to_rgb(v));
+}
+
+static void csc(enum v4l2_colorspace colorspace, enum v4l2_xfer_func xfer_func,
+               double *r, double *g, double *b)
+{
+       int clamp = 1;
+
+       *r = transfer_srgb_to_rgb(*r);
+       *g = transfer_srgb_to_rgb(*g);
+       *b = transfer_srgb_to_rgb(*b);
+
+       /* Convert the primaries of Rec. 709 Linear RGB */
+       switch (colorspace) {
+       case V4L2_COLORSPACE_SMPTE240M:
+               mult_matrix(r, g, b, rec709_to_240m);
+               break;
+       case V4L2_COLORSPACE_SMPTE170M:
+               mult_matrix(r, g, b, rec709_to_170m);
+               break;
+       case V4L2_COLORSPACE_470_SYSTEM_BG:
+               mult_matrix(r, g, b, rec709_to_ebu);
+               break;
+       case V4L2_COLORSPACE_470_SYSTEM_M:
+               mult_matrix(r, g, b, rec709_to_ntsc1953);
+               break;
+       case V4L2_COLORSPACE_ADOBERGB:
+               mult_matrix(r, g, b, rec709_to_adobergb);
+               break;
+       case V4L2_COLORSPACE_BT2020:
+               mult_matrix(r, g, b, rec709_to_bt2020);
+               break;
+       case V4L2_COLORSPACE_DCI_P3:
+               mult_matrix(r, g, b, rec709_to_dcip3);
+               break;
+       case V4L2_COLORSPACE_SRGB:
+       case V4L2_COLORSPACE_REC709:
+               break;
+       default:
+               break;
+       }
+
+       if (clamp) {
+               *r = ((*r) < 0) ? 0 : (((*r) > 1) ? 1 : (*r));
+               *g = ((*g) < 0) ? 0 : (((*g) > 1) ? 1 : (*g));
+               *b = ((*b) < 0) ? 0 : (((*b) > 1) ? 1 : (*b));
+       }
+
+       switch (xfer_func) {
+       case V4L2_XFER_FUNC_709:
+               *r = transfer_rgb_to_rec709(*r);
+               *g = transfer_rgb_to_rec709(*g);
+               *b = transfer_rgb_to_rec709(*b);
+               break;
+       case V4L2_XFER_FUNC_SRGB:
+               *r = transfer_rgb_to_srgb(*r);
+               *g = transfer_rgb_to_srgb(*g);
+               *b = transfer_rgb_to_srgb(*b);
+               break;
+       case V4L2_XFER_FUNC_ADOBERGB:
+               *r = transfer_rgb_to_adobergb(*r);
+               *g = transfer_rgb_to_adobergb(*g);
+               *b = transfer_rgb_to_adobergb(*b);
+               break;
+       case V4L2_XFER_FUNC_DCI_P3:
+               *r = transfer_rgb_to_dcip3(*r);
+               *g = transfer_rgb_to_dcip3(*g);
+               *b = transfer_rgb_to_dcip3(*b);
+               break;
+       case V4L2_XFER_FUNC_SMPTE2084:
+               *r = transfer_rgb_to_smpte2084(*r);
+               *g = transfer_rgb_to_smpte2084(*g);
+               *b = transfer_rgb_to_smpte2084(*b);
+               break;
+       case V4L2_XFER_FUNC_SMPTE240M:
+               *r = transfer_rgb_to_smpte240m(*r);
+               *g = transfer_rgb_to_smpte240m(*g);
+               *b = transfer_rgb_to_smpte240m(*b);
+               break;
+       case V4L2_XFER_FUNC_NONE:
+               break;
+       }
+}
+
+int main(int argc, char **argv)
+{
+       static const unsigned colorspaces[] = {
+               0,
+               V4L2_COLORSPACE_SMPTE170M,
+               V4L2_COLORSPACE_SMPTE240M,
+               V4L2_COLORSPACE_REC709,
+               0,
+               V4L2_COLORSPACE_470_SYSTEM_M,
+               V4L2_COLORSPACE_470_SYSTEM_BG,
+               0,
+               V4L2_COLORSPACE_SRGB,
+               V4L2_COLORSPACE_ADOBERGB,
+               V4L2_COLORSPACE_BT2020,
+               0,
+               V4L2_COLORSPACE_DCI_P3,
+       };
+       static const char * const colorspace_names[] = {
+               "",
+               "V4L2_COLORSPACE_SMPTE170M",
+               "V4L2_COLORSPACE_SMPTE240M",
+               "V4L2_COLORSPACE_REC709",
+               "",
+               "V4L2_COLORSPACE_470_SYSTEM_M",
+               "V4L2_COLORSPACE_470_SYSTEM_BG",
+               "",
+               "V4L2_COLORSPACE_SRGB",
+               "V4L2_COLORSPACE_ADOBERGB",
+               "V4L2_COLORSPACE_BT2020",
+               "",
+               "V4L2_COLORSPACE_DCI_P3",
+       };
+       static const char * const xfer_func_names[] = {
+               "",
+               "V4L2_XFER_FUNC_709",
+               "V4L2_XFER_FUNC_SRGB",
+               "V4L2_XFER_FUNC_ADOBERGB",
+               "V4L2_XFER_FUNC_SMPTE240M",
+               "V4L2_XFER_FUNC_NONE",
+               "V4L2_XFER_FUNC_DCI_P3",
+               "V4L2_XFER_FUNC_SMPTE2084",
+       };
+       int i;
+       int x;
+       int c;
+
+       printf("/* Generated table */\n");
+       printf("const unsigned short tpg_rec709_to_linear[255 * 16 + 1] = {");
+       for (i = 0; i <= 255 * 16; i++) {
+               if (i % 16 == 0)
+                       printf("\n\t");
+               printf("%4d,%s",
+                       (int)(0.5 + 16.0 * 255.0 *
+                               transfer_rec709_to_rgb(i / (16.0 * 255.0))),
+                       i % 16 == 15 || i == 255 * 16 ? "" : " ");
+       }
+       printf("\n};\n\n");
+
+       printf("/* Generated table */\n");
+       printf("const unsigned short tpg_linear_to_rec709[255 * 16 + 1] = {");
+       for (i = 0; i <= 255 * 16; i++) {
+               if (i % 16 == 0)
+                       printf("\n\t");
+               printf("%4d,%s",
+                       (int)(0.5 + 16.0 * 255.0 *
+                               transfer_rgb_to_rec709(i / (16.0 * 255.0))),
+                       i % 16 == 15 || i == 255 * 16 ? "" : " ");
+       }
+       printf("\n};\n\n");
+
+       printf("/* Generated table */\n");
+       printf("const struct color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFER_FUNC_SMPTE2084 + 1][TPG_COLOR_CSC_BLACK + 1] = {\n");
+       for (c = 0; c <= V4L2_COLORSPACE_DCI_P3; c++) {
+               for (x = 1; x <= V4L2_XFER_FUNC_SMPTE2084; x++) {
+                       for (i = 0; i <= TPG_COLOR_CSC_BLACK; i++) {
+                               double r, g, b;
+
+                               if (colorspaces[c] == 0)
+                                       continue;
+
+                               r = tpg_colors[i].r / 255.0;
+                               g = tpg_colors[i].g / 255.0;
+                               b = tpg_colors[i].b / 255.0;
+
+                               csc(c, x, &r, &g, &b);
+
+                               printf("\t[%s][%s][%d] = { %d, %d, %d },\n",
+                                       colorspace_names[c],
+                                       xfer_func_names[x], i,
+                                       (int)(r * 4080), (int)(g * 4080), (int)(b * 4080));
+                       }
+               }
+       }
+       printf("};\n\n");
+       return 0;
+}
+
+#endif
diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
new file mode 100644 (file)
index 0000000..cf1dadd
--- /dev/null
@@ -0,0 +1,2335 @@
+/*
+ * v4l2-tpg-core.c - Test Pattern Generator
+ *
+ * Note: gen_twopix and tpg_gen_text are based on code from vivi.c. See the
+ * vivi.c source for the copyright information of those functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <media/v4l2-tpg.h>
+
+/* Must remain in sync with enum tpg_pattern */
+const char * const tpg_pattern_strings[] = {
+       "75% Colorbar",
+       "100% Colorbar",
+       "CSC Colorbar",
+       "Horizontal 100% Colorbar",
+       "100% Color Squares",
+       "100% Black",
+       "100% White",
+       "100% Red",
+       "100% Green",
+       "100% Blue",
+       "16x16 Checkers",
+       "2x2 Checkers",
+       "1x1 Checkers",
+       "2x2 Red/Green Checkers",
+       "1x1 Red/Green Checkers",
+       "Alternating Hor Lines",
+       "Alternating Vert Lines",
+       "One Pixel Wide Cross",
+       "Two Pixels Wide Cross",
+       "Ten Pixels Wide Cross",
+       "Gray Ramp",
+       "Noise",
+       NULL
+};
+EXPORT_SYMBOL_GPL(tpg_pattern_strings);
+
+/* Must remain in sync with enum tpg_aspect */
+const char * const tpg_aspect_strings[] = {
+       "Source Width x Height",
+       "4x3",
+       "14x9",
+       "16x9",
+       "16x9 Anamorphic",
+       NULL
+};
+EXPORT_SYMBOL_GPL(tpg_aspect_strings);
+
+/*
+ * Sine table: sin[0] = 127 * sin(-180 degrees)
+ *             sin[128] = 127 * sin(0 degrees)
+ *             sin[256] = 127 * sin(180 degrees)
+ */
+static const s8 sin[257] = {
+          0,   -4,   -7,  -11,  -13,  -18,  -20,  -22,  -26,  -29,  -33,  -35,  -37,  -41,  -43,  -48,
+        -50,  -52,  -56,  -58,  -62,  -63,  -65,  -69,  -71,  -75,  -76,  -78,  -82,  -83,  -87,  -88,
+        -90,  -93,  -94,  -97,  -99, -101, -103, -104, -107, -108, -110, -111, -112, -114, -115, -117,
+       -118, -119, -120, -121, -122, -123, -123, -124, -125, -125, -126, -126, -127, -127, -127, -127,
+       -127, -127, -127, -127, -126, -126, -125, -125, -124, -124, -123, -122, -121, -120, -119, -118,
+       -117, -116, -114, -113, -111, -110, -109, -107, -105, -103, -101, -100,  -97,  -96,  -93,  -91,
+        -90,  -87,  -85,  -82,  -80,  -76,  -75,  -73,  -69,  -67,  -63,  -62,  -60,  -56,  -54,  -50,
+        -48,  -46,  -41,  -39,  -35,  -33,  -31,  -26,  -24,  -20,  -18,  -15,  -11,   -9,   -4,   -2,
+          0,    2,    4,    9,   11,   15,   18,   20,   24,   26,   31,   33,   35,   39,   41,   46,
+         48,   50,   54,   56,   60,   62,   64,   67,   69,   73,   75,   76,   80,   82,   85,   87,
+         90,   91,   93,   96,   97,  100,  101,  103,  105,  107,  109,  110,  111,  113,  114,  116,
+        117,  118,  119,  120,  121,  122,  123,  124,  124,  125,  125,  126,  126,  127,  127,  127,
+        127,  127,  127,  127,  127,  126,  126,  125,  125,  124,  123,  123,  122,  121,  120,  119,
+        118,  117,  115,  114,  112,  111,  110,  108,  107,  104,  103,  101,   99,   97,   94,   93,
+         90,   88,   87,   83,   82,   78,   76,   75,   71,   69,   65,   64,   62,   58,   56,   52,
+         50,   48,   43,   41,   37,   35,   33,   29,   26,   22,   20,   18,   13,   11,    7,    4,
+          0,
+};
+
+#define cos(idx) sin[((idx) + 64) % sizeof(sin)]
+
+/* Global font descriptor */
+static const u8 *font8x16;
+
+void tpg_set_font(const u8 *f)
+{
+       font8x16 = f;
+}
+EXPORT_SYMBOL_GPL(tpg_set_font);
+
+void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h)
+{
+       memset(tpg, 0, sizeof(*tpg));
+       tpg->scaled_width = tpg->src_width = w;
+       tpg->src_height = tpg->buf_height = h;
+       tpg->crop.width = tpg->compose.width = w;
+       tpg->crop.height = tpg->compose.height = h;
+       tpg->recalc_colors = true;
+       tpg->recalc_square_border = true;
+       tpg->brightness = 128;
+       tpg->contrast = 128;
+       tpg->saturation = 128;
+       tpg->hue = 0;
+       tpg->mv_hor_mode = TPG_MOVE_NONE;
+       tpg->mv_vert_mode = TPG_MOVE_NONE;
+       tpg->field = V4L2_FIELD_NONE;
+       tpg_s_fourcc(tpg, V4L2_PIX_FMT_RGB24);
+       tpg->colorspace = V4L2_COLORSPACE_SRGB;
+       tpg->perc_fill = 100;
+}
+EXPORT_SYMBOL_GPL(tpg_init);
+
+int tpg_alloc(struct tpg_data *tpg, unsigned max_w)
+{
+       unsigned pat;
+       unsigned plane;
+
+       tpg->max_line_width = max_w;
+       for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) {
+               for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
+                       unsigned pixelsz = plane ? 2 : 4;
+
+                       tpg->lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
+                       if (!tpg->lines[pat][plane])
+                               return -ENOMEM;
+                       if (plane == 0)
+                               continue;
+                       tpg->downsampled_lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
+                       if (!tpg->downsampled_lines[pat][plane])
+                               return -ENOMEM;
+               }
+       }
+       for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
+               unsigned pixelsz = plane ? 2 : 4;
+
+               tpg->contrast_line[plane] = vzalloc(max_w * pixelsz);
+               if (!tpg->contrast_line[plane])
+                       return -ENOMEM;
+               tpg->black_line[plane] = vzalloc(max_w * pixelsz);
+               if (!tpg->black_line[plane])
+                       return -ENOMEM;
+               tpg->random_line[plane] = vzalloc(max_w * 2 * pixelsz);
+               if (!tpg->random_line[plane])
+                       return -ENOMEM;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tpg_alloc);
+
+void tpg_free(struct tpg_data *tpg)
+{
+       unsigned pat;
+       unsigned plane;
+
+       for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++)
+               for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
+                       vfree(tpg->lines[pat][plane]);
+                       tpg->lines[pat][plane] = NULL;
+                       if (plane == 0)
+                               continue;
+                       vfree(tpg->downsampled_lines[pat][plane]);
+                       tpg->downsampled_lines[pat][plane] = NULL;
+               }
+       for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
+               vfree(tpg->contrast_line[plane]);
+               vfree(tpg->black_line[plane]);
+               vfree(tpg->random_line[plane]);
+               tpg->contrast_line[plane] = NULL;
+               tpg->black_line[plane] = NULL;
+               tpg->random_line[plane] = NULL;
+       }
+}
+EXPORT_SYMBOL_GPL(tpg_free);
+
+bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
+{
+       tpg->fourcc = fourcc;
+       tpg->planes = 1;
+       tpg->buffers = 1;
+       tpg->recalc_colors = true;
+       tpg->interleaved = false;
+       tpg->vdownsampling[0] = 1;
+       tpg->hdownsampling[0] = 1;
+       tpg->hmask[0] = ~0;
+       tpg->hmask[1] = ~0;
+       tpg->hmask[2] = ~0;
+
+       switch (fourcc) {
+       case V4L2_PIX_FMT_SBGGR8:
+       case V4L2_PIX_FMT_SGBRG8:
+       case V4L2_PIX_FMT_SGRBG8:
+       case V4L2_PIX_FMT_SRGGB8:
+       case V4L2_PIX_FMT_SBGGR10:
+       case V4L2_PIX_FMT_SGBRG10:
+       case V4L2_PIX_FMT_SGRBG10:
+       case V4L2_PIX_FMT_SRGGB10:
+       case V4L2_PIX_FMT_SBGGR12:
+       case V4L2_PIX_FMT_SGBRG12:
+       case V4L2_PIX_FMT_SGRBG12:
+       case V4L2_PIX_FMT_SRGGB12:
+               tpg->interleaved = true;
+               tpg->vdownsampling[1] = 1;
+               tpg->hdownsampling[1] = 1;
+               tpg->planes = 2;
+               /* fall through */
+       case V4L2_PIX_FMT_RGB332:
+       case V4L2_PIX_FMT_RGB565:
+       case V4L2_PIX_FMT_RGB565X:
+       case V4L2_PIX_FMT_RGB444:
+       case V4L2_PIX_FMT_XRGB444:
+       case V4L2_PIX_FMT_ARGB444:
+       case V4L2_PIX_FMT_RGB555:
+       case V4L2_PIX_FMT_XRGB555:
+       case V4L2_PIX_FMT_ARGB555:
+       case V4L2_PIX_FMT_RGB555X:
+       case V4L2_PIX_FMT_XRGB555X:
+       case V4L2_PIX_FMT_ARGB555X:
+       case V4L2_PIX_FMT_BGR666:
+       case V4L2_PIX_FMT_RGB24:
+       case V4L2_PIX_FMT_BGR24:
+       case V4L2_PIX_FMT_RGB32:
+       case V4L2_PIX_FMT_BGR32:
+       case V4L2_PIX_FMT_XRGB32:
+       case V4L2_PIX_FMT_XBGR32:
+       case V4L2_PIX_FMT_ARGB32:
+       case V4L2_PIX_FMT_ABGR32:
+       case V4L2_PIX_FMT_GREY:
+       case V4L2_PIX_FMT_Y16:
+       case V4L2_PIX_FMT_Y16_BE:
+               tpg->is_yuv = false;
+               break;
+       case V4L2_PIX_FMT_YUV444:
+       case V4L2_PIX_FMT_YUV555:
+       case V4L2_PIX_FMT_YUV565:
+       case V4L2_PIX_FMT_YUV32:
+               tpg->is_yuv = true;
+               break;
+       case V4L2_PIX_FMT_YUV420M:
+       case V4L2_PIX_FMT_YVU420M:
+               tpg->buffers = 3;
+               /* fall through */
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+               tpg->vdownsampling[1] = 2;
+               tpg->vdownsampling[2] = 2;
+               tpg->hdownsampling[1] = 2;
+               tpg->hdownsampling[2] = 2;
+               tpg->planes = 3;
+               tpg->is_yuv = true;
+               break;
+       case V4L2_PIX_FMT_YUV422M:
+       case V4L2_PIX_FMT_YVU422M:
+               tpg->buffers = 3;
+               /* fall through */
+       case V4L2_PIX_FMT_YUV422P:
+               tpg->vdownsampling[1] = 1;
+               tpg->vdownsampling[2] = 1;
+               tpg->hdownsampling[1] = 2;
+               tpg->hdownsampling[2] = 2;
+               tpg->planes = 3;
+               tpg->is_yuv = true;
+               break;
+       case V4L2_PIX_FMT_NV16M:
+       case V4L2_PIX_FMT_NV61M:
+               tpg->buffers = 2;
+               /* fall through */
+       case V4L2_PIX_FMT_NV16:
+       case V4L2_PIX_FMT_NV61:
+               tpg->vdownsampling[1] = 1;
+               tpg->hdownsampling[1] = 1;
+               tpg->hmask[1] = ~1;
+               tpg->planes = 2;
+               tpg->is_yuv = true;
+               break;
+       case V4L2_PIX_FMT_NV12M:
+       case V4L2_PIX_FMT_NV21M:
+               tpg->buffers = 2;
+               /* fall through */
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV21:
+               tpg->vdownsampling[1] = 2;
+               tpg->hdownsampling[1] = 1;
+               tpg->hmask[1] = ~1;
+               tpg->planes = 2;
+               tpg->is_yuv = true;
+               break;
+       case V4L2_PIX_FMT_YUV444M:
+       case V4L2_PIX_FMT_YVU444M:
+               tpg->buffers = 3;
+               tpg->planes = 3;
+               tpg->vdownsampling[1] = 1;
+               tpg->vdownsampling[2] = 1;
+               tpg->hdownsampling[1] = 1;
+               tpg->hdownsampling[2] = 1;
+               tpg->is_yuv = true;
+               break;
+       case V4L2_PIX_FMT_NV24:
+       case V4L2_PIX_FMT_NV42:
+               tpg->vdownsampling[1] = 1;
+               tpg->hdownsampling[1] = 1;
+               tpg->planes = 2;
+               tpg->is_yuv = true;
+               break;
+       case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_UYVY:
+       case V4L2_PIX_FMT_YVYU:
+       case V4L2_PIX_FMT_VYUY:
+               tpg->hmask[0] = ~1;
+               tpg->is_yuv = true;
+               break;
+       default:
+               return false;
+       }
+
+       switch (fourcc) {
+       case V4L2_PIX_FMT_GREY:
+       case V4L2_PIX_FMT_RGB332:
+               tpg->twopixelsize[0] = 2;
+               break;
+       case V4L2_PIX_FMT_RGB565:
+       case V4L2_PIX_FMT_RGB565X:
+       case V4L2_PIX_FMT_RGB444:
+       case V4L2_PIX_FMT_XRGB444:
+       case V4L2_PIX_FMT_ARGB444:
+       case V4L2_PIX_FMT_RGB555:
+       case V4L2_PIX_FMT_XRGB555:
+       case V4L2_PIX_FMT_ARGB555:
+       case V4L2_PIX_FMT_RGB555X:
+       case V4L2_PIX_FMT_XRGB555X:
+       case V4L2_PIX_FMT_ARGB555X:
+       case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_UYVY:
+       case V4L2_PIX_FMT_YVYU:
+       case V4L2_PIX_FMT_VYUY:
+       case V4L2_PIX_FMT_YUV444:
+       case V4L2_PIX_FMT_YUV555:
+       case V4L2_PIX_FMT_YUV565:
+       case V4L2_PIX_FMT_Y16:
+       case V4L2_PIX_FMT_Y16_BE:
+               tpg->twopixelsize[0] = 2 * 2;
+               break;
+       case V4L2_PIX_FMT_RGB24:
+       case V4L2_PIX_FMT_BGR24:
+               tpg->twopixelsize[0] = 2 * 3;
+               break;
+       case V4L2_PIX_FMT_BGR666:
+       case V4L2_PIX_FMT_RGB32:
+       case V4L2_PIX_FMT_BGR32:
+       case V4L2_PIX_FMT_XRGB32:
+       case V4L2_PIX_FMT_XBGR32:
+       case V4L2_PIX_FMT_ARGB32:
+       case V4L2_PIX_FMT_ABGR32:
+       case V4L2_PIX_FMT_YUV32:
+               tpg->twopixelsize[0] = 2 * 4;
+               break;
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV21:
+       case V4L2_PIX_FMT_NV12M:
+       case V4L2_PIX_FMT_NV21M:
+       case V4L2_PIX_FMT_NV16:
+       case V4L2_PIX_FMT_NV61:
+       case V4L2_PIX_FMT_NV16M:
+       case V4L2_PIX_FMT_NV61M:
+       case V4L2_PIX_FMT_SBGGR8:
+       case V4L2_PIX_FMT_SGBRG8:
+       case V4L2_PIX_FMT_SGRBG8:
+       case V4L2_PIX_FMT_SRGGB8:
+               tpg->twopixelsize[0] = 2;
+               tpg->twopixelsize[1] = 2;
+               break;
+       case V4L2_PIX_FMT_SRGGB10:
+       case V4L2_PIX_FMT_SGRBG10:
+       case V4L2_PIX_FMT_SGBRG10:
+       case V4L2_PIX_FMT_SBGGR10:
+       case V4L2_PIX_FMT_SRGGB12:
+       case V4L2_PIX_FMT_SGRBG12:
+       case V4L2_PIX_FMT_SGBRG12:
+       case V4L2_PIX_FMT_SBGGR12:
+               tpg->twopixelsize[0] = 4;
+               tpg->twopixelsize[1] = 4;
+               break;
+       case V4L2_PIX_FMT_YUV444M:
+       case V4L2_PIX_FMT_YVU444M:
+       case V4L2_PIX_FMT_YUV422M:
+       case V4L2_PIX_FMT_YVU422M:
+       case V4L2_PIX_FMT_YUV422P:
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+       case V4L2_PIX_FMT_YUV420M:
+       case V4L2_PIX_FMT_YVU420M:
+               tpg->twopixelsize[0] = 2;
+               tpg->twopixelsize[1] = 2;
+               tpg->twopixelsize[2] = 2;
+               break;
+       case V4L2_PIX_FMT_NV24:
+       case V4L2_PIX_FMT_NV42:
+               tpg->twopixelsize[0] = 2;
+               tpg->twopixelsize[1] = 4;
+               break;
+       }
+       return true;
+}
+EXPORT_SYMBOL_GPL(tpg_s_fourcc);
+
+void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
+               const struct v4l2_rect *compose)
+{
+       tpg->crop = *crop;
+       tpg->compose = *compose;
+       tpg->scaled_width = (tpg->src_width * tpg->compose.width +
+                                tpg->crop.width - 1) / tpg->crop.width;
+       tpg->scaled_width &= ~1;
+       if (tpg->scaled_width > tpg->max_line_width)
+               tpg->scaled_width = tpg->max_line_width;
+       if (tpg->scaled_width < 2)
+               tpg->scaled_width = 2;
+       tpg->recalc_lines = true;
+}
+EXPORT_SYMBOL_GPL(tpg_s_crop_compose);
+
+void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
+                      u32 field)
+{
+       unsigned p;
+
+       tpg->src_width = width;
+       tpg->src_height = height;
+       tpg->field = field;
+       tpg->buf_height = height;
+       if (V4L2_FIELD_HAS_T_OR_B(field))
+               tpg->buf_height /= 2;
+       tpg->scaled_width = width;
+       tpg->crop.top = tpg->crop.left = 0;
+       tpg->crop.width = width;
+       tpg->crop.height = height;
+       tpg->compose.top = tpg->compose.left = 0;
+       tpg->compose.width = width;
+       tpg->compose.height = tpg->buf_height;
+       for (p = 0; p < tpg->planes; p++)
+               tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) /
+                                      (2 * tpg->hdownsampling[p]);
+       tpg->recalc_square_border = true;
+}
+EXPORT_SYMBOL_GPL(tpg_reset_source);
+
+static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)
+{
+       switch (tpg->pattern) {
+       case TPG_PAT_BLACK:
+               return TPG_COLOR_100_WHITE;
+       case TPG_PAT_CSC_COLORBAR:
+               return TPG_COLOR_CSC_BLACK;
+       default:
+               return TPG_COLOR_100_BLACK;
+       }
+}
+
+static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)
+{
+       switch (tpg->pattern) {
+       case TPG_PAT_75_COLORBAR:
+       case TPG_PAT_CSC_COLORBAR:
+               return TPG_COLOR_CSC_WHITE;
+       case TPG_PAT_BLACK:
+               return TPG_COLOR_100_BLACK;
+       default:
+               return TPG_COLOR_100_WHITE;
+       }
+}
+
+static inline int rec709_to_linear(int v)
+{
+       v = clamp(v, 0, 0xff0);
+       return tpg_rec709_to_linear[v];
+}
+
+static inline int linear_to_rec709(int v)
+{
+       v = clamp(v, 0, 0xff0);
+       return tpg_linear_to_rec709[v];
+}
+
+static void rgb2ycbcr(const int m[3][3], int r, int g, int b,
+                       int y_offset, int *y, int *cb, int *cr)
+{
+       *y  = ((m[0][0] * r + m[0][1] * g + m[0][2] * b) >> 16) + (y_offset << 4);
+       *cb = ((m[1][0] * r + m[1][1] * g + m[1][2] * b) >> 16) + (128 << 4);
+       *cr = ((m[2][0] * r + m[2][1] * g + m[2][2] * b) >> 16) + (128 << 4);
+}
+
+static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
+                          int *y, int *cb, int *cr)
+{
+#define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
+
+       static const int bt601[3][3] = {
+               { COEFF(0.299, 219),  COEFF(0.587, 219),  COEFF(0.114, 219)  },
+               { COEFF(-0.169, 224), COEFF(-0.331, 224), COEFF(0.5, 224)    },
+               { COEFF(0.5, 224),    COEFF(-0.419, 224), COEFF(-0.081, 224) },
+       };
+       static const int bt601_full[3][3] = {
+               { COEFF(0.299, 255),  COEFF(0.587, 255),  COEFF(0.114, 255)  },
+               { COEFF(-0.169, 255), COEFF(-0.331, 255), COEFF(0.5, 255)    },
+               { COEFF(0.5, 255),    COEFF(-0.419, 255), COEFF(-0.081, 255) },
+       };
+       static const int rec709[3][3] = {
+               { COEFF(0.2126, 219),  COEFF(0.7152, 219),  COEFF(0.0722, 219)  },
+               { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224)     },
+               { COEFF(0.5, 224),     COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
+       };
+       static const int rec709_full[3][3] = {
+               { COEFF(0.2126, 255),  COEFF(0.7152, 255),  COEFF(0.0722, 255)  },
+               { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255)     },
+               { COEFF(0.5, 255),     COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
+       };
+       static const int smpte240m[3][3] = {
+               { COEFF(0.212, 219),  COEFF(0.701, 219),  COEFF(0.087, 219)  },
+               { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224)    },
+               { COEFF(0.5, 224),    COEFF(-0.445, 224), COEFF(-0.055, 224) },
+       };
+       static const int smpte240m_full[3][3] = {
+               { COEFF(0.212, 255),  COEFF(0.701, 255),  COEFF(0.087, 255)  },
+               { COEFF(-0.116, 255), COEFF(-0.384, 255), COEFF(0.5, 255)    },
+               { COEFF(0.5, 255),    COEFF(-0.445, 255), COEFF(-0.055, 255) },
+       };
+       static const int bt2020[3][3] = {
+               { COEFF(0.2627, 219),  COEFF(0.6780, 219),  COEFF(0.0593, 219)  },
+               { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224)     },
+               { COEFF(0.5, 224),     COEFF(-0.4598, 224), COEFF(-0.0402, 224) },
+       };
+       static const int bt2020_full[3][3] = {
+               { COEFF(0.2627, 255),  COEFF(0.6780, 255),  COEFF(0.0593, 255)  },
+               { COEFF(-0.1396, 255), COEFF(-0.3604, 255), COEFF(0.5, 255)     },
+               { COEFF(0.5, 255),     COEFF(-0.4698, 255), COEFF(-0.0402, 255) },
+       };
+       static const int bt2020c[4] = {
+               COEFF(1.0 / 1.9404, 224), COEFF(1.0 / 1.5816, 224),
+               COEFF(1.0 / 1.7184, 224), COEFF(1.0 / 0.9936, 224),
+       };
+       static const int bt2020c_full[4] = {
+               COEFF(1.0 / 1.9404, 255), COEFF(1.0 / 1.5816, 255),
+               COEFF(1.0 / 1.7184, 255), COEFF(1.0 / 0.9936, 255),
+       };
+
+       bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
+       unsigned y_offset = full ? 0 : 16;
+       int lin_y, yc;
+
+       switch (tpg->real_ycbcr_enc) {
+       case V4L2_YCBCR_ENC_601:
+       case V4L2_YCBCR_ENC_SYCC:
+               rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr);
+               break;
+       case V4L2_YCBCR_ENC_XV601:
+               /* Ignore quantization range, there is only one possible
+                * Y'CbCr encoding. */
+               rgb2ycbcr(bt601, r, g, b, 16, y, cb, cr);
+               break;
+       case V4L2_YCBCR_ENC_XV709:
+               /* Ignore quantization range, there is only one possible
+                * Y'CbCr encoding. */
+               rgb2ycbcr(rec709, r, g, b, 16, y, cb, cr);
+               break;
+       case V4L2_YCBCR_ENC_BT2020:
+               rgb2ycbcr(full ? bt2020_full : bt2020, r, g, b, y_offset, y, cb, cr);
+               break;
+       case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
+               lin_y = (COEFF(0.2627, 255) * rec709_to_linear(r) +
+                        COEFF(0.6780, 255) * rec709_to_linear(g) +
+                        COEFF(0.0593, 255) * rec709_to_linear(b)) >> 16;
+               yc = linear_to_rec709(lin_y);
+               *y = full ? yc : (yc * 219) / 255 + (16 << 4);
+               if (b <= yc)
+                       *cb = (((b - yc) * (full ? bt2020c_full[0] : bt2020c[0])) >> 16) + (128 << 4);
+               else
+                       *cb = (((b - yc) * (full ? bt2020c_full[1] : bt2020c[1])) >> 16) + (128 << 4);
+               if (r <= yc)
+                       *cr = (((r - yc) * (full ? bt2020c_full[2] : bt2020c[2])) >> 16) + (128 << 4);
+               else
+                       *cr = (((r - yc) * (full ? bt2020c_full[3] : bt2020c[3])) >> 16) + (128 << 4);
+               break;
+       case V4L2_YCBCR_ENC_SMPTE240M:
+               rgb2ycbcr(full ? smpte240m_full : smpte240m, r, g, b, y_offset, y, cb, cr);
+               break;
+       case V4L2_YCBCR_ENC_709:
+       default:
+               rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr);
+               break;
+       }
+}
+
+static void ycbcr2rgb(const int m[3][3], int y, int cb, int cr,
+                       int y_offset, int *r, int *g, int *b)
+{
+       y -= y_offset << 4;
+       cb -= 128 << 4;
+       cr -= 128 << 4;
+       *r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;
+       *g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;
+       *b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;
+       *r = clamp(*r >> 12, 0, 0xff0);
+       *g = clamp(*g >> 12, 0, 0xff0);
+       *b = clamp(*b >> 12, 0, 0xff0);
+}
+
+static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,
+                          int *r, int *g, int *b)
+{
+#undef COEFF
+#define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))
+       static const int bt601[3][3] = {
+               { COEFF(1, 219), COEFF(0, 224),       COEFF(1.4020, 224)  },
+               { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },
+               { COEFF(1, 219), COEFF(1.7720, 224),  COEFF(0, 224)       },
+       };
+       static const int bt601_full[3][3] = {
+               { COEFF(1, 255), COEFF(0, 255),       COEFF(1.4020, 255)  },
+               { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },
+               { COEFF(1, 255), COEFF(1.7720, 255),  COEFF(0, 255)       },
+       };
+       static const int rec709[3][3] = {
+               { COEFF(1, 219), COEFF(0, 224),       COEFF(1.5748, 224)  },
+               { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },
+               { COEFF(1, 219), COEFF(1.8556, 224),  COEFF(0, 224)       },
+       };
+       static const int rec709_full[3][3] = {
+               { COEFF(1, 255), COEFF(0, 255),       COEFF(1.5748, 255)  },
+               { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },
+               { COEFF(1, 255), COEFF(1.8556, 255),  COEFF(0, 255)       },
+       };
+       static const int smpte240m[3][3] = {
+               { COEFF(1, 219), COEFF(0, 224),       COEFF(1.5756, 224)  },
+               { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },
+               { COEFF(1, 219), COEFF(1.8270, 224),  COEFF(0, 224)       },
+       };
+       static const int smpte240m_full[3][3] = {
+               { COEFF(1, 255), COEFF(0, 255),       COEFF(1.5756, 255)  },
+               { COEFF(1, 255), COEFF(-0.2253, 255), COEFF(-0.4767, 255) },
+               { COEFF(1, 255), COEFF(1.8270, 255),  COEFF(0, 255)       },
+       };
+       static const int bt2020[3][3] = {
+               { COEFF(1, 219), COEFF(0, 224),       COEFF(1.4746, 224)  },
+               { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },
+               { COEFF(1, 219), COEFF(1.8814, 224),  COEFF(0, 224)       },
+       };
+       static const int bt2020_full[3][3] = {
+               { COEFF(1, 255), COEFF(0, 255),       COEFF(1.4746, 255)  },
+               { COEFF(1, 255), COEFF(-0.1646, 255), COEFF(-0.5714, 255) },
+               { COEFF(1, 255), COEFF(1.8814, 255),  COEFF(0, 255)       },
+       };
+       static const int bt2020c[4] = {
+               COEFF(1.9404, 224), COEFF(1.5816, 224),
+               COEFF(1.7184, 224), COEFF(0.9936, 224),
+       };
+       static const int bt2020c_full[4] = {
+               COEFF(1.9404, 255), COEFF(1.5816, 255),
+               COEFF(1.7184, 255), COEFF(0.9936, 255),
+       };
+
+       bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
+       unsigned y_offset = full ? 0 : 16;
+       int y_fac = full ? COEFF(1.0, 255) : COEFF(1.0, 219);
+       int lin_r, lin_g, lin_b, lin_y;
+
+       switch (tpg->real_ycbcr_enc) {
+       case V4L2_YCBCR_ENC_601:
+       case V4L2_YCBCR_ENC_SYCC:
+               ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b);
+               break;
+       case V4L2_YCBCR_ENC_XV601:
+               /* Ignore quantization range, there is only one possible
+                * Y'CbCr encoding. */
+               ycbcr2rgb(bt601, y, cb, cr, 16, r, g, b);
+               break;
+       case V4L2_YCBCR_ENC_XV709:
+               /* Ignore quantization range, there is only one possible
+                * Y'CbCr encoding. */
+               ycbcr2rgb(rec709, y, cb, cr, 16, r, g, b);
+               break;
+       case V4L2_YCBCR_ENC_BT2020:
+               ycbcr2rgb(full ? bt2020_full : bt2020, y, cb, cr, y_offset, r, g, b);
+               break;
+       case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
+               y -= full ? 0 : 16 << 4;
+               cb -= 128 << 4;
+               cr -= 128 << 4;
+
+               if (cb <= 0)
+                       *b = y_fac * y + (full ? bt2020c_full[0] : bt2020c[0]) * cb;
+               else
+                       *b = y_fac * y + (full ? bt2020c_full[1] : bt2020c[1]) * cb;
+               *b = *b >> 12;
+               if (cr <= 0)
+                       *r = y_fac * y + (full ? bt2020c_full[2] : bt2020c[2]) * cr;
+               else
+                       *r = y_fac * y + (full ? bt2020c_full[3] : bt2020c[3]) * cr;
+               *r = *r >> 12;
+               lin_r = rec709_to_linear(*r);
+               lin_b = rec709_to_linear(*b);
+               lin_y = rec709_to_linear((y * 255) / (full ? 255 : 219));
+
+               lin_g = COEFF(1.0 / 0.6780, 255) * lin_y -
+                       COEFF(0.2627 / 0.6780, 255) * lin_r -
+                       COEFF(0.0593 / 0.6780, 255) * lin_b;
+               *g = linear_to_rec709(lin_g >> 12);
+               break;
+       case V4L2_YCBCR_ENC_SMPTE240M:
+               ycbcr2rgb(full ? smpte240m_full : smpte240m, y, cb, cr, y_offset, r, g, b);
+               break;
+       case V4L2_YCBCR_ENC_709:
+       default:
+               ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b);
+               break;
+       }
+}
+
+/* precalculate color bar values to speed up rendering */
+static void precalculate_color(struct tpg_data *tpg, int k)
+{
+       int col = k;
+       int r = tpg_colors[col].r;
+       int g = tpg_colors[col].g;
+       int b = tpg_colors[col].b;
+
+       if (k == TPG_COLOR_TEXTBG) {
+               col = tpg_get_textbg_color(tpg);
+
+               r = tpg_colors[col].r;
+               g = tpg_colors[col].g;
+               b = tpg_colors[col].b;
+       } else if (k == TPG_COLOR_TEXTFG) {
+               col = tpg_get_textfg_color(tpg);
+
+               r = tpg_colors[col].r;
+               g = tpg_colors[col].g;
+               b = tpg_colors[col].b;
+       } else if (tpg->pattern == TPG_PAT_NOISE) {
+               r = g = b = prandom_u32_max(256);
+       } else if (k == TPG_COLOR_RANDOM) {
+               r = g = b = tpg->qual_offset + prandom_u32_max(196);
+       } else if (k >= TPG_COLOR_RAMP) {
+               r = g = b = k - TPG_COLOR_RAMP;
+       }
+
+       if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
+               r = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].r;
+               g = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].g;
+               b = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].b;
+       } else {
+               r <<= 4;
+               g <<= 4;
+               b <<= 4;
+       }
+       if (tpg->qual == TPG_QUAL_GRAY || tpg->fourcc == V4L2_PIX_FMT_GREY ||
+           tpg->fourcc == V4L2_PIX_FMT_Y16 ||
+           tpg->fourcc == V4L2_PIX_FMT_Y16_BE) {
+               /* Rec. 709 Luma function */
+               /* (0.2126, 0.7152, 0.0722) * (255 * 256) */
+               r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;
+       }
+
+       /*
+        * The assumption is that the RGB output is always full range,
+        * so only if the rgb_range overrides the 'real' rgb range do
+        * we need to convert the RGB values.
+        *
+        * Remember that r, g and b are still in the 0 - 0xff0 range.
+        */
+       if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
+           tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL) {
+               /*
+                * Convert from full range (which is what r, g and b are)
+                * to limited range (which is the 'real' RGB range), which
+                * is then interpreted as full range.
+                */
+               r = (r * 219) / 255 + (16 << 4);
+               g = (g * 219) / 255 + (16 << 4);
+               b = (b * 219) / 255 + (16 << 4);
+       } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
+                  tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED) {
+               /*
+                * Clamp r, g and b to the limited range and convert to full
+                * range since that's what we deliver.
+                */
+               r = clamp(r, 16 << 4, 235 << 4);
+               g = clamp(g, 16 << 4, 235 << 4);
+               b = clamp(b, 16 << 4, 235 << 4);
+               r = (r - (16 << 4)) * 255 / 219;
+               g = (g - (16 << 4)) * 255 / 219;
+               b = (b - (16 << 4)) * 255 / 219;
+       }
+
+       if (tpg->brightness != 128 || tpg->contrast != 128 ||
+           tpg->saturation != 128 || tpg->hue) {
+               /* Implement these operations */
+               int y, cb, cr;
+               int tmp_cb, tmp_cr;
+
+               /* First convert to YCbCr */
+
+               color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
+
+               y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
+               y += (tpg->brightness << 4) - (128 << 4);
+
+               cb -= 128 << 4;
+               cr -= 128 << 4;
+               tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
+               tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
+
+               cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
+               cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
+               if (tpg->is_yuv) {
+                       tpg->colors[k][0] = clamp(y >> 4, 1, 254);
+                       tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
+                       tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
+                       return;
+               }
+               ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b);
+       }
+
+       if (tpg->is_yuv) {
+               /* Convert to YCbCr */
+               int y, cb, cr;
+
+               color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
+
+               if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
+                       y = clamp(y, 16 << 4, 235 << 4);
+                       cb = clamp(cb, 16 << 4, 240 << 4);
+                       cr = clamp(cr, 16 << 4, 240 << 4);
+               }
+               y = clamp(y >> 4, 1, 254);
+               cb = clamp(cb >> 4, 1, 254);
+               cr = clamp(cr >> 4, 1, 254);
+               switch (tpg->fourcc) {
+               case V4L2_PIX_FMT_YUV444:
+                       y >>= 4;
+                       cb >>= 4;
+                       cr >>= 4;
+                       break;
+               case V4L2_PIX_FMT_YUV555:
+                       y >>= 3;
+                       cb >>= 3;
+                       cr >>= 3;
+                       break;
+               case V4L2_PIX_FMT_YUV565:
+                       y >>= 3;
+                       cb >>= 2;
+                       cr >>= 3;
+                       break;
+               }
+               tpg->colors[k][0] = y;
+               tpg->colors[k][1] = cb;
+               tpg->colors[k][2] = cr;
+       } else {
+               if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
+                       r = (r * 219) / 255 + (16 << 4);
+                       g = (g * 219) / 255 + (16 << 4);
+                       b = (b * 219) / 255 + (16 << 4);
+               }
+               switch (tpg->fourcc) {
+               case V4L2_PIX_FMT_RGB332:
+                       r >>= 9;
+                       g >>= 9;
+                       b >>= 10;
+                       break;
+               case V4L2_PIX_FMT_RGB565:
+               case V4L2_PIX_FMT_RGB565X:
+                       r >>= 7;
+                       g >>= 6;
+                       b >>= 7;
+                       break;
+               case V4L2_PIX_FMT_RGB444:
+               case V4L2_PIX_FMT_XRGB444:
+               case V4L2_PIX_FMT_ARGB444:
+                       r >>= 8;
+                       g >>= 8;
+                       b >>= 8;
+                       break;
+               case V4L2_PIX_FMT_RGB555:
+               case V4L2_PIX_FMT_XRGB555:
+               case V4L2_PIX_FMT_ARGB555:
+               case V4L2_PIX_FMT_RGB555X:
+               case V4L2_PIX_FMT_XRGB555X:
+               case V4L2_PIX_FMT_ARGB555X:
+                       r >>= 7;
+                       g >>= 7;
+                       b >>= 7;
+                       break;
+               case V4L2_PIX_FMT_BGR666:
+                       r >>= 6;
+                       g >>= 6;
+                       b >>= 6;
+                       break;
+               default:
+                       r >>= 4;
+                       g >>= 4;
+                       b >>= 4;
+                       break;
+               }
+
+               tpg->colors[k][0] = r;
+               tpg->colors[k][1] = g;
+               tpg->colors[k][2] = b;
+       }
+}
+
+static void tpg_precalculate_colors(struct tpg_data *tpg)
+{
+       int k;
+
+       for (k = 0; k < TPG_COLOR_MAX; k++)
+               precalculate_color(tpg, k);
+}
+
+/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
+static void gen_twopix(struct tpg_data *tpg,
+               u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
+{
+       unsigned offset = odd * tpg->twopixelsize[0] / 2;
+       u8 alpha = tpg->alpha_component;
+       u8 r_y, g_u, b_v;
+
+       if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
+                                  color != TPG_COLOR_100_RED &&
+                                  color != TPG_COLOR_75_RED)
+               alpha = 0;
+       if (color == TPG_COLOR_RANDOM)
+               precalculate_color(tpg, color);
+       r_y = tpg->colors[color][0]; /* R or precalculated Y */
+       g_u = tpg->colors[color][1]; /* G or precalculated U */
+       b_v = tpg->colors[color][2]; /* B or precalculated V */
+
+       switch (tpg->fourcc) {
+       case V4L2_PIX_FMT_GREY:
+               buf[0][offset] = r_y;
+               break;
+       case V4L2_PIX_FMT_Y16:
+               /*
+                * Ideally both bytes should be set to r_y, but then you won't
+                * be able to detect endian problems. So keep it 0 except for
+                * the corner case where r_y is 0xff so white really will be
+                * white (0xffff).
+                */
+               buf[0][offset] = r_y == 0xff ? r_y : 0;
+               buf[0][offset+1] = r_y;
+               break;
+       case V4L2_PIX_FMT_Y16_BE:
+               /* See comment for V4L2_PIX_FMT_Y16 above */
+               buf[0][offset] = r_y;
+               buf[0][offset+1] = r_y == 0xff ? r_y : 0;
+               break;
+       case V4L2_PIX_FMT_YUV422M:
+       case V4L2_PIX_FMT_YUV422P:
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YUV420M:
+               buf[0][offset] = r_y;
+               if (odd) {
+                       buf[1][0] = (buf[1][0] + g_u) / 2;
+                       buf[2][0] = (buf[2][0] + b_v) / 2;
+                       buf[1][1] = buf[1][0];
+                       buf[2][1] = buf[2][0];
+                       break;
+               }
+               buf[1][0] = g_u;
+               buf[2][0] = b_v;
+               break;
+       case V4L2_PIX_FMT_YVU422M:
+       case V4L2_PIX_FMT_YVU420:
+       case V4L2_PIX_FMT_YVU420M:
+               buf[0][offset] = r_y;
+               if (odd) {
+                       buf[1][0] = (buf[1][0] + b_v) / 2;
+                       buf[2][0] = (buf[2][0] + g_u) / 2;
+                       buf[1][1] = buf[1][0];
+                       buf[2][1] = buf[2][0];
+                       break;
+               }
+               buf[1][0] = b_v;
+               buf[2][0] = g_u;
+               break;
+
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV12M:
+       case V4L2_PIX_FMT_NV16:
+       case V4L2_PIX_FMT_NV16M:
+               buf[0][offset] = r_y;
+               if (odd) {
+                       buf[1][0] = (buf[1][0] + g_u) / 2;
+                       buf[1][1] = (buf[1][1] + b_v) / 2;
+                       break;
+               }
+               buf[1][0] = g_u;
+               buf[1][1] = b_v;
+               break;
+       case V4L2_PIX_FMT_NV21:
+       case V4L2_PIX_FMT_NV21M:
+       case V4L2_PIX_FMT_NV61:
+       case V4L2_PIX_FMT_NV61M:
+               buf[0][offset] = r_y;
+               if (odd) {
+                       buf[1][0] = (buf[1][0] + b_v) / 2;
+                       buf[1][1] = (buf[1][1] + g_u) / 2;
+                       break;
+               }
+               buf[1][0] = b_v;
+               buf[1][1] = g_u;
+               break;
+
+       case V4L2_PIX_FMT_YUV444M:
+               buf[0][offset] = r_y;
+               buf[1][offset] = g_u;
+               buf[2][offset] = b_v;
+               break;
+
+       case V4L2_PIX_FMT_YVU444M:
+               buf[0][offset] = r_y;
+               buf[1][offset] = b_v;
+               buf[2][offset] = g_u;
+               break;
+
+       case V4L2_PIX_FMT_NV24:
+               buf[0][offset] = r_y;
+               buf[1][2 * offset] = g_u;
+               buf[1][2 * offset + 1] = b_v;
+               break;
+
+       case V4L2_PIX_FMT_NV42:
+               buf[0][offset] = r_y;
+               buf[1][2 * offset] = b_v;
+               buf[1][2 * offset + 1] = g_u;
+               break;
+
+       case V4L2_PIX_FMT_YUYV:
+               buf[0][offset] = r_y;
+               if (odd) {
+                       buf[0][1] = (buf[0][1] + g_u) / 2;
+                       buf[0][3] = (buf[0][3] + b_v) / 2;
+                       break;
+               }
+               buf[0][1] = g_u;
+               buf[0][3] = b_v;
+               break;
+       case V4L2_PIX_FMT_UYVY:
+               buf[0][offset + 1] = r_y;
+               if (odd) {
+                       buf[0][0] = (buf[0][0] + g_u) / 2;
+                       buf[0][2] = (buf[0][2] + b_v) / 2;
+                       break;
+               }
+               buf[0][0] = g_u;
+               buf[0][2] = b_v;
+               break;
+       case V4L2_PIX_FMT_YVYU:
+               buf[0][offset] = r_y;
+               if (odd) {
+                       buf[0][1] = (buf[0][1] + b_v) / 2;
+                       buf[0][3] = (buf[0][3] + g_u) / 2;
+                       break;
+               }
+               buf[0][1] = b_v;
+               buf[0][3] = g_u;
+               break;
+       case V4L2_PIX_FMT_VYUY:
+               buf[0][offset + 1] = r_y;
+               if (odd) {
+                       buf[0][0] = (buf[0][0] + b_v) / 2;
+                       buf[0][2] = (buf[0][2] + g_u) / 2;
+                       break;
+               }
+               buf[0][0] = b_v;
+               buf[0][2] = g_u;
+               break;
+       case V4L2_PIX_FMT_RGB332:
+               buf[0][offset] = (r_y << 5) | (g_u << 2) | b_v;
+               break;
+       case V4L2_PIX_FMT_YUV565:
+       case V4L2_PIX_FMT_RGB565:
+               buf[0][offset] = (g_u << 5) | b_v;
+               buf[0][offset + 1] = (r_y << 3) | (g_u >> 3);
+               break;
+       case V4L2_PIX_FMT_RGB565X:
+               buf[0][offset] = (r_y << 3) | (g_u >> 3);
+               buf[0][offset + 1] = (g_u << 5) | b_v;
+               break;
+       case V4L2_PIX_FMT_RGB444:
+       case V4L2_PIX_FMT_XRGB444:
+               alpha = 0;
+               /* fall through */
+       case V4L2_PIX_FMT_YUV444:
+       case V4L2_PIX_FMT_ARGB444:
+               buf[0][offset] = (g_u << 4) | b_v;
+               buf[0][offset + 1] = (alpha & 0xf0) | r_y;
+               break;
+       case V4L2_PIX_FMT_RGB555:
+       case V4L2_PIX_FMT_XRGB555:
+               alpha = 0;
+               /* fall through */
+       case V4L2_PIX_FMT_YUV555:
+       case V4L2_PIX_FMT_ARGB555:
+               buf[0][offset] = (g_u << 5) | b_v;
+               buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
+               break;
+       case V4L2_PIX_FMT_RGB555X:
+       case V4L2_PIX_FMT_XRGB555X:
+               alpha = 0;
+               /* fall through */
+       case V4L2_PIX_FMT_ARGB555X:
+               buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
+               buf[0][offset + 1] = (g_u << 5) | b_v;
+               break;
+       case V4L2_PIX_FMT_RGB24:
+               buf[0][offset] = r_y;
+               buf[0][offset + 1] = g_u;
+               buf[0][offset + 2] = b_v;
+               break;
+       case V4L2_PIX_FMT_BGR24:
+               buf[0][offset] = b_v;
+               buf[0][offset + 1] = g_u;
+               buf[0][offset + 2] = r_y;
+               break;
+       case V4L2_PIX_FMT_BGR666:
+               buf[0][offset] = (b_v << 2) | (g_u >> 4);
+               buf[0][offset + 1] = (g_u << 4) | (r_y >> 2);
+               buf[0][offset + 2] = r_y << 6;
+               buf[0][offset + 3] = 0;
+               break;
+       case V4L2_PIX_FMT_RGB32:
+       case V4L2_PIX_FMT_XRGB32:
+               alpha = 0;
+               /* fall through */
+       case V4L2_PIX_FMT_YUV32:
+       case V4L2_PIX_FMT_ARGB32:
+               buf[0][offset] = alpha;
+               buf[0][offset + 1] = r_y;
+               buf[0][offset + 2] = g_u;
+               buf[0][offset + 3] = b_v;
+               break;
+       case V4L2_PIX_FMT_BGR32:
+       case V4L2_PIX_FMT_XBGR32:
+               alpha = 0;
+               /* fall through */
+       case V4L2_PIX_FMT_ABGR32:
+               buf[0][offset] = b_v;
+               buf[0][offset + 1] = g_u;
+               buf[0][offset + 2] = r_y;
+               buf[0][offset + 3] = alpha;
+               break;
+       case V4L2_PIX_FMT_SBGGR8:
+               buf[0][offset] = odd ? g_u : b_v;
+               buf[1][offset] = odd ? r_y : g_u;
+               break;
+       case V4L2_PIX_FMT_SGBRG8:
+               buf[0][offset] = odd ? b_v : g_u;
+               buf[1][offset] = odd ? g_u : r_y;
+               break;
+       case V4L2_PIX_FMT_SGRBG8:
+               buf[0][offset] = odd ? r_y : g_u;
+               buf[1][offset] = odd ? g_u : b_v;
+               break;
+       case V4L2_PIX_FMT_SRGGB8:
+               buf[0][offset] = odd ? g_u : r_y;
+               buf[1][offset] = odd ? b_v : g_u;
+               break;
+       case V4L2_PIX_FMT_SBGGR10:
+               buf[0][offset] = odd ? g_u << 2 : b_v << 2;
+               buf[0][offset + 1] = odd ? g_u >> 6 : b_v >> 6;
+               buf[1][offset] = odd ? r_y << 2 : g_u << 2;
+               buf[1][offset + 1] = odd ? r_y >> 6 : g_u >> 6;
+               buf[0][offset] |= (buf[0][offset] >> 2) & 3;
+               buf[1][offset] |= (buf[1][offset] >> 2) & 3;
+               break;
+       case V4L2_PIX_FMT_SGBRG10:
+               buf[0][offset] = odd ? b_v << 2 : g_u << 2;
+               buf[0][offset + 1] = odd ? b_v >> 6 : g_u >> 6;
+               buf[1][offset] = odd ? g_u << 2 : r_y << 2;
+               buf[1][offset + 1] = odd ? g_u >> 6 : r_y >> 6;
+               buf[0][offset] |= (buf[0][offset] >> 2) & 3;
+               buf[1][offset] |= (buf[1][offset] >> 2) & 3;
+               break;
+       case V4L2_PIX_FMT_SGRBG10:
+               buf[0][offset] = odd ? r_y << 2 : g_u << 2;
+               buf[0][offset + 1] = odd ? r_y >> 6 : g_u >> 6;
+               buf[1][offset] = odd ? g_u << 2 : b_v << 2;
+               buf[1][offset + 1] = odd ? g_u >> 6 : b_v >> 6;
+               buf[0][offset] |= (buf[0][offset] >> 2) & 3;
+               buf[1][offset] |= (buf[1][offset] >> 2) & 3;
+               break;
+       case V4L2_PIX_FMT_SRGGB10:
+               buf[0][offset] = odd ? g_u << 2 : r_y << 2;
+               buf[0][offset + 1] = odd ? g_u >> 6 : r_y >> 6;
+               buf[1][offset] = odd ? b_v << 2 : g_u << 2;
+               buf[1][offset + 1] = odd ? b_v >> 6 : g_u >> 6;
+               buf[0][offset] |= (buf[0][offset] >> 2) & 3;
+               buf[1][offset] |= (buf[1][offset] >> 2) & 3;
+               break;
+       case V4L2_PIX_FMT_SBGGR12:
+               buf[0][offset] = odd ? g_u << 4 : b_v << 4;
+               buf[0][offset + 1] = odd ? g_u >> 4 : b_v >> 4;
+               buf[1][offset] = odd ? r_y << 4 : g_u << 4;
+               buf[1][offset + 1] = odd ? r_y >> 4 : g_u >> 4;
+               buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
+               buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
+               break;
+       case V4L2_PIX_FMT_SGBRG12:
+               buf[0][offset] = odd ? b_v << 4 : g_u << 4;
+               buf[0][offset + 1] = odd ? b_v >> 4 : g_u >> 4;
+               buf[1][offset] = odd ? g_u << 4 : r_y << 4;
+               buf[1][offset + 1] = odd ? g_u >> 4 : r_y >> 4;
+               buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
+               buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
+               break;
+       case V4L2_PIX_FMT_SGRBG12:
+               buf[0][offset] = odd ? r_y << 4 : g_u << 4;
+               buf[0][offset + 1] = odd ? r_y >> 4 : g_u >> 4;
+               buf[1][offset] = odd ? g_u << 4 : b_v << 4;
+               buf[1][offset + 1] = odd ? g_u >> 4 : b_v >> 4;
+               buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
+               buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
+               break;
+       case V4L2_PIX_FMT_SRGGB12:
+               buf[0][offset] = odd ? g_u << 4 : r_y << 4;
+               buf[0][offset + 1] = odd ? g_u >> 4 : r_y >> 4;
+               buf[1][offset] = odd ? b_v << 4 : g_u << 4;
+               buf[1][offset + 1] = odd ? b_v >> 4 : g_u >> 4;
+               buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
+               buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
+               break;
+       }
+}
+
+unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line)
+{
+       switch (tpg->fourcc) {
+       case V4L2_PIX_FMT_SBGGR8:
+       case V4L2_PIX_FMT_SGBRG8:
+       case V4L2_PIX_FMT_SGRBG8:
+       case V4L2_PIX_FMT_SRGGB8:
+       case V4L2_PIX_FMT_SBGGR10:
+       case V4L2_PIX_FMT_SGBRG10:
+       case V4L2_PIX_FMT_SGRBG10:
+       case V4L2_PIX_FMT_SRGGB10:
+       case V4L2_PIX_FMT_SBGGR12:
+       case V4L2_PIX_FMT_SGBRG12:
+       case V4L2_PIX_FMT_SGRBG12:
+       case V4L2_PIX_FMT_SRGGB12:
+               return buf_line & 1;
+       default:
+               return 0;
+       }
+}
+EXPORT_SYMBOL_GPL(tpg_g_interleaved_plane);
+
+/* Return how many pattern lines are used by the current pattern. */
+static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)
+{
+       switch (tpg->pattern) {
+       case TPG_PAT_CHECKERS_16X16:
+       case TPG_PAT_CHECKERS_2X2:
+       case TPG_PAT_CHECKERS_1X1:
+       case TPG_PAT_COLOR_CHECKERS_2X2:
+       case TPG_PAT_COLOR_CHECKERS_1X1:
+       case TPG_PAT_ALTERNATING_HLINES:
+       case TPG_PAT_CROSS_1_PIXEL:
+       case TPG_PAT_CROSS_2_PIXELS:
+       case TPG_PAT_CROSS_10_PIXELS:
+               return 2;
+       case TPG_PAT_100_COLORSQUARES:
+       case TPG_PAT_100_HCOLORBAR:
+               return 8;
+       default:
+               return 1;
+       }
+}
+
+/* Which pattern line should be used for the given frame line. */
+static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line)
+{
+       switch (tpg->pattern) {
+       case TPG_PAT_CHECKERS_16X16:
+               return (line >> 4) & 1;
+       case TPG_PAT_CHECKERS_1X1:
+       case TPG_PAT_COLOR_CHECKERS_1X1:
+       case TPG_PAT_ALTERNATING_HLINES:
+               return line & 1;
+       case TPG_PAT_CHECKERS_2X2:
+       case TPG_PAT_COLOR_CHECKERS_2X2:
+               return (line & 2) >> 1;
+       case TPG_PAT_100_COLORSQUARES:
+       case TPG_PAT_100_HCOLORBAR:
+               return (line * 8) / tpg->src_height;
+       case TPG_PAT_CROSS_1_PIXEL:
+               return line == tpg->src_height / 2;
+       case TPG_PAT_CROSS_2_PIXELS:
+               return (line + 1) / 2 == tpg->src_height / 4;
+       case TPG_PAT_CROSS_10_PIXELS:
+               return (line + 10) / 20 == tpg->src_height / 40;
+       default:
+               return 0;
+       }
+}
+
+/*
+ * Which color should be used for the given pattern line and X coordinate.
+ * Note: x is in the range 0 to 2 * tpg->src_width.
+ */
+static enum tpg_color tpg_get_color(const struct tpg_data *tpg,
+                                   unsigned pat_line, unsigned x)
+{
+       /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
+          should be modified */
+       static const enum tpg_color bars[3][8] = {
+               /* Standard ITU-R 75% color bar sequence */
+               { TPG_COLOR_CSC_WHITE,   TPG_COLOR_75_YELLOW,
+                 TPG_COLOR_75_CYAN,     TPG_COLOR_75_GREEN,
+                 TPG_COLOR_75_MAGENTA,  TPG_COLOR_75_RED,
+                 TPG_COLOR_75_BLUE,     TPG_COLOR_100_BLACK, },
+               /* Standard ITU-R 100% color bar sequence */
+               { TPG_COLOR_100_WHITE,   TPG_COLOR_100_YELLOW,
+                 TPG_COLOR_100_CYAN,    TPG_COLOR_100_GREEN,
+                 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
+                 TPG_COLOR_100_BLUE,    TPG_COLOR_100_BLACK, },
+               /* Color bar sequence suitable to test CSC */
+               { TPG_COLOR_CSC_WHITE,   TPG_COLOR_CSC_YELLOW,
+                 TPG_COLOR_CSC_CYAN,    TPG_COLOR_CSC_GREEN,
+                 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
+                 TPG_COLOR_CSC_BLUE,    TPG_COLOR_CSC_BLACK, },
+       };
+
+       switch (tpg->pattern) {
+       case TPG_PAT_75_COLORBAR:
+       case TPG_PAT_100_COLORBAR:
+       case TPG_PAT_CSC_COLORBAR:
+               return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
+       case TPG_PAT_100_COLORSQUARES:
+               return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
+       case TPG_PAT_100_HCOLORBAR:
+               return bars[1][pat_line];
+       case TPG_PAT_BLACK:
+               return TPG_COLOR_100_BLACK;
+       case TPG_PAT_WHITE:
+               return TPG_COLOR_100_WHITE;
+       case TPG_PAT_RED:
+               return TPG_COLOR_100_RED;
+       case TPG_PAT_GREEN:
+               return TPG_COLOR_100_GREEN;
+       case TPG_PAT_BLUE:
+               return TPG_COLOR_100_BLUE;
+       case TPG_PAT_CHECKERS_16X16:
+               return (((x >> 4) & 1) ^ (pat_line & 1)) ?
+                       TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
+       case TPG_PAT_CHECKERS_1X1:
+               return ((x & 1) ^ (pat_line & 1)) ?
+                       TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
+       case TPG_PAT_COLOR_CHECKERS_1X1:
+               return ((x & 1) ^ (pat_line & 1)) ?
+                       TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
+       case TPG_PAT_CHECKERS_2X2:
+               return (((x >> 1) & 1) ^ (pat_line & 1)) ?
+                       TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
+       case TPG_PAT_COLOR_CHECKERS_2X2:
+               return (((x >> 1) & 1) ^ (pat_line & 1)) ?
+                       TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
+       case TPG_PAT_ALTERNATING_HLINES:
+               return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
+       case TPG_PAT_ALTERNATING_VLINES:
+               return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
+       case TPG_PAT_CROSS_1_PIXEL:
+               if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
+                       return TPG_COLOR_100_BLACK;
+               return TPG_COLOR_100_WHITE;
+       case TPG_PAT_CROSS_2_PIXELS:
+               if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
+                       return TPG_COLOR_100_BLACK;
+               return TPG_COLOR_100_WHITE;
+       case TPG_PAT_CROSS_10_PIXELS:
+               if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
+                       return TPG_COLOR_100_BLACK;
+               return TPG_COLOR_100_WHITE;
+       case TPG_PAT_GRAY_RAMP:
+               return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
+       default:
+               return TPG_COLOR_100_RED;
+       }
+}
+
+/*
+ * Given the pixel aspect ratio and video aspect ratio calculate the
+ * coordinates of a centered square and the coordinates of the border of
+ * the active video area. The coordinates are relative to the source
+ * frame rectangle.
+ */
+static void tpg_calculate_square_border(struct tpg_data *tpg)
+{
+       unsigned w = tpg->src_width;
+       unsigned h = tpg->src_height;
+       unsigned sq_w, sq_h;
+
+       sq_w = (w * 2 / 5) & ~1;
+       if (((w - sq_w) / 2) & 1)
+               sq_w += 2;
+       sq_h = sq_w;
+       tpg->square.width = sq_w;
+       if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
+               unsigned ana_sq_w = (sq_w / 4) * 3;
+
+               if (((w - ana_sq_w) / 2) & 1)
+                       ana_sq_w += 2;
+               tpg->square.width = ana_sq_w;
+       }
+       tpg->square.left = (w - tpg->square.width) / 2;
+       if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
+               sq_h = sq_w * 10 / 11;
+       else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
+               sq_h = sq_w * 59 / 54;
+       tpg->square.height = sq_h;
+       tpg->square.top = (h - sq_h) / 2;
+       tpg->border.left = 0;
+       tpg->border.width = w;
+       tpg->border.top = 0;
+       tpg->border.height = h;
+       switch (tpg->vid_aspect) {
+       case TPG_VIDEO_ASPECT_4X3:
+               if (tpg->pix_aspect)
+                       return;
+               if (3 * w >= 4 * h) {
+                       tpg->border.width = ((4 * h) / 3) & ~1;
+                       if (((w - tpg->border.width) / 2) & ~1)
+                               tpg->border.width -= 2;
+                       tpg->border.left = (w - tpg->border.width) / 2;
+                       break;
+               }
+               tpg->border.height = ((3 * w) / 4) & ~1;
+               tpg->border.top = (h - tpg->border.height) / 2;
+               break;
+       case TPG_VIDEO_ASPECT_14X9_CENTRE:
+               if (tpg->pix_aspect) {
+                       tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
+                       tpg->border.top = (h - tpg->border.height) / 2;
+                       break;
+               }
+               if (9 * w >= 14 * h) {
+                       tpg->border.width = ((14 * h) / 9) & ~1;
+                       if (((w - tpg->border.width) / 2) & ~1)
+                               tpg->border.width -= 2;
+                       tpg->border.left = (w - tpg->border.width) / 2;
+                       break;
+               }
+               tpg->border.height = ((9 * w) / 14) & ~1;
+               tpg->border.top = (h - tpg->border.height) / 2;
+               break;
+       case TPG_VIDEO_ASPECT_16X9_CENTRE:
+               if (tpg->pix_aspect) {
+                       tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
+                       tpg->border.top = (h - tpg->border.height) / 2;
+                       break;
+               }
+               if (9 * w >= 16 * h) {
+                       tpg->border.width = ((16 * h) / 9) & ~1;
+                       if (((w - tpg->border.width) / 2) & ~1)
+                               tpg->border.width -= 2;
+                       tpg->border.left = (w - tpg->border.width) / 2;
+                       break;
+               }
+               tpg->border.height = ((9 * w) / 16) & ~1;
+               tpg->border.top = (h - tpg->border.height) / 2;
+               break;
+       default:
+               break;
+       }
+}
+
+static void tpg_precalculate_line(struct tpg_data *tpg)
+{
+       enum tpg_color contrast;
+       u8 pix[TPG_MAX_PLANES][8];
+       unsigned pat;
+       unsigned p;
+       unsigned x;
+
+       switch (tpg->pattern) {
+       case TPG_PAT_GREEN:
+               contrast = TPG_COLOR_100_RED;
+               break;
+       case TPG_PAT_CSC_COLORBAR:
+               contrast = TPG_COLOR_CSC_GREEN;
+               break;
+       default:
+               contrast = TPG_COLOR_100_GREEN;
+               break;
+       }
+
+       for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
+               /* Coarse scaling with Bresenham */
+               unsigned int_part = tpg->src_width / tpg->scaled_width;
+               unsigned fract_part = tpg->src_width % tpg->scaled_width;
+               unsigned src_x = 0;
+               unsigned error = 0;
+
+               for (x = 0; x < tpg->scaled_width * 2; x += 2) {
+                       unsigned real_x = src_x;
+                       enum tpg_color color1, color2;
+
+                       real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
+                       color1 = tpg_get_color(tpg, pat, real_x);
+
+                       src_x += int_part;
+                       error += fract_part;
+                       if (error >= tpg->scaled_width) {
+                               error -= tpg->scaled_width;
+                               src_x++;
+                       }
+
+                       real_x = src_x;
+                       real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
+                       color2 = tpg_get_color(tpg, pat, real_x);
+
+                       src_x += int_part;
+                       error += fract_part;
+                       if (error >= tpg->scaled_width) {
+                               error -= tpg->scaled_width;
+                               src_x++;
+                       }
+
+                       gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);
+                       gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
+                       for (p = 0; p < tpg->planes; p++) {
+                               unsigned twopixsize = tpg->twopixelsize[p];
+                               unsigned hdiv = tpg->hdownsampling[p];
+                               u8 *pos = tpg->lines[pat][p] + tpg_hdiv(tpg, p, x);
+
+                               memcpy(pos, pix[p], twopixsize / hdiv);
+                       }
+               }
+       }
+
+       if (tpg->vdownsampling[tpg->planes - 1] > 1) {
+               unsigned pat_lines = tpg_get_pat_lines(tpg);
+
+               for (pat = 0; pat < pat_lines; pat++) {
+                       unsigned next_pat = (pat + 1) % pat_lines;
+
+                       for (p = 1; p < tpg->planes; p++) {
+                               unsigned w = tpg_hdiv(tpg, p, tpg->scaled_width * 2);
+                               u8 *pos1 = tpg->lines[pat][p];
+                               u8 *pos2 = tpg->lines[next_pat][p];
+                               u8 *dest = tpg->downsampled_lines[pat][p];
+
+                               for (x = 0; x < w; x++, pos1++, pos2++, dest++)
+                                       *dest = ((u16)*pos1 + (u16)*pos2) / 2;
+                       }
+               }
+       }
+
+       gen_twopix(tpg, pix, contrast, 0);
+       gen_twopix(tpg, pix, contrast, 1);
+       for (p = 0; p < tpg->planes; p++) {
+               unsigned twopixsize = tpg->twopixelsize[p];
+               u8 *pos = tpg->contrast_line[p];
+
+               for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
+                       memcpy(pos, pix[p], twopixsize);
+       }
+
+       gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
+       gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
+       for (p = 0; p < tpg->planes; p++) {
+               unsigned twopixsize = tpg->twopixelsize[p];
+               u8 *pos = tpg->black_line[p];
+
+               for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
+                       memcpy(pos, pix[p], twopixsize);
+       }
+
+       for (x = 0; x < tpg->scaled_width * 2; x += 2) {
+               gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
+               gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
+               for (p = 0; p < tpg->planes; p++) {
+                       unsigned twopixsize = tpg->twopixelsize[p];
+                       u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
+
+                       memcpy(pos, pix[p], twopixsize);
+               }
+       }
+
+       gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
+       gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
+       gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
+       gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);
+}
+
+/* need this to do rgb24 rendering */
+typedef struct { u16 __; u8 _; } __packed x24;
+
+#define PRINTSTR(PIXTYPE) do { \
+       unsigned vdiv = tpg->vdownsampling[p]; \
+       unsigned hdiv = tpg->hdownsampling[p]; \
+       int line;       \
+       PIXTYPE fg;     \
+       PIXTYPE bg;     \
+       memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE));   \
+       memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE));   \
+       \
+       for (line = first; line < 16; line += vdiv * step) {    \
+               int l = tpg->vflip ? 15 - line : line; \
+               PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \
+                              ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \
+                              (x / hdiv) * sizeof(PIXTYPE));   \
+               unsigned s;     \
+       \
+               for (s = 0; s < len; s++) {     \
+                       u8 chr = font8x16[text[s] * 16 + line]; \
+       \
+                       if (hdiv == 2 && tpg->hflip) { \
+                               pos[3] = (chr & (0x01 << 6) ? fg : bg); \
+                               pos[2] = (chr & (0x01 << 4) ? fg : bg); \
+                               pos[1] = (chr & (0x01 << 2) ? fg : bg); \
+                               pos[0] = (chr & (0x01 << 0) ? fg : bg); \
+                       } else if (hdiv == 2) { \
+                               pos[0] = (chr & (0x01 << 7) ? fg : bg); \
+                               pos[1] = (chr & (0x01 << 5) ? fg : bg); \
+                               pos[2] = (chr & (0x01 << 3) ? fg : bg); \
+                               pos[3] = (chr & (0x01 << 1) ? fg : bg); \
+                       } else if (tpg->hflip) { \
+                               pos[7] = (chr & (0x01 << 7) ? fg : bg); \
+                               pos[6] = (chr & (0x01 << 6) ? fg : bg); \
+                               pos[5] = (chr & (0x01 << 5) ? fg : bg); \
+                               pos[4] = (chr & (0x01 << 4) ? fg : bg); \
+                               pos[3] = (chr & (0x01 << 3) ? fg : bg); \
+                               pos[2] = (chr & (0x01 << 2) ? fg : bg); \
+                               pos[1] = (chr & (0x01 << 1) ? fg : bg); \
+                               pos[0] = (chr & (0x01 << 0) ? fg : bg); \
+                       } else { \
+                               pos[0] = (chr & (0x01 << 7) ? fg : bg); \
+                               pos[1] = (chr & (0x01 << 6) ? fg : bg); \
+                               pos[2] = (chr & (0x01 << 5) ? fg : bg); \
+                               pos[3] = (chr & (0x01 << 4) ? fg : bg); \
+                               pos[4] = (chr & (0x01 << 3) ? fg : bg); \
+                               pos[5] = (chr & (0x01 << 2) ? fg : bg); \
+                               pos[6] = (chr & (0x01 << 1) ? fg : bg); \
+                               pos[7] = (chr & (0x01 << 0) ? fg : bg); \
+                       } \
+       \
+                       pos += (tpg->hflip ? -8 : 8) / hdiv;    \
+               }       \
+       }       \
+} while (0)
+
+static noinline void tpg_print_str_2(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
+                       unsigned p, unsigned first, unsigned div, unsigned step,
+                       int y, int x, char *text, unsigned len)
+{
+       PRINTSTR(u8);
+}
+
+static noinline void tpg_print_str_4(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
+                       unsigned p, unsigned first, unsigned div, unsigned step,
+                       int y, int x, char *text, unsigned len)
+{
+       PRINTSTR(u16);
+}
+
+static noinline void tpg_print_str_6(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
+                       unsigned p, unsigned first, unsigned div, unsigned step,
+                       int y, int x, char *text, unsigned len)
+{
+       PRINTSTR(x24);
+}
+
+static noinline void tpg_print_str_8(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
+                       unsigned p, unsigned first, unsigned div, unsigned step,
+                       int y, int x, char *text, unsigned len)
+{
+       PRINTSTR(u32);
+}
+
+void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
+                 int y, int x, char *text)
+{
+       unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
+       unsigned div = step;
+       unsigned first = 0;
+       unsigned len = strlen(text);
+       unsigned p;
+
+       if (font8x16 == NULL || basep == NULL)
+               return;
+
+       /* Checks if it is possible to show string */
+       if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
+               return;
+
+       if (len > (tpg->compose.width - x) / 8)
+               len = (tpg->compose.width - x) / 8;
+       if (tpg->vflip)
+               y = tpg->compose.height - y - 16;
+       if (tpg->hflip)
+               x = tpg->compose.width - x - 8;
+       y += tpg->compose.top;
+       x += tpg->compose.left;
+       if (tpg->field == V4L2_FIELD_BOTTOM)
+               first = 1;
+       else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
+               div = 2;
+
+       for (p = 0; p < tpg->planes; p++) {
+               /* Print text */
+               switch (tpg->twopixelsize[p]) {
+               case 2:
+                       tpg_print_str_2(tpg, basep, p, first, div, step, y, x,
+                                       text, len);
+                       break;
+               case 4:
+                       tpg_print_str_4(tpg, basep, p, first, div, step, y, x,
+                                       text, len);
+                       break;
+               case 6:
+                       tpg_print_str_6(tpg, basep, p, first, div, step, y, x,
+                                       text, len);
+                       break;
+               case 8:
+                       tpg_print_str_8(tpg, basep, p, first, div, step, y, x,
+                                       text, len);
+                       break;
+               }
+       }
+}
+EXPORT_SYMBOL_GPL(tpg_gen_text);
+
+void tpg_update_mv_step(struct tpg_data *tpg)
+{
+       int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
+
+       if (tpg->hflip)
+               factor = -factor;
+       switch (tpg->mv_hor_mode) {
+       case TPG_MOVE_NEG_FAST:
+       case TPG_MOVE_POS_FAST:
+               tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
+               break;
+       case TPG_MOVE_NEG:
+       case TPG_MOVE_POS:
+               tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
+               break;
+       case TPG_MOVE_NEG_SLOW:
+       case TPG_MOVE_POS_SLOW:
+               tpg->mv_hor_step = 2;
+               break;
+       case TPG_MOVE_NONE:
+               tpg->mv_hor_step = 0;
+               break;
+       }
+       if (factor < 0)
+               tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
+
+       factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
+       switch (tpg->mv_vert_mode) {
+       case TPG_MOVE_NEG_FAST:
+       case TPG_MOVE_POS_FAST:
+               tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
+               break;
+       case TPG_MOVE_NEG:
+       case TPG_MOVE_POS:
+               tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
+               break;
+       case TPG_MOVE_NEG_SLOW:
+       case TPG_MOVE_POS_SLOW:
+               tpg->mv_vert_step = 1;
+               break;
+       case TPG_MOVE_NONE:
+               tpg->mv_vert_step = 0;
+               break;
+       }
+       if (factor < 0)
+               tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
+}
+EXPORT_SYMBOL_GPL(tpg_update_mv_step);
+
+/* Map the line number relative to the crop rectangle to a frame line number */
+static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y,
+                                   unsigned field)
+{
+       switch (field) {
+       case V4L2_FIELD_TOP:
+               return tpg->crop.top + src_y * 2;
+       case V4L2_FIELD_BOTTOM:
+               return tpg->crop.top + src_y * 2 + 1;
+       default:
+               return src_y + tpg->crop.top;
+       }
+}
+
+/*
+ * Map the line number relative to the compose rectangle to a destination
+ * buffer line number.
+ */
+static unsigned tpg_calc_buffer_line(const struct tpg_data *tpg, unsigned y,
+                                   unsigned field)
+{
+       y += tpg->compose.top;
+       switch (field) {
+       case V4L2_FIELD_SEQ_TB:
+               if (y & 1)
+                       return tpg->buf_height / 2 + y / 2;
+               return y / 2;
+       case V4L2_FIELD_SEQ_BT:
+               if (y & 1)
+                       return y / 2;
+               return tpg->buf_height / 2 + y / 2;
+       default:
+               return y;
+       }
+}
+
+static void tpg_recalc(struct tpg_data *tpg)
+{
+       if (tpg->recalc_colors) {
+               tpg->recalc_colors = false;
+               tpg->recalc_lines = true;
+               tpg->real_xfer_func = tpg->xfer_func;
+               tpg->real_ycbcr_enc = tpg->ycbcr_enc;
+               tpg->real_quantization = tpg->quantization;
+
+               if (tpg->xfer_func == V4L2_XFER_FUNC_DEFAULT)
+                       tpg->real_xfer_func =
+                               V4L2_MAP_XFER_FUNC_DEFAULT(tpg->colorspace);
+
+               if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
+                       tpg->real_ycbcr_enc =
+                               V4L2_MAP_YCBCR_ENC_DEFAULT(tpg->colorspace);
+
+               if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT)
+                       tpg->real_quantization =
+                               V4L2_MAP_QUANTIZATION_DEFAULT(!tpg->is_yuv,
+                                       tpg->colorspace, tpg->real_ycbcr_enc);
+
+               tpg_precalculate_colors(tpg);
+       }
+       if (tpg->recalc_square_border) {
+               tpg->recalc_square_border = false;
+               tpg_calculate_square_border(tpg);
+       }
+       if (tpg->recalc_lines) {
+               tpg->recalc_lines = false;
+               tpg_precalculate_line(tpg);
+       }
+}
+
+void tpg_calc_text_basep(struct tpg_data *tpg,
+               u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
+{
+       unsigned stride = tpg->bytesperline[p];
+       unsigned h = tpg->buf_height;
+
+       tpg_recalc(tpg);
+
+       basep[p][0] = vbuf;
+       basep[p][1] = vbuf;
+       h /= tpg->vdownsampling[p];
+       if (tpg->field == V4L2_FIELD_SEQ_TB)
+               basep[p][1] += h * stride / 2;
+       else if (tpg->field == V4L2_FIELD_SEQ_BT)
+               basep[p][0] += h * stride / 2;
+       if (p == 0 && tpg->interleaved)
+               tpg_calc_text_basep(tpg, basep, 1, vbuf);
+}
+EXPORT_SYMBOL_GPL(tpg_calc_text_basep);
+
+static int tpg_pattern_avg(const struct tpg_data *tpg,
+                          unsigned pat1, unsigned pat2)
+{
+       unsigned pat_lines = tpg_get_pat_lines(tpg);
+
+       if (pat1 == (pat2 + 1) % pat_lines)
+               return pat2;
+       if (pat2 == (pat1 + 1) % pat_lines)
+               return pat1;
+       return -1;
+}
+
+void tpg_log_status(struct tpg_data *tpg)
+{
+       pr_info("tpg source WxH: %ux%u (%s)\n",
+                       tpg->src_width, tpg->src_height,
+                       tpg->is_yuv ? "YCbCr" : "RGB");
+       pr_info("tpg field: %u\n", tpg->field);
+       pr_info("tpg crop: %ux%u@%dx%d\n", tpg->crop.width, tpg->crop.height,
+                       tpg->crop.left, tpg->crop.top);
+       pr_info("tpg compose: %ux%u@%dx%d\n", tpg->compose.width, tpg->compose.height,
+                       tpg->compose.left, tpg->compose.top);
+       pr_info("tpg colorspace: %d\n", tpg->colorspace);
+       pr_info("tpg transfer function: %d/%d\n", tpg->xfer_func, tpg->real_xfer_func);
+       pr_info("tpg Y'CbCr encoding: %d/%d\n", tpg->ycbcr_enc, tpg->real_ycbcr_enc);
+       pr_info("tpg quantization: %d/%d\n", tpg->quantization, tpg->real_quantization);
+       pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range);
+}
+EXPORT_SYMBOL_GPL(tpg_log_status);
+
+/*
+ * This struct contains common parameters used by both the drawing of the
+ * test pattern and the drawing of the extras (borders, square, etc.)
+ */
+struct tpg_draw_params {
+       /* common data */
+       bool is_tv;
+       bool is_60hz;
+       unsigned twopixsize;
+       unsigned img_width;
+       unsigned stride;
+       unsigned hmax;
+       unsigned frame_line;
+       unsigned frame_line_next;
+
+       /* test pattern */
+       unsigned mv_hor_old;
+       unsigned mv_hor_new;
+       unsigned mv_vert_old;
+       unsigned mv_vert_new;
+
+       /* extras */
+       unsigned wss_width;
+       unsigned wss_random_offset;
+       unsigned sav_eav_f;
+       unsigned left_pillar_width;
+       unsigned right_pillar_start;
+};
+
+static void tpg_fill_params_pattern(const struct tpg_data *tpg, unsigned p,
+                                   struct tpg_draw_params *params)
+{
+       params->mv_hor_old =
+               tpg_hscale_div(tpg, p, tpg->mv_hor_count % tpg->src_width);
+       params->mv_hor_new =
+               tpg_hscale_div(tpg, p, (tpg->mv_hor_count + tpg->mv_hor_step) %
+                              tpg->src_width);
+       params->mv_vert_old = tpg->mv_vert_count % tpg->src_height;
+       params->mv_vert_new =
+               (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
+}
+
+static void tpg_fill_params_extras(const struct tpg_data *tpg,
+                                  unsigned p,
+                                  struct tpg_draw_params *params)
+{
+       unsigned left_pillar_width = 0;
+       unsigned right_pillar_start = params->img_width;
+
+       params->wss_width = tpg->crop.left < tpg->src_width / 2 ?
+               tpg->src_width / 2 - tpg->crop.left : 0;
+       if (params->wss_width > tpg->crop.width)
+               params->wss_width = tpg->crop.width;
+       params->wss_width = tpg_hscale_div(tpg, p, params->wss_width);
+       params->wss_random_offset =
+               params->twopixsize * prandom_u32_max(tpg->src_width / 2);
+
+       if (tpg->crop.left < tpg->border.left) {
+               left_pillar_width = tpg->border.left - tpg->crop.left;
+               if (left_pillar_width > tpg->crop.width)
+                       left_pillar_width = tpg->crop.width;
+               left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width);
+       }
+       params->left_pillar_width = left_pillar_width;
+
+       if (tpg->crop.left + tpg->crop.width >
+           tpg->border.left + tpg->border.width) {
+               right_pillar_start =
+                       tpg->border.left + tpg->border.width - tpg->crop.left;
+               right_pillar_start =
+                       tpg_hscale_div(tpg, p, right_pillar_start);
+               if (right_pillar_start > params->img_width)
+                       right_pillar_start = params->img_width;
+       }
+       params->right_pillar_start = right_pillar_start;
+
+       params->sav_eav_f = tpg->field ==
+                       (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
+}
+
+static void tpg_fill_plane_extras(const struct tpg_data *tpg,
+                                 const struct tpg_draw_params *params,
+                                 unsigned p, unsigned h, u8 *vbuf)
+{
+       unsigned twopixsize = params->twopixsize;
+       unsigned img_width = params->img_width;
+       unsigned frame_line = params->frame_line;
+       const struct v4l2_rect *sq = &tpg->square;
+       const struct v4l2_rect *b = &tpg->border;
+       const struct v4l2_rect *c = &tpg->crop;
+
+       if (params->is_tv && !params->is_60hz &&
+           frame_line == 0 && params->wss_width) {
+               /*
+                * Replace the first half of the top line of a 50 Hz frame
+                * with random data to simulate a WSS signal.
+                */
+               u8 *wss = tpg->random_line[p] + params->wss_random_offset;
+
+               memcpy(vbuf, wss, params->wss_width);
+       }
+
+       if (tpg->show_border && frame_line >= b->top &&
+           frame_line < b->top + b->height) {
+               unsigned bottom = b->top + b->height - 1;
+               unsigned left = params->left_pillar_width;
+               unsigned right = params->right_pillar_start;
+
+               if (frame_line == b->top || frame_line == b->top + 1 ||
+                   frame_line == bottom || frame_line == bottom - 1) {
+                       memcpy(vbuf + left, tpg->contrast_line[p],
+                                       right - left);
+               } else {
+                       if (b->left >= c->left &&
+                           b->left < c->left + c->width)
+                               memcpy(vbuf + left,
+                                       tpg->contrast_line[p], twopixsize);
+                       if (b->left + b->width > c->left &&
+                           b->left + b->width <= c->left + c->width)
+                               memcpy(vbuf + right - twopixsize,
+                                       tpg->contrast_line[p], twopixsize);
+               }
+       }
+       if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
+           frame_line < b->top + b->height) {
+               memcpy(vbuf, tpg->black_line[p], params->left_pillar_width);
+               memcpy(vbuf + params->right_pillar_start, tpg->black_line[p],
+                      img_width - params->right_pillar_start);
+       }
+       if (tpg->show_square && frame_line >= sq->top &&
+           frame_line < sq->top + sq->height &&
+           sq->left < c->left + c->width &&
+           sq->left + sq->width >= c->left) {
+               unsigned left = sq->left;
+               unsigned width = sq->width;
+
+               if (c->left > left) {
+                       width -= c->left - left;
+                       left = c->left;
+               }
+               if (c->left + c->width < left + width)
+                       width -= left + width - c->left - c->width;
+               left -= c->left;
+               left = tpg_hscale_div(tpg, p, left);
+               width = tpg_hscale_div(tpg, p, width);
+               memcpy(vbuf + left, tpg->contrast_line[p], width);
+       }
+       if (tpg->insert_sav) {
+               unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3);
+               u8 *p = vbuf + offset;
+               unsigned vact = 0, hact = 0;
+
+               p[0] = 0xff;
+               p[1] = 0;
+               p[2] = 0;
+               p[3] = 0x80 | (params->sav_eav_f << 6) |
+                       (vact << 5) | (hact << 4) |
+                       ((hact ^ vact) << 3) |
+                       ((hact ^ params->sav_eav_f) << 2) |
+                       ((params->sav_eav_f ^ vact) << 1) |
+                       (hact ^ vact ^ params->sav_eav_f);
+       }
+       if (tpg->insert_eav) {
+               unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3);
+               u8 *p = vbuf + offset;
+               unsigned vact = 0, hact = 1;
+
+               p[0] = 0xff;
+               p[1] = 0;
+               p[2] = 0;
+               p[3] = 0x80 | (params->sav_eav_f << 6) |
+                       (vact << 5) | (hact << 4) |
+                       ((hact ^ vact) << 3) |
+                       ((hact ^ params->sav_eav_f) << 2) |
+                       ((params->sav_eav_f ^ vact) << 1) |
+                       (hact ^ vact ^ params->sav_eav_f);
+       }
+}
+
+static void tpg_fill_plane_pattern(const struct tpg_data *tpg,
+                                  const struct tpg_draw_params *params,
+                                  unsigned p, unsigned h, u8 *vbuf)
+{
+       unsigned twopixsize = params->twopixsize;
+       unsigned img_width = params->img_width;
+       unsigned mv_hor_old = params->mv_hor_old;
+       unsigned mv_hor_new = params->mv_hor_new;
+       unsigned mv_vert_old = params->mv_vert_old;
+       unsigned mv_vert_new = params->mv_vert_new;
+       unsigned frame_line = params->frame_line;
+       unsigned frame_line_next = params->frame_line_next;
+       unsigned line_offset = tpg_hscale_div(tpg, p, tpg->crop.left);
+       bool even;
+       bool fill_blank = false;
+       unsigned pat_line_old;
+       unsigned pat_line_new;
+       u8 *linestart_older;
+       u8 *linestart_newer;
+       u8 *linestart_top;
+       u8 *linestart_bottom;
+
+       even = !(frame_line & 1);
+
+       if (h >= params->hmax) {
+               if (params->hmax == tpg->compose.height)
+                       return;
+               if (!tpg->perc_fill_blank)
+                       return;
+               fill_blank = true;
+       }
+
+       if (tpg->vflip) {
+               frame_line = tpg->src_height - frame_line - 1;
+               frame_line_next = tpg->src_height - frame_line_next - 1;
+       }
+
+       if (fill_blank) {
+               linestart_older = tpg->contrast_line[p];
+               linestart_newer = tpg->contrast_line[p];
+       } else if (tpg->qual != TPG_QUAL_NOISE &&
+                  (frame_line < tpg->border.top ||
+                   frame_line >= tpg->border.top + tpg->border.height)) {
+               linestart_older = tpg->black_line[p];
+               linestart_newer = tpg->black_line[p];
+       } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
+               linestart_older = tpg->random_line[p] +
+                                 twopixsize * prandom_u32_max(tpg->src_width / 2);
+               linestart_newer = tpg->random_line[p] +
+                                 twopixsize * prandom_u32_max(tpg->src_width / 2);
+       } else {
+               unsigned frame_line_old =
+                       (frame_line + mv_vert_old) % tpg->src_height;
+               unsigned frame_line_new =
+                       (frame_line + mv_vert_new) % tpg->src_height;
+               unsigned pat_line_next_old;
+               unsigned pat_line_next_new;
+
+               pat_line_old = tpg_get_pat_line(tpg, frame_line_old);
+               pat_line_new = tpg_get_pat_line(tpg, frame_line_new);
+               linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old;
+               linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new;
+
+               if (tpg->vdownsampling[p] > 1 && frame_line != frame_line_next) {
+                       int avg_pat;
+
+                       /*
+                        * Now decide whether we need to use downsampled_lines[].
+                        * That's necessary if the two lines use different patterns.
+                        */
+                       pat_line_next_old = tpg_get_pat_line(tpg,
+                                       (frame_line_next + mv_vert_old) % tpg->src_height);
+                       pat_line_next_new = tpg_get_pat_line(tpg,
+                                       (frame_line_next + mv_vert_new) % tpg->src_height);
+
+                       switch (tpg->field) {
+                       case V4L2_FIELD_INTERLACED:
+                       case V4L2_FIELD_INTERLACED_BT:
+                       case V4L2_FIELD_INTERLACED_TB:
+                               avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new);
+                               if (avg_pat < 0)
+                                       break;
+                               linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old;
+                               linestart_newer = linestart_older;
+                               break;
+                       case V4L2_FIELD_NONE:
+                       case V4L2_FIELD_TOP:
+                       case V4L2_FIELD_BOTTOM:
+                       case V4L2_FIELD_SEQ_BT:
+                       case V4L2_FIELD_SEQ_TB:
+                               avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old);
+                               if (avg_pat >= 0)
+                                       linestart_older = tpg->downsampled_lines[avg_pat][p] +
+                                               mv_hor_old;
+                               avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new);
+                               if (avg_pat >= 0)
+                                       linestart_newer = tpg->downsampled_lines[avg_pat][p] +
+                                               mv_hor_new;
+                               break;
+                       }
+               }
+               linestart_older += line_offset;
+               linestart_newer += line_offset;
+       }
+       if (tpg->field_alternate) {
+               linestart_top = linestart_bottom = linestart_older;
+       } else if (params->is_60hz) {
+               linestart_top = linestart_newer;
+               linestart_bottom = linestart_older;
+       } else {
+               linestart_top = linestart_older;
+               linestart_bottom = linestart_newer;
+       }
+
+       switch (tpg->field) {
+       case V4L2_FIELD_INTERLACED:
+       case V4L2_FIELD_INTERLACED_TB:
+       case V4L2_FIELD_SEQ_TB:
+       case V4L2_FIELD_SEQ_BT:
+               if (even)
+                       memcpy(vbuf, linestart_top, img_width);
+               else
+                       memcpy(vbuf, linestart_bottom, img_width);
+               break;
+       case V4L2_FIELD_INTERLACED_BT:
+               if (even)
+                       memcpy(vbuf, linestart_bottom, img_width);
+               else
+                       memcpy(vbuf, linestart_top, img_width);
+               break;
+       case V4L2_FIELD_TOP:
+               memcpy(vbuf, linestart_top, img_width);
+               break;
+       case V4L2_FIELD_BOTTOM:
+               memcpy(vbuf, linestart_bottom, img_width);
+               break;
+       case V4L2_FIELD_NONE:
+       default:
+               memcpy(vbuf, linestart_older, img_width);
+               break;
+       }
+}
+
+void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,
+                          unsigned p, u8 *vbuf)
+{
+       struct tpg_draw_params params;
+       unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
+
+       /* Coarse scaling with Bresenham */
+       unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
+       unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
+       unsigned src_y = 0;
+       unsigned error = 0;
+       unsigned h;
+
+       tpg_recalc(tpg);
+
+       params.is_tv = std;
+       params.is_60hz = std & V4L2_STD_525_60;
+       params.twopixsize = tpg->twopixelsize[p];
+       params.img_width = tpg_hdiv(tpg, p, tpg->compose.width);
+       params.stride = tpg->bytesperline[p];
+       params.hmax = (tpg->compose.height * tpg->perc_fill) / 100;
+
+       tpg_fill_params_pattern(tpg, p, &params);
+       tpg_fill_params_extras(tpg, p, &params);
+
+       vbuf += tpg_hdiv(tpg, p, tpg->compose.left);
+
+       for (h = 0; h < tpg->compose.height; h++) {
+               unsigned buf_line;
+
+               params.frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
+               params.frame_line_next = params.frame_line;
+               buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
+               src_y += int_part;
+               error += fract_part;
+               if (error >= tpg->compose.height) {
+                       error -= tpg->compose.height;
+                       src_y++;
+               }
+
+               /*
+                * For line-interleaved formats determine the 'plane'
+                * based on the buffer line.
+                */
+               if (tpg_g_interleaved(tpg))
+                       p = tpg_g_interleaved_plane(tpg, buf_line);
+
+               if (tpg->vdownsampling[p] > 1) {
+                       /*
+                        * When doing vertical downsampling the field setting
+                        * matters: for SEQ_BT/TB we downsample each field
+                        * separately (i.e. lines 0+2 are combined, as are
+                        * lines 1+3), for the other field settings we combine
+                        * odd and even lines. Doing that for SEQ_BT/TB would
+                        * be really weird.
+                        */
+                       if (tpg->field == V4L2_FIELD_SEQ_BT ||
+                           tpg->field == V4L2_FIELD_SEQ_TB) {
+                               unsigned next_src_y = src_y;
+
+                               if ((h & 3) >= 2)
+                                       continue;
+                               next_src_y += int_part;
+                               if (error + fract_part >= tpg->compose.height)
+                                       next_src_y++;
+                               params.frame_line_next =
+                                       tpg_calc_frameline(tpg, next_src_y, tpg->field);
+                       } else {
+                               if (h & 1)
+                                       continue;
+                               params.frame_line_next =
+                                       tpg_calc_frameline(tpg, src_y, tpg->field);
+                       }
+
+                       buf_line /= tpg->vdownsampling[p];
+               }
+               tpg_fill_plane_pattern(tpg, &params, p, h,
+                               vbuf + buf_line * params.stride);
+               tpg_fill_plane_extras(tpg, &params, p, h,
+                               vbuf + buf_line * params.stride);
+       }
+}
+EXPORT_SYMBOL_GPL(tpg_fill_plane_buffer);
+
+void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
+{
+       unsigned offset = 0;
+       unsigned i;
+
+       if (tpg->buffers > 1) {
+               tpg_fill_plane_buffer(tpg, std, p, vbuf);
+               return;
+       }
+
+       for (i = 0; i < tpg_g_planes(tpg); i++) {
+               tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);
+               offset += tpg_calc_plane_size(tpg, i);
+       }
+}
+EXPORT_SYMBOL_GPL(tpg_fillbuffer);
+
+MODULE_DESCRIPTION("V4L2 Test Pattern Generator");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL");
index 0afad39..a7a4674 100644 (file)
 #define USB_VID_TELESTAR                       0x10b9
 #define USB_VID_VISIONPLUS                     0x13d3
 #define USB_VID_SONY                           0x1415
+#define USB_PID_TEVII_S421                     0xd421
+#define USB_PID_TEVII_S480_1                   0xd481
+#define USB_PID_TEVII_S480_2                   0xd482
+#define USB_PID_TEVII_S630                     0xd630
+#define USB_PID_TEVII_S632                     0xd632
+#define USB_PID_TEVII_S650                     0xd650
+#define USB_PID_TEVII_S660                     0xd660
+#define USB_PID_TEVII_S662                     0xd662
 #define USB_VID_TWINHAN                                0x1822
 #define USB_VID_ULTIMA_ELECTRONIC              0x05d8
 #define USB_VID_UNIWILL                                0x1584
 #define USB_PID_GENIUS_TVGO_DVB_T03                    0x4012
 #define USB_PID_GRANDTEC_DVBT_USB_COLD                 0x0fa0
 #define USB_PID_GRANDTEC_DVBT_USB_WARM                 0x0fa1
+#define USB_PID_GOTVIEW_SAT_HD                         0x5456
 #define USB_PID_INTEL_CE9500                           0x9500
 #define USB_PID_ITETECH_IT9135                         0x9135
 #define USB_PID_ITETECH_IT9135_9005                    0x9005
 #define USB_PID_KWORLD_UB499_2T_T09                    0xe409
 #define USB_PID_KWORLD_VSTREAM_COLD                    0x17de
 #define USB_PID_KWORLD_VSTREAM_WARM                    0x17df
+#define USB_PID_PROF_1100                              0xb012
+#define USB_PID_TERRATEC_CINERGY_S                     0x0064
 #define USB_PID_TERRATEC_CINERGY_T_USB_XE              0x0055
 #define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2         0x0069
 #define USB_PID_TERRATEC_CINERGY_T_STICK               0x0093
 #define USB_PID_YUAN_STK7700D                          0x1efc
 #define USB_PID_YUAN_STK7700D_2                                0x1e8c
 #define USB_PID_DW2102                                 0x2102
+#define USB_PID_DW2104                                 0x2104
+#define USB_PID_DW3101                                 0x3101
 #define USB_PID_XTENSIONS_XD_380                       0x0381
 #define USB_PID_TELESTAR_STARSTICK_2                   0x8000
 #define USB_PID_MSI_DIGI_VOX_MINI_III                   0x8807
 #define USB_PID_ELGATO_EYETV_DTT_Dlx                   0x0020
 #define USB_PID_ELGATO_EYETV_SAT                       0x002a
 #define USB_PID_ELGATO_EYETV_SAT_V2                    0x0025
+#define USB_PID_ELGATO_EYETV_SAT_V3                    0x0036
 #define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD                0x5000
 #define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM                0x5001
 #define USB_PID_FRIIO_WHITE                            0x0001
index e1684c5..75a3f4b 100644 (file)
@@ -676,13 +676,13 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
                                             demux, 0, MEDIA_LNK_FL_ENABLED,
                                             false);
                if (ret)
-                       return -ENOMEM;
+                       return ret;
        }
        if (demux && ca) {
                ret = media_create_pad_link(demux, 1, ca,
                                            0, MEDIA_LNK_FL_ENABLED);
                if (ret)
-                       return -ENOMEM;
+                       return ret;
        }
 
        /* Create demux links for each ringbuffer/pad */
index dc2d41e..d879dc0 100644 (file)
@@ -1121,7 +1121,7 @@ void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
                                (state->current_band == BAND_CBAND) ? "CBAND" : "NOT CBAND",
                                state->identity.version & 0x1f);
 
-               if (rf_ramp && ((state->rf_ramp[0] == 0) ||
+               if (rf_ramp && ((state->rf_ramp && state->rf_ramp[0] == 0) ||
                    (state->current_band == BAND_CBAND &&
                    (state->identity.version & 0x1f) <= P1D_E_F))) {
                        dprintk("DE-Engage mux for direct gain reg control");
index e8fc032..addffc3 100644 (file)
@@ -458,7 +458,7 @@ static int ds3000_read_status(struct dvb_frontend *fe, enum fe_status *status)
 
                break;
        default:
-               return 1;
+               return -EINVAL;
        }
 
        if (state->config->set_lock_led)
@@ -528,7 +528,7 @@ static int ds3000_read_ber(struct dvb_frontend *fe, u32* ber)
                        *ber = 0xffffffff;
                break;
        default:
-               return 1;
+               return -EINVAL;
        }
 
        return 0;
@@ -623,7 +623,7 @@ static int ds3000_read_snr(struct dvb_frontend *fe, u16 *snr)
                                snr_reading, *snr);
                break;
        default:
-               return 1;
+               return -EINVAL;
        }
 
        return 0;
@@ -661,7 +661,7 @@ static int ds3000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
                state->prevUCBS2 = _ucblocks;
                break;
        default:
-               return 1;
+               return -EINVAL;
        }
 
        return 0;
@@ -754,7 +754,7 @@ static int ds3000_send_diseqc_msg(struct dvb_frontend *fe,
                data |= 0x80;
                ds3000_writereg(state, 0xa2, data);
 
-               return 1;
+               return -ETIMEDOUT;
        }
 
        data = ds3000_readreg(state, 0xa2);
@@ -808,7 +808,7 @@ static int ds3000_diseqc_send_burst(struct dvb_frontend *fe,
                data |= 0x80;
                ds3000_writereg(state, 0xa2, data);
 
-               return 1;
+               return -ETIMEDOUT;
        }
 
        data = ds3000_readreg(state, 0xa2);
@@ -951,7 +951,7 @@ static int ds3000_set_frontend(struct dvb_frontend *fe)
                        ds3000_writereg(state, 0xfe, 0x98);
                break;
        default:
-               return 1;
+               return -EINVAL;
        }
 
        /* enable 27MHz clock output */
index eee8c22..651e005 100644 (file)
@@ -46,7 +46,7 @@ struct m88ds3103_dev {
        /* auto detect chip id to do different config */
        u8 chip_id;
        /* main mclk is calculated for M88RS6000 dynamically */
-       u32 mclk_khz;
+       s32 mclk_khz;
        u64 post_bit_error;
        u64 post_bit_count;
 };
index 1832c2f..3b08176 100644 (file)
@@ -135,8 +135,7 @@ static void zl10353_calc_nominal_rate(struct dvb_frontend *fe,
 
        value = (u64)10 * (1 << 23) / 7 * 125;
        value = (bw * value) + adc_clock / 2;
-       do_div(value, adc_clock);
-       *nominal_rate = value;
+       *nominal_rate = div_u64(value, adc_clock);
 
        dprintk("%s: bw %d, adc_clock %d => 0x%x\n",
                __func__, bw, adc_clock, *nominal_rate);
@@ -163,8 +162,7 @@ static void zl10353_calc_input_freq(struct dvb_frontend *fe,
                if (ife > adc_clock / 2)
                        ife = adc_clock - ife;
        }
-       value = (u64)65536 * ife + adc_clock / 2;
-       do_div(value, adc_clock);
+       value = div_u64((u64)65536 * ife + adc_clock / 2, adc_clock);
        *input_freq = -value;
 
        dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n",
index 788967d..0462f46 100644 (file)
@@ -1130,8 +1130,6 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id *
        hdl = &state->hdl;
        v4l2_ctrl_handler_init(hdl, 5);
 
-       /* private controls */
-
        state->hdmi_mode_ctrl = v4l2_ctrl_new_std_menu(hdl, &ad9389b_ctrl_ops,
                        V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI,
                        0, V4L2_DV_TX_MODE_DVI_D);
@@ -1151,12 +1149,6 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id *
 
                goto err_hdl;
        }
-       state->hdmi_mode_ctrl->is_private = true;
-       state->hotplug_ctrl->is_private = true;
-       state->rx_sense_ctrl->is_private = true;
-       state->have_edid0_ctrl->is_private = true;
-       state->rgb_quantization_range_ctrl->is_private = true;
-
        state->pad.flags = MEDIA_PAD_FL_SINK;
        err = media_entity_pads_init(&sd->entity, 1, &state->pad);
        if (err)
index fb7ed73..9e1731c 100644 (file)
@@ -466,9 +466,9 @@ static int adp1653_of_init(struct i2c_client *client,
        of_node_put(child);
 
        pd->enable_gpio = devm_gpiod_get(&client->dev, "enable", GPIOD_OUT_LOW);
-       if (!pd->enable_gpio) {
+       if (IS_ERR(pd->enable_gpio)) {
                dev_err(&client->dev, "Error getting GPIO\n");
-               return -EINVAL;
+               return PTR_ERR(pd->enable_gpio);
        }
 
        return 0;
index ff57c1d..b77b0a4 100644 (file)
@@ -26,8 +26,9 @@
 #include <linux/i2c.h>
 #include <linux/slab.h>
 #include <linux/of.h>
-#include <media/v4l2-ioctl.h>
 #include <linux/videodev2.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
 #include <linux/mutex.h>
@@ -192,8 +193,8 @@ struct adv7180_state {
        struct mutex            mutex; /* mutual excl. when accessing chip */
        int                     irq;
        v4l2_std_id             curr_norm;
-       bool                    autodetect;
        bool                    powered;
+       bool                    streaming;
        u8                      input;
 
        struct i2c_client       *client;
@@ -338,12 +339,26 @@ static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
        if (err)
                return err;
 
-       /* when we are interrupt driven we know the state */
-       if (!state->autodetect || state->irq > 0)
-               *std = state->curr_norm;
-       else
-               err = __adv7180_status(state, NULL, std);
+       if (state->streaming) {
+               err = -EBUSY;
+               goto unlock;
+       }
+
+       err = adv7180_set_video_standard(state,
+                       ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM);
+       if (err)
+               goto unlock;
+
+       msleep(100);
+       __adv7180_status(state, NULL, std);
+
+       err = v4l2_std_to_adv7180(state->curr_norm);
+       if (err < 0)
+               goto unlock;
 
+       err = adv7180_set_video_standard(state, err);
+
+unlock:
        mutex_unlock(&state->mutex);
        return err;
 }
@@ -387,23 +402,13 @@ static int adv7180_program_std(struct adv7180_state *state)
 {
        int ret;
 
-       if (state->autodetect) {
-               ret = adv7180_set_video_standard(state,
-                       ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM);
-               if (ret < 0)
-                       return ret;
-
-               __adv7180_status(state, NULL, &state->curr_norm);
-       } else {
-               ret = v4l2_std_to_adv7180(state->curr_norm);
-               if (ret < 0)
-                       return ret;
-
-               ret = adv7180_set_video_standard(state, ret);
-               if (ret < 0)
-                       return ret;
-       }
+       ret = v4l2_std_to_adv7180(state->curr_norm);
+       if (ret < 0)
+               return ret;
 
+       ret = adv7180_set_video_standard(state, ret);
+       if (ret < 0)
+               return ret;
        return 0;
 }
 
@@ -415,18 +420,12 @@ static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
        if (ret)
                return ret;
 
-       /* all standards -> autodetect */
-       if (std == V4L2_STD_ALL) {
-               state->autodetect = true;
-       } else {
-               /* Make sure we can support this std */
-               ret = v4l2_std_to_adv7180(std);
-               if (ret < 0)
-                       goto out;
+       /* Make sure we can support this std */
+       ret = v4l2_std_to_adv7180(std);
+       if (ret < 0)
+               goto out;
 
-               state->curr_norm = std;
-               state->autodetect = false;
-       }
+       state->curr_norm = std;
 
        ret = adv7180_program_std(state);
 out:
@@ -434,6 +433,15 @@ out:
        return ret;
 }
 
+static int adv7180_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm)
+{
+       struct adv7180_state *state = to_state(sd);
+
+       *norm = state->curr_norm;
+
+       return 0;
+}
+
 static int adv7180_set_power(struct adv7180_state *state, bool on)
 {
        u8 val;
@@ -717,17 +725,77 @@ static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
        return 0;
 }
 
+static int adv7180_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *cropcap)
+{
+       struct adv7180_state *state = to_state(sd);
+
+       if (state->curr_norm & V4L2_STD_525_60) {
+               cropcap->pixelaspect.numerator = 11;
+               cropcap->pixelaspect.denominator = 10;
+       } else {
+               cropcap->pixelaspect.numerator = 54;
+               cropcap->pixelaspect.denominator = 59;
+       }
+
+       return 0;
+}
+
+static int adv7180_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm)
+{
+       *norm = V4L2_STD_ALL;
+       return 0;
+}
+
+static int adv7180_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct adv7180_state *state = to_state(sd);
+       int ret;
+
+       /* It's always safe to stop streaming, no need to take the lock */
+       if (!enable) {
+               state->streaming = enable;
+               return 0;
+       }
+
+       /* Must wait until querystd released the lock */
+       ret = mutex_lock_interruptible(&state->mutex);
+       if (ret)
+               return ret;
+       state->streaming = enable;
+       mutex_unlock(&state->mutex);
+       return 0;
+}
+
+static int adv7180_subscribe_event(struct v4l2_subdev *sd,
+                                  struct v4l2_fh *fh,
+                                  struct v4l2_event_subscription *sub)
+{
+       switch (sub->type) {
+       case V4L2_EVENT_SOURCE_CHANGE:
+               return v4l2_src_change_event_subdev_subscribe(sd, fh, sub);
+       case V4L2_EVENT_CTRL:
+               return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub);
+       default:
+               return -EINVAL;
+       }
+}
+
 static const struct v4l2_subdev_video_ops adv7180_video_ops = {
        .s_std = adv7180_s_std,
+       .g_std = adv7180_g_std,
        .querystd = adv7180_querystd,
        .g_input_status = adv7180_g_input_status,
        .s_routing = adv7180_s_routing,
        .g_mbus_config = adv7180_g_mbus_config,
+       .cropcap = adv7180_cropcap,
+       .g_tvnorms = adv7180_g_tvnorms,
+       .s_stream = adv7180_s_stream,
 };
 
-
 static const struct v4l2_subdev_core_ops adv7180_core_ops = {
        .s_power = adv7180_s_power,
+       .subscribe_event = adv7180_subscribe_event,
+       .unsubscribe_event = v4l2_event_subdev_unsubscribe,
 };
 
 static const struct v4l2_subdev_pad_ops adv7180_pad_ops = {
@@ -752,8 +820,14 @@ static irqreturn_t adv7180_irq(int irq, void *devid)
        /* clear */
        adv7180_write(state, ADV7180_REG_ICR3, isr3);
 
-       if (isr3 & ADV7180_IRQ3_AD_CHANGE && state->autodetect)
-               __adv7180_status(state, NULL, &state->curr_norm);
+       if (isr3 & ADV7180_IRQ3_AD_CHANGE) {
+               static const struct v4l2_event src_ch = {
+                       .type = V4L2_EVENT_SOURCE_CHANGE,
+                       .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
+               };
+
+               v4l2_subdev_notify_event(&state->sd, &src_ch);
+       }
        mutex_unlock(&state->mutex);
 
        return IRQ_HANDLED;
@@ -1198,7 +1272,7 @@ static int adv7180_probe(struct i2c_client *client,
 
        state->irq = client->irq;
        mutex_init(&state->mutex);
-       state->autodetect = true;
+       state->curr_norm = V4L2_STD_NTSC;
        if (state->chip_info->flags & ADV7180_FLAG_RESET_POWERED)
                state->powered = true;
        else
@@ -1206,7 +1280,7 @@ static int adv7180_probe(struct i2c_client *client,
        state->input = 0;
        sd = &state->sd;
        v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
-       sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+       sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
 
        ret = adv7180_init_controls(state);
        if (ret)
@@ -1328,6 +1402,14 @@ static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume);
 #ifdef CONFIG_OF
 static const struct of_device_id adv7180_of_id[] = {
        { .compatible = "adi,adv7180", },
+       { .compatible = "adi,adv7182", },
+       { .compatible = "adi,adv7280", },
+       { .compatible = "adi,adv7280-m", },
+       { .compatible = "adi,adv7281", },
+       { .compatible = "adi,adv7281-m", },
+       { .compatible = "adi,adv7281-ma", },
+       { .compatible = "adi,adv7282", },
+       { .compatible = "adi,adv7282-m", },
        { },
 };
 
index bd822f0..39271c3 100644 (file)
@@ -1502,12 +1502,6 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *
                err = hdl->error;
                goto err_hdl;
        }
-       state->hdmi_mode_ctrl->is_private = true;
-       state->hotplug_ctrl->is_private = true;
-       state->rx_sense_ctrl->is_private = true;
-       state->have_edid0_ctrl->is_private = true;
-       state->rgb_quantization_range_ctrl->is_private = true;
-
        state->pad.flags = MEDIA_PAD_FL_SINK;
        err = media_entity_pads_init(&sd->entity, 1, &state->pad);
        if (err)
index 41a1bfc..beb2841 100644 (file)
@@ -3141,7 +3141,6 @@ static int adv76xx_probe(struct i2c_client *client,
        if (ctrl)
                ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
 
-       /* private controls */
        state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL,
                        V4L2_CID_DV_RX_POWER_PRESENT, 0,
                        (1 << state->info->num_dv_ports) - 1, 0, 0);
@@ -3164,13 +3163,6 @@ static int adv76xx_probe(struct i2c_client *client,
                err = hdl->error;
                goto err_hdl;
        }
-       state->detect_tx_5v_ctrl->is_private = true;
-       state->rgb_quantization_range_ctrl->is_private = true;
-       if (adv76xx_has_afe(state))
-               state->analog_sampling_phase_ctrl->is_private = true;
-       state->free_run_color_manual_ctrl->is_private = true;
-       state->free_run_color_ctrl->is_private = true;
-
        if (adv76xx_s_detect_tx_5v_ctrl(sd)) {
                err = -ENODEV;
                goto err_hdl;
index 7ccb85d..ecaacb0 100644 (file)
@@ -3300,12 +3300,6 @@ static int adv7842_probe(struct i2c_client *client,
                err = hdl->error;
                goto err_hdl;
        }
-       state->detect_tx_5v_ctrl->is_private = true;
-       state->rgb_quantization_range_ctrl->is_private = true;
-       state->analog_sampling_phase_ctrl->is_private = true;
-       state->free_run_color_ctrl_manual->is_private = true;
-       state->free_run_color_ctrl->is_private = true;
-
        if (adv7842_s_detect_tx_5v_ctrl(sd)) {
                err = -ENODEV;
                goto err_hdl;
index a60931e..c2218c0 100644 (file)
@@ -405,7 +405,7 @@ static int m5mols_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
        struct v4l2_subdev *sd = to_sd(ctrl);
        struct m5mols_info *info = to_m5mols(sd);
        int ret = 0;
-       u8 status;
+       u8 status = REG_ISO_AUTO;
 
        v4l2_dbg(1, m5mols_debug, sd, "%s: ctrl: %s (%d)\n",
                 __func__, ctrl->name, info->isp_ready);
index d2a1ce2..bd3526b 100644 (file)
@@ -1798,6 +1798,21 @@ static int saa711x_detect_chip(struct i2c_client *client,
                return GM7113C;
        }
 
+       /* Check if it is a CJC7113 */
+       if (!memcmp(name, "1111111111111111", CHIP_VER_SIZE)) {
+               strlcpy(name, "cjc7113", CHIP_VER_SIZE);
+
+               if (!autodetect && strcmp(name, id->name))
+                       return -EINVAL;
+
+               v4l_dbg(1, debug, client,
+                       "It seems to be a %s chip (%*ph) @ 0x%x.\n",
+                       name, 16, chip_ver, client->addr << 1);
+
+               /* CJC7113 seems to be SAA7113-compatible */
+               return SAA7113;
+       }
+
        /* Chip was not discovered. Return its ID and don't bind */
        v4l_dbg(1, debug, client, "chip %*ph @ 0x%x is unknown.\n",
                16, chip_ver, client->addr << 1);
index a215efe..3dfe387 100644 (file)
@@ -188,6 +188,8 @@ static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor)
                embedded_end = 0;
        }
 
+       sensor->image_start = image_start;
+
        dev_dbg(&client->dev, "embedded data from lines %d to %d\n",
                embedded_start, embedded_end);
        dev_dbg(&client->dev, "image data starts at line %d\n", image_start);
@@ -2280,6 +2282,15 @@ static int smiapp_get_skip_frames(struct v4l2_subdev *subdev, u32 *frames)
        return 0;
 }
 
+static int smiapp_get_skip_top_lines(struct v4l2_subdev *subdev, u32 *lines)
+{
+       struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+
+       *lines = sensor->image_start;
+
+       return 0;
+}
+
 /* -----------------------------------------------------------------------------
  * sysfs attributes
  */
@@ -2890,6 +2901,7 @@ static const struct v4l2_subdev_pad_ops smiapp_pad_ops = {
 
 static const struct v4l2_subdev_sensor_ops smiapp_sensor_ops = {
        .g_skip_frames = smiapp_get_skip_frames,
+       .g_skip_top_lines = smiapp_get_skip_top_lines,
 };
 
 static const struct v4l2_subdev_ops smiapp_ops = {
index f6af0cc..2174f89 100644 (file)
@@ -217,6 +217,7 @@ struct smiapp_sensor {
 
        u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */
        u8 frame_skip;
+       u16 image_start;        /* Offset to first line after metadata lines */
 
        int power_count;
 
index 972e0d4..6cf6d06 100644 (file)
@@ -1551,6 +1551,8 @@ static int tc358743_g_edid(struct v4l2_subdev *sd,
 {
        struct tc358743_state *state = to_state(sd);
 
+       memset(edid->reserved, 0, sizeof(edid->reserved));
+
        if (edid->pad != 0)
                return -EINVAL;
 
@@ -1585,6 +1587,8 @@ static int tc358743_s_edid(struct v4l2_subdev *sd,
        v4l2_dbg(2, debug, sd, "%s, pad %d, start block %d, blocks %d\n",
                 __func__, edid->pad, edid->start_block, edid->blocks);
 
+       memset(edid->reserved, 0, sizeof(edid->reserved));
+
        if (edid->pad != 0)
                return -EINVAL;
 
@@ -1859,7 +1863,6 @@ static int tc358743_probe(struct i2c_client *client,
        /* control handlers */
        v4l2_ctrl_handler_init(&state->hdl, 3);
 
-       /* private controls */
        state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(&state->hdl, NULL,
                        V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0);
 
index 5bbfcab..71a3135 100644 (file)
@@ -285,7 +285,7 @@ static int ths7303_log_status(struct v4l2_subdev *sd)
        v4l2_info(sd, "stream %s\n", state->stream_on ? "On" : "Off");
 
        if (state->bt.pixelclock) {
-               struct v4l2_bt_timings *bt = bt = &state->bt;
+               struct v4l2_bt_timings *bt = &state->bt;
                u32 frame_width, frame_height;
 
                frame_width = V4L2_DV_BT_FRAME_WIDTH(bt);
index ff18444..0b6d46c 100644 (file)
@@ -83,7 +83,7 @@ static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr)
        return rc;
 }
 
-static inline void tvp5150_write(struct v4l2_subdev *sd, unsigned char addr,
+static int tvp5150_write(struct v4l2_subdev *sd, unsigned char addr,
                                 unsigned char value)
 {
        struct i2c_client *c = v4l2_get_subdevdata(sd);
@@ -92,7 +92,9 @@ static inline void tvp5150_write(struct v4l2_subdev *sd, unsigned char addr,
        v4l2_dbg(2, debug, sd, "tvp5150: writing 0x%02x 0x%02x\n", addr, value);
        rc = i2c_smbus_write_byte_data(c, addr, value);
        if (rc < 0)
-               v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d\n", rc);
+               v4l2_err(sd, "i2c i/o error: rc == %d\n", rc);
+
+       return rc;
 }
 
 static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init,
@@ -1159,8 +1161,7 @@ static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
 
 static int tvp5150_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
 {
-       tvp5150_write(sd, reg->reg & 0xff, reg->val & 0xff);
-       return 0;
+       return tvp5150_write(sd, reg->reg & 0xff, reg->val & 0xff);
 }
 #endif
 
index 3cfd7af..a1cd50f 100644 (file)
@@ -90,18 +90,13 @@ static struct media_entity *find_entity(struct media_device *mdev, u32 id)
 
        id &= ~MEDIA_ENT_ID_FLAG_NEXT;
 
-       spin_lock(&mdev->lock);
-
        media_device_for_each_entity(entity, mdev) {
                if (((media_entity_id(entity) == id) && !next) ||
                    ((media_entity_id(entity) > id) && next)) {
-                       spin_unlock(&mdev->lock);
                        return entity;
                }
        }
 
-       spin_unlock(&mdev->lock);
-
        return NULL;
 }
 
@@ -431,6 +426,7 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
        struct media_device *dev = to_media_device(devnode);
        long ret;
 
+       mutex_lock(&dev->graph_mutex);
        switch (cmd) {
        case MEDIA_IOC_DEVICE_INFO:
                ret = media_device_get_info(dev,
@@ -443,29 +439,24 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
                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;
 
        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;
 
        case MEDIA_IOC_G_TOPOLOGY:
-               mutex_lock(&dev->graph_mutex);
                ret = media_device_get_topology(dev,
                                (struct media_v2_topology __user *)arg);
-               mutex_unlock(&dev->graph_mutex);
                break;
 
        default:
                ret = -ENOIOCTLCMD;
        }
+       mutex_unlock(&dev->graph_mutex);
 
        return ret;
 }
@@ -508,12 +499,6 @@ static long media_device_compat_ioctl(struct file *filp, unsigned int cmd,
        long ret;
 
        switch (cmd) {
-       case MEDIA_IOC_DEVICE_INFO:
-       case MEDIA_IOC_ENUM_ENTITIES:
-       case MEDIA_IOC_SETUP_LINK:
-       case MEDIA_IOC_G_TOPOLOGY:
-               return media_device_ioctl(filp, cmd, arg);
-
        case MEDIA_IOC_ENUM_LINKS32:
                mutex_lock(&dev->graph_mutex);
                ret = media_device_enum_links32(dev,
@@ -522,7 +507,7 @@ static long media_device_compat_ioctl(struct file *filp, unsigned int cmd,
                break;
 
        default:
-               ret = -ENOIOCTLCMD;
+               return media_device_ioctl(filp, cmd, arg);
        }
 
        return ret;
@@ -590,12 +575,12 @@ int __must_check media_device_register_entity(struct media_device *mdev,
        if (!ida_pre_get(&mdev->entity_internal_idx, GFP_KERNEL))
                return -ENOMEM;
 
-       spin_lock(&mdev->lock);
+       mutex_lock(&mdev->graph_mutex);
 
        ret = ida_get_new_above(&mdev->entity_internal_idx, 1,
                                &entity->internal_idx);
        if (ret < 0) {
-               spin_unlock(&mdev->lock);
+               mutex_unlock(&mdev->graph_mutex);
                return ret;
        }
 
@@ -615,9 +600,6 @@ int __must_check media_device_register_entity(struct media_device *mdev,
                (notify)->notify(entity, notify->notify_data);
        }
 
-       spin_unlock(&mdev->lock);
-
-       mutex_lock(&mdev->graph_mutex);
        if (mdev->entity_internal_idx_max
            >= mdev->pm_count_walk.ent_enum.idx_max) {
                struct media_entity_graph new = { .top = 0 };
@@ -680,9 +662,9 @@ void media_device_unregister_entity(struct media_entity *entity)
        if (mdev == NULL)
                return;
 
-       spin_lock(&mdev->lock);
+       mutex_lock(&mdev->graph_mutex);
        __media_device_unregister_entity(entity);
-       spin_unlock(&mdev->lock);
+       mutex_unlock(&mdev->graph_mutex);
 }
 EXPORT_SYMBOL_GPL(media_device_unregister_entity);
 
@@ -703,7 +685,6 @@ void media_device_init(struct media_device *mdev)
        INIT_LIST_HEAD(&mdev->pads);
        INIT_LIST_HEAD(&mdev->links);
        INIT_LIST_HEAD(&mdev->entity_notify);
-       spin_lock_init(&mdev->lock);
        mutex_init(&mdev->graph_mutex);
        ida_init(&mdev->entity_internal_idx);
 
@@ -752,9 +733,9 @@ EXPORT_SYMBOL_GPL(__media_device_register);
 int __must_check media_device_register_entity_notify(struct media_device *mdev,
                                        struct media_entity_notify *nptr)
 {
-       spin_lock(&mdev->lock);
+       mutex_lock(&mdev->graph_mutex);
        list_add_tail(&nptr->list, &mdev->entity_notify);
-       spin_unlock(&mdev->lock);
+       mutex_unlock(&mdev->graph_mutex);
        return 0;
 }
 EXPORT_SYMBOL_GPL(media_device_register_entity_notify);
@@ -771,9 +752,9 @@ static void __media_device_unregister_entity_notify(struct media_device *mdev,
 void media_device_unregister_entity_notify(struct media_device *mdev,
                                        struct media_entity_notify *nptr)
 {
-       spin_lock(&mdev->lock);
+       mutex_lock(&mdev->graph_mutex);
        __media_device_unregister_entity_notify(mdev, nptr);
-       spin_unlock(&mdev->lock);
+       mutex_unlock(&mdev->graph_mutex);
 }
 EXPORT_SYMBOL_GPL(media_device_unregister_entity_notify);
 
@@ -787,11 +768,11 @@ void media_device_unregister(struct media_device *mdev)
        if (mdev == NULL)
                return;
 
-       spin_lock(&mdev->lock);
+       mutex_lock(&mdev->graph_mutex);
 
        /* Check if mdev was ever registered at all */
        if (!media_devnode_is_registered(&mdev->devnode)) {
-               spin_unlock(&mdev->lock);
+               mutex_unlock(&mdev->graph_mutex);
                return;
        }
 
@@ -811,12 +792,11 @@ void media_device_unregister(struct media_device *mdev)
                kfree(intf);
        }
 
-       spin_unlock(&mdev->lock);
+       mutex_unlock(&mdev->graph_mutex);
 
        device_remove_file(&mdev->devnode.dev, &dev_attr_model);
+       dev_dbg(mdev->dev, "Media device unregistering\n");
        media_devnode_unregister(&mdev->devnode);
-
-       dev_dbg(mdev->dev, "Media device unregistered\n");
 }
 EXPORT_SYMBOL_GPL(media_device_unregister);
 
index 29409f4..b66dc9d 100644 (file)
@@ -197,10 +197,11 @@ static int media_release(struct inode *inode, struct file *filp)
        if (mdev->fops->release)
                mdev->fops->release(filp);
 
+       filp->private_data = NULL;
+
        /* decrease the refcount unconditionally since the release()
           return value is ignored. */
        put_device(&mdev->dev);
-       filp->private_data = NULL;
        return 0;
 }
 
@@ -267,8 +268,11 @@ int __must_check media_devnode_register(struct media_devnode *mdev,
        return 0;
 
 error:
+       mutex_lock(&media_devnode_lock);
        cdev_del(&mdev->cdev);
        clear_bit(mdev->minor, media_devnode_nums);
+       mutex_unlock(&media_devnode_lock);
+
        return ret;
 }
 
index e95070b..d8a2299 100644 (file)
@@ -219,7 +219,7 @@ int media_entity_pads_init(struct media_entity *entity, u16 num_pads,
        entity->pads = pads;
 
        if (mdev)
-               spin_lock(&mdev->lock);
+               mutex_lock(&mdev->graph_mutex);
 
        for (i = 0; i < num_pads; i++) {
                pads[i].entity = entity;
@@ -230,7 +230,7 @@ int media_entity_pads_init(struct media_entity *entity, u16 num_pads,
        }
 
        if (mdev)
-               spin_unlock(&mdev->lock);
+               mutex_unlock(&mdev->graph_mutex);
 
        return 0;
 }
@@ -445,7 +445,7 @@ __must_check int __media_entity_pipeline_start(struct media_entity *entity,
                bitmap_or(active, active, has_no_links, entity->num_pads);
 
                if (!bitmap_full(active, entity->num_pads)) {
-                       ret = -EPIPE;
+                       ret = -ENOLINK;
                        dev_dbg(entity->graph_obj.mdev->dev,
                                "\"%s\":%u must be connected by an enabled link\n",
                                entity->name,
@@ -747,9 +747,9 @@ void media_entity_remove_links(struct media_entity *entity)
        if (mdev == NULL)
                return;
 
-       spin_lock(&mdev->lock);
+       mutex_lock(&mdev->graph_mutex);
        __media_entity_remove_links(entity);
-       spin_unlock(&mdev->lock);
+       mutex_unlock(&mdev->graph_mutex);
 }
 EXPORT_SYMBOL_GPL(media_entity_remove_links);
 
@@ -951,9 +951,9 @@ void media_remove_intf_link(struct media_link *link)
        if (mdev == NULL)
                return;
 
-       spin_lock(&mdev->lock);
+       mutex_lock(&mdev->graph_mutex);
        __media_remove_intf_link(link);
-       spin_unlock(&mdev->lock);
+       mutex_unlock(&mdev->graph_mutex);
 }
 EXPORT_SYMBOL_GPL(media_remove_intf_link);
 
@@ -975,8 +975,8 @@ void media_remove_intf_links(struct media_interface *intf)
        if (mdev == NULL)
                return;
 
-       spin_lock(&mdev->lock);
+       mutex_lock(&mdev->graph_mutex);
        __media_remove_intf_links(intf);
-       spin_unlock(&mdev->lock);
+       mutex_unlock(&mdev->graph_mutex);
 }
 EXPORT_SYMBOL_GPL(media_remove_intf_links);
index 48a611b..4f6467f 100644 (file)
@@ -14,6 +14,7 @@ source "drivers/media/pci/meye/Kconfig"
 source "drivers/media/pci/solo6x10/Kconfig"
 source "drivers/media/pci/sta2x11/Kconfig"
 source "drivers/media/pci/tw68/Kconfig"
+source "drivers/media/pci/tw686x/Kconfig"
 source "drivers/media/pci/zoran/Kconfig"
 endif
 
index 5f8aacb..2e54c36 100644 (file)
@@ -25,6 +25,7 @@ obj-$(CONFIG_VIDEO_BT848) += bt8xx/
 obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
 obj-$(CONFIG_VIDEO_SAA7164) += saa7164/
 obj-$(CONFIG_VIDEO_TW68) += tw68/
+obj-$(CONFIG_VIDEO_TW686X) += tw686x/
 obj-$(CONFIG_VIDEO_DT3155) += dt3155/
 obj-$(CONFIG_VIDEO_MEYE) += meye/
 obj-$(CONFIG_STA2X11_VIP) += sta2x11/
index a01f0cc..7034382 100644 (file)
@@ -4,6 +4,7 @@ config VIDEO_COBALT
        depends on PCI_MSI && MTD_COMPLEX_MAPPINGS
        depends on GPIOLIB || COMPILE_TEST
        depends on SND
+       depends on MTD
        select I2C_ALGOBIT
        select VIDEO_ADV7604
        select VIDEO_ADV7511
index 7e31f2a..47ce80f 100644 (file)
@@ -707,11 +707,7 @@ static inline int cx18_raw_vbi(const struct cx18 *cx)
 /* Call the specified callback for all subdevs with a grp_id bit matching the
  * mask in hw (if 0, then match them all). Ignore any errors. */
 #define cx18_call_hw(cx, hw, o, f, args...)                            \
-       do {                                                            \
-               struct v4l2_subdev *__sd;                               \
-               __v4l2_device_call_subdevs_p(&(cx)->v4l2_dev, __sd,     \
-                       !(hw) || (__sd->grp_id & (hw)), o, f , ##args); \
-       } while (0)
+       v4l2_device_mask_call_all(&(cx)->v4l2_dev, hw, o, f, ##args)
 
 #define cx18_call_all(cx, o, f, args...) cx18_call_hw(cx, 0, o, f , ##args)
 
@@ -719,12 +715,7 @@ static inline int cx18_raw_vbi(const struct cx18 *cx)
  * mask in hw (if 0, then match them all). If the callback returns an error
  * other than 0 or -ENOIOCTLCMD, then return with that error code. */
 #define cx18_call_hw_err(cx, hw, o, f, args...)                                \
-({                                                                     \
-       struct v4l2_subdev *__sd;                                       \
-       __v4l2_device_call_subdevs_until_err_p(&(cx)->v4l2_dev,         \
-                       __sd, !(hw) || (__sd->grp_id & (hw)), o, f,     \
-                       ##args);                                        \
-})
+       v4l2_device_mask_call_until_err(&(cx)->v4l2_dev, hw, o, f, ##args)
 
 #define cx18_call_all_err(cx, o, f, args...) \
        cx18_call_hw_err(cx, 0, o, f , ##args)
index 877dad8..e7d4406 100644 (file)
@@ -24,7 +24,7 @@ void cx23885_av_work_handler(struct work_struct *work)
 {
        struct cx23885_dev *dev =
                           container_of(work, struct cx23885_dev, cx25840_work);
-       bool handled;
+       bool handled = false;
 
        v4l2_subdev_call(dev->sd_cx25840, core, interrupt_service_routine,
                         PCI_MSK_AV_CORE, &handled);
index 6c08dae..10cba30 100644 (file)
@@ -827,12 +827,7 @@ static inline int ivtv_raw_vbi(const struct ivtv *itv)
 /* Call the specified callback for all subdevs matching hw (if 0, then
    match them all). Ignore any errors. */
 #define ivtv_call_hw(itv, hw, o, f, args...)                           \
-       do {                                                            \
-               struct v4l2_subdev *__sd;                               \
-               __v4l2_device_call_subdevs_p(&(itv)->v4l2_dev, __sd,    \
-                        !(hw) ? true : (__sd->grp_id & (hw)),          \
-                        o, f, ##args);                                 \
-       } while (0)
+       v4l2_device_mask_call_all(&(itv)->v4l2_dev, hw, o, f, ##args)
 
 #define ivtv_call_all(itv, o, f, args...) ivtv_call_hw(itv, 0, o, f , ##args)
 
@@ -840,11 +835,7 @@ static inline int ivtv_raw_vbi(const struct ivtv *itv)
    match them all). If the callback returns an error other than 0 or
    -ENOIOCTLCMD, then return with that error code. */
 #define ivtv_call_hw_err(itv, hw, o, f, args...)                       \
-({                                                                     \
-       struct v4l2_subdev *__sd;                                       \
-       __v4l2_device_call_subdevs_until_err_p(&(itv)->v4l2_dev, __sd,  \
-               !(hw) || (__sd->grp_id & (hw)), o, f , ##args);         \
-})
+       v4l2_device_mask_call_until_err(&(itv)->v4l2_dev, hw, o, f, ##args)
 
 #define ivtv_call_all_err(itv, o, f, args...) ivtv_call_hw_err(itv, 0, o, f , ##args)
 
index d018673..826c7c7 100644 (file)
@@ -203,7 +203,7 @@ int smi_ir_init(struct smi_dev *dev)
        rc_dev->dev.parent = &dev->pci_dev->dev;
 
        rc_dev->driver_type = RC_DRIVER_SCANCODE;
-       rc_dev->map_name = RC_MAP_DVBSKY;
+       rc_dev->map_name = dev->info->rc_map;
 
        ir->rc_dev = rc_dev;
        ir->dev = dev;
index b039a22..83981d6 100644 (file)
@@ -716,7 +716,8 @@ static int smi_fe_init(struct smi_port *port)
        /* init MAC.*/
        ret = smi_read_eeprom(&dev->i2c_bus[0], 0xc0, mac_ee, 16);
        dev_info(&port->dev->pci_dev->dev,
-               "DVBSky SMI PCIe MAC= %pM\n", mac_ee + (port->idx)*8);
+               "%s port %d MAC: %pM\n", dev->info->name,
+               port->idx, mac_ee + (port->idx)*8);
        memcpy(adap->proposed_mac, mac_ee + (port->idx)*8, 6);
        return ret;
 }
@@ -1066,6 +1067,7 @@ static struct smi_cfg_info dvbsky_s950_cfg = {
        .ts_1 = SMI_TS_DMA_BOTH,
        .fe_0 = DVBSKY_FE_NULL,
        .fe_1 = DVBSKY_FE_M88DS3103,
+       .rc_map = RC_MAP_DVBSKY,
 };
 
 static struct smi_cfg_info dvbsky_s952_cfg = {
@@ -1075,6 +1077,7 @@ static struct smi_cfg_info dvbsky_s952_cfg = {
        .ts_1 = SMI_TS_DMA_BOTH,
        .fe_0 = DVBSKY_FE_M88RS6000,
        .fe_1 = DVBSKY_FE_M88RS6000,
+       .rc_map = RC_MAP_DVBSKY,
 };
 
 static struct smi_cfg_info dvbsky_t9580_cfg = {
@@ -1084,6 +1087,17 @@ static struct smi_cfg_info dvbsky_t9580_cfg = {
        .ts_1 = SMI_TS_DMA_BOTH,
        .fe_0 = DVBSKY_FE_SIT2,
        .fe_1 = DVBSKY_FE_M88DS3103,
+       .rc_map = RC_MAP_DVBSKY,
+};
+
+static struct smi_cfg_info technotrend_s2_4200_cfg = {
+       .type = SMI_TECHNOTREND_S2_4200,
+       .name = "TechnoTrend TT-budget S2-4200 Twin",
+       .ts_0 = SMI_TS_DMA_BOTH,
+       .ts_1 = SMI_TS_DMA_BOTH,
+       .fe_0 = DVBSKY_FE_M88RS6000,
+       .fe_1 = DVBSKY_FE_M88RS6000,
+       .rc_map = RC_MAP_TT_1500,
 };
 
 /* PCI IDs */
@@ -1096,6 +1110,7 @@ static const struct pci_device_id smi_id_table[] = {
        SMI_ID(0x4254, 0x0550, dvbsky_s950_cfg),
        SMI_ID(0x4254, 0x0552, dvbsky_s952_cfg),
        SMI_ID(0x4254, 0x5580, dvbsky_t9580_cfg),
+       SMI_ID(0x13c2, 0x3016, technotrend_s2_4200_cfg),
        {0}
 };
 MODULE_DEVICE_TABLE(pci, smi_id_table);
index 68cdda2..611e4f0 100644 (file)
@@ -216,6 +216,7 @@ struct smi_cfg_info {
 #define SMI_DVBSKY_S950         1
 #define SMI_DVBSKY_T9580        2
 #define SMI_DVBSKY_T982         3
+#define SMI_TECHNOTREND_S2_4200 4
        int type;
        char *name;
 #define SMI_TS_NULL             0
@@ -232,6 +233,7 @@ struct smi_cfg_info {
 #define DVBSKY_FE_SIT2          3
        int fe_0;
        int fe_1;
+       char *rc_map;
 };
 
 struct smi_rc {
index 753411c..1fc195f 100644 (file)
@@ -444,27 +444,19 @@ static int vidioc_querycap(struct file *file, void *priv,
 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std)
 {
        struct sta2x11_vip *vip = video_drvdata(file);
-       v4l2_std_id oldstd = vip->std, newstd;
-       int status;
-
-       if (V4L2_STD_ALL == std) {
-               v4l2_subdev_call(vip->decoder, video, s_std, std);
-               ssleep(2);
-               v4l2_subdev_call(vip->decoder, video, querystd, &newstd);
-               v4l2_subdev_call(vip->decoder, video, g_input_status, &status);
-               if (status & V4L2_IN_ST_NO_SIGNAL)
+
+       /*
+        * This is here for backwards compatibility only.
+        * The use of V4L2_STD_ALL to trigger a querystd is non-standard.
+        */
+       if (std == V4L2_STD_ALL) {
+               v4l2_subdev_call(vip->decoder, video, querystd, &std);
+               if (std == V4L2_STD_UNKNOWN)
                        return -EIO;
-               std = vip->std = newstd;
-               if (oldstd != std) {
-                       if (V4L2_STD_525_60 & std)
-                               vip->format = formats_60[0];
-                       else
-                               vip->format = formats_50[0];
-               }
-               return 0;
        }
 
-       if (oldstd != std) {
+       if (vip->std != std) {
+               vip->std = std;
                if (V4L2_STD_525_60 & std)
                        vip->format = formats_60[0];
                else
diff --git a/drivers/media/pci/tw686x/Kconfig b/drivers/media/pci/tw686x/Kconfig
new file mode 100644 (file)
index 0000000..fb85369
--- /dev/null
@@ -0,0 +1,18 @@
+config VIDEO_TW686X
+       tristate "Intersil/Techwell TW686x video capture cards"
+       depends on PCI && VIDEO_DEV && VIDEO_V4L2 && SND
+       depends on HAS_DMA
+       select VIDEOBUF2_VMALLOC
+       select SND_PCM
+       help
+         Support for Intersil/Techwell TW686x-based frame grabber cards.
+
+         Currently supported chips:
+         - TW6864 (4 video channels),
+         - TW6865 (4 video channels, not tested, second generation chip),
+         - TW6868 (8 video channels but only 4 first channels using
+           built-in video decoder are supported, not tested),
+         - TW6869 (8 video channels, second generation chip).
+
+         To compile this driver as a module, choose M here: the module
+         will be named tw686x.
diff --git a/drivers/media/pci/tw686x/Makefile b/drivers/media/pci/tw686x/Makefile
new file mode 100644 (file)
index 0000000..9981954
--- /dev/null
@@ -0,0 +1,3 @@
+tw686x-objs := tw686x-core.o tw686x-video.o tw686x-audio.o
+
+obj-$(CONFIG_VIDEO_TW686X) += tw686x.o
diff --git a/drivers/media/pci/tw686x/tw686x-audio.c b/drivers/media/pci/tw686x/tw686x-audio.c
new file mode 100644 (file)
index 0000000..91459ab
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2015 VanguardiaSur - www.vanguardiasur.com.ar
+ *
+ * Based on the audio support from the tw6869 driver:
+ * Copyright 2015 www.starterkit.ru <info@starterkit.ru>
+ *
+ * Based on:
+ * Driver for Intersil|Techwell TW6869 based DVR cards
+ * (c) 2011-12 liran <jli11@intersil.com> [Intersil|Techwell China]
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/mutex.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/control.h>
+#include "tw686x.h"
+#include "tw686x-regs.h"
+
+#define AUDIO_CHANNEL_OFFSET 8
+
+void tw686x_audio_irq(struct tw686x_dev *dev, unsigned long requests,
+                     unsigned int pb_status)
+{
+       unsigned long flags;
+       unsigned int ch, pb;
+
+       for_each_set_bit(ch, &requests, max_channels(dev)) {
+               struct tw686x_audio_channel *ac = &dev->audio_channels[ch];
+               struct tw686x_audio_buf *done = NULL;
+               struct tw686x_audio_buf *next = NULL;
+               struct tw686x_dma_desc *desc;
+
+               pb = !!(pb_status & BIT(AUDIO_CHANNEL_OFFSET + ch));
+
+               spin_lock_irqsave(&ac->lock, flags);
+
+               /* Sanity check */
+               if (!ac->ss || !ac->curr_bufs[0] || !ac->curr_bufs[1]) {
+                       spin_unlock_irqrestore(&ac->lock, flags);
+                       continue;
+               }
+
+               if (!list_empty(&ac->buf_list)) {
+                       next = list_first_entry(&ac->buf_list,
+                                       struct tw686x_audio_buf, list);
+                       list_move_tail(&next->list, &ac->buf_list);
+                       done = ac->curr_bufs[!pb];
+                       ac->curr_bufs[pb] = next;
+               }
+               spin_unlock_irqrestore(&ac->lock, flags);
+
+               desc = &ac->dma_descs[pb];
+               if (done && next && desc->virt) {
+                       memcpy(done->virt, desc->virt, desc->size);
+                       ac->ptr = done->dma - ac->buf[0].dma;
+                       snd_pcm_period_elapsed(ac->ss);
+               }
+       }
+}
+
+static int tw686x_pcm_hw_params(struct snd_pcm_substream *ss,
+                               struct snd_pcm_hw_params *hw_params)
+{
+       return snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params));
+}
+
+static int tw686x_pcm_hw_free(struct snd_pcm_substream *ss)
+{
+       return snd_pcm_lib_free_pages(ss);
+}
+
+/*
+ * The audio device rate is global and shared among all
+ * capture channels. The driver makes no effort to prevent
+ * rate modifications. User is free change the rate, but it
+ * means changing the rate for all capture sub-devices.
+ */
+static const struct snd_pcm_hardware tw686x_capture_hw = {
+       .info                   = (SNDRV_PCM_INFO_MMAP |
+                                  SNDRV_PCM_INFO_INTERLEAVED |
+                                  SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                                  SNDRV_PCM_INFO_MMAP_VALID),
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE,
+       .rates                  = SNDRV_PCM_RATE_8000_48000,
+       .rate_min               = 8000,
+       .rate_max               = 48000,
+       .channels_min           = 1,
+       .channels_max           = 1,
+       .buffer_bytes_max       = TW686X_AUDIO_PAGE_MAX * TW686X_AUDIO_PAGE_SZ,
+       .period_bytes_min       = TW686X_AUDIO_PAGE_SZ,
+       .period_bytes_max       = TW686X_AUDIO_PAGE_SZ,
+       .periods_min            = TW686X_AUDIO_PERIODS_MIN,
+       .periods_max            = TW686X_AUDIO_PERIODS_MAX,
+};
+
+static int tw686x_pcm_open(struct snd_pcm_substream *ss)
+{
+       struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
+       struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];
+       struct snd_pcm_runtime *rt = ss->runtime;
+       int err;
+
+       ac->ss = ss;
+       rt->hw = tw686x_capture_hw;
+
+       err = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int tw686x_pcm_close(struct snd_pcm_substream *ss)
+{
+       struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
+       struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];
+
+       ac->ss = NULL;
+       return 0;
+}
+
+static int tw686x_pcm_prepare(struct snd_pcm_substream *ss)
+{
+       struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
+       struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];
+       struct snd_pcm_runtime *rt = ss->runtime;
+       unsigned int period_size = snd_pcm_lib_period_bytes(ss);
+       struct tw686x_audio_buf *p_buf, *b_buf;
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       tw686x_disable_channel(dev, AUDIO_CHANNEL_OFFSET + ac->ch);
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       if (dev->audio_rate != rt->rate) {
+               u32 reg;
+
+               dev->audio_rate = rt->rate;
+               reg = ((125000000 / rt->rate) << 16) +
+                      ((125000000 % rt->rate) << 16) / rt->rate;
+
+               reg_write(dev, AUDIO_CONTROL2, reg);
+       }
+
+       if (period_size != TW686X_AUDIO_PAGE_SZ ||
+           rt->periods < TW686X_AUDIO_PERIODS_MIN ||
+           rt->periods > TW686X_AUDIO_PERIODS_MAX) {
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&ac->lock, flags);
+       INIT_LIST_HEAD(&ac->buf_list);
+
+       for (i = 0; i < rt->periods; i++) {
+               ac->buf[i].dma = rt->dma_addr + period_size * i;
+               ac->buf[i].virt = rt->dma_area + period_size * i;
+               INIT_LIST_HEAD(&ac->buf[i].list);
+               list_add_tail(&ac->buf[i].list, &ac->buf_list);
+       }
+
+       p_buf = list_first_entry(&ac->buf_list, struct tw686x_audio_buf, list);
+       list_move_tail(&p_buf->list, &ac->buf_list);
+
+       b_buf = list_first_entry(&ac->buf_list, struct tw686x_audio_buf, list);
+       list_move_tail(&b_buf->list, &ac->buf_list);
+
+       ac->curr_bufs[0] = p_buf;
+       ac->curr_bufs[1] = b_buf;
+       ac->ptr = 0;
+       spin_unlock_irqrestore(&ac->lock, flags);
+
+       return 0;
+}
+
+static int tw686x_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
+{
+       struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
+       struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];
+       unsigned long flags;
+       int err = 0;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               if (ac->curr_bufs[0] && ac->curr_bufs[1]) {
+                       spin_lock_irqsave(&dev->lock, flags);
+                       tw686x_enable_channel(dev,
+                               AUDIO_CHANNEL_OFFSET + ac->ch);
+                       spin_unlock_irqrestore(&dev->lock, flags);
+
+                       mod_timer(&dev->dma_delay_timer,
+                                 jiffies + msecs_to_jiffies(100));
+               } else {
+                       err = -EIO;
+               }
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               spin_lock_irqsave(&dev->lock, flags);
+               tw686x_disable_channel(dev, AUDIO_CHANNEL_OFFSET + ac->ch);
+               spin_unlock_irqrestore(&dev->lock, flags);
+
+               spin_lock_irqsave(&ac->lock, flags);
+               ac->curr_bufs[0] = NULL;
+               ac->curr_bufs[1] = NULL;
+               spin_unlock_irqrestore(&ac->lock, flags);
+               break;
+       default:
+               err = -EINVAL;
+       }
+       return err;
+}
+
+static snd_pcm_uframes_t tw686x_pcm_pointer(struct snd_pcm_substream *ss)
+{
+       struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
+       struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];
+
+       return bytes_to_frames(ss->runtime, ac->ptr);
+}
+
+static struct snd_pcm_ops tw686x_pcm_ops = {
+       .open = tw686x_pcm_open,
+       .close = tw686x_pcm_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = tw686x_pcm_hw_params,
+       .hw_free = tw686x_pcm_hw_free,
+       .prepare = tw686x_pcm_prepare,
+       .trigger = tw686x_pcm_trigger,
+       .pointer = tw686x_pcm_pointer,
+};
+
+static int tw686x_snd_pcm_init(struct tw686x_dev *dev)
+{
+       struct snd_card *card = dev->snd_card;
+       struct snd_pcm *pcm;
+       struct snd_pcm_substream *ss;
+       unsigned int i;
+       int err;
+
+       err = snd_pcm_new(card, card->driver, 0, 0, max_channels(dev), &pcm);
+       if (err < 0)
+               return err;
+
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &tw686x_pcm_ops);
+       snd_pcm_chip(pcm) = dev;
+       pcm->info_flags = 0;
+       strlcpy(pcm->name, "tw686x PCM", sizeof(pcm->name));
+
+       for (i = 0, ss = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+            ss; ss = ss->next, i++)
+               snprintf(ss->name, sizeof(ss->name), "vch%u audio", i);
+
+       return snd_pcm_lib_preallocate_pages_for_all(pcm,
+                               SNDRV_DMA_TYPE_DEV,
+                               snd_dma_pci_data(dev->pci_dev),
+                               TW686X_AUDIO_PAGE_MAX * TW686X_AUDIO_PAGE_SZ,
+                               TW686X_AUDIO_PAGE_MAX * TW686X_AUDIO_PAGE_SZ);
+}
+
+static void tw686x_audio_dma_free(struct tw686x_dev *dev,
+                                 struct tw686x_audio_channel *ac)
+{
+       int pb;
+
+       for (pb = 0; pb < 2; pb++) {
+               if (!ac->dma_descs[pb].virt)
+                       continue;
+               pci_free_consistent(dev->pci_dev, ac->dma_descs[pb].size,
+                                   ac->dma_descs[pb].virt,
+                                   ac->dma_descs[pb].phys);
+               ac->dma_descs[pb].virt = NULL;
+       }
+}
+
+static int tw686x_audio_dma_alloc(struct tw686x_dev *dev,
+                                 struct tw686x_audio_channel *ac)
+{
+       int pb;
+
+       for (pb = 0; pb < 2; pb++) {
+               u32 reg = pb ? ADMA_B_ADDR[ac->ch] : ADMA_P_ADDR[ac->ch];
+               void *virt;
+
+               virt = pci_alloc_consistent(dev->pci_dev, TW686X_AUDIO_PAGE_SZ,
+                                           &ac->dma_descs[pb].phys);
+               if (!virt) {
+                       dev_err(&dev->pci_dev->dev,
+                               "dma%d: unable to allocate audio DMA %s-buffer\n",
+                               ac->ch, pb ? "B" : "P");
+                       return -ENOMEM;
+               }
+               ac->dma_descs[pb].virt = virt;
+               ac->dma_descs[pb].size = TW686X_AUDIO_PAGE_SZ;
+               reg_write(dev, reg, ac->dma_descs[pb].phys);
+       }
+       return 0;
+}
+
+void tw686x_audio_free(struct tw686x_dev *dev)
+{
+       unsigned long flags;
+       u32 dma_ch_mask;
+       u32 dma_cmd;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       dma_cmd = reg_read(dev, DMA_CMD);
+       dma_ch_mask = reg_read(dev, DMA_CHANNEL_ENABLE);
+       reg_write(dev, DMA_CMD, dma_cmd & ~0xff00);
+       reg_write(dev, DMA_CHANNEL_ENABLE, dma_ch_mask & ~0xff00);
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       if (!dev->snd_card)
+               return;
+       snd_card_free(dev->snd_card);
+       dev->snd_card = NULL;
+}
+
+int tw686x_audio_init(struct tw686x_dev *dev)
+{
+       struct pci_dev *pci_dev = dev->pci_dev;
+       struct snd_card *card;
+       int err, ch;
+
+       /*
+        * AUDIO_CONTROL1
+        * DMA byte length [31:19] = 4096 (i.e. ALSA period)
+        * External audio enable [0] = enabled
+        */
+       reg_write(dev, AUDIO_CONTROL1, 0x80000001);
+
+       err = snd_card_new(&pci_dev->dev, SNDRV_DEFAULT_IDX1,
+                          SNDRV_DEFAULT_STR1,
+                          THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
+
+       dev->snd_card = card;
+       strlcpy(card->driver, "tw686x", sizeof(card->driver));
+       strlcpy(card->shortname, "tw686x", sizeof(card->shortname));
+       strlcpy(card->longname, pci_name(pci_dev), sizeof(card->longname));
+       snd_card_set_dev(card, &pci_dev->dev);
+
+       for (ch = 0; ch < max_channels(dev); ch++) {
+               struct tw686x_audio_channel *ac;
+
+               ac = &dev->audio_channels[ch];
+               spin_lock_init(&ac->lock);
+               ac->dev = dev;
+               ac->ch = ch;
+
+               err = tw686x_audio_dma_alloc(dev, ac);
+               if (err < 0)
+                       goto err_cleanup;
+       }
+
+       err = tw686x_snd_pcm_init(dev);
+       if (err < 0)
+               goto err_cleanup;
+
+       err = snd_card_register(card);
+       if (!err)
+               return 0;
+
+err_cleanup:
+       for (ch = 0; ch < max_channels(dev); ch++) {
+               if (!dev->audio_channels[ch].dev)
+                       continue;
+               tw686x_audio_dma_free(dev, &dev->audio_channels[ch]);
+       }
+       snd_card_free(card);
+       dev->snd_card = NULL;
+       return err;
+}
diff --git a/drivers/media/pci/tw686x/tw686x-core.c b/drivers/media/pci/tw686x/tw686x-core.c
new file mode 100644 (file)
index 0000000..cf53b0e
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2015 VanguardiaSur - www.vanguardiasur.com.ar
+ *
+ * Based on original driver by Krzysztof Ha?asa:
+ * Copyright (C) 2015 Industrial Research Institute for Automation
+ * and Measurements PIAP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * Notes
+ * -----
+ *
+ * 1. Under stress-testing, it has been observed that the PCIe link
+ * goes down, without reason. Therefore, the driver takes special care
+ * to allow device hot-unplugging.
+ *
+ * 2. TW686X devices are capable of setting a few different DMA modes,
+ * including: scatter-gather, field and frame modes. However,
+ * under stress testings it has been found that the machine can
+ * freeze completely if DMA registers are programmed while streaming
+ * is active.
+ * This driver tries to access hardware registers as infrequently
+ * as possible by:
+ *   i.  allocating fixed DMA buffers and memcpy'ing into
+ *       vmalloc'ed buffers
+ *   ii. using a timer to mitigate the rate of DMA reset operations,
+ *       on DMA channels error.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+
+#include "tw686x.h"
+#include "tw686x-regs.h"
+
+/*
+ * This module parameter allows to control the DMA_TIMER_INTERVAL value.
+ * The DMA_TIMER_INTERVAL register controls the minimum DMA interrupt
+ * time span (iow, the maximum DMA interrupt rate) thus allowing for
+ * IRQ coalescing.
+ *
+ * The chip datasheet does not mention a time unit for this value, so
+ * users wanting fine-grain control over the interrupt rate should
+ * determine the desired value through testing.
+ */
+static u32 dma_interval = 0x00098968;
+module_param(dma_interval, int, 0444);
+MODULE_PARM_DESC(dma_interval, "Minimum time span for DMA interrupting host");
+
+void tw686x_disable_channel(struct tw686x_dev *dev, unsigned int channel)
+{
+       u32 dma_en = reg_read(dev, DMA_CHANNEL_ENABLE);
+       u32 dma_cmd = reg_read(dev, DMA_CMD);
+
+       dma_en &= ~BIT(channel);
+       dma_cmd &= ~BIT(channel);
+
+       /* Must remove it from pending too */
+       dev->pending_dma_en &= ~BIT(channel);
+       dev->pending_dma_cmd &= ~BIT(channel);
+
+       /* Stop DMA if no channels are enabled */
+       if (!dma_en)
+               dma_cmd = 0;
+       reg_write(dev, DMA_CHANNEL_ENABLE, dma_en);
+       reg_write(dev, DMA_CMD, dma_cmd);
+}
+
+void tw686x_enable_channel(struct tw686x_dev *dev, unsigned int channel)
+{
+       u32 dma_en = reg_read(dev, DMA_CHANNEL_ENABLE);
+       u32 dma_cmd = reg_read(dev, DMA_CMD);
+
+       dev->pending_dma_en |= dma_en | BIT(channel);
+       dev->pending_dma_cmd |= dma_cmd | DMA_CMD_ENABLE | BIT(channel);
+}
+
+/*
+ * The purpose of this awful hack is to avoid enabling the DMA
+ * channels "too fast" which makes some TW686x devices very
+ * angry and freeze the CPU (see note 1).
+ */
+static void tw686x_dma_delay(unsigned long data)
+{
+       struct tw686x_dev *dev = (struct tw686x_dev *)data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       reg_write(dev, DMA_CHANNEL_ENABLE, dev->pending_dma_en);
+       reg_write(dev, DMA_CMD, dev->pending_dma_cmd);
+       dev->pending_dma_en = 0;
+       dev->pending_dma_cmd = 0;
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+static void tw686x_reset_channels(struct tw686x_dev *dev, unsigned int ch_mask)
+{
+       u32 dma_en, dma_cmd;
+
+       dma_en = reg_read(dev, DMA_CHANNEL_ENABLE);
+       dma_cmd = reg_read(dev, DMA_CMD);
+
+       /*
+        * Save pending register status, the timer will
+        * restore them.
+        */
+       dev->pending_dma_en |= dma_en;
+       dev->pending_dma_cmd |= dma_cmd;
+
+       /* Disable the reset channels */
+       reg_write(dev, DMA_CHANNEL_ENABLE, dma_en & ~ch_mask);
+
+       if ((dma_en & ~ch_mask) == 0) {
+               dev_dbg(&dev->pci_dev->dev, "reset: stopping DMA\n");
+               dma_cmd &= ~DMA_CMD_ENABLE;
+       }
+       reg_write(dev, DMA_CMD, dma_cmd & ~ch_mask);
+}
+
+static irqreturn_t tw686x_irq(int irq, void *dev_id)
+{
+       struct tw686x_dev *dev = (struct tw686x_dev *)dev_id;
+       unsigned int video_requests, audio_requests, reset_ch;
+       u32 fifo_status, fifo_signal, fifo_ov, fifo_bad, fifo_errors;
+       u32 int_status, dma_en, video_en, pb_status;
+       unsigned long flags;
+
+       int_status = reg_read(dev, INT_STATUS); /* cleared on read */
+       fifo_status = reg_read(dev, VIDEO_FIFO_STATUS);
+
+       /* INT_STATUS does not include FIFO_STATUS errors! */
+       if (!int_status && !TW686X_FIFO_ERROR(fifo_status))
+               return IRQ_NONE;
+
+       if (int_status & INT_STATUS_DMA_TOUT) {
+               dev_dbg(&dev->pci_dev->dev,
+                       "DMA timeout. Resetting DMA for all channels\n");
+               reset_ch = ~0;
+               goto reset_channels;
+       }
+
+       spin_lock_irqsave(&dev->lock, flags);
+       dma_en = reg_read(dev, DMA_CHANNEL_ENABLE);
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       video_en = dma_en & 0xff;
+       fifo_signal = ~(fifo_status & 0xff) & video_en;
+       fifo_ov = fifo_status >> 24;
+       fifo_bad = fifo_status >> 16;
+
+       /* Mask of channels with signal and FIFO errors */
+       fifo_errors = fifo_signal & (fifo_ov | fifo_bad);
+
+       reset_ch = 0;
+       pb_status = reg_read(dev, PB_STATUS);
+
+       /* Coalesce video frame/error events */
+       video_requests = (int_status & video_en) | fifo_errors;
+       audio_requests = (int_status & dma_en) >> 8;
+
+       if (video_requests)
+               tw686x_video_irq(dev, video_requests, pb_status,
+                                fifo_status, &reset_ch);
+       if (audio_requests)
+               tw686x_audio_irq(dev, audio_requests, pb_status);
+
+reset_channels:
+       if (reset_ch) {
+               spin_lock_irqsave(&dev->lock, flags);
+               tw686x_reset_channels(dev, reset_ch);
+               spin_unlock_irqrestore(&dev->lock, flags);
+               mod_timer(&dev->dma_delay_timer,
+                         jiffies + msecs_to_jiffies(100));
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void tw686x_dev_release(struct v4l2_device *v4l2_dev)
+{
+       struct tw686x_dev *dev = container_of(v4l2_dev, struct tw686x_dev,
+                                             v4l2_dev);
+       unsigned int ch;
+
+       for (ch = 0; ch < max_channels(dev); ch++)
+               v4l2_ctrl_handler_free(&dev->video_channels[ch].ctrl_handler);
+
+       v4l2_device_unregister(&dev->v4l2_dev);
+
+       kfree(dev->audio_channels);
+       kfree(dev->video_channels);
+       kfree(dev);
+}
+
+static int tw686x_probe(struct pci_dev *pci_dev,
+                       const struct pci_device_id *pci_id)
+{
+       struct tw686x_dev *dev;
+       int err;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+       dev->type = pci_id->driver_data;
+       sprintf(dev->name, "tw%04X", pci_dev->device);
+
+       dev->video_channels = kcalloc(max_channels(dev),
+               sizeof(*dev->video_channels), GFP_KERNEL);
+       if (!dev->video_channels) {
+               err = -ENOMEM;
+               goto free_dev;
+       }
+
+       dev->audio_channels = kcalloc(max_channels(dev),
+               sizeof(*dev->audio_channels), GFP_KERNEL);
+       if (!dev->audio_channels) {
+               err = -ENOMEM;
+               goto free_video;
+       }
+
+       pr_info("%s: PCI %s, IRQ %d, MMIO 0x%lx\n", dev->name,
+               pci_name(pci_dev), pci_dev->irq,
+               (unsigned long)pci_resource_start(pci_dev, 0));
+
+       dev->pci_dev = pci_dev;
+       if (pci_enable_device(pci_dev)) {
+               err = -EIO;
+               goto free_audio;
+       }
+
+       pci_set_master(pci_dev);
+       err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
+       if (err) {
+               dev_err(&pci_dev->dev, "32-bit PCI DMA not supported\n");
+               err = -EIO;
+               goto disable_pci;
+       }
+
+       err = pci_request_regions(pci_dev, dev->name);
+       if (err) {
+               dev_err(&pci_dev->dev, "unable to request PCI region\n");
+               goto disable_pci;
+       }
+
+       dev->mmio = pci_ioremap_bar(pci_dev, 0);
+       if (!dev->mmio) {
+               dev_err(&pci_dev->dev, "unable to remap PCI region\n");
+               err = -ENOMEM;
+               goto free_region;
+       }
+
+       /* Reset all subsystems */
+       reg_write(dev, SYS_SOFT_RST, 0x0f);
+       mdelay(1);
+
+       reg_write(dev, SRST[0], 0x3f);
+       if (max_channels(dev) > 4)
+               reg_write(dev, SRST[1], 0x3f);
+
+       /* Disable the DMA engine */
+       reg_write(dev, DMA_CMD, 0);
+       reg_write(dev, DMA_CHANNEL_ENABLE, 0);
+
+       /* Enable DMA FIFO overflow and pointer check */
+       reg_write(dev, DMA_CONFIG, 0xffffff04);
+       reg_write(dev, DMA_CHANNEL_TIMEOUT, 0x140c8584);
+       reg_write(dev, DMA_TIMER_INTERVAL, dma_interval);
+
+       spin_lock_init(&dev->lock);
+
+       err = request_irq(pci_dev->irq, tw686x_irq, IRQF_SHARED,
+                         dev->name, dev);
+       if (err < 0) {
+               dev_err(&pci_dev->dev, "unable to request interrupt\n");
+               goto iounmap;
+       }
+
+       setup_timer(&dev->dma_delay_timer,
+                   tw686x_dma_delay, (unsigned long) dev);
+
+       /*
+        * This must be set right before initializing v4l2_dev.
+        * It's used to release resources after the last handle
+        * held is released.
+        */
+       dev->v4l2_dev.release = tw686x_dev_release;
+       err = tw686x_video_init(dev);
+       if (err) {
+               dev_err(&pci_dev->dev, "can't register video\n");
+               goto free_irq;
+       }
+
+       err = tw686x_audio_init(dev);
+       if (err)
+               dev_warn(&pci_dev->dev, "can't register audio\n");
+
+       pci_set_drvdata(pci_dev, dev);
+       return 0;
+
+free_irq:
+       free_irq(pci_dev->irq, dev);
+iounmap:
+       pci_iounmap(pci_dev, dev->mmio);
+free_region:
+       pci_release_regions(pci_dev);
+disable_pci:
+       pci_disable_device(pci_dev);
+free_audio:
+       kfree(dev->audio_channels);
+free_video:
+       kfree(dev->video_channels);
+free_dev:
+       kfree(dev);
+       return err;
+}
+
+static void tw686x_remove(struct pci_dev *pci_dev)
+{
+       struct tw686x_dev *dev = pci_get_drvdata(pci_dev);
+       unsigned long flags;
+
+       /* This guarantees the IRQ handler is no longer running,
+        * which means we can kiss good-bye some resources.
+        */
+       free_irq(pci_dev->irq, dev);
+
+       tw686x_video_free(dev);
+       tw686x_audio_free(dev);
+       del_timer_sync(&dev->dma_delay_timer);
+
+       pci_iounmap(pci_dev, dev->mmio);
+       pci_release_regions(pci_dev);
+       pci_disable_device(pci_dev);
+
+       /*
+        * Setting pci_dev to NULL allows to detect hardware is no longer
+        * available and will be used by vb2_ops. This is required because
+        * the device sometimes hot-unplugs itself as the result of a PCIe
+        * link down.
+        * The lock is really important here.
+        */
+       spin_lock_irqsave(&dev->lock, flags);
+       dev->pci_dev = NULL;
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       /*
+        * This calls tw686x_dev_release if it's the last reference.
+        * Otherwise, release is postponed until there are no users left.
+        */
+       v4l2_device_put(&dev->v4l2_dev);
+}
+
+/*
+ * On TW6864 and TW6868, all channels share the pair of video DMA SG tables,
+ * with 10-bit start_idx and end_idx determining start and end of frame buffer
+ * for particular channel.
+ * TW6868 with all its 8 channels would be problematic (only 127 SG entries per
+ * channel) but we support only 4 channels on this chip anyway (the first
+ * 4 channels are driven with internal video decoder, the other 4 would require
+ * an external TW286x part).
+ *
+ * On TW6865 and TW6869, each channel has its own DMA SG table, with indexes
+ * starting with 0. Both chips have complete sets of internal video decoders
+ * (respectively 4 or 8-channel).
+ *
+ * All chips have separate SG tables for two video frames.
+ */
+
+/* driver_data is number of A/V channels */
+static const struct pci_device_id tw686x_pci_tbl[] = {
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6864),
+               .driver_data = 4
+       },
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6865), /* not tested */
+               .driver_data = 4 | TYPE_SECOND_GEN
+       },
+       /*
+        * TW6868 supports 8 A/V channels with an external TW2865 chip;
+        * not supported by the driver.
+        */
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6868), /* not tested */
+               .driver_data = 4
+       },
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6869),
+               .driver_data = 8 | TYPE_SECOND_GEN},
+       {}
+};
+MODULE_DEVICE_TABLE(pci, tw686x_pci_tbl);
+
+static struct pci_driver tw686x_pci_driver = {
+       .name = "tw686x",
+       .id_table = tw686x_pci_tbl,
+       .probe = tw686x_probe,
+       .remove = tw686x_remove,
+};
+module_pci_driver(tw686x_pci_driver);
+
+MODULE_DESCRIPTION("Driver for video frame grabber cards based on Intersil/Techwell TW686[4589]");
+MODULE_AUTHOR("Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>");
+MODULE_AUTHOR("Krzysztof Ha?asa <khalasa@piap.pl>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/pci/tw686x/tw686x-regs.h b/drivers/media/pci/tw686x/tw686x-regs.h
new file mode 100644 (file)
index 0000000..fcef586
--- /dev/null
@@ -0,0 +1,122 @@
+/* DMA controller registers */
+#define REG8_1(a0) ((const u16[8]) { a0, a0 + 1, a0 + 2, a0 + 3, \
+                                    a0 + 4, a0 + 5, a0 + 6, a0 + 7})
+#define REG8_2(a0) ((const u16[8]) { a0, a0 + 2, a0 + 4, a0 + 6,       \
+                                    a0 + 8, a0 + 0xa, a0 + 0xc, a0 + 0xe})
+#define REG8_8(a0) ((const u16[8]) { a0, a0 + 8, a0 + 0x10, a0 + 0x18, \
+                                    a0 + 0x20, a0 + 0x28, a0 + 0x30, \
+                                    a0 + 0x38})
+#define INT_STATUS             0x00
+#define PB_STATUS              0x01
+#define DMA_CMD                        0x02
+#define VIDEO_FIFO_STATUS      0x03
+#define VIDEO_CHANNEL_ID       0x04
+#define VIDEO_PARSER_STATUS    0x05
+#define SYS_SOFT_RST           0x06
+#define DMA_PAGE_TABLE0_ADDR   ((const u16[8]) { 0x08, 0xd0, 0xd2, 0xd4, \
+                                                 0xd6, 0xd8, 0xda, 0xdc })
+#define DMA_PAGE_TABLE1_ADDR   ((const u16[8]) { 0x09, 0xd1, 0xd3, 0xd5, \
+                                                 0xd7, 0xd9, 0xdb, 0xdd })
+#define DMA_CHANNEL_ENABLE     0x0a
+#define DMA_CONFIG             0x0b
+#define DMA_TIMER_INTERVAL     0x0c
+#define DMA_CHANNEL_TIMEOUT    0x0d
+#define VDMA_CHANNEL_CONFIG    REG8_1(0x10)
+#define ADMA_P_ADDR            REG8_2(0x18)
+#define ADMA_B_ADDR            REG8_2(0x19)
+#define DMA10_P_ADDR           0x28
+#define DMA10_B_ADDR           0x29
+#define VIDEO_CONTROL1         0x2a
+#define VIDEO_CONTROL2         0x2b
+#define AUDIO_CONTROL1         0x2c
+#define AUDIO_CONTROL2         0x2d
+#define PHASE_REF              0x2e
+#define GPIO_REG               0x2f
+#define INTL_HBAR_CTRL         REG8_1(0x30)
+#define AUDIO_CONTROL3         0x38
+#define VIDEO_FIELD_CTRL       REG8_1(0x39)
+#define HSCALER_CTRL           REG8_1(0x42)
+#define VIDEO_SIZE             REG8_1(0x4A)
+#define VIDEO_SIZE_F2          REG8_1(0x52)
+#define MD_CONF                        REG8_1(0x60)
+#define MD_INIT                        REG8_1(0x68)
+#define MD_MAP0                        REG8_1(0x70)
+#define VDMA_P_ADDR            REG8_8(0x80) /* not used in DMA SG mode */
+#define VDMA_WHP               REG8_8(0x81)
+#define VDMA_B_ADDR            REG8_8(0x82)
+#define VDMA_F2_P_ADDR         REG8_8(0x84)
+#define VDMA_F2_WHP            REG8_8(0x85)
+#define VDMA_F2_B_ADDR         REG8_8(0x86)
+#define EP_REG_ADDR            0xfe
+#define EP_REG_DATA            0xff
+
+/* Video decoder registers */
+#define VDREG8(a0) ((const u16[8]) { \
+       a0 + 0x000, a0 + 0x010, a0 + 0x020, a0 + 0x030, \
+       a0 + 0x100, a0 + 0x110, a0 + 0x120, a0 + 0x130})
+#define VIDSTAT                        VDREG8(0x100)
+#define BRIGHT                 VDREG8(0x101)
+#define CONTRAST               VDREG8(0x102)
+#define SHARPNESS              VDREG8(0x103)
+#define SAT_U                  VDREG8(0x104)
+#define SAT_V                  VDREG8(0x105)
+#define HUE                    VDREG8(0x106)
+#define CROP_HI                        VDREG8(0x107)
+#define VDELAY_LO              VDREG8(0x108)
+#define VACTIVE_LO             VDREG8(0x109)
+#define HDELAY_LO              VDREG8(0x10a)
+#define HACTIVE_LO             VDREG8(0x10b)
+#define MVSN                   VDREG8(0x10c)
+#define STATUS2                        VDREG8(0x10d)
+#define SDT                    VDREG8(0x10e)
+#define SDT_EN                 VDREG8(0x10f)
+
+#define VSCALE_LO              VDREG8(0x144)
+#define SCALE_HI               VDREG8(0x145)
+#define HSCALE_LO              VDREG8(0x146)
+#define F2CROP_HI              VDREG8(0x147)
+#define F2VDELAY_LO            VDREG8(0x148)
+#define F2VACTIVE_LO           VDREG8(0x149)
+#define F2HDELAY_LO            VDREG8(0x14a)
+#define F2HACTIVE_LO           VDREG8(0x14b)
+#define F2VSCALE_LO            VDREG8(0x14c)
+#define F2SCALE_HI             VDREG8(0x14d)
+#define F2HSCALE_LO            VDREG8(0x14e)
+#define F2CNT                  VDREG8(0x14f)
+
+#define VDREG2(a0) ((const u16[2]) { a0, a0 + 0x100 })
+#define SRST                   VDREG2(0x180)
+#define ACNTL                  VDREG2(0x181)
+#define ACNTL2                 VDREG2(0x182)
+#define CNTRL1                 VDREG2(0x183)
+#define CKHY                   VDREG2(0x184)
+#define SHCOR                  VDREG2(0x185)
+#define CORING                 VDREG2(0x186)
+#define CLMPG                  VDREG2(0x187)
+#define IAGC                   VDREG2(0x188)
+#define VCTRL1                 VDREG2(0x18f)
+#define MISC1                  VDREG2(0x194)
+#define LOOP                   VDREG2(0x195)
+#define MISC2                  VDREG2(0x196)
+
+#define CLMD                   VDREG2(0x197)
+#define ANPWRDOWN              VDREG2(0x1ce)
+#define AIGAIN                 ((const u16[8]) { 0x1d0, 0x1d1, 0x1d2, 0x1d3, \
+                                                 0x2d0, 0x2d1, 0x2d2, 0x2d3 })
+
+#define SYS_MODE_DMA_SHIFT     13
+
+#define DMA_CMD_ENABLE         BIT(31)
+#define INT_STATUS_DMA_TOUT    BIT(17)
+#define TW686X_VIDSTAT_HLOCK   BIT(6)
+#define TW686X_VIDSTAT_VDLOSS  BIT(7)
+
+#define TW686X_STD_NTSC_M      0
+#define TW686X_STD_PAL         1
+#define TW686X_STD_SECAM       2
+#define TW686X_STD_NTSC_443    3
+#define TW686X_STD_PAL_M       4
+#define TW686X_STD_PAL_CN      5
+#define TW686X_STD_PAL_60      6
+
+#define TW686X_FIFO_ERROR(x)   (x & ~(0xff))
diff --git a/drivers/media/pci/tw686x/tw686x-video.c b/drivers/media/pci/tw686x/tw686x-video.c
new file mode 100644 (file)
index 0000000..253e108
--- /dev/null
@@ -0,0 +1,937 @@
+/*
+ * Copyright (C) 2015 VanguardiaSur - www.vanguardiasur.com.ar
+ *
+ * Based on original driver by Krzysztof Ha?asa:
+ * Copyright (C) 2015 Industrial Research Institute for Automation
+ * and Measurements PIAP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-vmalloc.h>
+#include "tw686x.h"
+#include "tw686x-regs.h"
+
+#define TW686X_INPUTS_PER_CH           4
+#define TW686X_VIDEO_WIDTH             720
+#define TW686X_VIDEO_HEIGHT(id)                ((id & V4L2_STD_525_60) ? 480 : 576)
+
+static const struct tw686x_format formats[] = {
+       {
+               .fourcc = V4L2_PIX_FMT_UYVY,
+               .mode = 0,
+               .depth = 16,
+       }, {
+               .fourcc = V4L2_PIX_FMT_RGB565,
+               .mode = 5,
+               .depth = 16,
+       }, {
+               .fourcc = V4L2_PIX_FMT_YUYV,
+               .mode = 6,
+               .depth = 16,
+       }
+};
+
+static unsigned int tw686x_fields_map(v4l2_std_id std, unsigned int fps)
+{
+       static const unsigned int map[15] = {
+               0x00000000, 0x00000001, 0x00004001, 0x00104001, 0x00404041,
+               0x01041041, 0x01104411, 0x01111111, 0x04444445, 0x04511445,
+               0x05145145, 0x05151515, 0x05515455, 0x05551555, 0x05555555
+       };
+
+       static const unsigned int std_625_50[26] = {
+               0, 1, 1, 2,  3,  3,  4,  4,  5,  5,  6,  7,  7,
+                  8, 8, 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 0
+       };
+
+       static const unsigned int std_525_60[31] = {
+               0, 1, 1, 1, 2,  2,  3,  3,  4,  4,  5,  5,  6,  6, 7, 7,
+                  8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 0, 0
+       };
+
+       unsigned int i;
+
+       if (std & V4L2_STD_525_60) {
+               if (fps >= ARRAY_SIZE(std_525_60))
+                       fps = 30;
+               i = std_525_60[fps];
+       } else {
+               if (fps >= ARRAY_SIZE(std_625_50))
+                       fps = 25;
+               i = std_625_50[fps];
+       }
+
+       return map[i];
+}
+
+static void tw686x_set_framerate(struct tw686x_video_channel *vc,
+                                unsigned int fps)
+{
+       unsigned int map;
+
+       if (vc->fps == fps)
+               return;
+
+       map = tw686x_fields_map(vc->video_standard, fps) << 1;
+       map |= map << 1;
+       if (map > 0)
+               map |= BIT(31);
+       reg_write(vc->dev, VIDEO_FIELD_CTRL[vc->ch], map);
+       vc->fps = fps;
+}
+
+static const struct tw686x_format *format_by_fourcc(unsigned int fourcc)
+{
+       unsigned int cnt;
+
+       for (cnt = 0; cnt < ARRAY_SIZE(formats); cnt++)
+               if (formats[cnt].fourcc == fourcc)
+                       return &formats[cnt];
+       return NULL;
+}
+
+static int tw686x_queue_setup(struct vb2_queue *vq,
+                             unsigned int *nbuffers, unsigned int *nplanes,
+                             unsigned int sizes[], void *alloc_ctxs[])
+{
+       struct tw686x_video_channel *vc = vb2_get_drv_priv(vq);
+       unsigned int szimage =
+               (vc->width * vc->height * vc->format->depth) >> 3;
+
+       /*
+        * Let's request at least three buffers: two for the
+        * DMA engine and one for userspace.
+        */
+       if (vq->num_buffers + *nbuffers < 3)
+               *nbuffers = 3 - vq->num_buffers;
+
+       if (*nplanes) {
+               if (*nplanes != 1 || sizes[0] < szimage)
+                       return -EINVAL;
+               return 0;
+       }
+
+       sizes[0] = szimage;
+       *nplanes = 1;
+       return 0;
+}
+
+static void tw686x_buf_queue(struct vb2_buffer *vb)
+{
+       struct tw686x_video_channel *vc = vb2_get_drv_priv(vb->vb2_queue);
+       struct tw686x_dev *dev = vc->dev;
+       struct pci_dev *pci_dev;
+       unsigned long flags;
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+       struct tw686x_v4l2_buf *buf =
+               container_of(vbuf, struct tw686x_v4l2_buf, vb);
+
+       /* Check device presence */
+       spin_lock_irqsave(&dev->lock, flags);
+       pci_dev = dev->pci_dev;
+       spin_unlock_irqrestore(&dev->lock, flags);
+       if (!pci_dev) {
+               vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+               return;
+       }
+
+       spin_lock_irqsave(&vc->qlock, flags);
+       list_add_tail(&buf->list, &vc->vidq_queued);
+       spin_unlock_irqrestore(&vc->qlock, flags);
+}
+
+/*
+ * We can call this even when alloc_dma failed for the given channel
+ */
+static void tw686x_free_dma(struct tw686x_video_channel *vc, unsigned int pb)
+{
+       struct tw686x_dma_desc *desc = &vc->dma_descs[pb];
+       struct tw686x_dev *dev = vc->dev;
+       struct pci_dev *pci_dev;
+       unsigned long flags;
+
+       /* Check device presence. Shouldn't really happen! */
+       spin_lock_irqsave(&dev->lock, flags);
+       pci_dev = dev->pci_dev;
+       spin_unlock_irqrestore(&dev->lock, flags);
+       if (!pci_dev) {
+               WARN(1, "trying to deallocate on missing device\n");
+               return;
+       }
+
+       if (desc->virt) {
+               pci_free_consistent(dev->pci_dev, desc->size,
+                                   desc->virt, desc->phys);
+               desc->virt = NULL;
+       }
+}
+
+static int tw686x_alloc_dma(struct tw686x_video_channel *vc, unsigned int pb)
+{
+       struct tw686x_dev *dev = vc->dev;
+       u32 reg = pb ? VDMA_B_ADDR[vc->ch] : VDMA_P_ADDR[vc->ch];
+       unsigned int len;
+       void *virt;
+
+       WARN(vc->dma_descs[pb].virt,
+            "Allocating buffer but previous still here\n");
+
+       len = (vc->width * vc->height * vc->format->depth) >> 3;
+       virt = pci_alloc_consistent(dev->pci_dev, len,
+                                   &vc->dma_descs[pb].phys);
+       if (!virt) {
+               v4l2_err(&dev->v4l2_dev,
+                        "dma%d: unable to allocate %s-buffer\n",
+                        vc->ch, pb ? "B" : "P");
+               return -ENOMEM;
+       }
+       vc->dma_descs[pb].size = len;
+       vc->dma_descs[pb].virt = virt;
+       reg_write(dev, reg, vc->dma_descs[pb].phys);
+
+       return 0;
+}
+
+static void tw686x_buffer_refill(struct tw686x_video_channel *vc,
+                                unsigned int pb)
+{
+       struct tw686x_v4l2_buf *buf;
+
+       while (!list_empty(&vc->vidq_queued)) {
+
+               buf = list_first_entry(&vc->vidq_queued,
+                       struct tw686x_v4l2_buf, list);
+               list_del(&buf->list);
+
+               vc->curr_bufs[pb] = buf;
+               return;
+       }
+       vc->curr_bufs[pb] = NULL;
+}
+
+static void tw686x_clear_queue(struct tw686x_video_channel *vc,
+                              enum vb2_buffer_state state)
+{
+       unsigned int pb;
+
+       while (!list_empty(&vc->vidq_queued)) {
+               struct tw686x_v4l2_buf *buf;
+
+               buf = list_first_entry(&vc->vidq_queued,
+                       struct tw686x_v4l2_buf, list);
+               list_del(&buf->list);
+               vb2_buffer_done(&buf->vb.vb2_buf, state);
+       }
+
+       for (pb = 0; pb < 2; pb++) {
+               if (vc->curr_bufs[pb])
+                       vb2_buffer_done(&vc->curr_bufs[pb]->vb.vb2_buf, state);
+               vc->curr_bufs[pb] = NULL;
+       }
+}
+
+static int tw686x_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+       struct tw686x_video_channel *vc = vb2_get_drv_priv(vq);
+       struct tw686x_dev *dev = vc->dev;
+       struct pci_dev *pci_dev;
+       unsigned long flags;
+       int pb, err;
+
+       /* Check device presence */
+       spin_lock_irqsave(&dev->lock, flags);
+       pci_dev = dev->pci_dev;
+       spin_unlock_irqrestore(&dev->lock, flags);
+       if (!pci_dev) {
+               err = -ENODEV;
+               goto err_clear_queue;
+       }
+
+       spin_lock_irqsave(&vc->qlock, flags);
+
+       /* Sanity check */
+       if (!vc->dma_descs[0].virt || !vc->dma_descs[1].virt) {
+               spin_unlock_irqrestore(&vc->qlock, flags);
+               v4l2_err(&dev->v4l2_dev,
+                        "video%d: refusing to start without DMA buffers\n",
+                        vc->num);
+               err = -ENOMEM;
+               goto err_clear_queue;
+       }
+
+       for (pb = 0; pb < 2; pb++)
+               tw686x_buffer_refill(vc, pb);
+       spin_unlock_irqrestore(&vc->qlock, flags);
+
+       vc->sequence = 0;
+       vc->pb = 0;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       tw686x_enable_channel(dev, vc->ch);
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       mod_timer(&dev->dma_delay_timer, jiffies + msecs_to_jiffies(100));
+
+       return 0;
+
+err_clear_queue:
+       spin_lock_irqsave(&vc->qlock, flags);
+       tw686x_clear_queue(vc, VB2_BUF_STATE_QUEUED);
+       spin_unlock_irqrestore(&vc->qlock, flags);
+       return err;
+}
+
+static void tw686x_stop_streaming(struct vb2_queue *vq)
+{
+       struct tw686x_video_channel *vc = vb2_get_drv_priv(vq);
+       struct tw686x_dev *dev = vc->dev;
+       struct pci_dev *pci_dev;
+       unsigned long flags;
+
+       /* Check device presence */
+       spin_lock_irqsave(&dev->lock, flags);
+       pci_dev = dev->pci_dev;
+       spin_unlock_irqrestore(&dev->lock, flags);
+       if (pci_dev)
+               tw686x_disable_channel(dev, vc->ch);
+
+       spin_lock_irqsave(&vc->qlock, flags);
+       tw686x_clear_queue(vc, VB2_BUF_STATE_ERROR);
+       spin_unlock_irqrestore(&vc->qlock, flags);
+}
+
+static int tw686x_buf_prepare(struct vb2_buffer *vb)
+{
+       struct tw686x_video_channel *vc = vb2_get_drv_priv(vb->vb2_queue);
+       unsigned int size =
+               (vc->width * vc->height * vc->format->depth) >> 3;
+
+       if (vb2_plane_size(vb, 0) < size)
+               return -EINVAL;
+       vb2_set_plane_payload(vb, 0, size);
+       return 0;
+}
+
+static struct vb2_ops tw686x_video_qops = {
+       .queue_setup            = tw686x_queue_setup,
+       .buf_queue              = tw686x_buf_queue,
+       .buf_prepare            = tw686x_buf_prepare,
+       .start_streaming        = tw686x_start_streaming,
+       .stop_streaming         = tw686x_stop_streaming,
+       .wait_prepare           = vb2_ops_wait_prepare,
+       .wait_finish            = vb2_ops_wait_finish,
+};
+
+static int tw686x_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct tw686x_video_channel *vc;
+       struct tw686x_dev *dev;
+       unsigned int ch;
+
+       vc = container_of(ctrl->handler, struct tw686x_video_channel,
+                         ctrl_handler);
+       dev = vc->dev;
+       ch = vc->ch;
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               reg_write(dev, BRIGHT[ch], ctrl->val & 0xff);
+               return 0;
+
+       case V4L2_CID_CONTRAST:
+               reg_write(dev, CONTRAST[ch], ctrl->val);
+               return 0;
+
+       case V4L2_CID_SATURATION:
+               reg_write(dev, SAT_U[ch], ctrl->val);
+               reg_write(dev, SAT_V[ch], ctrl->val);
+               return 0;
+
+       case V4L2_CID_HUE:
+               reg_write(dev, HUE[ch], ctrl->val & 0xff);
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static const struct v4l2_ctrl_ops ctrl_ops = {
+       .s_ctrl = tw686x_s_ctrl,
+};
+
+static int tw686x_g_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct tw686x_video_channel *vc = video_drvdata(file);
+
+       f->fmt.pix.width = vc->width;
+       f->fmt.pix.height = vc->height;
+       f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+       f->fmt.pix.pixelformat = vc->format->fourcc;
+       f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+       f->fmt.pix.bytesperline = (f->fmt.pix.width * vc->format->depth) / 8;
+       f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+       return 0;
+}
+
+static int tw686x_try_fmt_vid_cap(struct file *file, void *priv,
+                                 struct v4l2_format *f)
+{
+       struct tw686x_video_channel *vc = video_drvdata(file);
+       unsigned int video_height = TW686X_VIDEO_HEIGHT(vc->video_standard);
+       const struct tw686x_format *format;
+
+       format = format_by_fourcc(f->fmt.pix.pixelformat);
+       if (!format) {
+               format = &formats[0];
+               f->fmt.pix.pixelformat = format->fourcc;
+       }
+
+       if (f->fmt.pix.width <= TW686X_VIDEO_WIDTH / 2)
+               f->fmt.pix.width = TW686X_VIDEO_WIDTH / 2;
+       else
+               f->fmt.pix.width = TW686X_VIDEO_WIDTH;
+
+       if (f->fmt.pix.height <= video_height / 2)
+               f->fmt.pix.height = video_height / 2;
+       else
+               f->fmt.pix.height = video_height;
+
+       f->fmt.pix.bytesperline = (f->fmt.pix.width * format->depth) / 8;
+       f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+       f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+       f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+       return 0;
+}
+
+static int tw686x_s_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct tw686x_video_channel *vc = video_drvdata(file);
+       u32 val, width, line_width, height;
+       unsigned long bitsperframe;
+       int err, pb;
+
+       if (vb2_is_busy(&vc->vidq))
+               return -EBUSY;
+
+       bitsperframe = vc->width * vc->height * vc->format->depth;
+       err = tw686x_try_fmt_vid_cap(file, priv, f);
+       if (err)
+               return err;
+
+       vc->format = format_by_fourcc(f->fmt.pix.pixelformat);
+       vc->width = f->fmt.pix.width;
+       vc->height = f->fmt.pix.height;
+
+       /* We need new DMA buffers if the framesize has changed */
+       if (bitsperframe != vc->width * vc->height * vc->format->depth) {
+               for (pb = 0; pb < 2; pb++)
+                       tw686x_free_dma(vc, pb);
+
+               for (pb = 0; pb < 2; pb++) {
+                       err = tw686x_alloc_dma(vc, pb);
+                       if (err) {
+                               if (pb > 0)
+                                       tw686x_free_dma(vc, 0);
+                               return err;
+                       }
+               }
+       }
+
+       val = reg_read(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch]);
+
+       if (vc->width <= TW686X_VIDEO_WIDTH / 2)
+               val |= BIT(23);
+       else
+               val &= ~BIT(23);
+
+       if (vc->height <= TW686X_VIDEO_HEIGHT(vc->video_standard) / 2)
+               val |= BIT(24);
+       else
+               val &= ~BIT(24);
+
+       val &= ~(0x7 << 20);
+       val |= vc->format->mode << 20;
+       reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], val);
+
+       /* Program the DMA frame size */
+       width = (vc->width * 2) & 0x7ff;
+       height = vc->height / 2;
+       line_width = (vc->width * 2) & 0x7ff;
+       val = (height << 22) | (line_width << 11)  | width;
+       reg_write(vc->dev, VDMA_WHP[vc->ch], val);
+       return 0;
+}
+
+static int tw686x_querycap(struct file *file, void *priv,
+                          struct v4l2_capability *cap)
+{
+       struct tw686x_video_channel *vc = video_drvdata(file);
+       struct tw686x_dev *dev = vc->dev;
+
+       strlcpy(cap->driver, "tw686x", sizeof(cap->driver));
+       strlcpy(cap->card, dev->name, sizeof(cap->card));
+       snprintf(cap->bus_info, sizeof(cap->bus_info),
+                "PCI:%s", pci_name(dev->pci_dev));
+       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+                          V4L2_CAP_READWRITE;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+       return 0;
+}
+
+static int tw686x_s_std(struct file *file, void *priv, v4l2_std_id id)
+{
+       struct tw686x_video_channel *vc = video_drvdata(file);
+       struct v4l2_format f;
+       u32 val, ret;
+
+       if (vc->video_standard == id)
+               return 0;
+
+       if (vb2_is_busy(&vc->vidq))
+               return -EBUSY;
+
+       if (id & V4L2_STD_NTSC)
+               val = 0;
+       else if (id & V4L2_STD_PAL)
+               val = 1;
+       else if (id & V4L2_STD_SECAM)
+               val = 2;
+       else if (id & V4L2_STD_NTSC_443)
+               val = 3;
+       else if (id & V4L2_STD_PAL_M)
+               val = 4;
+       else if (id & V4L2_STD_PAL_Nc)
+               val = 5;
+       else if (id & V4L2_STD_PAL_60)
+               val = 6;
+       else
+               return -EINVAL;
+
+       vc->video_standard = id;
+       reg_write(vc->dev, SDT[vc->ch], val);
+
+       val = reg_read(vc->dev, VIDEO_CONTROL1);
+       if (id & V4L2_STD_525_60)
+               val &= ~(1 << (SYS_MODE_DMA_SHIFT + vc->ch));
+       else
+               val |= (1 << (SYS_MODE_DMA_SHIFT + vc->ch));
+       reg_write(vc->dev, VIDEO_CONTROL1, val);
+
+       /*
+        * Adjust format after V4L2_STD_525_60/V4L2_STD_625_50 change,
+        * calling g_fmt and s_fmt will sanitize the height
+        * according to the standard.
+        */
+       ret = tw686x_g_fmt_vid_cap(file, priv, &f);
+       if (!ret)
+               tw686x_s_fmt_vid_cap(file, priv, &f);
+       return 0;
+}
+
+static int tw686x_querystd(struct file *file, void *priv, v4l2_std_id *std)
+{
+       struct tw686x_video_channel *vc = video_drvdata(file);
+       struct tw686x_dev *dev = vc->dev;
+       unsigned int old_std, detected_std = 0;
+       unsigned long end;
+
+       if (vb2_is_streaming(&vc->vidq))
+               return -EBUSY;
+
+       /* Enable and start standard detection */
+       old_std = reg_read(dev, SDT[vc->ch]);
+       reg_write(dev, SDT[vc->ch], 0x7);
+       reg_write(dev, SDT_EN[vc->ch], 0xff);
+
+       end = jiffies + msecs_to_jiffies(500);
+       while (time_is_after_jiffies(end)) {
+
+               detected_std = reg_read(dev, SDT[vc->ch]);
+               if (!(detected_std & BIT(7)))
+                       break;
+               msleep(100);
+       }
+       reg_write(dev, SDT[vc->ch], old_std);
+
+       /* Exit if still busy */
+       if (detected_std & BIT(7))
+               return 0;
+
+       detected_std = (detected_std >> 4) & 0x7;
+       switch (detected_std) {
+       case TW686X_STD_NTSC_M:
+               *std &= V4L2_STD_NTSC;
+               break;
+       case TW686X_STD_NTSC_443:
+               *std &= V4L2_STD_NTSC_443;
+               break;
+       case TW686X_STD_PAL_M:
+               *std &= V4L2_STD_PAL_M;
+               break;
+       case TW686X_STD_PAL_60:
+               *std &= V4L2_STD_PAL_60;
+               break;
+       case TW686X_STD_PAL:
+               *std &= V4L2_STD_PAL;
+               break;
+       case TW686X_STD_PAL_CN:
+               *std &= V4L2_STD_PAL_Nc;
+               break;
+       case TW686X_STD_SECAM:
+               *std &= V4L2_STD_SECAM;
+               break;
+       default:
+               *std = 0;
+       }
+       return 0;
+}
+
+static int tw686x_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct tw686x_video_channel *vc = video_drvdata(file);
+
+       *id = vc->video_standard;
+       return 0;
+}
+
+static int tw686x_enum_fmt_vid_cap(struct file *file, void *priv,
+                                  struct v4l2_fmtdesc *f)
+{
+       if (f->index >= ARRAY_SIZE(formats))
+               return -EINVAL;
+       f->pixelformat = formats[f->index].fourcc;
+       return 0;
+}
+
+static int tw686x_s_input(struct file *file, void *priv, unsigned int i)
+{
+       struct tw686x_video_channel *vc = video_drvdata(file);
+       u32 val;
+
+       if (i >= TW686X_INPUTS_PER_CH)
+               return -EINVAL;
+       if (i == vc->input)
+               return 0;
+       /*
+        * Not sure we are able to support on the fly input change
+        */
+       if (vb2_is_busy(&vc->vidq))
+               return -EBUSY;
+
+       vc->input = i;
+
+       val = reg_read(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch]);
+       val &= ~(0x3 << 30);
+       val |= i << 30;
+       reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], val);
+       return 0;
+}
+
+static int tw686x_g_input(struct file *file, void *priv, unsigned int *i)
+{
+       struct tw686x_video_channel *vc = video_drvdata(file);
+
+       *i = vc->input;
+       return 0;
+}
+
+static int tw686x_enum_input(struct file *file, void *priv,
+                            struct v4l2_input *i)
+{
+       struct tw686x_video_channel *vc = video_drvdata(file);
+       unsigned int vidstat;
+
+       if (i->index >= TW686X_INPUTS_PER_CH)
+               return -EINVAL;
+
+       snprintf(i->name, sizeof(i->name), "Composite%d", i->index);
+       i->type = V4L2_INPUT_TYPE_CAMERA;
+       i->std = vc->device->tvnorms;
+       i->capabilities = V4L2_IN_CAP_STD;
+
+       vidstat = reg_read(vc->dev, VIDSTAT[vc->ch]);
+       i->status = 0;
+       if (vidstat & TW686X_VIDSTAT_VDLOSS)
+               i->status |= V4L2_IN_ST_NO_SIGNAL;
+       if (!(vidstat & TW686X_VIDSTAT_HLOCK))
+               i->status |= V4L2_IN_ST_NO_H_LOCK;
+
+       return 0;
+}
+
+static const struct v4l2_file_operations tw686x_video_fops = {
+       .owner          = THIS_MODULE,
+       .open           = v4l2_fh_open,
+       .unlocked_ioctl = video_ioctl2,
+       .release        = vb2_fop_release,
+       .poll           = vb2_fop_poll,
+       .read           = vb2_fop_read,
+       .mmap           = vb2_fop_mmap,
+};
+
+static const struct v4l2_ioctl_ops tw686x_video_ioctl_ops = {
+       .vidioc_querycap                = tw686x_querycap,
+       .vidioc_g_fmt_vid_cap           = tw686x_g_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap           = tw686x_s_fmt_vid_cap,
+       .vidioc_enum_fmt_vid_cap        = tw686x_enum_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap         = tw686x_try_fmt_vid_cap,
+
+       .vidioc_querystd                = tw686x_querystd,
+       .vidioc_g_std                   = tw686x_g_std,
+       .vidioc_s_std                   = tw686x_s_std,
+
+       .vidioc_enum_input              = tw686x_enum_input,
+       .vidioc_g_input                 = tw686x_g_input,
+       .vidioc_s_input                 = tw686x_s_input,
+
+       .vidioc_reqbufs                 = vb2_ioctl_reqbufs,
+       .vidioc_querybuf                = vb2_ioctl_querybuf,
+       .vidioc_qbuf                    = vb2_ioctl_qbuf,
+       .vidioc_dqbuf                   = vb2_ioctl_dqbuf,
+       .vidioc_create_bufs             = vb2_ioctl_create_bufs,
+       .vidioc_streamon                = vb2_ioctl_streamon,
+       .vidioc_streamoff               = vb2_ioctl_streamoff,
+       .vidioc_prepare_buf             = vb2_ioctl_prepare_buf,
+
+       .vidioc_log_status              = v4l2_ctrl_log_status,
+       .vidioc_subscribe_event         = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
+};
+
+static void tw686x_buffer_copy(struct tw686x_video_channel *vc,
+                              unsigned int pb, struct vb2_v4l2_buffer *vb)
+{
+       struct tw686x_dma_desc *desc = &vc->dma_descs[pb];
+       struct vb2_buffer *vb2_buf = &vb->vb2_buf;
+
+       vb->field = V4L2_FIELD_INTERLACED;
+       vb->sequence = vc->sequence++;
+
+       memcpy(vb2_plane_vaddr(vb2_buf, 0), desc->virt, desc->size);
+       vb2_buf->timestamp = ktime_get_ns();
+       vb2_buffer_done(vb2_buf, VB2_BUF_STATE_DONE);
+}
+
+void tw686x_video_irq(struct tw686x_dev *dev, unsigned long requests,
+                     unsigned int pb_status, unsigned int fifo_status,
+                     unsigned int *reset_ch)
+{
+       struct tw686x_video_channel *vc;
+       struct vb2_v4l2_buffer *vb;
+       unsigned long flags;
+       unsigned int ch, pb;
+
+       for_each_set_bit(ch, &requests, max_channels(dev)) {
+               vc = &dev->video_channels[ch];
+
+               /*
+                * This can either be a blue frame (with signal-lost bit set)
+                * or a good frame (with signal-lost bit clear). If we have just
+                * got signal, then this channel needs resetting.
+                */
+               if (vc->no_signal && !(fifo_status & BIT(ch))) {
+                       v4l2_printk(KERN_DEBUG, &dev->v4l2_dev,
+                                   "video%d: signal recovered\n", vc->num);
+                       vc->no_signal = false;
+                       *reset_ch |= BIT(ch);
+                       vc->pb = 0;
+                       continue;
+               }
+               vc->no_signal = !!(fifo_status & BIT(ch));
+
+               /* Check FIFO errors only if there's signal */
+               if (!vc->no_signal) {
+                       u32 fifo_ov, fifo_bad;
+
+                       fifo_ov = (fifo_status >> 24) & BIT(ch);
+                       fifo_bad = (fifo_status >> 16) & BIT(ch);
+                       if (fifo_ov || fifo_bad) {
+                               /* Mark this channel for reset */
+                               v4l2_printk(KERN_DEBUG, &dev->v4l2_dev,
+                                           "video%d: FIFO error\n", vc->num);
+                               *reset_ch |= BIT(ch);
+                               vc->pb = 0;
+                               continue;
+                       }
+               }
+
+               pb = !!(pb_status & BIT(ch));
+               if (vc->pb != pb) {
+                       /* Mark this channel for reset */
+                       v4l2_printk(KERN_DEBUG, &dev->v4l2_dev,
+                                   "video%d: unexpected p-b buffer!\n",
+                                   vc->num);
+                       *reset_ch |= BIT(ch);
+                       vc->pb = 0;
+                       continue;
+               }
+
+               /* handle video stream */
+               spin_lock_irqsave(&vc->qlock, flags);
+               if (vc->curr_bufs[pb]) {
+                       vb = &vc->curr_bufs[pb]->vb;
+                       tw686x_buffer_copy(vc, pb, vb);
+               }
+               vc->pb = !pb;
+               tw686x_buffer_refill(vc, pb);
+               spin_unlock_irqrestore(&vc->qlock, flags);
+       }
+}
+
+void tw686x_video_free(struct tw686x_dev *dev)
+{
+       unsigned int ch, pb;
+
+       for (ch = 0; ch < max_channels(dev); ch++) {
+               struct tw686x_video_channel *vc = &dev->video_channels[ch];
+
+               if (vc->device)
+                       video_unregister_device(vc->device);
+
+               for (pb = 0; pb < 2; pb++)
+                       tw686x_free_dma(vc, pb);
+       }
+}
+
+int tw686x_video_init(struct tw686x_dev *dev)
+{
+       unsigned int ch, val, pb;
+       int err;
+
+       err = v4l2_device_register(&dev->pci_dev->dev, &dev->v4l2_dev);
+       if (err)
+               return err;
+
+       for (ch = 0; ch < max_channels(dev); ch++) {
+               struct tw686x_video_channel *vc = &dev->video_channels[ch];
+               struct video_device *vdev;
+
+               mutex_init(&vc->vb_mutex);
+               spin_lock_init(&vc->qlock);
+               INIT_LIST_HEAD(&vc->vidq_queued);
+
+               vc->dev = dev;
+               vc->ch = ch;
+
+               /* default settings */
+               vc->format = &formats[0];
+               vc->video_standard = V4L2_STD_NTSC;
+               vc->width = TW686X_VIDEO_WIDTH;
+               vc->height = TW686X_VIDEO_HEIGHT(vc->video_standard);
+               vc->input = 0;
+
+               reg_write(vc->dev, SDT[ch], 0);
+               tw686x_set_framerate(vc, 30);
+
+               reg_write(dev, VDELAY_LO[ch], 0x14);
+               reg_write(dev, HACTIVE_LO[ch], 0xd0);
+               reg_write(dev, VIDEO_SIZE[ch], 0);
+
+               for (pb = 0; pb < 2; pb++) {
+                       err = tw686x_alloc_dma(vc, pb);
+                       if (err)
+                               goto error;
+               }
+
+               vc->vidq.io_modes = VB2_READ | VB2_MMAP | VB2_DMABUF;
+               vc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               vc->vidq.drv_priv = vc;
+               vc->vidq.buf_struct_size = sizeof(struct tw686x_v4l2_buf);
+               vc->vidq.ops = &tw686x_video_qops;
+               vc->vidq.mem_ops = &vb2_vmalloc_memops;
+               vc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+               vc->vidq.min_buffers_needed = 2;
+               vc->vidq.lock = &vc->vb_mutex;
+               vc->vidq.gfp_flags = GFP_DMA32;
+
+               err = vb2_queue_init(&vc->vidq);
+               if (err) {
+                       v4l2_err(&dev->v4l2_dev,
+                                "dma%d: cannot init vb2 queue\n", ch);
+                       goto error;
+               }
+
+               err = v4l2_ctrl_handler_init(&vc->ctrl_handler, 4);
+               if (err) {
+                       v4l2_err(&dev->v4l2_dev,
+                                "dma%d: cannot init ctrl handler\n", ch);
+                       goto error;
+               }
+               v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops,
+                                 V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
+               v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops,
+                                 V4L2_CID_CONTRAST, 0, 255, 1, 100);
+               v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops,
+                                 V4L2_CID_SATURATION, 0, 255, 1, 128);
+               v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops,
+                                 V4L2_CID_HUE, -128, 127, 1, 0);
+               err = vc->ctrl_handler.error;
+               if (err)
+                       goto error;
+
+               err = v4l2_ctrl_handler_setup(&vc->ctrl_handler);
+               if (err)
+                       goto error;
+
+               vdev = video_device_alloc();
+               if (!vdev) {
+                       v4l2_err(&dev->v4l2_dev,
+                                "dma%d: unable to allocate device\n", ch);
+                       err = -ENOMEM;
+                       goto error;
+               }
+
+               snprintf(vdev->name, sizeof(vdev->name), "%s video", dev->name);
+               vdev->fops = &tw686x_video_fops;
+               vdev->ioctl_ops = &tw686x_video_ioctl_ops;
+               vdev->release = video_device_release;
+               vdev->v4l2_dev = &dev->v4l2_dev;
+               vdev->queue = &vc->vidq;
+               vdev->tvnorms = V4L2_STD_525_60 | V4L2_STD_625_50;
+               vdev->minor = -1;
+               vdev->lock = &vc->vb_mutex;
+               vdev->ctrl_handler = &vc->ctrl_handler;
+               vc->device = vdev;
+               video_set_drvdata(vdev, vc);
+
+               err = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+               if (err < 0)
+                       goto error;
+               vc->num = vdev->num;
+       }
+
+       /* Set DMA frame mode on all channels. Only supported mode for now. */
+       val = TW686X_DEF_PHASE_REF;
+       for (ch = 0; ch < max_channels(dev); ch++)
+               val |= TW686X_FRAME_MODE << (16 + ch * 2);
+       reg_write(dev, PHASE_REF, val);
+
+       reg_write(dev, MISC2[0], 0xe7);
+       reg_write(dev, VCTRL1[0], 0xcc);
+       reg_write(dev, LOOP[0], 0xa5);
+       if (max_channels(dev) > 4) {
+               reg_write(dev, VCTRL1[1], 0xcc);
+               reg_write(dev, LOOP[1], 0xa5);
+               reg_write(dev, MISC2[1], 0xe7);
+       }
+       return 0;
+
+error:
+       tw686x_video_free(dev);
+       return err;
+}
diff --git a/drivers/media/pci/tw686x/tw686x.h b/drivers/media/pci/tw686x/tw686x.h
new file mode 100644 (file)
index 0000000..44b5755
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2015 VanguardiaSur - www.vanguardiasur.com.ar
+ *
+ * Copyright (C) 2015 Industrial Research Institute for Automation
+ * and Measurements PIAP
+ * Written by Krzysztof Ha?asa
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/mutex.h>
+#include <linux/pci.h>
+#include <linux/timer.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-v4l2.h>
+#include <sound/pcm.h>
+
+#include "tw686x-regs.h"
+
+#define TYPE_MAX_CHANNELS      0x0f
+#define TYPE_SECOND_GEN                0x10
+#define TW686X_DEF_PHASE_REF   0x1518
+
+#define TW686X_FIELD_MODE      0x3
+#define TW686X_FRAME_MODE      0x2
+/* 0x1 is reserved */
+#define TW686X_SG_MODE         0x0
+
+#define TW686X_AUDIO_PAGE_SZ           4096
+#define TW686X_AUDIO_PAGE_MAX          16
+#define TW686X_AUDIO_PERIODS_MIN       2
+#define TW686X_AUDIO_PERIODS_MAX       TW686X_AUDIO_PAGE_MAX
+
+struct tw686x_format {
+       char *name;
+       unsigned int fourcc;
+       unsigned int depth;
+       unsigned int mode;
+};
+
+struct tw686x_dma_desc {
+       dma_addr_t phys;
+       void *virt;
+       unsigned int size;
+};
+
+struct tw686x_audio_buf {
+       dma_addr_t dma;
+       void *virt;
+       struct list_head list;
+};
+
+struct tw686x_v4l2_buf {
+       struct vb2_v4l2_buffer vb;
+       struct list_head list;
+};
+
+struct tw686x_audio_channel {
+       struct tw686x_dev *dev;
+       struct snd_pcm_substream *ss;
+       unsigned int ch;
+       struct tw686x_audio_buf *curr_bufs[2];
+       struct tw686x_dma_desc dma_descs[2];
+       dma_addr_t ptr;
+
+       struct tw686x_audio_buf buf[TW686X_AUDIO_PAGE_MAX];
+       struct list_head buf_list;
+       spinlock_t lock;
+};
+
+struct tw686x_video_channel {
+       struct tw686x_dev *dev;
+
+       struct vb2_queue vidq;
+       struct list_head vidq_queued;
+       struct video_device *device;
+       struct tw686x_v4l2_buf *curr_bufs[2];
+       struct tw686x_dma_desc dma_descs[2];
+
+       struct v4l2_ctrl_handler ctrl_handler;
+       const struct tw686x_format *format;
+       struct mutex vb_mutex;
+       spinlock_t qlock;
+       v4l2_std_id video_standard;
+       unsigned int width, height;
+       unsigned int h_halve, v_halve;
+       unsigned int ch;
+       unsigned int num;
+       unsigned int fps;
+       unsigned int input;
+       unsigned int sequence;
+       unsigned int pb;
+       bool no_signal;
+};
+
+/**
+ * struct tw686x_dev - global device status
+ * @lock: spinlock controlling access to the
+ *        shared device registers (DMA enable/disable).
+ */
+struct tw686x_dev {
+       spinlock_t lock;
+
+       struct v4l2_device v4l2_dev;
+       struct snd_card *snd_card;
+
+       char name[32];
+       unsigned int type;
+       struct pci_dev *pci_dev;
+       __u32 __iomem *mmio;
+
+       void *alloc_ctx;
+
+       struct tw686x_video_channel *video_channels;
+       struct tw686x_audio_channel *audio_channels;
+
+       int audio_rate; /* per-device value */
+
+       struct timer_list dma_delay_timer;
+       u32 pending_dma_en; /* must be protected by lock */
+       u32 pending_dma_cmd; /* must be protected by lock */
+};
+
+static inline uint32_t reg_read(struct tw686x_dev *dev, unsigned int reg)
+{
+       return readl(dev->mmio + reg);
+}
+
+static inline void reg_write(struct tw686x_dev *dev, unsigned int reg,
+                            uint32_t value)
+{
+       writel(value, dev->mmio + reg);
+}
+
+static inline unsigned int max_channels(struct tw686x_dev *dev)
+{
+       return dev->type & TYPE_MAX_CHANNELS; /* 4 or 8 channels */
+}
+
+void tw686x_enable_channel(struct tw686x_dev *dev, unsigned int channel);
+void tw686x_disable_channel(struct tw686x_dev *dev, unsigned int channel);
+
+int tw686x_video_init(struct tw686x_dev *dev);
+void tw686x_video_free(struct tw686x_dev *dev);
+void tw686x_video_irq(struct tw686x_dev *dev, unsigned long requests,
+                     unsigned int pb_status, unsigned int fifo_status,
+                     unsigned int *reset_ch);
+
+int tw686x_audio_init(struct tw686x_dev *dev);
+void tw686x_audio_free(struct tw686x_dev *dev);
+void tw686x_audio_irq(struct tw686x_dev *dev, unsigned long requests,
+                     unsigned int pb_status);
index c010716..13a3c07 100644 (file)
@@ -116,8 +116,9 @@ videocodec_attach (struct videocodec_master *master)
                                goto out_module_put;
                        }
 
-                       snprintf(codec->name, sizeof(codec->name),
-                                "%s[%d]", codec->name, h->attached);
+                       res = strlen(codec->name);
+                       snprintf(codec->name + res, sizeof(codec->name) - res,
+                                "[%d]", h->attached);
                        codec->master_data = master;
                        res = codec->setup(codec);
                        if (res == 0) {
index 201f5c2..84e041c 100644 (file)
@@ -238,7 +238,7 @@ config VIDEO_SH_VEU
 config VIDEO_RENESAS_JPU
        tristate "Renesas JPEG Processing Unit"
        depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
-       depends on ARCH_SHMOBILE || COMPILE_TEST
+       depends on ARCH_RENESAS || COMPILE_TEST
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        ---help---
@@ -250,7 +250,7 @@ config VIDEO_RENESAS_JPU
 config VIDEO_RENESAS_VSP1
        tristate "Renesas VSP1 Video Processing Engine"
        depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA
-       depends on (ARCH_SHMOBILE && OF) || COMPILE_TEST
+       depends on (ARCH_RENESAS && OF) || COMPILE_TEST
        select VIDEOBUF2_DMA_CONTIG
        ---help---
          This is a V4L2 driver for the Renesas VSP1 video processing engine.
index de32e3a..e749eb7 100644 (file)
@@ -1047,7 +1047,7 @@ static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe,
 static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe)
 {
        enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED;
-       int ret;
+       int ret = 0;
 
        vpfe_dbg(2, vpfe, "vpfe_config_ccdc_image_format\n");
 
@@ -1706,7 +1706,7 @@ static int vpfe_get_app_input_index(struct vpfe_device *vpfe,
                sdinfo = &cfg->sub_devs[i];
                client = v4l2_get_subdevdata(sdinfo->sd);
                if (client->addr == curr_client->addr &&
-                   client->adapter->nr == client->adapter->nr) {
+                   client->adapter->nr == curr_client->adapter->nr) {
                        if (vpfe->current_input >= 1)
                                return -1;
                        *app_input_index = j + vpfe->current_input;
index 9b9e423..c049736 100644 (file)
@@ -967,15 +967,6 @@ static struct gsc_driverdata gsc_v_100_drvdata = {
        .lclk_frequency = 266000000UL,
 };
 
-static const struct platform_device_id gsc_driver_ids[] = {
-       {
-               .name           = "exynos-gsc",
-               .driver_data    = (unsigned long)&gsc_v_100_drvdata,
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(platform, gsc_driver_ids);
-
 static const struct of_device_id exynos_gsc_match[] = {
        {
                .compatible = "samsung,exynos5-gsc",
@@ -988,17 +979,11 @@ MODULE_DEVICE_TABLE(of, exynos_gsc_match);
 static void *gsc_get_drv_data(struct platform_device *pdev)
 {
        struct gsc_driverdata *driver_data = NULL;
+       const struct of_device_id *match;
 
-       if (pdev->dev.of_node) {
-               const struct of_device_id *match;
-               match = of_match_node(exynos_gsc_match,
-                                       pdev->dev.of_node);
-               if (match)
-                       driver_data = (struct gsc_driverdata *)match->data;
-       } else {
-               driver_data = (struct gsc_driverdata *)
-                       platform_get_device_id(pdev)->driver_data;
-       }
+       match = of_match_node(exynos_gsc_match, pdev->dev.of_node);
+       if (match)
+               driver_data = (struct gsc_driverdata *)match->data;
 
        return driver_data;
 }
@@ -1078,17 +1063,17 @@ static int gsc_probe(struct platform_device *pdev)
        struct resource *res;
        struct gsc_driverdata *drv_data = gsc_get_drv_data(pdev);
        struct device *dev = &pdev->dev;
-       int ret = 0;
+       int ret;
 
        gsc = devm_kzalloc(dev, sizeof(struct gsc_dev), GFP_KERNEL);
        if (!gsc)
                return -ENOMEM;
 
-       if (dev->of_node)
-               gsc->id = of_alias_get_id(pdev->dev.of_node, "gsc");
-       else
-               gsc->id = pdev->id;
+       ret = of_alias_get_id(pdev->dev.of_node, "gsc");
+       if (ret < 0)
+               return ret;
 
+       gsc->id = ret;
        if (gsc->id >= drv_data->num_entities) {
                dev_err(dev, "Invalid platform device id: %d\n", gsc->id);
                return -EINVAL;
@@ -1096,7 +1081,6 @@ static int gsc_probe(struct platform_device *pdev)
 
        gsc->variant = drv_data->variant[gsc->id];
        gsc->pdev = pdev;
-       gsc->pdata = dev->platform_data;
 
        init_waitqueue_head(&gsc->irq_queue);
        spin_lock_init(&gsc->slock);
@@ -1253,7 +1237,6 @@ static const struct dev_pm_ops gsc_pm_ops = {
 static struct platform_driver gsc_driver = {
        .probe          = gsc_probe,
        .remove         = gsc_remove,
-       .id_table       = gsc_driver_ids,
        .driver = {
                .name   = GSC_MODULE_NAME,
                .pm     = &gsc_pm_ops,
index e93a233..ec4000c 100644 (file)
@@ -340,7 +340,6 @@ struct gsc_dev {
        void __iomem                    *regs;
        wait_queue_head_t               irq_queue;
        struct gsc_m2m_device           m2m;
-       struct exynos_platform_gscaler  *pdata;
        unsigned long                   state;
        struct vb2_alloc_ctx            *alloc_ctx;
        struct video_device             vdev;
index cef2a7f..b1c1cea 100644 (file)
@@ -1154,26 +1154,6 @@ static const struct fimc_pix_limit s5p_pix_limit[4] = {
        },
 };
 
-static const struct fimc_variant fimc0_variant_s5p = {
-       .has_inp_rot     = 1,
-       .has_out_rot     = 1,
-       .has_cam_if      = 1,
-       .min_inp_pixsize = 16,
-       .min_out_pixsize = 16,
-       .hor_offs_align  = 8,
-       .min_vsize_align = 16,
-       .pix_limit       = &s5p_pix_limit[0],
-};
-
-static const struct fimc_variant fimc2_variant_s5p = {
-       .has_cam_if      = 1,
-       .min_inp_pixsize = 16,
-       .min_out_pixsize = 16,
-       .hor_offs_align  = 8,
-       .min_vsize_align = 16,
-       .pix_limit       = &s5p_pix_limit[1],
-};
-
 static const struct fimc_variant fimc0_variant_s5pv210 = {
        .has_inp_rot     = 1,
        .has_out_rot     = 1,
@@ -1206,18 +1186,6 @@ static const struct fimc_variant fimc2_variant_s5pv210 = {
        .pix_limit       = &s5p_pix_limit[2],
 };
 
-/* S5PC100 */
-static const struct fimc_drvdata fimc_drvdata_s5p = {
-       .variant = {
-               [0] = &fimc0_variant_s5p,
-               [1] = &fimc0_variant_s5p,
-               [2] = &fimc2_variant_s5p,
-       },
-       .num_entities   = 3,
-       .lclk_frequency = 133000000UL,
-       .out_buf_count  = 4,
-};
-
 /* S5PV210, S5PC110 */
 static const struct fimc_drvdata fimc_drvdata_s5pv210 = {
        .variant = {
@@ -1251,23 +1219,6 @@ static const struct fimc_drvdata fimc_drvdata_exynos4x12 = {
        .out_buf_count  = 32,
 };
 
-static const struct platform_device_id fimc_driver_ids[] = {
-       {
-               .name           = "s5p-fimc",
-               .driver_data    = (unsigned long)&fimc_drvdata_s5p,
-       }, {
-               .name           = "s5pv210-fimc",
-               .driver_data    = (unsigned long)&fimc_drvdata_s5pv210,
-       }, {
-               .name           = "exynos4-fimc",
-               .driver_data    = (unsigned long)&fimc_drvdata_exynos4210,
-       }, {
-               .name           = "exynos4x12-fimc",
-               .driver_data    = (unsigned long)&fimc_drvdata_exynos4x12,
-       },
-       { },
-};
-
 static const struct of_device_id fimc_of_match[] = {
        {
                .compatible = "samsung,s5pv210-fimc",
@@ -1290,7 +1241,6 @@ static const struct dev_pm_ops fimc_pm_ops = {
 static struct platform_driver fimc_driver = {
        .probe          = fimc_probe,
        .remove         = fimc_remove,
-       .id_table       = fimc_driver_ids,
        .driver = {
                .of_match_table = fimc_of_match,
                .name           = FIMC_DRIVER_NAME,
index 4f494ac..891625e 100644 (file)
@@ -446,8 +446,10 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
        else
                pd->fimc_bus_type = pd->sensor_bus_type;
 
-       if (WARN_ON(index >= ARRAY_SIZE(fmd->sensor)))
+       if (WARN_ON(index >= ARRAY_SIZE(fmd->sensor))) {
+               of_node_put(rem);
                return -EINVAL;
+       }
 
        fmd->sensor[index].asd.match_type = V4L2_ASYNC_MATCH_OF;
        fmd->sensor[index].asd.match.of.node = rem;
@@ -1130,7 +1132,7 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
        media_entity_graph_walk_start(graph, entity);
 
        while ((entity = media_entity_graph_walk_next(graph))) {
-               if (!is_media_entity_v4l2_io(entity))
+               if (!is_media_entity_v4l2_video_device(entity))
                        continue;
 
                ret  = __fimc_md_modify_pipeline(entity, enable);
@@ -1145,7 +1147,7 @@ err:
        media_entity_graph_walk_start(graph, entity_err);
 
        while ((entity_err = media_entity_graph_walk_next(graph))) {
-               if (!is_media_entity_v4l2_io(entity_err))
+               if (!is_media_entity_v4l2_video_device(entity_err))
                        continue;
 
                __fimc_md_modify_pipeline(entity_err, !enable);
index bd5c46c..bf95442 100644 (file)
@@ -757,8 +757,10 @@ static int s5pcsis_parse_dt(struct platform_device *pdev,
                goto err;
 
        state->index = endpoint.base.port - FIMC_INPUT_MIPI_CSI2_0;
-       if (state->index >= CSIS_MAX_ENTITIES)
-               return -ENXIO;
+       if (state->index >= CSIS_MAX_ENTITIES) {
+               ret = -ENXIO;
+               goto err;
+       }
 
        /* Get MIPI CSI-2 bus configration from the endpoint node. */
        of_property_read_u32(node, "samsung,csis-hs-settle",
index ac76d29..1b1a95d 100644 (file)
@@ -251,7 +251,7 @@ static int isp_video_get_graph_data(struct isp_video *video,
                if (entity == &video->video.entity)
                        continue;
 
-               if (!is_media_entity_v4l2_io(entity))
+               if (!is_media_entity_v4l2_video_device(entity))
                        continue;
 
                __video = to_isp_video(media_entity_to_video_device(entity));
index 74bd46c..612d1ea 100644 (file)
@@ -719,16 +719,12 @@ static int g2d_probe(struct platform_device *pdev)
 
        def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3;
 
-       if (!pdev->dev.of_node) {
-               dev->variant = g2d_get_drv_data(pdev);
-       } else {
-               of_id = of_match_node(exynos_g2d_match, pdev->dev.of_node);
-               if (!of_id) {
-                       ret = -ENODEV;
-                       goto unreg_video_dev;
-               }
-               dev->variant = (struct g2d_variant *)of_id->data;
+       of_id = of_match_node(exynos_g2d_match, pdev->dev.of_node);
+       if (!of_id) {
+               ret = -ENODEV;
+               goto unreg_video_dev;
        }
+       dev->variant = (struct g2d_variant *)of_id->data;
 
        return 0;
 
@@ -788,22 +784,9 @@ static const struct of_device_id exynos_g2d_match[] = {
 };
 MODULE_DEVICE_TABLE(of, exynos_g2d_match);
 
-static const struct platform_device_id g2d_driver_ids[] = {
-       {
-               .name = "s5p-g2d",
-               .driver_data = (unsigned long)&g2d_drvdata_v3x,
-       }, {
-               .name = "s5p-g2d-v4x",
-               .driver_data = (unsigned long)&g2d_drvdata_v4x,
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(platform, g2d_driver_ids);
-
 static struct platform_driver g2d_pdrv = {
        .probe          = g2d_probe,
        .remove         = g2d_remove,
-       .id_table       = g2d_driver_ids,
        .driver         = {
                .name = G2D_NAME,
                .of_match_table = exynos_g2d_match,
index b0e52ab..e31df54 100644 (file)
@@ -89,8 +89,3 @@ void g2d_set_flip(struct g2d_dev *d, u32 r);
 void g2d_set_v41_stretch(struct g2d_dev *d,
                        struct g2d_frame *src, struct g2d_frame *dst);
 void g2d_set_cmd(struct g2d_dev *d, u32 c);
-
-static inline struct g2d_variant *g2d_get_drv_data(struct platform_device *pdev)
-{
-       return (struct g2d_variant *)platform_get_device_id(pdev)->driver_data;
-}
index c3b13a6..caa19b4 100644 (file)
@@ -1548,8 +1548,10 @@ static int exynos4_jpeg_get_output_buffer_size(struct s5p_jpeg_ctx *ctx,
        struct v4l2_pix_format *pix = &f->fmt.pix;
        u32 pix_fmt = f->fmt.pix.pixelformat;
        int w = pix->width, h = pix->height, wh_align;
+       int padding = 0;
 
        if (pix_fmt == V4L2_PIX_FMT_RGB32 ||
+           pix_fmt == V4L2_PIX_FMT_RGB565 ||
            pix_fmt == V4L2_PIX_FMT_NV24 ||
            pix_fmt == V4L2_PIX_FMT_NV42 ||
            pix_fmt == V4L2_PIX_FMT_NV12 ||
@@ -1564,7 +1566,10 @@ static int exynos4_jpeg_get_output_buffer_size(struct s5p_jpeg_ctx *ctx,
                               &h, S5P_JPEG_MIN_HEIGHT,
                               S5P_JPEG_MAX_HEIGHT, wh_align);
 
-       return w * h * fmt_depth >> 3;
+       if (ctx->jpeg->variant->version == SJPEG_EXYNOS4)
+               padding = PAGE_SIZE;
+
+       return (w * h * fmt_depth >> 3) + padding;
 }
 
 static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx,
index 927ab49..b16466f 100644 (file)
@@ -1489,27 +1489,6 @@ static struct s5p_mfc_variant mfc_drvdata_v8 = {
        .fw_name[0]     = "s5p-mfc-v8.fw",
 };
 
-static const struct platform_device_id mfc_driver_ids[] = {
-       {
-               .name = "s5p-mfc",
-               .driver_data = (unsigned long)&mfc_drvdata_v5,
-       }, {
-               .name = "s5p-mfc-v5",
-               .driver_data = (unsigned long)&mfc_drvdata_v5,
-       }, {
-               .name = "s5p-mfc-v6",
-               .driver_data = (unsigned long)&mfc_drvdata_v6,
-       }, {
-               .name = "s5p-mfc-v7",
-               .driver_data = (unsigned long)&mfc_drvdata_v7,
-       }, {
-               .name = "s5p-mfc-v8",
-               .driver_data = (unsigned long)&mfc_drvdata_v8,
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(platform, mfc_driver_ids);
-
 static const struct of_device_id exynos_mfc_match[] = {
        {
                .compatible = "samsung,mfc-v5",
@@ -1531,24 +1510,18 @@ MODULE_DEVICE_TABLE(of, exynos_mfc_match);
 static void *mfc_get_drv_data(struct platform_device *pdev)
 {
        struct s5p_mfc_variant *driver_data = NULL;
+       const struct of_device_id *match;
+
+       match = of_match_node(exynos_mfc_match, pdev->dev.of_node);
+       if (match)
+               driver_data = (struct s5p_mfc_variant *)match->data;
 
-       if (pdev->dev.of_node) {
-               const struct of_device_id *match;
-               match = of_match_node(exynos_mfc_match,
-                               pdev->dev.of_node);
-               if (match)
-                       driver_data = (struct s5p_mfc_variant *)match->data;
-       } else {
-               driver_data = (struct s5p_mfc_variant *)
-                       platform_get_device_id(pdev)->driver_data;
-       }
        return driver_data;
 }
 
 static struct platform_driver s5p_mfc_driver = {
        .probe          = s5p_mfc_probe,
        .remove         = s5p_mfc_remove,
-       .id_table       = mfc_driver_ids,
        .driver = {
                .name   = S5P_MFC_NAME,
                .pm     = &s5p_mfc_pm_ops,
index 42cd270..4dd62a9 100644 (file)
@@ -300,7 +300,7 @@ void mxr_release_video(struct mxr_device *mdev);
 struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx);
 struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx);
 struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
-       int idx, char *name, struct mxr_layer_ops *ops);
+       int idx, char *name, const struct mxr_layer_ops *ops);
 
 void mxr_base_layer_release(struct mxr_layer *layer);
 void mxr_layer_release(struct mxr_layer *layer);
index db3163b..d4d2564 100644 (file)
@@ -235,7 +235,7 @@ struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx)
 {
        struct mxr_layer *layer;
        int ret;
-       struct mxr_layer_ops ops = {
+       const struct mxr_layer_ops ops = {
                .release = mxr_graph_layer_release,
                .buffer_set = mxr_graph_buffer_set,
                .stream_set = mxr_graph_stream_set,
index d9e7f03..7ab5578 100644 (file)
@@ -1070,7 +1070,7 @@ static void mxr_vfd_release(struct video_device *vdev)
 }
 
 struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
-       int idx, char *name, struct mxr_layer_ops *ops)
+       int idx, char *name, const struct mxr_layer_ops *ops)
 {
        struct mxr_layer *layer;
 
index dd002a4..6fa6f67 100644 (file)
@@ -207,7 +207,7 @@ struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx)
 {
        struct mxr_layer *layer;
        int ret;
-       struct mxr_layer_ops ops = {
+       const struct mxr_layer_ops ops = {
                .release = mxr_vp_layer_release,
                .buffer_set = mxr_vp_buffer_set,
                .stream_set = mxr_vp_stream_set,
index 3552989..83029a4 100644 (file)
@@ -28,7 +28,7 @@ config VIDEO_PXA27x
 config VIDEO_RCAR_VIN
        tristate "R-Car Video Input (VIN) support"
        depends on VIDEO_DEV && SOC_CAMERA
-       depends on ARCH_SHMOBILE || COMPILE_TEST
+       depends on ARCH_RENESAS || COMPILE_TEST
        depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select SOC_CAMERA_SCALE_CROP
@@ -45,7 +45,7 @@ config VIDEO_SH_MOBILE_CSI2
 config VIDEO_SH_MOBILE_CEU
        tristate "SuperH Mobile CEU Interface driver"
        depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK
-       depends on ARCH_SHMOBILE || SUPERH || COMPILE_TEST
+       depends on ARCH_SHMOBILE || COMPILE_TEST
        depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select SOC_CAMERA_SCALE_CROP
index 3b8edf4..3f9c1b8 100644 (file)
@@ -1845,6 +1845,8 @@ static const struct of_device_id rcar_vin_of_table[] = {
        { .compatible = "renesas,vin-r8a7790", .data = (void *)RCAR_GEN2 },
        { .compatible = "renesas,vin-r8a7779", .data = (void *)RCAR_H1 },
        { .compatible = "renesas,vin-r8a7778", .data = (void *)RCAR_M1 },
+       { .compatible = "renesas,rcar-gen3-vin", .data = (void *)RCAR_GEN3 },
+       { .compatible = "renesas,rcar-gen2-vin", .data = (void *)RCAR_GEN2 },
        { },
 };
 MODULE_DEVICE_TABLE(of, rcar_vin_of_table);
index 78e3cb9..7dddf77 100644 (file)
@@ -49,7 +49,7 @@ MODULE_FIRMWARE(FIRMWARE_MEMDMA);
 #define PID_TABLE_SIZE 1024
 #define POLL_MSECS 50
 
-static int load_c8sectpfe_fw_step1(struct c8sectpfei *fei);
+static int load_c8sectpfe_fw(struct c8sectpfei *fei);
 
 #define TS_PKT_SIZE 188
 #define HEADER_SIZE (4)
@@ -130,7 +130,7 @@ static void channel_swdemux_tsklet(unsigned long data)
                writel(channel->back_buffer_busaddr, channel->irec +
                        DMA_PRDS_BUSRP_TP(0));
        else
-               writel(wp, channel->irec + DMA_PRDS_BUSWP_TP(0));
+               writel(wp, channel->irec + DMA_PRDS_BUSRP_TP(0));
 }
 
 static int c8sectpfe_start_feed(struct dvb_demux_feed *dvbdmxfeed)
@@ -141,6 +141,7 @@ static int c8sectpfe_start_feed(struct dvb_demux_feed *dvbdmxfeed)
        struct channel_info *channel;
        u32 tmp;
        unsigned long *bitmap;
+       int ret;
 
        switch (dvbdmxfeed->type) {
        case DMX_TYPE_TS:
@@ -169,8 +170,9 @@ static int c8sectpfe_start_feed(struct dvb_demux_feed *dvbdmxfeed)
        }
 
        if (!atomic_read(&fei->fw_loaded)) {
-               dev_err(fei->dev, "%s: c8sectpfe fw not loaded\n", __func__);
-               return -EINVAL;
+               ret = load_c8sectpfe_fw(fei);
+               if (ret)
+                       return ret;
        }
 
        mutex_lock(&fei->lock);
@@ -265,8 +267,9 @@ static int c8sectpfe_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
        unsigned long *bitmap;
 
        if (!atomic_read(&fei->fw_loaded)) {
-               dev_err(fei->dev, "%s: c8sectpfe fw not loaded\n", __func__);
-               return -EINVAL;
+               ret = load_c8sectpfe_fw(fei);
+               if (ret)
+                       return ret;
        }
 
        mutex_lock(&fei->lock);
@@ -585,7 +588,7 @@ static int configure_memdma_and_inputblock(struct c8sectpfei *fei,
        writel(tsin->pid_buffer_busaddr,
                fei->io + PIDF_BASE(tsin->tsin_id));
 
-       dev_info(fei->dev, "chan=%d PIDF_BASE=0x%x pid_bus_addr=%pad\n",
+       dev_dbg(fei->dev, "chan=%d PIDF_BASE=0x%x pid_bus_addr=%pad\n",
                tsin->tsin_id, readl(fei->io + PIDF_BASE(tsin->tsin_id)),
                &tsin->pid_buffer_busaddr);
 
@@ -880,13 +883,6 @@ static int c8sectpfe_probe(struct platform_device *pdev)
                goto err_clk_disable;
        }
 
-       /* ensure all other init has been done before requesting firmware */
-       ret = load_c8sectpfe_fw_step1(fei);
-       if (ret) {
-               dev_err(dev, "Couldn't load slim core firmware\n");
-               goto err_clk_disable;
-       }
-
        c8sectpfe_debugfs_init(fei);
 
        return 0;
@@ -1091,15 +1087,14 @@ static void load_dmem_segment(struct c8sectpfei *fei, Elf32_Phdr *phdr,
                phdr->p_memsz - phdr->p_filesz);
 }
 
-static int load_slim_core_fw(const struct firmware *fw, void *context)
+static int load_slim_core_fw(const struct firmware *fw, struct c8sectpfei *fei)
 {
-       struct c8sectpfei *fei = context;
        Elf32_Ehdr *ehdr;
        Elf32_Phdr *phdr;
        u8 __iomem *dst;
        int err = 0, i;
 
-       if (!fw || !context)
+       if (!fw || !fei)
                return -EINVAL;
 
        ehdr = (Elf32_Ehdr *)fw->data;
@@ -1151,29 +1146,35 @@ static int load_slim_core_fw(const struct firmware *fw, void *context)
        return err;
 }
 
-static void load_c8sectpfe_fw_cb(const struct firmware *fw, void *context)
+static int load_c8sectpfe_fw(struct c8sectpfei *fei)
 {
-       struct c8sectpfei *fei = context;
+       const struct firmware *fw;
        int err;
 
+       dev_info(fei->dev, "Loading firmware: %s\n", FIRMWARE_MEMDMA);
+
+       err = request_firmware(&fw, FIRMWARE_MEMDMA, fei->dev);
+       if (err)
+               return err;
+
        err = c8sectpfe_elf_sanity_check(fei, fw);
        if (err) {
                dev_err(fei->dev, "c8sectpfe_elf_sanity_check failed err=(%d)\n"
                        , err);
-               goto err;
+               return err;
        }
 
-       err = load_slim_core_fw(fw, context);
+       err = load_slim_core_fw(fw, fei);
        if (err) {
                dev_err(fei->dev, "load_slim_core_fw failed err=(%d)\n", err);
-               goto err;
+               return err;
        }
 
        /* now the firmware is loaded configure the input blocks */
        err = configure_channels(fei);
        if (err) {
                dev_err(fei->dev, "configure_channels failed err=(%d)\n", err);
-               goto err;
+               return err;
        }
 
        /*
@@ -1186,28 +1187,6 @@ static void load_c8sectpfe_fw_cb(const struct firmware *fw, void *context)
        writel(0x1,  fei->io + DMA_CPU_RUN);
 
        atomic_set(&fei->fw_loaded, 1);
-err:
-       complete_all(&fei->fw_ack);
-}
-
-static int load_c8sectpfe_fw_step1(struct c8sectpfei *fei)
-{
-       int err;
-
-       dev_info(fei->dev, "Loading firmware: %s\n", FIRMWARE_MEMDMA);
-
-       init_completion(&fei->fw_ack);
-       atomic_set(&fei->fw_loaded, 0);
-
-       err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
-                               FIRMWARE_MEMDMA, fei->dev, GFP_KERNEL, fei,
-                               load_c8sectpfe_fw_cb);
-
-       if (err) {
-               dev_err(fei->dev, "request_firmware_nowait err: %d.\n", err);
-               complete_all(&fei->fw_ack);
-               return err;
-       }
 
        return 0;
 }
index 0885e93..f535f57 100644 (file)
@@ -7,6 +7,7 @@ config VIDEO_VIVID
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
        select VIDEOBUF2_VMALLOC
+       select VIDEO_V4L2_TPG
        default n
        ---help---
          Enables a virtual video driver. This driver emulates a webcam,
index 756fc12..633c8a1 100644 (file)
@@ -2,5 +2,5 @@ vivid-objs := vivid-core.o vivid-ctrls.o vivid-vid-common.o vivid-vbi-gen.o \
                vivid-vid-cap.o vivid-vid-out.o vivid-kthread-cap.o vivid-kthread-out.o \
                vivid-radio-rx.o vivid-radio-tx.o vivid-radio-common.o \
                vivid-rds-gen.o vivid-sdr-cap.o vivid-vbi-cap.o vivid-vbi-out.o \
-               vivid-osd.o vivid-tpg.o vivid-tpg-colors.o
+               vivid-osd.o
 obj-$(CONFIG_VIDEO_VIVID) += vivid.o
index ec125be..c14da84 100644 (file)
@@ -200,27 +200,12 @@ static int vidioc_querycap(struct file *file, void  *priv,
                                        struct v4l2_capability *cap)
 {
        struct vivid_dev *dev = video_drvdata(file);
-       struct video_device *vdev = video_devdata(file);
 
        strcpy(cap->driver, "vivid");
        strcpy(cap->card, "vivid");
        snprintf(cap->bus_info, sizeof(cap->bus_info),
                        "platform:%s", dev->v4l2_dev.name);
 
-       if (vdev->vfl_type == VFL_TYPE_GRABBER && vdev->vfl_dir == VFL_DIR_RX)
-               cap->device_caps = dev->vid_cap_caps;
-       if (vdev->vfl_type == VFL_TYPE_GRABBER && vdev->vfl_dir == VFL_DIR_TX)
-               cap->device_caps = dev->vid_out_caps;
-       else if (vdev->vfl_type == VFL_TYPE_VBI && vdev->vfl_dir == VFL_DIR_RX)
-               cap->device_caps = dev->vbi_cap_caps;
-       else if (vdev->vfl_type == VFL_TYPE_VBI && vdev->vfl_dir == VFL_DIR_TX)
-               cap->device_caps = dev->vbi_out_caps;
-       else if (vdev->vfl_type == VFL_TYPE_SDR)
-               cap->device_caps = dev->sdr_cap_caps;
-       else if (vdev->vfl_type == VFL_TYPE_RADIO && vdev->vfl_dir == VFL_DIR_RX)
-               cap->device_caps = dev->radio_rx_caps;
-       else if (vdev->vfl_type == VFL_TYPE_RADIO && vdev->vfl_dir == VFL_DIR_TX)
-               cap->device_caps = dev->radio_tx_caps;
        cap->capabilities = dev->vid_cap_caps | dev->vid_out_caps |
                dev->vbi_cap_caps | dev->vbi_out_caps |
                dev->radio_rx_caps | dev->radio_tx_caps |
@@ -1135,6 +1120,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
                strlcpy(vfd->name, "vivid-vid-cap", sizeof(vfd->name));
                vfd->fops = &vivid_fops;
                vfd->ioctl_ops = &vivid_ioctl_ops;
+               vfd->device_caps = dev->vid_cap_caps;
                vfd->release = video_device_release_empty;
                vfd->v4l2_dev = &dev->v4l2_dev;
                vfd->queue = &dev->vb_vid_cap_q;
@@ -1160,6 +1146,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
                vfd->vfl_dir = VFL_DIR_TX;
                vfd->fops = &vivid_fops;
                vfd->ioctl_ops = &vivid_ioctl_ops;
+               vfd->device_caps = dev->vid_out_caps;
                vfd->release = video_device_release_empty;
                vfd->v4l2_dev = &dev->v4l2_dev;
                vfd->queue = &dev->vb_vid_out_q;
@@ -1184,6 +1171,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
                strlcpy(vfd->name, "vivid-vbi-cap", sizeof(vfd->name));
                vfd->fops = &vivid_fops;
                vfd->ioctl_ops = &vivid_ioctl_ops;
+               vfd->device_caps = dev->vbi_cap_caps;
                vfd->release = video_device_release_empty;
                vfd->v4l2_dev = &dev->v4l2_dev;
                vfd->queue = &dev->vb_vbi_cap_q;
@@ -1207,6 +1195,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
                vfd->vfl_dir = VFL_DIR_TX;
                vfd->fops = &vivid_fops;
                vfd->ioctl_ops = &vivid_ioctl_ops;
+               vfd->device_caps = dev->vbi_out_caps;
                vfd->release = video_device_release_empty;
                vfd->v4l2_dev = &dev->v4l2_dev;
                vfd->queue = &dev->vb_vbi_out_q;
@@ -1229,6 +1218,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
                strlcpy(vfd->name, "vivid-sdr-cap", sizeof(vfd->name));
                vfd->fops = &vivid_fops;
                vfd->ioctl_ops = &vivid_ioctl_ops;
+               vfd->device_caps = dev->sdr_cap_caps;
                vfd->release = video_device_release_empty;
                vfd->v4l2_dev = &dev->v4l2_dev;
                vfd->queue = &dev->vb_sdr_cap_q;
@@ -1247,6 +1237,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
                strlcpy(vfd->name, "vivid-rad-rx", sizeof(vfd->name));
                vfd->fops = &vivid_radio_fops;
                vfd->ioctl_ops = &vivid_ioctl_ops;
+               vfd->device_caps = dev->radio_rx_caps;
                vfd->release = video_device_release_empty;
                vfd->v4l2_dev = &dev->v4l2_dev;
                vfd->lock = &dev->mutex;
@@ -1265,6 +1256,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
                vfd->vfl_dir = VFL_DIR_TX;
                vfd->fops = &vivid_radio_fops;
                vfd->ioctl_ops = &vivid_ioctl_ops;
+               vfd->device_caps = dev->radio_tx_caps;
                vfd->release = video_device_release_empty;
                vfd->v4l2_dev = &dev->v4l2_dev;
                vfd->lock = &dev->mutex;
index 751c1ba..776783b 100644 (file)
@@ -25,7 +25,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-ctrls.h>
-#include "vivid-tpg.h"
+#include <media/v4l2-tpg.h>
 #include "vivid-rds-gen.h"
 #include "vivid-vbi-gen.h"
 
index 9034281..3b8c101 100644 (file)
@@ -36,6 +36,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-fh.h>
 #include <media/v4l2-event.h>
+#include <media/v4l2-rect.h>
 
 #include "vivid-core.h"
 #include "vivid-vid-common.h"
@@ -184,15 +185,15 @@ static void vivid_precalc_copy_rects(struct vivid_dev *dev)
                dev->compose_out.width, dev->compose_out.height
        };
 
-       dev->loop_vid_copy = rect_intersect(&dev->crop_cap, &dev->compose_out);
+       v4l2_rect_intersect(&dev->loop_vid_copy, &dev->crop_cap, &dev->compose_out);
 
        dev->loop_vid_out = dev->loop_vid_copy;
-       rect_scale(&dev->loop_vid_out, &dev->compose_out, &dev->crop_out);
+       v4l2_rect_scale(&dev->loop_vid_out, &dev->compose_out, &dev->crop_out);
        dev->loop_vid_out.left += dev->crop_out.left;
        dev->loop_vid_out.top += dev->crop_out.top;
 
        dev->loop_vid_cap = dev->loop_vid_copy;
-       rect_scale(&dev->loop_vid_cap, &dev->crop_cap, &dev->compose_cap);
+       v4l2_rect_scale(&dev->loop_vid_cap, &dev->crop_cap, &dev->compose_cap);
 
        dprintk(dev, 1,
                "loop_vid_copy: %dx%d@%dx%d loop_vid_out: %dx%d@%dx%d loop_vid_cap: %dx%d@%dx%d\n",
@@ -203,13 +204,13 @@ static void vivid_precalc_copy_rects(struct vivid_dev *dev)
                dev->loop_vid_cap.width, dev->loop_vid_cap.height,
                dev->loop_vid_cap.left, dev->loop_vid_cap.top);
 
-       r_overlay = rect_intersect(&r_fb, &r_overlay);
+       v4l2_rect_intersect(&r_overlay, &r_fb, &r_overlay);
 
        /* shift r_overlay to the same origin as compose_out */
        r_overlay.left += dev->compose_out.left - dev->overlay_out_left;
        r_overlay.top += dev->compose_out.top - dev->overlay_out_top;
 
-       dev->loop_vid_overlay = rect_intersect(&r_overlay, &dev->loop_vid_copy);
+       v4l2_rect_intersect(&dev->loop_vid_overlay, &r_overlay, &dev->loop_vid_copy);
        dev->loop_fb_copy = dev->loop_vid_overlay;
 
        /* shift dev->loop_fb_copy back again to the fb origin */
@@ -217,7 +218,7 @@ static void vivid_precalc_copy_rects(struct vivid_dev *dev)
        dev->loop_fb_copy.top -= dev->compose_out.top - dev->overlay_out_top;
 
        dev->loop_vid_overlay_cap = dev->loop_vid_overlay;
-       rect_scale(&dev->loop_vid_overlay_cap, &dev->crop_cap, &dev->compose_cap);
+       v4l2_rect_scale(&dev->loop_vid_overlay_cap, &dev->crop_cap, &dev->compose_cap);
 
        dprintk(dev, 1,
                "loop_fb_copy: %dx%d@%dx%d loop_vid_overlay: %dx%d@%dx%d loop_vid_overlay_cap: %dx%d@%dx%d\n",
index c382343..53c7777 100644 (file)
@@ -55,6 +55,7 @@ void vivid_rds_generate(struct vivid_rds_gen *rds)
 {
        struct v4l2_rds_data *data = rds->data;
        unsigned grp;
+       unsigned idx;
        struct tm tm;
        unsigned date;
        unsigned time;
@@ -73,24 +74,26 @@ void vivid_rds_generate(struct vivid_rds_gen *rds)
                case 0 ... 3:
                case 22 ... 25:
                case 44 ... 47: /* Group 0B */
+                       idx = (grp % 22) % 4;
                        data[1].lsb |= (rds->ta << 4) | (rds->ms << 3);
-                       data[1].lsb |= vivid_get_di(rds, grp % 22);
+                       data[1].lsb |= vivid_get_di(rds, idx);
                        data[1].msb |= 1 << 3;
                        data[2].lsb = rds->picode & 0xff;
                        data[2].msb = rds->picode >> 8;
                        data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3);
-                       data[3].lsb = rds->psname[2 * (grp % 22) + 1];
-                       data[3].msb = rds->psname[2 * (grp % 22)];
+                       data[3].lsb = rds->psname[2 * idx + 1];
+                       data[3].msb = rds->psname[2 * idx];
                        break;
                case 4 ... 19:
                case 26 ... 41: /* Group 2A */
-                       data[1].lsb |= (grp - 4) % 22;
+                       idx = ((grp - 4) % 22) % 16;
+                       data[1].lsb |= idx;
                        data[1].msb |= 4 << 3;
-                       data[2].msb = rds->radiotext[4 * ((grp - 4) % 22)];
-                       data[2].lsb = rds->radiotext[4 * ((grp - 4) % 22) + 1];
+                       data[2].msb = rds->radiotext[4 * idx];
+                       data[2].lsb = rds->radiotext[4 * idx + 1];
                        data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3);
-                       data[3].msb = rds->radiotext[4 * ((grp - 4) % 22) + 2];
-                       data[3].lsb = rds->radiotext[4 * ((grp - 4) % 22) + 3];
+                       data[3].msb = rds->radiotext[4 * idx + 2];
+                       data[3].lsb = rds->radiotext[4 * idx + 3];
                        break;
                case 56:
                        /*
diff --git a/drivers/media/platform/vivid/vivid-tpg-colors.c b/drivers/media/platform/vivid/vivid-tpg-colors.c
deleted file mode 100644 (file)
index 2299f0c..0000000
+++ /dev/null
@@ -1,1416 +0,0 @@
-/*
- * vivid-color.c - A table that converts colors to various colorspaces
- *
- * The test pattern generator uses the tpg_colors for its test patterns.
- * For testing colorspaces the first 8 colors of that table need to be
- * converted to their equivalent in the target colorspace.
- *
- * The tpg_csc_colors[] table is the result of that conversion and since
- * it is precalculated the colorspace conversion is just a simple table
- * lookup.
- *
- * This source also contains the code used to generate the tpg_csc_colors
- * table. Run the following command to compile it:
- *
- *     gcc vivid-tpg-colors.c -DCOMPILE_APP -o gen-colors -lm
- *
- * and run the utility.
- *
- * Note that the converted colors are in the range 0x000-0xff0 (so times 16)
- * in order to preserve precision.
- *
- * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/videodev2.h>
-
-#include "vivid-tpg-colors.h"
-
-/* sRGB colors with range [0-255] */
-const struct color tpg_colors[TPG_COLOR_MAX] = {
-       /*
-        * Colors to test colorspace conversion: converting these colors
-        * to other colorspaces will never lead to out-of-gamut colors.
-        */
-       { 191, 191, 191 }, /* TPG_COLOR_CSC_WHITE */
-       { 191, 191,  50 }, /* TPG_COLOR_CSC_YELLOW */
-       {  50, 191, 191 }, /* TPG_COLOR_CSC_CYAN */
-       {  50, 191,  50 }, /* TPG_COLOR_CSC_GREEN */
-       { 191,  50, 191 }, /* TPG_COLOR_CSC_MAGENTA */
-       { 191,  50,  50 }, /* TPG_COLOR_CSC_RED */
-       {  50,  50, 191 }, /* TPG_COLOR_CSC_BLUE */
-       {  50,  50,  50 }, /* TPG_COLOR_CSC_BLACK */
-
-       /* 75% colors */
-       { 191, 191,   0 }, /* TPG_COLOR_75_YELLOW */
-       {   0, 191, 191 }, /* TPG_COLOR_75_CYAN */
-       {   0, 191,   0 }, /* TPG_COLOR_75_GREEN */
-       { 191,   0, 191 }, /* TPG_COLOR_75_MAGENTA */
-       { 191,   0,   0 }, /* TPG_COLOR_75_RED */
-       {   0,   0, 191 }, /* TPG_COLOR_75_BLUE */
-
-       /* 100% colors */
-       { 255, 255, 255 }, /* TPG_COLOR_100_WHITE */
-       { 255, 255,   0 }, /* TPG_COLOR_100_YELLOW */
-       {   0, 255, 255 }, /* TPG_COLOR_100_CYAN */
-       {   0, 255,   0 }, /* TPG_COLOR_100_GREEN */
-       { 255,   0, 255 }, /* TPG_COLOR_100_MAGENTA */
-       { 255,   0,   0 }, /* TPG_COLOR_100_RED */
-       {   0,   0, 255 }, /* TPG_COLOR_100_BLUE */
-       {   0,   0,   0 }, /* TPG_COLOR_100_BLACK */
-
-       {   0,   0,   0 }, /* TPG_COLOR_RANDOM placeholder */
-};
-
-#ifndef COMPILE_APP
-
-/* Generated table */
-const unsigned short tpg_rec709_to_linear[255 * 16 + 1] = {
-          0,    0,    0,    1,    1,    1,    1,    2,    2,    2,    2,    2,    3,    3,    3,    3,
-          4,    4,    4,    4,    4,    5,    5,    5,    5,    6,    6,    6,    6,    6,    7,    7,
-          7,    7,    8,    8,    8,    8,    8,    9,    9,    9,    9,   10,   10,   10,   10,   10,
-         11,   11,   11,   11,   12,   12,   12,   12,   12,   13,   13,   13,   13,   14,   14,   14,
-         14,   14,   15,   15,   15,   15,   16,   16,   16,   16,   16,   17,   17,   17,   17,   18,
-         18,   18,   18,   18,   19,   19,   19,   19,   20,   20,   20,   20,   20,   21,   21,   21,
-         21,   22,   22,   22,   22,   22,   23,   23,   23,   23,   24,   24,   24,   24,   24,   25,
-         25,   25,   25,   26,   26,   26,   26,   26,   27,   27,   27,   27,   28,   28,   28,   28,
-         28,   29,   29,   29,   29,   30,   30,   30,   30,   30,   31,   31,   31,   31,   32,   32,
-         32,   32,   32,   33,   33,   33,   33,   34,   34,   34,   34,   34,   35,   35,   35,   35,
-         36,   36,   36,   36,   36,   37,   37,   37,   37,   38,   38,   38,   38,   38,   39,   39,
-         39,   39,   40,   40,   40,   40,   40,   41,   41,   41,   41,   42,   42,   42,   42,   42,
-         43,   43,   43,   43,   44,   44,   44,   44,   44,   45,   45,   45,   45,   46,   46,   46,
-         46,   46,   47,   47,   47,   47,   48,   48,   48,   48,   48,   49,   49,   49,   49,   50,
-         50,   50,   50,   50,   51,   51,   51,   51,   52,   52,   52,   52,   52,   53,   53,   53,
-         53,   54,   54,   54,   54,   54,   55,   55,   55,   55,   56,   56,   56,   56,   56,   57,
-         57,   57,   57,   58,   58,   58,   58,   58,   59,   59,   59,   59,   60,   60,   60,   60,
-         60,   61,   61,   61,   61,   62,   62,   62,   62,   62,   63,   63,   63,   63,   64,   64,
-         64,   64,   64,   65,   65,   65,   65,   66,   66,   66,   66,   66,   67,   67,   67,   67,
-         68,   68,   68,   68,   68,   69,   69,   69,   69,   70,   70,   70,   70,   70,   71,   71,
-         71,   71,   72,   72,   72,   72,   72,   73,   73,   73,   73,   73,   74,   74,   74,   74,
-         74,   75,   75,   75,   75,   76,   76,   76,   76,   76,   77,   77,   77,   77,   78,   78,
-         78,   78,   79,   79,   79,   79,   79,   80,   80,   80,   80,   81,   81,   81,   81,   82,
-         82,   82,   82,   82,   83,   83,   83,   83,   84,   84,   84,   84,   85,   85,   85,   85,
-         86,   86,   86,   86,   87,   87,   87,   87,   88,   88,   88,   88,   89,   89,   89,   89,
-         90,   90,   90,   90,   91,   91,   91,   91,   92,   92,   92,   92,   93,   93,   93,   93,
-         94,   94,   94,   94,   95,   95,   95,   95,   96,   96,   96,   96,   97,   97,   97,   97,
-         98,   98,   98,   98,   99,   99,   99,   99,  100,  100,  100,  101,  101,  101,  101,  102,
-        102,  102,  102,  103,  103,  103,  103,  104,  104,  104,  105,  105,  105,  105,  106,  106,
-        106,  106,  107,  107,  107,  107,  108,  108,  108,  109,  109,  109,  109,  110,  110,  110,
-        111,  111,  111,  111,  112,  112,  112,  112,  113,  113,  113,  114,  114,  114,  114,  115,
-        115,  115,  116,  116,  116,  116,  117,  117,  117,  118,  118,  118,  118,  119,  119,  119,
-        120,  120,  120,  120,  121,  121,  121,  122,  122,  122,  123,  123,  123,  123,  124,  124,
-        124,  125,  125,  125,  125,  126,  126,  126,  127,  127,  127,  128,  128,  128,  128,  129,
-        129,  129,  130,  130,  130,  131,  131,  131,  132,  132,  132,  132,  133,  133,  133,  134,
-        134,  134,  135,  135,  135,  136,  136,  136,  136,  137,  137,  137,  138,  138,  138,  139,
-        139,  139,  140,  140,  140,  141,  141,  141,  142,  142,  142,  142,  143,  143,  143,  144,
-        144,  144,  145,  145,  145,  146,  146,  146,  147,  147,  147,  148,  148,  148,  149,  149,
-        149,  150,  150,  150,  151,  151,  151,  152,  152,  152,  153,  153,  153,  154,  154,  154,
-        155,  155,  155,  156,  156,  156,  157,  157,  157,  158,  158,  158,  159,  159,  159,  160,
-        160,  160,  161,  161,  161,  162,  162,  162,  163,  163,  163,  164,  164,  164,  165,  165,
-        165,  166,  166,  167,  167,  167,  168,  168,  168,  169,  169,  169,  170,  170,  170,  171,
-        171,  171,  172,  172,  172,  173,  173,  174,  174,  174,  175,  175,  175,  176,  176,  176,
-        177,  177,  177,  178,  178,  179,  179,  179,  180,  180,  180,  181,  181,  181,  182,  182,
-        183,  183,  183,  184,  184,  184,  185,  185,  186,  186,  186,  187,  187,  187,  188,  188,
-        188,  189,  189,  190,  190,  190,  191,  191,  191,  192,  192,  193,  193,  193,  194,  194,
-        194,  195,  195,  196,  196,  196,  197,  197,  198,  198,  198,  199,  199,  199,  200,  200,
-        201,  201,  201,  202,  202,  203,  203,  203,  204,  204,  204,  205,  205,  206,  206,  206,
-        207,  207,  208,  208,  208,  209,  209,  210,  210,  210,  211,  211,  212,  212,  212,  213,
-        213,  214,  214,  214,  215,  215,  216,  216,  216,  217,  217,  218,  218,  218,  219,  219,
-        220,  220,  220,  221,  221,  222,  222,  222,  223,  223,  224,  224,  224,  225,  225,  226,
-        226,  227,  227,  227,  228,  228,  229,  229,  229,  230,  230,  231,  231,  232,  232,  232,
-        233,  233,  234,  234,  234,  235,  235,  236,  236,  237,  237,  237,  238,  238,  239,  239,
-        240,  240,  240,  241,  241,  242,  242,  243,  243,  243,  244,  244,  245,  245,  246,  246,
-        246,  247,  247,  248,  248,  249,  249,  249,  250,  250,  251,  251,  252,  252,  252,  253,
-        253,  254,  254,  255,  255,  256,  256,  256,  257,  257,  258,  258,  259,  259,  260,  260,
-        260,  261,  261,  262,  262,  263,  263,  264,  264,  264,  265,  265,  266,  266,  267,  267,
-        268,  268,  269,  269,  269,  270,  270,  271,  271,  272,  272,  273,  273,  274,  274,  274,
-        275,  275,  276,  276,  277,  277,  278,  278,  279,  279,  279,  280,  280,  281,  281,  282,
-        282,  283,  283,  284,  284,  285,  285,  286,  286,  286,  287,  287,  288,  288,  289,  289,
-        290,  290,  291,  291,  292,  292,  293,  293,  294,  294,  295,  295,  295,  296,  296,  297,
-        297,  298,  298,  299,  299,  300,  300,  301,  301,  302,  302,  303,  303,  304,  304,  305,
-        305,  306,  306,  307,  307,  308,  308,  309,  309,  309,  310,  310,  311,  311,  312,  312,
-        313,  313,  314,  314,  315,  315,  316,  316,  317,  317,  318,  318,  319,  319,  320,  320,
-        321,  321,  322,  322,  323,  323,  324,  324,  325,  325,  326,  326,  327,  327,  328,  328,
-        329,  329,  330,  330,  331,  331,  332,  332,  333,  333,  334,  335,  335,  336,  336,  337,
-        337,  338,  338,  339,  339,  340,  340,  341,  341,  342,  342,  343,  343,  344,  344,  345,
-        345,  346,  346,  347,  347,  348,  348,  349,  349,  350,  351,  351,  352,  352,  353,  353,
-        354,  354,  355,  355,  356,  356,  357,  357,  358,  358,  359,  360,  360,  361,  361,  362,
-        362,  363,  363,  364,  364,  365,  365,  366,  366,  367,  368,  368,  369,  369,  370,  370,
-        371,  371,  372,  372,  373,  373,  374,  375,  375,  376,  376,  377,  377,  378,  378,  379,
-        379,  380,  381,  381,  382,  382,  383,  383,  384,  384,  385,  386,  386,  387,  387,  388,
-        388,  389,  389,  390,  391,  391,  392,  392,  393,  393,  394,  394,  395,  396,  396,  397,
-        397,  398,  398,  399,  399,  400,  401,  401,  402,  402,  403,  403,  404,  405,  405,  406,
-        406,  407,  407,  408,  409,  409,  410,  410,  411,  411,  412,  413,  413,  414,  414,  415,
-        415,  416,  417,  417,  418,  418,  419,  419,  420,  421,  421,  422,  422,  423,  424,  424,
-        425,  425,  426,  426,  427,  428,  428,  429,  429,  430,  431,  431,  432,  432,  433,  433,
-        434,  435,  435,  436,  436,  437,  438,  438,  439,  439,  440,  441,  441,  442,  442,  443,
-        444,  444,  445,  445,  446,  447,  447,  448,  448,  449,  450,  450,  451,  451,  452,  453,
-        453,  454,  454,  455,  456,  456,  457,  457,  458,  459,  459,  460,  460,  461,  462,  462,
-        463,  463,  464,  465,  465,  466,  467,  467,  468,  468,  469,  470,  470,  471,  471,  472,
-        473,  473,  474,  475,  475,  476,  476,  477,  478,  478,  479,  480,  480,  481,  481,  482,
-        483,  483,  484,  485,  485,  486,  486,  487,  488,  488,  489,  490,  490,  491,  491,  492,
-        493,  493,  494,  495,  495,  496,  497,  497,  498,  498,  499,  500,  500,  501,  502,  502,
-        503,  504,  504,  505,  505,  506,  507,  507,  508,  509,  509,  510,  511,  511,  512,  513,
-        513,  514,  514,  515,  516,  516,  517,  518,  518,  519,  520,  520,  521,  522,  522,  523,
-        524,  524,  525,  526,  526,  527,  528,  528,  529,  529,  530,  531,  531,  532,  533,  533,
-        534,  535,  535,  536,  537,  537,  538,  539,  539,  540,  541,  541,  542,  543,  543,  544,
-        545,  545,  546,  547,  547,  548,  549,  549,  550,  551,  551,  552,  553,  553,  554,  555,
-        555,  556,  557,  557,  558,  559,  560,  560,  561,  562,  562,  563,  564,  564,  565,  566,
-        566,  567,  568,  568,  569,  570,  570,  571,  572,  572,  573,  574,  575,  575,  576,  577,
-        577,  578,  579,  579,  580,  581,  581,  582,  583,  584,  584,  585,  586,  586,  587,  588,
-        588,  589,  590,  590,  591,  592,  593,  593,  594,  595,  595,  596,  597,  598,  598,  599,
-        600,  600,  601,  602,  602,  603,  604,  605,  605,  606,  607,  607,  608,  609,  610,  610,
-        611,  612,  612,  613,  614,  615,  615,  616,  617,  617,  618,  619,  620,  620,  621,  622,
-        622,  623,  624,  625,  625,  626,  627,  627,  628,  629,  630,  630,  631,  632,  632,  633,
-        634,  635,  635,  636,  637,  638,  638,  639,  640,  640,  641,  642,  643,  643,  644,  645,
-        646,  646,  647,  648,  649,  649,  650,  651,  652,  652,  653,  654,  654,  655,  656,  657,
-        657,  658,  659,  660,  660,  661,  662,  663,  663,  664,  665,  666,  666,  667,  668,  669,
-        669,  670,  671,  672,  672,  673,  674,  675,  675,  676,  677,  678,  678,  679,  680,  681,
-        681,  682,  683,  684,  684,  685,  686,  687,  687,  688,  689,  690,  690,  691,  692,  693,
-        694,  694,  695,  696,  697,  697,  698,  699,  700,  700,  701,  702,  703,  703,  704,  705,
-        706,  707,  707,  708,  709,  710,  710,  711,  712,  713,  714,  714,  715,  716,  717,  717,
-        718,  719,  720,  720,  721,  722,  723,  724,  724,  725,  726,  727,  728,  728,  729,  730,
-        731,  731,  732,  733,  734,  735,  735,  736,  737,  738,  739,  739,  740,  741,  742,  742,
-        743,  744,  745,  746,  746,  747,  748,  749,  750,  750,  751,  752,  753,  754,  754,  755,
-        756,  757,  758,  758,  759,  760,  761,  762,  762,  763,  764,  765,  766,  766,  767,  768,
-        769,  770,  771,  771,  772,  773,  774,  775,  775,  776,  777,  778,  779,  779,  780,  781,
-        782,  783,  783,  784,  785,  786,  787,  788,  788,  789,  790,  791,  792,  793,  793,  794,
-        795,  796,  797,  797,  798,  799,  800,  801,  802,  802,  803,  804,  805,  806,  807,  807,
-        808,  809,  810,  811,  812,  812,  813,  814,  815,  816,  817,  817,  818,  819,  820,  821,
-        822,  822,  823,  824,  825,  826,  827,  827,  828,  829,  830,  831,  832,  832,  833,  834,
-        835,  836,  837,  838,  838,  839,  840,  841,  842,  843,  843,  844,  845,  846,  847,  848,
-        849,  849,  850,  851,  852,  853,  854,  855,  855,  856,  857,  858,  859,  860,  861,  861,
-        862,  863,  864,  865,  866,  867,  867,  868,  869,  870,  871,  872,  873,  873,  874,  875,
-        876,  877,  878,  879,  880,  880,  881,  882,  883,  884,  885,  886,  887,  887,  888,  889,
-        890,  891,  892,  893,  894,  894,  895,  896,  897,  898,  899,  900,  901,  901,  902,  903,
-        904,  905,  906,  907,  908,  909,  909,  910,  911,  912,  913,  914,  915,  916,  916,  917,
-        918,  919,  920,  921,  922,  923,  924,  925,  925,  926,  927,  928,  929,  930,  931,  932,
-        933,  933,  934,  935,  936,  937,  938,  939,  940,  941,  942,  942,  943,  944,  945,  946,
-        947,  948,  949,  950,  951,  952,  952,  953,  954,  955,  956,  957,  958,  959,  960,  961,
-        962,  962,  963,  964,  965,  966,  967,  968,  969,  970,  971,  972,  973,  973,  974,  975,
-        976,  977,  978,  979,  980,  981,  982,  983,  984,  985,  985,  986,  987,  988,  989,  990,
-        991,  992,  993,  994,  995,  996,  997,  998,  998,  999, 1000, 1001, 1002, 1003, 1004, 1005,
-       1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020,
-       1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1030, 1031, 1032, 1033, 1034, 1035,
-       1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1050,
-       1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066,
-       1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1078, 1079, 1080, 1081,
-       1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097,
-       1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113,
-       1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129,
-       1130, 1131, 1132, 1133, 1134, 1135, 1136, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145,
-       1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161,
-       1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, 1177,
-       1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1193, 1194,
-       1195, 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1210,
-       1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1223, 1224, 1225, 1226, 1227,
-       1228, 1229, 1230, 1231, 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, 1241, 1242, 1243,
-       1245, 1246, 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, 1259, 1260,
-       1261, 1262, 1264, 1265, 1266, 1267, 1268, 1269, 1270, 1271, 1272, 1273, 1274, 1275, 1276, 1277,
-       1278, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1291, 1292, 1293, 1295,
-       1296, 1297, 1298, 1299, 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1309, 1310, 1311, 1312,
-       1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329,
-       1330, 1331, 1332, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341, 1342, 1343, 1345, 1346, 1347,
-       1348, 1349, 1350, 1351, 1352, 1353, 1354, 1356, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1364,
-       1365, 1367, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1375, 1377, 1378, 1379, 1380, 1381, 1382,
-       1383, 1384, 1385, 1387, 1388, 1389, 1390, 1391, 1392, 1393, 1394, 1396, 1397, 1398, 1399, 1400,
-       1401, 1402, 1403, 1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412, 1414, 1415, 1416, 1417, 1418,
-       1419, 1420, 1421, 1423, 1424, 1425, 1426, 1427, 1428, 1429, 1431, 1432, 1433, 1434, 1435, 1436,
-       1437, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1448, 1449, 1450, 1451, 1452, 1453, 1455,
-       1456, 1457, 1458, 1459, 1460, 1461, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1471, 1472, 1473,
-       1474, 1475, 1476, 1478, 1479, 1480, 1481, 1482, 1483, 1484, 1486, 1487, 1488, 1489, 1490, 1491,
-       1493, 1494, 1495, 1496, 1497, 1498, 1500, 1501, 1502, 1503, 1504, 1505, 1507, 1508, 1509, 1510,
-       1511, 1512, 1514, 1515, 1516, 1517, 1518, 1519, 1521, 1522, 1523, 1524, 1525, 1527, 1528, 1529,
-       1530, 1531, 1532, 1534, 1535, 1536, 1537, 1538, 1540, 1541, 1542, 1543, 1544, 1545, 1547, 1548,
-       1549, 1550, 1551, 1553, 1554, 1555, 1556, 1557, 1559, 1560, 1561, 1562, 1563, 1564, 1566, 1567,
-       1568, 1569, 1570, 1572, 1573, 1574, 1575, 1576, 1578, 1579, 1580, 1581, 1582, 1584, 1585, 1586,
-       1587, 1588, 1590, 1591, 1592, 1593, 1594, 1596, 1597, 1598, 1599, 1601, 1602, 1603, 1604, 1605,
-       1607, 1608, 1609, 1610, 1611, 1613, 1614, 1615, 1616, 1617, 1619, 1620, 1621, 1622, 1624, 1625,
-       1626, 1627, 1628, 1630, 1631, 1632, 1633, 1635, 1636, 1637, 1638, 1639, 1641, 1642, 1643, 1644,
-       1646, 1647, 1648, 1649, 1650, 1652, 1653, 1654, 1655, 1657, 1658, 1659, 1660, 1662, 1663, 1664,
-       1665, 1667, 1668, 1669, 1670, 1671, 1673, 1674, 1675, 1676, 1678, 1679, 1680, 1681, 1683, 1684,
-       1685, 1686, 1688, 1689, 1690, 1691, 1693, 1694, 1695, 1696, 1698, 1699, 1700, 1701, 1703, 1704,
-       1705, 1706, 1708, 1709, 1710, 1711, 1713, 1714, 1715, 1716, 1718, 1719, 1720, 1721, 1723, 1724,
-       1725, 1726, 1728, 1729, 1730, 1731, 1733, 1734, 1735, 1737, 1738, 1739, 1740, 1742, 1743, 1744,
-       1745, 1747, 1748, 1749, 1750, 1752, 1753, 1754, 1756, 1757, 1758, 1759, 1761, 1762, 1763, 1764,
-       1766, 1767, 1768, 1770, 1771, 1772, 1773, 1775, 1776, 1777, 1778, 1780, 1781, 1782, 1784, 1785,
-       1786, 1787, 1789, 1790, 1791, 1793, 1794, 1795, 1796, 1798, 1799, 1800, 1802, 1803, 1804, 1806,
-       1807, 1808, 1809, 1811, 1812, 1813, 1815, 1816, 1817, 1818, 1820, 1821, 1822, 1824, 1825, 1826,
-       1828, 1829, 1830, 1831, 1833, 1834, 1835, 1837, 1838, 1839, 1841, 1842, 1843, 1844, 1846, 1847,
-       1848, 1850, 1851, 1852, 1854, 1855, 1856, 1858, 1859, 1860, 1862, 1863, 1864, 1865, 1867, 1868,
-       1869, 1871, 1872, 1873, 1875, 1876, 1877, 1879, 1880, 1881, 1883, 1884, 1885, 1887, 1888, 1889,
-       1891, 1892, 1893, 1894, 1896, 1897, 1898, 1900, 1901, 1902, 1904, 1905, 1906, 1908, 1909, 1910,
-       1912, 1913, 1914, 1916, 1917, 1918, 1920, 1921, 1922, 1924, 1925, 1926, 1928, 1929, 1930, 1932,
-       1933, 1935, 1936, 1937, 1939, 1940, 1941, 1943, 1944, 1945, 1947, 1948, 1949, 1951, 1952, 1953,
-       1955, 1956, 1957, 1959, 1960, 1961, 1963, 1964, 1965, 1967, 1968, 1970, 1971, 1972, 1974, 1975,
-       1976, 1978, 1979, 1980, 1982, 1983, 1984, 1986, 1987, 1989, 1990, 1991, 1993, 1994, 1995, 1997,
-       1998, 1999, 2001, 2002, 2004, 2005, 2006, 2008, 2009, 2010, 2012, 2013, 2015, 2016, 2017, 2019,
-       2020, 2021, 2023, 2024, 2026, 2027, 2028, 2030, 2031, 2032, 2034, 2035, 2037, 2038, 2039, 2041,
-       2042, 2043, 2045, 2046, 2048, 2049, 2050, 2052, 2053, 2055, 2056, 2057, 2059, 2060, 2061, 2063,
-       2064, 2066, 2067, 2068, 2070, 2071, 2073, 2074, 2075, 2077, 2078, 2080, 2081, 2082, 2084, 2085,
-       2087, 2088, 2089, 2091, 2092, 2094, 2095, 2096, 2098, 2099, 2101, 2102, 2103, 2105, 2106, 2108,
-       2109, 2110, 2112, 2113, 2115, 2116, 2117, 2119, 2120, 2122, 2123, 2124, 2126, 2127, 2129, 2130,
-       2132, 2133, 2134, 2136, 2137, 2139, 2140, 2141, 2143, 2144, 2146, 2147, 2149, 2150, 2151, 2153,
-       2154, 2156, 2157, 2159, 2160, 2161, 2163, 2164, 2166, 2167, 2169, 2170, 2171, 2173, 2174, 2176,
-       2177, 2179, 2180, 2181, 2183, 2184, 2186, 2187, 2189, 2190, 2191, 2193, 2194, 2196, 2197, 2199,
-       2200, 2202, 2203, 2204, 2206, 2207, 2209, 2210, 2212, 2213, 2214, 2216, 2217, 2219, 2220, 2222,
-       2223, 2225, 2226, 2228, 2229, 2230, 2232, 2233, 2235, 2236, 2238, 2239, 2241, 2242, 2243, 2245,
-       2246, 2248, 2249, 2251, 2252, 2254, 2255, 2257, 2258, 2260, 2261, 2262, 2264, 2265, 2267, 2268,
-       2270, 2271, 2273, 2274, 2276, 2277, 2279, 2280, 2282, 2283, 2284, 2286, 2287, 2289, 2290, 2292,
-       2293, 2295, 2296, 2298, 2299, 2301, 2302, 2304, 2305, 2307, 2308, 2310, 2311, 2312, 2314, 2315,
-       2317, 2318, 2320, 2321, 2323, 2324, 2326, 2327, 2329, 2330, 2332, 2333, 2335, 2336, 2338, 2339,
-       2341, 2342, 2344, 2345, 2347, 2348, 2350, 2351, 2353, 2354, 2356, 2357, 2359, 2360, 2362, 2363,
-       2365, 2366, 2368, 2369, 2371, 2372, 2374, 2375, 2377, 2378, 2380, 2381, 2383, 2384, 2386, 2387,
-       2389, 2390, 2392, 2393, 2395, 2396, 2398, 2399, 2401, 2402, 2404, 2405, 2407, 2408, 2410, 2411,
-       2413, 2414, 2416, 2417, 2419, 2420, 2422, 2423, 2425, 2426, 2428, 2429, 2431, 2433, 2434, 2436,
-       2437, 2439, 2440, 2442, 2443, 2445, 2446, 2448, 2449, 2451, 2452, 2454, 2455, 2457, 2458, 2460,
-       2462, 2463, 2465, 2466, 2468, 2469, 2471, 2472, 2474, 2475, 2477, 2478, 2480, 2481, 2483, 2485,
-       2486, 2488, 2489, 2491, 2492, 2494, 2495, 2497, 2498, 2500, 2502, 2503, 2505, 2506, 2508, 2509,
-       2511, 2512, 2514, 2515, 2517, 2519, 2520, 2522, 2523, 2525, 2526, 2528, 2529, 2531, 2533, 2534,
-       2536, 2537, 2539, 2540, 2542, 2543, 2545, 2547, 2548, 2550, 2551, 2553, 2554, 2556, 2557, 2559,
-       2561, 2562, 2564, 2565, 2567, 2568, 2570, 2572, 2573, 2575, 2576, 2578, 2579, 2581, 2583, 2584,
-       2586, 2587, 2589, 2590, 2592, 2594, 2595, 2597, 2598, 2600, 2601, 2603, 2605, 2606, 2608, 2609,
-       2611, 2613, 2614, 2616, 2617, 2619, 2620, 2622, 2624, 2625, 2627, 2628, 2630, 2632, 2633, 2635,
-       2636, 2638, 2640, 2641, 2643, 2644, 2646, 2647, 2649, 2651, 2652, 2654, 2655, 2657, 2659, 2660,
-       2662, 2663, 2665, 2667, 2668, 2670, 2671, 2673, 2675, 2676, 2678, 2679, 2681, 2683, 2684, 2686,
-       2687, 2689, 2691, 2692, 2694, 2696, 2697, 2699, 2700, 2702, 2704, 2705, 2707, 2708, 2710, 2712,
-       2713, 2715, 2716, 2718, 2720, 2721, 2723, 2725, 2726, 2728, 2729, 2731, 2733, 2734, 2736, 2738,
-       2739, 2741, 2742, 2744, 2746, 2747, 2749, 2751, 2752, 2754, 2755, 2757, 2759, 2760, 2762, 2764,
-       2765, 2767, 2769, 2770, 2772, 2773, 2775, 2777, 2778, 2780, 2782, 2783, 2785, 2787, 2788, 2790,
-       2791, 2793, 2795, 2796, 2798, 2800, 2801, 2803, 2805, 2806, 2808, 2810, 2811, 2813, 2814, 2816,
-       2818, 2819, 2821, 2823, 2824, 2826, 2828, 2829, 2831, 2833, 2834, 2836, 2838, 2839, 2841, 2843,
-       2844, 2846, 2848, 2849, 2851, 2853, 2854, 2856, 2857, 2859, 2861, 2862, 2864, 2866, 2867, 2869,
-       2871, 2872, 2874, 2876, 2877, 2879, 2881, 2882, 2884, 2886, 2888, 2889, 2891, 2893, 2894, 2896,
-       2898, 2899, 2901, 2903, 2904, 2906, 2908, 2909, 2911, 2913, 2914, 2916, 2918, 2919, 2921, 2923,
-       2924, 2926, 2928, 2929, 2931, 2933, 2935, 2936, 2938, 2940, 2941, 2943, 2945, 2946, 2948, 2950,
-       2951, 2953, 2955, 2956, 2958, 2960, 2962, 2963, 2965, 2967, 2968, 2970, 2972, 2973, 2975, 2977,
-       2979, 2980, 2982, 2984, 2985, 2987, 2989, 2990, 2992, 2994, 2996, 2997, 2999, 3001, 3002, 3004,
-       3006, 3008, 3009, 3011, 3013, 3014, 3016, 3018, 3020, 3021, 3023, 3025, 3026, 3028, 3030, 3032,
-       3033, 3035, 3037, 3038, 3040, 3042, 3044, 3045, 3047, 3049, 3050, 3052, 3054, 3056, 3057, 3059,
-       3061, 3063, 3064, 3066, 3068, 3069, 3071, 3073, 3075, 3076, 3078, 3080, 3082, 3083, 3085, 3087,
-       3089, 3090, 3092, 3094, 3095, 3097, 3099, 3101, 3102, 3104, 3106, 3108, 3109, 3111, 3113, 3115,
-       3116, 3118, 3120, 3122, 3123, 3125, 3127, 3129, 3130, 3132, 3134, 3136, 3137, 3139, 3141, 3143,
-       3144, 3146, 3148, 3150, 3151, 3153, 3155, 3157, 3158, 3160, 3162, 3164, 3165, 3167, 3169, 3171,
-       3172, 3174, 3176, 3178, 3179, 3181, 3183, 3185, 3187, 3188, 3190, 3192, 3194, 3195, 3197, 3199,
-       3201, 3202, 3204, 3206, 3208, 3209, 3211, 3213, 3215, 3217, 3218, 3220, 3222, 3224, 3225, 3227,
-       3229, 3231, 3233, 3234, 3236, 3238, 3240, 3241, 3243, 3245, 3247, 3249, 3250, 3252, 3254, 3256,
-       3258, 3259, 3261, 3263, 3265, 3266, 3268, 3270, 3272, 3274, 3275, 3277, 3279, 3281, 3283, 3284,
-       3286, 3288, 3290, 3292, 3293, 3295, 3297, 3299, 3301, 3302, 3304, 3306, 3308, 3310, 3311, 3313,
-       3315, 3317, 3319, 3320, 3322, 3324, 3326, 3328, 3329, 3331, 3333, 3335, 3337, 3338, 3340, 3342,
-       3344, 3346, 3348, 3349, 3351, 3353, 3355, 3357, 3358, 3360, 3362, 3364, 3366, 3368, 3369, 3371,
-       3373, 3375, 3377, 3378, 3380, 3382, 3384, 3386, 3388, 3389, 3391, 3393, 3395, 3397, 3399, 3400,
-       3402, 3404, 3406, 3408, 3410, 3411, 3413, 3415, 3417, 3419, 3421, 3422, 3424, 3426, 3428, 3430,
-       3432, 3433, 3435, 3437, 3439, 3441, 3443, 3444, 3446, 3448, 3450, 3452, 3454, 3455, 3457, 3459,
-       3461, 3463, 3465, 3467, 3468, 3470, 3472, 3474, 3476, 3478, 3480, 3481, 3483, 3485, 3487, 3489,
-       3491, 3492, 3494, 3496, 3498, 3500, 3502, 3504, 3506, 3507, 3509, 3511, 3513, 3515, 3517, 3519,
-       3520, 3522, 3524, 3526, 3528, 3530, 3532, 3533, 3535, 3537, 3539, 3541, 3543, 3545, 3547, 3548,
-       3550, 3552, 3554, 3556, 3558, 3560, 3562, 3563, 3565, 3567, 3569, 3571, 3573, 3575, 3577, 3578,
-       3580, 3582, 3584, 3586, 3588, 3590, 3592, 3594, 3595, 3597, 3599, 3601, 3603, 3605, 3607, 3609,
-       3611, 3612, 3614, 3616, 3618, 3620, 3622, 3624, 3626, 3628, 3629, 3631, 3633, 3635, 3637, 3639,
-       3641, 3643, 3645, 3647, 3648, 3650, 3652, 3654, 3656, 3658, 3660, 3662, 3664, 3666, 3667, 3669,
-       3671, 3673, 3675, 3677, 3679, 3681, 3683, 3685, 3687, 3688, 3690, 3692, 3694, 3696, 3698, 3700,
-       3702, 3704, 3706, 3708, 3710, 3711, 3713, 3715, 3717, 3719, 3721, 3723, 3725, 3727, 3729, 3731,
-       3733, 3735, 3736, 3738, 3740, 3742, 3744, 3746, 3748, 3750, 3752, 3754, 3756, 3758, 3760, 3762,
-       3764, 3765, 3767, 3769, 3771, 3773, 3775, 3777, 3779, 3781, 3783, 3785, 3787, 3789, 3791, 3793,
-       3795, 3796, 3798, 3800, 3802, 3804, 3806, 3808, 3810, 3812, 3814, 3816, 3818, 3820, 3822, 3824,
-       3826, 3828, 3830, 3832, 3833, 3835, 3837, 3839, 3841, 3843, 3845, 3847, 3849, 3851, 3853, 3855,
-       3857, 3859, 3861, 3863, 3865, 3867, 3869, 3871, 3873, 3875, 3877, 3879, 3881, 3883, 3884, 3886,
-       3888, 3890, 3892, 3894, 3896, 3898, 3900, 3902, 3904, 3906, 3908, 3910, 3912, 3914, 3916, 3918,
-       3920, 3922, 3924, 3926, 3928, 3930, 3932, 3934, 3936, 3938, 3940, 3942, 3944, 3946, 3948, 3950,
-       3952, 3954, 3956, 3958, 3960, 3962, 3964, 3966, 3968, 3970, 3972, 3974, 3976, 3978, 3980, 3982,
-       3984, 3986, 3988, 3990, 3992, 3994, 3996, 3998, 4000, 4002, 4004, 4006, 4008, 4010, 4012, 4014,
-       4016, 4018, 4020, 4022, 4024, 4026, 4028, 4030, 4032, 4034, 4036, 4038, 4040, 4042, 4044, 4046,
-       4048, 4050, 4052, 4054, 4056, 4058, 4060, 4062, 4064, 4066, 4068, 4070, 4072, 4074, 4076, 4078,
-       4080,
-};
-
-/* Generated table */
-const unsigned short tpg_linear_to_rec709[255 * 16 + 1] = {
-          0,    5,    9,   14,   18,   22,   27,   32,   36,   41,   45,   50,   54,   59,   63,   68,
-         72,   77,   81,   86,   90,   95,   99,  104,  108,  113,  117,  122,  126,  131,  135,  139,
-        144,  149,  153,  158,  162,  167,  171,  176,  180,  185,  189,  194,  198,  203,  207,  212,
-        216,  221,  225,  230,  234,  239,  243,  248,  252,  257,  261,  266,  270,  275,  279,  284,
-        288,  293,  297,  302,  306,  311,  315,  320,  324,  328,  334,  338,  343,  347,  352,  356,
-        360,  365,  369,  373,  377,  381,  386,  390,  394,  398,  402,  406,  410,  414,  418,  422,
-        426,  430,  433,  437,  441,  445,  449,  452,  456,  460,  464,  467,  471,  475,  478,  482,
-        485,  489,  492,  496,  499,  503,  506,  510,  513,  517,  520,  524,  527,  530,  534,  537,
-        540,  544,  547,  550,  554,  557,  560,  563,  566,  570,  573,  576,  579,  582,  586,  589,
-        592,  595,  598,  601,  604,  607,  610,  613,  616,  619,  622,  625,  628,  631,  634,  637,
-        640,  643,  646,  649,  652,  655,  658,  660,  663,  666,  669,  672,  675,  677,  680,  683,
-        686,  689,  691,  694,  697,  700,  702,  705,  708,  711,  713,  716,  719,  721,  724,  727,
-        729,  732,  735,  737,  740,  743,  745,  748,  750,  753,  756,  758,  761,  763,  766,  768,
-        771,  773,  776,  779,  781,  784,  786,  789,  791,  794,  796,  799,  801,  803,  806,  808,
-        811,  813,  816,  818,  821,  823,  825,  828,  830,  833,  835,  837,  840,  842,  844,  847,
-        849,  851,  854,  856,  858,  861,  863,  865,  868,  870,  872,  875,  877,  879,  881,  884,
-        886,  888,  891,  893,  895,  897,  900,  902,  904,  906,  908,  911,  913,  915,  917,  919,
-        922,  924,  926,  928,  930,  933,  935,  937,  939,  941,  943,  946,  948,  950,  952,  954,
-        956,  958,  960,  963,  965,  967,  969,  971,  973,  975,  977,  979,  981,  984,  986,  988,
-        990,  992,  994,  996,  998, 1000, 1002, 1004, 1006, 1008, 1010, 1012, 1014, 1016, 1018, 1020,
-       1022, 1024, 1026, 1028, 1030, 1032, 1034, 1036, 1038, 1040, 1042, 1044, 1046, 1048, 1050, 1052,
-       1054, 1056, 1058, 1060, 1062, 1064, 1066, 1068, 1069, 1071, 1073, 1075, 1077, 1079, 1081, 1083,
-       1085, 1087, 1089, 1090, 1092, 1094, 1096, 1098, 1100, 1102, 1104, 1106, 1107, 1109, 1111, 1113,
-       1115, 1117, 1119, 1120, 1122, 1124, 1126, 1128, 1130, 1131, 1133, 1135, 1137, 1139, 1141, 1142,
-       1144, 1146, 1148, 1150, 1151, 1153, 1155, 1157, 1159, 1160, 1162, 1164, 1166, 1168, 1169, 1171,
-       1173, 1175, 1176, 1178, 1180, 1182, 1184, 1185, 1187, 1189, 1191, 1192, 1194, 1196, 1198, 1199,
-       1201, 1203, 1204, 1206, 1208, 1210, 1211, 1213, 1215, 1217, 1218, 1220, 1222, 1223, 1225, 1227,
-       1228, 1230, 1232, 1234, 1235, 1237, 1239, 1240, 1242, 1244, 1245, 1247, 1249, 1250, 1252, 1254,
-       1255, 1257, 1259, 1260, 1262, 1264, 1265, 1267, 1269, 1270, 1272, 1274, 1275, 1277, 1279, 1280,
-       1282, 1283, 1285, 1287, 1288, 1290, 1292, 1293, 1295, 1296, 1298, 1300, 1301, 1303, 1305, 1306,
-       1308, 1309, 1311, 1313, 1314, 1316, 1317, 1319, 1321, 1322, 1324, 1325, 1327, 1328, 1330, 1332,
-       1333, 1335, 1336, 1338, 1339, 1341, 1343, 1344, 1346, 1347, 1349, 1350, 1352, 1354, 1355, 1357,
-       1358, 1360, 1361, 1363, 1364, 1366, 1367, 1369, 1371, 1372, 1374, 1375, 1377, 1378, 1380, 1381,
-       1383, 1384, 1386, 1387, 1389, 1390, 1392, 1393, 1395, 1396, 1398, 1399, 1401, 1402, 1404, 1405,
-       1407, 1408, 1410, 1411, 1413, 1414, 1416, 1417, 1419, 1420, 1422, 1423, 1425, 1426, 1428, 1429,
-       1431, 1432, 1434, 1435, 1437, 1438, 1440, 1441, 1442, 1444, 1445, 1447, 1448, 1450, 1451, 1453,
-       1454, 1456, 1457, 1458, 1460, 1461, 1463, 1464, 1466, 1467, 1469, 1470, 1471, 1473, 1474, 1476,
-       1477, 1479, 1480, 1481, 1483, 1484, 1486, 1487, 1489, 1490, 1491, 1493, 1494, 1496, 1497, 1498,
-       1500, 1501, 1503, 1504, 1505, 1507, 1508, 1510, 1511, 1512, 1514, 1515, 1517, 1518, 1519, 1521,
-       1522, 1524, 1525, 1526, 1528, 1529, 1531, 1532, 1533, 1535, 1536, 1537, 1539, 1540, 1542, 1543,
-       1544, 1546, 1547, 1548, 1550, 1551, 1553, 1554, 1555, 1557, 1558, 1559, 1561, 1562, 1563, 1565,
-       1566, 1567, 1569, 1570, 1571, 1573, 1574, 1576, 1577, 1578, 1580, 1581, 1582, 1584, 1585, 1586,
-       1588, 1589, 1590, 1592, 1593, 1594, 1596, 1597, 1598, 1600, 1601, 1602, 1603, 1605, 1606, 1607,
-       1609, 1610, 1611, 1613, 1614, 1615, 1617, 1618, 1619, 1621, 1622, 1623, 1624, 1626, 1627, 1628,
-       1630, 1631, 1632, 1634, 1635, 1636, 1637, 1639, 1640, 1641, 1643, 1644, 1645, 1647, 1648, 1649,
-       1650, 1652, 1653, 1654, 1655, 1657, 1658, 1659, 1661, 1662, 1663, 1664, 1666, 1667, 1668, 1670,
-       1671, 1672, 1673, 1675, 1676, 1677, 1678, 1680, 1681, 1682, 1683, 1685, 1686, 1687, 1688, 1690,
-       1691, 1692, 1693, 1695, 1696, 1697, 1698, 1700, 1701, 1702, 1703, 1705, 1706, 1707, 1708, 1710,
-       1711, 1712, 1713, 1715, 1716, 1717, 1718, 1720, 1721, 1722, 1723, 1724, 1726, 1727, 1728, 1729,
-       1731, 1732, 1733, 1734, 1736, 1737, 1738, 1739, 1740, 1742, 1743, 1744, 1745, 1746, 1748, 1749,
-       1750, 1751, 1753, 1754, 1755, 1756, 1757, 1759, 1760, 1761, 1762, 1763, 1765, 1766, 1767, 1768,
-       1769, 1771, 1772, 1773, 1774, 1775, 1777, 1778, 1779, 1780, 1781, 1783, 1784, 1785, 1786, 1787,
-       1788, 1790, 1791, 1792, 1793, 1794, 1796, 1797, 1798, 1799, 1800, 1801, 1803, 1804, 1805, 1806,
-       1807, 1809, 1810, 1811, 1812, 1813, 1814, 1816, 1817, 1818, 1819, 1820, 1821, 1823, 1824, 1825,
-       1826, 1827, 1828, 1829, 1831, 1832, 1833, 1834, 1835, 1836, 1838, 1839, 1840, 1841, 1842, 1843,
-       1845, 1846, 1847, 1848, 1849, 1850, 1851, 1853, 1854, 1855, 1856, 1857, 1858, 1859, 1861, 1862,
-       1863, 1864, 1865, 1866, 1867, 1868, 1870, 1871, 1872, 1873, 1874, 1875, 1876, 1878, 1879, 1880,
-       1881, 1882, 1883, 1884, 1885, 1887, 1888, 1889, 1890, 1891, 1892, 1893, 1894, 1896, 1897, 1898,
-       1899, 1900, 1901, 1902, 1903, 1904, 1906, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914, 1916,
-       1917, 1918, 1919, 1920, 1921, 1922, 1923, 1924, 1925, 1927, 1928, 1929, 1930, 1931, 1932, 1933,
-       1934, 1935, 1936, 1938, 1939, 1940, 1941, 1942, 1943, 1944, 1945, 1946, 1947, 1948, 1950, 1951,
-       1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960, 1961, 1963, 1964, 1965, 1966, 1967, 1968,
-       1969, 1970, 1971, 1972, 1973, 1974, 1975, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985,
-       1986, 1987, 1988, 1989, 1990, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-       2003, 2004, 2005, 2006, 2007, 2008, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
-       2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2031, 2032, 2033, 2034, 2035, 2036,
-       2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050, 2051, 2052,
-       2053, 2054, 2055, 2056, 2057, 2058, 2060, 2061, 2062, 2063, 2064, 2065, 2066, 2067, 2068, 2069,
-       2070, 2071, 2072, 2073, 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2085,
-       2086, 2087, 2088, 2089, 2090, 2091, 2092, 2093, 2094, 2095, 2096, 2097, 2098, 2099, 2100, 2101,
-       2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2114, 2115, 2116, 2117,
-       2118, 2119, 2120, 2121, 2122, 2123, 2124, 2125, 2126, 2127, 2128, 2129, 2130, 2131, 2132, 2133,
-       2134, 2135, 2136, 2137, 2138, 2139, 2140, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2149,
-       2150, 2151, 2152, 2153, 2154, 2155, 2156, 2157, 2158, 2159, 2160, 2161, 2162, 2163, 2164, 2165,
-       2166, 2167, 2168, 2169, 2170, 2171, 2172, 2173, 2173, 2174, 2175, 2176, 2177, 2178, 2179, 2180,
-       2181, 2182, 2183, 2184, 2185, 2186, 2187, 2188, 2189, 2190, 2191, 2192, 2193, 2194, 2195, 2196,
-       2197, 2198, 2199, 2200, 2201, 2202, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2210, 2211,
-       2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2221, 2222, 2223, 2224, 2224, 2225, 2226,
-       2227, 2228, 2229, 2230, 2231, 2232, 2233, 2234, 2235, 2236, 2237, 2238, 2239, 2240, 2241, 2241,
-       2242, 2243, 2244, 2245, 2246, 2247, 2248, 2249, 2250, 2251, 2252, 2253, 2254, 2255, 2256, 2257,
-       2257, 2258, 2259, 2260, 2261, 2262, 2263, 2264, 2265, 2266, 2267, 2268, 2269, 2270, 2271, 2271,
-       2272, 2273, 2274, 2275, 2276, 2277, 2278, 2279, 2280, 2281, 2282, 2283, 2283, 2284, 2285, 2286,
-       2287, 2288, 2289, 2290, 2291, 2292, 2293, 2294, 2295, 2295, 2296, 2297, 2298, 2299, 2300, 2301,
-       2302, 2303, 2304, 2305, 2306, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2315, 2316,
-       2317, 2317, 2318, 2319, 2320, 2321, 2322, 2323, 2324, 2325, 2326, 2327, 2327, 2328, 2329, 2330,
-       2331, 2332, 2333, 2334, 2335, 2336, 2336, 2337, 2338, 2339, 2340, 2341, 2342, 2343, 2344, 2345,
-       2345, 2346, 2347, 2348, 2349, 2350, 2351, 2352, 2353, 2354, 2354, 2355, 2356, 2357, 2358, 2359,
-       2360, 2361, 2362, 2363, 2363, 2364, 2365, 2366, 2367, 2368, 2369, 2370, 2371, 2371, 2372, 2373,
-       2374, 2375, 2376, 2377, 2378, 2379, 2379, 2380, 2381, 2382, 2383, 2384, 2385, 2386, 2386, 2387,
-       2388, 2389, 2390, 2391, 2392, 2393, 2394, 2394, 2395, 2396, 2397, 2398, 2399, 2400, 2401, 2401,
-       2402, 2403, 2404, 2405, 2406, 2407, 2408, 2408, 2409, 2410, 2411, 2412, 2413, 2414, 2415, 2415,
-       2416, 2417, 2418, 2419, 2420, 2421, 2422, 2422, 2423, 2424, 2425, 2426, 2427, 2428, 2428, 2429,
-       2430, 2431, 2432, 2433, 2434, 2435, 2435, 2436, 2437, 2438, 2439, 2440, 2441, 2441, 2442, 2443,
-       2444, 2445, 2446, 2447, 2447, 2448, 2449, 2450, 2451, 2452, 2453, 2453, 2454, 2455, 2456, 2457,
-       2458, 2459, 2459, 2460, 2461, 2462, 2463, 2464, 2465, 2465, 2466, 2467, 2468, 2469, 2470, 2471,
-       2471, 2472, 2473, 2474, 2475, 2476, 2477, 2477, 2478, 2479, 2480, 2481, 2482, 2482, 2483, 2484,
-       2485, 2486, 2487, 2488, 2488, 2489, 2490, 2491, 2492, 2493, 2493, 2494, 2495, 2496, 2497, 2498,
-       2499, 2499, 2500, 2501, 2502, 2503, 2504, 2504, 2505, 2506, 2507, 2508, 2509, 2509, 2510, 2511,
-       2512, 2513, 2514, 2514, 2515, 2516, 2517, 2518, 2519, 2519, 2520, 2521, 2522, 2523, 2524, 2524,
-       2525, 2526, 2527, 2528, 2529, 2529, 2530, 2531, 2532, 2533, 2534, 2534, 2535, 2536, 2537, 2538,
-       2539, 2539, 2540, 2541, 2542, 2543, 2544, 2544, 2545, 2546, 2547, 2548, 2548, 2549, 2550, 2551,
-       2552, 2553, 2553, 2554, 2555, 2556, 2557, 2558, 2558, 2559, 2560, 2561, 2562, 2562, 2563, 2564,
-       2565, 2566, 2567, 2567, 2568, 2569, 2570, 2571, 2571, 2572, 2573, 2574, 2575, 2576, 2576, 2577,
-       2578, 2579, 2580, 2580, 2581, 2582, 2583, 2584, 2584, 2585, 2586, 2587, 2588, 2589, 2589, 2590,
-       2591, 2592, 2593, 2593, 2594, 2595, 2596, 2597, 2597, 2598, 2599, 2600, 2601, 2601, 2602, 2603,
-       2604, 2605, 2605, 2606, 2607, 2608, 2609, 2610, 2610, 2611, 2612, 2613, 2614, 2614, 2615, 2616,
-       2617, 2618, 2618, 2619, 2620, 2621, 2622, 2622, 2623, 2624, 2625, 2626, 2626, 2627, 2628, 2629,
-       2630, 2630, 2631, 2632, 2633, 2634, 2634, 2635, 2636, 2637, 2637, 2638, 2639, 2640, 2641, 2641,
-       2642, 2643, 2644, 2645, 2645, 2646, 2647, 2648, 2649, 2649, 2650, 2651, 2652, 2653, 2653, 2654,
-       2655, 2656, 2656, 2657, 2658, 2659, 2660, 2660, 2661, 2662, 2663, 2664, 2664, 2665, 2666, 2667,
-       2668, 2668, 2669, 2670, 2671, 2671, 2672, 2673, 2674, 2675, 2675, 2676, 2677, 2678, 2678, 2679,
-       2680, 2681, 2682, 2682, 2683, 2684, 2685, 2686, 2686, 2687, 2688, 2689, 2689, 2690, 2691, 2692,
-       2693, 2693, 2694, 2695, 2696, 2696, 2697, 2698, 2699, 2700, 2700, 2701, 2702, 2703, 2703, 2704,
-       2705, 2706, 2706, 2707, 2708, 2709, 2710, 2710, 2711, 2712, 2713, 2713, 2714, 2715, 2716, 2717,
-       2717, 2718, 2719, 2720, 2720, 2721, 2722, 2723, 2723, 2724, 2725, 2726, 2727, 2727, 2728, 2729,
-       2730, 2730, 2731, 2732, 2733, 2733, 2734, 2735, 2736, 2736, 2737, 2738, 2739, 2740, 2740, 2741,
-       2742, 2743, 2743, 2744, 2745, 2746, 2746, 2747, 2748, 2749, 2749, 2750, 2751, 2752, 2752, 2753,
-       2754, 2755, 2755, 2756, 2757, 2758, 2759, 2759, 2760, 2761, 2762, 2762, 2763, 2764, 2765, 2765,
-       2766, 2767, 2768, 2768, 2769, 2770, 2771, 2771, 2772, 2773, 2774, 2774, 2775, 2776, 2777, 2777,
-       2778, 2779, 2780, 2780, 2781, 2782, 2783, 2783, 2784, 2785, 2786, 2786, 2787, 2788, 2789, 2789,
-       2790, 2791, 2792, 2792, 2793, 2794, 2795, 2795, 2796, 2797, 2798, 2798, 2799, 2800, 2801, 2801,
-       2802, 2803, 2804, 2804, 2805, 2806, 2807, 2807, 2808, 2809, 2810, 2810, 2811, 2812, 2813, 2813,
-       2814, 2815, 2815, 2816, 2817, 2818, 2818, 2819, 2820, 2821, 2821, 2822, 2823, 2824, 2824, 2825,
-       2826, 2827, 2827, 2828, 2829, 2830, 2830, 2831, 2832, 2832, 2833, 2834, 2835, 2835, 2836, 2837,
-       2838, 2838, 2839, 2840, 2841, 2841, 2842, 2843, 2844, 2844, 2845, 2846, 2846, 2847, 2848, 2849,
-       2849, 2850, 2851, 2852, 2852, 2853, 2854, 2855, 2855, 2856, 2857, 2857, 2858, 2859, 2860, 2860,
-       2861, 2862, 2863, 2863, 2864, 2865, 2865, 2866, 2867, 2868, 2868, 2869, 2870, 2871, 2871, 2872,
-       2873, 2873, 2874, 2875, 2876, 2876, 2877, 2878, 2879, 2879, 2880, 2881, 2881, 2882, 2883, 2884,
-       2884, 2885, 2886, 2886, 2887, 2888, 2889, 2889, 2890, 2891, 2892, 2892, 2893, 2894, 2894, 2895,
-       2896, 2897, 2897, 2898, 2899, 2899, 2900, 2901, 2902, 2902, 2903, 2904, 2904, 2905, 2906, 2907,
-       2907, 2908, 2909, 2909, 2910, 2911, 2912, 2912, 2913, 2914, 2914, 2915, 2916, 2917, 2917, 2918,
-       2919, 2919, 2920, 2921, 2922, 2922, 2923, 2924, 2924, 2925, 2926, 2927, 2927, 2928, 2929, 2929,
-       2930, 2931, 2932, 2932, 2933, 2934, 2934, 2935, 2936, 2937, 2937, 2938, 2939, 2939, 2940, 2941,
-       2941, 2942, 2943, 2944, 2944, 2945, 2946, 2946, 2947, 2948, 2949, 2949, 2950, 2951, 2951, 2952,
-       2953, 2953, 2954, 2955, 2956, 2956, 2957, 2958, 2958, 2959, 2960, 2961, 2961, 2962, 2963, 2963,
-       2964, 2965, 2965, 2966, 2967, 2968, 2968, 2969, 2970, 2970, 2971, 2972, 2972, 2973, 2974, 2975,
-       2975, 2976, 2977, 2977, 2978, 2979, 2979, 2980, 2981, 2982, 2982, 2983, 2984, 2984, 2985, 2986,
-       2986, 2987, 2988, 2988, 2989, 2990, 2991, 2991, 2992, 2993, 2993, 2994, 2995, 2995, 2996, 2997,
-       2998, 2998, 2999, 3000, 3000, 3001, 3002, 3002, 3003, 3004, 3004, 3005, 3006, 3006, 3007, 3008,
-       3009, 3009, 3010, 3011, 3011, 3012, 3013, 3013, 3014, 3015, 3015, 3016, 3017, 3018, 3018, 3019,
-       3020, 3020, 3021, 3022, 3022, 3023, 3024, 3024, 3025, 3026, 3026, 3027, 3028, 3029, 3029, 3030,
-       3031, 3031, 3032, 3033, 3033, 3034, 3035, 3035, 3036, 3037, 3037, 3038, 3039, 3039, 3040, 3041,
-       3042, 3042, 3043, 3044, 3044, 3045, 3046, 3046, 3047, 3048, 3048, 3049, 3050, 3050, 3051, 3052,
-       3052, 3053, 3054, 3054, 3055, 3056, 3056, 3057, 3058, 3059, 3059, 3060, 3061, 3061, 3062, 3063,
-       3063, 3064, 3065, 3065, 3066, 3067, 3067, 3068, 3069, 3069, 3070, 3071, 3071, 3072, 3073, 3073,
-       3074, 3075, 3075, 3076, 3077, 3077, 3078, 3079, 3079, 3080, 3081, 3081, 3082, 3083, 3084, 3084,
-       3085, 3086, 3086, 3087, 3088, 3088, 3089, 3090, 3090, 3091, 3092, 3092, 3093, 3094, 3094, 3095,
-       3096, 3096, 3097, 3098, 3098, 3099, 3100, 3100, 3101, 3102, 3102, 3103, 3104, 3104, 3105, 3106,
-       3106, 3107, 3108, 3108, 3109, 3110, 3110, 3111, 3112, 3112, 3113, 3114, 3114, 3115, 3116, 3116,
-       3117, 3118, 3118, 3119, 3120, 3120, 3121, 3122, 3122, 3123, 3124, 3124, 3125, 3126, 3126, 3127,
-       3128, 3128, 3129, 3130, 3130, 3131, 3132, 3132, 3133, 3134, 3134, 3135, 3135, 3136, 3137, 3137,
-       3138, 3139, 3139, 3140, 3141, 3141, 3142, 3143, 3143, 3144, 3145, 3145, 3146, 3147, 3147, 3148,
-       3149, 3149, 3150, 3151, 3151, 3152, 3153, 3153, 3154, 3155, 3155, 3156, 3157, 3157, 3158, 3159,
-       3159, 3160, 3160, 3161, 3162, 3162, 3163, 3164, 3164, 3165, 3166, 3166, 3167, 3168, 3168, 3169,
-       3170, 3170, 3171, 3172, 3172, 3173, 3174, 3174, 3175, 3175, 3176, 3177, 3177, 3178, 3179, 3179,
-       3180, 3181, 3181, 3182, 3183, 3183, 3184, 3185, 3185, 3186, 3187, 3187, 3188, 3188, 3189, 3190,
-       3190, 3191, 3192, 3192, 3193, 3194, 3194, 3195, 3196, 3196, 3197, 3198, 3198, 3199, 3199, 3200,
-       3201, 3201, 3202, 3203, 3203, 3204, 3205, 3205, 3206, 3207, 3207, 3208, 3209, 3209, 3210, 3210,
-       3211, 3212, 3212, 3213, 3214, 3214, 3215, 3216, 3216, 3217, 3218, 3218, 3219, 3219, 3220, 3221,
-       3221, 3222, 3223, 3223, 3224, 3225, 3225, 3226, 3227, 3227, 3228, 3228, 3229, 3230, 3230, 3231,
-       3232, 3232, 3233, 3234, 3234, 3235, 3235, 3236, 3237, 3237, 3238, 3239, 3239, 3240, 3241, 3241,
-       3242, 3242, 3243, 3244, 3244, 3245, 3246, 3246, 3247, 3248, 3248, 3249, 3249, 3250, 3251, 3251,
-       3252, 3253, 3253, 3254, 3255, 3255, 3256, 3256, 3257, 3258, 3258, 3259, 3260, 3260, 3261, 3262,
-       3262, 3263, 3263, 3264, 3265, 3265, 3266, 3267, 3267, 3268, 3268, 3269, 3270, 3270, 3271, 3272,
-       3272, 3273, 3274, 3274, 3275, 3275, 3276, 3277, 3277, 3278, 3279, 3279, 3280, 3280, 3281, 3282,
-       3282, 3283, 3284, 3284, 3285, 3285, 3286, 3287, 3287, 3288, 3289, 3289, 3290, 3290, 3291, 3292,
-       3292, 3293, 3294, 3294, 3295, 3295, 3296, 3297, 3297, 3298, 3299, 3299, 3300, 3300, 3301, 3302,
-       3302, 3303, 3304, 3304, 3305, 3305, 3306, 3307, 3307, 3308, 3309, 3309, 3310, 3310, 3311, 3312,
-       3312, 3313, 3314, 3314, 3315, 3315, 3316, 3317, 3317, 3318, 3319, 3319, 3320, 3320, 3321, 3322,
-       3322, 3323, 3323, 3324, 3325, 3325, 3326, 3327, 3327, 3328, 3328, 3329, 3330, 3330, 3331, 3332,
-       3332, 3333, 3333, 3334, 3335, 3335, 3336, 3336, 3337, 3338, 3338, 3339, 3340, 3340, 3341, 3341,
-       3342, 3343, 3343, 3344, 3345, 3345, 3346, 3346, 3347, 3348, 3348, 3349, 3349, 3350, 3351, 3351,
-       3352, 3352, 3353, 3354, 3354, 3355, 3356, 3356, 3357, 3357, 3358, 3359, 3359, 3360, 3360, 3361,
-       3362, 3362, 3363, 3364, 3364, 3365, 3365, 3366, 3367, 3367, 3368, 3368, 3369, 3370, 3370, 3371,
-       3371, 3372, 3373, 3373, 3374, 3375, 3375, 3376, 3376, 3377, 3378, 3378, 3379, 3379, 3380, 3381,
-       3381, 3382, 3382, 3383, 3384, 3384, 3385, 3385, 3386, 3387, 3387, 3388, 3389, 3389, 3390, 3390,
-       3391, 3392, 3392, 3393, 3393, 3394, 3395, 3395, 3396, 3396, 3397, 3398, 3398, 3399, 3399, 3400,
-       3401, 3401, 3402, 3402, 3403, 3404, 3404, 3405, 3405, 3406, 3407, 3407, 3408, 3408, 3409, 3410,
-       3410, 3411, 3411, 3412, 3413, 3413, 3414, 3414, 3415, 3416, 3416, 3417, 3418, 3418, 3419, 3419,
-       3420, 3421, 3421, 3422, 3422, 3423, 3424, 3424, 3425, 3425, 3426, 3427, 3427, 3428, 3428, 3429,
-       3430, 3430, 3431, 3431, 3432, 3433, 3433, 3434, 3434, 3435, 3435, 3436, 3437, 3437, 3438, 3438,
-       3439, 3440, 3440, 3441, 3441, 3442, 3443, 3443, 3444, 3444, 3445, 3446, 3446, 3447, 3447, 3448,
-       3449, 3449, 3450, 3450, 3451, 3452, 3452, 3453, 3453, 3454, 3455, 3455, 3456, 3456, 3457, 3458,
-       3458, 3459, 3459, 3460, 3461, 3461, 3462, 3462, 3463, 3463, 3464, 3465, 3465, 3466, 3466, 3467,
-       3468, 3468, 3469, 3469, 3470, 3471, 3471, 3472, 3472, 3473, 3474, 3474, 3475, 3475, 3476, 3476,
-       3477, 3478, 3478, 3479, 3479, 3480, 3481, 3481, 3482, 3482, 3483, 3484, 3484, 3485, 3485, 3486,
-       3486, 3487, 3488, 3488, 3489, 3489, 3490, 3491, 3491, 3492, 3492, 3493, 3494, 3494, 3495, 3495,
-       3496, 3496, 3497, 3498, 3498, 3499, 3499, 3500, 3501, 3501, 3502, 3502, 3503, 3504, 3504, 3505,
-       3505, 3506, 3506, 3507, 3508, 3508, 3509, 3509, 3510, 3511, 3511, 3512, 3512, 3513, 3513, 3514,
-       3515, 3515, 3516, 3516, 3517, 3518, 3518, 3519, 3519, 3520, 3520, 3521, 3522, 3522, 3523, 3523,
-       3524, 3525, 3525, 3526, 3526, 3527, 3527, 3528, 3529, 3529, 3530, 3530, 3531, 3531, 3532, 3533,
-       3533, 3534, 3534, 3535, 3536, 3536, 3537, 3537, 3538, 3538, 3539, 3540, 3540, 3541, 3541, 3542,
-       3542, 3543, 3544, 3544, 3545, 3545, 3546, 3547, 3547, 3548, 3548, 3549, 3549, 3550, 3551, 3551,
-       3552, 3552, 3553, 3553, 3554, 3555, 3555, 3556, 3556, 3557, 3557, 3558, 3559, 3559, 3560, 3560,
-       3561, 3561, 3562, 3563, 3563, 3564, 3564, 3565, 3566, 3566, 3567, 3567, 3568, 3568, 3569, 3570,
-       3570, 3571, 3571, 3572, 3572, 3573, 3574, 3574, 3575, 3575, 3576, 3576, 3577, 3578, 3578, 3579,
-       3579, 3580, 3580, 3581, 3582, 3582, 3583, 3583, 3584, 3584, 3585, 3586, 3586, 3587, 3587, 3588,
-       3588, 3589, 3590, 3590, 3591, 3591, 3592, 3592, 3593, 3594, 3594, 3595, 3595, 3596, 3596, 3597,
-       3597, 3598, 3599, 3599, 3600, 3600, 3601, 3601, 3602, 3603, 3603, 3604, 3604, 3605, 3605, 3606,
-       3607, 3607, 3608, 3608, 3609, 3609, 3610, 3611, 3611, 3612, 3612, 3613, 3613, 3614, 3615, 3615,
-       3616, 3616, 3617, 3617, 3618, 3618, 3619, 3620, 3620, 3621, 3621, 3622, 3622, 3623, 3624, 3624,
-       3625, 3625, 3626, 3626, 3627, 3627, 3628, 3629, 3629, 3630, 3630, 3631, 3631, 3632, 3633, 3633,
-       3634, 3634, 3635, 3635, 3636, 3636, 3637, 3638, 3638, 3639, 3639, 3640, 3640, 3641, 3642, 3642,
-       3643, 3643, 3644, 3644, 3645, 3645, 3646, 3647, 3647, 3648, 3648, 3649, 3649, 3650, 3650, 3651,
-       3652, 3652, 3653, 3653, 3654, 3654, 3655, 3656, 3656, 3657, 3657, 3658, 3658, 3659, 3659, 3660,
-       3661, 3661, 3662, 3662, 3663, 3663, 3664, 3664, 3665, 3666, 3666, 3667, 3667, 3668, 3668, 3669,
-       3669, 3670, 3671, 3671, 3672, 3672, 3673, 3673, 3674, 3674, 3675, 3676, 3676, 3677, 3677, 3678,
-       3678, 3679, 3679, 3680, 3681, 3681, 3682, 3682, 3683, 3683, 3684, 3684, 3685, 3686, 3686, 3687,
-       3687, 3688, 3688, 3689, 3689, 3690, 3691, 3691, 3692, 3692, 3693, 3693, 3694, 3694, 3695, 3695,
-       3696, 3697, 3697, 3698, 3698, 3699, 3699, 3700, 3700, 3701, 3702, 3702, 3703, 3703, 3704, 3704,
-       3705, 3705, 3706, 3707, 3707, 3708, 3708, 3709, 3709, 3710, 3710, 3711, 3711, 3712, 3713, 3713,
-       3714, 3714, 3715, 3715, 3716, 3716, 3717, 3717, 3718, 3719, 3719, 3720, 3720, 3721, 3721, 3722,
-       3722, 3723, 3724, 3724, 3725, 3725, 3726, 3726, 3727, 3727, 3728, 3728, 3729, 3730, 3730, 3731,
-       3731, 3732, 3732, 3733, 3733, 3734, 3734, 3735, 3736, 3736, 3737, 3737, 3738, 3738, 3739, 3739,
-       3740, 3740, 3741, 3742, 3742, 3743, 3743, 3744, 3744, 3745, 3745, 3746, 3746, 3747, 3748, 3748,
-       3749, 3749, 3750, 3750, 3751, 3751, 3752, 3752, 3753, 3753, 3754, 3755, 3755, 3756, 3756, 3757,
-       3757, 3758, 3758, 3759, 3759, 3760, 3761, 3761, 3762, 3762, 3763, 3763, 3764, 3764, 3765, 3765,
-       3766, 3766, 3767, 3768, 3768, 3769, 3769, 3770, 3770, 3771, 3771, 3772, 3772, 3773, 3773, 3774,
-       3775, 3775, 3776, 3776, 3777, 3777, 3778, 3778, 3779, 3779, 3780, 3781, 3781, 3782, 3782, 3783,
-       3783, 3784, 3784, 3785, 3785, 3786, 3786, 3787, 3787, 3788, 3789, 3789, 3790, 3790, 3791, 3791,
-       3792, 3792, 3793, 3793, 3794, 3794, 3795, 3796, 3796, 3797, 3797, 3798, 3798, 3799, 3799, 3800,
-       3800, 3801, 3801, 3802, 3802, 3803, 3804, 3804, 3805, 3805, 3806, 3806, 3807, 3807, 3808, 3808,
-       3809, 3809, 3810, 3811, 3811, 3812, 3812, 3813, 3813, 3814, 3814, 3815, 3815, 3816, 3816, 3817,
-       3817, 3818, 3819, 3819, 3820, 3820, 3821, 3821, 3822, 3822, 3823, 3823, 3824, 3824, 3825, 3825,
-       3826, 3826, 3827, 3828, 3828, 3829, 3829, 3830, 3830, 3831, 3831, 3832, 3832, 3833, 3833, 3834,
-       3834, 3835, 3835, 3836, 3837, 3837, 3838, 3838, 3839, 3839, 3840, 3840, 3841, 3841, 3842, 3842,
-       3843, 3843, 3844, 3844, 3845, 3846, 3846, 3847, 3847, 3848, 3848, 3849, 3849, 3850, 3850, 3851,
-       3851, 3852, 3852, 3853, 3853, 3854, 3855, 3855, 3856, 3856, 3857, 3857, 3858, 3858, 3859, 3859,
-       3860, 3860, 3861, 3861, 3862, 3862, 3863, 3863, 3864, 3864, 3865, 3866, 3866, 3867, 3867, 3868,
-       3868, 3869, 3869, 3870, 3870, 3871, 3871, 3872, 3872, 3873, 3873, 3874, 3874, 3875, 3876, 3876,
-       3877, 3877, 3878, 3878, 3879, 3879, 3880, 3880, 3881, 3881, 3882, 3882, 3883, 3883, 3884, 3884,
-       3885, 3885, 3886, 3886, 3887, 3888, 3888, 3889, 3889, 3890, 3890, 3891, 3891, 3892, 3892, 3893,
-       3893, 3894, 3894, 3895, 3895, 3896, 3896, 3897, 3897, 3898, 3898, 3899, 3900, 3900, 3901, 3901,
-       3902, 3902, 3903, 3903, 3904, 3904, 3905, 3905, 3906, 3906, 3907, 3907, 3908, 3908, 3909, 3909,
-       3910, 3910, 3911, 3911, 3912, 3912, 3913, 3914, 3914, 3915, 3915, 3916, 3916, 3917, 3917, 3918,
-       3918, 3919, 3919, 3920, 3920, 3921, 3921, 3922, 3922, 3923, 3923, 3924, 3924, 3925, 3925, 3926,
-       3926, 3927, 3927, 3928, 3929, 3929, 3930, 3930, 3931, 3931, 3932, 3932, 3933, 3933, 3934, 3934,
-       3935, 3935, 3936, 3936, 3937, 3937, 3938, 3938, 3939, 3939, 3940, 3940, 3941, 3941, 3942, 3942,
-       3943, 3943, 3944, 3944, 3945, 3945, 3946, 3947, 3947, 3948, 3948, 3949, 3949, 3950, 3950, 3951,
-       3951, 3952, 3952, 3953, 3953, 3954, 3954, 3955, 3955, 3956, 3956, 3957, 3957, 3958, 3958, 3959,
-       3959, 3960, 3960, 3961, 3961, 3962, 3962, 3963, 3963, 3964, 3964, 3965, 3965, 3966, 3966, 3967,
-       3967, 3968, 3969, 3969, 3970, 3970, 3971, 3971, 3972, 3972, 3973, 3973, 3974, 3974, 3975, 3975,
-       3976, 3976, 3977, 3977, 3978, 3978, 3979, 3979, 3980, 3980, 3981, 3981, 3982, 3982, 3983, 3983,
-       3984, 3984, 3985, 3985, 3986, 3986, 3987, 3987, 3988, 3988, 3989, 3989, 3990, 3990, 3991, 3991,
-       3992, 3992, 3993, 3993, 3994, 3994, 3995, 3995, 3996, 3996, 3997, 3997, 3998, 3998, 3999, 3999,
-       4000, 4001, 4001, 4002, 4002, 4003, 4003, 4004, 4004, 4005, 4005, 4006, 4006, 4007, 4007, 4008,
-       4008, 4009, 4009, 4010, 4010, 4011, 4011, 4012, 4012, 4013, 4013, 4014, 4014, 4015, 4015, 4016,
-       4016, 4017, 4017, 4018, 4018, 4019, 4019, 4020, 4020, 4021, 4021, 4022, 4022, 4023, 4023, 4024,
-       4024, 4025, 4025, 4026, 4026, 4027, 4027, 4028, 4028, 4029, 4029, 4030, 4030, 4031, 4031, 4032,
-       4032, 4033, 4033, 4034, 4034, 4035, 4035, 4036, 4036, 4037, 4037, 4038, 4038, 4039, 4039, 4040,
-       4040, 4041, 4041, 4042, 4042, 4043, 4043, 4044, 4044, 4045, 4045, 4046, 4046, 4047, 4047, 4048,
-       4048, 4049, 4049, 4050, 4050, 4051, 4051, 4052, 4052, 4053, 4053, 4054, 4054, 4055, 4055, 4056,
-       4056, 4057, 4057, 4058, 4058, 4059, 4059, 4060, 4060, 4061, 4061, 4062, 4062, 4063, 4063, 4064,
-       4064, 4065, 4065, 4066, 4066, 4067, 4067, 4068, 4068, 4069, 4069, 4070, 4070, 4071, 4071, 4072,
-       4072, 4073, 4073, 4074, 4074, 4075, 4075, 4076, 4076, 4077, 4077, 4078, 4078, 4079, 4079, 4080,
-       4080,
-};
-
-/* Generated table */
-const struct color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFER_FUNC_SMPTE2084 + 1][TPG_COLOR_CSC_BLACK + 1] = {
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][1] = { 2953, 2963, 586 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][2] = { 0, 2967, 2937 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][3] = { 88, 2990, 575 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][4] = { 3016, 259, 2933 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][5] = { 3030, 405, 558 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][6] = { 478, 428, 2931 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][1] = { 3068, 3077, 838 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][2] = { 0, 3081, 3053 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][3] = { 241, 3102, 828 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][4] = { 3126, 504, 3050 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][5] = { 3138, 657, 810 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][6] = { 731, 680, 3048 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][7] = { 800, 799, 800 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][1] = { 3046, 3054, 886 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][2] = { 0, 3058, 3031 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][3] = { 360, 3079, 877 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][4] = { 3103, 587, 3027 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][5] = { 3116, 723, 861 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][6] = { 789, 744, 3025 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][1] = { 2941, 2950, 546 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][2] = { 0, 2954, 2924 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][3] = { 78, 2978, 536 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][4] = { 3004, 230, 2920 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][5] = { 3018, 363, 518 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][6] = { 437, 387, 2918 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][1] = { 2145, 2159, 142 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][2] = { 0, 2164, 2122 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][3] = { 19, 2198, 138 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][4] = { 2236, 57, 2116 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][5] = { 2256, 90, 133 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][6] = { 110, 96, 2113 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_DCI_P3][0] = { 3175, 3175, 3175 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_DCI_P3][1] = { 3186, 3194, 1121 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_DCI_P3][2] = { 0, 3197, 3173 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_DCI_P3][3] = { 523, 3216, 1112 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_DCI_P3][4] = { 3237, 792, 3169 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_DCI_P3][5] = { 3248, 944, 1094 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_DCI_P3][6] = { 1017, 967, 3168 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][1] = { 3802, 3805, 2602 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][2] = { 0, 3806, 3797 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][3] = { 1780, 3812, 2592 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][4] = { 3820, 2215, 3796 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][5] = { 3824, 2409, 2574 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][6] = { 2491, 2435, 3795 },
-       [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][1] = { 2953, 2963, 586 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][2] = { 0, 2967, 2937 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][3] = { 88, 2990, 575 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][4] = { 3016, 259, 2933 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][5] = { 3030, 405, 558 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][6] = { 478, 428, 2931 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][1] = { 3068, 3077, 838 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][2] = { 0, 3081, 3053 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][3] = { 241, 3102, 828 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][4] = { 3126, 504, 3050 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][5] = { 3138, 657, 810 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][6] = { 731, 680, 3048 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][7] = { 800, 799, 800 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][1] = { 3046, 3054, 886 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][2] = { 0, 3058, 3031 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][3] = { 360, 3079, 877 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][4] = { 3103, 587, 3027 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][5] = { 3116, 723, 861 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][6] = { 789, 744, 3025 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][1] = { 2941, 2950, 546 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][2] = { 0, 2954, 2924 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][3] = { 78, 2978, 536 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][4] = { 3004, 230, 2920 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][5] = { 3018, 363, 518 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][6] = { 437, 387, 2918 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][1] = { 2145, 2159, 142 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][2] = { 0, 2164, 2122 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][3] = { 19, 2198, 138 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][4] = { 2236, 57, 2116 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][5] = { 2256, 90, 133 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][6] = { 110, 96, 2113 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_DCI_P3][0] = { 3175, 3175, 3175 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_DCI_P3][1] = { 3186, 3194, 1121 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_DCI_P3][2] = { 0, 3197, 3173 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_DCI_P3][3] = { 523, 3216, 1112 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_DCI_P3][4] = { 3237, 792, 3169 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_DCI_P3][5] = { 3248, 944, 1094 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_DCI_P3][6] = { 1017, 967, 3168 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][1] = { 3802, 3805, 2602 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][2] = { 0, 3806, 3797 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][3] = { 1780, 3812, 2592 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][4] = { 3820, 2215, 3796 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][5] = { 3824, 2409, 2574 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][6] = { 2491, 2435, 3795 },
-       [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][1] = { 2939, 2939, 547 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][2] = { 547, 2939, 2939 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][3] = { 547, 2939, 547 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][4] = { 2939, 547, 2939 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][5] = { 2939, 547, 547 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][6] = { 547, 547, 2939 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][1] = { 3056, 3056, 800 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][2] = { 800, 3056, 3056 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][3] = { 800, 3056, 800 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][4] = { 3056, 800, 3056 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][5] = { 3056, 800, 800 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][6] = { 800, 800, 3056 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 800 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][1] = { 3033, 3033, 851 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][2] = { 851, 3033, 3033 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][3] = { 851, 3033, 851 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][4] = { 3033, 851, 3033 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][5] = { 3033, 851, 851 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][6] = { 851, 851, 3033 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][1] = { 2926, 2926, 507 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][2] = { 507, 2926, 2926 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][3] = { 507, 2926, 507 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][4] = { 2926, 507, 2926 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][5] = { 2926, 507, 507 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][6] = { 507, 507, 2926 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][1] = { 2125, 2125, 130 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][2] = { 130, 2125, 2125 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][3] = { 130, 2125, 130 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][4] = { 2125, 130, 2125 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][5] = { 2125, 130, 130 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][6] = { 130, 130, 2125 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_DCI_P3][0] = { 3175, 3175, 3175 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_DCI_P3][1] = { 3175, 3175, 1084 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_DCI_P3][2] = { 1084, 3175, 3175 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_DCI_P3][3] = { 1084, 3175, 1084 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_DCI_P3][4] = { 3175, 1084, 3175 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_DCI_P3][5] = { 3175, 1084, 1084 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_DCI_P3][6] = { 1084, 1084, 3175 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][1] = { 3798, 3798, 2563 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][2] = { 2563, 3798, 3798 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][3] = { 2563, 3798, 2563 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][4] = { 3798, 2563, 3798 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][5] = { 3798, 2563, 2563 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][6] = { 2563, 2563, 3798 },
-       [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][1] = { 2892, 3034, 910 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][2] = { 1715, 2916, 2914 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][3] = { 1631, 3012, 828 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][4] = { 2497, 119, 2867 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][5] = { 2440, 649, 657 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][6] = { 740, 0, 2841 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3055, 3056 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][1] = { 3013, 3142, 1157 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][2] = { 1926, 3034, 3032 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][3] = { 1847, 3121, 1076 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][4] = { 2651, 304, 2990 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][5] = { 2599, 901, 909 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][6] = { 991, 0, 2966 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][7] = { 800, 799, 800 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][1] = { 2989, 3120, 1180 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][2] = { 1913, 3011, 3009 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][3] = { 1836, 3099, 1105 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][4] = { 2627, 413, 2966 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][5] = { 2576, 943, 951 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][6] = { 1026, 0, 2942 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][1] = { 2879, 3022, 874 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][2] = { 1688, 2903, 2901 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][3] = { 1603, 2999, 791 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][4] = { 2479, 106, 2853 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][5] = { 2422, 610, 618 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][6] = { 702, 0, 2827 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][1] = { 2059, 2262, 266 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][2] = { 771, 2092, 2089 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][3] = { 705, 2229, 231 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][4] = { 1550, 26, 2024 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][5] = { 1484, 163, 165 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][6] = { 196, 0, 1988 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_DCI_P3][0] = { 3175, 3175, 3175 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_DCI_P3][1] = { 3136, 3251, 1429 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_DCI_P3][2] = { 2150, 3156, 3154 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_DCI_P3][3] = { 2077, 3233, 1352 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_DCI_P3][4] = { 2812, 589, 3116 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_DCI_P3][5] = { 2765, 1182, 1190 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_DCI_P3][6] = { 1270, 0, 3094 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][1] = { 3784, 3825, 2879 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][2] = { 3351, 3791, 3790 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][3] = { 3311, 3819, 2815 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][4] = { 3659, 1900, 3777 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][5] = { 3640, 2662, 2669 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][6] = { 2743, 0, 3769 },
-       [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][1] = { 2939, 2939, 464 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][2] = { 786, 2939, 2939 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][3] = { 786, 2939, 464 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][4] = { 2879, 547, 2956 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][5] = { 2879, 547, 547 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][6] = { 547, 547, 2956 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][1] = { 3056, 3056, 717 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][2] = { 1036, 3056, 3056 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][3] = { 1036, 3056, 717 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][4] = { 3001, 800, 3071 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][5] = { 3001, 800, 799 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][6] = { 800, 800, 3071 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 799 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][1] = { 3033, 3033, 776 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][2] = { 1068, 3033, 3033 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][3] = { 1068, 3033, 776 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][4] = { 2977, 851, 3048 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][5] = { 2977, 851, 851 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][6] = { 851, 851, 3048 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][1] = { 2926, 2926, 423 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][2] = { 749, 2926, 2926 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][3] = { 749, 2926, 423 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][4] = { 2865, 507, 2943 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][5] = { 2865, 507, 507 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][6] = { 507, 507, 2943 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][1] = { 2125, 2125, 106 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][2] = { 214, 2125, 2125 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][3] = { 214, 2125, 106 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][4] = { 2041, 130, 2149 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][5] = { 2041, 130, 130 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][6] = { 130, 130, 2149 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_DCI_P3][0] = { 3175, 3175, 3175 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_DCI_P3][1] = { 3175, 3175, 1003 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_DCI_P3][2] = { 1313, 3175, 3175 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_DCI_P3][3] = { 1313, 3175, 1003 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_DCI_P3][4] = { 3126, 1084, 3188 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_DCI_P3][5] = { 3126, 1084, 1084 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_DCI_P3][6] = { 1084, 1084, 3188 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][1] = { 3798, 3798, 2476 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][2] = { 2782, 3798, 3798 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][3] = { 2782, 3798, 2476 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][4] = { 3780, 2563, 3803 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][5] = { 3780, 2563, 2563 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][6] = { 2563, 2563, 3803 },
-       [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][1] = { 2939, 2939, 547 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][2] = { 547, 2939, 2939 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][3] = { 547, 2939, 547 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][4] = { 2939, 547, 2939 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][5] = { 2939, 547, 547 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][6] = { 547, 547, 2939 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][1] = { 3056, 3056, 800 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][2] = { 800, 3056, 3056 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][3] = { 800, 3056, 800 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][4] = { 3056, 800, 3056 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][5] = { 3056, 800, 800 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][6] = { 800, 800, 3056 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 800 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][1] = { 3033, 3033, 851 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][2] = { 851, 3033, 3033 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][3] = { 851, 3033, 851 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][4] = { 3033, 851, 3033 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][5] = { 3033, 851, 851 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][6] = { 851, 851, 3033 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][1] = { 2926, 2926, 507 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][2] = { 507, 2926, 2926 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][3] = { 507, 2926, 507 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][4] = { 2926, 507, 2926 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][5] = { 2926, 507, 507 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][6] = { 507, 507, 2926 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][1] = { 2125, 2125, 130 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][2] = { 130, 2125, 2125 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][3] = { 130, 2125, 130 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][4] = { 2125, 130, 2125 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][5] = { 2125, 130, 130 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][6] = { 130, 130, 2125 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_DCI_P3][0] = { 3175, 3175, 3175 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_DCI_P3][1] = { 3175, 3175, 1084 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_DCI_P3][2] = { 1084, 3175, 3175 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_DCI_P3][3] = { 1084, 3175, 1084 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_DCI_P3][4] = { 3175, 1084, 3175 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_DCI_P3][5] = { 3175, 1084, 1084 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_DCI_P3][6] = { 1084, 1084, 3175 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][1] = { 3798, 3798, 2563 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][2] = { 2563, 3798, 3798 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][3] = { 2563, 3798, 2563 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][4] = { 3798, 2563, 3798 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][5] = { 3798, 2563, 2563 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][6] = { 2563, 2563, 3798 },
-       [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][1] = { 2939, 2939, 781 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][2] = { 1622, 2939, 2939 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][3] = { 1622, 2939, 781 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][4] = { 2502, 547, 2881 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][5] = { 2502, 547, 547 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][6] = { 547, 547, 2881 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][1] = { 3056, 3056, 1031 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][2] = { 1838, 3056, 3056 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][3] = { 1838, 3056, 1031 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][4] = { 2657, 800, 3002 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][5] = { 2657, 800, 800 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][6] = { 800, 800, 3002 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 800 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][1] = { 3033, 3033, 1063 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][2] = { 1828, 3033, 3033 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][3] = { 1828, 3033, 1063 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][4] = { 2633, 851, 2979 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][5] = { 2633, 851, 851 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][6] = { 851, 851, 2979 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][1] = { 2926, 2926, 744 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][2] = { 1594, 2926, 2926 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][3] = { 1594, 2926, 744 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][4] = { 2484, 507, 2867 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][5] = { 2484, 507, 507 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][6] = { 507, 507, 2867 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][1] = { 2125, 2125, 212 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][2] = { 698, 2125, 2125 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][3] = { 698, 2125, 212 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][4] = { 1557, 130, 2043 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][5] = { 1557, 130, 130 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][6] = { 130, 130, 2043 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][0] = { 3175, 3175, 3175 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][1] = { 3175, 3175, 1308 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][2] = { 2069, 3175, 3175 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][3] = { 2069, 3175, 1308 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][4] = { 2816, 1084, 3127 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][5] = { 2816, 1084, 1084 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][6] = { 1084, 1084, 3127 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][1] = { 3798, 3798, 2778 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][2] = { 3306, 3798, 3798 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][3] = { 3306, 3798, 2778 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][4] = { 3661, 2563, 3781 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][5] = { 3661, 2563, 2563 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][6] = { 2563, 2563, 3781 },
-       [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][1] = { 2877, 2923, 1058 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][2] = { 1837, 2840, 2916 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][3] = { 1734, 2823, 993 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][4] = { 2427, 961, 2812 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][5] = { 2351, 912, 648 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][6] = { 792, 618, 2788 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][1] = { 2999, 3041, 1301 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][2] = { 2040, 2965, 3034 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][3] = { 1944, 2950, 1238 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][4] = { 2587, 1207, 2940 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][5] = { 2517, 1159, 900 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][6] = { 1042, 870, 2917 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 800 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][1] = { 2976, 3018, 1315 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][2] = { 2024, 2942, 3011 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][3] = { 1930, 2926, 1256 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][4] = { 2563, 1227, 2916 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][5] = { 2494, 1183, 943 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][6] = { 1073, 916, 2894 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][1] = { 2864, 2910, 1024 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][2] = { 1811, 2826, 2903 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][3] = { 1707, 2809, 958 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][4] = { 2408, 926, 2798 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][5] = { 2331, 876, 609 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][6] = { 755, 579, 2773 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][1] = { 2039, 2102, 338 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][2] = { 873, 1987, 2092 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][3] = { 787, 1965, 305 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][4] = { 1468, 290, 1949 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][5] = { 1382, 268, 162 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][6] = { 216, 152, 1917 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_DCI_P3][0] = { 3175, 3175, 3175 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_DCI_P3][1] = { 3124, 3161, 1566 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_DCI_P3][2] = { 2255, 3094, 3156 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_DCI_P3][3] = { 2166, 3080, 1506 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_DCI_P3][4] = { 2754, 1477, 3071 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_DCI_P3][5] = { 2690, 1431, 1182 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_DCI_P3][6] = { 1318, 1153, 3051 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][1] = { 3780, 3793, 2984 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][2] = { 3406, 3768, 3791 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][3] = { 3359, 3763, 2939 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][4] = { 3636, 2916, 3760 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][5] = { 3609, 2880, 2661 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][6] = { 2786, 2633, 3753 },
-       [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_709][1] = { 2936, 2934, 992 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_709][2] = { 1159, 2890, 2916 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_709][3] = { 1150, 2885, 921 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_709][4] = { 2751, 766, 2837 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_709][5] = { 2747, 747, 650 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_709][6] = { 563, 570, 2812 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3055 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SRGB][1] = { 3052, 3051, 1237 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SRGB][2] = { 1397, 3011, 3034 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SRGB][3] = { 1389, 3006, 1168 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SRGB][4] = { 2884, 1016, 2962 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SRGB][5] = { 2880, 998, 902 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SRGB][6] = { 816, 823, 2940 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 799 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][1] = { 3029, 3028, 1255 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][2] = { 1406, 2988, 3011 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][3] = { 1398, 2983, 1190 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][4] = { 2860, 1050, 2939 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][5] = { 2857, 1033, 945 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][6] = { 866, 873, 2916 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE240M][1] = { 2923, 2921, 957 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE240M][2] = { 1125, 2877, 2902 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE240M][3] = { 1116, 2871, 885 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE240M][4] = { 2736, 729, 2823 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE240M][5] = { 2732, 710, 611 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE240M][6] = { 523, 531, 2798 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_NONE][1] = { 2120, 2118, 305 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_NONE][2] = { 392, 2056, 2092 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_NONE][3] = { 387, 2049, 271 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_NONE][4] = { 1868, 206, 1983 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_NONE][5] = { 1863, 199, 163 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_NONE][6] = { 135, 137, 1950 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_DCI_P3][0] = { 3175, 3175, 3175 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_DCI_P3][1] = { 3172, 3170, 1505 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_DCI_P3][2] = { 1657, 3135, 3155 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_DCI_P3][3] = { 1649, 3130, 1439 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_DCI_P3][4] = { 3021, 1294, 3091 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_DCI_P3][5] = { 3018, 1276, 1184 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_DCI_P3][6] = { 1100, 1107, 3071 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][1] = { 3797, 3796, 2938 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][2] = { 3049, 3783, 3791 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][3] = { 3044, 3782, 2887 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][4] = { 3741, 2765, 3768 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][5] = { 3740, 2749, 2663 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][6] = { 2580, 2587, 3760 },
-       [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 },
-};
-
-#else
-
-/* This code generates the table above */
-
-#include <math.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-static const double rec709_to_ntsc1953[3][3] = {
-       /*
-        * This transform uses the Bradford method to compensate for
-        * the different whitepoints.
-        */
-       { 0.6785011, 0.2883441, 0.0331548 },
-       { 0.0165284, 1.0518725, -0.0684009 },
-       { 0.0179230, 0.0506096, 0.9314674 }
-};
-
-static const double rec709_to_ebu[3][3] = {
-       { 0.9578221, 0.0421779, -0.0000000 },
-       { -0.0000000, 1.0000000, 0.0000000 },
-       { -0.0000000, -0.0119367, 1.0119367 }
-};
-
-static const double rec709_to_170m[3][3] = {
-       { 1.0653640, -0.0553900, -0.0099740 },
-       { -0.0196361, 1.0363630, -0.0167269 },
-       { 0.0016327, 0.0044133, 0.9939540 },
-};
-
-static const double rec709_to_240m[3][3] = {
-       { 1.0653640, -0.0553900, -0.0099740 },
-       { -0.0196361, 1.0363630, -0.0167269 },
-       { 0.0016327, 0.0044133, 0.9939540 },
-};
-
-static const double rec709_to_adobergb[3][3] = {
-       { 0.7151627, 0.2848373, -0.0000000 },
-       { 0.0000000, 1.0000000, 0.0000000 },
-       { -0.0000000, 0.0411705, 0.9588295 },
-};
-
-static const double rec709_to_bt2020[3][3] = {
-       { 0.6274524, 0.3292485, 0.0432991 },
-       { 0.0691092, 0.9195311, 0.0113597 },
-       { 0.0163976, 0.0880301, 0.8955723 },
-};
-
-static const double rec709_to_dcip3[3][3] = {
-       /*
-        * This transform uses the Bradford method to compensate for
-        * the different whitepoints.
-        */
-       { 0.8686648, 0.1288456, 0.0024896 },
-       { 0.0345479, 0.9618084, 0.0036437 },
-       { 0.0167785, 0.0710559, 0.9121655 }
-};
-
-static void mult_matrix(double *r, double *g, double *b, const double m[3][3])
-{
-       double ir, ig, ib;
-
-       ir = m[0][0] * (*r) + m[0][1] * (*g) + m[0][2] * (*b);
-       ig = m[1][0] * (*r) + m[1][1] * (*g) + m[1][2] * (*b);
-       ib = m[2][0] * (*r) + m[2][1] * (*g) + m[2][2] * (*b);
-       *r = ir;
-       *g = ig;
-       *b = ib;
-}
-
-static double transfer_srgb_to_rgb(double v)
-{
-       if (v < -0.04045)
-               return pow((-v + 0.055) / 1.055, 2.4);
-       return (v <= 0.04045) ? v / 12.92 : pow((v + 0.055) / 1.055, 2.4);
-}
-
-static double transfer_rgb_to_srgb(double v)
-{
-       if (v <= -0.0031308)
-               return -1.055 * pow(-v, 1.0 / 2.4) + 0.055;
-       if (v <= 0.0031308)
-               return v * 12.92;
-       return 1.055 * pow(v, 1.0 / 2.4) - 0.055;
-}
-
-static double transfer_rgb_to_smpte240m(double v)
-{
-       return (v <= 0.0228) ? v * 4.0 : 1.1115 * pow(v, 0.45) - 0.1115;
-}
-
-static double transfer_rgb_to_rec709(double v)
-{
-       if (v <= -0.018)
-               return -1.099 * pow(-v, 0.45) + 0.099;
-       return (v < 0.018) ? v * 4.5 : 1.099 * pow(v, 0.45) - 0.099;
-}
-
-static double transfer_rec709_to_rgb(double v)
-{
-       return (v < 0.081) ? v / 4.5 : pow((v + 0.099) / 1.099, 1.0 / 0.45);
-}
-
-static double transfer_rgb_to_adobergb(double v)
-{
-       return pow(v, 1.0 / 2.19921875);
-}
-
-static double transfer_rgb_to_dcip3(double v)
-{
-       return pow(v, 1.0 / 2.6);
-}
-
-static double transfer_rgb_to_smpte2084(double v)
-{
-       const double m1 = (2610.0 / 4096.0) / 4.0;
-       const double m2 = 128.0 * 2523.0 / 4096.0;
-       const double c1 = 3424.0 / 4096.0;
-       const double c2 = 32.0 * 2413.0 / 4096.0;
-       const double c3 = 32.0 * 2392.0 / 4096.0;
-
-       v = pow(v, m1);
-       return pow((c1 + c2 * v) / (1 + c3 * v), m2);
-}
-
-static double transfer_srgb_to_rec709(double v)
-{
-       return transfer_rgb_to_rec709(transfer_srgb_to_rgb(v));
-}
-
-static void csc(enum v4l2_colorspace colorspace, enum v4l2_xfer_func xfer_func,
-               double *r, double *g, double *b)
-{
-       int clamp = 1;
-
-       *r = transfer_srgb_to_rgb(*r);
-       *g = transfer_srgb_to_rgb(*g);
-       *b = transfer_srgb_to_rgb(*b);
-
-       /* Convert the primaries of Rec. 709 Linear RGB */
-       switch (colorspace) {
-       case V4L2_COLORSPACE_SMPTE240M:
-               mult_matrix(r, g, b, rec709_to_240m);
-               break;
-       case V4L2_COLORSPACE_SMPTE170M:
-               mult_matrix(r, g, b, rec709_to_170m);
-               break;
-       case V4L2_COLORSPACE_470_SYSTEM_BG:
-               mult_matrix(r, g, b, rec709_to_ebu);
-               break;
-       case V4L2_COLORSPACE_470_SYSTEM_M:
-               mult_matrix(r, g, b, rec709_to_ntsc1953);
-               break;
-       case V4L2_COLORSPACE_ADOBERGB:
-               mult_matrix(r, g, b, rec709_to_adobergb);
-               break;
-       case V4L2_COLORSPACE_BT2020:
-               mult_matrix(r, g, b, rec709_to_bt2020);
-               break;
-       case V4L2_COLORSPACE_DCI_P3:
-               mult_matrix(r, g, b, rec709_to_dcip3);
-               break;
-       case V4L2_COLORSPACE_SRGB:
-       case V4L2_COLORSPACE_REC709:
-               break;
-       default:
-               break;
-       }
-
-       if (clamp) {
-               *r = ((*r) < 0) ? 0 : (((*r) > 1) ? 1 : (*r));
-               *g = ((*g) < 0) ? 0 : (((*g) > 1) ? 1 : (*g));
-               *b = ((*b) < 0) ? 0 : (((*b) > 1) ? 1 : (*b));
-       }
-
-       switch (xfer_func) {
-       case V4L2_XFER_FUNC_709:
-               *r = transfer_rgb_to_rec709(*r);
-               *g = transfer_rgb_to_rec709(*g);
-               *b = transfer_rgb_to_rec709(*b);
-               break;
-       case V4L2_XFER_FUNC_SRGB:
-               *r = transfer_rgb_to_srgb(*r);
-               *g = transfer_rgb_to_srgb(*g);
-               *b = transfer_rgb_to_srgb(*b);
-               break;
-       case V4L2_XFER_FUNC_ADOBERGB:
-               *r = transfer_rgb_to_adobergb(*r);
-               *g = transfer_rgb_to_adobergb(*g);
-               *b = transfer_rgb_to_adobergb(*b);
-               break;
-       case V4L2_XFER_FUNC_DCI_P3:
-               *r = transfer_rgb_to_dcip3(*r);
-               *g = transfer_rgb_to_dcip3(*g);
-               *b = transfer_rgb_to_dcip3(*b);
-               break;
-       case V4L2_XFER_FUNC_SMPTE2084:
-               *r = transfer_rgb_to_smpte2084(*r);
-               *g = transfer_rgb_to_smpte2084(*g);
-               *b = transfer_rgb_to_smpte2084(*b);
-               break;
-       case V4L2_XFER_FUNC_SMPTE240M:
-               *r = transfer_rgb_to_smpte240m(*r);
-               *g = transfer_rgb_to_smpte240m(*g);
-               *b = transfer_rgb_to_smpte240m(*b);
-               break;
-       case V4L2_XFER_FUNC_NONE:
-               break;
-       }
-}
-
-int main(int argc, char **argv)
-{
-       static const unsigned colorspaces[] = {
-               0,
-               V4L2_COLORSPACE_SMPTE170M,
-               V4L2_COLORSPACE_SMPTE240M,
-               V4L2_COLORSPACE_REC709,
-               0,
-               V4L2_COLORSPACE_470_SYSTEM_M,
-               V4L2_COLORSPACE_470_SYSTEM_BG,
-               0,
-               V4L2_COLORSPACE_SRGB,
-               V4L2_COLORSPACE_ADOBERGB,
-               V4L2_COLORSPACE_BT2020,
-               0,
-               V4L2_COLORSPACE_DCI_P3,
-       };
-       static const char * const colorspace_names[] = {
-               "",
-               "V4L2_COLORSPACE_SMPTE170M",
-               "V4L2_COLORSPACE_SMPTE240M",
-               "V4L2_COLORSPACE_REC709",
-               "",
-               "V4L2_COLORSPACE_470_SYSTEM_M",
-               "V4L2_COLORSPACE_470_SYSTEM_BG",
-               "",
-               "V4L2_COLORSPACE_SRGB",
-               "V4L2_COLORSPACE_ADOBERGB",
-               "V4L2_COLORSPACE_BT2020",
-               "",
-               "V4L2_COLORSPACE_DCI_P3",
-       };
-       static const char * const xfer_func_names[] = {
-               "",
-               "V4L2_XFER_FUNC_709",
-               "V4L2_XFER_FUNC_SRGB",
-               "V4L2_XFER_FUNC_ADOBERGB",
-               "V4L2_XFER_FUNC_SMPTE240M",
-               "V4L2_XFER_FUNC_NONE",
-               "V4L2_XFER_FUNC_DCI_P3",
-               "V4L2_XFER_FUNC_SMPTE2084",
-       };
-       int i;
-       int x;
-       int c;
-
-       printf("/* Generated table */\n");
-       printf("const unsigned short tpg_rec709_to_linear[255 * 16 + 1] = {");
-       for (i = 0; i <= 255 * 16; i++) {
-               if (i % 16 == 0)
-                       printf("\n\t");
-               printf("%4d,%s",
-                       (int)(0.5 + 16.0 * 255.0 *
-                               transfer_rec709_to_rgb(i / (16.0 * 255.0))),
-                       i % 16 == 15 || i == 255 * 16 ? "" : " ");
-       }
-       printf("\n};\n\n");
-
-       printf("/* Generated table */\n");
-       printf("const unsigned short tpg_linear_to_rec709[255 * 16 + 1] = {");
-       for (i = 0; i <= 255 * 16; i++) {
-               if (i % 16 == 0)
-                       printf("\n\t");
-               printf("%4d,%s",
-                       (int)(0.5 + 16.0 * 255.0 *
-                               transfer_rgb_to_rec709(i / (16.0 * 255.0))),
-                       i % 16 == 15 || i == 255 * 16 ? "" : " ");
-       }
-       printf("\n};\n\n");
-
-       printf("/* Generated table */\n");
-       printf("const struct color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFER_FUNC_SMPTE2084 + 1][TPG_COLOR_CSC_BLACK + 1] = {\n");
-       for (c = 0; c <= V4L2_COLORSPACE_DCI_P3; c++) {
-               for (x = 1; x <= V4L2_XFER_FUNC_SMPTE2084; x++) {
-                       for (i = 0; i <= TPG_COLOR_CSC_BLACK; i++) {
-                               double r, g, b;
-
-                               if (colorspaces[c] == 0)
-                                       continue;
-
-                               r = tpg_colors[i].r / 255.0;
-                               g = tpg_colors[i].g / 255.0;
-                               b = tpg_colors[i].b / 255.0;
-
-                               csc(c, x, &r, &g, &b);
-
-                               printf("\t[%s][%s][%d] = { %d, %d, %d },\n",
-                                       colorspace_names[c],
-                                       xfer_func_names[x], i,
-                                       (int)(r * 4080), (int)(g * 4080), (int)(b * 4080));
-                       }
-               }
-       }
-       printf("};\n\n");
-       return 0;
-}
-
-#endif
diff --git a/drivers/media/platform/vivid/vivid-tpg-colors.h b/drivers/media/platform/vivid/vivid-tpg-colors.h
deleted file mode 100644 (file)
index 4e5a76a..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * vivid-color.h - Color definitions for the test pattern generator
- *
- * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _VIVID_COLORS_H_
-#define _VIVID_COLORS_H_
-
-struct color {
-       unsigned char r, g, b;
-};
-
-struct color16 {
-       int r, g, b;
-};
-
-enum tpg_color {
-       TPG_COLOR_CSC_WHITE,
-       TPG_COLOR_CSC_YELLOW,
-       TPG_COLOR_CSC_CYAN,
-       TPG_COLOR_CSC_GREEN,
-       TPG_COLOR_CSC_MAGENTA,
-       TPG_COLOR_CSC_RED,
-       TPG_COLOR_CSC_BLUE,
-       TPG_COLOR_CSC_BLACK,
-       TPG_COLOR_75_YELLOW,
-       TPG_COLOR_75_CYAN,
-       TPG_COLOR_75_GREEN,
-       TPG_COLOR_75_MAGENTA,
-       TPG_COLOR_75_RED,
-       TPG_COLOR_75_BLUE,
-       TPG_COLOR_100_WHITE,
-       TPG_COLOR_100_YELLOW,
-       TPG_COLOR_100_CYAN,
-       TPG_COLOR_100_GREEN,
-       TPG_COLOR_100_MAGENTA,
-       TPG_COLOR_100_RED,
-       TPG_COLOR_100_BLUE,
-       TPG_COLOR_100_BLACK,
-       TPG_COLOR_TEXTFG,
-       TPG_COLOR_TEXTBG,
-       TPG_COLOR_RANDOM,
-       TPG_COLOR_RAMP,
-       TPG_COLOR_MAX = TPG_COLOR_RAMP + 256
-};
-
-extern const struct color tpg_colors[TPG_COLOR_MAX];
-extern const unsigned short tpg_rec709_to_linear[255 * 16 + 1];
-extern const unsigned short tpg_linear_to_rec709[255 * 16 + 1];
-extern const struct color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1]
-                                         [V4L2_XFER_FUNC_SMPTE2084 + 1]
-                                         [TPG_COLOR_CSC_BLACK + 1];
-
-#endif
diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c
deleted file mode 100644 (file)
index da862bb..0000000
+++ /dev/null
@@ -1,2314 +0,0 @@
-/*
- * vivid-tpg.c - Test Pattern Generator
- *
- * Note: gen_twopix and tpg_gen_text are based on code from vivi.c. See the
- * vivi.c source for the copyright information of those functions.
- *
- * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "vivid-tpg.h"
-
-/* Must remain in sync with enum tpg_pattern */
-const char * const tpg_pattern_strings[] = {
-       "75% Colorbar",
-       "100% Colorbar",
-       "CSC Colorbar",
-       "Horizontal 100% Colorbar",
-       "100% Color Squares",
-       "100% Black",
-       "100% White",
-       "100% Red",
-       "100% Green",
-       "100% Blue",
-       "16x16 Checkers",
-       "2x2 Checkers",
-       "1x1 Checkers",
-       "2x2 Red/Green Checkers",
-       "1x1 Red/Green Checkers",
-       "Alternating Hor Lines",
-       "Alternating Vert Lines",
-       "One Pixel Wide Cross",
-       "Two Pixels Wide Cross",
-       "Ten Pixels Wide Cross",
-       "Gray Ramp",
-       "Noise",
-       NULL
-};
-
-/* Must remain in sync with enum tpg_aspect */
-const char * const tpg_aspect_strings[] = {
-       "Source Width x Height",
-       "4x3",
-       "14x9",
-       "16x9",
-       "16x9 Anamorphic",
-       NULL
-};
-
-/*
- * Sine table: sin[0] = 127 * sin(-180 degrees)
- *             sin[128] = 127 * sin(0 degrees)
- *             sin[256] = 127 * sin(180 degrees)
- */
-static const s8 sin[257] = {
-          0,   -4,   -7,  -11,  -13,  -18,  -20,  -22,  -26,  -29,  -33,  -35,  -37,  -41,  -43,  -48,
-        -50,  -52,  -56,  -58,  -62,  -63,  -65,  -69,  -71,  -75,  -76,  -78,  -82,  -83,  -87,  -88,
-        -90,  -93,  -94,  -97,  -99, -101, -103, -104, -107, -108, -110, -111, -112, -114, -115, -117,
-       -118, -119, -120, -121, -122, -123, -123, -124, -125, -125, -126, -126, -127, -127, -127, -127,
-       -127, -127, -127, -127, -126, -126, -125, -125, -124, -124, -123, -122, -121, -120, -119, -118,
-       -117, -116, -114, -113, -111, -110, -109, -107, -105, -103, -101, -100,  -97,  -96,  -93,  -91,
-        -90,  -87,  -85,  -82,  -80,  -76,  -75,  -73,  -69,  -67,  -63,  -62,  -60,  -56,  -54,  -50,
-        -48,  -46,  -41,  -39,  -35,  -33,  -31,  -26,  -24,  -20,  -18,  -15,  -11,   -9,   -4,   -2,
-          0,    2,    4,    9,   11,   15,   18,   20,   24,   26,   31,   33,   35,   39,   41,   46,
-         48,   50,   54,   56,   60,   62,   64,   67,   69,   73,   75,   76,   80,   82,   85,   87,
-         90,   91,   93,   96,   97,  100,  101,  103,  105,  107,  109,  110,  111,  113,  114,  116,
-        117,  118,  119,  120,  121,  122,  123,  124,  124,  125,  125,  126,  126,  127,  127,  127,
-        127,  127,  127,  127,  127,  126,  126,  125,  125,  124,  123,  123,  122,  121,  120,  119,
-        118,  117,  115,  114,  112,  111,  110,  108,  107,  104,  103,  101,   99,   97,   94,   93,
-         90,   88,   87,   83,   82,   78,   76,   75,   71,   69,   65,   64,   62,   58,   56,   52,
-         50,   48,   43,   41,   37,   35,   33,   29,   26,   22,   20,   18,   13,   11,    7,    4,
-          0,
-};
-
-#define cos(idx) sin[((idx) + 64) % sizeof(sin)]
-
-/* Global font descriptor */
-static const u8 *font8x16;
-
-void tpg_set_font(const u8 *f)
-{
-       font8x16 = f;
-}
-
-void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h)
-{
-       memset(tpg, 0, sizeof(*tpg));
-       tpg->scaled_width = tpg->src_width = w;
-       tpg->src_height = tpg->buf_height = h;
-       tpg->crop.width = tpg->compose.width = w;
-       tpg->crop.height = tpg->compose.height = h;
-       tpg->recalc_colors = true;
-       tpg->recalc_square_border = true;
-       tpg->brightness = 128;
-       tpg->contrast = 128;
-       tpg->saturation = 128;
-       tpg->hue = 0;
-       tpg->mv_hor_mode = TPG_MOVE_NONE;
-       tpg->mv_vert_mode = TPG_MOVE_NONE;
-       tpg->field = V4L2_FIELD_NONE;
-       tpg_s_fourcc(tpg, V4L2_PIX_FMT_RGB24);
-       tpg->colorspace = V4L2_COLORSPACE_SRGB;
-       tpg->perc_fill = 100;
-}
-
-int tpg_alloc(struct tpg_data *tpg, unsigned max_w)
-{
-       unsigned pat;
-       unsigned plane;
-
-       tpg->max_line_width = max_w;
-       for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) {
-               for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
-                       unsigned pixelsz = plane ? 2 : 4;
-
-                       tpg->lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
-                       if (!tpg->lines[pat][plane])
-                               return -ENOMEM;
-                       if (plane == 0)
-                               continue;
-                       tpg->downsampled_lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
-                       if (!tpg->downsampled_lines[pat][plane])
-                               return -ENOMEM;
-               }
-       }
-       for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
-               unsigned pixelsz = plane ? 2 : 4;
-
-               tpg->contrast_line[plane] = vzalloc(max_w * pixelsz);
-               if (!tpg->contrast_line[plane])
-                       return -ENOMEM;
-               tpg->black_line[plane] = vzalloc(max_w * pixelsz);
-               if (!tpg->black_line[plane])
-                       return -ENOMEM;
-               tpg->random_line[plane] = vzalloc(max_w * 2 * pixelsz);
-               if (!tpg->random_line[plane])
-                       return -ENOMEM;
-       }
-       return 0;
-}
-
-void tpg_free(struct tpg_data *tpg)
-{
-       unsigned pat;
-       unsigned plane;
-
-       for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++)
-               for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
-                       vfree(tpg->lines[pat][plane]);
-                       tpg->lines[pat][plane] = NULL;
-                       if (plane == 0)
-                               continue;
-                       vfree(tpg->downsampled_lines[pat][plane]);
-                       tpg->downsampled_lines[pat][plane] = NULL;
-               }
-       for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
-               vfree(tpg->contrast_line[plane]);
-               vfree(tpg->black_line[plane]);
-               vfree(tpg->random_line[plane]);
-               tpg->contrast_line[plane] = NULL;
-               tpg->black_line[plane] = NULL;
-               tpg->random_line[plane] = NULL;
-       }
-}
-
-bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
-{
-       tpg->fourcc = fourcc;
-       tpg->planes = 1;
-       tpg->buffers = 1;
-       tpg->recalc_colors = true;
-       tpg->interleaved = false;
-       tpg->vdownsampling[0] = 1;
-       tpg->hdownsampling[0] = 1;
-       tpg->hmask[0] = ~0;
-       tpg->hmask[1] = ~0;
-       tpg->hmask[2] = ~0;
-
-       switch (fourcc) {
-       case V4L2_PIX_FMT_SBGGR8:
-       case V4L2_PIX_FMT_SGBRG8:
-       case V4L2_PIX_FMT_SGRBG8:
-       case V4L2_PIX_FMT_SRGGB8:
-       case V4L2_PIX_FMT_SBGGR10:
-       case V4L2_PIX_FMT_SGBRG10:
-       case V4L2_PIX_FMT_SGRBG10:
-       case V4L2_PIX_FMT_SRGGB10:
-       case V4L2_PIX_FMT_SBGGR12:
-       case V4L2_PIX_FMT_SGBRG12:
-       case V4L2_PIX_FMT_SGRBG12:
-       case V4L2_PIX_FMT_SRGGB12:
-               tpg->interleaved = true;
-               tpg->vdownsampling[1] = 1;
-               tpg->hdownsampling[1] = 1;
-               tpg->planes = 2;
-               /* fall through */
-       case V4L2_PIX_FMT_RGB332:
-       case V4L2_PIX_FMT_RGB565:
-       case V4L2_PIX_FMT_RGB565X:
-       case V4L2_PIX_FMT_RGB444:
-       case V4L2_PIX_FMT_XRGB444:
-       case V4L2_PIX_FMT_ARGB444:
-       case V4L2_PIX_FMT_RGB555:
-       case V4L2_PIX_FMT_XRGB555:
-       case V4L2_PIX_FMT_ARGB555:
-       case V4L2_PIX_FMT_RGB555X:
-       case V4L2_PIX_FMT_XRGB555X:
-       case V4L2_PIX_FMT_ARGB555X:
-       case V4L2_PIX_FMT_BGR666:
-       case V4L2_PIX_FMT_RGB24:
-       case V4L2_PIX_FMT_BGR24:
-       case V4L2_PIX_FMT_RGB32:
-       case V4L2_PIX_FMT_BGR32:
-       case V4L2_PIX_FMT_XRGB32:
-       case V4L2_PIX_FMT_XBGR32:
-       case V4L2_PIX_FMT_ARGB32:
-       case V4L2_PIX_FMT_ABGR32:
-       case V4L2_PIX_FMT_GREY:
-       case V4L2_PIX_FMT_Y16:
-       case V4L2_PIX_FMT_Y16_BE:
-               tpg->is_yuv = false;
-               break;
-       case V4L2_PIX_FMT_YUV444:
-       case V4L2_PIX_FMT_YUV555:
-       case V4L2_PIX_FMT_YUV565:
-       case V4L2_PIX_FMT_YUV32:
-               tpg->is_yuv = true;
-               break;
-       case V4L2_PIX_FMT_YUV420M:
-       case V4L2_PIX_FMT_YVU420M:
-               tpg->buffers = 3;
-               /* fall through */
-       case V4L2_PIX_FMT_YUV420:
-       case V4L2_PIX_FMT_YVU420:
-               tpg->vdownsampling[1] = 2;
-               tpg->vdownsampling[2] = 2;
-               tpg->hdownsampling[1] = 2;
-               tpg->hdownsampling[2] = 2;
-               tpg->planes = 3;
-               tpg->is_yuv = true;
-               break;
-       case V4L2_PIX_FMT_YUV422M:
-       case V4L2_PIX_FMT_YVU422M:
-               tpg->buffers = 3;
-               /* fall through */
-       case V4L2_PIX_FMT_YUV422P:
-               tpg->vdownsampling[1] = 1;
-               tpg->vdownsampling[2] = 1;
-               tpg->hdownsampling[1] = 2;
-               tpg->hdownsampling[2] = 2;
-               tpg->planes = 3;
-               tpg->is_yuv = true;
-               break;
-       case V4L2_PIX_FMT_NV16M:
-       case V4L2_PIX_FMT_NV61M:
-               tpg->buffers = 2;
-               /* fall through */
-       case V4L2_PIX_FMT_NV16:
-       case V4L2_PIX_FMT_NV61:
-               tpg->vdownsampling[1] = 1;
-               tpg->hdownsampling[1] = 1;
-               tpg->hmask[1] = ~1;
-               tpg->planes = 2;
-               tpg->is_yuv = true;
-               break;
-       case V4L2_PIX_FMT_NV12M:
-       case V4L2_PIX_FMT_NV21M:
-               tpg->buffers = 2;
-               /* fall through */
-       case V4L2_PIX_FMT_NV12:
-       case V4L2_PIX_FMT_NV21:
-               tpg->vdownsampling[1] = 2;
-               tpg->hdownsampling[1] = 1;
-               tpg->hmask[1] = ~1;
-               tpg->planes = 2;
-               tpg->is_yuv = true;
-               break;
-       case V4L2_PIX_FMT_YUV444M:
-       case V4L2_PIX_FMT_YVU444M:
-               tpg->buffers = 3;
-               tpg->planes = 3;
-               tpg->vdownsampling[1] = 1;
-               tpg->vdownsampling[2] = 1;
-               tpg->hdownsampling[1] = 1;
-               tpg->hdownsampling[2] = 1;
-               tpg->is_yuv = true;
-               break;
-       case V4L2_PIX_FMT_NV24:
-       case V4L2_PIX_FMT_NV42:
-               tpg->vdownsampling[1] = 1;
-               tpg->hdownsampling[1] = 1;
-               tpg->planes = 2;
-               tpg->is_yuv = true;
-               break;
-       case V4L2_PIX_FMT_YUYV:
-       case V4L2_PIX_FMT_UYVY:
-       case V4L2_PIX_FMT_YVYU:
-       case V4L2_PIX_FMT_VYUY:
-               tpg->hmask[0] = ~1;
-               tpg->is_yuv = true;
-               break;
-       default:
-               return false;
-       }
-
-       switch (fourcc) {
-       case V4L2_PIX_FMT_GREY:
-       case V4L2_PIX_FMT_RGB332:
-               tpg->twopixelsize[0] = 2;
-               break;
-       case V4L2_PIX_FMT_RGB565:
-       case V4L2_PIX_FMT_RGB565X:
-       case V4L2_PIX_FMT_RGB444:
-       case V4L2_PIX_FMT_XRGB444:
-       case V4L2_PIX_FMT_ARGB444:
-       case V4L2_PIX_FMT_RGB555:
-       case V4L2_PIX_FMT_XRGB555:
-       case V4L2_PIX_FMT_ARGB555:
-       case V4L2_PIX_FMT_RGB555X:
-       case V4L2_PIX_FMT_XRGB555X:
-       case V4L2_PIX_FMT_ARGB555X:
-       case V4L2_PIX_FMT_YUYV:
-       case V4L2_PIX_FMT_UYVY:
-       case V4L2_PIX_FMT_YVYU:
-       case V4L2_PIX_FMT_VYUY:
-       case V4L2_PIX_FMT_YUV444:
-       case V4L2_PIX_FMT_YUV555:
-       case V4L2_PIX_FMT_YUV565:
-       case V4L2_PIX_FMT_Y16:
-       case V4L2_PIX_FMT_Y16_BE:
-               tpg->twopixelsize[0] = 2 * 2;
-               break;
-       case V4L2_PIX_FMT_RGB24:
-       case V4L2_PIX_FMT_BGR24:
-               tpg->twopixelsize[0] = 2 * 3;
-               break;
-       case V4L2_PIX_FMT_BGR666:
-       case V4L2_PIX_FMT_RGB32:
-       case V4L2_PIX_FMT_BGR32:
-       case V4L2_PIX_FMT_XRGB32:
-       case V4L2_PIX_FMT_XBGR32:
-       case V4L2_PIX_FMT_ARGB32:
-       case V4L2_PIX_FMT_ABGR32:
-       case V4L2_PIX_FMT_YUV32:
-               tpg->twopixelsize[0] = 2 * 4;
-               break;
-       case V4L2_PIX_FMT_NV12:
-       case V4L2_PIX_FMT_NV21:
-       case V4L2_PIX_FMT_NV12M:
-       case V4L2_PIX_FMT_NV21M:
-       case V4L2_PIX_FMT_NV16:
-       case V4L2_PIX_FMT_NV61:
-       case V4L2_PIX_FMT_NV16M:
-       case V4L2_PIX_FMT_NV61M:
-       case V4L2_PIX_FMT_SBGGR8:
-       case V4L2_PIX_FMT_SGBRG8:
-       case V4L2_PIX_FMT_SGRBG8:
-       case V4L2_PIX_FMT_SRGGB8:
-               tpg->twopixelsize[0] = 2;
-               tpg->twopixelsize[1] = 2;
-               break;
-       case V4L2_PIX_FMT_SRGGB10:
-       case V4L2_PIX_FMT_SGRBG10:
-       case V4L2_PIX_FMT_SGBRG10:
-       case V4L2_PIX_FMT_SBGGR10:
-       case V4L2_PIX_FMT_SRGGB12:
-       case V4L2_PIX_FMT_SGRBG12:
-       case V4L2_PIX_FMT_SGBRG12:
-       case V4L2_PIX_FMT_SBGGR12:
-               tpg->twopixelsize[0] = 4;
-               tpg->twopixelsize[1] = 4;
-               break;
-       case V4L2_PIX_FMT_YUV444M:
-       case V4L2_PIX_FMT_YVU444M:
-       case V4L2_PIX_FMT_YUV422M:
-       case V4L2_PIX_FMT_YVU422M:
-       case V4L2_PIX_FMT_YUV422P:
-       case V4L2_PIX_FMT_YUV420:
-       case V4L2_PIX_FMT_YVU420:
-       case V4L2_PIX_FMT_YUV420M:
-       case V4L2_PIX_FMT_YVU420M:
-               tpg->twopixelsize[0] = 2;
-               tpg->twopixelsize[1] = 2;
-               tpg->twopixelsize[2] = 2;
-               break;
-       case V4L2_PIX_FMT_NV24:
-       case V4L2_PIX_FMT_NV42:
-               tpg->twopixelsize[0] = 2;
-               tpg->twopixelsize[1] = 4;
-               break;
-       }
-       return true;
-}
-
-void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
-               const struct v4l2_rect *compose)
-{
-       tpg->crop = *crop;
-       tpg->compose = *compose;
-       tpg->scaled_width = (tpg->src_width * tpg->compose.width +
-                                tpg->crop.width - 1) / tpg->crop.width;
-       tpg->scaled_width &= ~1;
-       if (tpg->scaled_width > tpg->max_line_width)
-               tpg->scaled_width = tpg->max_line_width;
-       if (tpg->scaled_width < 2)
-               tpg->scaled_width = 2;
-       tpg->recalc_lines = true;
-}
-
-void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
-                      u32 field)
-{
-       unsigned p;
-
-       tpg->src_width = width;
-       tpg->src_height = height;
-       tpg->field = field;
-       tpg->buf_height = height;
-       if (V4L2_FIELD_HAS_T_OR_B(field))
-               tpg->buf_height /= 2;
-       tpg->scaled_width = width;
-       tpg->crop.top = tpg->crop.left = 0;
-       tpg->crop.width = width;
-       tpg->crop.height = height;
-       tpg->compose.top = tpg->compose.left = 0;
-       tpg->compose.width = width;
-       tpg->compose.height = tpg->buf_height;
-       for (p = 0; p < tpg->planes; p++)
-               tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) /
-                                      (2 * tpg->hdownsampling[p]);
-       tpg->recalc_square_border = true;
-}
-
-static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)
-{
-       switch (tpg->pattern) {
-       case TPG_PAT_BLACK:
-               return TPG_COLOR_100_WHITE;
-       case TPG_PAT_CSC_COLORBAR:
-               return TPG_COLOR_CSC_BLACK;
-       default:
-               return TPG_COLOR_100_BLACK;
-       }
-}
-
-static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)
-{
-       switch (tpg->pattern) {
-       case TPG_PAT_75_COLORBAR:
-       case TPG_PAT_CSC_COLORBAR:
-               return TPG_COLOR_CSC_WHITE;
-       case TPG_PAT_BLACK:
-               return TPG_COLOR_100_BLACK;
-       default:
-               return TPG_COLOR_100_WHITE;
-       }
-}
-
-static inline int rec709_to_linear(int v)
-{
-       v = clamp(v, 0, 0xff0);
-       return tpg_rec709_to_linear[v];
-}
-
-static inline int linear_to_rec709(int v)
-{
-       v = clamp(v, 0, 0xff0);
-       return tpg_linear_to_rec709[v];
-}
-
-static void rgb2ycbcr(const int m[3][3], int r, int g, int b,
-                       int y_offset, int *y, int *cb, int *cr)
-{
-       *y  = ((m[0][0] * r + m[0][1] * g + m[0][2] * b) >> 16) + (y_offset << 4);
-       *cb = ((m[1][0] * r + m[1][1] * g + m[1][2] * b) >> 16) + (128 << 4);
-       *cr = ((m[2][0] * r + m[2][1] * g + m[2][2] * b) >> 16) + (128 << 4);
-}
-
-static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
-                          int *y, int *cb, int *cr)
-{
-#define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
-
-       static const int bt601[3][3] = {
-               { COEFF(0.299, 219),  COEFF(0.587, 219),  COEFF(0.114, 219)  },
-               { COEFF(-0.169, 224), COEFF(-0.331, 224), COEFF(0.5, 224)    },
-               { COEFF(0.5, 224),    COEFF(-0.419, 224), COEFF(-0.081, 224) },
-       };
-       static const int bt601_full[3][3] = {
-               { COEFF(0.299, 255),  COEFF(0.587, 255),  COEFF(0.114, 255)  },
-               { COEFF(-0.169, 255), COEFF(-0.331, 255), COEFF(0.5, 255)    },
-               { COEFF(0.5, 255),    COEFF(-0.419, 255), COEFF(-0.081, 255) },
-       };
-       static const int rec709[3][3] = {
-               { COEFF(0.2126, 219),  COEFF(0.7152, 219),  COEFF(0.0722, 219)  },
-               { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224)     },
-               { COEFF(0.5, 224),     COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
-       };
-       static const int rec709_full[3][3] = {
-               { COEFF(0.2126, 255),  COEFF(0.7152, 255),  COEFF(0.0722, 255)  },
-               { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255)     },
-               { COEFF(0.5, 255),     COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
-       };
-       static const int smpte240m[3][3] = {
-               { COEFF(0.212, 219),  COEFF(0.701, 219),  COEFF(0.087, 219)  },
-               { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224)    },
-               { COEFF(0.5, 224),    COEFF(-0.445, 224), COEFF(-0.055, 224) },
-       };
-       static const int smpte240m_full[3][3] = {
-               { COEFF(0.212, 255),  COEFF(0.701, 255),  COEFF(0.087, 255)  },
-               { COEFF(-0.116, 255), COEFF(-0.384, 255), COEFF(0.5, 255)    },
-               { COEFF(0.5, 255),    COEFF(-0.445, 255), COEFF(-0.055, 255) },
-       };
-       static const int bt2020[3][3] = {
-               { COEFF(0.2627, 219),  COEFF(0.6780, 219),  COEFF(0.0593, 219)  },
-               { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224)     },
-               { COEFF(0.5, 224),     COEFF(-0.4598, 224), COEFF(-0.0402, 224) },
-       };
-       static const int bt2020_full[3][3] = {
-               { COEFF(0.2627, 255),  COEFF(0.6780, 255),  COEFF(0.0593, 255)  },
-               { COEFF(-0.1396, 255), COEFF(-0.3604, 255), COEFF(0.5, 255)     },
-               { COEFF(0.5, 255),     COEFF(-0.4698, 255), COEFF(-0.0402, 255) },
-       };
-       static const int bt2020c[4] = {
-               COEFF(1.0 / 1.9404, 224), COEFF(1.0 / 1.5816, 224),
-               COEFF(1.0 / 1.7184, 224), COEFF(1.0 / 0.9936, 224),
-       };
-       static const int bt2020c_full[4] = {
-               COEFF(1.0 / 1.9404, 255), COEFF(1.0 / 1.5816, 255),
-               COEFF(1.0 / 1.7184, 255), COEFF(1.0 / 0.9936, 255),
-       };
-
-       bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
-       unsigned y_offset = full ? 0 : 16;
-       int lin_y, yc;
-
-       switch (tpg->real_ycbcr_enc) {
-       case V4L2_YCBCR_ENC_601:
-       case V4L2_YCBCR_ENC_SYCC:
-               rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr);
-               break;
-       case V4L2_YCBCR_ENC_XV601:
-               /* Ignore quantization range, there is only one possible
-                * Y'CbCr encoding. */
-               rgb2ycbcr(bt601, r, g, b, 16, y, cb, cr);
-               break;
-       case V4L2_YCBCR_ENC_XV709:
-               /* Ignore quantization range, there is only one possible
-                * Y'CbCr encoding. */
-               rgb2ycbcr(rec709, r, g, b, 16, y, cb, cr);
-               break;
-       case V4L2_YCBCR_ENC_BT2020:
-               rgb2ycbcr(full ? bt2020_full : bt2020, r, g, b, y_offset, y, cb, cr);
-               break;
-       case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
-               lin_y = (COEFF(0.2627, 255) * rec709_to_linear(r) +
-                        COEFF(0.6780, 255) * rec709_to_linear(g) +
-                        COEFF(0.0593, 255) * rec709_to_linear(b)) >> 16;
-               yc = linear_to_rec709(lin_y);
-               *y = full ? yc : (yc * 219) / 255 + (16 << 4);
-               if (b <= yc)
-                       *cb = (((b - yc) * (full ? bt2020c_full[0] : bt2020c[0])) >> 16) + (128 << 4);
-               else
-                       *cb = (((b - yc) * (full ? bt2020c_full[1] : bt2020c[1])) >> 16) + (128 << 4);
-               if (r <= yc)
-                       *cr = (((r - yc) * (full ? bt2020c_full[2] : bt2020c[2])) >> 16) + (128 << 4);
-               else
-                       *cr = (((r - yc) * (full ? bt2020c_full[3] : bt2020c[3])) >> 16) + (128 << 4);
-               break;
-       case V4L2_YCBCR_ENC_SMPTE240M:
-               rgb2ycbcr(full ? smpte240m_full : smpte240m, r, g, b, y_offset, y, cb, cr);
-               break;
-       case V4L2_YCBCR_ENC_709:
-       default:
-               rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr);
-               break;
-       }
-}
-
-static void ycbcr2rgb(const int m[3][3], int y, int cb, int cr,
-                       int y_offset, int *r, int *g, int *b)
-{
-       y -= y_offset << 4;
-       cb -= 128 << 4;
-       cr -= 128 << 4;
-       *r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;
-       *g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;
-       *b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;
-       *r = clamp(*r >> 12, 0, 0xff0);
-       *g = clamp(*g >> 12, 0, 0xff0);
-       *b = clamp(*b >> 12, 0, 0xff0);
-}
-
-static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,
-                          int *r, int *g, int *b)
-{
-#undef COEFF
-#define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))
-       static const int bt601[3][3] = {
-               { COEFF(1, 219), COEFF(0, 224),       COEFF(1.4020, 224)  },
-               { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },
-               { COEFF(1, 219), COEFF(1.7720, 224),  COEFF(0, 224)       },
-       };
-       static const int bt601_full[3][3] = {
-               { COEFF(1, 255), COEFF(0, 255),       COEFF(1.4020, 255)  },
-               { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },
-               { COEFF(1, 255), COEFF(1.7720, 255),  COEFF(0, 255)       },
-       };
-       static const int rec709[3][3] = {
-               { COEFF(1, 219), COEFF(0, 224),       COEFF(1.5748, 224)  },
-               { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },
-               { COEFF(1, 219), COEFF(1.8556, 224),  COEFF(0, 224)       },
-       };
-       static const int rec709_full[3][3] = {
-               { COEFF(1, 255), COEFF(0, 255),       COEFF(1.5748, 255)  },
-               { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },
-               { COEFF(1, 255), COEFF(1.8556, 255),  COEFF(0, 255)       },
-       };
-       static const int smpte240m[3][3] = {
-               { COEFF(1, 219), COEFF(0, 224),       COEFF(1.5756, 224)  },
-               { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },
-               { COEFF(1, 219), COEFF(1.8270, 224),  COEFF(0, 224)       },
-       };
-       static const int smpte240m_full[3][3] = {
-               { COEFF(1, 255), COEFF(0, 255),       COEFF(1.5756, 255)  },
-               { COEFF(1, 255), COEFF(-0.2253, 255), COEFF(-0.4767, 255) },
-               { COEFF(1, 255), COEFF(1.8270, 255),  COEFF(0, 255)       },
-       };
-       static const int bt2020[3][3] = {
-               { COEFF(1, 219), COEFF(0, 224),       COEFF(1.4746, 224)  },
-               { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },
-               { COEFF(1, 219), COEFF(1.8814, 224),  COEFF(0, 224)       },
-       };
-       static const int bt2020_full[3][3] = {
-               { COEFF(1, 255), COEFF(0, 255),       COEFF(1.4746, 255)  },
-               { COEFF(1, 255), COEFF(-0.1646, 255), COEFF(-0.5714, 255) },
-               { COEFF(1, 255), COEFF(1.8814, 255),  COEFF(0, 255)       },
-       };
-       static const int bt2020c[4] = {
-               COEFF(1.9404, 224), COEFF(1.5816, 224),
-               COEFF(1.7184, 224), COEFF(0.9936, 224),
-       };
-       static const int bt2020c_full[4] = {
-               COEFF(1.9404, 255), COEFF(1.5816, 255),
-               COEFF(1.7184, 255), COEFF(0.9936, 255),
-       };
-
-       bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
-       unsigned y_offset = full ? 0 : 16;
-       int y_fac = full ? COEFF(1.0, 255) : COEFF(1.0, 219);
-       int lin_r, lin_g, lin_b, lin_y;
-
-       switch (tpg->real_ycbcr_enc) {
-       case V4L2_YCBCR_ENC_601:
-       case V4L2_YCBCR_ENC_SYCC:
-               ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b);
-               break;
-       case V4L2_YCBCR_ENC_XV601:
-               /* Ignore quantization range, there is only one possible
-                * Y'CbCr encoding. */
-               ycbcr2rgb(bt601, y, cb, cr, 16, r, g, b);
-               break;
-       case V4L2_YCBCR_ENC_XV709:
-               /* Ignore quantization range, there is only one possible
-                * Y'CbCr encoding. */
-               ycbcr2rgb(rec709, y, cb, cr, 16, r, g, b);
-               break;
-       case V4L2_YCBCR_ENC_BT2020:
-               ycbcr2rgb(full ? bt2020_full : bt2020, y, cb, cr, y_offset, r, g, b);
-               break;
-       case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
-               y -= full ? 0 : 16 << 4;
-               cb -= 128 << 4;
-               cr -= 128 << 4;
-
-               if (cb <= 0)
-                       *b = y_fac * y + (full ? bt2020c_full[0] : bt2020c[0]) * cb;
-               else
-                       *b = y_fac * y + (full ? bt2020c_full[1] : bt2020c[1]) * cb;
-               *b = *b >> 12;
-               if (cr <= 0)
-                       *r = y_fac * y + (full ? bt2020c_full[2] : bt2020c[2]) * cr;
-               else
-                       *r = y_fac * y + (full ? bt2020c_full[3] : bt2020c[3]) * cr;
-               *r = *r >> 12;
-               lin_r = rec709_to_linear(*r);
-               lin_b = rec709_to_linear(*b);
-               lin_y = rec709_to_linear((y * 255) / (full ? 255 : 219));
-
-               lin_g = COEFF(1.0 / 0.6780, 255) * lin_y -
-                       COEFF(0.2627 / 0.6780, 255) * lin_r -
-                       COEFF(0.0593 / 0.6780, 255) * lin_b;
-               *g = linear_to_rec709(lin_g >> 12);
-               break;
-       case V4L2_YCBCR_ENC_SMPTE240M:
-               ycbcr2rgb(full ? smpte240m_full : smpte240m, y, cb, cr, y_offset, r, g, b);
-               break;
-       case V4L2_YCBCR_ENC_709:
-       default:
-               ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b);
-               break;
-       }
-}
-
-/* precalculate color bar values to speed up rendering */
-static void precalculate_color(struct tpg_data *tpg, int k)
-{
-       int col = k;
-       int r = tpg_colors[col].r;
-       int g = tpg_colors[col].g;
-       int b = tpg_colors[col].b;
-
-       if (k == TPG_COLOR_TEXTBG) {
-               col = tpg_get_textbg_color(tpg);
-
-               r = tpg_colors[col].r;
-               g = tpg_colors[col].g;
-               b = tpg_colors[col].b;
-       } else if (k == TPG_COLOR_TEXTFG) {
-               col = tpg_get_textfg_color(tpg);
-
-               r = tpg_colors[col].r;
-               g = tpg_colors[col].g;
-               b = tpg_colors[col].b;
-       } else if (tpg->pattern == TPG_PAT_NOISE) {
-               r = g = b = prandom_u32_max(256);
-       } else if (k == TPG_COLOR_RANDOM) {
-               r = g = b = tpg->qual_offset + prandom_u32_max(196);
-       } else if (k >= TPG_COLOR_RAMP) {
-               r = g = b = k - TPG_COLOR_RAMP;
-       }
-
-       if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
-               r = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].r;
-               g = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].g;
-               b = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].b;
-       } else {
-               r <<= 4;
-               g <<= 4;
-               b <<= 4;
-       }
-       if (tpg->qual == TPG_QUAL_GRAY || tpg->fourcc == V4L2_PIX_FMT_GREY ||
-           tpg->fourcc == V4L2_PIX_FMT_Y16 ||
-           tpg->fourcc == V4L2_PIX_FMT_Y16_BE) {
-               /* Rec. 709 Luma function */
-               /* (0.2126, 0.7152, 0.0722) * (255 * 256) */
-               r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;
-       }
-
-       /*
-        * The assumption is that the RGB output is always full range,
-        * so only if the rgb_range overrides the 'real' rgb range do
-        * we need to convert the RGB values.
-        *
-        * Remember that r, g and b are still in the 0 - 0xff0 range.
-        */
-       if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
-           tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL) {
-               /*
-                * Convert from full range (which is what r, g and b are)
-                * to limited range (which is the 'real' RGB range), which
-                * is then interpreted as full range.
-                */
-               r = (r * 219) / 255 + (16 << 4);
-               g = (g * 219) / 255 + (16 << 4);
-               b = (b * 219) / 255 + (16 << 4);
-       } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
-                  tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED) {
-               /*
-                * Clamp r, g and b to the limited range and convert to full
-                * range since that's what we deliver.
-                */
-               r = clamp(r, 16 << 4, 235 << 4);
-               g = clamp(g, 16 << 4, 235 << 4);
-               b = clamp(b, 16 << 4, 235 << 4);
-               r = (r - (16 << 4)) * 255 / 219;
-               g = (g - (16 << 4)) * 255 / 219;
-               b = (b - (16 << 4)) * 255 / 219;
-       }
-
-       if (tpg->brightness != 128 || tpg->contrast != 128 ||
-           tpg->saturation != 128 || tpg->hue) {
-               /* Implement these operations */
-               int y, cb, cr;
-               int tmp_cb, tmp_cr;
-
-               /* First convert to YCbCr */
-
-               color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
-
-               y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
-               y += (tpg->brightness << 4) - (128 << 4);
-
-               cb -= 128 << 4;
-               cr -= 128 << 4;
-               tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
-               tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
-
-               cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
-               cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
-               if (tpg->is_yuv) {
-                       tpg->colors[k][0] = clamp(y >> 4, 1, 254);
-                       tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
-                       tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
-                       return;
-               }
-               ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b);
-       }
-
-       if (tpg->is_yuv) {
-               /* Convert to YCbCr */
-               int y, cb, cr;
-
-               color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
-
-               if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
-                       y = clamp(y, 16 << 4, 235 << 4);
-                       cb = clamp(cb, 16 << 4, 240 << 4);
-                       cr = clamp(cr, 16 << 4, 240 << 4);
-               }
-               y = clamp(y >> 4, 1, 254);
-               cb = clamp(cb >> 4, 1, 254);
-               cr = clamp(cr >> 4, 1, 254);
-               switch (tpg->fourcc) {
-               case V4L2_PIX_FMT_YUV444:
-                       y >>= 4;
-                       cb >>= 4;
-                       cr >>= 4;
-                       break;
-               case V4L2_PIX_FMT_YUV555:
-                       y >>= 3;
-                       cb >>= 3;
-                       cr >>= 3;
-                       break;
-               case V4L2_PIX_FMT_YUV565:
-                       y >>= 3;
-                       cb >>= 2;
-                       cr >>= 3;
-                       break;
-               }
-               tpg->colors[k][0] = y;
-               tpg->colors[k][1] = cb;
-               tpg->colors[k][2] = cr;
-       } else {
-               if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
-                       r = (r * 219) / 255 + (16 << 4);
-                       g = (g * 219) / 255 + (16 << 4);
-                       b = (b * 219) / 255 + (16 << 4);
-               }
-               switch (tpg->fourcc) {
-               case V4L2_PIX_FMT_RGB332:
-                       r >>= 9;
-                       g >>= 9;
-                       b >>= 10;
-                       break;
-               case V4L2_PIX_FMT_RGB565:
-               case V4L2_PIX_FMT_RGB565X:
-                       r >>= 7;
-                       g >>= 6;
-                       b >>= 7;
-                       break;
-               case V4L2_PIX_FMT_RGB444:
-               case V4L2_PIX_FMT_XRGB444:
-               case V4L2_PIX_FMT_ARGB444:
-                       r >>= 8;
-                       g >>= 8;
-                       b >>= 8;
-                       break;
-               case V4L2_PIX_FMT_RGB555:
-               case V4L2_PIX_FMT_XRGB555:
-               case V4L2_PIX_FMT_ARGB555:
-               case V4L2_PIX_FMT_RGB555X:
-               case V4L2_PIX_FMT_XRGB555X:
-               case V4L2_PIX_FMT_ARGB555X:
-                       r >>= 7;
-                       g >>= 7;
-                       b >>= 7;
-                       break;
-               case V4L2_PIX_FMT_BGR666:
-                       r >>= 6;
-                       g >>= 6;
-                       b >>= 6;
-                       break;
-               default:
-                       r >>= 4;
-                       g >>= 4;
-                       b >>= 4;
-                       break;
-               }
-
-               tpg->colors[k][0] = r;
-               tpg->colors[k][1] = g;
-               tpg->colors[k][2] = b;
-       }
-}
-
-static void tpg_precalculate_colors(struct tpg_data *tpg)
-{
-       int k;
-
-       for (k = 0; k < TPG_COLOR_MAX; k++)
-               precalculate_color(tpg, k);
-}
-
-/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
-static void gen_twopix(struct tpg_data *tpg,
-               u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
-{
-       unsigned offset = odd * tpg->twopixelsize[0] / 2;
-       u8 alpha = tpg->alpha_component;
-       u8 r_y, g_u, b_v;
-
-       if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
-                                  color != TPG_COLOR_100_RED &&
-                                  color != TPG_COLOR_75_RED)
-               alpha = 0;
-       if (color == TPG_COLOR_RANDOM)
-               precalculate_color(tpg, color);
-       r_y = tpg->colors[color][0]; /* R or precalculated Y */
-       g_u = tpg->colors[color][1]; /* G or precalculated U */
-       b_v = tpg->colors[color][2]; /* B or precalculated V */
-
-       switch (tpg->fourcc) {
-       case V4L2_PIX_FMT_GREY:
-               buf[0][offset] = r_y;
-               break;
-       case V4L2_PIX_FMT_Y16:
-               /*
-                * Ideally both bytes should be set to r_y, but then you won't
-                * be able to detect endian problems. So keep it 0 except for
-                * the corner case where r_y is 0xff so white really will be
-                * white (0xffff).
-                */
-               buf[0][offset] = r_y == 0xff ? r_y : 0;
-               buf[0][offset+1] = r_y;
-               break;
-       case V4L2_PIX_FMT_Y16_BE:
-               /* See comment for V4L2_PIX_FMT_Y16 above */
-               buf[0][offset] = r_y;
-               buf[0][offset+1] = r_y == 0xff ? r_y : 0;
-               break;
-       case V4L2_PIX_FMT_YUV422M:
-       case V4L2_PIX_FMT_YUV422P:
-       case V4L2_PIX_FMT_YUV420:
-       case V4L2_PIX_FMT_YUV420M:
-               buf[0][offset] = r_y;
-               if (odd) {
-                       buf[1][0] = (buf[1][0] + g_u) / 2;
-                       buf[2][0] = (buf[2][0] + b_v) / 2;
-                       buf[1][1] = buf[1][0];
-                       buf[2][1] = buf[2][0];
-                       break;
-               }
-               buf[1][0] = g_u;
-               buf[2][0] = b_v;
-               break;
-       case V4L2_PIX_FMT_YVU422M:
-       case V4L2_PIX_FMT_YVU420:
-       case V4L2_PIX_FMT_YVU420M:
-               buf[0][offset] = r_y;
-               if (odd) {
-                       buf[1][0] = (buf[1][0] + b_v) / 2;
-                       buf[2][0] = (buf[2][0] + g_u) / 2;
-                       buf[1][1] = buf[1][0];
-                       buf[2][1] = buf[2][0];
-                       break;
-               }
-               buf[1][0] = b_v;
-               buf[2][0] = g_u;
-               break;
-
-       case V4L2_PIX_FMT_NV12:
-       case V4L2_PIX_FMT_NV12M:
-       case V4L2_PIX_FMT_NV16:
-       case V4L2_PIX_FMT_NV16M:
-               buf[0][offset] = r_y;
-               if (odd) {
-                       buf[1][0] = (buf[1][0] + g_u) / 2;
-                       buf[1][1] = (buf[1][1] + b_v) / 2;
-                       break;
-               }
-               buf[1][0] = g_u;
-               buf[1][1] = b_v;
-               break;
-       case V4L2_PIX_FMT_NV21:
-       case V4L2_PIX_FMT_NV21M:
-       case V4L2_PIX_FMT_NV61:
-       case V4L2_PIX_FMT_NV61M:
-               buf[0][offset] = r_y;
-               if (odd) {
-                       buf[1][0] = (buf[1][0] + b_v) / 2;
-                       buf[1][1] = (buf[1][1] + g_u) / 2;
-                       break;
-               }
-               buf[1][0] = b_v;
-               buf[1][1] = g_u;
-               break;
-
-       case V4L2_PIX_FMT_YUV444M:
-               buf[0][offset] = r_y;
-               buf[1][offset] = g_u;
-               buf[2][offset] = b_v;
-               break;
-
-       case V4L2_PIX_FMT_YVU444M:
-               buf[0][offset] = r_y;
-               buf[1][offset] = b_v;
-               buf[2][offset] = g_u;
-               break;
-
-       case V4L2_PIX_FMT_NV24:
-               buf[0][offset] = r_y;
-               buf[1][2 * offset] = g_u;
-               buf[1][2 * offset + 1] = b_v;
-               break;
-
-       case V4L2_PIX_FMT_NV42:
-               buf[0][offset] = r_y;
-               buf[1][2 * offset] = b_v;
-               buf[1][2 * offset + 1] = g_u;
-               break;
-
-       case V4L2_PIX_FMT_YUYV:
-               buf[0][offset] = r_y;
-               if (odd) {
-                       buf[0][1] = (buf[0][1] + g_u) / 2;
-                       buf[0][3] = (buf[0][3] + b_v) / 2;
-                       break;
-               }
-               buf[0][1] = g_u;
-               buf[0][3] = b_v;
-               break;
-       case V4L2_PIX_FMT_UYVY:
-               buf[0][offset + 1] = r_y;
-               if (odd) {
-                       buf[0][0] = (buf[0][0] + g_u) / 2;
-                       buf[0][2] = (buf[0][2] + b_v) / 2;
-                       break;
-               }
-               buf[0][0] = g_u;
-               buf[0][2] = b_v;
-               break;
-       case V4L2_PIX_FMT_YVYU:
-               buf[0][offset] = r_y;
-               if (odd) {
-                       buf[0][1] = (buf[0][1] + b_v) / 2;
-                       buf[0][3] = (buf[0][3] + g_u) / 2;
-                       break;
-               }
-               buf[0][1] = b_v;
-               buf[0][3] = g_u;
-               break;
-       case V4L2_PIX_FMT_VYUY:
-               buf[0][offset + 1] = r_y;
-               if (odd) {
-                       buf[0][0] = (buf[0][0] + b_v) / 2;
-                       buf[0][2] = (buf[0][2] + g_u) / 2;
-                       break;
-               }
-               buf[0][0] = b_v;
-               buf[0][2] = g_u;
-               break;
-       case V4L2_PIX_FMT_RGB332:
-               buf[0][offset] = (r_y << 5) | (g_u << 2) | b_v;
-               break;
-       case V4L2_PIX_FMT_YUV565:
-       case V4L2_PIX_FMT_RGB565:
-               buf[0][offset] = (g_u << 5) | b_v;
-               buf[0][offset + 1] = (r_y << 3) | (g_u >> 3);
-               break;
-       case V4L2_PIX_FMT_RGB565X:
-               buf[0][offset] = (r_y << 3) | (g_u >> 3);
-               buf[0][offset + 1] = (g_u << 5) | b_v;
-               break;
-       case V4L2_PIX_FMT_RGB444:
-       case V4L2_PIX_FMT_XRGB444:
-               alpha = 0;
-               /* fall through */
-       case V4L2_PIX_FMT_YUV444:
-       case V4L2_PIX_FMT_ARGB444:
-               buf[0][offset] = (g_u << 4) | b_v;
-               buf[0][offset + 1] = (alpha & 0xf0) | r_y;
-               break;
-       case V4L2_PIX_FMT_RGB555:
-       case V4L2_PIX_FMT_XRGB555:
-               alpha = 0;
-               /* fall through */
-       case V4L2_PIX_FMT_YUV555:
-       case V4L2_PIX_FMT_ARGB555:
-               buf[0][offset] = (g_u << 5) | b_v;
-               buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
-               break;
-       case V4L2_PIX_FMT_RGB555X:
-       case V4L2_PIX_FMT_XRGB555X:
-               alpha = 0;
-               /* fall through */
-       case V4L2_PIX_FMT_ARGB555X:
-               buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
-               buf[0][offset + 1] = (g_u << 5) | b_v;
-               break;
-       case V4L2_PIX_FMT_RGB24:
-               buf[0][offset] = r_y;
-               buf[0][offset + 1] = g_u;
-               buf[0][offset + 2] = b_v;
-               break;
-       case V4L2_PIX_FMT_BGR24:
-               buf[0][offset] = b_v;
-               buf[0][offset + 1] = g_u;
-               buf[0][offset + 2] = r_y;
-               break;
-       case V4L2_PIX_FMT_BGR666:
-               buf[0][offset] = (b_v << 2) | (g_u >> 4);
-               buf[0][offset + 1] = (g_u << 4) | (r_y >> 2);
-               buf[0][offset + 2] = r_y << 6;
-               buf[0][offset + 3] = 0;
-               break;
-       case V4L2_PIX_FMT_RGB32:
-       case V4L2_PIX_FMT_XRGB32:
-               alpha = 0;
-               /* fall through */
-       case V4L2_PIX_FMT_YUV32:
-       case V4L2_PIX_FMT_ARGB32:
-               buf[0][offset] = alpha;
-               buf[0][offset + 1] = r_y;
-               buf[0][offset + 2] = g_u;
-               buf[0][offset + 3] = b_v;
-               break;
-       case V4L2_PIX_FMT_BGR32:
-       case V4L2_PIX_FMT_XBGR32:
-               alpha = 0;
-               /* fall through */
-       case V4L2_PIX_FMT_ABGR32:
-               buf[0][offset] = b_v;
-               buf[0][offset + 1] = g_u;
-               buf[0][offset + 2] = r_y;
-               buf[0][offset + 3] = alpha;
-               break;
-       case V4L2_PIX_FMT_SBGGR8:
-               buf[0][offset] = odd ? g_u : b_v;
-               buf[1][offset] = odd ? r_y : g_u;
-               break;
-       case V4L2_PIX_FMT_SGBRG8:
-               buf[0][offset] = odd ? b_v : g_u;
-               buf[1][offset] = odd ? g_u : r_y;
-               break;
-       case V4L2_PIX_FMT_SGRBG8:
-               buf[0][offset] = odd ? r_y : g_u;
-               buf[1][offset] = odd ? g_u : b_v;
-               break;
-       case V4L2_PIX_FMT_SRGGB8:
-               buf[0][offset] = odd ? g_u : r_y;
-               buf[1][offset] = odd ? b_v : g_u;
-               break;
-       case V4L2_PIX_FMT_SBGGR10:
-               buf[0][offset] = odd ? g_u << 2 : b_v << 2;
-               buf[0][offset + 1] = odd ? g_u >> 6 : b_v >> 6;
-               buf[1][offset] = odd ? r_y << 2 : g_u << 2;
-               buf[1][offset + 1] = odd ? r_y >> 6 : g_u >> 6;
-               buf[0][offset] |= (buf[0][offset] >> 2) & 3;
-               buf[1][offset] |= (buf[1][offset] >> 2) & 3;
-               break;
-       case V4L2_PIX_FMT_SGBRG10:
-               buf[0][offset] = odd ? b_v << 2 : g_u << 2;
-               buf[0][offset + 1] = odd ? b_v >> 6 : g_u >> 6;
-               buf[1][offset] = odd ? g_u << 2 : r_y << 2;
-               buf[1][offset + 1] = odd ? g_u >> 6 : r_y >> 6;
-               buf[0][offset] |= (buf[0][offset] >> 2) & 3;
-               buf[1][offset] |= (buf[1][offset] >> 2) & 3;
-               break;
-       case V4L2_PIX_FMT_SGRBG10:
-               buf[0][offset] = odd ? r_y << 2 : g_u << 2;
-               buf[0][offset + 1] = odd ? r_y >> 6 : g_u >> 6;
-               buf[1][offset] = odd ? g_u << 2 : b_v << 2;
-               buf[1][offset + 1] = odd ? g_u >> 6 : b_v >> 6;
-               buf[0][offset] |= (buf[0][offset] >> 2) & 3;
-               buf[1][offset] |= (buf[1][offset] >> 2) & 3;
-               break;
-       case V4L2_PIX_FMT_SRGGB10:
-               buf[0][offset] = odd ? g_u << 2 : r_y << 2;
-               buf[0][offset + 1] = odd ? g_u >> 6 : r_y >> 6;
-               buf[1][offset] = odd ? b_v << 2 : g_u << 2;
-               buf[1][offset + 1] = odd ? b_v >> 6 : g_u >> 6;
-               buf[0][offset] |= (buf[0][offset] >> 2) & 3;
-               buf[1][offset] |= (buf[1][offset] >> 2) & 3;
-               break;
-       case V4L2_PIX_FMT_SBGGR12:
-               buf[0][offset] = odd ? g_u << 4 : b_v << 4;
-               buf[0][offset + 1] = odd ? g_u >> 4 : b_v >> 4;
-               buf[1][offset] = odd ? r_y << 4 : g_u << 4;
-               buf[1][offset + 1] = odd ? r_y >> 4 : g_u >> 4;
-               buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
-               buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
-               break;
-       case V4L2_PIX_FMT_SGBRG12:
-               buf[0][offset] = odd ? b_v << 4 : g_u << 4;
-               buf[0][offset + 1] = odd ? b_v >> 4 : g_u >> 4;
-               buf[1][offset] = odd ? g_u << 4 : r_y << 4;
-               buf[1][offset + 1] = odd ? g_u >> 4 : r_y >> 4;
-               buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
-               buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
-               break;
-       case V4L2_PIX_FMT_SGRBG12:
-               buf[0][offset] = odd ? r_y << 4 : g_u << 4;
-               buf[0][offset + 1] = odd ? r_y >> 4 : g_u >> 4;
-               buf[1][offset] = odd ? g_u << 4 : b_v << 4;
-               buf[1][offset + 1] = odd ? g_u >> 4 : b_v >> 4;
-               buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
-               buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
-               break;
-       case V4L2_PIX_FMT_SRGGB12:
-               buf[0][offset] = odd ? g_u << 4 : r_y << 4;
-               buf[0][offset + 1] = odd ? g_u >> 4 : r_y >> 4;
-               buf[1][offset] = odd ? b_v << 4 : g_u << 4;
-               buf[1][offset + 1] = odd ? b_v >> 4 : g_u >> 4;
-               buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
-               buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
-               break;
-       }
-}
-
-unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line)
-{
-       switch (tpg->fourcc) {
-       case V4L2_PIX_FMT_SBGGR8:
-       case V4L2_PIX_FMT_SGBRG8:
-       case V4L2_PIX_FMT_SGRBG8:
-       case V4L2_PIX_FMT_SRGGB8:
-       case V4L2_PIX_FMT_SBGGR10:
-       case V4L2_PIX_FMT_SGBRG10:
-       case V4L2_PIX_FMT_SGRBG10:
-       case V4L2_PIX_FMT_SRGGB10:
-       case V4L2_PIX_FMT_SBGGR12:
-       case V4L2_PIX_FMT_SGBRG12:
-       case V4L2_PIX_FMT_SGRBG12:
-       case V4L2_PIX_FMT_SRGGB12:
-               return buf_line & 1;
-       default:
-               return 0;
-       }
-}
-
-/* Return how many pattern lines are used by the current pattern. */
-static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)
-{
-       switch (tpg->pattern) {
-       case TPG_PAT_CHECKERS_16X16:
-       case TPG_PAT_CHECKERS_2X2:
-       case TPG_PAT_CHECKERS_1X1:
-       case TPG_PAT_COLOR_CHECKERS_2X2:
-       case TPG_PAT_COLOR_CHECKERS_1X1:
-       case TPG_PAT_ALTERNATING_HLINES:
-       case TPG_PAT_CROSS_1_PIXEL:
-       case TPG_PAT_CROSS_2_PIXELS:
-       case TPG_PAT_CROSS_10_PIXELS:
-               return 2;
-       case TPG_PAT_100_COLORSQUARES:
-       case TPG_PAT_100_HCOLORBAR:
-               return 8;
-       default:
-               return 1;
-       }
-}
-
-/* Which pattern line should be used for the given frame line. */
-static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line)
-{
-       switch (tpg->pattern) {
-       case TPG_PAT_CHECKERS_16X16:
-               return (line >> 4) & 1;
-       case TPG_PAT_CHECKERS_1X1:
-       case TPG_PAT_COLOR_CHECKERS_1X1:
-       case TPG_PAT_ALTERNATING_HLINES:
-               return line & 1;
-       case TPG_PAT_CHECKERS_2X2:
-       case TPG_PAT_COLOR_CHECKERS_2X2:
-               return (line & 2) >> 1;
-       case TPG_PAT_100_COLORSQUARES:
-       case TPG_PAT_100_HCOLORBAR:
-               return (line * 8) / tpg->src_height;
-       case TPG_PAT_CROSS_1_PIXEL:
-               return line == tpg->src_height / 2;
-       case TPG_PAT_CROSS_2_PIXELS:
-               return (line + 1) / 2 == tpg->src_height / 4;
-       case TPG_PAT_CROSS_10_PIXELS:
-               return (line + 10) / 20 == tpg->src_height / 40;
-       default:
-               return 0;
-       }
-}
-
-/*
- * Which color should be used for the given pattern line and X coordinate.
- * Note: x is in the range 0 to 2 * tpg->src_width.
- */
-static enum tpg_color tpg_get_color(const struct tpg_data *tpg,
-                                   unsigned pat_line, unsigned x)
-{
-       /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
-          should be modified */
-       static const enum tpg_color bars[3][8] = {
-               /* Standard ITU-R 75% color bar sequence */
-               { TPG_COLOR_CSC_WHITE,   TPG_COLOR_75_YELLOW,
-                 TPG_COLOR_75_CYAN,     TPG_COLOR_75_GREEN,
-                 TPG_COLOR_75_MAGENTA,  TPG_COLOR_75_RED,
-                 TPG_COLOR_75_BLUE,     TPG_COLOR_100_BLACK, },
-               /* Standard ITU-R 100% color bar sequence */
-               { TPG_COLOR_100_WHITE,   TPG_COLOR_100_YELLOW,
-                 TPG_COLOR_100_CYAN,    TPG_COLOR_100_GREEN,
-                 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
-                 TPG_COLOR_100_BLUE,    TPG_COLOR_100_BLACK, },
-               /* Color bar sequence suitable to test CSC */
-               { TPG_COLOR_CSC_WHITE,   TPG_COLOR_CSC_YELLOW,
-                 TPG_COLOR_CSC_CYAN,    TPG_COLOR_CSC_GREEN,
-                 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
-                 TPG_COLOR_CSC_BLUE,    TPG_COLOR_CSC_BLACK, },
-       };
-
-       switch (tpg->pattern) {
-       case TPG_PAT_75_COLORBAR:
-       case TPG_PAT_100_COLORBAR:
-       case TPG_PAT_CSC_COLORBAR:
-               return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
-       case TPG_PAT_100_COLORSQUARES:
-               return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
-       case TPG_PAT_100_HCOLORBAR:
-               return bars[1][pat_line];
-       case TPG_PAT_BLACK:
-               return TPG_COLOR_100_BLACK;
-       case TPG_PAT_WHITE:
-               return TPG_COLOR_100_WHITE;
-       case TPG_PAT_RED:
-               return TPG_COLOR_100_RED;
-       case TPG_PAT_GREEN:
-               return TPG_COLOR_100_GREEN;
-       case TPG_PAT_BLUE:
-               return TPG_COLOR_100_BLUE;
-       case TPG_PAT_CHECKERS_16X16:
-               return (((x >> 4) & 1) ^ (pat_line & 1)) ?
-                       TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
-       case TPG_PAT_CHECKERS_1X1:
-               return ((x & 1) ^ (pat_line & 1)) ?
-                       TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
-       case TPG_PAT_COLOR_CHECKERS_1X1:
-               return ((x & 1) ^ (pat_line & 1)) ?
-                       TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
-       case TPG_PAT_CHECKERS_2X2:
-               return (((x >> 1) & 1) ^ (pat_line & 1)) ?
-                       TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
-       case TPG_PAT_COLOR_CHECKERS_2X2:
-               return (((x >> 1) & 1) ^ (pat_line & 1)) ?
-                       TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
-       case TPG_PAT_ALTERNATING_HLINES:
-               return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
-       case TPG_PAT_ALTERNATING_VLINES:
-               return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
-       case TPG_PAT_CROSS_1_PIXEL:
-               if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
-                       return TPG_COLOR_100_BLACK;
-               return TPG_COLOR_100_WHITE;
-       case TPG_PAT_CROSS_2_PIXELS:
-               if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
-                       return TPG_COLOR_100_BLACK;
-               return TPG_COLOR_100_WHITE;
-       case TPG_PAT_CROSS_10_PIXELS:
-               if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
-                       return TPG_COLOR_100_BLACK;
-               return TPG_COLOR_100_WHITE;
-       case TPG_PAT_GRAY_RAMP:
-               return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
-       default:
-               return TPG_COLOR_100_RED;
-       }
-}
-
-/*
- * Given the pixel aspect ratio and video aspect ratio calculate the
- * coordinates of a centered square and the coordinates of the border of
- * the active video area. The coordinates are relative to the source
- * frame rectangle.
- */
-static void tpg_calculate_square_border(struct tpg_data *tpg)
-{
-       unsigned w = tpg->src_width;
-       unsigned h = tpg->src_height;
-       unsigned sq_w, sq_h;
-
-       sq_w = (w * 2 / 5) & ~1;
-       if (((w - sq_w) / 2) & 1)
-               sq_w += 2;
-       sq_h = sq_w;
-       tpg->square.width = sq_w;
-       if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
-               unsigned ana_sq_w = (sq_w / 4) * 3;
-
-               if (((w - ana_sq_w) / 2) & 1)
-                       ana_sq_w += 2;
-               tpg->square.width = ana_sq_w;
-       }
-       tpg->square.left = (w - tpg->square.width) / 2;
-       if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
-               sq_h = sq_w * 10 / 11;
-       else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
-               sq_h = sq_w * 59 / 54;
-       tpg->square.height = sq_h;
-       tpg->square.top = (h - sq_h) / 2;
-       tpg->border.left = 0;
-       tpg->border.width = w;
-       tpg->border.top = 0;
-       tpg->border.height = h;
-       switch (tpg->vid_aspect) {
-       case TPG_VIDEO_ASPECT_4X3:
-               if (tpg->pix_aspect)
-                       return;
-               if (3 * w >= 4 * h) {
-                       tpg->border.width = ((4 * h) / 3) & ~1;
-                       if (((w - tpg->border.width) / 2) & ~1)
-                               tpg->border.width -= 2;
-                       tpg->border.left = (w - tpg->border.width) / 2;
-                       break;
-               }
-               tpg->border.height = ((3 * w) / 4) & ~1;
-               tpg->border.top = (h - tpg->border.height) / 2;
-               break;
-       case TPG_VIDEO_ASPECT_14X9_CENTRE:
-               if (tpg->pix_aspect) {
-                       tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
-                       tpg->border.top = (h - tpg->border.height) / 2;
-                       break;
-               }
-               if (9 * w >= 14 * h) {
-                       tpg->border.width = ((14 * h) / 9) & ~1;
-                       if (((w - tpg->border.width) / 2) & ~1)
-                               tpg->border.width -= 2;
-                       tpg->border.left = (w - tpg->border.width) / 2;
-                       break;
-               }
-               tpg->border.height = ((9 * w) / 14) & ~1;
-               tpg->border.top = (h - tpg->border.height) / 2;
-               break;
-       case TPG_VIDEO_ASPECT_16X9_CENTRE:
-               if (tpg->pix_aspect) {
-                       tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
-                       tpg->border.top = (h - tpg->border.height) / 2;
-                       break;
-               }
-               if (9 * w >= 16 * h) {
-                       tpg->border.width = ((16 * h) / 9) & ~1;
-                       if (((w - tpg->border.width) / 2) & ~1)
-                               tpg->border.width -= 2;
-                       tpg->border.left = (w - tpg->border.width) / 2;
-                       break;
-               }
-               tpg->border.height = ((9 * w) / 16) & ~1;
-               tpg->border.top = (h - tpg->border.height) / 2;
-               break;
-       default:
-               break;
-       }
-}
-
-static void tpg_precalculate_line(struct tpg_data *tpg)
-{
-       enum tpg_color contrast;
-       u8 pix[TPG_MAX_PLANES][8];
-       unsigned pat;
-       unsigned p;
-       unsigned x;
-
-       switch (tpg->pattern) {
-       case TPG_PAT_GREEN:
-               contrast = TPG_COLOR_100_RED;
-               break;
-       case TPG_PAT_CSC_COLORBAR:
-               contrast = TPG_COLOR_CSC_GREEN;
-               break;
-       default:
-               contrast = TPG_COLOR_100_GREEN;
-               break;
-       }
-
-       for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
-               /* Coarse scaling with Bresenham */
-               unsigned int_part = tpg->src_width / tpg->scaled_width;
-               unsigned fract_part = tpg->src_width % tpg->scaled_width;
-               unsigned src_x = 0;
-               unsigned error = 0;
-
-               for (x = 0; x < tpg->scaled_width * 2; x += 2) {
-                       unsigned real_x = src_x;
-                       enum tpg_color color1, color2;
-
-                       real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
-                       color1 = tpg_get_color(tpg, pat, real_x);
-
-                       src_x += int_part;
-                       error += fract_part;
-                       if (error >= tpg->scaled_width) {
-                               error -= tpg->scaled_width;
-                               src_x++;
-                       }
-
-                       real_x = src_x;
-                       real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
-                       color2 = tpg_get_color(tpg, pat, real_x);
-
-                       src_x += int_part;
-                       error += fract_part;
-                       if (error >= tpg->scaled_width) {
-                               error -= tpg->scaled_width;
-                               src_x++;
-                       }
-
-                       gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);
-                       gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
-                       for (p = 0; p < tpg->planes; p++) {
-                               unsigned twopixsize = tpg->twopixelsize[p];
-                               unsigned hdiv = tpg->hdownsampling[p];
-                               u8 *pos = tpg->lines[pat][p] + tpg_hdiv(tpg, p, x);
-
-                               memcpy(pos, pix[p], twopixsize / hdiv);
-                       }
-               }
-       }
-
-       if (tpg->vdownsampling[tpg->planes - 1] > 1) {
-               unsigned pat_lines = tpg_get_pat_lines(tpg);
-
-               for (pat = 0; pat < pat_lines; pat++) {
-                       unsigned next_pat = (pat + 1) % pat_lines;
-
-                       for (p = 1; p < tpg->planes; p++) {
-                               unsigned w = tpg_hdiv(tpg, p, tpg->scaled_width * 2);
-                               u8 *pos1 = tpg->lines[pat][p];
-                               u8 *pos2 = tpg->lines[next_pat][p];
-                               u8 *dest = tpg->downsampled_lines[pat][p];
-
-                               for (x = 0; x < w; x++, pos1++, pos2++, dest++)
-                                       *dest = ((u16)*pos1 + (u16)*pos2) / 2;
-                       }
-               }
-       }
-
-       gen_twopix(tpg, pix, contrast, 0);
-       gen_twopix(tpg, pix, contrast, 1);
-       for (p = 0; p < tpg->planes; p++) {
-               unsigned twopixsize = tpg->twopixelsize[p];
-               u8 *pos = tpg->contrast_line[p];
-
-               for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
-                       memcpy(pos, pix[p], twopixsize);
-       }
-
-       gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
-       gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
-       for (p = 0; p < tpg->planes; p++) {
-               unsigned twopixsize = tpg->twopixelsize[p];
-               u8 *pos = tpg->black_line[p];
-
-               for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
-                       memcpy(pos, pix[p], twopixsize);
-       }
-
-       for (x = 0; x < tpg->scaled_width * 2; x += 2) {
-               gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
-               gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
-               for (p = 0; p < tpg->planes; p++) {
-                       unsigned twopixsize = tpg->twopixelsize[p];
-                       u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
-
-                       memcpy(pos, pix[p], twopixsize);
-               }
-       }
-
-       gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
-       gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
-       gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
-       gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);
-}
-
-/* need this to do rgb24 rendering */
-typedef struct { u16 __; u8 _; } __packed x24;
-
-#define PRINTSTR(PIXTYPE) do { \
-       unsigned vdiv = tpg->vdownsampling[p]; \
-       unsigned hdiv = tpg->hdownsampling[p]; \
-       int line;       \
-       PIXTYPE fg;     \
-       PIXTYPE bg;     \
-       memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE));   \
-       memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE));   \
-       \
-       for (line = first; line < 16; line += vdiv * step) {    \
-               int l = tpg->vflip ? 15 - line : line; \
-               PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \
-                              ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \
-                              (x / hdiv) * sizeof(PIXTYPE));   \
-               unsigned s;     \
-       \
-               for (s = 0; s < len; s++) {     \
-                       u8 chr = font8x16[text[s] * 16 + line]; \
-       \
-                       if (hdiv == 2 && tpg->hflip) { \
-                               pos[3] = (chr & (0x01 << 6) ? fg : bg); \
-                               pos[2] = (chr & (0x01 << 4) ? fg : bg); \
-                               pos[1] = (chr & (0x01 << 2) ? fg : bg); \
-                               pos[0] = (chr & (0x01 << 0) ? fg : bg); \
-                       } else if (hdiv == 2) { \
-                               pos[0] = (chr & (0x01 << 7) ? fg : bg); \
-                               pos[1] = (chr & (0x01 << 5) ? fg : bg); \
-                               pos[2] = (chr & (0x01 << 3) ? fg : bg); \
-                               pos[3] = (chr & (0x01 << 1) ? fg : bg); \
-                       } else if (tpg->hflip) { \
-                               pos[7] = (chr & (0x01 << 7) ? fg : bg); \
-                               pos[6] = (chr & (0x01 << 6) ? fg : bg); \
-                               pos[5] = (chr & (0x01 << 5) ? fg : bg); \
-                               pos[4] = (chr & (0x01 << 4) ? fg : bg); \
-                               pos[3] = (chr & (0x01 << 3) ? fg : bg); \
-                               pos[2] = (chr & (0x01 << 2) ? fg : bg); \
-                               pos[1] = (chr & (0x01 << 1) ? fg : bg); \
-                               pos[0] = (chr & (0x01 << 0) ? fg : bg); \
-                       } else { \
-                               pos[0] = (chr & (0x01 << 7) ? fg : bg); \
-                               pos[1] = (chr & (0x01 << 6) ? fg : bg); \
-                               pos[2] = (chr & (0x01 << 5) ? fg : bg); \
-                               pos[3] = (chr & (0x01 << 4) ? fg : bg); \
-                               pos[4] = (chr & (0x01 << 3) ? fg : bg); \
-                               pos[5] = (chr & (0x01 << 2) ? fg : bg); \
-                               pos[6] = (chr & (0x01 << 1) ? fg : bg); \
-                               pos[7] = (chr & (0x01 << 0) ? fg : bg); \
-                       } \
-       \
-                       pos += (tpg->hflip ? -8 : 8) / hdiv;    \
-               }       \
-       }       \
-} while (0)
-
-static noinline void tpg_print_str_2(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
-                       unsigned p, unsigned first, unsigned div, unsigned step,
-                       int y, int x, char *text, unsigned len)
-{
-       PRINTSTR(u8);
-}
-
-static noinline void tpg_print_str_4(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
-                       unsigned p, unsigned first, unsigned div, unsigned step,
-                       int y, int x, char *text, unsigned len)
-{
-       PRINTSTR(u16);
-}
-
-static noinline void tpg_print_str_6(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
-                       unsigned p, unsigned first, unsigned div, unsigned step,
-                       int y, int x, char *text, unsigned len)
-{
-       PRINTSTR(x24);
-}
-
-static noinline void tpg_print_str_8(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
-                       unsigned p, unsigned first, unsigned div, unsigned step,
-                       int y, int x, char *text, unsigned len)
-{
-       PRINTSTR(u32);
-}
-
-void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
-                 int y, int x, char *text)
-{
-       unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
-       unsigned div = step;
-       unsigned first = 0;
-       unsigned len = strlen(text);
-       unsigned p;
-
-       if (font8x16 == NULL || basep == NULL)
-               return;
-
-       /* Checks if it is possible to show string */
-       if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
-               return;
-
-       if (len > (tpg->compose.width - x) / 8)
-               len = (tpg->compose.width - x) / 8;
-       if (tpg->vflip)
-               y = tpg->compose.height - y - 16;
-       if (tpg->hflip)
-               x = tpg->compose.width - x - 8;
-       y += tpg->compose.top;
-       x += tpg->compose.left;
-       if (tpg->field == V4L2_FIELD_BOTTOM)
-               first = 1;
-       else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
-               div = 2;
-
-       for (p = 0; p < tpg->planes; p++) {
-               /* Print text */
-               switch (tpg->twopixelsize[p]) {
-               case 2:
-                       tpg_print_str_2(tpg, basep, p, first, div, step, y, x,
-                                       text, len);
-                       break;
-               case 4:
-                       tpg_print_str_4(tpg, basep, p, first, div, step, y, x,
-                                       text, len);
-                       break;
-               case 6:
-                       tpg_print_str_6(tpg, basep, p, first, div, step, y, x,
-                                       text, len);
-                       break;
-               case 8:
-                       tpg_print_str_8(tpg, basep, p, first, div, step, y, x,
-                                       text, len);
-                       break;
-               }
-       }
-}
-
-void tpg_update_mv_step(struct tpg_data *tpg)
-{
-       int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
-
-       if (tpg->hflip)
-               factor = -factor;
-       switch (tpg->mv_hor_mode) {
-       case TPG_MOVE_NEG_FAST:
-       case TPG_MOVE_POS_FAST:
-               tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
-               break;
-       case TPG_MOVE_NEG:
-       case TPG_MOVE_POS:
-               tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
-               break;
-       case TPG_MOVE_NEG_SLOW:
-       case TPG_MOVE_POS_SLOW:
-               tpg->mv_hor_step = 2;
-               break;
-       case TPG_MOVE_NONE:
-               tpg->mv_hor_step = 0;
-               break;
-       }
-       if (factor < 0)
-               tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
-
-       factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
-       switch (tpg->mv_vert_mode) {
-       case TPG_MOVE_NEG_FAST:
-       case TPG_MOVE_POS_FAST:
-               tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
-               break;
-       case TPG_MOVE_NEG:
-       case TPG_MOVE_POS:
-               tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
-               break;
-       case TPG_MOVE_NEG_SLOW:
-       case TPG_MOVE_POS_SLOW:
-               tpg->mv_vert_step = 1;
-               break;
-       case TPG_MOVE_NONE:
-               tpg->mv_vert_step = 0;
-               break;
-       }
-       if (factor < 0)
-               tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
-}
-
-/* Map the line number relative to the crop rectangle to a frame line number */
-static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y,
-                                   unsigned field)
-{
-       switch (field) {
-       case V4L2_FIELD_TOP:
-               return tpg->crop.top + src_y * 2;
-       case V4L2_FIELD_BOTTOM:
-               return tpg->crop.top + src_y * 2 + 1;
-       default:
-               return src_y + tpg->crop.top;
-       }
-}
-
-/*
- * Map the line number relative to the compose rectangle to a destination
- * buffer line number.
- */
-static unsigned tpg_calc_buffer_line(const struct tpg_data *tpg, unsigned y,
-                                   unsigned field)
-{
-       y += tpg->compose.top;
-       switch (field) {
-       case V4L2_FIELD_SEQ_TB:
-               if (y & 1)
-                       return tpg->buf_height / 2 + y / 2;
-               return y / 2;
-       case V4L2_FIELD_SEQ_BT:
-               if (y & 1)
-                       return y / 2;
-               return tpg->buf_height / 2 + y / 2;
-       default:
-               return y;
-       }
-}
-
-static void tpg_recalc(struct tpg_data *tpg)
-{
-       if (tpg->recalc_colors) {
-               tpg->recalc_colors = false;
-               tpg->recalc_lines = true;
-               tpg->real_xfer_func = tpg->xfer_func;
-               tpg->real_ycbcr_enc = tpg->ycbcr_enc;
-               tpg->real_quantization = tpg->quantization;
-
-               if (tpg->xfer_func == V4L2_XFER_FUNC_DEFAULT)
-                       tpg->real_xfer_func =
-                               V4L2_MAP_XFER_FUNC_DEFAULT(tpg->colorspace);
-
-               if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
-                       tpg->real_ycbcr_enc =
-                               V4L2_MAP_YCBCR_ENC_DEFAULT(tpg->colorspace);
-
-               if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT)
-                       tpg->real_quantization =
-                               V4L2_MAP_QUANTIZATION_DEFAULT(!tpg->is_yuv,
-                                       tpg->colorspace, tpg->real_ycbcr_enc);
-
-               tpg_precalculate_colors(tpg);
-       }
-       if (tpg->recalc_square_border) {
-               tpg->recalc_square_border = false;
-               tpg_calculate_square_border(tpg);
-       }
-       if (tpg->recalc_lines) {
-               tpg->recalc_lines = false;
-               tpg_precalculate_line(tpg);
-       }
-}
-
-void tpg_calc_text_basep(struct tpg_data *tpg,
-               u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
-{
-       unsigned stride = tpg->bytesperline[p];
-       unsigned h = tpg->buf_height;
-
-       tpg_recalc(tpg);
-
-       basep[p][0] = vbuf;
-       basep[p][1] = vbuf;
-       h /= tpg->vdownsampling[p];
-       if (tpg->field == V4L2_FIELD_SEQ_TB)
-               basep[p][1] += h * stride / 2;
-       else if (tpg->field == V4L2_FIELD_SEQ_BT)
-               basep[p][0] += h * stride / 2;
-       if (p == 0 && tpg->interleaved)
-               tpg_calc_text_basep(tpg, basep, 1, vbuf);
-}
-
-static int tpg_pattern_avg(const struct tpg_data *tpg,
-                          unsigned pat1, unsigned pat2)
-{
-       unsigned pat_lines = tpg_get_pat_lines(tpg);
-
-       if (pat1 == (pat2 + 1) % pat_lines)
-               return pat2;
-       if (pat2 == (pat1 + 1) % pat_lines)
-               return pat1;
-       return -1;
-}
-
-void tpg_log_status(struct tpg_data *tpg)
-{
-       pr_info("tpg source WxH: %ux%u (%s)\n",
-                       tpg->src_width, tpg->src_height,
-                       tpg->is_yuv ? "YCbCr" : "RGB");
-       pr_info("tpg field: %u\n", tpg->field);
-       pr_info("tpg crop: %ux%u@%dx%d\n", tpg->crop.width, tpg->crop.height,
-                       tpg->crop.left, tpg->crop.top);
-       pr_info("tpg compose: %ux%u@%dx%d\n", tpg->compose.width, tpg->compose.height,
-                       tpg->compose.left, tpg->compose.top);
-       pr_info("tpg colorspace: %d\n", tpg->colorspace);
-       pr_info("tpg transfer function: %d/%d\n", tpg->xfer_func, tpg->real_xfer_func);
-       pr_info("tpg Y'CbCr encoding: %d/%d\n", tpg->ycbcr_enc, tpg->real_ycbcr_enc);
-       pr_info("tpg quantization: %d/%d\n", tpg->quantization, tpg->real_quantization);
-       pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range);
-}
-
-/*
- * This struct contains common parameters used by both the drawing of the
- * test pattern and the drawing of the extras (borders, square, etc.)
- */
-struct tpg_draw_params {
-       /* common data */
-       bool is_tv;
-       bool is_60hz;
-       unsigned twopixsize;
-       unsigned img_width;
-       unsigned stride;
-       unsigned hmax;
-       unsigned frame_line;
-       unsigned frame_line_next;
-
-       /* test pattern */
-       unsigned mv_hor_old;
-       unsigned mv_hor_new;
-       unsigned mv_vert_old;
-       unsigned mv_vert_new;
-
-       /* extras */
-       unsigned wss_width;
-       unsigned wss_random_offset;
-       unsigned sav_eav_f;
-       unsigned left_pillar_width;
-       unsigned right_pillar_start;
-};
-
-static void tpg_fill_params_pattern(const struct tpg_data *tpg, unsigned p,
-                                   struct tpg_draw_params *params)
-{
-       params->mv_hor_old =
-               tpg_hscale_div(tpg, p, tpg->mv_hor_count % tpg->src_width);
-       params->mv_hor_new =
-               tpg_hscale_div(tpg, p, (tpg->mv_hor_count + tpg->mv_hor_step) %
-                              tpg->src_width);
-       params->mv_vert_old = tpg->mv_vert_count % tpg->src_height;
-       params->mv_vert_new =
-               (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
-}
-
-static void tpg_fill_params_extras(const struct tpg_data *tpg,
-                                  unsigned p,
-                                  struct tpg_draw_params *params)
-{
-       unsigned left_pillar_width = 0;
-       unsigned right_pillar_start = params->img_width;
-
-       params->wss_width = tpg->crop.left < tpg->src_width / 2 ?
-               tpg->src_width / 2 - tpg->crop.left : 0;
-       if (params->wss_width > tpg->crop.width)
-               params->wss_width = tpg->crop.width;
-       params->wss_width = tpg_hscale_div(tpg, p, params->wss_width);
-       params->wss_random_offset =
-               params->twopixsize * prandom_u32_max(tpg->src_width / 2);
-
-       if (tpg->crop.left < tpg->border.left) {
-               left_pillar_width = tpg->border.left - tpg->crop.left;
-               if (left_pillar_width > tpg->crop.width)
-                       left_pillar_width = tpg->crop.width;
-               left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width);
-       }
-       params->left_pillar_width = left_pillar_width;
-
-       if (tpg->crop.left + tpg->crop.width >
-           tpg->border.left + tpg->border.width) {
-               right_pillar_start =
-                       tpg->border.left + tpg->border.width - tpg->crop.left;
-               right_pillar_start =
-                       tpg_hscale_div(tpg, p, right_pillar_start);
-               if (right_pillar_start > params->img_width)
-                       right_pillar_start = params->img_width;
-       }
-       params->right_pillar_start = right_pillar_start;
-
-       params->sav_eav_f = tpg->field ==
-                       (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
-}
-
-static void tpg_fill_plane_extras(const struct tpg_data *tpg,
-                                 const struct tpg_draw_params *params,
-                                 unsigned p, unsigned h, u8 *vbuf)
-{
-       unsigned twopixsize = params->twopixsize;
-       unsigned img_width = params->img_width;
-       unsigned frame_line = params->frame_line;
-       const struct v4l2_rect *sq = &tpg->square;
-       const struct v4l2_rect *b = &tpg->border;
-       const struct v4l2_rect *c = &tpg->crop;
-
-       if (params->is_tv && !params->is_60hz &&
-           frame_line == 0 && params->wss_width) {
-               /*
-                * Replace the first half of the top line of a 50 Hz frame
-                * with random data to simulate a WSS signal.
-                */
-               u8 *wss = tpg->random_line[p] + params->wss_random_offset;
-
-               memcpy(vbuf, wss, params->wss_width);
-       }
-
-       if (tpg->show_border && frame_line >= b->top &&
-           frame_line < b->top + b->height) {
-               unsigned bottom = b->top + b->height - 1;
-               unsigned left = params->left_pillar_width;
-               unsigned right = params->right_pillar_start;
-
-               if (frame_line == b->top || frame_line == b->top + 1 ||
-                   frame_line == bottom || frame_line == bottom - 1) {
-                       memcpy(vbuf + left, tpg->contrast_line[p],
-                                       right - left);
-               } else {
-                       if (b->left >= c->left &&
-                           b->left < c->left + c->width)
-                               memcpy(vbuf + left,
-                                       tpg->contrast_line[p], twopixsize);
-                       if (b->left + b->width > c->left &&
-                           b->left + b->width <= c->left + c->width)
-                               memcpy(vbuf + right - twopixsize,
-                                       tpg->contrast_line[p], twopixsize);
-               }
-       }
-       if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
-           frame_line < b->top + b->height) {
-               memcpy(vbuf, tpg->black_line[p], params->left_pillar_width);
-               memcpy(vbuf + params->right_pillar_start, tpg->black_line[p],
-                      img_width - params->right_pillar_start);
-       }
-       if (tpg->show_square && frame_line >= sq->top &&
-           frame_line < sq->top + sq->height &&
-           sq->left < c->left + c->width &&
-           sq->left + sq->width >= c->left) {
-               unsigned left = sq->left;
-               unsigned width = sq->width;
-
-               if (c->left > left) {
-                       width -= c->left - left;
-                       left = c->left;
-               }
-               if (c->left + c->width < left + width)
-                       width -= left + width - c->left - c->width;
-               left -= c->left;
-               left = tpg_hscale_div(tpg, p, left);
-               width = tpg_hscale_div(tpg, p, width);
-               memcpy(vbuf + left, tpg->contrast_line[p], width);
-       }
-       if (tpg->insert_sav) {
-               unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3);
-               u8 *p = vbuf + offset;
-               unsigned vact = 0, hact = 0;
-
-               p[0] = 0xff;
-               p[1] = 0;
-               p[2] = 0;
-               p[3] = 0x80 | (params->sav_eav_f << 6) |
-                       (vact << 5) | (hact << 4) |
-                       ((hact ^ vact) << 3) |
-                       ((hact ^ params->sav_eav_f) << 2) |
-                       ((params->sav_eav_f ^ vact) << 1) |
-                       (hact ^ vact ^ params->sav_eav_f);
-       }
-       if (tpg->insert_eav) {
-               unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3);
-               u8 *p = vbuf + offset;
-               unsigned vact = 0, hact = 1;
-
-               p[0] = 0xff;
-               p[1] = 0;
-               p[2] = 0;
-               p[3] = 0x80 | (params->sav_eav_f << 6) |
-                       (vact << 5) | (hact << 4) |
-                       ((hact ^ vact) << 3) |
-                       ((hact ^ params->sav_eav_f) << 2) |
-                       ((params->sav_eav_f ^ vact) << 1) |
-                       (hact ^ vact ^ params->sav_eav_f);
-       }
-}
-
-static void tpg_fill_plane_pattern(const struct tpg_data *tpg,
-                                  const struct tpg_draw_params *params,
-                                  unsigned p, unsigned h, u8 *vbuf)
-{
-       unsigned twopixsize = params->twopixsize;
-       unsigned img_width = params->img_width;
-       unsigned mv_hor_old = params->mv_hor_old;
-       unsigned mv_hor_new = params->mv_hor_new;
-       unsigned mv_vert_old = params->mv_vert_old;
-       unsigned mv_vert_new = params->mv_vert_new;
-       unsigned frame_line = params->frame_line;
-       unsigned frame_line_next = params->frame_line_next;
-       unsigned line_offset = tpg_hscale_div(tpg, p, tpg->crop.left);
-       bool even;
-       bool fill_blank = false;
-       unsigned pat_line_old;
-       unsigned pat_line_new;
-       u8 *linestart_older;
-       u8 *linestart_newer;
-       u8 *linestart_top;
-       u8 *linestart_bottom;
-
-       even = !(frame_line & 1);
-
-       if (h >= params->hmax) {
-               if (params->hmax == tpg->compose.height)
-                       return;
-               if (!tpg->perc_fill_blank)
-                       return;
-               fill_blank = true;
-       }
-
-       if (tpg->vflip) {
-               frame_line = tpg->src_height - frame_line - 1;
-               frame_line_next = tpg->src_height - frame_line_next - 1;
-       }
-
-       if (fill_blank) {
-               linestart_older = tpg->contrast_line[p];
-               linestart_newer = tpg->contrast_line[p];
-       } else if (tpg->qual != TPG_QUAL_NOISE &&
-                  (frame_line < tpg->border.top ||
-                   frame_line >= tpg->border.top + tpg->border.height)) {
-               linestart_older = tpg->black_line[p];
-               linestart_newer = tpg->black_line[p];
-       } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
-               linestart_older = tpg->random_line[p] +
-                                 twopixsize * prandom_u32_max(tpg->src_width / 2);
-               linestart_newer = tpg->random_line[p] +
-                                 twopixsize * prandom_u32_max(tpg->src_width / 2);
-       } else {
-               unsigned frame_line_old =
-                       (frame_line + mv_vert_old) % tpg->src_height;
-               unsigned frame_line_new =
-                       (frame_line + mv_vert_new) % tpg->src_height;
-               unsigned pat_line_next_old;
-               unsigned pat_line_next_new;
-
-               pat_line_old = tpg_get_pat_line(tpg, frame_line_old);
-               pat_line_new = tpg_get_pat_line(tpg, frame_line_new);
-               linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old;
-               linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new;
-
-               if (tpg->vdownsampling[p] > 1 && frame_line != frame_line_next) {
-                       int avg_pat;
-
-                       /*
-                        * Now decide whether we need to use downsampled_lines[].
-                        * That's necessary if the two lines use different patterns.
-                        */
-                       pat_line_next_old = tpg_get_pat_line(tpg,
-                                       (frame_line_next + mv_vert_old) % tpg->src_height);
-                       pat_line_next_new = tpg_get_pat_line(tpg,
-                                       (frame_line_next + mv_vert_new) % tpg->src_height);
-
-                       switch (tpg->field) {
-                       case V4L2_FIELD_INTERLACED:
-                       case V4L2_FIELD_INTERLACED_BT:
-                       case V4L2_FIELD_INTERLACED_TB:
-                               avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new);
-                               if (avg_pat < 0)
-                                       break;
-                               linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old;
-                               linestart_newer = linestart_older;
-                               break;
-                       case V4L2_FIELD_NONE:
-                       case V4L2_FIELD_TOP:
-                       case V4L2_FIELD_BOTTOM:
-                       case V4L2_FIELD_SEQ_BT:
-                       case V4L2_FIELD_SEQ_TB:
-                               avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old);
-                               if (avg_pat >= 0)
-                                       linestart_older = tpg->downsampled_lines[avg_pat][p] +
-                                               mv_hor_old;
-                               avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new);
-                               if (avg_pat >= 0)
-                                       linestart_newer = tpg->downsampled_lines[avg_pat][p] +
-                                               mv_hor_new;
-                               break;
-                       }
-               }
-               linestart_older += line_offset;
-               linestart_newer += line_offset;
-       }
-       if (tpg->field_alternate) {
-               linestart_top = linestart_bottom = linestart_older;
-       } else if (params->is_60hz) {
-               linestart_top = linestart_newer;
-               linestart_bottom = linestart_older;
-       } else {
-               linestart_top = linestart_older;
-               linestart_bottom = linestart_newer;
-       }
-
-       switch (tpg->field) {
-       case V4L2_FIELD_INTERLACED:
-       case V4L2_FIELD_INTERLACED_TB:
-       case V4L2_FIELD_SEQ_TB:
-       case V4L2_FIELD_SEQ_BT:
-               if (even)
-                       memcpy(vbuf, linestart_top, img_width);
-               else
-                       memcpy(vbuf, linestart_bottom, img_width);
-               break;
-       case V4L2_FIELD_INTERLACED_BT:
-               if (even)
-                       memcpy(vbuf, linestart_bottom, img_width);
-               else
-                       memcpy(vbuf, linestart_top, img_width);
-               break;
-       case V4L2_FIELD_TOP:
-               memcpy(vbuf, linestart_top, img_width);
-               break;
-       case V4L2_FIELD_BOTTOM:
-               memcpy(vbuf, linestart_bottom, img_width);
-               break;
-       case V4L2_FIELD_NONE:
-       default:
-               memcpy(vbuf, linestart_older, img_width);
-               break;
-       }
-}
-
-void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,
-                          unsigned p, u8 *vbuf)
-{
-       struct tpg_draw_params params;
-       unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
-
-       /* Coarse scaling with Bresenham */
-       unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
-       unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
-       unsigned src_y = 0;
-       unsigned error = 0;
-       unsigned h;
-
-       tpg_recalc(tpg);
-
-       params.is_tv = std;
-       params.is_60hz = std & V4L2_STD_525_60;
-       params.twopixsize = tpg->twopixelsize[p];
-       params.img_width = tpg_hdiv(tpg, p, tpg->compose.width);
-       params.stride = tpg->bytesperline[p];
-       params.hmax = (tpg->compose.height * tpg->perc_fill) / 100;
-
-       tpg_fill_params_pattern(tpg, p, &params);
-       tpg_fill_params_extras(tpg, p, &params);
-
-       vbuf += tpg_hdiv(tpg, p, tpg->compose.left);
-
-       for (h = 0; h < tpg->compose.height; h++) {
-               unsigned buf_line;
-
-               params.frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
-               params.frame_line_next = params.frame_line;
-               buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
-               src_y += int_part;
-               error += fract_part;
-               if (error >= tpg->compose.height) {
-                       error -= tpg->compose.height;
-                       src_y++;
-               }
-
-               /*
-                * For line-interleaved formats determine the 'plane'
-                * based on the buffer line.
-                */
-               if (tpg_g_interleaved(tpg))
-                       p = tpg_g_interleaved_plane(tpg, buf_line);
-
-               if (tpg->vdownsampling[p] > 1) {
-                       /*
-                        * When doing vertical downsampling the field setting
-                        * matters: for SEQ_BT/TB we downsample each field
-                        * separately (i.e. lines 0+2 are combined, as are
-                        * lines 1+3), for the other field settings we combine
-                        * odd and even lines. Doing that for SEQ_BT/TB would
-                        * be really weird.
-                        */
-                       if (tpg->field == V4L2_FIELD_SEQ_BT ||
-                           tpg->field == V4L2_FIELD_SEQ_TB) {
-                               unsigned next_src_y = src_y;
-
-                               if ((h & 3) >= 2)
-                                       continue;
-                               next_src_y += int_part;
-                               if (error + fract_part >= tpg->compose.height)
-                                       next_src_y++;
-                               params.frame_line_next =
-                                       tpg_calc_frameline(tpg, next_src_y, tpg->field);
-                       } else {
-                               if (h & 1)
-                                       continue;
-                               params.frame_line_next =
-                                       tpg_calc_frameline(tpg, src_y, tpg->field);
-                       }
-
-                       buf_line /= tpg->vdownsampling[p];
-               }
-               tpg_fill_plane_pattern(tpg, &params, p, h,
-                               vbuf + buf_line * params.stride);
-               tpg_fill_plane_extras(tpg, &params, p, h,
-                               vbuf + buf_line * params.stride);
-       }
-}
-
-void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
-{
-       unsigned offset = 0;
-       unsigned i;
-
-       if (tpg->buffers > 1) {
-               tpg_fill_plane_buffer(tpg, std, p, vbuf);
-               return;
-       }
-
-       for (i = 0; i < tpg_g_planes(tpg); i++) {
-               tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);
-               offset += tpg_calc_plane_size(tpg, i);
-       }
-}
diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h
deleted file mode 100644 (file)
index 93fbaee..0000000
+++ /dev/null
@@ -1,598 +0,0 @@
-/*
- * vivid-tpg.h - Test Pattern Generator
- *
- * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _VIVID_TPG_H_
-#define _VIVID_TPG_H_
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/random.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/videodev2.h>
-
-#include "vivid-tpg-colors.h"
-
-enum tpg_pattern {
-       TPG_PAT_75_COLORBAR,
-       TPG_PAT_100_COLORBAR,
-       TPG_PAT_CSC_COLORBAR,
-       TPG_PAT_100_HCOLORBAR,
-       TPG_PAT_100_COLORSQUARES,
-       TPG_PAT_BLACK,
-       TPG_PAT_WHITE,
-       TPG_PAT_RED,
-       TPG_PAT_GREEN,
-       TPG_PAT_BLUE,
-       TPG_PAT_CHECKERS_16X16,
-       TPG_PAT_CHECKERS_2X2,
-       TPG_PAT_CHECKERS_1X1,
-       TPG_PAT_COLOR_CHECKERS_2X2,
-       TPG_PAT_COLOR_CHECKERS_1X1,
-       TPG_PAT_ALTERNATING_HLINES,
-       TPG_PAT_ALTERNATING_VLINES,
-       TPG_PAT_CROSS_1_PIXEL,
-       TPG_PAT_CROSS_2_PIXELS,
-       TPG_PAT_CROSS_10_PIXELS,
-       TPG_PAT_GRAY_RAMP,
-
-       /* Must be the last pattern */
-       TPG_PAT_NOISE,
-};
-
-extern const char * const tpg_pattern_strings[];
-
-enum tpg_quality {
-       TPG_QUAL_COLOR,
-       TPG_QUAL_GRAY,
-       TPG_QUAL_NOISE
-};
-
-enum tpg_video_aspect {
-       TPG_VIDEO_ASPECT_IMAGE,
-       TPG_VIDEO_ASPECT_4X3,
-       TPG_VIDEO_ASPECT_14X9_CENTRE,
-       TPG_VIDEO_ASPECT_16X9_CENTRE,
-       TPG_VIDEO_ASPECT_16X9_ANAMORPHIC,
-};
-
-enum tpg_pixel_aspect {
-       TPG_PIXEL_ASPECT_SQUARE,
-       TPG_PIXEL_ASPECT_NTSC,
-       TPG_PIXEL_ASPECT_PAL,
-};
-
-enum tpg_move_mode {
-       TPG_MOVE_NEG_FAST,
-       TPG_MOVE_NEG,
-       TPG_MOVE_NEG_SLOW,
-       TPG_MOVE_NONE,
-       TPG_MOVE_POS_SLOW,
-       TPG_MOVE_POS,
-       TPG_MOVE_POS_FAST,
-};
-
-extern const char * const tpg_aspect_strings[];
-
-#define TPG_MAX_PLANES 3
-#define TPG_MAX_PAT_LINES 8
-
-struct tpg_data {
-       /* Source frame size */
-       unsigned                        src_width, src_height;
-       /* Buffer height */
-       unsigned                        buf_height;
-       /* Scaled output frame size */
-       unsigned                        scaled_width;
-       u32                             field;
-       bool                            field_alternate;
-       /* crop coordinates are frame-based */
-       struct v4l2_rect                crop;
-       /* compose coordinates are format-based */
-       struct v4l2_rect                compose;
-       /* border and square coordinates are frame-based */
-       struct v4l2_rect                border;
-       struct v4l2_rect                square;
-
-       /* Color-related fields */
-       enum tpg_quality                qual;
-       unsigned                        qual_offset;
-       u8                              alpha_component;
-       bool                            alpha_red_only;
-       u8                              brightness;
-       u8                              contrast;
-       u8                              saturation;
-       s16                             hue;
-       u32                             fourcc;
-       bool                            is_yuv;
-       u32                             colorspace;
-       u32                             xfer_func;
-       u32                             ycbcr_enc;
-       /*
-        * Stores the actual transfer function, i.e. will never be
-        * V4L2_XFER_FUNC_DEFAULT.
-        */
-       u32                             real_xfer_func;
-       /*
-        * Stores the actual Y'CbCr encoding, i.e. will never be
-        * V4L2_YCBCR_ENC_DEFAULT.
-        */
-       u32                             real_ycbcr_enc;
-       u32                             quantization;
-       /*
-        * Stores the actual quantization, i.e. will never be
-        * V4L2_QUANTIZATION_DEFAULT.
-        */
-       u32                             real_quantization;
-       enum tpg_video_aspect           vid_aspect;
-       enum tpg_pixel_aspect           pix_aspect;
-       unsigned                        rgb_range;
-       unsigned                        real_rgb_range;
-       unsigned                        buffers;
-       unsigned                        planes;
-       bool                            interleaved;
-       u8                              vdownsampling[TPG_MAX_PLANES];
-       u8                              hdownsampling[TPG_MAX_PLANES];
-       /*
-        * horizontal positions must be ANDed with this value to enforce
-        * correct boundaries for packed YUYV values.
-        */
-       unsigned                        hmask[TPG_MAX_PLANES];
-       /* Used to store the colors in native format, either RGB or YUV */
-       u8                              colors[TPG_COLOR_MAX][3];
-       u8                              textfg[TPG_MAX_PLANES][8], textbg[TPG_MAX_PLANES][8];
-       /* size in bytes for two pixels in each plane */
-       unsigned                        twopixelsize[TPG_MAX_PLANES];
-       unsigned                        bytesperline[TPG_MAX_PLANES];
-
-       /* Configuration */
-       enum tpg_pattern                pattern;
-       bool                            hflip;
-       bool                            vflip;
-       unsigned                        perc_fill;
-       bool                            perc_fill_blank;
-       bool                            show_border;
-       bool                            show_square;
-       bool                            insert_sav;
-       bool                            insert_eav;
-
-       /* Test pattern movement */
-       enum tpg_move_mode              mv_hor_mode;
-       int                             mv_hor_count;
-       int                             mv_hor_step;
-       enum tpg_move_mode              mv_vert_mode;
-       int                             mv_vert_count;
-       int                             mv_vert_step;
-
-       bool                            recalc_colors;
-       bool                            recalc_lines;
-       bool                            recalc_square_border;
-
-       /* Used to store TPG_MAX_PAT_LINES lines, each with up to two planes */
-       unsigned                        max_line_width;
-       u8                              *lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES];
-       u8                              *downsampled_lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES];
-       u8                              *random_line[TPG_MAX_PLANES];
-       u8                              *contrast_line[TPG_MAX_PLANES];
-       u8                              *black_line[TPG_MAX_PLANES];
-};
-
-void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h);
-int tpg_alloc(struct tpg_data *tpg, unsigned max_w);
-void tpg_free(struct tpg_data *tpg);
-void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
-                      u32 field);
-void tpg_log_status(struct tpg_data *tpg);
-
-void tpg_set_font(const u8 *f);
-void tpg_gen_text(const struct tpg_data *tpg,
-               u8 *basep[TPG_MAX_PLANES][2], int y, int x, char *text);
-void tpg_calc_text_basep(struct tpg_data *tpg,
-               u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf);
-unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line);
-void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,
-                          unsigned p, u8 *vbuf);
-void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std,
-                   unsigned p, u8 *vbuf);
-bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc);
-void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
-               const struct v4l2_rect *compose);
-
-static inline void tpg_s_pattern(struct tpg_data *tpg, enum tpg_pattern pattern)
-{
-       if (tpg->pattern == pattern)
-               return;
-       tpg->pattern = pattern;
-       tpg->recalc_colors = true;
-}
-
-static inline void tpg_s_quality(struct tpg_data *tpg,
-                                   enum tpg_quality qual, unsigned qual_offset)
-{
-       if (tpg->qual == qual && tpg->qual_offset == qual_offset)
-               return;
-       tpg->qual = qual;
-       tpg->qual_offset = qual_offset;
-       tpg->recalc_colors = true;
-}
-
-static inline enum tpg_quality tpg_g_quality(const struct tpg_data *tpg)
-{
-       return tpg->qual;
-}
-
-static inline void tpg_s_alpha_component(struct tpg_data *tpg,
-                                           u8 alpha_component)
-{
-       if (tpg->alpha_component == alpha_component)
-               return;
-       tpg->alpha_component = alpha_component;
-       tpg->recalc_colors = true;
-}
-
-static inline void tpg_s_alpha_mode(struct tpg_data *tpg,
-                                           bool red_only)
-{
-       if (tpg->alpha_red_only == red_only)
-               return;
-       tpg->alpha_red_only = red_only;
-       tpg->recalc_colors = true;
-}
-
-static inline void tpg_s_brightness(struct tpg_data *tpg,
-                                       u8 brightness)
-{
-       if (tpg->brightness == brightness)
-               return;
-       tpg->brightness = brightness;
-       tpg->recalc_colors = true;
-}
-
-static inline void tpg_s_contrast(struct tpg_data *tpg,
-                                       u8 contrast)
-{
-       if (tpg->contrast == contrast)
-               return;
-       tpg->contrast = contrast;
-       tpg->recalc_colors = true;
-}
-
-static inline void tpg_s_saturation(struct tpg_data *tpg,
-                                       u8 saturation)
-{
-       if (tpg->saturation == saturation)
-               return;
-       tpg->saturation = saturation;
-       tpg->recalc_colors = true;
-}
-
-static inline void tpg_s_hue(struct tpg_data *tpg,
-                                       s16 hue)
-{
-       if (tpg->hue == hue)
-               return;
-       tpg->hue = hue;
-       tpg->recalc_colors = true;
-}
-
-static inline void tpg_s_rgb_range(struct tpg_data *tpg,
-                                       unsigned rgb_range)
-{
-       if (tpg->rgb_range == rgb_range)
-               return;
-       tpg->rgb_range = rgb_range;
-       tpg->recalc_colors = true;
-}
-
-static inline void tpg_s_real_rgb_range(struct tpg_data *tpg,
-                                       unsigned rgb_range)
-{
-       if (tpg->real_rgb_range == rgb_range)
-               return;
-       tpg->real_rgb_range = rgb_range;
-       tpg->recalc_colors = true;
-}
-
-static inline void tpg_s_colorspace(struct tpg_data *tpg, u32 colorspace)
-{
-       if (tpg->colorspace == colorspace)
-               return;
-       tpg->colorspace = colorspace;
-       tpg->recalc_colors = true;
-}
-
-static inline u32 tpg_g_colorspace(const struct tpg_data *tpg)
-{
-       return tpg->colorspace;
-}
-
-static inline void tpg_s_ycbcr_enc(struct tpg_data *tpg, u32 ycbcr_enc)
-{
-       if (tpg->ycbcr_enc == ycbcr_enc)
-               return;
-       tpg->ycbcr_enc = ycbcr_enc;
-       tpg->recalc_colors = true;
-}
-
-static inline u32 tpg_g_ycbcr_enc(const struct tpg_data *tpg)
-{
-       return tpg->ycbcr_enc;
-}
-
-static inline void tpg_s_xfer_func(struct tpg_data *tpg, u32 xfer_func)
-{
-       if (tpg->xfer_func == xfer_func)
-               return;
-       tpg->xfer_func = xfer_func;
-       tpg->recalc_colors = true;
-}
-
-static inline u32 tpg_g_xfer_func(const struct tpg_data *tpg)
-{
-       return tpg->xfer_func;
-}
-
-static inline void tpg_s_quantization(struct tpg_data *tpg, u32 quantization)
-{
-       if (tpg->quantization == quantization)
-               return;
-       tpg->quantization = quantization;
-       tpg->recalc_colors = true;
-}
-
-static inline u32 tpg_g_quantization(const struct tpg_data *tpg)
-{
-       return tpg->quantization;
-}
-
-static inline unsigned tpg_g_buffers(const struct tpg_data *tpg)
-{
-       return tpg->buffers;
-}
-
-static inline unsigned tpg_g_planes(const struct tpg_data *tpg)
-{
-       return tpg->interleaved ? 1 : tpg->planes;
-}
-
-static inline bool tpg_g_interleaved(const struct tpg_data *tpg)
-{
-       return tpg->interleaved;
-}
-
-static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned plane)
-{
-       return tpg->twopixelsize[plane];
-}
-
-static inline unsigned tpg_hdiv(const struct tpg_data *tpg,
-                                 unsigned plane, unsigned x)
-{
-       return ((x / tpg->hdownsampling[plane]) & tpg->hmask[plane]) *
-               tpg->twopixelsize[plane] / 2;
-}
-
-static inline unsigned tpg_hscale(const struct tpg_data *tpg, unsigned x)
-{
-       return (x * tpg->scaled_width) / tpg->src_width;
-}
-
-static inline unsigned tpg_hscale_div(const struct tpg_data *tpg,
-                                     unsigned plane, unsigned x)
-{
-       return tpg_hdiv(tpg, plane, tpg_hscale(tpg, x));
-}
-
-static inline unsigned tpg_g_bytesperline(const struct tpg_data *tpg, unsigned plane)
-{
-       return tpg->bytesperline[plane];
-}
-
-static inline void tpg_s_bytesperline(struct tpg_data *tpg, unsigned plane, unsigned bpl)
-{
-       unsigned p;
-
-       if (tpg->buffers > 1) {
-               tpg->bytesperline[plane] = bpl;
-               return;
-       }
-
-       for (p = 0; p < tpg_g_planes(tpg); p++) {
-               unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0];
-
-               tpg->bytesperline[p] = plane_w / tpg->hdownsampling[p];
-       }
-       if (tpg_g_interleaved(tpg))
-               tpg->bytesperline[1] = tpg->bytesperline[0];
-}
-
-
-static inline unsigned tpg_g_line_width(const struct tpg_data *tpg, unsigned plane)
-{
-       unsigned w = 0;
-       unsigned p;
-
-       if (tpg->buffers > 1)
-               return tpg_g_bytesperline(tpg, plane);
-       for (p = 0; p < tpg_g_planes(tpg); p++) {
-               unsigned plane_w = tpg_g_bytesperline(tpg, p);
-
-               w += plane_w / tpg->vdownsampling[p];
-       }
-       return w;
-}
-
-static inline unsigned tpg_calc_line_width(const struct tpg_data *tpg,
-                                          unsigned plane, unsigned bpl)
-{
-       unsigned w = 0;
-       unsigned p;
-
-       if (tpg->buffers > 1)
-               return bpl;
-       for (p = 0; p < tpg_g_planes(tpg); p++) {
-               unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0];
-
-               plane_w /= tpg->hdownsampling[p];
-               w += plane_w / tpg->vdownsampling[p];
-       }
-       return w;
-}
-
-static inline unsigned tpg_calc_plane_size(const struct tpg_data *tpg, unsigned plane)
-{
-       if (plane >= tpg_g_planes(tpg))
-               return 0;
-
-       return tpg_g_bytesperline(tpg, plane) * tpg->buf_height /
-              tpg->vdownsampling[plane];
-}
-
-static inline void tpg_s_buf_height(struct tpg_data *tpg, unsigned h)
-{
-       tpg->buf_height = h;
-}
-
-static inline void tpg_s_field(struct tpg_data *tpg, unsigned field, bool alternate)
-{
-       tpg->field = field;
-       tpg->field_alternate = alternate;
-}
-
-static inline void tpg_s_perc_fill(struct tpg_data *tpg,
-                                     unsigned perc_fill)
-{
-       tpg->perc_fill = perc_fill;
-}
-
-static inline unsigned tpg_g_perc_fill(const struct tpg_data *tpg)
-{
-       return tpg->perc_fill;
-}
-
-static inline void tpg_s_perc_fill_blank(struct tpg_data *tpg,
-                                        bool perc_fill_blank)
-{
-       tpg->perc_fill_blank = perc_fill_blank;
-}
-
-static inline void tpg_s_video_aspect(struct tpg_data *tpg,
-                                       enum tpg_video_aspect vid_aspect)
-{
-       if (tpg->vid_aspect == vid_aspect)
-               return;
-       tpg->vid_aspect = vid_aspect;
-       tpg->recalc_square_border = true;
-}
-
-static inline enum tpg_video_aspect tpg_g_video_aspect(const struct tpg_data *tpg)
-{
-       return tpg->vid_aspect;
-}
-
-static inline void tpg_s_pixel_aspect(struct tpg_data *tpg,
-                                       enum tpg_pixel_aspect pix_aspect)
-{
-       if (tpg->pix_aspect == pix_aspect)
-               return;
-       tpg->pix_aspect = pix_aspect;
-       tpg->recalc_square_border = true;
-}
-
-static inline void tpg_s_show_border(struct tpg_data *tpg,
-                                       bool show_border)
-{
-       tpg->show_border = show_border;
-}
-
-static inline void tpg_s_show_square(struct tpg_data *tpg,
-                                       bool show_square)
-{
-       tpg->show_square = show_square;
-}
-
-static inline void tpg_s_insert_sav(struct tpg_data *tpg, bool insert_sav)
-{
-       tpg->insert_sav = insert_sav;
-}
-
-static inline void tpg_s_insert_eav(struct tpg_data *tpg, bool insert_eav)
-{
-       tpg->insert_eav = insert_eav;
-}
-
-void tpg_update_mv_step(struct tpg_data *tpg);
-
-static inline void tpg_s_mv_hor_mode(struct tpg_data *tpg,
-                               enum tpg_move_mode mv_hor_mode)
-{
-       tpg->mv_hor_mode = mv_hor_mode;
-       tpg_update_mv_step(tpg);
-}
-
-static inline void tpg_s_mv_vert_mode(struct tpg_data *tpg,
-                               enum tpg_move_mode mv_vert_mode)
-{
-       tpg->mv_vert_mode = mv_vert_mode;
-       tpg_update_mv_step(tpg);
-}
-
-static inline void tpg_init_mv_count(struct tpg_data *tpg)
-{
-       tpg->mv_hor_count = tpg->mv_vert_count = 0;
-}
-
-static inline void tpg_update_mv_count(struct tpg_data *tpg, bool frame_is_field)
-{
-       tpg->mv_hor_count += tpg->mv_hor_step * (frame_is_field ? 1 : 2);
-       tpg->mv_vert_count += tpg->mv_vert_step * (frame_is_field ? 1 : 2);
-}
-
-static inline void tpg_s_hflip(struct tpg_data *tpg, bool hflip)
-{
-       if (tpg->hflip == hflip)
-               return;
-       tpg->hflip = hflip;
-       tpg_update_mv_step(tpg);
-       tpg->recalc_lines = true;
-}
-
-static inline bool tpg_g_hflip(const struct tpg_data *tpg)
-{
-       return tpg->hflip;
-}
-
-static inline void tpg_s_vflip(struct tpg_data *tpg, bool vflip)
-{
-       tpg->vflip = vflip;
-}
-
-static inline bool tpg_g_vflip(const struct tpg_data *tpg)
-{
-       return tpg->vflip;
-}
-
-static inline bool tpg_pattern_is_static(const struct tpg_data *tpg)
-{
-       return tpg->pattern != TPG_PAT_NOISE &&
-              tpg->mv_hor_mode == TPG_MOVE_NONE &&
-              tpg->mv_vert_mode == TPG_MOVE_NONE;
-}
-
-#endif
index b84f081..4f730f3 100644 (file)
@@ -26,6 +26,7 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-event.h>
 #include <media/v4l2-dv-timings.h>
+#include <media/v4l2-rect.h>
 
 #include "vivid-core.h"
 #include "vivid-vid-common.h"
@@ -590,16 +591,16 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv,
        } else {
                struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor };
 
-               rect_set_min_size(&r, &vivid_min_rect);
-               rect_set_max_size(&r, &vivid_max_rect);
+               v4l2_rect_set_min_size(&r, &vivid_min_rect);
+               v4l2_rect_set_max_size(&r, &vivid_max_rect);
                if (dev->has_scaler_cap && !dev->has_compose_cap) {
                        struct v4l2_rect max_r = { 0, 0, MAX_ZOOM * w, MAX_ZOOM * h };
 
-                       rect_set_max_size(&r, &max_r);
+                       v4l2_rect_set_max_size(&r, &max_r);
                } else if (!dev->has_scaler_cap && dev->has_crop_cap && !dev->has_compose_cap) {
-                       rect_set_max_size(&r, &dev->src_rect);
+                       v4l2_rect_set_max_size(&r, &dev->src_rect);
                } else if (!dev->has_scaler_cap && !dev->has_crop_cap) {
-                       rect_set_min_size(&r, &dev->src_rect);
+                       v4l2_rect_set_min_size(&r, &dev->src_rect);
                }
                mp->width = r.width;
                mp->height = r.height / factor;
@@ -668,7 +669,7 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv,
 
                if (dev->has_scaler_cap) {
                        if (dev->has_compose_cap)
-                               rect_map_inside(compose, &r);
+                               v4l2_rect_map_inside(compose, &r);
                        else
                                *compose = r;
                        if (dev->has_crop_cap && !dev->has_compose_cap) {
@@ -683,9 +684,9 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv,
                                        factor * r.height * MAX_ZOOM
                                };
 
-                               rect_set_min_size(crop, &min_r);
-                               rect_set_max_size(crop, &max_r);
-                               rect_map_inside(crop, &dev->crop_bounds_cap);
+                               v4l2_rect_set_min_size(crop, &min_r);
+                               v4l2_rect_set_max_size(crop, &max_r);
+                               v4l2_rect_map_inside(crop, &dev->crop_bounds_cap);
                        } else if (dev->has_crop_cap) {
                                struct v4l2_rect min_r = {
                                        0, 0,
@@ -698,27 +699,27 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv,
                                        factor * compose->height * MAX_ZOOM
                                };
 
-                               rect_set_min_size(crop, &min_r);
-                               rect_set_max_size(crop, &max_r);
-                               rect_map_inside(crop, &dev->crop_bounds_cap);
+                               v4l2_rect_set_min_size(crop, &min_r);
+                               v4l2_rect_set_max_size(crop, &max_r);
+                               v4l2_rect_map_inside(crop, &dev->crop_bounds_cap);
                        }
                } else if (dev->has_crop_cap && !dev->has_compose_cap) {
                        r.height *= factor;
-                       rect_set_size_to(crop, &r);
-                       rect_map_inside(crop, &dev->crop_bounds_cap);
+                       v4l2_rect_set_size_to(crop, &r);
+                       v4l2_rect_map_inside(crop, &dev->crop_bounds_cap);
                        r = *crop;
                        r.height /= factor;
-                       rect_set_size_to(compose, &r);
+                       v4l2_rect_set_size_to(compose, &r);
                } else if (!dev->has_crop_cap) {
-                       rect_map_inside(compose, &r);
+                       v4l2_rect_map_inside(compose, &r);
                } else {
                        r.height *= factor;
-                       rect_set_max_size(crop, &r);
-                       rect_map_inside(crop, &dev->crop_bounds_cap);
+                       v4l2_rect_set_max_size(crop, &r);
+                       v4l2_rect_map_inside(crop, &dev->crop_bounds_cap);
                        compose->top *= factor;
                        compose->height *= factor;
-                       rect_set_size_to(compose, crop);
-                       rect_map_inside(compose, &r);
+                       v4l2_rect_set_size_to(compose, crop);
+                       v4l2_rect_map_inside(compose, &r);
                        compose->top /= factor;
                        compose->height /= factor;
                }
@@ -735,9 +736,9 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv,
        } else {
                struct v4l2_rect r = { 0, 0, mp->width, mp->height };
 
-               rect_set_size_to(compose, &r);
+               v4l2_rect_set_size_to(compose, &r);
                r.height *= factor;
-               rect_set_size_to(crop, &r);
+               v4l2_rect_set_size_to(crop, &r);
        }
 
        dev->fmt_cap_rect.width = mp->width;
@@ -886,9 +887,9 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection
                ret = vivid_vid_adjust_sel(s->flags, &s->r);
                if (ret)
                        return ret;
-               rect_set_min_size(&s->r, &vivid_min_rect);
-               rect_set_max_size(&s->r, &dev->src_rect);
-               rect_map_inside(&s->r, &dev->crop_bounds_cap);
+               v4l2_rect_set_min_size(&s->r, &vivid_min_rect);
+               v4l2_rect_set_max_size(&s->r, &dev->src_rect);
+               v4l2_rect_map_inside(&s->r, &dev->crop_bounds_cap);
                s->r.top /= factor;
                s->r.height /= factor;
                if (dev->has_scaler_cap) {
@@ -904,36 +905,36 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection
                                s->r.height / MAX_ZOOM
                        };
 
-                       rect_set_min_size(&fmt, &min_rect);
+                       v4l2_rect_set_min_size(&fmt, &min_rect);
                        if (!dev->has_compose_cap)
-                               rect_set_max_size(&fmt, &max_rect);
-                       if (!rect_same_size(&dev->fmt_cap_rect, &fmt) &&
+                               v4l2_rect_set_max_size(&fmt, &max_rect);
+                       if (!v4l2_rect_same_size(&dev->fmt_cap_rect, &fmt) &&
                            vb2_is_busy(&dev->vb_vid_cap_q))
                                return -EBUSY;
                        if (dev->has_compose_cap) {
-                               rect_set_min_size(compose, &min_rect);
-                               rect_set_max_size(compose, &max_rect);
+                               v4l2_rect_set_min_size(compose, &min_rect);
+                               v4l2_rect_set_max_size(compose, &max_rect);
                        }
                        dev->fmt_cap_rect = fmt;
                        tpg_s_buf_height(&dev->tpg, fmt.height);
                } else if (dev->has_compose_cap) {
                        struct v4l2_rect fmt = dev->fmt_cap_rect;
 
-                       rect_set_min_size(&fmt, &s->r);
-                       if (!rect_same_size(&dev->fmt_cap_rect, &fmt) &&
+                       v4l2_rect_set_min_size(&fmt, &s->r);
+                       if (!v4l2_rect_same_size(&dev->fmt_cap_rect, &fmt) &&
                            vb2_is_busy(&dev->vb_vid_cap_q))
                                return -EBUSY;
                        dev->fmt_cap_rect = fmt;
                        tpg_s_buf_height(&dev->tpg, fmt.height);
-                       rect_set_size_to(compose, &s->r);
-                       rect_map_inside(compose, &dev->fmt_cap_rect);
+                       v4l2_rect_set_size_to(compose, &s->r);
+                       v4l2_rect_map_inside(compose, &dev->fmt_cap_rect);
                } else {
-                       if (!rect_same_size(&s->r, &dev->fmt_cap_rect) &&
+                       if (!v4l2_rect_same_size(&s->r, &dev->fmt_cap_rect) &&
                            vb2_is_busy(&dev->vb_vid_cap_q))
                                return -EBUSY;
-                       rect_set_size_to(&dev->fmt_cap_rect, &s->r);
-                       rect_set_size_to(compose, &s->r);
-                       rect_map_inside(compose, &dev->fmt_cap_rect);
+                       v4l2_rect_set_size_to(&dev->fmt_cap_rect, &s->r);
+                       v4l2_rect_set_size_to(compose, &s->r);
+                       v4l2_rect_map_inside(compose, &dev->fmt_cap_rect);
                        tpg_s_buf_height(&dev->tpg, dev->fmt_cap_rect.height);
                }
                s->r.top *= factor;
@@ -946,8 +947,8 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection
                ret = vivid_vid_adjust_sel(s->flags, &s->r);
                if (ret)
                        return ret;
-               rect_set_min_size(&s->r, &vivid_min_rect);
-               rect_set_max_size(&s->r, &dev->fmt_cap_rect);
+               v4l2_rect_set_min_size(&s->r, &vivid_min_rect);
+               v4l2_rect_set_max_size(&s->r, &dev->fmt_cap_rect);
                if (dev->has_scaler_cap) {
                        struct v4l2_rect max_rect = {
                                0, 0,
@@ -955,7 +956,7 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection
                                (dev->src_rect.height / factor) * MAX_ZOOM
                        };
 
-                       rect_set_max_size(&s->r, &max_rect);
+                       v4l2_rect_set_max_size(&s->r, &max_rect);
                        if (dev->has_crop_cap) {
                                struct v4l2_rect min_rect = {
                                        0, 0,
@@ -968,23 +969,23 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection
                                        (s->r.height * factor) * MAX_ZOOM
                                };
 
-                               rect_set_min_size(crop, &min_rect);
-                               rect_set_max_size(crop, &max_rect);
-                               rect_map_inside(crop, &dev->crop_bounds_cap);
+                               v4l2_rect_set_min_size(crop, &min_rect);
+                               v4l2_rect_set_max_size(crop, &max_rect);
+                               v4l2_rect_map_inside(crop, &dev->crop_bounds_cap);
                        }
                } else if (dev->has_crop_cap) {
                        s->r.top *= factor;
                        s->r.height *= factor;
-                       rect_set_max_size(&s->r, &dev->src_rect);
-                       rect_set_size_to(crop, &s->r);
-                       rect_map_inside(crop, &dev->crop_bounds_cap);
+                       v4l2_rect_set_max_size(&s->r, &dev->src_rect);
+                       v4l2_rect_set_size_to(crop, &s->r);
+                       v4l2_rect_map_inside(crop, &dev->crop_bounds_cap);
                        s->r.top /= factor;
                        s->r.height /= factor;
                } else {
-                       rect_set_size_to(&s->r, &dev->src_rect);
+                       v4l2_rect_set_size_to(&s->r, &dev->src_rect);
                        s->r.height /= factor;
                }
-               rect_map_inside(&s->r, &dev->fmt_cap_rect);
+               v4l2_rect_map_inside(&s->r, &dev->fmt_cap_rect);
                if (dev->bitmap_cap && (compose->width != s->r.width ||
                                        compose->height != s->r.height)) {
                        kfree(dev->bitmap_cap);
@@ -1124,7 +1125,7 @@ int vidioc_try_fmt_vid_overlay(struct file *file, void *priv,
                        for (j = i + 1; j < win->clipcount; j++) {
                                struct v4l2_rect *r2 = &dev->try_clips_cap[j].c;
 
-                               if (rect_overlap(r1, r2))
+                               if (v4l2_rect_overlap(r1, r2))
                                        return -EINVAL;
                        }
                }
index b0d4e3a..39ea228 100644 (file)
@@ -653,103 +653,6 @@ int fmt_sp2mp_func(struct file *file, void *priv,
        return ret;
 }
 
-/* v4l2_rect helper function: copy the width/height values */
-void rect_set_size_to(struct v4l2_rect *r, const struct v4l2_rect *size)
-{
-       r->width = size->width;
-       r->height = size->height;
-}
-
-/* v4l2_rect helper function: width and height of r should be >= min_size */
-void rect_set_min_size(struct v4l2_rect *r, const struct v4l2_rect *min_size)
-{
-       if (r->width < min_size->width)
-               r->width = min_size->width;
-       if (r->height < min_size->height)
-               r->height = min_size->height;
-}
-
-/* v4l2_rect helper function: width and height of r should be <= max_size */
-void rect_set_max_size(struct v4l2_rect *r, const struct v4l2_rect *max_size)
-{
-       if (r->width > max_size->width)
-               r->width = max_size->width;
-       if (r->height > max_size->height)
-               r->height = max_size->height;
-}
-
-/* v4l2_rect helper function: r should be inside boundary */
-void rect_map_inside(struct v4l2_rect *r, const struct v4l2_rect *boundary)
-{
-       rect_set_max_size(r, boundary);
-       if (r->left < boundary->left)
-               r->left = boundary->left;
-       if (r->top < boundary->top)
-               r->top = boundary->top;
-       if (r->left + r->width > boundary->width)
-               r->left = boundary->width - r->width;
-       if (r->top + r->height > boundary->height)
-               r->top = boundary->height - r->height;
-}
-
-/* v4l2_rect helper function: return true if r1 has the same size as r2 */
-bool rect_same_size(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
-{
-       return r1->width == r2->width && r1->height == r2->height;
-}
-
-/* v4l2_rect helper function: calculate the intersection of two rects */
-struct v4l2_rect rect_intersect(const struct v4l2_rect *a, const struct v4l2_rect *b)
-{
-       struct v4l2_rect r;
-       int right, bottom;
-
-       r.top = max(a->top, b->top);
-       r.left = max(a->left, b->left);
-       bottom = min(a->top + a->height, b->top + b->height);
-       right = min(a->left + a->width, b->left + b->width);
-       r.height = max(0, bottom - r.top);
-       r.width = max(0, right - r.left);
-       return r;
-}
-
-/*
- * v4l2_rect helper function: scale rect r by to->width / from->width and
- * to->height / from->height.
- */
-void rect_scale(struct v4l2_rect *r, const struct v4l2_rect *from,
-                                    const struct v4l2_rect *to)
-{
-       if (from->width == 0 || from->height == 0) {
-               r->left = r->top = r->width = r->height = 0;
-               return;
-       }
-       r->left = (((r->left - from->left) * to->width) / from->width) & ~1;
-       r->width = ((r->width * to->width) / from->width) & ~1;
-       r->top = ((r->top - from->top) * to->height) / from->height;
-       r->height = (r->height * to->height) / from->height;
-}
-
-bool rect_overlap(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
-{
-       /*
-        * IF the left side of r1 is to the right of the right side of r2 OR
-        *    the left side of r2 is to the right of the right side of r1 THEN
-        * they do not overlap.
-        */
-       if (r1->left >= r2->left + r2->width ||
-           r2->left >= r1->left + r1->width)
-               return false;
-       /*
-        * IF the top side of r1 is below the bottom of r2 OR
-        *    the top side of r2 is below the bottom of r1 THEN
-        * they do not overlap.
-        */
-       if (r1->top >= r2->top + r2->height ||
-           r2->top >= r1->top + r1->height)
-               return false;
-       return true;
-}
 int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r)
 {
        unsigned w = r->width;
index 3ec4fa8..4b6175e 100644 (file)
@@ -37,15 +37,6 @@ const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat)
 bool vivid_vid_can_loop(struct vivid_dev *dev);
 void vivid_send_source_change(struct vivid_dev *dev, unsigned type);
 
-bool rect_overlap(const struct v4l2_rect *r1, const struct v4l2_rect *r2);
-void rect_set_size_to(struct v4l2_rect *r, const struct v4l2_rect *size);
-void rect_set_min_size(struct v4l2_rect *r, const struct v4l2_rect *min_size);
-void rect_set_max_size(struct v4l2_rect *r, const struct v4l2_rect *max_size);
-void rect_map_inside(struct v4l2_rect *r, const struct v4l2_rect *boundary);
-bool rect_same_size(const struct v4l2_rect *r1, const struct v4l2_rect *r2);
-struct v4l2_rect rect_intersect(const struct v4l2_rect *a, const struct v4l2_rect *b);
-void rect_scale(struct v4l2_rect *r, const struct v4l2_rect *from,
-                                    const struct v4l2_rect *to);
 int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r);
 
 int vivid_enum_fmt_vid(struct file *file, void  *priv, struct v4l2_fmtdesc *f);
index 64e4d66..f92f449 100644 (file)
@@ -25,6 +25,7 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-event.h>
 #include <media/v4l2-dv-timings.h>
+#include <media/v4l2-rect.h>
 
 #include "vivid-core.h"
 #include "vivid-vid-common.h"
@@ -376,16 +377,16 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv,
        } else {
                struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor };
 
-               rect_set_min_size(&r, &vivid_min_rect);
-               rect_set_max_size(&r, &vivid_max_rect);
+               v4l2_rect_set_min_size(&r, &vivid_min_rect);
+               v4l2_rect_set_max_size(&r, &vivid_max_rect);
                if (dev->has_scaler_out && !dev->has_crop_out) {
                        struct v4l2_rect max_r = { 0, 0, MAX_ZOOM * w, MAX_ZOOM * h };
 
-                       rect_set_max_size(&r, &max_r);
+                       v4l2_rect_set_max_size(&r, &max_r);
                } else if (!dev->has_scaler_out && dev->has_compose_out && !dev->has_crop_out) {
-                       rect_set_max_size(&r, &dev->sink_rect);
+                       v4l2_rect_set_max_size(&r, &dev->sink_rect);
                } else if (!dev->has_scaler_out && !dev->has_compose_out) {
-                       rect_set_min_size(&r, &dev->sink_rect);
+                       v4l2_rect_set_min_size(&r, &dev->sink_rect);
                }
                mp->width = r.width;
                mp->height = r.height / factor;
@@ -473,7 +474,7 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv,
 
                if (dev->has_scaler_out) {
                        if (dev->has_crop_out)
-                               rect_map_inside(crop, &r);
+                               v4l2_rect_map_inside(crop, &r);
                        else
                                *crop = r;
                        if (dev->has_compose_out && !dev->has_crop_out) {
@@ -488,9 +489,9 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv,
                                        factor * r.height * MAX_ZOOM
                                };
 
-                               rect_set_min_size(compose, &min_r);
-                               rect_set_max_size(compose, &max_r);
-                               rect_map_inside(compose, &dev->compose_bounds_out);
+                               v4l2_rect_set_min_size(compose, &min_r);
+                               v4l2_rect_set_max_size(compose, &max_r);
+                               v4l2_rect_map_inside(compose, &dev->compose_bounds_out);
                        } else if (dev->has_compose_out) {
                                struct v4l2_rect min_r = {
                                        0, 0,
@@ -503,36 +504,36 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv,
                                        factor * crop->height * MAX_ZOOM
                                };
 
-                               rect_set_min_size(compose, &min_r);
-                               rect_set_max_size(compose, &max_r);
-                               rect_map_inside(compose, &dev->compose_bounds_out);
+                               v4l2_rect_set_min_size(compose, &min_r);
+                               v4l2_rect_set_max_size(compose, &max_r);
+                               v4l2_rect_map_inside(compose, &dev->compose_bounds_out);
                        }
                } else if (dev->has_compose_out && !dev->has_crop_out) {
-                       rect_set_size_to(crop, &r);
+                       v4l2_rect_set_size_to(crop, &r);
                        r.height *= factor;
-                       rect_set_size_to(compose, &r);
-                       rect_map_inside(compose, &dev->compose_bounds_out);
+                       v4l2_rect_set_size_to(compose, &r);
+                       v4l2_rect_map_inside(compose, &dev->compose_bounds_out);
                } else if (!dev->has_compose_out) {
-                       rect_map_inside(crop, &r);
+                       v4l2_rect_map_inside(crop, &r);
                        r.height /= factor;
-                       rect_set_size_to(compose, &r);
+                       v4l2_rect_set_size_to(compose, &r);
                } else {
                        r.height *= factor;
-                       rect_set_max_size(compose, &r);
-                       rect_map_inside(compose, &dev->compose_bounds_out);
+                       v4l2_rect_set_max_size(compose, &r);
+                       v4l2_rect_map_inside(compose, &dev->compose_bounds_out);
                        crop->top *= factor;
                        crop->height *= factor;
-                       rect_set_size_to(crop, compose);
-                       rect_map_inside(crop, &r);
+                       v4l2_rect_set_size_to(crop, compose);
+                       v4l2_rect_map_inside(crop, &r);
                        crop->top /= factor;
                        crop->height /= factor;
                }
        } else {
                struct v4l2_rect r = { 0, 0, mp->width, mp->height };
 
-               rect_set_size_to(crop, &r);
+               v4l2_rect_set_size_to(crop, &r);
                r.height /= factor;
-               rect_set_size_to(compose, &r);
+               v4l2_rect_set_size_to(compose, &r);
        }
 
        dev->fmt_out_rect.width = mp->width;
@@ -683,8 +684,8 @@ int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection
                ret = vivid_vid_adjust_sel(s->flags, &s->r);
                if (ret)
                        return ret;
-               rect_set_min_size(&s->r, &vivid_min_rect);
-               rect_set_max_size(&s->r, &dev->fmt_out_rect);
+               v4l2_rect_set_min_size(&s->r, &vivid_min_rect);
+               v4l2_rect_set_max_size(&s->r, &dev->fmt_out_rect);
                if (dev->has_scaler_out) {
                        struct v4l2_rect max_rect = {
                                0, 0,
@@ -692,7 +693,7 @@ int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection
                                (dev->sink_rect.height / factor) * MAX_ZOOM
                        };
 
-                       rect_set_max_size(&s->r, &max_rect);
+                       v4l2_rect_set_max_size(&s->r, &max_rect);
                        if (dev->has_compose_out) {
                                struct v4l2_rect min_rect = {
                                        0, 0,
@@ -705,23 +706,23 @@ int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection
                                        (s->r.height * factor) * MAX_ZOOM
                                };
 
-                               rect_set_min_size(compose, &min_rect);
-                               rect_set_max_size(compose, &max_rect);
-                               rect_map_inside(compose, &dev->compose_bounds_out);
+                               v4l2_rect_set_min_size(compose, &min_rect);
+                               v4l2_rect_set_max_size(compose, &max_rect);
+                               v4l2_rect_map_inside(compose, &dev->compose_bounds_out);
                        }
                } else if (dev->has_compose_out) {
                        s->r.top *= factor;
                        s->r.height *= factor;
-                       rect_set_max_size(&s->r, &dev->sink_rect);
-                       rect_set_size_to(compose, &s->r);
-                       rect_map_inside(compose, &dev->compose_bounds_out);
+                       v4l2_rect_set_max_size(&s->r, &dev->sink_rect);
+                       v4l2_rect_set_size_to(compose, &s->r);
+                       v4l2_rect_map_inside(compose, &dev->compose_bounds_out);
                        s->r.top /= factor;
                        s->r.height /= factor;
                } else {
-                       rect_set_size_to(&s->r, &dev->sink_rect);
+                       v4l2_rect_set_size_to(&s->r, &dev->sink_rect);
                        s->r.height /= factor;
                }
-               rect_map_inside(&s->r, &dev->fmt_out_rect);
+               v4l2_rect_map_inside(&s->r, &dev->fmt_out_rect);
                *crop = s->r;
                break;
        case V4L2_SEL_TGT_COMPOSE:
@@ -730,9 +731,9 @@ int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection
                ret = vivid_vid_adjust_sel(s->flags, &s->r);
                if (ret)
                        return ret;
-               rect_set_min_size(&s->r, &vivid_min_rect);
-               rect_set_max_size(&s->r, &dev->sink_rect);
-               rect_map_inside(&s->r, &dev->compose_bounds_out);
+               v4l2_rect_set_min_size(&s->r, &vivid_min_rect);
+               v4l2_rect_set_max_size(&s->r, &dev->sink_rect);
+               v4l2_rect_map_inside(&s->r, &dev->compose_bounds_out);
                s->r.top /= factor;
                s->r.height /= factor;
                if (dev->has_scaler_out) {
@@ -748,35 +749,35 @@ int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection
                                s->r.height / MAX_ZOOM
                        };
 
-                       rect_set_min_size(&fmt, &min_rect);
+                       v4l2_rect_set_min_size(&fmt, &min_rect);
                        if (!dev->has_crop_out)
-                               rect_set_max_size(&fmt, &max_rect);
-                       if (!rect_same_size(&dev->fmt_out_rect, &fmt) &&
+                               v4l2_rect_set_max_size(&fmt, &max_rect);
+                       if (!v4l2_rect_same_size(&dev->fmt_out_rect, &fmt) &&
                            vb2_is_busy(&dev->vb_vid_out_q))
                                return -EBUSY;
                        if (dev->has_crop_out) {
-                               rect_set_min_size(crop, &min_rect);
-                               rect_set_max_size(crop, &max_rect);
+                               v4l2_rect_set_min_size(crop, &min_rect);
+                               v4l2_rect_set_max_size(crop, &max_rect);
                        }
                        dev->fmt_out_rect = fmt;
                } else if (dev->has_crop_out) {
                        struct v4l2_rect fmt = dev->fmt_out_rect;
 
-                       rect_set_min_size(&fmt, &s->r);
-                       if (!rect_same_size(&dev->fmt_out_rect, &fmt) &&
+                       v4l2_rect_set_min_size(&fmt, &s->r);
+                       if (!v4l2_rect_same_size(&dev->fmt_out_rect, &fmt) &&
                            vb2_is_busy(&dev->vb_vid_out_q))
                                return -EBUSY;
                        dev->fmt_out_rect = fmt;
-                       rect_set_size_to(crop, &s->r);
-                       rect_map_inside(crop, &dev->fmt_out_rect);
+                       v4l2_rect_set_size_to(crop, &s->r);
+                       v4l2_rect_map_inside(crop, &dev->fmt_out_rect);
                } else {
-                       if (!rect_same_size(&s->r, &dev->fmt_out_rect) &&
+                       if (!v4l2_rect_same_size(&s->r, &dev->fmt_out_rect) &&
                            vb2_is_busy(&dev->vb_vid_out_q))
                                return -EBUSY;
-                       rect_set_size_to(&dev->fmt_out_rect, &s->r);
-                       rect_set_size_to(crop, &s->r);
+                       v4l2_rect_set_size_to(&dev->fmt_out_rect, &s->r);
+                       v4l2_rect_set_size_to(crop, &s->r);
                        crop->height /= factor;
-                       rect_map_inside(crop, &dev->fmt_out_rect);
+                       v4l2_rect_map_inside(crop, &dev->fmt_out_rect);
                }
                s->r.top *= factor;
                s->r.height *= factor;
@@ -901,7 +902,7 @@ int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv,
                        for (j = i + 1; j < win->clipcount; j++) {
                                struct v4l2_rect *r2 = &dev->try_clips_out[j].c;
 
-                               if (rect_overlap(r1, r2))
+                               if (v4l2_rect_overlap(r1, r2))
                                        return -EINVAL;
                        }
                }
index 910d6b8..46738b6 100644 (file)
@@ -26,7 +26,6 @@
 struct clk;
 struct device;
 
-struct vsp1_dl;
 struct vsp1_drm;
 struct vsp1_entity;
 struct vsp1_platform_data;
@@ -49,6 +48,7 @@ struct vsp1_uds;
 
 struct vsp1_device_info {
        u32 version;
+       unsigned int gen;
        unsigned int features;
        unsigned int rpf_count;
        unsigned int uds_count;
@@ -85,8 +85,6 @@ struct vsp1_device {
        struct media_entity_operations media_ops;
 
        struct vsp1_drm *drm;
-
-       bool use_dl;
 };
 
 int vsp1_device_get(struct vsp1_device *vsp1);
@@ -104,14 +102,4 @@ static inline void vsp1_write(struct vsp1_device *vsp1, u32 reg, u32 data)
        iowrite32(data, vsp1->mmio + reg);
 }
 
-#include "vsp1_dl.h"
-
-static inline void vsp1_mod_write(struct vsp1_entity *e, u32 reg, u32 data)
-{
-       if (e->vsp1->use_dl)
-               vsp1_dl_add(e, reg, data);
-       else
-               vsp1_write(e->vsp1, reg, data);
-}
-
 #endif /* __VSP1_H__ */
index cb0dbc1..b1068c0 100644 (file)
@@ -18,6 +18,8 @@
 
 #include "vsp1.h"
 #include "vsp1_bru.h"
+#include "vsp1_dl.h"
+#include "vsp1_pipe.h"
 #include "vsp1_rwpf.h"
 #include "vsp1_video.h"
 
  * Device Access
  */
 
-static inline void vsp1_bru_write(struct vsp1_bru *bru, u32 reg, u32 data)
+static inline void vsp1_bru_write(struct vsp1_bru *bru, struct vsp1_dl_list *dl,
+                                 u32 reg, u32 data)
 {
-       vsp1_mod_write(&bru->entity, reg, data);
+       vsp1_dl_list_write(dl, reg, data);
 }
 
 /* -----------------------------------------------------------------------------
@@ -42,13 +45,9 @@ static int bru_s_ctrl(struct v4l2_ctrl *ctrl)
        struct vsp1_bru *bru =
                container_of(ctrl->handler, struct vsp1_bru, ctrls);
 
-       if (!vsp1_entity_is_streaming(&bru->entity))
-               return 0;
-
        switch (ctrl->id) {
        case V4L2_CID_BG_COLOR:
-               vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL, ctrl->val |
-                              (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT));
+               bru->bgcolor = ctrl->val;
                break;
        }
 
@@ -60,116 +59,7 @@ static const struct v4l2_ctrl_ops bru_ctrl_ops = {
 };
 
 /* -----------------------------------------------------------------------------
- * V4L2 Subdevice Core Operations
- */
-
-static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
-{
-       struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity);
-       struct vsp1_bru *bru = to_bru(subdev);
-       struct v4l2_mbus_framefmt *format;
-       unsigned int flags;
-       unsigned int i;
-       int ret;
-
-       ret = vsp1_entity_set_streaming(&bru->entity, enable);
-       if (ret < 0)
-               return ret;
-
-       if (!enable)
-               return 0;
-
-       format = &bru->entity.formats[bru->entity.source_pad];
-
-       /* The hardware is extremely flexible but we have no userspace API to
-        * expose all the parameters, nor is it clear whether we would have use
-        * cases for all the supported modes. Let's just harcode the parameters
-        * to sane default values for now.
-        */
-
-       /* Disable dithering and enable color data normalization unless the
-        * format at the pipeline output is premultiplied.
-        */
-       flags = pipe->output ? pipe->output->format.flags : 0;
-       vsp1_bru_write(bru, VI6_BRU_INCTRL,
-                      flags & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA ?
-                      0 : VI6_BRU_INCTRL_NRM);
-
-       /* Set the background position to cover the whole output image. */
-       vsp1_bru_write(bru, VI6_BRU_VIRRPF_SIZE,
-                      (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) |
-                      (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT));
-       vsp1_bru_write(bru, VI6_BRU_VIRRPF_LOC, 0);
-
-       /* Route BRU input 1 as SRC input to the ROP unit and configure the ROP
-        * unit with a NOP operation to make BRU input 1 available as the
-        * Blend/ROP unit B SRC input.
-        */
-       vsp1_bru_write(bru, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) |
-                      VI6_BRU_ROP_CROP(VI6_ROP_NOP) |
-                      VI6_BRU_ROP_AROP(VI6_ROP_NOP));
-
-       for (i = 0; i < bru->entity.source_pad; ++i) {
-               bool premultiplied = false;
-               u32 ctrl = 0;
-
-               /* Configure all Blend/ROP units corresponding to an enabled BRU
-                * input for alpha blending. Blend/ROP units corresponding to
-                * disabled BRU inputs are used in ROP NOP mode to ignore the
-                * SRC input.
-                */
-               if (bru->inputs[i].rpf) {
-                       ctrl |= VI6_BRU_CTRL_RBC;
-
-                       premultiplied = bru->inputs[i].rpf->format.flags
-                                     & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA;
-               } else {
-                       ctrl |= VI6_BRU_CTRL_CROP(VI6_ROP_NOP)
-                            |  VI6_BRU_CTRL_AROP(VI6_ROP_NOP);
-               }
-
-               /* Select the virtual RPF as the Blend/ROP unit A DST input to
-                * serve as a background color.
-                */
-               if (i == 0)
-                       ctrl |= VI6_BRU_CTRL_DSTSEL_VRPF;
-
-               /* Route BRU inputs 0 to 3 as SRC inputs to Blend/ROP units A to
-                * D in that order. The Blend/ROP unit B SRC is hardwired to the
-                * ROP unit output, the corresponding register bits must be set
-                * to 0.
-                */
-               if (i != 1)
-                       ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i);
-
-               vsp1_bru_write(bru, VI6_BRU_CTRL(i), ctrl);
-
-               /* Harcode the blending formula to
-                *
-                *      DSTc = DSTc * (1 - SRCa) + SRCc * SRCa
-                *      DSTa = DSTa * (1 - SRCa) + SRCa
-                *
-                * when the SRC input isn't premultiplied, and to
-                *
-                *      DSTc = DSTc * (1 - SRCa) + SRCc
-                *      DSTa = DSTa * (1 - SRCa) + SRCa
-                *
-                * otherwise.
-                */
-               vsp1_bru_write(bru, VI6_BRU_BLD(i),
-                              VI6_BRU_BLD_CCMDX_255_SRC_A |
-                              (premultiplied ? VI6_BRU_BLD_CCMDY_COEFY :
-                                               VI6_BRU_BLD_CCMDY_SRC_A) |
-                              VI6_BRU_BLD_ACMDX_255_SRC_A |
-                              VI6_BRU_BLD_ACMDY_COEFY |
-                              (0xff << VI6_BRU_BLD_COEFY_SHIFT));
-       }
-
-       return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Pad Operations
+ * V4L2 Subdevice Operations
  */
 
 /*
@@ -186,24 +76,9 @@ static int bru_enum_mbus_code(struct v4l2_subdev *subdev,
                MEDIA_BUS_FMT_ARGB8888_1X32,
                MEDIA_BUS_FMT_AYUV8_1X32,
        };
-       struct vsp1_bru *bru = to_bru(subdev);
-       struct v4l2_mbus_framefmt *format;
-
-       if (code->pad == BRU_PAD_SINK(0)) {
-               if (code->index >= ARRAY_SIZE(codes))
-                       return -EINVAL;
-
-               code->code = codes[code->index];
-       } else {
-               if (code->index)
-                       return -EINVAL;
-
-               format = vsp1_entity_get_pad_format(&bru->entity, cfg,
-                                                   BRU_PAD_SINK(0), code->which);
-               code->code = format->code;
-       }
 
-       return 0;
+       return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes,
+                                         ARRAY_SIZE(codes));
 }
 
 static int bru_enum_frame_size(struct v4l2_subdev *subdev,
@@ -227,32 +102,14 @@ static int bru_enum_frame_size(struct v4l2_subdev *subdev,
 
 static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru,
                                         struct v4l2_subdev_pad_config *cfg,
-                                        unsigned int pad, u32 which)
-{
-       switch (which) {
-       case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_crop(&bru->entity.subdev, cfg, pad);
-       case V4L2_SUBDEV_FORMAT_ACTIVE:
-               return &bru->inputs[pad].compose;
-       default:
-               return NULL;
-       }
-}
-
-static int bru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
-                         struct v4l2_subdev_format *fmt)
+                                        unsigned int pad)
 {
-       struct vsp1_bru *bru = to_bru(subdev);
-
-       fmt->format = *vsp1_entity_get_pad_format(&bru->entity, cfg, fmt->pad,
-                                                 fmt->which);
-
-       return 0;
+       return v4l2_subdev_get_try_compose(&bru->entity.subdev, cfg, pad);
 }
 
-static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_pad_config *cfg,
-                          unsigned int pad, struct v4l2_mbus_framefmt *fmt,
-                          enum v4l2_subdev_format_whence which)
+static void bru_try_format(struct vsp1_bru *bru,
+                          struct v4l2_subdev_pad_config *config,
+                          unsigned int pad, struct v4l2_mbus_framefmt *fmt)
 {
        struct v4l2_mbus_framefmt *format;
 
@@ -266,8 +123,8 @@ static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_pad_config *
 
        default:
                /* The BRU can't perform format conversion. */
-               format = vsp1_entity_get_pad_format(&bru->entity, cfg,
-                                                   BRU_PAD_SINK(0), which);
+               format = vsp1_entity_get_pad_format(&bru->entity, config,
+                                                   BRU_PAD_SINK(0));
                fmt->code = format->code;
                break;
        }
@@ -278,23 +135,28 @@ static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_pad_config *
        fmt->colorspace = V4L2_COLORSPACE_SRGB;
 }
 
-static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int bru_set_format(struct v4l2_subdev *subdev,
+                         struct v4l2_subdev_pad_config *cfg,
                          struct v4l2_subdev_format *fmt)
 {
        struct vsp1_bru *bru = to_bru(subdev);
+       struct v4l2_subdev_pad_config *config;
        struct v4l2_mbus_framefmt *format;
 
-       bru_try_format(bru, cfg, fmt->pad, &fmt->format, fmt->which);
+       config = vsp1_entity_get_pad_config(&bru->entity, cfg, fmt->which);
+       if (!config)
+               return -EINVAL;
+
+       bru_try_format(bru, config, fmt->pad, &fmt->format);
 
-       format = vsp1_entity_get_pad_format(&bru->entity, cfg, fmt->pad,
-                                           fmt->which);
+       format = vsp1_entity_get_pad_format(&bru->entity, config, fmt->pad);
        *format = fmt->format;
 
        /* Reset the compose rectangle */
        if (fmt->pad != bru->entity.source_pad) {
                struct v4l2_rect *compose;
 
-               compose = bru_get_compose(bru, cfg, fmt->pad, fmt->which);
+               compose = bru_get_compose(bru, config, fmt->pad);
                compose->left = 0;
                compose->top = 0;
                compose->width = format->width;
@@ -306,8 +168,8 @@ static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con
                unsigned int i;
 
                for (i = 0; i <= bru->entity.source_pad; ++i) {
-                       format = vsp1_entity_get_pad_format(&bru->entity, cfg,
-                                                           i, fmt->which);
+                       format = vsp1_entity_get_pad_format(&bru->entity,
+                                                           config, i);
                        format->code = fmt->format.code;
                }
        }
@@ -320,6 +182,7 @@ static int bru_get_selection(struct v4l2_subdev *subdev,
                             struct v4l2_subdev_selection *sel)
 {
        struct vsp1_bru *bru = to_bru(subdev);
+       struct v4l2_subdev_pad_config *config;
 
        if (sel->pad == bru->entity.source_pad)
                return -EINVAL;
@@ -333,7 +196,12 @@ static int bru_get_selection(struct v4l2_subdev *subdev,
                return 0;
 
        case V4L2_SEL_TGT_COMPOSE:
-               sel->r = *bru_get_compose(bru, cfg, sel->pad, sel->which);
+               config = vsp1_entity_get_pad_config(&bru->entity, cfg,
+                                                   sel->which);
+               if (!config)
+                       return -EINVAL;
+
+               sel->r = *bru_get_compose(bru, config, sel->pad);
                return 0;
 
        default:
@@ -346,6 +214,7 @@ static int bru_set_selection(struct v4l2_subdev *subdev,
                             struct v4l2_subdev_selection *sel)
 {
        struct vsp1_bru *bru = to_bru(subdev);
+       struct v4l2_subdev_pad_config *config;
        struct v4l2_mbus_framefmt *format;
        struct v4l2_rect *compose;
 
@@ -355,57 +224,161 @@ static int bru_set_selection(struct v4l2_subdev *subdev,
        if (sel->target != V4L2_SEL_TGT_COMPOSE)
                return -EINVAL;
 
+       config = vsp1_entity_get_pad_config(&bru->entity, cfg, sel->which);
+       if (!config)
+               return -EINVAL;
+
        /* The compose rectangle top left corner must be inside the output
         * frame.
         */
-       format = vsp1_entity_get_pad_format(&bru->entity, cfg,
-                                           bru->entity.source_pad, sel->which);
+       format = vsp1_entity_get_pad_format(&bru->entity, config,
+                                           bru->entity.source_pad);
        sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1);
        sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1);
 
        /* Scaling isn't supported, the compose rectangle size must be identical
         * to the sink format size.
         */
-       format = vsp1_entity_get_pad_format(&bru->entity, cfg, sel->pad,
-                                           sel->which);
+       format = vsp1_entity_get_pad_format(&bru->entity, config, sel->pad);
        sel->r.width = format->width;
        sel->r.height = format->height;
 
-       compose = bru_get_compose(bru, cfg, sel->pad, sel->which);
+       compose = bru_get_compose(bru, config, sel->pad);
        *compose = sel->r;
 
        return 0;
 }
 
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Operations
- */
-
-static struct v4l2_subdev_video_ops bru_video_ops = {
-       .s_stream = bru_s_stream,
-};
-
 static struct v4l2_subdev_pad_ops bru_pad_ops = {
+       .init_cfg = vsp1_entity_init_cfg,
        .enum_mbus_code = bru_enum_mbus_code,
        .enum_frame_size = bru_enum_frame_size,
-       .get_fmt = bru_get_format,
+       .get_fmt = vsp1_subdev_get_pad_format,
        .set_fmt = bru_set_format,
        .get_selection = bru_get_selection,
        .set_selection = bru_set_selection,
 };
 
 static struct v4l2_subdev_ops bru_ops = {
-       .video  = &bru_video_ops,
        .pad    = &bru_pad_ops,
 };
 
+/* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
+
+static void bru_configure(struct vsp1_entity *entity,
+                         struct vsp1_pipeline *pipe,
+                         struct vsp1_dl_list *dl)
+{
+       struct vsp1_bru *bru = to_bru(&entity->subdev);
+       struct v4l2_mbus_framefmt *format;
+       unsigned int flags;
+       unsigned int i;
+
+       format = vsp1_entity_get_pad_format(&bru->entity, bru->entity.config,
+                                           bru->entity.source_pad);
+
+       /* The hardware is extremely flexible but we have no userspace API to
+        * expose all the parameters, nor is it clear whether we would have use
+        * cases for all the supported modes. Let's just harcode the parameters
+        * to sane default values for now.
+        */
+
+       /* Disable dithering and enable color data normalization unless the
+        * format at the pipeline output is premultiplied.
+        */
+       flags = pipe->output ? pipe->output->format.flags : 0;
+       vsp1_bru_write(bru, dl, VI6_BRU_INCTRL,
+                      flags & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA ?
+                      0 : VI6_BRU_INCTRL_NRM);
+
+       /* Set the background position to cover the whole output image and
+        * configure its color.
+        */
+       vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_SIZE,
+                      (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) |
+                      (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT));
+       vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_LOC, 0);
+
+       vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_COL, bru->bgcolor |
+                      (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT));
+
+       /* Route BRU input 1 as SRC input to the ROP unit and configure the ROP
+        * unit with a NOP operation to make BRU input 1 available as the
+        * Blend/ROP unit B SRC input.
+        */
+       vsp1_bru_write(bru, dl, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) |
+                      VI6_BRU_ROP_CROP(VI6_ROP_NOP) |
+                      VI6_BRU_ROP_AROP(VI6_ROP_NOP));
+
+       for (i = 0; i < bru->entity.source_pad; ++i) {
+               bool premultiplied = false;
+               u32 ctrl = 0;
+
+               /* Configure all Blend/ROP units corresponding to an enabled BRU
+                * input for alpha blending. Blend/ROP units corresponding to
+                * disabled BRU inputs are used in ROP NOP mode to ignore the
+                * SRC input.
+                */
+               if (bru->inputs[i].rpf) {
+                       ctrl |= VI6_BRU_CTRL_RBC;
+
+                       premultiplied = bru->inputs[i].rpf->format.flags
+                                     & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA;
+               } else {
+                       ctrl |= VI6_BRU_CTRL_CROP(VI6_ROP_NOP)
+                            |  VI6_BRU_CTRL_AROP(VI6_ROP_NOP);
+               }
+
+               /* Select the virtual RPF as the Blend/ROP unit A DST input to
+                * serve as a background color.
+                */
+               if (i == 0)
+                       ctrl |= VI6_BRU_CTRL_DSTSEL_VRPF;
+
+               /* Route BRU inputs 0 to 3 as SRC inputs to Blend/ROP units A to
+                * D in that order. The Blend/ROP unit B SRC is hardwired to the
+                * ROP unit output, the corresponding register bits must be set
+                * to 0.
+                */
+               if (i != 1)
+                       ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i);
+
+               vsp1_bru_write(bru, dl, VI6_BRU_CTRL(i), ctrl);
+
+               /* Harcode the blending formula to
+                *
+                *      DSTc = DSTc * (1 - SRCa) + SRCc * SRCa
+                *      DSTa = DSTa * (1 - SRCa) + SRCa
+                *
+                * when the SRC input isn't premultiplied, and to
+                *
+                *      DSTc = DSTc * (1 - SRCa) + SRCc
+                *      DSTa = DSTa * (1 - SRCa) + SRCa
+                *
+                * otherwise.
+                */
+               vsp1_bru_write(bru, dl, VI6_BRU_BLD(i),
+                              VI6_BRU_BLD_CCMDX_255_SRC_A |
+                              (premultiplied ? VI6_BRU_BLD_CCMDY_COEFY :
+                                               VI6_BRU_BLD_CCMDY_SRC_A) |
+                              VI6_BRU_BLD_ACMDX_255_SRC_A |
+                              VI6_BRU_BLD_ACMDY_COEFY |
+                              (0xff << VI6_BRU_BLD_COEFY_SHIFT));
+       }
+}
+
+static const struct vsp1_entity_operations bru_entity_ops = {
+       .configure = bru_configure,
+};
+
 /* -----------------------------------------------------------------------------
  * Initialization and Cleanup
  */
 
 struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1)
 {
-       struct v4l2_subdev *subdev;
        struct vsp1_bru *bru;
        int ret;
 
@@ -413,31 +386,21 @@ struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1)
        if (bru == NULL)
                return ERR_PTR(-ENOMEM);
 
+       bru->entity.ops = &bru_entity_ops;
        bru->entity.type = VSP1_ENTITY_BRU;
 
-       ret = vsp1_entity_init(vsp1, &bru->entity,
-                              vsp1->info->num_bru_inputs + 1);
+       ret = vsp1_entity_init(vsp1, &bru->entity, "bru",
+                              vsp1->info->num_bru_inputs + 1, &bru_ops);
        if (ret < 0)
                return ERR_PTR(ret);
 
-       /* Initialize the V4L2 subdev. */
-       subdev = &bru->entity.subdev;
-       v4l2_subdev_init(subdev, &bru_ops);
-
-       subdev->entity.ops = &vsp1->media_ops;
-       subdev->internal_ops = &vsp1_subdev_internal_ops;
-       snprintf(subdev->name, sizeof(subdev->name), "%s bru",
-                dev_name(vsp1->dev));
-       v4l2_set_subdevdata(subdev, bru);
-       subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-       vsp1_entity_init_formats(subdev, NULL);
-
        /* Initialize the control handler. */
        v4l2_ctrl_handler_init(&bru->ctrls, 1);
        v4l2_ctrl_new_std(&bru->ctrls, &bru_ctrl_ops, V4L2_CID_BG_COLOR,
                          0, 0xffffff, 1, 0);
 
+       bru->bgcolor = 0;
+
        bru->entity.subdev.ctrl_handler = &bru->ctrls;
 
        if (bru->ctrls.error) {
index dbac968..828a3fc 100644 (file)
@@ -31,8 +31,9 @@ struct vsp1_bru {
 
        struct {
                struct vsp1_rwpf *rpf;
-               struct v4l2_rect compose;
        } inputs[VSP1_MAX_RPF];
+
+       u32 bgcolor;
 };
 
 static inline struct vsp1_bru *to_bru(struct v4l2_subdev *subdev)
index 1a9a585..e238d9b 100644 (file)
 
 #include "vsp1.h"
 #include "vsp1_dl.h"
-#include "vsp1_pipe.h"
 
-/*
- * Global resources
- *
- * - Display-related interrupts (can be used for vblank evasion ?)
- * - Display-list enable
- * - Header-less for WPF0
- * - DL swap
- */
-
-#define VSP1_DL_BODY_SIZE              (2 * 4 * 256)
+#define VSP1_DL_NUM_ENTRIES            256
 #define VSP1_DL_NUM_LISTS              3
 
+#define VSP1_DLH_INT_ENABLE            (1 << 1)
+#define VSP1_DLH_AUTO_START            (1 << 0)
+
+struct vsp1_dl_header_list {
+       u32 num_bytes;
+       u32 addr;
+} __attribute__((__packed__));
+
+struct vsp1_dl_header {
+       u32 num_lists;
+       struct vsp1_dl_header_list lists[8];
+       u32 next_header;
+       u32 flags;
+} __attribute__((__packed__));
+
 struct vsp1_dl_entry {
        u32 addr;
        u32 data;
 } __attribute__((__packed__));
 
-struct vsp1_dl_list {
+/**
+ * struct vsp1_dl_body - Display list body
+ * @list: entry in the display list list of bodies
+ * @vsp1: the VSP1 device
+ * @entries: array of entries
+ * @dma: DMA address of the entries
+ * @size: size of the DMA memory in bytes
+ * @num_entries: number of stored entries
+ */
+struct vsp1_dl_body {
+       struct list_head list;
+       struct vsp1_device *vsp1;
+
+       struct vsp1_dl_entry *entries;
+       dma_addr_t dma;
        size_t size;
-       int reg_count;
 
-       bool in_use;
+       unsigned int num_entries;
+};
 
-       struct vsp1_dl_entry *body;
+/**
+ * struct vsp1_dl_list - Display list
+ * @list: entry in the display list manager lists
+ * @dlm: the display list manager
+ * @header: display list header, NULL for headerless lists
+ * @dma: DMA address for the header
+ * @body0: first display list body
+ * @fragments: list of extra display list bodies
+ */
+struct vsp1_dl_list {
+       struct list_head list;
+       struct vsp1_dl_manager *dlm;
+
+       struct vsp1_dl_header *header;
        dma_addr_t dma;
+
+       struct vsp1_dl_body body0;
+       struct list_head fragments;
+};
+
+enum vsp1_dl_mode {
+       VSP1_DL_MODE_HEADER,
+       VSP1_DL_MODE_HEADERLESS,
 };
 
 /**
- * struct vsp1_dl - Display List manager
+ * struct vsp1_dl_manager - Display List manager
+ * @index: index of the related WPF
+ * @mode: display list operation mode (header or headerless)
  * @vsp1: the VSP1 device
  * @lock: protects the active, queued and pending lists
- * @lists.all: array of all allocate display lists
- * @lists.active: list currently being processed (loaded) by hardware
- * @lists.queued: list queued to the hardware (written to the DL registers)
- * @lists.pending: list waiting to be queued to the hardware
- * @lists.write: list being written to by software
+ * @free: array of all free display lists
+ * @active: list currently being processed (loaded) by hardware
+ * @queued: list queued to the hardware (written to the DL registers)
+ * @pending: list waiting to be queued to the hardware
  */
-struct vsp1_dl {
+struct vsp1_dl_manager {
+       unsigned int index;
+       enum vsp1_dl_mode mode;
        struct vsp1_device *vsp1;
 
        spinlock_t lock;
+       struct list_head free;
+       struct vsp1_dl_list *active;
+       struct vsp1_dl_list *queued;
+       struct vsp1_dl_list *pending;
+};
 
-       size_t size;
-       dma_addr_t dma;
-       void *mem;
+/* -----------------------------------------------------------------------------
+ * Display List Body Management
+ */
+
+/*
+ * Initialize a display list body object and allocate DMA memory for the body
+ * data. The display list body object is expected to have been initialized to
+ * 0 when allocated.
+ */
+static int vsp1_dl_body_init(struct vsp1_device *vsp1,
+                            struct vsp1_dl_body *dlb, unsigned int num_entries,
+                            size_t extra_size)
+{
+       size_t size = num_entries * sizeof(*dlb->entries) + extra_size;
 
-       struct {
-               struct vsp1_dl_list all[VSP1_DL_NUM_LISTS];
+       dlb->vsp1 = vsp1;
+       dlb->size = size;
 
-               struct vsp1_dl_list *active;
-               struct vsp1_dl_list *queued;
-               struct vsp1_dl_list *pending;
-               struct vsp1_dl_list *write;
-       } lists;
-};
+       dlb->entries = dma_alloc_wc(vsp1->dev, dlb->size, &dlb->dma,
+                                   GFP_KERNEL);
+       if (!dlb->entries)
+               return -ENOMEM;
+
+       return 0;
+}
+
+/*
+ * Cleanup a display list body and free allocated DMA memory allocated.
+ */
+static void vsp1_dl_body_cleanup(struct vsp1_dl_body *dlb)
+{
+       dma_free_wc(dlb->vsp1->dev, dlb->size, dlb->entries, dlb->dma);
+}
+
+/**
+ * vsp1_dl_fragment_alloc - Allocate a display list fragment
+ * @vsp1: The VSP1 device
+ * @num_entries: The maximum number of entries that the fragment can contain
+ *
+ * Allocate a display list fragment with enough memory to contain the requested
+ * number of entries.
+ *
+ * Return a pointer to a fragment on success or NULL if memory can't be
+ * allocated.
+ */
+struct vsp1_dl_body *vsp1_dl_fragment_alloc(struct vsp1_device *vsp1,
+                                           unsigned int num_entries)
+{
+       struct vsp1_dl_body *dlb;
+       int ret;
+
+       dlb = kzalloc(sizeof(*dlb), GFP_KERNEL);
+       if (!dlb)
+               return NULL;
+
+       ret = vsp1_dl_body_init(vsp1, dlb, num_entries, 0);
+       if (ret < 0) {
+               kfree(dlb);
+               return NULL;
+       }
+
+       return dlb;
+}
+
+/**
+ * vsp1_dl_fragment_free - Free a display list fragment
+ * @dlb: The fragment
+ *
+ * Free the given display list fragment and the associated DMA memory.
+ *
+ * Fragments must only be freed explicitly if they are not added to a display
+ * list, as the display list will take ownership of them and free them
+ * otherwise. Manual free typically happens at cleanup time for fragments that
+ * have been allocated but not used.
+ *
+ * Passing a NULL pointer to this function is safe, in that case no operation
+ * will be performed.
+ */
+void vsp1_dl_fragment_free(struct vsp1_dl_body *dlb)
+{
+       if (!dlb)
+               return;
+
+       vsp1_dl_body_cleanup(dlb);
+       kfree(dlb);
+}
+
+/**
+ * vsp1_dl_fragment_write - Write a register to a display list fragment
+ * @dlb: The fragment
+ * @reg: The register address
+ * @data: The register value
+ *
+ * Write the given register and value to the display list fragment. The maximum
+ * number of entries that can be written in a fragment is specified when the
+ * fragment is allocated by vsp1_dl_fragment_alloc().
+ */
+void vsp1_dl_fragment_write(struct vsp1_dl_body *dlb, u32 reg, u32 data)
+{
+       dlb->entries[dlb->num_entries].addr = reg;
+       dlb->entries[dlb->num_entries].data = data;
+       dlb->num_entries++;
+}
 
 /* -----------------------------------------------------------------------------
  * Display List Transaction Management
  */
 
-static void vsp1_dl_free_list(struct vsp1_dl_list *list)
+static struct vsp1_dl_list *vsp1_dl_list_alloc(struct vsp1_dl_manager *dlm)
 {
-       if (!list)
-               return;
+       struct vsp1_dl_list *dl;
+       size_t header_size;
+       int ret;
+
+       dl = kzalloc(sizeof(*dl), GFP_KERNEL);
+       if (!dl)
+               return NULL;
 
-       list->in_use = false;
+       INIT_LIST_HEAD(&dl->fragments);
+       dl->dlm = dlm;
+
+       /* Initialize the display list body and allocate DMA memory for the body
+        * and the optional header. Both are allocated together to avoid memory
+        * fragmentation, with the header located right after the body in
+        * memory.
+        */
+       header_size = dlm->mode == VSP1_DL_MODE_HEADER
+                   ? ALIGN(sizeof(struct vsp1_dl_header), 8)
+                   : 0;
+
+       ret = vsp1_dl_body_init(dlm->vsp1, &dl->body0, VSP1_DL_NUM_ENTRIES,
+                               header_size);
+       if (ret < 0) {
+               kfree(dl);
+               return NULL;
+       }
+
+       if (dlm->mode == VSP1_DL_MODE_HEADER) {
+               size_t header_offset = VSP1_DL_NUM_ENTRIES
+                                    * sizeof(*dl->body0.entries);
+
+               dl->header = ((void *)dl->body0.entries) + header_offset;
+               dl->dma = dl->body0.dma + header_offset;
+
+               memset(dl->header, 0, sizeof(*dl->header));
+               dl->header->lists[0].addr = dl->body0.dma;
+               dl->header->flags = VSP1_DLH_INT_ENABLE;
+       }
+
+       return dl;
 }
 
-void vsp1_dl_reset(struct vsp1_dl *dl)
+static void vsp1_dl_list_free_fragments(struct vsp1_dl_list *dl)
 {
-       unsigned int i;
+       struct vsp1_dl_body *dlb, *next;
 
-       dl->lists.active = NULL;
-       dl->lists.queued = NULL;
-       dl->lists.pending = NULL;
-       dl->lists.write = NULL;
+       list_for_each_entry_safe(dlb, next, &dl->fragments, list) {
+               list_del(&dlb->list);
+               vsp1_dl_body_cleanup(dlb);
+               kfree(dlb);
+       }
+}
 
-       for (i = 0; i < ARRAY_SIZE(dl->lists.all); ++i)
-               dl->lists.all[i].in_use = false;
+static void vsp1_dl_list_free(struct vsp1_dl_list *dl)
+{
+       vsp1_dl_body_cleanup(&dl->body0);
+       vsp1_dl_list_free_fragments(dl);
+       kfree(dl);
 }
 
-void vsp1_dl_begin(struct vsp1_dl *dl)
+/**
+ * vsp1_dl_list_get - Get a free display list
+ * @dlm: The display list manager
+ *
+ * Get a display list from the pool of free lists and return it.
+ *
+ * This function must be called without the display list manager lock held.
+ */
+struct vsp1_dl_list *vsp1_dl_list_get(struct vsp1_dl_manager *dlm)
 {
-       struct vsp1_dl_list *list = NULL;
+       struct vsp1_dl_list *dl = NULL;
        unsigned long flags;
-       unsigned int i;
 
-       spin_lock_irqsave(&dl->lock, flags);
+       spin_lock_irqsave(&dlm->lock, flags);
 
-       for (i = 0; i < ARRAY_SIZE(dl->lists.all); ++i) {
-               if (!dl->lists.all[i].in_use) {
-                       list = &dl->lists.all[i];
-                       break;
-               }
+       if (!list_empty(&dlm->free)) {
+               dl = list_first_entry(&dlm->free, struct vsp1_dl_list, list);
+               list_del(&dl->list);
        }
 
-       if (!list) {
-               list = dl->lists.pending;
-               dl->lists.pending = NULL;
-       }
+       spin_unlock_irqrestore(&dlm->lock, flags);
+
+       return dl;
+}
+
+/* This function must be called with the display list manager lock held.*/
+static void __vsp1_dl_list_put(struct vsp1_dl_list *dl)
+{
+       if (!dl)
+               return;
+
+       vsp1_dl_list_free_fragments(dl);
+       dl->body0.num_entries = 0;
+
+       list_add_tail(&dl->list, &dl->dlm->free);
+}
+
+/**
+ * vsp1_dl_list_put - Release a display list
+ * @dl: The display list
+ *
+ * Release the display list and return it to the pool of free lists.
+ *
+ * Passing a NULL pointer to this function is safe, in that case no operation
+ * will be performed.
+ */
+void vsp1_dl_list_put(struct vsp1_dl_list *dl)
+{
+       unsigned long flags;
 
-       spin_unlock_irqrestore(&dl->lock, flags);
+       if (!dl)
+               return;
 
-       dl->lists.write = list;
+       spin_lock_irqsave(&dl->dlm->lock, flags);
+       __vsp1_dl_list_put(dl);
+       spin_unlock_irqrestore(&dl->dlm->lock, flags);
+}
 
-       list->in_use = true;
-       list->reg_count = 0;
+/**
+ * vsp1_dl_list_write - Write a register to the display list
+ * @dl: The display list
+ * @reg: The register address
+ * @data: The register value
+ *
+ * Write the given register and value to the display list. Up to 256 registers
+ * can be written per display list.
+ */
+void vsp1_dl_list_write(struct vsp1_dl_list *dl, u32 reg, u32 data)
+{
+       vsp1_dl_fragment_write(&dl->body0, reg, data);
 }
 
-void vsp1_dl_add(struct vsp1_entity *e, u32 reg, u32 data)
+/**
+ * vsp1_dl_list_add_fragment - Add a fragment to the display list
+ * @dl: The display list
+ * @dlb: The fragment
+ *
+ * Add a display list body as a fragment to a display list. Registers contained
+ * in fragments are processed after registers contained in the main display
+ * list, in the order in which fragments are added.
+ *
+ * Adding a fragment to a display list passes ownership of the fragment to the
+ * list. The caller must not touch the fragment after this call, and must not
+ * free it explicitly with vsp1_dl_fragment_free().
+ *
+ * Fragments are only usable for display lists in header mode. Attempt to
+ * add a fragment to a header-less display list will return an error.
+ */
+int vsp1_dl_list_add_fragment(struct vsp1_dl_list *dl,
+                             struct vsp1_dl_body *dlb)
 {
-       struct vsp1_pipeline *pipe = to_vsp1_pipeline(&e->subdev.entity);
-       struct vsp1_dl *dl = pipe->dl;
-       struct vsp1_dl_list *list = dl->lists.write;
+       /* Multi-body lists are only available in header mode. */
+       if (dl->dlm->mode != VSP1_DL_MODE_HEADER)
+               return -EINVAL;
 
-       list->body[list->reg_count].addr = reg;
-       list->body[list->reg_count].data = data;
-       list->reg_count++;
+       list_add_tail(&dlb->list, &dl->fragments);
+       return 0;
 }
 
-void vsp1_dl_commit(struct vsp1_dl *dl)
+void vsp1_dl_list_commit(struct vsp1_dl_list *dl)
 {
-       struct vsp1_device *vsp1 = dl->vsp1;
-       struct vsp1_dl_list *list;
+       struct vsp1_dl_manager *dlm = dl->dlm;
+       struct vsp1_device *vsp1 = dlm->vsp1;
        unsigned long flags;
        bool update;
 
-       list = dl->lists.write;
-       dl->lists.write = NULL;
+       spin_lock_irqsave(&dlm->lock, flags);
+
+       if (dl->dlm->mode == VSP1_DL_MODE_HEADER) {
+               struct vsp1_dl_header_list *hdr = dl->header->lists;
+               struct vsp1_dl_body *dlb;
+               unsigned int num_lists = 0;
+
+               /* Fill the header with the display list bodies addresses and
+                * sizes. The address of the first body has already been filled
+                * when the display list was allocated.
+                *
+                * In header mode the caller guarantees that the hardware is
+                * idle at this point.
+                */
+               hdr->num_bytes = dl->body0.num_entries
+                              * sizeof(*dl->header->lists);
+
+               list_for_each_entry(dlb, &dl->fragments, list) {
+                       num_lists++;
+                       hdr++;
+
+                       hdr->addr = dlb->dma;
+                       hdr->num_bytes = dlb->num_entries
+                                      * sizeof(*dl->header->lists);
+               }
+
+               dl->header->num_lists = num_lists;
+               vsp1_write(vsp1, VI6_DL_HDR_ADDR(dlm->index), dl->dma);
 
-       spin_lock_irqsave(&dl->lock, flags);
+               dlm->active = dl;
+               goto done;
+       }
 
        /* Once the UPD bit has been set the hardware can start processing the
         * display list at any time and we can't touch the address and size
@@ -159,8 +426,8 @@ void vsp1_dl_commit(struct vsp1_dl *dl)
         */
        update = !!(vsp1_read(vsp1, VI6_DL_BODY_SIZE) & VI6_DL_BODY_SIZE_UPD);
        if (update) {
-               vsp1_dl_free_list(dl->lists.pending);
-               dl->lists.pending = list;
+               __vsp1_dl_list_put(dlm->pending);
+               dlm->pending = dl;
                goto done;
        }
 
@@ -168,42 +435,51 @@ void vsp1_dl_commit(struct vsp1_dl *dl)
         * The UPD bit will be cleared by the device when the display list is
         * processed.
         */
-       vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), list->dma);
+       vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), dl->body0.dma);
        vsp1_write(vsp1, VI6_DL_BODY_SIZE, VI6_DL_BODY_SIZE_UPD |
-                  (list->reg_count * 8));
+                  (dl->body0.num_entries * sizeof(*dl->header->lists)));
 
-       vsp1_dl_free_list(dl->lists.queued);
-       dl->lists.queued = list;
+       __vsp1_dl_list_put(dlm->queued);
+       dlm->queued = dl;
 
 done:
-       spin_unlock_irqrestore(&dl->lock, flags);
+       spin_unlock_irqrestore(&dlm->lock, flags);
 }
 
 /* -----------------------------------------------------------------------------
- * Interrupt Handling
+ * Display List Manager
  */
 
-void vsp1_dl_irq_display_start(struct vsp1_dl *dl)
+/* Interrupt Handling */
+void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm)
 {
-       spin_lock(&dl->lock);
+       spin_lock(&dlm->lock);
 
        /* The display start interrupt signals the end of the display list
         * processing by the device. The active display list, if any, won't be
         * accessed anymore and can be reused.
         */
-       if (dl->lists.active) {
-               vsp1_dl_free_list(dl->lists.active);
-               dl->lists.active = NULL;
-       }
+       __vsp1_dl_list_put(dlm->active);
+       dlm->active = NULL;
 
-       spin_unlock(&dl->lock);
+       spin_unlock(&dlm->lock);
 }
 
-void vsp1_dl_irq_frame_end(struct vsp1_dl *dl)
+void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm)
 {
-       struct vsp1_device *vsp1 = dl->vsp1;
+       struct vsp1_device *vsp1 = dlm->vsp1;
+
+       spin_lock(&dlm->lock);
+
+       __vsp1_dl_list_put(dlm->active);
+       dlm->active = NULL;
 
-       spin_lock(&dl->lock);
+       /* Header mode is used for mem-to-mem pipelines only. We don't need to
+        * perform any operation as there can't be any new display list queued
+        * in that case.
+        */
+       if (dlm->mode == VSP1_DL_MODE_HEADER)
+               goto done;
 
        /* The UPD bit set indicates that the commit operation raced with the
         * interrupt and occurred after the frame end event and UPD clear but
@@ -216,42 +492,39 @@ void vsp1_dl_irq_frame_end(struct vsp1_dl *dl)
        /* The device starts processing the queued display list right after the
         * frame end interrupt. The display list thus becomes active.
         */
-       if (dl->lists.queued) {
-               WARN_ON(dl->lists.active);
-               dl->lists.active = dl->lists.queued;
-               dl->lists.queued = NULL;
+       if (dlm->queued) {
+               dlm->active = dlm->queued;
+               dlm->queued = NULL;
        }
 
        /* Now that the UPD bit has been cleared we can queue the next display
         * list to the hardware if one has been prepared.
         */
-       if (dl->lists.pending) {
-               struct vsp1_dl_list *list = dl->lists.pending;
+       if (dlm->pending) {
+               struct vsp1_dl_list *dl = dlm->pending;
 
-               vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), list->dma);
+               vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), dl->body0.dma);
                vsp1_write(vsp1, VI6_DL_BODY_SIZE, VI6_DL_BODY_SIZE_UPD |
-                          (list->reg_count * 8));
+                          (dl->body0.num_entries *
+                           sizeof(*dl->header->lists)));
 
-               dl->lists.queued = list;
-               dl->lists.pending = NULL;
+               dlm->queued = dl;
+               dlm->pending = NULL;
        }
 
 done:
-       spin_unlock(&dl->lock);
+       spin_unlock(&dlm->lock);
 }
 
-/* -----------------------------------------------------------------------------
- * Hardware Setup
- */
-
-void vsp1_dl_setup(struct vsp1_device *vsp1)
+/* Hardware Setup */
+void vsp1_dlm_setup(struct vsp1_device *vsp1)
 {
        u32 ctrl = (256 << VI6_DL_CTRL_AR_WAIT_SHIFT)
                 | VI6_DL_CTRL_DC2 | VI6_DL_CTRL_DC1 | VI6_DL_CTRL_DC0
                 | VI6_DL_CTRL_DLE;
 
-       /* The DRM pipeline operates with header-less display lists in
-        * Continuous Frame Mode.
+       /* The DRM pipeline operates with display lists in Continuous Frame
+        * Mode, all other pipelines use manual start.
         */
        if (vsp1->drm)
                ctrl |= VI6_DL_CTRL_CFM0 | VI6_DL_CTRL_NH0;
@@ -260,46 +533,64 @@ void vsp1_dl_setup(struct vsp1_device *vsp1)
        vsp1_write(vsp1, VI6_DL_SWAP, VI6_DL_SWAP_LWS);
 }
 
-/* -----------------------------------------------------------------------------
- * Initialization and Cleanup
- */
+void vsp1_dlm_reset(struct vsp1_dl_manager *dlm)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dlm->lock, flags);
 
-struct vsp1_dl *vsp1_dl_create(struct vsp1_device *vsp1)
+       __vsp1_dl_list_put(dlm->active);
+       __vsp1_dl_list_put(dlm->queued);
+       __vsp1_dl_list_put(dlm->pending);
+
+       spin_unlock_irqrestore(&dlm->lock, flags);
+
+       dlm->active = NULL;
+       dlm->queued = NULL;
+       dlm->pending = NULL;
+}
+
+struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1,
+                                       unsigned int index,
+                                       unsigned int prealloc)
 {
-       struct vsp1_dl *dl;
+       struct vsp1_dl_manager *dlm;
        unsigned int i;
 
-       dl = kzalloc(sizeof(*dl), GFP_KERNEL);
-       if (!dl)
+       dlm = devm_kzalloc(vsp1->dev, sizeof(*dlm), GFP_KERNEL);
+       if (!dlm)
                return NULL;
 
-       spin_lock_init(&dl->lock);
+       dlm->index = index;
+       dlm->mode = index == 0 && !vsp1->info->uapi
+                 ? VSP1_DL_MODE_HEADERLESS : VSP1_DL_MODE_HEADER;
+       dlm->vsp1 = vsp1;
 
-       dl->vsp1 = vsp1;
-       dl->size = VSP1_DL_BODY_SIZE * ARRAY_SIZE(dl->lists.all);
+       spin_lock_init(&dlm->lock);
+       INIT_LIST_HEAD(&dlm->free);
 
-       dl->mem = dma_alloc_wc(vsp1->dev, dl->size, &dl->dma,
-                                        GFP_KERNEL);
-       if (!dl->mem) {
-               kfree(dl);
-               return NULL;
-       }
+       for (i = 0; i < prealloc; ++i) {
+               struct vsp1_dl_list *dl;
 
-       for (i = 0; i < ARRAY_SIZE(dl->lists.all); ++i) {
-               struct vsp1_dl_list *list = &dl->lists.all[i];
+               dl = vsp1_dl_list_alloc(dlm);
+               if (!dl)
+                       return NULL;
 
-               list->size = VSP1_DL_BODY_SIZE;
-               list->reg_count = 0;
-               list->in_use = false;
-               list->dma = dl->dma + VSP1_DL_BODY_SIZE * i;
-               list->body = dl->mem + VSP1_DL_BODY_SIZE * i;
+               list_add_tail(&dl->list, &dlm->free);
        }
 
-       return dl;
+       return dlm;
 }
 
-void vsp1_dl_destroy(struct vsp1_dl *dl)
+void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm)
 {
-       dma_free_wc(dl->vsp1->dev, dl->size, dl->mem, dl->dma);
-       kfree(dl);
+       struct vsp1_dl_list *dl, *next;
+
+       if (!dlm)
+               return;
+
+       list_for_each_entry_safe(dl, next, &dlm->free, list) {
+               list_del(&dl->list);
+               vsp1_dl_list_free(dl);
+       }
 }
index 448c425..de387cd 100644 (file)
 #ifndef __VSP1_DL_H__
 #define __VSP1_DL_H__
 
-#include "vsp1_entity.h"
+#include <linux/types.h>
 
 struct vsp1_device;
-struct vsp1_dl;
-
-struct vsp1_dl *vsp1_dl_create(struct vsp1_device *vsp1);
-void vsp1_dl_destroy(struct vsp1_dl *dl);
-
-void vsp1_dl_setup(struct vsp1_device *vsp1);
-
-void vsp1_dl_reset(struct vsp1_dl *dl);
-void vsp1_dl_begin(struct vsp1_dl *dl);
-void vsp1_dl_add(struct vsp1_entity *e, u32 reg, u32 data);
-void vsp1_dl_commit(struct vsp1_dl *dl);
-
-void vsp1_dl_irq_display_start(struct vsp1_dl *dl);
-void vsp1_dl_irq_frame_end(struct vsp1_dl *dl);
-
-static inline void vsp1_dl_mod_write(struct vsp1_entity *e, u32 reg, u32 data)
-{
-       if (e->vsp1->use_dl)
-               vsp1_dl_add(e, reg, data);
-       else
-               vsp1_write(e->vsp1, reg, data);
-}
+struct vsp1_dl_fragment;
+struct vsp1_dl_list;
+struct vsp1_dl_manager;
+
+void vsp1_dlm_setup(struct vsp1_device *vsp1);
+
+struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1,
+                                       unsigned int index,
+                                       unsigned int prealloc);
+void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm);
+void vsp1_dlm_reset(struct vsp1_dl_manager *dlm);
+void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm);
+void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm);
+
+struct vsp1_dl_list *vsp1_dl_list_get(struct vsp1_dl_manager *dlm);
+void vsp1_dl_list_put(struct vsp1_dl_list *dl);
+void vsp1_dl_list_write(struct vsp1_dl_list *dl, u32 reg, u32 data);
+void vsp1_dl_list_commit(struct vsp1_dl_list *dl);
+
+struct vsp1_dl_body *vsp1_dl_fragment_alloc(struct vsp1_device *vsp1,
+                                           unsigned int num_entries);
+void vsp1_dl_fragment_free(struct vsp1_dl_body *dlb);
+void vsp1_dl_fragment_write(struct vsp1_dl_body *dlb, u32 reg, u32 data);
+int vsp1_dl_list_add_fragment(struct vsp1_dl_list *dl,
+                             struct vsp1_dl_body *dlb);
 
 #endif /* __VSP1_DL_H__ */
index 021fe57..fc4bbc4 100644 (file)
 
 #include <linux/device.h>
 #include <linux/slab.h>
-#include <linux/vsp1.h>
 
 #include <media/media-entity.h>
 #include <media/v4l2-subdev.h>
+#include <media/vsp1.h>
 
 #include "vsp1.h"
 #include "vsp1_bru.h"
 #include "vsp1_pipe.h"
 #include "vsp1_rwpf.h"
 
+
 /* -----------------------------------------------------------------------------
- * Runtime Handling
+ * Interrupt Handling
  */
 
-static void vsp1_drm_pipeline_frame_end(struct vsp1_pipeline *pipe)
+void vsp1_drm_display_start(struct vsp1_device *vsp1)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&pipe->irqlock, flags);
-       if (pipe->num_inputs)
-               vsp1_pipeline_run(pipe);
-       spin_unlock_irqrestore(&pipe->irqlock, flags);
+       vsp1_dlm_irq_display_start(vsp1->drm->pipe.output->dlm);
 }
 
 /* -----------------------------------------------------------------------------
@@ -97,12 +93,14 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int width,
                media_entity_pipeline_stop(&pipe->output->entity.subdev.entity);
 
                for (i = 0; i < bru->entity.source_pad; ++i) {
+                       vsp1->drm->inputs[i].enabled = false;
                        bru->inputs[i].rpf = NULL;
                        pipe->inputs[i] = NULL;
                }
 
                pipe->num_inputs = 0;
 
+               vsp1_dlm_reset(pipe->output->dlm);
                vsp1_device_put(vsp1);
 
                dev_dbg(vsp1->dev, "%s: pipeline disabled\n", __func__);
@@ -110,8 +108,6 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int width,
                return 0;
        }
 
-       vsp1_dl_reset(vsp1->drm->dl);
-
        /* Configure the format at the BRU sinks and propagate it through the
         * pipeline.
         */
@@ -222,16 +218,11 @@ void vsp1_du_atomic_begin(struct device *dev)
 {
        struct vsp1_device *vsp1 = dev_get_drvdata(dev);
        struct vsp1_pipeline *pipe = &vsp1->drm->pipe;
-       unsigned long flags;
-
-       spin_lock_irqsave(&pipe->irqlock, flags);
 
        vsp1->drm->num_inputs = pipe->num_inputs;
 
-       spin_unlock_irqrestore(&pipe->irqlock, flags);
-
        /* Prepare the display list. */
-       vsp1_dl_begin(vsp1->drm->dl);
+       pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
 }
 EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin);
 
@@ -244,10 +235,13 @@ EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin);
  * @mem: DMA addresses of the memory buffers (one per plane)
  * @src: the source crop rectangle for the RPF
  * @dst: the destination compose rectangle for the BRU input
+ * @alpha: global alpha value for the input
+ * @zpos: the Z-order position of the input
  *
  * Configure the VSP to perform composition of the image referenced by @mem
  * through RPF @rpf_index, using the @src crop rectangle and the @dst
- * composition rectangle. The Z-order is fixed with RPF 0 at the bottom.
+ * composition rectangle. The Z-order is configurable with higher @zpos values
+ * displayed on top.
  *
  * Image format as stored in memory is expressed as a V4L2 @pixelformat value.
  * As a special case, setting the pixel format to 0 will disable the RPF. The
@@ -265,25 +259,17 @@ EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin);
  *
  * This function isn't reentrant, the caller needs to serialize calls.
  *
- * TODO: Implement Z-order control by decoupling the RPF index from the BRU
- * input index.
- *
  * Return 0 on success or a negative error code on failure.
  */
-int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
-                         u32 pixelformat, unsigned int pitch,
-                         dma_addr_t mem[2], const struct v4l2_rect *src,
-                         const struct v4l2_rect *dst)
+int vsp1_du_atomic_update_ext(struct device *dev, unsigned int rpf_index,
+                             u32 pixelformat, unsigned int pitch,
+                             dma_addr_t mem[2], const struct v4l2_rect *src,
+                             const struct v4l2_rect *dst, unsigned int alpha,
+                             unsigned int zpos)
 {
        struct vsp1_device *vsp1 = dev_get_drvdata(dev);
-       struct vsp1_pipeline *pipe = &vsp1->drm->pipe;
        const struct vsp1_format_info *fmtinfo;
-       struct v4l2_subdev_selection sel;
-       struct v4l2_subdev_format format;
-       struct vsp1_rwpf_memory memory;
        struct vsp1_rwpf *rpf;
-       unsigned long flags;
-       int ret;
 
        if (rpf_index >= vsp1->info->rpf_count)
                return -EINVAL;
@@ -294,31 +280,20 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
                dev_dbg(vsp1->dev, "%s: RPF%u: disable requested\n", __func__,
                        rpf_index);
 
-               spin_lock_irqsave(&pipe->irqlock, flags);
-
-               if (pipe->inputs[rpf_index]) {
-                       /* Remove the RPF from the pipeline if it was previously
-                        * enabled.
-                        */
-                       vsp1->bru->inputs[rpf_index].rpf = NULL;
-                       pipe->inputs[rpf_index] = NULL;
-
-                       pipe->num_inputs--;
-               }
-
-               spin_unlock_irqrestore(&pipe->irqlock, flags);
-
+               vsp1->drm->inputs[rpf_index].enabled = false;
                return 0;
        }
 
        dev_dbg(vsp1->dev,
-               "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad }\n",
+               "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad } zpos %u\n",
                __func__, rpf_index,
                src->left, src->top, src->width, src->height,
                dst->left, dst->top, dst->width, dst->height,
-               pixelformat, pitch, &mem[0], &mem[1]);
+               pixelformat, pitch, &mem[0], &mem[1], zpos);
 
-       /* Set the stride at the RPF input. */
+       /* Store the format, stride, memory buffer address, crop and compose
+        * rectangles and Z-order position and for the input.
+        */
        fmtinfo = vsp1_get_format_info(pixelformat);
        if (!fmtinfo) {
                dev_dbg(vsp1->dev, "Unsupport pixel format %08x for RPF\n",
@@ -330,16 +305,40 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
        rpf->format.num_planes = fmtinfo->planes;
        rpf->format.plane_fmt[0].bytesperline = pitch;
        rpf->format.plane_fmt[1].bytesperline = pitch;
+       rpf->alpha = alpha;
+
+       rpf->mem.addr[0] = mem[0];
+       rpf->mem.addr[1] = mem[1];
+       rpf->mem.addr[2] = 0;
+
+       vsp1->drm->inputs[rpf_index].crop = *src;
+       vsp1->drm->inputs[rpf_index].compose = *dst;
+       vsp1->drm->inputs[rpf_index].zpos = zpos;
+       vsp1->drm->inputs[rpf_index].enabled = true;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(vsp1_du_atomic_update_ext);
+
+static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1,
+                                 struct vsp1_rwpf *rpf, unsigned int bru_input)
+{
+       struct v4l2_subdev_selection sel;
+       struct v4l2_subdev_format format;
+       const struct v4l2_rect *crop;
+       int ret;
 
        /* Configure the format on the RPF sink pad and propagate it up to the
         * BRU sink pad.
         */
+       crop = &vsp1->drm->inputs[rpf->entity.index].crop;
+
        memset(&format, 0, sizeof(format));
        format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
        format.pad = RWPF_PAD_SINK;
-       format.format.width = src->width + src->left;
-       format.format.height = src->height + src->top;
-       format.format.code = fmtinfo->mbus;
+       format.format.width = crop->width + crop->left;
+       format.format.height = crop->height + crop->top;
+       format.format.code = rpf->fmtinfo->mbus;
        format.format.field = V4L2_FIELD_NONE;
 
        ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_fmt, NULL,
@@ -356,7 +355,7 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
        sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
        sel.pad = RWPF_PAD_SINK;
        sel.target = V4L2_SEL_TGT_CROP;
-       sel.r = *src;
+       sel.r = *crop;
 
        ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_selection, NULL,
                               &sel);
@@ -391,7 +390,7 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
                return ret;
 
        /* BRU sink, propagate the format from the RPF source. */
-       format.pad = rpf->entity.index;
+       format.pad = bru_input;
 
        ret = v4l2_subdev_call(&vsp1->bru->entity.subdev, pad, set_fmt, NULL,
                               &format);
@@ -402,9 +401,9 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
                __func__, format.format.width, format.format.height,
                format.format.code, format.pad);
 
-       sel.pad = rpf->entity.index;
+       sel.pad = bru_input;
        sel.target = V4L2_SEL_TGT_COMPOSE;
-       sel.r = *dst;
+       sel.r = vsp1->drm->inputs[rpf->entity.index].compose;
 
        ret = v4l2_subdev_call(&vsp1->bru->entity.subdev, pad, set_selection,
                               NULL, &sel);
@@ -416,33 +415,13 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
                __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height,
                sel.pad);
 
-       /* Store the compose rectangle coordinates in the RPF. */
-       rpf->location.left = dst->left;
-       rpf->location.top = dst->top;
-
-       /* Set the memory buffer address. */
-       memory.num_planes = fmtinfo->planes;
-       memory.addr[0] = mem[0];
-       memory.addr[1] = mem[1];
-
-       rpf->ops->set_memory(rpf, &memory);
-
-       spin_lock_irqsave(&pipe->irqlock, flags);
-
-       /* If the RPF was previously stopped set the BRU input to the RPF and
-        * store the RPF in the pipeline inputs array.
-        */
-       if (!pipe->inputs[rpf->entity.index]) {
-               vsp1->bru->inputs[rpf_index].rpf = rpf;
-               pipe->inputs[rpf->entity.index] = rpf;
-               pipe->num_inputs++;
-       }
-
-       spin_unlock_irqrestore(&pipe->irqlock, flags);
-
        return 0;
 }
-EXPORT_SYMBOL_GPL(vsp1_du_atomic_update);
+
+static unsigned int rpf_zpos(struct vsp1_device *vsp1, struct vsp1_rwpf *rpf)
+{
+       return vsp1->drm->inputs[rpf->entity.index].zpos;
+}
 
 /**
  * vsp1_du_atomic_flush - Commit an atomic update
@@ -452,51 +431,96 @@ void vsp1_du_atomic_flush(struct device *dev)
 {
        struct vsp1_device *vsp1 = dev_get_drvdata(dev);
        struct vsp1_pipeline *pipe = &vsp1->drm->pipe;
+       struct vsp1_rwpf *inputs[VSP1_MAX_RPF] = { NULL, };
        struct vsp1_entity *entity;
        unsigned long flags;
-       bool stop = false;
+       unsigned int i;
        int ret;
 
+       /* Count the number of enabled inputs and sort them by Z-order. */
+       pipe->num_inputs = 0;
+
+       for (i = 0; i < vsp1->info->rpf_count; ++i) {
+               struct vsp1_rwpf *rpf = vsp1->rpf[i];
+               unsigned int j;
+
+               if (!vsp1->drm->inputs[i].enabled) {
+                       pipe->inputs[i] = NULL;
+                       continue;
+               }
+
+               pipe->inputs[i] = rpf;
+
+               /* Insert the RPF in the sorted RPFs array. */
+               for (j = pipe->num_inputs++; j > 0; --j) {
+                       if (rpf_zpos(vsp1, inputs[j-1]) <= rpf_zpos(vsp1, rpf))
+                               break;
+                       inputs[j] = inputs[j-1];
+               }
+
+               inputs[j] = rpf;
+       }
+
+       /* Setup the RPF input pipeline for every enabled input. */
+       for (i = 0; i < vsp1->info->num_bru_inputs; ++i) {
+               struct vsp1_rwpf *rpf = inputs[i];
+
+               if (!rpf) {
+                       vsp1->bru->inputs[i].rpf = NULL;
+                       continue;
+               }
+
+               vsp1->bru->inputs[i].rpf = rpf;
+               rpf->bru_input = i;
+               rpf->entity.sink_pad = i;
+
+               dev_dbg(vsp1->dev, "%s: connecting RPF.%u to BRU:%u\n",
+                       __func__, rpf->entity.index, i);
+
+               ret = vsp1_du_setup_rpf_pipe(vsp1, rpf, i);
+               if (ret < 0)
+                       dev_err(vsp1->dev,
+                               "%s: failed to setup RPF.%u\n",
+                               __func__, rpf->entity.index);
+       }
+
+       /* Configure all entities in the pipeline. */
        list_for_each_entry(entity, &pipe->entities, list_pipe) {
                /* Disconnect unused RPFs from the pipeline. */
                if (entity->type == VSP1_ENTITY_RPF) {
                        struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
 
                        if (!pipe->inputs[rpf->entity.index]) {
-                               vsp1_mod_write(entity, entity->route->reg,
-                                          VI6_DPR_NODE_UNUSED);
+                               vsp1_dl_list_write(pipe->dl, entity->route->reg,
+                                                  VI6_DPR_NODE_UNUSED);
                                continue;
                        }
                }
 
-               vsp1_entity_route_setup(entity);
+               vsp1_entity_route_setup(entity, pipe->dl);
 
-               ret = v4l2_subdev_call(&entity->subdev, video,
-                                      s_stream, 1);
-               if (ret < 0) {
-                       dev_err(vsp1->dev,
-                               "DRM pipeline start failure on entity %s\n",
-                               entity->subdev.name);
-                       return;
-               }
-       }
+               if (entity->ops->configure)
+                       entity->ops->configure(entity, pipe, pipe->dl);
 
-       vsp1_dl_commit(vsp1->drm->dl);
+               /* The memory buffer address must be applied after configuring
+                * the RPF to make sure the crop offset are computed.
+                */
+               if (entity->type == VSP1_ENTITY_RPF)
+                       vsp1_rwpf_set_memory(to_rwpf(&entity->subdev),
+                                            pipe->dl);
+       }
 
-       spin_lock_irqsave(&pipe->irqlock, flags);
+       vsp1_dl_list_commit(pipe->dl);
+       pipe->dl = NULL;
 
        /* Start or stop the pipeline if needed. */
        if (!vsp1->drm->num_inputs && pipe->num_inputs) {
                vsp1_write(vsp1, VI6_DISP_IRQ_STA, 0);
                vsp1_write(vsp1, VI6_DISP_IRQ_ENB, VI6_DISP_IRQ_ENB_DSTE);
+               spin_lock_irqsave(&pipe->irqlock, flags);
                vsp1_pipeline_run(pipe);
+               spin_unlock_irqrestore(&pipe->irqlock, flags);
        } else if (vsp1->drm->num_inputs && !pipe->num_inputs) {
-               stop = true;
-       }
-
-       spin_unlock_irqrestore(&pipe->irqlock, flags);
-
-       if (stop) {
                vsp1_write(vsp1, VI6_DISP_IRQ_ENB, 0);
                vsp1_pipeline_stop(pipe);
        }
@@ -562,14 +586,9 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
        if (!vsp1->drm)
                return -ENOMEM;
 
-       vsp1->drm->dl = vsp1_dl_create(vsp1);
-       if (!vsp1->drm->dl)
-               return -ENOMEM;
-
        pipe = &vsp1->drm->pipe;
 
        vsp1_pipeline_init(pipe);
-       pipe->frame_end = vsp1_drm_pipeline_frame_end;
 
        /* The DRM pipeline is static, add entities manually. */
        for (i = 0; i < vsp1->info->rpf_count; ++i) {
@@ -586,12 +605,9 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
        pipe->lif = &vsp1->lif->entity;
        pipe->output = vsp1->wpf[0];
 
-       pipe->dl = vsp1->drm->dl;
-
        return 0;
 }
 
 void vsp1_drm_cleanup(struct vsp1_device *vsp1)
 {
-       vsp1_dl_destroy(vsp1->drm->dl);
 }
index f680568..9e28ab9 100644 (file)
 #ifndef __VSP1_DRM_H__
 #define __VSP1_DRM_H__
 
-#include "vsp1_pipe.h"
+#include <linux/videodev2.h>
 
-struct vsp1_dl;
+#include "vsp1_pipe.h"
 
 /**
  * vsp1_drm - State for the API exposed to the DRM driver
- * @dl: display list for DRM pipeline operation
  * @pipe: the VSP1 pipeline used for display
  * @num_inputs: number of active pipeline inputs at the beginning of an update
- * @update: the pipeline configuration has been updated
+ * @planes: source crop rectangle, destination compose rectangle and z-order
+ *     position for every input
  */
 struct vsp1_drm {
-       struct vsp1_dl *dl;
        struct vsp1_pipeline pipe;
        unsigned int num_inputs;
-       bool update;
+       struct {
+               bool enabled;
+               struct v4l2_rect crop;
+               struct v4l2_rect compose;
+               unsigned int zpos;
+       } inputs[VSP1_MAX_RPF];
 };
 
 int vsp1_drm_init(struct vsp1_device *vsp1);
 void vsp1_drm_cleanup(struct vsp1_device *vsp1);
 int vsp1_drm_create_links(struct vsp1_device *vsp1);
 
-int vsp1_du_init(struct device *dev);
-int vsp1_du_setup_lif(struct device *dev, unsigned int width,
-                     unsigned int height);
-void vsp1_du_atomic_begin(struct device *dev);
-int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
-                         u32 pixelformat, unsigned int pitch,
-                         dma_addr_t mem[2], const struct v4l2_rect *src,
-                         const struct v4l2_rect *dst);
-void vsp1_du_atomic_flush(struct device *dev);
-
+void vsp1_drm_display_start(struct vsp1_device *vsp1);
 
 #endif /* __VSP1_DRM_H__ */
index 25750a0..e2d779f 100644 (file)
@@ -30,6 +30,7 @@
 #include "vsp1_hsit.h"
 #include "vsp1_lif.h"
 #include "vsp1_lut.h"
+#include "vsp1_pipe.h"
 #include "vsp1_rwpf.h"
 #include "vsp1_sru.h"
 #include "vsp1_uds.h"
@@ -49,17 +50,15 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data)
 
        for (i = 0; i < vsp1->info->wpf_count; ++i) {
                struct vsp1_rwpf *wpf = vsp1->wpf[i];
-               struct vsp1_pipeline *pipe;
 
                if (wpf == NULL)
                        continue;
 
-               pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity);
                status = vsp1_read(vsp1, VI6_WPF_IRQ_STA(i));
                vsp1_write(vsp1, VI6_WPF_IRQ_STA(i), ~status & mask);
 
                if (status & VI6_WFP_IRQ_STA_FRE) {
-                       vsp1_pipeline_frame_end(pipe);
+                       vsp1_pipeline_frame_end(wpf->pipe);
                        ret = IRQ_HANDLED;
                }
        }
@@ -68,14 +67,7 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data)
        vsp1_write(vsp1, VI6_DISP_IRQ_STA, ~status & VI6_DISP_IRQ_STA_DST);
 
        if (status & VI6_DISP_IRQ_STA_DST) {
-               struct vsp1_rwpf *wpf = vsp1->wpf[0];
-               struct vsp1_pipeline *pipe;
-
-               if (wpf) {
-                       pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity);
-                       vsp1_pipeline_display_start(pipe);
-               }
-
+               vsp1_drm_display_start(vsp1);
                ret = IRQ_HANDLED;
        }
 
@@ -387,13 +379,10 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
        /* Register subdev nodes if the userspace API is enabled or initialize
         * the DRM pipeline otherwise.
         */
-       if (vsp1->info->uapi) {
-               vsp1->use_dl = false;
+       if (vsp1->info->uapi)
                ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev);
-       } else {
-               vsp1->use_dl = true;
+       else
                ret = vsp1_drm_init(vsp1);
-       }
        if (ret < 0)
                goto done;
 
@@ -465,8 +454,7 @@ static int vsp1_device_init(struct vsp1_device *vsp1)
        vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
                   (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
 
-       if (vsp1->use_dl)
-               vsp1_dl_setup(vsp1);
+       vsp1_dlm_setup(vsp1);
 
        return 0;
 }
@@ -570,6 +558,7 @@ static const struct dev_pm_ops vsp1_pm_ops = {
 static const struct vsp1_device_info vsp1_device_infos[] = {
        {
                .version = VI6_IP_VERSION_MODEL_VSPS_H2,
+               .gen = 2,
                .features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU,
                .rpf_count = 5,
                .uds_count = 3,
@@ -578,6 +567,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
                .uapi = true,
        }, {
                .version = VI6_IP_VERSION_MODEL_VSPR_H2,
+               .gen = 2,
                .features = VSP1_HAS_BRU | VSP1_HAS_SRU,
                .rpf_count = 5,
                .uds_count = 1,
@@ -586,6 +576,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
                .uapi = true,
        }, {
                .version = VI6_IP_VERSION_MODEL_VSPD_GEN2,
+               .gen = 2,
                .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_LUT,
                .rpf_count = 4,
                .uds_count = 1,
@@ -594,6 +585,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
                .uapi = true,
        }, {
                .version = VI6_IP_VERSION_MODEL_VSPS_M2,
+               .gen = 2,
                .features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU,
                .rpf_count = 5,
                .uds_count = 3,
@@ -602,6 +594,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
                .uapi = true,
        }, {
                .version = VI6_IP_VERSION_MODEL_VSPI_GEN3,
+               .gen = 3,
                .features = VSP1_HAS_LUT | VSP1_HAS_SRU,
                .rpf_count = 1,
                .uds_count = 1,
@@ -609,6 +602,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
                .uapi = true,
        }, {
                .version = VI6_IP_VERSION_MODEL_VSPBD_GEN3,
+               .gen = 3,
                .features = VSP1_HAS_BRU,
                .rpf_count = 5,
                .wpf_count = 1,
@@ -616,6 +610,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
                .uapi = true,
        }, {
                .version = VI6_IP_VERSION_MODEL_VSPBC_GEN3,
+               .gen = 3,
                .features = VSP1_HAS_BRU | VSP1_HAS_LUT,
                .rpf_count = 5,
                .wpf_count = 1,
@@ -623,7 +618,8 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
                .uapi = true,
        }, {
                .version = VI6_IP_VERSION_MODEL_VSPD_GEN3,
-               .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_LUT,
+               .gen = 3,
+               .features = VSP1_HAS_BRU | VSP1_HAS_LIF,
                .rpf_count = 5,
                .wpf_count = 2,
                .num_bru_inputs = 5,
index 20a78fb..3d070bc 100644 (file)
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
 #include "vsp1_entity.h"
 
-bool vsp1_entity_is_streaming(struct vsp1_entity *entity)
-{
-       unsigned long flags;
-       bool streaming;
-
-       spin_lock_irqsave(&entity->lock, flags);
-       streaming = entity->streaming;
-       spin_unlock_irqrestore(&entity->lock, flags);
-
-       return streaming;
-}
-
-int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming)
-{
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&entity->lock, flags);
-       entity->streaming = streaming;
-       spin_unlock_irqrestore(&entity->lock, flags);
-
-       if (!streaming)
-               return 0;
-
-       if (!entity->vsp1->info->uapi || !entity->subdev.ctrl_handler)
-               return 0;
-
-       ret = v4l2_ctrl_handler_setup(entity->subdev.ctrl_handler);
-       if (ret < 0) {
-               spin_lock_irqsave(&entity->lock, flags);
-               entity->streaming = false;
-               spin_unlock_irqrestore(&entity->lock, flags);
-       }
-
-       return ret;
-}
-
-void vsp1_entity_route_setup(struct vsp1_entity *source)
+void vsp1_entity_route_setup(struct vsp1_entity *source,
+                            struct vsp1_dl_list *dl)
 {
        struct vsp1_entity *sink;
 
@@ -66,40 +31,74 @@ void vsp1_entity_route_setup(struct vsp1_entity *source)
                return;
 
        sink = container_of(source->sink, struct vsp1_entity, subdev.entity);
-       vsp1_mod_write(source, source->route->reg,
-                      sink->route->inputs[source->sink_pad]);
+       vsp1_dl_list_write(dl, source->route->reg,
+                          sink->route->inputs[source->sink_pad]);
 }
 
 /* -----------------------------------------------------------------------------
  * V4L2 Subdevice Operations
  */
 
-struct v4l2_mbus_framefmt *
-vsp1_entity_get_pad_format(struct vsp1_entity *entity,
+/**
+ * vsp1_entity_get_pad_config - Get the pad configuration for an entity
+ * @entity: the entity
+ * @cfg: the TRY pad configuration
+ * @which: configuration selector (ACTIVE or TRY)
+ *
+ * Return the pad configuration requested by the which argument. The TRY
+ * configuration is passed explicitly to the function through the cfg argument
+ * and simply returned when requested. The ACTIVE configuration comes from the
+ * entity structure.
+ */
+struct v4l2_subdev_pad_config *
+vsp1_entity_get_pad_config(struct vsp1_entity *entity,
                           struct v4l2_subdev_pad_config *cfg,
-                          unsigned int pad, u32 which)
+                          enum v4l2_subdev_format_whence which)
 {
        switch (which) {
-       case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
-               return &entity->formats[pad];
+               return entity->config;
+       case V4L2_SUBDEV_FORMAT_TRY:
        default:
-               return NULL;
+               return cfg;
        }
 }
 
+/**
+ * vsp1_entity_get_pad_format - Get a pad format from storage for an entity
+ * @entity: the entity
+ * @cfg: the configuration storage
+ * @pad: the pad number
+ *
+ * Return the format stored in the given configuration for an entity's pad. The
+ * configuration can be an ACTIVE or TRY configuration.
+ */
+struct v4l2_mbus_framefmt *
+vsp1_entity_get_pad_format(struct vsp1_entity *entity,
+                          struct v4l2_subdev_pad_config *cfg,
+                          unsigned int pad)
+{
+       return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad);
+}
+
+struct v4l2_rect *
+vsp1_entity_get_pad_compose(struct vsp1_entity *entity,
+                           struct v4l2_subdev_pad_config *cfg,
+                           unsigned int pad)
+{
+       return v4l2_subdev_get_try_compose(&entity->subdev, cfg, pad);
+}
+
 /*
- * vsp1_entity_init_formats - Initialize formats on all pads
+ * vsp1_entity_init_cfg - Initialize formats on all pads
  * @subdev: V4L2 subdevice
  * @cfg: V4L2 subdev pad configuration
  *
- * Initialize all pad formats with default values. If cfg is not NULL, try
- * formats are initialized on the file handle. Otherwise active formats are
- * initialized on the device.
+ * Initialize all pad formats with default values in the given pad config. This
+ * function can be used as a handler for the subdev pad::init_cfg operation.
  */
-void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
-                           struct v4l2_subdev_pad_config *cfg)
+int vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
+                        struct v4l2_subdev_pad_config *cfg)
 {
        struct v4l2_subdev_format format;
        unsigned int pad;
@@ -113,19 +112,132 @@ void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
 
                v4l2_subdev_call(subdev, pad, set_fmt, cfg, &format);
        }
+
+       return 0;
 }
 
-static int vsp1_entity_open(struct v4l2_subdev *subdev,
-                           struct v4l2_subdev_fh *fh)
+/*
+ * vsp1_subdev_get_pad_format - Subdev pad get_fmt handler
+ * @subdev: V4L2 subdevice
+ * @cfg: V4L2 subdev pad configuration
+ * @fmt: V4L2 subdev format
+ *
+ * This function implements the subdev get_fmt pad operation. It can be used as
+ * a direct drop-in for the operation handler.
+ */
+int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev,
+                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_format *fmt)
 {
-       vsp1_entity_init_formats(subdev, fh->pad);
+       struct vsp1_entity *entity = to_vsp1_entity(subdev);
+       struct v4l2_subdev_pad_config *config;
+
+       config = vsp1_entity_get_pad_config(entity, cfg, fmt->which);
+       if (!config)
+               return -EINVAL;
+
+       fmt->format = *vsp1_entity_get_pad_format(entity, config, fmt->pad);
 
        return 0;
 }
 
-const struct v4l2_subdev_internal_ops vsp1_subdev_internal_ops = {
-       .open = vsp1_entity_open,
-};
+/*
+ * vsp1_subdev_enum_mbus_code - Subdev pad enum_mbus_code handler
+ * @subdev: V4L2 subdevice
+ * @cfg: V4L2 subdev pad configuration
+ * @code: Media bus code enumeration
+ * @codes: Array of supported media bus codes
+ * @ncodes: Number of supported media bus codes
+ *
+ * This function implements the subdev enum_mbus_code pad operation for entities
+ * that do not support format conversion. It enumerates the given supported
+ * media bus codes on the sink pad and reports a source pad format identical to
+ * the sink pad.
+ */
+int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
+                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_mbus_code_enum *code,
+                              const unsigned int *codes, unsigned int ncodes)
+{
+       struct vsp1_entity *entity = to_vsp1_entity(subdev);
+
+       if (code->pad == 0) {
+               if (code->index >= ncodes)
+                       return -EINVAL;
+
+               code->code = codes[code->index];
+       } else {
+               struct v4l2_subdev_pad_config *config;
+               struct v4l2_mbus_framefmt *format;
+
+               /* The entity can't perform format conversion, the sink format
+                * is always identical to the source format.
+                */
+               if (code->index)
+                       return -EINVAL;
+
+               config = vsp1_entity_get_pad_config(entity, cfg, code->which);
+               if (!config)
+                       return -EINVAL;
+
+               format = vsp1_entity_get_pad_format(entity, config, 0);
+               code->code = format->code;
+       }
+
+       return 0;
+}
+
+/*
+ * vsp1_subdev_enum_frame_size - Subdev pad enum_frame_size handler
+ * @subdev: V4L2 subdevice
+ * @cfg: V4L2 subdev pad configuration
+ * @fse: Frame size enumeration
+ * @min_width: Minimum image width
+ * @min_height: Minimum image height
+ * @max_width: Maximum image width
+ * @max_height: Maximum image height
+ *
+ * This function implements the subdev enum_frame_size pad operation for
+ * entities that do not support scaling or cropping. It reports the given
+ * minimum and maximum frame width and height on the sink pad, and a fixed
+ * source pad size identical to the sink pad.
+ */
+int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev,
+                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_frame_size_enum *fse,
+                               unsigned int min_width, unsigned int min_height,
+                               unsigned int max_width, unsigned int max_height)
+{
+       struct vsp1_entity *entity = to_vsp1_entity(subdev);
+       struct v4l2_subdev_pad_config *config;
+       struct v4l2_mbus_framefmt *format;
+
+       config = vsp1_entity_get_pad_config(entity, cfg, fse->which);
+       if (!config)
+               return -EINVAL;
+
+       format = vsp1_entity_get_pad_format(entity, config, fse->pad);
+
+       if (fse->index || fse->code != format->code)
+               return -EINVAL;
+
+       if (fse->pad == 0) {
+               fse->min_width = min_width;
+               fse->max_width = max_width;
+               fse->min_height = min_height;
+               fse->max_height = max_height;
+       } else {
+               /* The size on the source pad are fixed and always identical to
+                * the size on the sink pad.
+                */
+               fse->min_width = format->width;
+               fse->max_width = format->width;
+               fse->min_height = format->height;
+               fse->max_height = format->height;
+       }
+
+       return 0;
+}
 
 /* -----------------------------------------------------------------------------
  * Media Operations
@@ -171,11 +283,11 @@ static const struct vsp1_route vsp1_routes[] = {
        { VSP1_ENTITY_HST, 0, VI6_DPR_HST_ROUTE, { VI6_DPR_NODE_HST, } },
        { VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, } },
        { VSP1_ENTITY_LUT, 0, VI6_DPR_LUT_ROUTE, { VI6_DPR_NODE_LUT, } },
-       { VSP1_ENTITY_RPF, 0, VI6_DPR_RPF_ROUTE(0), { VI6_DPR_NODE_RPF(0), } },
-       { VSP1_ENTITY_RPF, 1, VI6_DPR_RPF_ROUTE(1), { VI6_DPR_NODE_RPF(1), } },
-       { VSP1_ENTITY_RPF, 2, VI6_DPR_RPF_ROUTE(2), { VI6_DPR_NODE_RPF(2), } },
-       { VSP1_ENTITY_RPF, 3, VI6_DPR_RPF_ROUTE(3), { VI6_DPR_NODE_RPF(3), } },
-       { VSP1_ENTITY_RPF, 4, VI6_DPR_RPF_ROUTE(4), { VI6_DPR_NODE_RPF(4), } },
+       { VSP1_ENTITY_RPF, 0, VI6_DPR_RPF_ROUTE(0), { 0, } },
+       { VSP1_ENTITY_RPF, 1, VI6_DPR_RPF_ROUTE(1), { 0, } },
+       { VSP1_ENTITY_RPF, 2, VI6_DPR_RPF_ROUTE(2), { 0, } },
+       { VSP1_ENTITY_RPF, 3, VI6_DPR_RPF_ROUTE(3), { 0, } },
+       { VSP1_ENTITY_RPF, 4, VI6_DPR_RPF_ROUTE(4), { 0, } },
        { VSP1_ENTITY_SRU, 0, VI6_DPR_SRU_ROUTE, { VI6_DPR_NODE_SRU, } },
        { VSP1_ENTITY_UDS, 0, VI6_DPR_UDS_ROUTE(0), { VI6_DPR_NODE_UDS(0), } },
        { VSP1_ENTITY_UDS, 1, VI6_DPR_UDS_ROUTE(1), { VI6_DPR_NODE_UDS(1), } },
@@ -187,9 +299,12 @@ static const struct vsp1_route vsp1_routes[] = {
 };
 
 int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
-                    unsigned int num_pads)
+                    const char *name, unsigned int num_pads,
+                    const struct v4l2_subdev_ops *ops)
 {
+       struct v4l2_subdev *subdev;
        unsigned int i;
+       int ret;
 
        for (i = 0; i < ARRAY_SIZE(vsp1_routes); ++i) {
                if (vsp1_routes[i].type == entity->type &&
@@ -202,37 +317,56 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
        if (i == ARRAY_SIZE(vsp1_routes))
                return -EINVAL;
 
-       spin_lock_init(&entity->lock);
-
        entity->vsp1 = vsp1;
        entity->source_pad = num_pads - 1;
 
-       /* Allocate formats and pads. */
-       entity->formats = devm_kzalloc(vsp1->dev,
-                                      num_pads * sizeof(*entity->formats),
-                                      GFP_KERNEL);
-       if (entity->formats == NULL)
-               return -ENOMEM;
-
+       /* Allocate and initialize pads. */
        entity->pads = devm_kzalloc(vsp1->dev, num_pads * sizeof(*entity->pads),
                                    GFP_KERNEL);
        if (entity->pads == NULL)
                return -ENOMEM;
 
-       /* Initialize pads. */
        for (i = 0; i < num_pads - 1; ++i)
                entity->pads[i].flags = MEDIA_PAD_FL_SINK;
 
        entity->pads[num_pads - 1].flags = MEDIA_PAD_FL_SOURCE;
 
        /* Initialize the media entity. */
-       return media_entity_pads_init(&entity->subdev.entity, num_pads,
-                                entity->pads);
+       ret = media_entity_pads_init(&entity->subdev.entity, num_pads,
+                                    entity->pads);
+       if (ret < 0)
+               return ret;
+
+       /* Initialize the V4L2 subdev. */
+       subdev = &entity->subdev;
+       v4l2_subdev_init(subdev, ops);
+
+       subdev->entity.ops = &vsp1->media_ops;
+       subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+       snprintf(subdev->name, sizeof(subdev->name), "%s %s",
+                dev_name(vsp1->dev), name);
+
+       vsp1_entity_init_cfg(subdev, NULL);
+
+       /* Allocate the pad configuration to store formats and selection
+        * rectangles.
+        */
+       entity->config = v4l2_subdev_alloc_pad_config(&entity->subdev);
+       if (entity->config == NULL) {
+               media_entity_cleanup(&entity->subdev.entity);
+               return -ENOMEM;
+       }
+
+       return 0;
 }
 
 void vsp1_entity_destroy(struct vsp1_entity *entity)
 {
+       if (entity->ops && entity->ops->destroy)
+               entity->ops->destroy(entity);
        if (entity->subdev.ctrl_handler)
                v4l2_ctrl_handler_free(entity->subdev.ctrl_handler);
+       v4l2_subdev_free_pad_config(entity->config);
        media_entity_cleanup(&entity->subdev.entity);
 }
index 83570df..69eff4e 100644 (file)
@@ -19,6 +19,8 @@
 #include <media/v4l2-subdev.h>
 
 struct vsp1_device;
+struct vsp1_dl_list;
+struct vsp1_pipeline;
 
 enum vsp1_entity_type {
        VSP1_ENTITY_BRU,
@@ -53,9 +55,27 @@ struct vsp1_route {
        unsigned int inputs[VSP1_ENTITY_MAX_INPUTS];
 };
 
+/**
+ * struct vsp1_entity_operations - Entity operations
+ * @destroy:   Destroy the entity.
+ * @set_memory:        Setup memory buffer access. This operation applies the settings
+ *             stored in the rwpf mem field to the display list. Valid for RPF
+ *             and WPF only.
+ * @configure: Setup the hardware based on the entity state (pipeline, formats,
+ *             selection rectangles, ...)
+ */
+struct vsp1_entity_operations {
+       void (*destroy)(struct vsp1_entity *);
+       void (*set_memory)(struct vsp1_entity *, struct vsp1_dl_list *dl);
+       void (*configure)(struct vsp1_entity *, struct vsp1_pipeline *,
+                         struct vsp1_dl_list *);
+};
+
 struct vsp1_entity {
        struct vsp1_device *vsp1;
 
+       const struct vsp1_entity_operations *ops;
+
        enum vsp1_entity_type type;
        unsigned int index;
        const struct vsp1_route *route;
@@ -70,10 +90,7 @@ struct vsp1_entity {
        unsigned int sink_pad;
 
        struct v4l2_subdev subdev;
-       struct v4l2_mbus_framefmt *formats;
-
-       spinlock_t lock;                /* Protects the streaming field */
-       bool streaming;
+       struct v4l2_subdev_pad_config *config;
 };
 
 static inline struct vsp1_entity *to_vsp1_entity(struct v4l2_subdev *subdev)
@@ -82,7 +99,8 @@ static inline struct vsp1_entity *to_vsp1_entity(struct v4l2_subdev *subdev)
 }
 
 int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
-                    unsigned int num_pads);
+                    const char *name, unsigned int num_pads,
+                    const struct v4l2_subdev_ops *ops);
 void vsp1_entity_destroy(struct vsp1_entity *entity);
 
 extern const struct v4l2_subdev_internal_ops vsp1_subdev_internal_ops;
@@ -91,16 +109,35 @@ int vsp1_entity_link_setup(struct media_entity *entity,
                           const struct media_pad *local,
                           const struct media_pad *remote, u32 flags);
 
+struct v4l2_subdev_pad_config *
+vsp1_entity_get_pad_config(struct vsp1_entity *entity,
+                          struct v4l2_subdev_pad_config *cfg,
+                          enum v4l2_subdev_format_whence which);
 struct v4l2_mbus_framefmt *
 vsp1_entity_get_pad_format(struct vsp1_entity *entity,
                           struct v4l2_subdev_pad_config *cfg,
-                          unsigned int pad, u32 which);
-void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
-                             struct v4l2_subdev_pad_config *cfg);
-
-bool vsp1_entity_is_streaming(struct vsp1_entity *entity);
-int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming);
-
-void vsp1_entity_route_setup(struct vsp1_entity *source);
+                          unsigned int pad);
+struct v4l2_rect *
+vsp1_entity_get_pad_compose(struct vsp1_entity *entity,
+                           struct v4l2_subdev_pad_config *cfg,
+                           unsigned int pad);
+int vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
+                        struct v4l2_subdev_pad_config *cfg);
+
+void vsp1_entity_route_setup(struct vsp1_entity *source,
+                            struct vsp1_dl_list *dl);
+
+int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev,
+                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_format *fmt);
+int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
+                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_mbus_code_enum *code,
+                              const unsigned int *codes, unsigned int ncodes);
+int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev,
+                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_frame_size_enum *fse,
+                               unsigned int min_w, unsigned int min_h,
+                               unsigned int max_w, unsigned int max_h);
 
 #endif /* __VSP1_ENTITY_H__ */
index c1087cf..68b8567 100644 (file)
@@ -17,6 +17,7 @@
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
 #include "vsp1_hsit.h"
 
 #define HSIT_MIN_SIZE                          4U
  * Device Access
  */
 
-static inline void vsp1_hsit_write(struct vsp1_hsit *hsit, u32 reg, u32 data)
+static inline void vsp1_hsit_write(struct vsp1_hsit *hsit,
+                                  struct vsp1_dl_list *dl, u32 reg, u32 data)
 {
-       vsp1_write(hsit->entity.vsp1, reg, data);
+       vsp1_dl_list_write(dl, reg, data);
 }
 
 /* -----------------------------------------------------------------------------
- * V4L2 Subdevice Core Operations
- */
-
-static int hsit_s_stream(struct v4l2_subdev *subdev, int enable)
-{
-       struct vsp1_hsit *hsit = to_hsit(subdev);
-
-       if (!enable)
-               return 0;
-
-       if (hsit->inverse)
-               vsp1_hsit_write(hsit, VI6_HSI_CTRL, VI6_HSI_CTRL_EN);
-       else
-               vsp1_hsit_write(hsit, VI6_HST_CTRL, VI6_HST_CTRL_EN);
-
-       return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Pad Operations
+ * V4L2 Subdevice Operations
  */
 
 static int hsit_enum_mbus_code(struct v4l2_subdev *subdev,
@@ -76,43 +59,9 @@ static int hsit_enum_frame_size(struct v4l2_subdev *subdev,
                                struct v4l2_subdev_pad_config *cfg,
                                struct v4l2_subdev_frame_size_enum *fse)
 {
-       struct vsp1_hsit *hsit = to_hsit(subdev);
-       struct v4l2_mbus_framefmt *format;
-
-       format = vsp1_entity_get_pad_format(&hsit->entity, cfg, fse->pad,
-                                           fse->which);
-
-       if (fse->index || fse->code != format->code)
-               return -EINVAL;
-
-       if (fse->pad == HSIT_PAD_SINK) {
-               fse->min_width = HSIT_MIN_SIZE;
-               fse->max_width = HSIT_MAX_SIZE;
-               fse->min_height = HSIT_MIN_SIZE;
-               fse->max_height = HSIT_MAX_SIZE;
-       } else {
-               /* The size on the source pad are fixed and always identical to
-                * the size on the sink pad.
-                */
-               fse->min_width = format->width;
-               fse->max_width = format->width;
-               fse->min_height = format->height;
-               fse->max_height = format->height;
-       }
-
-       return 0;
-}
-
-static int hsit_get_format(struct v4l2_subdev *subdev,
-                          struct v4l2_subdev_pad_config *cfg,
-                          struct v4l2_subdev_format *fmt)
-{
-       struct vsp1_hsit *hsit = to_hsit(subdev);
-
-       fmt->format = *vsp1_entity_get_pad_format(&hsit->entity, cfg, fmt->pad,
-                                                 fmt->which);
-
-       return 0;
+       return vsp1_subdev_enum_frame_size(subdev, cfg, fse, HSIT_MIN_SIZE,
+                                          HSIT_MIN_SIZE, HSIT_MAX_SIZE,
+                                          HSIT_MAX_SIZE);
 }
 
 static int hsit_set_format(struct v4l2_subdev *subdev,
@@ -120,10 +69,14 @@ static int hsit_set_format(struct v4l2_subdev *subdev,
                           struct v4l2_subdev_format *fmt)
 {
        struct vsp1_hsit *hsit = to_hsit(subdev);
+       struct v4l2_subdev_pad_config *config;
        struct v4l2_mbus_framefmt *format;
 
-       format = vsp1_entity_get_pad_format(&hsit->entity, cfg, fmt->pad,
-                                           fmt->which);
+       config = vsp1_entity_get_pad_config(&hsit->entity, cfg, fmt->which);
+       if (!config)
+               return -EINVAL;
+
+       format = vsp1_entity_get_pad_format(&hsit->entity, config, fmt->pad);
 
        if (fmt->pad == HSIT_PAD_SOURCE) {
                /* The HST and HSI output format code and resolution can't be
@@ -145,8 +98,8 @@ static int hsit_set_format(struct v4l2_subdev *subdev,
        fmt->format = *format;
 
        /* Propagate the format to the source pad. */
-       format = vsp1_entity_get_pad_format(&hsit->entity, cfg, HSIT_PAD_SOURCE,
-                                           fmt->which);
+       format = vsp1_entity_get_pad_format(&hsit->entity, config,
+                                           HSIT_PAD_SOURCE);
        *format = fmt->format;
        format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32
                     : MEDIA_BUS_FMT_AHSV8888_1X32;
@@ -154,33 +107,44 @@ static int hsit_set_format(struct v4l2_subdev *subdev,
        return 0;
 }
 
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Operations
- */
-
-static struct v4l2_subdev_video_ops hsit_video_ops = {
-       .s_stream = hsit_s_stream,
-};
-
 static struct v4l2_subdev_pad_ops hsit_pad_ops = {
+       .init_cfg = vsp1_entity_init_cfg,
        .enum_mbus_code = hsit_enum_mbus_code,
        .enum_frame_size = hsit_enum_frame_size,
-       .get_fmt = hsit_get_format,
+       .get_fmt = vsp1_subdev_get_pad_format,
        .set_fmt = hsit_set_format,
 };
 
 static struct v4l2_subdev_ops hsit_ops = {
-       .video  = &hsit_video_ops,
        .pad    = &hsit_pad_ops,
 };
 
+/* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
+
+static void hsit_configure(struct vsp1_entity *entity,
+                          struct vsp1_pipeline *pipe,
+                          struct vsp1_dl_list *dl)
+{
+       struct vsp1_hsit *hsit = to_hsit(&entity->subdev);
+
+       if (hsit->inverse)
+               vsp1_hsit_write(hsit, dl, VI6_HSI_CTRL, VI6_HSI_CTRL_EN);
+       else
+               vsp1_hsit_write(hsit, dl, VI6_HST_CTRL, VI6_HST_CTRL_EN);
+}
+
+static const struct vsp1_entity_operations hsit_entity_ops = {
+       .configure = hsit_configure,
+};
+
 /* -----------------------------------------------------------------------------
  * Initialization and Cleanup
  */
 
 struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse)
 {
-       struct v4l2_subdev *subdev;
        struct vsp1_hsit *hsit;
        int ret;
 
@@ -190,27 +154,17 @@ struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse)
 
        hsit->inverse = inverse;
 
+       hsit->entity.ops = &hsit_entity_ops;
+
        if (inverse)
                hsit->entity.type = VSP1_ENTITY_HSI;
        else
                hsit->entity.type = VSP1_ENTITY_HST;
 
-       ret = vsp1_entity_init(vsp1, &hsit->entity, 2);
+       ret = vsp1_entity_init(vsp1, &hsit->entity, inverse ? "hsi" : "hst", 2,
+                              &hsit_ops);
        if (ret < 0)
                return ERR_PTR(ret);
 
-       /* Initialize the V4L2 subdev. */
-       subdev = &hsit->entity.subdev;
-       v4l2_subdev_init(subdev, &hsit_ops);
-
-       subdev->entity.ops = &vsp1->media_ops;
-       subdev->internal_ops = &vsp1_subdev_internal_ops;
-       snprintf(subdev->name, sizeof(subdev->name), "%s %s",
-                dev_name(vsp1->dev), inverse ? "hsi" : "hst");
-       v4l2_set_subdevdata(subdev, hsit);
-       subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-       vsp1_entity_init_formats(subdev, NULL);
-
        return hsit;
 }
index 433853c..0217393 100644 (file)
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
 #include "vsp1_lif.h"
 
 #define LIF_MIN_SIZE                           2U
-#define LIF_MAX_SIZE                           2048U
+#define LIF_MAX_SIZE                           8190U
 
 /* -----------------------------------------------------------------------------
  * Device Access
  */
 
-static inline void vsp1_lif_write(struct vsp1_lif *lif, u32 reg, u32 data)
+static inline void vsp1_lif_write(struct vsp1_lif *lif, struct vsp1_dl_list *dl,
+                                 u32 reg, u32 data)
 {
-       vsp1_mod_write(&lif->entity, reg, data);
+       vsp1_dl_list_write(dl, reg, data);
 }
 
 /* -----------------------------------------------------------------------------
- * V4L2 Subdevice Core Operations
- */
-
-static int lif_s_stream(struct v4l2_subdev *subdev, int enable)
-{
-       const struct v4l2_mbus_framefmt *format;
-       struct vsp1_lif *lif = to_lif(subdev);
-       unsigned int hbth = 1300;
-       unsigned int obth = 400;
-       unsigned int lbth = 200;
-
-       if (!enable) {
-               vsp1_write(lif->entity.vsp1, VI6_LIF_CTRL, 0);
-               return 0;
-       }
-
-       format = &lif->entity.formats[LIF_PAD_SOURCE];
-
-       obth = min(obth, (format->width + 1) / 2 * format->height - 4);
-
-       vsp1_lif_write(lif, VI6_LIF_CSBTH,
-                       (hbth << VI6_LIF_CSBTH_HBTH_SHIFT) |
-                       (lbth << VI6_LIF_CSBTH_LBTH_SHIFT));
-
-       vsp1_lif_write(lif, VI6_LIF_CTRL,
-                       (obth << VI6_LIF_CTRL_OBTH_SHIFT) |
-                       (format->code == 0 ? VI6_LIF_CTRL_CFMT : 0) |
-                       VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN);
-
-       return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Pad Operations
+ * V4L2 Subdevice Operations
  */
 
 static int lif_enum_mbus_code(struct v4l2_subdev *subdev,
@@ -76,82 +45,38 @@ static int lif_enum_mbus_code(struct v4l2_subdev *subdev,
                MEDIA_BUS_FMT_ARGB8888_1X32,
                MEDIA_BUS_FMT_AYUV8_1X32,
        };
-       struct vsp1_lif *lif = to_lif(subdev);
 
-       if (code->pad == LIF_PAD_SINK) {
-               if (code->index >= ARRAY_SIZE(codes))
-                       return -EINVAL;
-
-               code->code = codes[code->index];
-       } else {
-               struct v4l2_mbus_framefmt *format;
-
-               /* The LIF can't perform format conversion, the sink format is
-                * always identical to the source format.
-                */
-               if (code->index)
-                       return -EINVAL;
-
-               format = vsp1_entity_get_pad_format(&lif->entity, cfg,
-                                                   LIF_PAD_SINK, code->which);
-               code->code = format->code;
-       }
-
-       return 0;
+       return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes,
+                                         ARRAY_SIZE(codes));
 }
 
 static int lif_enum_frame_size(struct v4l2_subdev *subdev,
                               struct v4l2_subdev_pad_config *cfg,
                               struct v4l2_subdev_frame_size_enum *fse)
 {
-       struct vsp1_lif *lif = to_lif(subdev);
-       struct v4l2_mbus_framefmt *format;
-
-       format = vsp1_entity_get_pad_format(&lif->entity, cfg, LIF_PAD_SINK,
-                                           fse->which);
-
-       if (fse->index || fse->code != format->code)
-               return -EINVAL;
-
-       if (fse->pad == LIF_PAD_SINK) {
-               fse->min_width = LIF_MIN_SIZE;
-               fse->max_width = LIF_MAX_SIZE;
-               fse->min_height = LIF_MIN_SIZE;
-               fse->max_height = LIF_MAX_SIZE;
-       } else {
-               fse->min_width = format->width;
-               fse->max_width = format->width;
-               fse->min_height = format->height;
-               fse->max_height = format->height;
-       }
-
-       return 0;
+       return vsp1_subdev_enum_frame_size(subdev, cfg, fse, LIF_MIN_SIZE,
+                                          LIF_MIN_SIZE, LIF_MAX_SIZE,
+                                          LIF_MAX_SIZE);
 }
 
-static int lif_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
-                         struct v4l2_subdev_format *fmt)
-{
-       struct vsp1_lif *lif = to_lif(subdev);
-
-       fmt->format = *vsp1_entity_get_pad_format(&lif->entity, cfg, fmt->pad,
-                                                 fmt->which);
-
-       return 0;
-}
-
-static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int lif_set_format(struct v4l2_subdev *subdev,
+                         struct v4l2_subdev_pad_config *cfg,
                          struct v4l2_subdev_format *fmt)
 {
        struct vsp1_lif *lif = to_lif(subdev);
+       struct v4l2_subdev_pad_config *config;
        struct v4l2_mbus_framefmt *format;
 
+       config = vsp1_entity_get_pad_config(&lif->entity, cfg, fmt->which);
+       if (!config)
+               return -EINVAL;
+
        /* Default to YUV if the requested format is not supported. */
        if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
            fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
                fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
 
-       format = vsp1_entity_get_pad_format(&lif->entity, cfg, fmt->pad,
-                                           fmt->which);
+       format = vsp1_entity_get_pad_format(&lif->entity, config, fmt->pad);
 
        if (fmt->pad == LIF_PAD_SOURCE) {
                /* The LIF source format is always identical to its sink
@@ -172,40 +97,64 @@ static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con
        fmt->format = *format;
 
        /* Propagate the format to the source pad. */
-       format = vsp1_entity_get_pad_format(&lif->entity, cfg, LIF_PAD_SOURCE,
-                                           fmt->which);
+       format = vsp1_entity_get_pad_format(&lif->entity, config,
+                                           LIF_PAD_SOURCE);
        *format = fmt->format;
 
        return 0;
 }
 
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Operations
- */
-
-static struct v4l2_subdev_video_ops lif_video_ops = {
-       .s_stream = lif_s_stream,
-};
-
 static struct v4l2_subdev_pad_ops lif_pad_ops = {
+       .init_cfg = vsp1_entity_init_cfg,
        .enum_mbus_code = lif_enum_mbus_code,
        .enum_frame_size = lif_enum_frame_size,
-       .get_fmt = lif_get_format,
+       .get_fmt = vsp1_subdev_get_pad_format,
        .set_fmt = lif_set_format,
 };
 
 static struct v4l2_subdev_ops lif_ops = {
-       .video  = &lif_video_ops,
        .pad    = &lif_pad_ops,
 };
 
+/* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
+
+static void lif_configure(struct vsp1_entity *entity,
+                         struct vsp1_pipeline *pipe,
+                         struct vsp1_dl_list *dl)
+{
+       const struct v4l2_mbus_framefmt *format;
+       struct vsp1_lif *lif = to_lif(&entity->subdev);
+       unsigned int hbth = 1300;
+       unsigned int obth = 400;
+       unsigned int lbth = 200;
+
+       format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config,
+                                           LIF_PAD_SOURCE);
+
+       obth = min(obth, (format->width + 1) / 2 * format->height - 4);
+
+       vsp1_lif_write(lif, dl, VI6_LIF_CSBTH,
+                       (hbth << VI6_LIF_CSBTH_HBTH_SHIFT) |
+                       (lbth << VI6_LIF_CSBTH_LBTH_SHIFT));
+
+       vsp1_lif_write(lif, dl, VI6_LIF_CTRL,
+                       (obth << VI6_LIF_CTRL_OBTH_SHIFT) |
+                       (format->code == 0 ? VI6_LIF_CTRL_CFMT : 0) |
+                       VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN);
+}
+
+static const struct vsp1_entity_operations lif_entity_ops = {
+       .configure = lif_configure,
+};
+
 /* -----------------------------------------------------------------------------
  * Initialization and Cleanup
  */
 
 struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1)
 {
-       struct v4l2_subdev *subdev;
        struct vsp1_lif *lif;
        int ret;
 
@@ -213,24 +162,12 @@ struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1)
        if (lif == NULL)
                return ERR_PTR(-ENOMEM);
 
+       lif->entity.ops = &lif_entity_ops;
        lif->entity.type = VSP1_ENTITY_LIF;
 
-       ret = vsp1_entity_init(vsp1, &lif->entity, 2);
+       ret = vsp1_entity_init(vsp1, &lif->entity, "lif", 2, &lif_ops);
        if (ret < 0)
                return ERR_PTR(ret);
 
-       /* Initialize the V4L2 subdev. */
-       subdev = &lif->entity.subdev;
-       v4l2_subdev_init(subdev, &lif_ops);
-
-       subdev->entity.ops = &vsp1->media_ops;
-       subdev->internal_ops = &vsp1_subdev_internal_ops;
-       snprintf(subdev->name, sizeof(subdev->name), "%s lif",
-                dev_name(vsp1->dev));
-       v4l2_set_subdevdata(subdev, lif);
-       subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-       vsp1_entity_init_formats(subdev, NULL);
-
        return lif;
 }
index 4b89095..aa09e59 100644 (file)
@@ -18,6 +18,7 @@
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
 #include "vsp1_lut.h"
 
 #define LUT_MIN_SIZE                           4U
  * Device Access
  */
 
-static inline void vsp1_lut_write(struct vsp1_lut *lut, u32 reg, u32 data)
+static inline void vsp1_lut_write(struct vsp1_lut *lut, struct vsp1_dl_list *dl,
+                                 u32 reg, u32 data)
 {
-       vsp1_write(lut->entity.vsp1, reg, data);
+       vsp1_dl_list_write(dl, reg, data);
 }
 
 /* -----------------------------------------------------------------------------
  * V4L2 Subdevice Core Operations
  */
 
-static void lut_configure(struct vsp1_lut *lut, struct vsp1_lut_config *config)
+static int lut_set_table(struct vsp1_lut *lut, struct vsp1_lut_config *config)
 {
-       memcpy_toio(lut->entity.vsp1->mmio + VI6_LUT_TABLE, config->lut,
-                   sizeof(config->lut));
+       struct vsp1_dl_body *dlb;
+       unsigned int i;
+
+       dlb = vsp1_dl_fragment_alloc(lut->entity.vsp1, ARRAY_SIZE(config->lut));
+       if (!dlb)
+               return -ENOMEM;
+
+       for (i = 0; i < ARRAY_SIZE(config->lut); ++i)
+               vsp1_dl_fragment_write(dlb, VI6_LUT_TABLE + 4 * i,
+                                      config->lut[i]);
+
+       mutex_lock(&lut->lock);
+       swap(lut->lut, dlb);
+       mutex_unlock(&lut->lock);
+
+       vsp1_dl_fragment_free(dlb);
+       return 0;
 }
 
 static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg)
@@ -48,30 +65,13 @@ static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg)
 
        switch (cmd) {
        case VIDIOC_VSP1_LUT_CONFIG:
-               lut_configure(lut, arg);
-               return 0;
+               return lut_set_table(lut, arg);
 
        default:
                return -ENOIOCTLCMD;
        }
 }
 
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Video Operations
- */
-
-static int lut_s_stream(struct v4l2_subdev *subdev, int enable)
-{
-       struct vsp1_lut *lut = to_lut(subdev);
-
-       if (!enable)
-               return 0;
-
-       vsp1_lut_write(lut, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
-
-       return 0;
-}
-
 /* -----------------------------------------------------------------------------
  * V4L2 Subdevice Pad Operations
  */
@@ -85,85 +85,39 @@ static int lut_enum_mbus_code(struct v4l2_subdev *subdev,
                MEDIA_BUS_FMT_AHSV8888_1X32,
                MEDIA_BUS_FMT_AYUV8_1X32,
        };
-       struct vsp1_lut *lut = to_lut(subdev);
-       struct v4l2_mbus_framefmt *format;
-
-       if (code->pad == LUT_PAD_SINK) {
-               if (code->index >= ARRAY_SIZE(codes))
-                       return -EINVAL;
-
-               code->code = codes[code->index];
-       } else {
-               /* The LUT can't perform format conversion, the sink format is
-                * always identical to the source format.
-                */
-               if (code->index)
-                       return -EINVAL;
-
-               format = vsp1_entity_get_pad_format(&lut->entity, cfg,
-                                                   LUT_PAD_SINK, code->which);
-               code->code = format->code;
-       }
 
-       return 0;
+       return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes,
+                                         ARRAY_SIZE(codes));
 }
 
 static int lut_enum_frame_size(struct v4l2_subdev *subdev,
                               struct v4l2_subdev_pad_config *cfg,
                               struct v4l2_subdev_frame_size_enum *fse)
 {
-       struct vsp1_lut *lut = to_lut(subdev);
-       struct v4l2_mbus_framefmt *format;
-
-       format = vsp1_entity_get_pad_format(&lut->entity, cfg,
-                                           fse->pad, fse->which);
-
-       if (fse->index || fse->code != format->code)
-               return -EINVAL;
-
-       if (fse->pad == LUT_PAD_SINK) {
-               fse->min_width = LUT_MIN_SIZE;
-               fse->max_width = LUT_MAX_SIZE;
-               fse->min_height = LUT_MIN_SIZE;
-               fse->max_height = LUT_MAX_SIZE;
-       } else {
-               /* The size on the source pad are fixed and always identical to
-                * the size on the sink pad.
-                */
-               fse->min_width = format->width;
-               fse->max_width = format->width;
-               fse->min_height = format->height;
-               fse->max_height = format->height;
-       }
-
-       return 0;
-}
-
-static int lut_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
-                         struct v4l2_subdev_format *fmt)
-{
-       struct vsp1_lut *lut = to_lut(subdev);
-
-       fmt->format = *vsp1_entity_get_pad_format(&lut->entity, cfg, fmt->pad,
-                                                 fmt->which);
-
-       return 0;
+       return vsp1_subdev_enum_frame_size(subdev, cfg, fse, LUT_MIN_SIZE,
+                                          LUT_MIN_SIZE, LUT_MAX_SIZE,
+                                          LUT_MAX_SIZE);
 }
 
-static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int lut_set_format(struct v4l2_subdev *subdev,
+                         struct v4l2_subdev_pad_config *cfg,
                          struct v4l2_subdev_format *fmt)
 {
        struct vsp1_lut *lut = to_lut(subdev);
+       struct v4l2_subdev_pad_config *config;
        struct v4l2_mbus_framefmt *format;
 
+       config = vsp1_entity_get_pad_config(&lut->entity, cfg, fmt->which);
+       if (!config)
+               return -EINVAL;
+
        /* Default to YUV if the requested format is not supported. */
        if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
            fmt->format.code != MEDIA_BUS_FMT_AHSV8888_1X32 &&
            fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
                fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
 
-       format = vsp1_entity_get_pad_format(&lut->entity, cfg, fmt->pad,
-                                           fmt->which);
+       format = vsp1_entity_get_pad_format(&lut->entity, config, fmt->pad);
 
        if (fmt->pad == LUT_PAD_SOURCE) {
                /* The LUT output format can't be modified. */
@@ -171,6 +125,7 @@ static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con
                return 0;
        }
 
+       format->code = fmt->format.code;
        format->width = clamp_t(unsigned int, fmt->format.width,
                                LUT_MIN_SIZE, LUT_MAX_SIZE);
        format->height = clamp_t(unsigned int, fmt->format.height,
@@ -181,8 +136,8 @@ static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con
        fmt->format = *format;
 
        /* Propagate the format to the source pad. */
-       format = vsp1_entity_get_pad_format(&lut->entity, cfg, LUT_PAD_SOURCE,
-                                           fmt->which);
+       format = vsp1_entity_get_pad_format(&lut->entity, config,
+                                           LUT_PAD_SOURCE);
        *format = fmt->format;
 
        return 0;
@@ -196,30 +151,49 @@ static struct v4l2_subdev_core_ops lut_core_ops = {
        .ioctl = lut_ioctl,
 };
 
-static struct v4l2_subdev_video_ops lut_video_ops = {
-       .s_stream = lut_s_stream,
-};
-
 static struct v4l2_subdev_pad_ops lut_pad_ops = {
+       .init_cfg = vsp1_entity_init_cfg,
        .enum_mbus_code = lut_enum_mbus_code,
        .enum_frame_size = lut_enum_frame_size,
-       .get_fmt = lut_get_format,
+       .get_fmt = vsp1_subdev_get_pad_format,
        .set_fmt = lut_set_format,
 };
 
 static struct v4l2_subdev_ops lut_ops = {
        .core   = &lut_core_ops,
-       .video  = &lut_video_ops,
        .pad    = &lut_pad_ops,
 };
 
+/* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
+
+static void lut_configure(struct vsp1_entity *entity,
+                         struct vsp1_pipeline *pipe,
+                         struct vsp1_dl_list *dl)
+{
+       struct vsp1_lut *lut = to_lut(&entity->subdev);
+
+       vsp1_lut_write(lut, dl, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
+
+       mutex_lock(&lut->lock);
+       if (lut->lut) {
+               vsp1_dl_list_add_fragment(dl, lut->lut);
+               lut->lut = NULL;
+       }
+       mutex_unlock(&lut->lock);
+}
+
+static const struct vsp1_entity_operations lut_entity_ops = {
+       .configure = lut_configure,
+};
+
 /* -----------------------------------------------------------------------------
  * Initialization and Cleanup
  */
 
 struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1)
 {
-       struct v4l2_subdev *subdev;
        struct vsp1_lut *lut;
        int ret;
 
@@ -227,24 +201,12 @@ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1)
        if (lut == NULL)
                return ERR_PTR(-ENOMEM);
 
+       lut->entity.ops = &lut_entity_ops;
        lut->entity.type = VSP1_ENTITY_LUT;
 
-       ret = vsp1_entity_init(vsp1, &lut->entity, 2);
+       ret = vsp1_entity_init(vsp1, &lut->entity, "lut", 2, &lut_ops);
        if (ret < 0)
                return ERR_PTR(ret);
 
-       /* Initialize the V4L2 subdev. */
-       subdev = &lut->entity.subdev;
-       v4l2_subdev_init(subdev, &lut_ops);
-
-       subdev->entity.ops = &vsp1->media_ops;
-       subdev->internal_ops = &vsp1_subdev_internal_ops;
-       snprintf(subdev->name, sizeof(subdev->name), "%s lut",
-                dev_name(vsp1->dev));
-       v4l2_set_subdevdata(subdev, lut);
-       subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-       vsp1_entity_init_formats(subdev, NULL);
-
        return lut;
 }
index f92ffb8..cef874f 100644 (file)
@@ -13,6 +13,8 @@
 #ifndef __VSP1_LUT_H__
 #define __VSP1_LUT_H__
 
+#include <linux/mutex.h>
+
 #include <media/media-entity.h>
 #include <media/v4l2-subdev.h>
 
@@ -25,7 +27,9 @@ struct vsp1_device;
 
 struct vsp1_lut {
        struct vsp1_entity entity;
-       u32 lut[256];
+
+       struct mutex lock;
+       struct vsp1_dl_body *lut;
 };
 
 static inline struct vsp1_lut *to_lut(struct v4l2_subdev *subdev)
index 6659f06..4f3b4a1 100644 (file)
@@ -43,7 +43,7 @@ static const struct vsp1_format_info vsp1_video_formats[] = {
        { V4L2_PIX_FMT_XRGB444, MEDIA_BUS_FMT_ARGB8888_1X32,
          VI6_FMT_XRGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
          VI6_RPF_DSWAP_P_WDS,
-         1, { 16, 0, 0 }, false, false, 1, 1, true },
+         1, { 16, 0, 0 }, false, false, 1, 1, false },
        { V4L2_PIX_FMT_ARGB555, MEDIA_BUS_FMT_ARGB8888_1X32,
          VI6_FMT_ARGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
          VI6_RPF_DSWAP_P_WDS,
@@ -172,14 +172,18 @@ void vsp1_pipeline_reset(struct vsp1_pipeline *pipe)
                        bru->inputs[i].rpf = NULL;
        }
 
-       for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i)
+       for (i = 0; i < pipe->num_inputs; ++i) {
+               pipe->inputs[i]->pipe = NULL;
                pipe->inputs[i] = NULL;
+       }
+
+       pipe->output->pipe = NULL;
+       pipe->output = NULL;
 
        INIT_LIST_HEAD(&pipe->entities);
        pipe->state = VSP1_PIPELINE_STOPPED;
        pipe->buffers_ready = 0;
        pipe->num_inputs = 0;
-       pipe->output = NULL;
        pipe->bru = NULL;
        pipe->lif = NULL;
        pipe->uds = NULL;
@@ -190,11 +194,13 @@ void vsp1_pipeline_init(struct vsp1_pipeline *pipe)
        mutex_init(&pipe->lock);
        spin_lock_init(&pipe->irqlock);
        init_waitqueue_head(&pipe->wq);
+       kref_init(&pipe->kref);
 
        INIT_LIST_HEAD(&pipe->entities);
        pipe->state = VSP1_PIPELINE_STOPPED;
 }
 
+/* Must be called with the pipe irqlock held. */
 void vsp1_pipeline_run(struct vsp1_pipeline *pipe)
 {
        struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
@@ -226,7 +232,7 @@ int vsp1_pipeline_stop(struct vsp1_pipeline *pipe)
        unsigned long flags;
        int ret;
 
-       if (pipe->dl) {
+       if (pipe->lif) {
                /* When using display lists in continuous frame mode the only
                 * way to stop the pipeline is to reset the hardware.
                 */
@@ -253,10 +259,10 @@ int vsp1_pipeline_stop(struct vsp1_pipeline *pipe)
                if (entity->route && entity->route->reg)
                        vsp1_write(entity->vsp1, entity->route->reg,
                                   VI6_DPR_NODE_UNUSED);
-
-               v4l2_subdev_call(&entity->subdev, video, s_stream, 0);
        }
 
+       v4l2_subdev_call(&pipe->output->entity.subdev, video, s_stream, 0);
+
        return ret;
 }
 
@@ -271,50 +277,15 @@ bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe)
        return pipe->buffers_ready == mask;
 }
 
-void vsp1_pipeline_display_start(struct vsp1_pipeline *pipe)
-{
-       if (pipe->dl)
-               vsp1_dl_irq_display_start(pipe->dl);
-}
-
 void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
 {
-       enum vsp1_pipeline_state state;
-       unsigned long flags;
-
        if (pipe == NULL)
                return;
 
-       if (pipe->dl)
-               vsp1_dl_irq_frame_end(pipe->dl);
+       vsp1_dlm_irq_frame_end(pipe->output->dlm);
 
-       /* Signal frame end to the pipeline handler. */
-       pipe->frame_end(pipe);
-
-       spin_lock_irqsave(&pipe->irqlock, flags);
-
-       state = pipe->state;
-
-       /* When using display lists in continuous frame mode the pipeline is
-        * automatically restarted by the hardware.
-        */
-       if (!pipe->dl)
-               pipe->state = VSP1_PIPELINE_STOPPED;
-
-       /* If a stop has been requested, mark the pipeline as stopped and
-        * return.
-        */
-       if (state == VSP1_PIPELINE_STOPPING) {
-               wake_up(&pipe->wq);
-               goto done;
-       }
-
-       /* Restart the pipeline if ready. */
-       if (vsp1_pipeline_ready(pipe))
-               vsp1_pipeline_run(pipe);
-
-done:
-       spin_unlock_irqrestore(&pipe->irqlock, flags);
+       if (pipe->frame_end)
+               pipe->frame_end(pipe);
 }
 
 /*
@@ -324,9 +295,13 @@ done:
  * to be scaled, we disable alpha scaling when the UDS input has a fixed alpha
  * value. The UDS then outputs a fixed alpha value which needs to be programmed
  * from the input RPF alpha.
+ *
+ * This function can only be called from a subdev s_stream handler as it
+ * requires a valid display list context.
  */
 void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
                                   struct vsp1_entity *input,
+                                  struct vsp1_dl_list *dl,
                                   unsigned int alpha)
 {
        struct vsp1_entity *entity;
@@ -349,7 +324,7 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
                if (entity->type == VSP1_ENTITY_UDS) {
                        struct vsp1_uds *uds = to_uds(&entity->subdev);
 
-                       vsp1_uds_set_alpha(uds, alpha);
+                       vsp1_uds_set_alpha(uds, dl, alpha);
                        break;
                }
 
@@ -375,7 +350,7 @@ void vsp1_pipelines_suspend(struct vsp1_device *vsp1)
                if (wpf == NULL)
                        continue;
 
-               pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity);
+               pipe = wpf->pipe;
                if (pipe == NULL)
                        continue;
 
@@ -392,7 +367,7 @@ void vsp1_pipelines_suspend(struct vsp1_device *vsp1)
                if (wpf == NULL)
                        continue;
 
-               pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity);
+               pipe = wpf->pipe;
                if (pipe == NULL)
                        continue;
 
@@ -416,7 +391,7 @@ void vsp1_pipelines_resume(struct vsp1_device *vsp1)
                if (wpf == NULL)
                        continue;
 
-               pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity);
+               pipe = wpf->pipe;
                if (pipe == NULL)
                        continue;
 
index b2f3a8a..7b56113 100644 (file)
 #ifndef __VSP1_PIPE_H__
 #define __VSP1_PIPE_H__
 
+#include <linux/kref.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
 
 #include <media/media-entity.h>
 
-struct vsp1_dl;
+struct vsp1_dl_list;
 struct vsp1_rwpf;
 
 /*
@@ -63,7 +64,7 @@ enum vsp1_pipeline_state {
  * @wq: work queue to wait for state change completion
  * @frame_end: frame end interrupt handler
  * @lock: protects the pipeline use count and stream count
- * @use_count: number of video nodes using the pipeline
+ * @kref: pipeline reference count
  * @stream_count: number of streaming video nodes
  * @buffers_ready: bitmask of RPFs and WPFs with at least one buffer available
  * @num_inputs: number of RPFs
@@ -86,7 +87,7 @@ struct vsp1_pipeline {
        void (*frame_end)(struct vsp1_pipeline *pipe);
 
        struct mutex lock;
-       unsigned int use_count;
+       struct kref kref;
        unsigned int stream_count;
        unsigned int buffers_ready;
 
@@ -100,17 +101,9 @@ struct vsp1_pipeline {
 
        struct list_head entities;
 
-       struct vsp1_dl *dl;
+       struct vsp1_dl_list *dl;
 };
 
-static inline struct vsp1_pipeline *to_vsp1_pipeline(struct media_entity *e)
-{
-       if (likely(e->pipe))
-               return container_of(e->pipe, struct vsp1_pipeline, pipe);
-       else
-               return NULL;
-}
-
 void vsp1_pipeline_reset(struct vsp1_pipeline *pipe);
 void vsp1_pipeline_init(struct vsp1_pipeline *pipe);
 
@@ -119,11 +112,11 @@ bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe);
 int vsp1_pipeline_stop(struct vsp1_pipeline *pipe);
 bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe);
 
-void vsp1_pipeline_display_start(struct vsp1_pipeline *pipe);
 void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe);
 
 void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
                                   struct vsp1_entity *input,
+                                  struct vsp1_dl_list *dl,
                                   unsigned int alpha);
 
 void vsp1_pipelines_suspend(struct vsp1_device *vsp1);
index 069216f..927b5fb 100644 (file)
 #define VI6_RPF_SRCM_ADDR_C1           0x0344
 #define VI6_RPF_SRCM_ADDR_AI           0x0348
 
+#define VI6_RPF_MULT_ALPHA             0x036c
+#define VI6_RPF_MULT_ALPHA_A_MMD_NONE  (0 << 12)
+#define VI6_RPF_MULT_ALPHA_A_MMD_RATIO (1 << 12)
+#define VI6_RPF_MULT_ALPHA_P_MMD_NONE  (0 << 8)
+#define VI6_RPF_MULT_ALPHA_P_MMD_RATIO (1 << 8)
+#define VI6_RPF_MULT_ALPHA_P_MMD_IMAGE (2 << 8)
+#define VI6_RPF_MULT_ALPHA_P_MMD_BOTH  (3 << 8)
+#define VI6_RPF_MULT_ALPHA_RATIO_MASK  (0xff < 0)
+#define VI6_RPF_MULT_ALPHA_RATIO_SHIFT 0
+
 /* -----------------------------------------------------------------------------
  * WPF Control Registers
  */
index 5bc1d15..49168db 100644 (file)
@@ -16,6 +16,8 @@
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
+#include "vsp1_pipe.h"
 #include "vsp1_rwpf.h"
 #include "vsp1_video.h"
 
  * Device Access
  */
 
-static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, u32 reg, u32 data)
+static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf,
+                                 struct vsp1_dl_list *dl, u32 reg, u32 data)
 {
-       vsp1_mod_write(&rpf->entity, reg + rpf->entity.index * VI6_RPF_OFFSET,
-                      data);
+       vsp1_dl_list_write(dl, reg + rpf->entity.index * VI6_RPF_OFFSET, data);
 }
 
 /* -----------------------------------------------------------------------------
- * Controls
+ * V4L2 Subdevice Operations
  */
 
-static int rpf_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct vsp1_rwpf *rpf =
-               container_of(ctrl->handler, struct vsp1_rwpf, ctrls);
-       struct vsp1_pipeline *pipe;
-
-       if (!vsp1_entity_is_streaming(&rpf->entity))
-               return 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_ALPHA_COMPONENT:
-               vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET,
-                              ctrl->val << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
-
-               pipe = to_vsp1_pipeline(&rpf->entity.subdev.entity);
-               vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, ctrl->val);
-               break;
-       }
-
-       return 0;
-}
-
-static const struct v4l2_ctrl_ops rpf_ctrl_ops = {
-       .s_ctrl = rpf_s_ctrl,
+static struct v4l2_subdev_ops rpf_ops = {
+       .pad    = &vsp1_rwpf_pad_ops,
 };
 
 /* -----------------------------------------------------------------------------
- * V4L2 Subdevice Core Operations
+ * VSP1 Entity Operations
  */
 
-static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
+static void rpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl)
+{
+       struct vsp1_rwpf *rpf = entity_to_rwpf(entity);
+
+       vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_Y,
+                      rpf->mem.addr[0] + rpf->offsets[0]);
+       vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C0,
+                      rpf->mem.addr[1] + rpf->offsets[1]);
+       vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C1,
+                      rpf->mem.addr[2] + rpf->offsets[1]);
+}
+
+static void rpf_configure(struct vsp1_entity *entity,
+                         struct vsp1_pipeline *pipe,
+                         struct vsp1_dl_list *dl)
 {
-       struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity);
-       struct vsp1_rwpf *rpf = to_rwpf(subdev);
-       struct vsp1_device *vsp1 = rpf->entity.vsp1;
+       struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
        const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
        const struct v4l2_pix_format_mplane *format = &rpf->format;
-       const struct v4l2_rect *crop = &rpf->crop;
+       const struct v4l2_mbus_framefmt *source_format;
+       const struct v4l2_mbus_framefmt *sink_format;
+       const struct v4l2_rect *crop;
+       unsigned int left = 0;
+       unsigned int top = 0;
        u32 pstride;
        u32 infmt;
-       int ret;
-
-       ret = vsp1_entity_set_streaming(&rpf->entity, enable);
-       if (ret < 0)
-               return ret;
-
-       if (!enable)
-               return 0;
 
        /* Source size, stride and crop offsets.
         *
@@ -91,10 +79,12 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
         * left corner in the plane buffer. Only two offsets are needed, as
         * planes 2 and 3 always have identical strides.
         */
-       vsp1_rpf_write(rpf, VI6_RPF_SRC_BSIZE,
+       crop = vsp1_rwpf_get_crop(rpf, rpf->entity.config);
+
+       vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_BSIZE,
                       (crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
                       (crop->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
-       vsp1_rpf_write(rpf, VI6_RPF_SRC_ESIZE,
+       vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_ESIZE,
                       (crop->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
                       (crop->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));
 
@@ -103,26 +93,25 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
        pstride = format->plane_fmt[0].bytesperline
                << VI6_RPF_SRCM_PSTRIDE_Y_SHIFT;
 
-       vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
-                      rpf->buf_addr[0] + rpf->offsets[0]);
-
        if (format->num_planes > 1) {
                rpf->offsets[1] = crop->top * format->plane_fmt[1].bytesperline
                                + crop->left * fmtinfo->bpp[1] / 8;
                pstride |= format->plane_fmt[1].bytesperline
                        << VI6_RPF_SRCM_PSTRIDE_C_SHIFT;
-
-               vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
-                              rpf->buf_addr[1] + rpf->offsets[1]);
-
-               if (format->num_planes > 2)
-                       vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
-                                      rpf->buf_addr[2] + rpf->offsets[1]);
+       } else {
+               rpf->offsets[1] = 0;
        }
 
-       vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride);
+       vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_PSTRIDE, pstride);
 
        /* Format */
+       sink_format = vsp1_entity_get_pad_format(&rpf->entity,
+                                                rpf->entity.config,
+                                                RWPF_PAD_SINK);
+       source_format = vsp1_entity_get_pad_format(&rpf->entity,
+                                                  rpf->entity.config,
+                                                  RWPF_PAD_SOURCE);
+
        infmt = VI6_RPF_INFMT_CIPM
              | (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT);
 
@@ -131,88 +120,98 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
        if (fmtinfo->swap_uv)
                infmt |= VI6_RPF_INFMT_SPUVS;
 
-       if (rpf->entity.formats[RWPF_PAD_SINK].code !=
-           rpf->entity.formats[RWPF_PAD_SOURCE].code)
+       if (sink_format->code != source_format->code)
                infmt |= VI6_RPF_INFMT_CSC;
 
-       vsp1_rpf_write(rpf, VI6_RPF_INFMT, infmt);
-       vsp1_rpf_write(rpf, VI6_RPF_DSWAP, fmtinfo->swap);
+       vsp1_rpf_write(rpf, dl, VI6_RPF_INFMT, infmt);
+       vsp1_rpf_write(rpf, dl, VI6_RPF_DSWAP, fmtinfo->swap);
 
        /* Output location */
-       vsp1_rpf_write(rpf, VI6_RPF_LOC,
-                      (rpf->location.left << VI6_RPF_LOC_HCOORD_SHIFT) |
-                      (rpf->location.top << VI6_RPF_LOC_VCOORD_SHIFT));
+       if (pipe->bru) {
+               const struct v4l2_rect *compose;
+
+               compose = vsp1_entity_get_pad_compose(pipe->bru,
+                                                     pipe->bru->config,
+                                                     rpf->bru_input);
+               left = compose->left;
+               top = compose->top;
+       }
 
-       /* Use the alpha channel (extended to 8 bits) when available or an
-        * alpha value set through the V4L2_CID_ALPHA_COMPONENT control
-        * otherwise. Disable color keying.
+       vsp1_rpf_write(rpf, dl, VI6_RPF_LOC,
+                      (left << VI6_RPF_LOC_HCOORD_SHIFT) |
+                      (top << VI6_RPF_LOC_VCOORD_SHIFT));
+
+       /* On Gen2 use the alpha channel (extended to 8 bits) when available or
+        * a fixed alpha value set through the V4L2_CID_ALPHA_COMPONENT control
+        * otherwise.
+        *
+        * The Gen3 RPF has extended alpha capability and can both multiply the
+        * alpha channel by a fixed global alpha value, and multiply the pixel
+        * components to convert the input to premultiplied alpha.
+        *
+        * As alpha premultiplication is available in the BRU for both Gen2 and
+        * Gen3 we handle it there and use the Gen3 alpha multiplier for global
+        * alpha multiplication only. This however prevents conversion to
+        * premultiplied alpha if no BRU is present in the pipeline. If that use
+        * case turns out to be useful we will revisit the implementation (for
+        * Gen3 only).
+        *
+        * We enable alpha multiplication on Gen3 using the fixed alpha value
+        * set through the V4L2_CID_ALPHA_COMPONENT control when the input
+        * contains an alpha channel. On Gen2 the global alpha is ignored in
+        * that case.
+        *
+        * In all cases, disable color keying.
         */
-       vsp1_rpf_write(rpf, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_AEXT_EXT |
+       vsp1_rpf_write(rpf, dl, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_AEXT_EXT |
                       (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED
                                       : VI6_RPF_ALPH_SEL_ASEL_FIXED));
 
-       if (vsp1->info->uapi)
-               mutex_lock(rpf->ctrls.lock);
-       vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET,
-                      rpf->alpha->cur.val << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
-       vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, rpf->alpha->cur.val);
-       if (vsp1->info->uapi)
-               mutex_unlock(rpf->ctrls.lock);
-
-       vsp1_rpf_write(rpf, VI6_RPF_MSK_CTRL, 0);
-       vsp1_rpf_write(rpf, VI6_RPF_CKEY_CTRL, 0);
-
-       return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Operations
- */
-
-static struct v4l2_subdev_video_ops rpf_video_ops = {
-       .s_stream = rpf_s_stream,
-};
-
-static struct v4l2_subdev_pad_ops rpf_pad_ops = {
-       .enum_mbus_code = vsp1_rwpf_enum_mbus_code,
-       .enum_frame_size = vsp1_rwpf_enum_frame_size,
-       .get_fmt = vsp1_rwpf_get_format,
-       .set_fmt = vsp1_rwpf_set_format,
-       .get_selection = vsp1_rwpf_get_selection,
-       .set_selection = vsp1_rwpf_set_selection,
-};
+       vsp1_rpf_write(rpf, dl, VI6_RPF_VRTCOL_SET,
+                      rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
+
+       if (entity->vsp1->info->gen == 3) {
+               u32 mult;
+
+               if (fmtinfo->alpha) {
+                       /* When the input contains an alpha channel enable the
+                        * alpha multiplier. If the input is premultiplied we
+                        * need to multiply both the alpha channel and the pixel
+                        * components by the global alpha value to keep them
+                        * premultiplied. Otherwise multiply the alpha channel
+                        * only.
+                        */
+                       bool premultiplied = format->flags
+                                          & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA;
+
+                       mult = VI6_RPF_MULT_ALPHA_A_MMD_RATIO
+                            | (premultiplied ?
+                               VI6_RPF_MULT_ALPHA_P_MMD_RATIO :
+                               VI6_RPF_MULT_ALPHA_P_MMD_NONE)
+                            | (rpf->alpha << VI6_RPF_MULT_ALPHA_RATIO_SHIFT);
+               } else {
+                       /* When the input doesn't contain an alpha channel the
+                        * global alpha value is applied in the unpacking unit,
+                        * the alpha multiplier isn't needed and must be
+                        * disabled.
+                        */
+                       mult = VI6_RPF_MULT_ALPHA_A_MMD_NONE
+                            | VI6_RPF_MULT_ALPHA_P_MMD_NONE;
+               }
+
+               vsp1_rpf_write(rpf, dl, VI6_RPF_MULT_ALPHA, mult);
+       }
 
-static struct v4l2_subdev_ops rpf_ops = {
-       .video  = &rpf_video_ops,
-       .pad    = &rpf_pad_ops,
-};
+       vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, dl, rpf->alpha);
 
-/* -----------------------------------------------------------------------------
- * Video Device Operations
- */
+       vsp1_rpf_write(rpf, dl, VI6_RPF_MSK_CTRL, 0);
+       vsp1_rpf_write(rpf, dl, VI6_RPF_CKEY_CTRL, 0);
 
-static void rpf_set_memory(struct vsp1_rwpf *rpf, struct vsp1_rwpf_memory *mem)
-{
-       unsigned int i;
-
-       for (i = 0; i < 3; ++i)
-               rpf->buf_addr[i] = mem->addr[i];
-
-       if (!vsp1_entity_is_streaming(&rpf->entity))
-               return;
-
-       vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
-                      mem->addr[0] + rpf->offsets[0]);
-       if (mem->num_planes > 1)
-               vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
-                              mem->addr[1] + rpf->offsets[1]);
-       if (mem->num_planes > 2)
-               vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
-                              mem->addr[2] + rpf->offsets[1]);
 }
 
-static const struct vsp1_rwpf_operations rpf_vdev_ops = {
+static const struct vsp1_entity_operations rpf_entity_ops = {
        .set_memory = rpf_set_memory,
+       .configure = rpf_configure,
 };
 
 /* -----------------------------------------------------------------------------
@@ -221,51 +220,31 @@ static const struct vsp1_rwpf_operations rpf_vdev_ops = {
 
 struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
 {
-       struct v4l2_subdev *subdev;
        struct vsp1_rwpf *rpf;
+       char name[6];
        int ret;
 
        rpf = devm_kzalloc(vsp1->dev, sizeof(*rpf), GFP_KERNEL);
        if (rpf == NULL)
                return ERR_PTR(-ENOMEM);
 
-       rpf->ops = &rpf_vdev_ops;
-
        rpf->max_width = RPF_MAX_WIDTH;
        rpf->max_height = RPF_MAX_HEIGHT;
 
+       rpf->entity.ops = &rpf_entity_ops;
        rpf->entity.type = VSP1_ENTITY_RPF;
        rpf->entity.index = index;
 
-       ret = vsp1_entity_init(vsp1, &rpf->entity, 2);
+       sprintf(name, "rpf.%u", index);
+       ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &rpf_ops);
        if (ret < 0)
                return ERR_PTR(ret);
 
-       /* Initialize the V4L2 subdev. */
-       subdev = &rpf->entity.subdev;
-       v4l2_subdev_init(subdev, &rpf_ops);
-
-       subdev->entity.ops = &vsp1->media_ops;
-       subdev->internal_ops = &vsp1_subdev_internal_ops;
-       snprintf(subdev->name, sizeof(subdev->name), "%s rpf.%u",
-                dev_name(vsp1->dev), index);
-       v4l2_set_subdevdata(subdev, rpf);
-       subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-       vsp1_entity_init_formats(subdev, NULL);
-
        /* Initialize the control handler. */
-       v4l2_ctrl_handler_init(&rpf->ctrls, 1);
-       rpf->alpha = v4l2_ctrl_new_std(&rpf->ctrls, &rpf_ctrl_ops,
-                                      V4L2_CID_ALPHA_COMPONENT,
-                                      0, 255, 1, 255);
-
-       rpf->entity.subdev.ctrl_handler = &rpf->ctrls;
-
-       if (rpf->ctrls.error) {
+       ret = vsp1_rwpf_init_ctrls(rpf);
+       if (ret < 0) {
                dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n",
                        index);
-               ret = rpf->ctrls.error;
                goto error;
        }
 
index 9688c21..3b6e032 100644 (file)
 #define RWPF_MIN_WIDTH                         1
 #define RWPF_MIN_HEIGHT                                1
 
+struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
+                                    struct v4l2_subdev_pad_config *config)
+{
+       return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, config,
+                                       RWPF_PAD_SINK);
+}
+
 /* -----------------------------------------------------------------------------
  * V4L2 Subdevice Pad Operations
  */
 
-int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
-                            struct v4l2_subdev_pad_config *cfg,
-                            struct v4l2_subdev_mbus_code_enum *code)
+static int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
+                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_mbus_code_enum *code)
 {
        static const unsigned int codes[] = {
                MEDIA_BUS_FMT_ARGB8888_1X32,
@@ -41,75 +48,36 @@ int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
        return 0;
 }
 
-int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
-                             struct v4l2_subdev_pad_config *cfg,
-                             struct v4l2_subdev_frame_size_enum *fse)
-{
-       struct vsp1_rwpf *rwpf = to_rwpf(subdev);
-       struct v4l2_mbus_framefmt *format;
-
-       format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fse->pad,
-                                           fse->which);
-
-       if (fse->index || fse->code != format->code)
-               return -EINVAL;
-
-       if (fse->pad == RWPF_PAD_SINK) {
-               fse->min_width = RWPF_MIN_WIDTH;
-               fse->max_width = rwpf->max_width;
-               fse->min_height = RWPF_MIN_HEIGHT;
-               fse->max_height = rwpf->max_height;
-       } else {
-               /* The size on the source pad are fixed and always identical to
-                * the size on the sink pad.
-                */
-               fse->min_width = format->width;
-               fse->max_width = format->width;
-               fse->min_height = format->height;
-               fse->max_height = format->height;
-       }
-
-       return 0;
-}
-
-static struct v4l2_rect *
-vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_pad_config *cfg, u32 which)
-{
-       switch (which) {
-       case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, cfg, RWPF_PAD_SINK);
-       case V4L2_SUBDEV_FORMAT_ACTIVE:
-               return &rwpf->crop;
-       default:
-               return NULL;
-       }
-}
-
-int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
-                        struct v4l2_subdev_format *fmt)
+static int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
+                                    struct v4l2_subdev_pad_config *cfg,
+                                    struct v4l2_subdev_frame_size_enum *fse)
 {
        struct vsp1_rwpf *rwpf = to_rwpf(subdev);
 
-       fmt->format = *vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad,
-                                                 fmt->which);
-
-       return 0;
+       return vsp1_subdev_enum_frame_size(subdev, cfg, fse, RWPF_MIN_WIDTH,
+                                          RWPF_MIN_HEIGHT, rwpf->max_width,
+                                          rwpf->max_height);
 }
 
-int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
-                        struct v4l2_subdev_format *fmt)
+static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
+                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_format *fmt)
 {
        struct vsp1_rwpf *rwpf = to_rwpf(subdev);
+       struct v4l2_subdev_pad_config *config;
        struct v4l2_mbus_framefmt *format;
        struct v4l2_rect *crop;
 
+       config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, fmt->which);
+       if (!config)
+               return -EINVAL;
+
        /* Default to YUV if the requested format is not supported. */
        if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
            fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
                fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
 
-       format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad,
-                                           fmt->which);
+       format = vsp1_entity_get_pad_format(&rwpf->entity, config, fmt->pad);
 
        if (fmt->pad == RWPF_PAD_SOURCE) {
                /* The RWPF performs format conversion but can't scale, only the
@@ -131,39 +99,44 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_conf
        fmt->format = *format;
 
        /* Update the sink crop rectangle. */
-       crop = vsp1_rwpf_get_crop(rwpf, cfg, fmt->which);
+       crop = vsp1_rwpf_get_crop(rwpf, config);
        crop->left = 0;
        crop->top = 0;
        crop->width = fmt->format.width;
        crop->height = fmt->format.height;
 
        /* Propagate the format to the source pad. */
-       format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE,
-                                           fmt->which);
+       format = vsp1_entity_get_pad_format(&rwpf->entity, config,
+                                           RWPF_PAD_SOURCE);
        *format = fmt->format;
 
        return 0;
 }
 
-int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
-                           struct v4l2_subdev_pad_config *cfg,
-                           struct v4l2_subdev_selection *sel)
+static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
+                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_selection *sel)
 {
        struct vsp1_rwpf *rwpf = to_rwpf(subdev);
+       struct v4l2_subdev_pad_config *config;
        struct v4l2_mbus_framefmt *format;
 
        /* Cropping is implemented on the sink pad. */
        if (sel->pad != RWPF_PAD_SINK)
                return -EINVAL;
 
+       config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, sel->which);
+       if (!config)
+               return -EINVAL;
+
        switch (sel->target) {
        case V4L2_SEL_TGT_CROP:
-               sel->r = *vsp1_rwpf_get_crop(rwpf, cfg, sel->which);
+               sel->r = *vsp1_rwpf_get_crop(rwpf, config);
                break;
 
        case V4L2_SEL_TGT_CROP_BOUNDS:
-               format = vsp1_entity_get_pad_format(&rwpf->entity, cfg,
-                                                   RWPF_PAD_SINK, sel->which);
+               format = vsp1_entity_get_pad_format(&rwpf->entity, config,
+                                                   RWPF_PAD_SINK);
                sel->r.left = 0;
                sel->r.top = 0;
                sel->r.width = format->width;
@@ -177,11 +150,12 @@ int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
        return 0;
 }
 
-int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
-                           struct v4l2_subdev_pad_config *cfg,
-                           struct v4l2_subdev_selection *sel)
+static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
+                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_selection *sel)
 {
        struct vsp1_rwpf *rwpf = to_rwpf(subdev);
+       struct v4l2_subdev_pad_config *config;
        struct v4l2_mbus_framefmt *format;
        struct v4l2_rect *crop;
 
@@ -192,11 +166,15 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
        if (sel->target != V4L2_SEL_TGT_CROP)
                return -EINVAL;
 
+       config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, sel->which);
+       if (!config)
+               return -EINVAL;
+
        /* Make sure the crop rectangle is entirely contained in the image. The
         * WPF top and left offsets are limited to 255.
         */
-       format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SINK,
-                                           sel->which);
+       format = vsp1_entity_get_pad_format(&rwpf->entity, config,
+                                           RWPF_PAD_SINK);
 
        /* Restrict the crop rectangle coordinates to multiples of 2 to avoid
         * shifting the color plane.
@@ -219,14 +197,59 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
        sel->r.height = min_t(unsigned int, sel->r.height,
                              format->height - sel->r.top);
 
-       crop = vsp1_rwpf_get_crop(rwpf, cfg, sel->which);
+       crop = vsp1_rwpf_get_crop(rwpf, config);
        *crop = sel->r;
 
        /* Propagate the format to the source pad. */
-       format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE,
-                                           sel->which);
+       format = vsp1_entity_get_pad_format(&rwpf->entity, config,
+                                           RWPF_PAD_SOURCE);
        format->width = crop->width;
        format->height = crop->height;
 
        return 0;
 }
+
+const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops = {
+       .init_cfg = vsp1_entity_init_cfg,
+       .enum_mbus_code = vsp1_rwpf_enum_mbus_code,
+       .enum_frame_size = vsp1_rwpf_enum_frame_size,
+       .get_fmt = vsp1_subdev_get_pad_format,
+       .set_fmt = vsp1_rwpf_set_format,
+       .get_selection = vsp1_rwpf_get_selection,
+       .set_selection = vsp1_rwpf_set_selection,
+};
+
+/* -----------------------------------------------------------------------------
+ * Controls
+ */
+
+static int vsp1_rwpf_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vsp1_rwpf *rwpf =
+               container_of(ctrl->handler, struct vsp1_rwpf, ctrls);
+
+       switch (ctrl->id) {
+       case V4L2_CID_ALPHA_COMPONENT:
+               rwpf->alpha = ctrl->val;
+               break;
+       }
+
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vsp1_rwpf_ctrl_ops = {
+       .s_ctrl = vsp1_rwpf_s_ctrl,
+};
+
+int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf)
+{
+       rwpf->alpha = 255;
+
+       v4l2_ctrl_handler_init(&rwpf->ctrls, 1);
+       v4l2_ctrl_new_std(&rwpf->ctrls, &vsp1_rwpf_ctrl_ops,
+                         V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255);
+
+       rwpf->entity.subdev.ctrl_handler = &rwpf->ctrls;
+
+       return rwpf->ctrls.error;
+}
index 8e82356..9ff7c78 100644 (file)
 #define RWPF_PAD_SOURCE                                1
 
 struct v4l2_ctrl;
+struct vsp1_dl_manager;
+struct vsp1_pipeline;
 struct vsp1_rwpf;
 struct vsp1_video;
 
 struct vsp1_rwpf_memory {
-       unsigned int num_planes;
        dma_addr_t addr[3];
-       unsigned int length[3];
-};
-
-struct vsp1_rwpf_operations {
-       void (*set_memory)(struct vsp1_rwpf *rwpf,
-                          struct vsp1_rwpf_memory *mem);
 };
 
 struct vsp1_rwpf {
        struct vsp1_entity entity;
        struct v4l2_ctrl_handler ctrls;
-       struct v4l2_ctrl *alpha;
 
+       struct vsp1_pipeline *pipe;
        struct vsp1_video *video;
 
-       const struct vsp1_rwpf_operations *ops;
-
        unsigned int max_width;
        unsigned int max_height;
 
        struct v4l2_pix_format_mplane format;
        const struct vsp1_format_info *fmtinfo;
-       struct {
-               unsigned int left;
-               unsigned int top;
-       } location;
-       struct v4l2_rect crop;
+       unsigned int bru_input;
+
+       unsigned int alpha;
 
        unsigned int offsets[2];
-       dma_addr_t buf_addr[3];
+       struct vsp1_rwpf_memory mem;
+
+       struct vsp1_dl_manager *dlm;
 };
 
 static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev)
@@ -67,24 +60,31 @@ static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev)
        return container_of(subdev, struct vsp1_rwpf, entity.subdev);
 }
 
+static inline struct vsp1_rwpf *entity_to_rwpf(struct vsp1_entity *entity)
+{
+       return container_of(entity, struct vsp1_rwpf, entity);
+}
+
 struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index);
 struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index);
 
-int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
-                            struct v4l2_subdev_pad_config *cfg,
-                            struct v4l2_subdev_mbus_code_enum *code);
-int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
-                             struct v4l2_subdev_pad_config *cfg,
-                             struct v4l2_subdev_frame_size_enum *fse);
-int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
-                        struct v4l2_subdev_format *fmt);
-int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
-                        struct v4l2_subdev_format *fmt);
-int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
-                           struct v4l2_subdev_pad_config *cfg,
-                           struct v4l2_subdev_selection *sel);
-int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
-                           struct v4l2_subdev_pad_config *cfg,
-                           struct v4l2_subdev_selection *sel);
+int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf);
+
+extern const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops;
+
+struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
+                                    struct v4l2_subdev_pad_config *config);
+/**
+ * vsp1_rwpf_set_memory - Configure DMA addresses for a [RW]PF
+ * @rwpf: the [RW]PF instance
+ * @dl: the display list
+ *
+ * This function applies the cached memory buffer address to the display list.
+ */
+static inline void vsp1_rwpf_set_memory(struct vsp1_rwpf *rwpf,
+                                       struct vsp1_dl_list *dl)
+{
+       rwpf->entity.ops->set_memory(&rwpf->entity, dl);
+}
 
 #endif /* __VSP1_RWPF_H__ */
index cc09efb..97ef997 100644 (file)
@@ -17,6 +17,7 @@
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
 #include "vsp1_sru.h"
 
 #define SRU_MIN_SIZE                           4U
  * Device Access
  */
 
-static inline u32 vsp1_sru_read(struct vsp1_sru *sru, u32 reg)
+static inline void vsp1_sru_write(struct vsp1_sru *sru, struct vsp1_dl_list *dl,
+                                 u32 reg, u32 data)
 {
-       return vsp1_read(sru->entity.vsp1, reg);
-}
-
-static inline void vsp1_sru_write(struct vsp1_sru *sru, u32 reg, u32 data)
-{
-       vsp1_write(sru->entity.vsp1, reg, data);
+       vsp1_dl_list_write(dl, reg, data);
 }
 
 /* -----------------------------------------------------------------------------
@@ -82,20 +79,10 @@ static int sru_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct vsp1_sru *sru =
                container_of(ctrl->handler, struct vsp1_sru, ctrls);
-       const struct vsp1_sru_param *param;
-       u32 value;
 
        switch (ctrl->id) {
        case V4L2_CID_VSP1_SRU_INTENSITY:
-               param = &vsp1_sru_params[ctrl->val - 1];
-
-               value = vsp1_sru_read(sru, VI6_SRU_CTRL0);
-               value &= ~(VI6_SRU_CTRL0_PARAM0_MASK |
-                          VI6_SRU_CTRL0_PARAM1_MASK);
-               value |= param->ctrl0;
-               vsp1_sru_write(sru, VI6_SRU_CTRL0, value);
-
-               vsp1_sru_write(sru, VI6_SRU_CTRL2, param->ctrl2);
+               sru->intensity = ctrl->val;
                break;
        }
 
@@ -118,54 +105,7 @@ static const struct v4l2_ctrl_config sru_intensity_control = {
 };
 
 /* -----------------------------------------------------------------------------
- * V4L2 Subdevice Core Operations
- */
-
-static int sru_s_stream(struct v4l2_subdev *subdev, int enable)
-{
-       struct vsp1_sru *sru = to_sru(subdev);
-       struct v4l2_mbus_framefmt *input;
-       struct v4l2_mbus_framefmt *output;
-       u32 ctrl0;
-       int ret;
-
-       ret = vsp1_entity_set_streaming(&sru->entity, enable);
-       if (ret < 0)
-               return ret;
-
-       if (!enable)
-               return 0;
-
-       input = &sru->entity.formats[SRU_PAD_SINK];
-       output = &sru->entity.formats[SRU_PAD_SOURCE];
-
-       if (input->code == MEDIA_BUS_FMT_ARGB8888_1X32)
-               ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3
-                     | VI6_SRU_CTRL0_PARAM4;
-       else
-               ctrl0 = VI6_SRU_CTRL0_PARAM3;
-
-       if (input->width != output->width)
-               ctrl0 |= VI6_SRU_CTRL0_MODE_UPSCALE;
-
-       /* Take the control handler lock to ensure that the CTRL0 value won't be
-        * changed behind our back by a set control operation.
-        */
-       if (sru->entity.vsp1->info->uapi)
-               mutex_lock(sru->ctrls.lock);
-       ctrl0 |= vsp1_sru_read(sru, VI6_SRU_CTRL0)
-              & (VI6_SRU_CTRL0_PARAM0_MASK | VI6_SRU_CTRL0_PARAM1_MASK);
-       vsp1_sru_write(sru, VI6_SRU_CTRL0, ctrl0);
-       if (sru->entity.vsp1->info->uapi)
-               mutex_unlock(sru->ctrls.lock);
-
-       vsp1_sru_write(sru, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5);
-
-       return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Pad Operations
+ * V4L2 Subdevice Operations
  */
 
 static int sru_enum_mbus_code(struct v4l2_subdev *subdev,
@@ -176,27 +116,9 @@ static int sru_enum_mbus_code(struct v4l2_subdev *subdev,
                MEDIA_BUS_FMT_ARGB8888_1X32,
                MEDIA_BUS_FMT_AYUV8_1X32,
        };
-       struct vsp1_sru *sru = to_sru(subdev);
-       struct v4l2_mbus_framefmt *format;
-
-       if (code->pad == SRU_PAD_SINK) {
-               if (code->index >= ARRAY_SIZE(codes))
-                       return -EINVAL;
-
-               code->code = codes[code->index];
-       } else {
-               /* The SRU can't perform format conversion, the sink format is
-                * always identical to the source format.
-                */
-               if (code->index)
-                       return -EINVAL;
 
-               format = vsp1_entity_get_pad_format(&sru->entity, cfg,
-                                                   SRU_PAD_SINK, code->which);
-               code->code = format->code;
-       }
-
-       return 0;
+       return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes,
+                                         ARRAY_SIZE(codes));
 }
 
 static int sru_enum_frame_size(struct v4l2_subdev *subdev,
@@ -204,10 +126,14 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev,
                               struct v4l2_subdev_frame_size_enum *fse)
 {
        struct vsp1_sru *sru = to_sru(subdev);
+       struct v4l2_subdev_pad_config *config;
        struct v4l2_mbus_framefmt *format;
 
-       format = vsp1_entity_get_pad_format(&sru->entity, cfg,
-                                           SRU_PAD_SINK, fse->which);
+       config = vsp1_entity_get_pad_config(&sru->entity, cfg, fse->which);
+       if (!config)
+               return -EINVAL;
+
+       format = vsp1_entity_get_pad_format(&sru->entity, config, SRU_PAD_SINK);
 
        if (fse->index || fse->code != format->code)
                return -EINVAL;
@@ -233,20 +159,9 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev,
        return 0;
 }
 
-static int sru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
-                         struct v4l2_subdev_format *fmt)
-{
-       struct vsp1_sru *sru = to_sru(subdev);
-
-       fmt->format = *vsp1_entity_get_pad_format(&sru->entity, cfg, fmt->pad,
-                                                 fmt->which);
-
-       return 0;
-}
-
-static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_pad_config *cfg,
-                          unsigned int pad, struct v4l2_mbus_framefmt *fmt,
-                          enum v4l2_subdev_format_whence which)
+static void sru_try_format(struct vsp1_sru *sru,
+                          struct v4l2_subdev_pad_config *config,
+                          unsigned int pad, struct v4l2_mbus_framefmt *fmt)
 {
        struct v4l2_mbus_framefmt *format;
        unsigned int input_area;
@@ -265,8 +180,8 @@ static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_pad_config *
 
        case SRU_PAD_SOURCE:
                /* The SRU can't perform format conversion. */
-               format = vsp1_entity_get_pad_format(&sru->entity, cfg,
-                                                   SRU_PAD_SINK, which);
+               format = vsp1_entity_get_pad_format(&sru->entity, config,
+                                                   SRU_PAD_SINK);
                fmt->code = format->code;
 
                /* We can upscale by 2 in both direction, but not independently.
@@ -295,57 +210,94 @@ static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_pad_config *
        fmt->colorspace = V4L2_COLORSPACE_SRGB;
 }
 
-static int sru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int sru_set_format(struct v4l2_subdev *subdev,
+                         struct v4l2_subdev_pad_config *cfg,
                          struct v4l2_subdev_format *fmt)
 {
        struct vsp1_sru *sru = to_sru(subdev);
+       struct v4l2_subdev_pad_config *config;
        struct v4l2_mbus_framefmt *format;
 
-       sru_try_format(sru, cfg, fmt->pad, &fmt->format, fmt->which);
+       config = vsp1_entity_get_pad_config(&sru->entity, cfg, fmt->which);
+       if (!config)
+               return -EINVAL;
+
+       sru_try_format(sru, config, fmt->pad, &fmt->format);
 
-       format = vsp1_entity_get_pad_format(&sru->entity, cfg, fmt->pad,
-                                           fmt->which);
+       format = vsp1_entity_get_pad_format(&sru->entity, config, fmt->pad);
        *format = fmt->format;
 
        if (fmt->pad == SRU_PAD_SINK) {
                /* Propagate the format to the source pad. */
-               format = vsp1_entity_get_pad_format(&sru->entity, cfg,
-                                                   SRU_PAD_SOURCE, fmt->which);
+               format = vsp1_entity_get_pad_format(&sru->entity, config,
+                                                   SRU_PAD_SOURCE);
                *format = fmt->format;
 
-               sru_try_format(sru, cfg, SRU_PAD_SOURCE, format, fmt->which);
+               sru_try_format(sru, config, SRU_PAD_SOURCE, format);
        }
 
        return 0;
 }
 
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Operations
- */
-
-static struct v4l2_subdev_video_ops sru_video_ops = {
-       .s_stream = sru_s_stream,
-};
-
 static struct v4l2_subdev_pad_ops sru_pad_ops = {
+       .init_cfg = vsp1_entity_init_cfg,
        .enum_mbus_code = sru_enum_mbus_code,
        .enum_frame_size = sru_enum_frame_size,
-       .get_fmt = sru_get_format,
+       .get_fmt = vsp1_subdev_get_pad_format,
        .set_fmt = sru_set_format,
 };
 
 static struct v4l2_subdev_ops sru_ops = {
-       .video  = &sru_video_ops,
        .pad    = &sru_pad_ops,
 };
 
+/* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
+
+static void sru_configure(struct vsp1_entity *entity,
+                         struct vsp1_pipeline *pipe,
+                         struct vsp1_dl_list *dl)
+{
+       const struct vsp1_sru_param *param;
+       struct vsp1_sru *sru = to_sru(&entity->subdev);
+       struct v4l2_mbus_framefmt *input;
+       struct v4l2_mbus_framefmt *output;
+       u32 ctrl0;
+
+       input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
+                                          SRU_PAD_SINK);
+       output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
+                                           SRU_PAD_SOURCE);
+
+       if (input->code == MEDIA_BUS_FMT_ARGB8888_1X32)
+               ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3
+                     | VI6_SRU_CTRL0_PARAM4;
+       else
+               ctrl0 = VI6_SRU_CTRL0_PARAM3;
+
+       if (input->width != output->width)
+               ctrl0 |= VI6_SRU_CTRL0_MODE_UPSCALE;
+
+       param = &vsp1_sru_params[sru->intensity - 1];
+
+       ctrl0 |= param->ctrl0;
+
+       vsp1_sru_write(sru, dl, VI6_SRU_CTRL0, ctrl0);
+       vsp1_sru_write(sru, dl, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5);
+       vsp1_sru_write(sru, dl, VI6_SRU_CTRL2, param->ctrl2);
+}
+
+static const struct vsp1_entity_operations sru_entity_ops = {
+       .configure = sru_configure,
+};
+
 /* -----------------------------------------------------------------------------
  * Initialization and Cleanup
  */
 
 struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1)
 {
-       struct v4l2_subdev *subdev;
        struct vsp1_sru *sru;
        int ret;
 
@@ -353,29 +305,19 @@ struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1)
        if (sru == NULL)
                return ERR_PTR(-ENOMEM);
 
+       sru->entity.ops = &sru_entity_ops;
        sru->entity.type = VSP1_ENTITY_SRU;
 
-       ret = vsp1_entity_init(vsp1, &sru->entity, 2);
+       ret = vsp1_entity_init(vsp1, &sru->entity, "sru", 2, &sru_ops);
        if (ret < 0)
                return ERR_PTR(ret);
 
-       /* Initialize the V4L2 subdev. */
-       subdev = &sru->entity.subdev;
-       v4l2_subdev_init(subdev, &sru_ops);
-
-       subdev->entity.ops = &vsp1->media_ops;
-       subdev->internal_ops = &vsp1_subdev_internal_ops;
-       snprintf(subdev->name, sizeof(subdev->name), "%s sru",
-                dev_name(vsp1->dev));
-       v4l2_set_subdevdata(subdev, sru);
-       subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-       vsp1_entity_init_formats(subdev, NULL);
-
        /* Initialize the control handler. */
        v4l2_ctrl_handler_init(&sru->ctrls, 1);
        v4l2_ctrl_new_custom(&sru->ctrls, &sru_intensity_control, NULL);
 
+       sru->intensity = 1;
+
        sru->entity.subdev.ctrl_handler = &sru->ctrls;
 
        if (sru->ctrls.error) {
index b6768bf..85e2414 100644 (file)
@@ -28,6 +28,8 @@ struct vsp1_sru {
        struct vsp1_entity entity;
 
        struct v4l2_ctrl_handler ctrls;
+
+       unsigned int intensity;
 };
 
 static inline struct vsp1_sru *to_sru(struct v4l2_subdev *subdev)
index bba6777..1875e29 100644 (file)
@@ -17,6 +17,7 @@
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
 #include "vsp1_uds.h"
 
 #define UDS_MIN_SIZE                           4U
  * Device Access
  */
 
-static inline void vsp1_uds_write(struct vsp1_uds *uds, u32 reg, u32 data)
+static inline void vsp1_uds_write(struct vsp1_uds *uds, struct vsp1_dl_list *dl,
+                                 u32 reg, u32 data)
 {
-       vsp1_write(uds->entity.vsp1,
-                  reg + uds->entity.index * VI6_UDS_OFFSET, data);
+       vsp1_dl_list_write(dl, reg + uds->entity.index * VI6_UDS_OFFSET, data);
 }
 
 /* -----------------------------------------------------------------------------
  * Scaling Computation
  */
 
-void vsp1_uds_set_alpha(struct vsp1_uds *uds, unsigned int alpha)
+void vsp1_uds_set_alpha(struct vsp1_uds *uds, struct vsp1_dl_list *dl,
+                       unsigned int alpha)
 {
-       vsp1_uds_write(uds, VI6_UDS_ALPVAL, alpha << VI6_UDS_ALPVAL_VAL0_SHIFT);
+       vsp1_uds_write(uds, dl, VI6_UDS_ALPVAL,
+                      alpha << VI6_UDS_ALPVAL_VAL0_SHIFT);
 }
 
 /*
@@ -104,60 +107,6 @@ static unsigned int uds_compute_ratio(unsigned int input, unsigned int output)
        return (input - 1) * 4096 / (output - 1);
 }
 
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Core Operations
- */
-
-static int uds_s_stream(struct v4l2_subdev *subdev, int enable)
-{
-       struct vsp1_uds *uds = to_uds(subdev);
-       const struct v4l2_mbus_framefmt *output;
-       const struct v4l2_mbus_framefmt *input;
-       unsigned int hscale;
-       unsigned int vscale;
-       bool multitap;
-
-       if (!enable)
-               return 0;
-
-       input = &uds->entity.formats[UDS_PAD_SINK];
-       output = &uds->entity.formats[UDS_PAD_SOURCE];
-
-       hscale = uds_compute_ratio(input->width, output->width);
-       vscale = uds_compute_ratio(input->height, output->height);
-
-       dev_dbg(uds->entity.vsp1->dev, "hscale %u vscale %u\n", hscale, vscale);
-
-       /* Multi-tap scaling can't be enabled along with alpha scaling when
-        * scaling down with a factor lower than or equal to 1/2 in either
-        * direction.
-        */
-       if (uds->scale_alpha && (hscale >= 8192 || vscale >= 8192))
-               multitap = false;
-       else
-               multitap = true;
-
-       vsp1_uds_write(uds, VI6_UDS_CTRL,
-                      (uds->scale_alpha ? VI6_UDS_CTRL_AON : 0) |
-                      (multitap ? VI6_UDS_CTRL_BC : 0));
-
-       vsp1_uds_write(uds, VI6_UDS_PASS_BWIDTH,
-                      (uds_passband_width(hscale)
-                               << VI6_UDS_PASS_BWIDTH_H_SHIFT) |
-                      (uds_passband_width(vscale)
-                               << VI6_UDS_PASS_BWIDTH_V_SHIFT));
-
-       /* Set the scaling ratios and the output size. */
-       vsp1_uds_write(uds, VI6_UDS_SCALE,
-                      (hscale << VI6_UDS_SCALE_HFRAC_SHIFT) |
-                      (vscale << VI6_UDS_SCALE_VFRAC_SHIFT));
-       vsp1_uds_write(uds, VI6_UDS_CLIP_SIZE,
-                      (output->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) |
-                      (output->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT));
-
-       return 0;
-}
-
 /* -----------------------------------------------------------------------------
  * V4L2 Subdevice Pad Operations
  */
@@ -170,28 +119,9 @@ static int uds_enum_mbus_code(struct v4l2_subdev *subdev,
                MEDIA_BUS_FMT_ARGB8888_1X32,
                MEDIA_BUS_FMT_AYUV8_1X32,
        };
-       struct vsp1_uds *uds = to_uds(subdev);
-
-       if (code->pad == UDS_PAD_SINK) {
-               if (code->index >= ARRAY_SIZE(codes))
-                       return -EINVAL;
-
-               code->code = codes[code->index];
-       } else {
-               struct v4l2_mbus_framefmt *format;
-
-               /* The UDS can't perform format conversion, the sink format is
-                * always identical to the source format.
-                */
-               if (code->index)
-                       return -EINVAL;
 
-               format = vsp1_entity_get_pad_format(&uds->entity, cfg,
-                                                   UDS_PAD_SINK, code->which);
-               code->code = format->code;
-       }
-
-       return 0;
+       return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes,
+                                         ARRAY_SIZE(codes));
 }
 
 static int uds_enum_frame_size(struct v4l2_subdev *subdev,
@@ -199,10 +129,15 @@ static int uds_enum_frame_size(struct v4l2_subdev *subdev,
                               struct v4l2_subdev_frame_size_enum *fse)
 {
        struct vsp1_uds *uds = to_uds(subdev);
+       struct v4l2_subdev_pad_config *config;
        struct v4l2_mbus_framefmt *format;
 
-       format = vsp1_entity_get_pad_format(&uds->entity, cfg,
-                                           UDS_PAD_SINK, fse->which);
+       config = vsp1_entity_get_pad_config(&uds->entity, cfg, fse->which);
+       if (!config)
+               return -EINVAL;
+
+       format = vsp1_entity_get_pad_format(&uds->entity, config,
+                                           UDS_PAD_SINK);
 
        if (fse->index || fse->code != format->code)
                return -EINVAL;
@@ -222,20 +157,9 @@ static int uds_enum_frame_size(struct v4l2_subdev *subdev,
        return 0;
 }
 
-static int uds_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
-                         struct v4l2_subdev_format *fmt)
-{
-       struct vsp1_uds *uds = to_uds(subdev);
-
-       fmt->format = *vsp1_entity_get_pad_format(&uds->entity, cfg, fmt->pad,
-                                                 fmt->which);
-
-       return 0;
-}
-
-static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_pad_config *cfg,
-                          unsigned int pad, struct v4l2_mbus_framefmt *fmt,
-                          enum v4l2_subdev_format_whence which)
+static void uds_try_format(struct vsp1_uds *uds,
+                          struct v4l2_subdev_pad_config *config,
+                          unsigned int pad, struct v4l2_mbus_framefmt *fmt)
 {
        struct v4l2_mbus_framefmt *format;
        unsigned int minimum;
@@ -254,8 +178,8 @@ static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_pad_config *
 
        case UDS_PAD_SOURCE:
                /* The UDS scales but can't perform format conversion. */
-               format = vsp1_entity_get_pad_format(&uds->entity, cfg,
-                                                   UDS_PAD_SINK, which);
+               format = vsp1_entity_get_pad_format(&uds->entity, config,
+                                                   UDS_PAD_SINK);
                fmt->code = format->code;
 
                uds_output_limits(format->width, &minimum, &maximum);
@@ -269,25 +193,30 @@ static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_pad_config *
        fmt->colorspace = V4L2_COLORSPACE_SRGB;
 }
 
-static int uds_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int uds_set_format(struct v4l2_subdev *subdev,
+                         struct v4l2_subdev_pad_config *cfg,
                          struct v4l2_subdev_format *fmt)
 {
        struct vsp1_uds *uds = to_uds(subdev);
+       struct v4l2_subdev_pad_config *config;
        struct v4l2_mbus_framefmt *format;
 
-       uds_try_format(uds, cfg, fmt->pad, &fmt->format, fmt->which);
+       config = vsp1_entity_get_pad_config(&uds->entity, cfg, fmt->which);
+       if (!config)
+               return -EINVAL;
+
+       uds_try_format(uds, config, fmt->pad, &fmt->format);
 
-       format = vsp1_entity_get_pad_format(&uds->entity, cfg, fmt->pad,
-                                           fmt->which);
+       format = vsp1_entity_get_pad_format(&uds->entity, config, fmt->pad);
        *format = fmt->format;
 
        if (fmt->pad == UDS_PAD_SINK) {
                /* Propagate the format to the source pad. */
-               format = vsp1_entity_get_pad_format(&uds->entity, cfg,
-                                                   UDS_PAD_SOURCE, fmt->which);
+               format = vsp1_entity_get_pad_format(&uds->entity, config,
+                                                   UDS_PAD_SOURCE);
                *format = fmt->format;
 
-               uds_try_format(uds, cfg, UDS_PAD_SOURCE, format, fmt->which);
+               uds_try_format(uds, config, UDS_PAD_SOURCE, format);
        }
 
        return 0;
@@ -297,55 +226,97 @@ static int uds_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con
  * V4L2 Subdevice Operations
  */
 
-static struct v4l2_subdev_video_ops uds_video_ops = {
-       .s_stream = uds_s_stream,
-};
-
 static struct v4l2_subdev_pad_ops uds_pad_ops = {
+       .init_cfg = vsp1_entity_init_cfg,
        .enum_mbus_code = uds_enum_mbus_code,
        .enum_frame_size = uds_enum_frame_size,
-       .get_fmt = uds_get_format,
+       .get_fmt = vsp1_subdev_get_pad_format,
        .set_fmt = uds_set_format,
 };
 
 static struct v4l2_subdev_ops uds_ops = {
-       .video  = &uds_video_ops,
        .pad    = &uds_pad_ops,
 };
 
+/* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
+
+static void uds_configure(struct vsp1_entity *entity,
+                         struct vsp1_pipeline *pipe,
+                         struct vsp1_dl_list *dl)
+{
+       struct vsp1_uds *uds = to_uds(&entity->subdev);
+       const struct v4l2_mbus_framefmt *output;
+       const struct v4l2_mbus_framefmt *input;
+       unsigned int hscale;
+       unsigned int vscale;
+       bool multitap;
+
+       input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
+                                          UDS_PAD_SINK);
+       output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
+                                           UDS_PAD_SOURCE);
+
+       hscale = uds_compute_ratio(input->width, output->width);
+       vscale = uds_compute_ratio(input->height, output->height);
+
+       dev_dbg(uds->entity.vsp1->dev, "hscale %u vscale %u\n", hscale, vscale);
+
+       /* Multi-tap scaling can't be enabled along with alpha scaling when
+        * scaling down with a factor lower than or equal to 1/2 in either
+        * direction.
+        */
+       if (uds->scale_alpha && (hscale >= 8192 || vscale >= 8192))
+               multitap = false;
+       else
+               multitap = true;
+
+       vsp1_uds_write(uds, dl, VI6_UDS_CTRL,
+                      (uds->scale_alpha ? VI6_UDS_CTRL_AON : 0) |
+                      (multitap ? VI6_UDS_CTRL_BC : 0));
+
+       vsp1_uds_write(uds, dl, VI6_UDS_PASS_BWIDTH,
+                      (uds_passband_width(hscale)
+                               << VI6_UDS_PASS_BWIDTH_H_SHIFT) |
+                      (uds_passband_width(vscale)
+                               << VI6_UDS_PASS_BWIDTH_V_SHIFT));
+
+       /* Set the scaling ratios and the output size. */
+       vsp1_uds_write(uds, dl, VI6_UDS_SCALE,
+                      (hscale << VI6_UDS_SCALE_HFRAC_SHIFT) |
+                      (vscale << VI6_UDS_SCALE_VFRAC_SHIFT));
+       vsp1_uds_write(uds, dl, VI6_UDS_CLIP_SIZE,
+                      (output->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) |
+                      (output->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT));
+}
+
+static const struct vsp1_entity_operations uds_entity_ops = {
+       .configure = uds_configure,
+};
+
 /* -----------------------------------------------------------------------------
  * Initialization and Cleanup
  */
 
 struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index)
 {
-       struct v4l2_subdev *subdev;
        struct vsp1_uds *uds;
+       char name[6];
        int ret;
 
        uds = devm_kzalloc(vsp1->dev, sizeof(*uds), GFP_KERNEL);
        if (uds == NULL)
                return ERR_PTR(-ENOMEM);
 
+       uds->entity.ops = &uds_entity_ops;
        uds->entity.type = VSP1_ENTITY_UDS;
        uds->entity.index = index;
 
-       ret = vsp1_entity_init(vsp1, &uds->entity, 2);
+       sprintf(name, "uds.%u", index);
+       ret = vsp1_entity_init(vsp1, &uds->entity, name, 2, &uds_ops);
        if (ret < 0)
                return ERR_PTR(ret);
 
-       /* Initialize the V4L2 subdev. */
-       subdev = &uds->entity.subdev;
-       v4l2_subdev_init(subdev, &uds_ops);
-
-       subdev->entity.ops = &vsp1->media_ops;
-       subdev->internal_ops = &vsp1_subdev_internal_ops;
-       snprintf(subdev->name, sizeof(subdev->name), "%s uds.%u",
-                dev_name(vsp1->dev), index);
-       v4l2_set_subdevdata(subdev, uds);
-       subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-       vsp1_entity_init_formats(subdev, NULL);
-
        return uds;
 }
index 031ac0d..5c8cbfc 100644 (file)
@@ -35,6 +35,7 @@ static inline struct vsp1_uds *to_uds(struct v4l2_subdev *subdev)
 
 struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index);
 
-void vsp1_uds_set_alpha(struct vsp1_uds *uds, unsigned int alpha);
+void vsp1_uds_set_alpha(struct vsp1_uds *uds, struct vsp1_dl_list *dl,
+                       unsigned int alpha);
 
 #endif /* __VSP1_UDS_H__ */
index 72cc7d3..a9aec5c 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "vsp1.h"
 #include "vsp1_bru.h"
+#include "vsp1_dl.h"
 #include "vsp1_entity.h"
 #include "vsp1_pipe.h"
 #include "vsp1_rwpf.h"
@@ -171,53 +172,178 @@ static int __vsp1_video_try_format(struct vsp1_video *video,
  * Pipeline Management
  */
 
-static int vsp1_video_pipeline_validate_branch(struct vsp1_pipeline *pipe,
-                                              struct vsp1_rwpf *input,
-                                              struct vsp1_rwpf *output)
+/*
+ * vsp1_video_complete_buffer - Complete the current buffer
+ * @video: the video node
+ *
+ * This function completes the current buffer by filling its sequence number,
+ * time stamp and payload size, and hands it back to the videobuf core.
+ *
+ * When operating in DU output mode (deep pipeline to the DU through the LIF),
+ * the VSP1 needs to constantly supply frames to the display. In that case, if
+ * no other buffer is queued, reuse the one that has just been processed instead
+ * of handing it back to the videobuf core.
+ *
+ * Return the next queued buffer or NULL if the queue is empty.
+ */
+static struct vsp1_vb2_buffer *
+vsp1_video_complete_buffer(struct vsp1_video *video)
+{
+       struct vsp1_pipeline *pipe = video->rwpf->pipe;
+       struct vsp1_vb2_buffer *next = NULL;
+       struct vsp1_vb2_buffer *done;
+       unsigned long flags;
+       unsigned int i;
+
+       spin_lock_irqsave(&video->irqlock, flags);
+
+       if (list_empty(&video->irqqueue)) {
+               spin_unlock_irqrestore(&video->irqlock, flags);
+               return NULL;
+       }
+
+       done = list_first_entry(&video->irqqueue,
+                               struct vsp1_vb2_buffer, queue);
+
+       /* In DU output mode reuse the buffer if the list is singular. */
+       if (pipe->lif && list_is_singular(&video->irqqueue)) {
+               spin_unlock_irqrestore(&video->irqlock, flags);
+               return done;
+       }
+
+       list_del(&done->queue);
+
+       if (!list_empty(&video->irqqueue))
+               next = list_first_entry(&video->irqqueue,
+                                       struct vsp1_vb2_buffer, queue);
+
+       spin_unlock_irqrestore(&video->irqlock, flags);
+
+       done->buf.sequence = video->sequence++;
+       done->buf.vb2_buf.timestamp = ktime_get_ns();
+       for (i = 0; i < done->buf.vb2_buf.num_planes; ++i)
+               vb2_set_plane_payload(&done->buf.vb2_buf, i,
+                                     vb2_plane_size(&done->buf.vb2_buf, i));
+       vb2_buffer_done(&done->buf.vb2_buf, VB2_BUF_STATE_DONE);
+
+       return next;
+}
+
+static void vsp1_video_frame_end(struct vsp1_pipeline *pipe,
+                                struct vsp1_rwpf *rwpf)
+{
+       struct vsp1_video *video = rwpf->video;
+       struct vsp1_vb2_buffer *buf;
+       unsigned long flags;
+
+       buf = vsp1_video_complete_buffer(video);
+       if (buf == NULL)
+               return;
+
+       spin_lock_irqsave(&pipe->irqlock, flags);
+
+       video->rwpf->mem = buf->mem;
+       pipe->buffers_ready |= 1 << video->pipe_index;
+
+       spin_unlock_irqrestore(&pipe->irqlock, flags);
+}
+
+static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe)
+{
+       struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
+       unsigned int i;
+
+       if (!pipe->dl)
+               pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
+
+       for (i = 0; i < vsp1->info->rpf_count; ++i) {
+               struct vsp1_rwpf *rwpf = pipe->inputs[i];
+
+               if (rwpf)
+                       vsp1_rwpf_set_memory(rwpf, pipe->dl);
+       }
+
+       if (!pipe->lif)
+               vsp1_rwpf_set_memory(pipe->output, pipe->dl);
+
+       vsp1_dl_list_commit(pipe->dl);
+       pipe->dl = NULL;
+
+       vsp1_pipeline_run(pipe);
+}
+
+static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe)
+{
+       struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
+       enum vsp1_pipeline_state state;
+       unsigned long flags;
+       unsigned int i;
+
+       /* Complete buffers on all video nodes. */
+       for (i = 0; i < vsp1->info->rpf_count; ++i) {
+               if (!pipe->inputs[i])
+                       continue;
+
+               vsp1_video_frame_end(pipe, pipe->inputs[i]);
+       }
+
+       vsp1_video_frame_end(pipe, pipe->output);
+
+       spin_lock_irqsave(&pipe->irqlock, flags);
+
+       state = pipe->state;
+       pipe->state = VSP1_PIPELINE_STOPPED;
+
+       /* If a stop has been requested, mark the pipeline as stopped and
+        * return. Otherwise restart the pipeline if ready.
+        */
+       if (state == VSP1_PIPELINE_STOPPING)
+               wake_up(&pipe->wq);
+       else if (vsp1_pipeline_ready(pipe))
+               vsp1_video_pipeline_run(pipe);
+
+       spin_unlock_irqrestore(&pipe->irqlock, flags);
+}
+
+static int vsp1_video_pipeline_build_branch(struct vsp1_pipeline *pipe,
+                                           struct vsp1_rwpf *input,
+                                           struct vsp1_rwpf *output)
 {
-       struct vsp1_entity *entity;
        struct media_entity_enum ent_enum;
+       struct vsp1_entity *entity;
        struct media_pad *pad;
-       int rval;
        bool bru_found = false;
+       int ret;
 
-       input->location.left = 0;
-       input->location.top = 0;
-
-       rval = media_entity_enum_init(
-               &ent_enum, input->entity.pads[RWPF_PAD_SOURCE].graph_obj.mdev);
-       if (rval)
-               return rval;
+       ret = media_entity_enum_init(&ent_enum, &input->entity.vsp1->media_dev);
+       if (ret < 0)
+               return ret;
 
        pad = media_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]);
 
        while (1) {
                if (pad == NULL) {
-                       rval = -EPIPE;
+                       ret = -EPIPE;
                        goto out;
                }
 
                /* We've reached a video node, that shouldn't have happened. */
                if (!is_media_entity_v4l2_subdev(pad->entity)) {
-                       rval = -EPIPE;
+                       ret = -EPIPE;
                        goto out;
                }
 
                entity = to_vsp1_entity(
                        media_entity_to_v4l2_subdev(pad->entity));
 
-               /* A BRU is present in the pipeline, store the compose rectangle
-                * location in the input RPF for use when configuring the RPF.
+               /* A BRU is present in the pipeline, store the BRU input pad
+                * number in the input RPF for use when configuring the RPF.
                 */
                if (entity->type == VSP1_ENTITY_BRU) {
                        struct vsp1_bru *bru = to_bru(&entity->subdev);
-                       struct v4l2_rect *rect =
-                               &bru->inputs[pad->index].compose;
 
                        bru->inputs[pad->index].rpf = input;
-
-                       input->location.left = rect->left;
-                       input->location.top = rect->top;
+                       input->bru_input = pad->index;
 
                        bru_found = true;
                }
@@ -229,14 +355,14 @@ static int vsp1_video_pipeline_validate_branch(struct vsp1_pipeline *pipe,
                /* Ensure the branch has no loop. */
                if (media_entity_enum_test_and_set(&ent_enum,
                                                   &entity->subdev.entity)) {
-                       rval = -EPIPE;
+                       ret = -EPIPE;
                        goto out;
                }
 
                /* UDS can't be chained. */
                if (entity->type == VSP1_ENTITY_UDS) {
                        if (pipe->uds) {
-                               rval = -EPIPE;
+                               ret = -EPIPE;
                                goto out;
                        }
 
@@ -256,16 +382,16 @@ static int vsp1_video_pipeline_validate_branch(struct vsp1_pipeline *pipe,
 
        /* The last entity must be the output WPF. */
        if (entity != &output->entity)
-               rval = -EPIPE;
+               ret = -EPIPE;
 
 out:
        media_entity_enum_cleanup(&ent_enum);
 
-       return rval;
+       return ret;
 }
 
-static int vsp1_video_pipeline_validate(struct vsp1_pipeline *pipe,
-                                       struct vsp1_video *video)
+static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe,
+                                    struct vsp1_video *video)
 {
        struct media_entity_graph graph;
        struct media_entity *entity = &video->video.entity;
@@ -273,14 +399,10 @@ static int vsp1_video_pipeline_validate(struct vsp1_pipeline *pipe,
        unsigned int i;
        int ret;
 
-       mutex_lock(&mdev->graph_mutex);
-
        /* Walk the graph to locate the entities and video nodes. */
        ret = media_entity_graph_walk_init(&graph, mdev);
-       if (ret) {
-               mutex_unlock(&mdev->graph_mutex);
+       if (ret)
                return ret;
-       }
 
        media_entity_graph_walk_start(&graph, entity);
 
@@ -300,10 +422,12 @@ static int vsp1_video_pipeline_validate(struct vsp1_pipeline *pipe,
                        rwpf = to_rwpf(subdev);
                        pipe->inputs[rwpf->entity.index] = rwpf;
                        rwpf->video->pipe_index = ++pipe->num_inputs;
+                       rwpf->pipe = pipe;
                } else if (e->type == VSP1_ENTITY_WPF) {
                        rwpf = to_rwpf(subdev);
                        pipe->output = rwpf;
                        rwpf->video->pipe_index = 0;
+                       rwpf->pipe = pipe;
                } else if (e->type == VSP1_ENTITY_LIF) {
                        pipe->lif = e;
                } else if (e->type == VSP1_ENTITY_BRU) {
@@ -311,15 +435,11 @@ static int vsp1_video_pipeline_validate(struct vsp1_pipeline *pipe,
                }
        }
 
-       mutex_unlock(&mdev->graph_mutex);
-
        media_entity_graph_walk_cleanup(&graph);
 
        /* We need one output and at least one input. */
-       if (pipe->num_inputs == 0 || !pipe->output) {
-               ret = -EPIPE;
-               goto error;
-       }
+       if (pipe->num_inputs == 0 || !pipe->output)
+               return -EPIPE;
 
        /* Follow links downstream for each input and make sure the graph
         * contains no loop and that all branches end at the output WPF.
@@ -328,143 +448,69 @@ static int vsp1_video_pipeline_validate(struct vsp1_pipeline *pipe,
                if (!pipe->inputs[i])
                        continue;
 
-               ret = vsp1_video_pipeline_validate_branch(pipe, pipe->inputs[i],
-                                                         pipe->output);
+               ret = vsp1_video_pipeline_build_branch(pipe, pipe->inputs[i],
+                                                      pipe->output);
                if (ret < 0)
-                       goto error;
+                       return ret;
        }
 
        return 0;
-
-error:
-       vsp1_pipeline_reset(pipe);
-       return ret;
 }
 
 static int vsp1_video_pipeline_init(struct vsp1_pipeline *pipe,
                                    struct vsp1_video *video)
 {
-       int ret;
+       vsp1_pipeline_init(pipe);
 
-       mutex_lock(&pipe->lock);
-
-       /* If we're the first user validate and initialize the pipeline. */
-       if (pipe->use_count == 0) {
-               ret = vsp1_video_pipeline_validate(pipe, video);
-               if (ret < 0)
-                       goto done;
-       }
+       pipe->frame_end = vsp1_video_pipeline_frame_end;
 
-       pipe->use_count++;
-       ret = 0;
-
-done:
-       mutex_unlock(&pipe->lock);
-       return ret;
+       return vsp1_video_pipeline_build(pipe, video);
 }
 
-static void vsp1_video_pipeline_cleanup(struct vsp1_pipeline *pipe)
-{
-       mutex_lock(&pipe->lock);
-
-       /* If we're the last user clean up the pipeline. */
-       if (--pipe->use_count == 0)
-               vsp1_pipeline_reset(pipe);
-
-       mutex_unlock(&pipe->lock);
-}
-
-/*
- * vsp1_video_complete_buffer - Complete the current buffer
- * @video: the video node
- *
- * This function completes the current buffer by filling its sequence number,
- * time stamp and payload size, and hands it back to the videobuf core.
- *
- * When operating in DU output mode (deep pipeline to the DU through the LIF),
- * the VSP1 needs to constantly supply frames to the display. In that case, if
- * no other buffer is queued, reuse the one that has just been processed instead
- * of handing it back to the videobuf core.
- *
- * Return the next queued buffer or NULL if the queue is empty.
- */
-static struct vsp1_vb2_buffer *
-vsp1_video_complete_buffer(struct vsp1_video *video)
+static struct vsp1_pipeline *vsp1_video_pipeline_get(struct vsp1_video *video)
 {
-       struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity);
-       struct vsp1_vb2_buffer *next = NULL;
-       struct vsp1_vb2_buffer *done;
-       unsigned long flags;
-       unsigned int i;
-
-       spin_lock_irqsave(&video->irqlock, flags);
-
-       if (list_empty(&video->irqqueue)) {
-               spin_unlock_irqrestore(&video->irqlock, flags);
-               return NULL;
-       }
-
-       done = list_first_entry(&video->irqqueue,
-                               struct vsp1_vb2_buffer, queue);
+       struct vsp1_pipeline *pipe;
+       int ret;
 
-       /* In DU output mode reuse the buffer if the list is singular. */
-       if (pipe->lif && list_is_singular(&video->irqqueue)) {
-               spin_unlock_irqrestore(&video->irqlock, flags);
-               return done;
+       /* Get a pipeline object for the video node. If a pipeline has already
+        * been allocated just increment its reference count and return it.
+        * Otherwise allocate a new pipeline and initialize it, it will be freed
+        * when the last reference is released.
+        */
+       if (!video->rwpf->pipe) {
+               pipe = kzalloc(sizeof(*pipe), GFP_KERNEL);
+               if (!pipe)
+                       return ERR_PTR(-ENOMEM);
+
+               ret = vsp1_video_pipeline_init(pipe, video);
+               if (ret < 0) {
+                       vsp1_pipeline_reset(pipe);
+                       kfree(pipe);
+                       return ERR_PTR(ret);
+               }
+       } else {
+               pipe = video->rwpf->pipe;
+               kref_get(&pipe->kref);
        }
 
-       list_del(&done->queue);
-
-       if (!list_empty(&video->irqqueue))
-               next = list_first_entry(&video->irqqueue,
-                                       struct vsp1_vb2_buffer, queue);
-
-       spin_unlock_irqrestore(&video->irqlock, flags);
-
-       done->buf.sequence = video->sequence++;
-       done->buf.vb2_buf.timestamp = ktime_get_ns();
-       for (i = 0; i < done->buf.vb2_buf.num_planes; ++i)
-               vb2_set_plane_payload(&done->buf.vb2_buf, i,
-                                     done->mem.length[i]);
-       vb2_buffer_done(&done->buf.vb2_buf, VB2_BUF_STATE_DONE);
-
-       return next;
+       return pipe;
 }
 
-static void vsp1_video_frame_end(struct vsp1_pipeline *pipe,
-                                struct vsp1_rwpf *rwpf)
+static void vsp1_video_pipeline_release(struct kref *kref)
 {
-       struct vsp1_video *video = rwpf->video;
-       struct vsp1_vb2_buffer *buf;
-       unsigned long flags;
+       struct vsp1_pipeline *pipe = container_of(kref, typeof(*pipe), kref);
 
-       buf = vsp1_video_complete_buffer(video);
-       if (buf == NULL)
-               return;
-
-       spin_lock_irqsave(&pipe->irqlock, flags);
-
-       video->rwpf->ops->set_memory(video->rwpf, &buf->mem);
-       pipe->buffers_ready |= 1 << video->pipe_index;
-
-       spin_unlock_irqrestore(&pipe->irqlock, flags);
+       vsp1_pipeline_reset(pipe);
+       kfree(pipe);
 }
 
-static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe)
+static void vsp1_video_pipeline_put(struct vsp1_pipeline *pipe)
 {
-       struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
-       unsigned int i;
-
-       /* Complete buffers on all video nodes. */
-       for (i = 0; i < vsp1->info->rpf_count; ++i) {
-               if (!pipe->inputs[i])
-                       continue;
+       struct media_device *mdev = &pipe->output->entity.vsp1->media_dev;
 
-               vsp1_video_frame_end(pipe, pipe->inputs[i]);
-       }
-
-       if (!pipe->lif)
-               vsp1_video_frame_end(pipe, pipe->output);
+       mutex_lock(&mdev->graph_mutex);
+       kref_put(&pipe->kref, vsp1_video_pipeline_release);
+       mutex_unlock(&mdev->graph_mutex);
 }
 
 /* -----------------------------------------------------------------------------
@@ -513,16 +559,16 @@ static int vsp1_video_buffer_prepare(struct vb2_buffer *vb)
        if (vb->num_planes < format->num_planes)
                return -EINVAL;
 
-       buf->mem.num_planes = vb->num_planes;
-
        for (i = 0; i < vb->num_planes; ++i) {
                buf->mem.addr[i] = vb2_dma_contig_plane_dma_addr(vb, i);
-               buf->mem.length[i] = vb2_plane_size(vb, i);
 
-               if (buf->mem.length[i] < format->plane_fmt[i].sizeimage)
+               if (vb2_plane_size(vb, i) < format->plane_fmt[i].sizeimage)
                        return -EINVAL;
        }
 
+       for ( ; i < 3; ++i)
+               buf->mem.addr[i] = 0;
+
        return 0;
 }
 
@@ -530,7 +576,7 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
 {
        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
        struct vsp1_video *video = vb2_get_drv_priv(vb->vb2_queue);
-       struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity);
+       struct vsp1_pipeline *pipe = video->rwpf->pipe;
        struct vsp1_vb2_buffer *buf = to_vsp1_vb2_buffer(vbuf);
        unsigned long flags;
        bool empty;
@@ -545,54 +591,66 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
 
        spin_lock_irqsave(&pipe->irqlock, flags);
 
-       video->rwpf->ops->set_memory(video->rwpf, &buf->mem);
+       video->rwpf->mem = buf->mem;
        pipe->buffers_ready |= 1 << video->pipe_index;
 
        if (vb2_is_streaming(&video->queue) &&
            vsp1_pipeline_ready(pipe))
-               vsp1_pipeline_run(pipe);
+               vsp1_video_pipeline_run(pipe);
 
        spin_unlock_irqrestore(&pipe->irqlock, flags);
 }
 
+static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
+{
+       struct vsp1_entity *entity;
+
+       /* Prepare the display list. */
+       pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
+       if (!pipe->dl)
+               return -ENOMEM;
+
+       if (pipe->uds) {
+               struct vsp1_uds *uds = to_uds(&pipe->uds->subdev);
+
+               /* If a BRU is present in the pipeline before the UDS, the alpha
+                * component doesn't need to be scaled as the BRU output alpha
+                * value is fixed to 255. Otherwise we need to scale the alpha
+                * component only when available at the input RPF.
+                */
+               if (pipe->uds_input->type == VSP1_ENTITY_BRU) {
+                       uds->scale_alpha = false;
+               } else {
+                       struct vsp1_rwpf *rpf =
+                               to_rwpf(&pipe->uds_input->subdev);
+
+                       uds->scale_alpha = rpf->fmtinfo->alpha;
+               }
+       }
+
+       list_for_each_entry(entity, &pipe->entities, list_pipe) {
+               vsp1_entity_route_setup(entity, pipe->dl);
+
+               if (entity->ops->configure)
+                       entity->ops->configure(entity, pipe, pipe->dl);
+       }
+
+       return 0;
+}
+
 static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
 {
        struct vsp1_video *video = vb2_get_drv_priv(vq);
-       struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity);
-       struct vsp1_entity *entity;
+       struct vsp1_pipeline *pipe = video->rwpf->pipe;
        unsigned long flags;
        int ret;
 
        mutex_lock(&pipe->lock);
        if (pipe->stream_count == pipe->num_inputs) {
-               if (pipe->uds) {
-                       struct vsp1_uds *uds = to_uds(&pipe->uds->subdev);
-
-                       /* If a BRU is present in the pipeline before the UDS,
-                        * the alpha component doesn't need to be scaled as the
-                        * BRU output alpha value is fixed to 255. Otherwise we
-                        * need to scale the alpha component only when available
-                        * at the input RPF.
-                        */
-                       if (pipe->uds_input->type == VSP1_ENTITY_BRU) {
-                               uds->scale_alpha = false;
-                       } else {
-                               struct vsp1_rwpf *rpf =
-                                       to_rwpf(&pipe->uds_input->subdev);
-
-                               uds->scale_alpha = rpf->fmtinfo->alpha;
-                       }
-               }
-
-               list_for_each_entry(entity, &pipe->entities, list_pipe) {
-                       vsp1_entity_route_setup(entity);
-
-                       ret = v4l2_subdev_call(&entity->subdev, video,
-                                              s_stream, 1);
-                       if (ret < 0) {
-                               mutex_unlock(&pipe->lock);
-                               return ret;
-                       }
+               ret = vsp1_video_setup_pipeline(pipe);
+               if (ret < 0) {
+                       mutex_unlock(&pipe->lock);
+                       return ret;
                }
        }
 
@@ -601,7 +659,7 @@ static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
 
        spin_lock_irqsave(&pipe->irqlock, flags);
        if (vsp1_pipeline_ready(pipe))
-               vsp1_pipeline_run(pipe);
+               vsp1_video_pipeline_run(pipe);
        spin_unlock_irqrestore(&pipe->irqlock, flags);
 
        return 0;
@@ -610,7 +668,7 @@ static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
 static void vsp1_video_stop_streaming(struct vb2_queue *vq)
 {
        struct vsp1_video *video = vb2_get_drv_priv(vq);
-       struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity);
+       struct vsp1_pipeline *pipe = video->rwpf->pipe;
        struct vsp1_vb2_buffer *buffer;
        unsigned long flags;
        int ret;
@@ -621,11 +679,14 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq)
                ret = vsp1_pipeline_stop(pipe);
                if (ret == -ETIMEDOUT)
                        dev_err(video->vsp1->dev, "pipeline stop timeout\n");
+
+               vsp1_dl_list_put(pipe->dl);
+               pipe->dl = NULL;
        }
        mutex_unlock(&pipe->lock);
 
-       vsp1_video_pipeline_cleanup(pipe);
        media_entity_pipeline_stop(&video->video.entity);
+       vsp1_video_pipeline_put(pipe);
 
        /* Remove all buffers from the IRQ queue. */
        spin_lock_irqsave(&video->irqlock, flags);
@@ -737,6 +798,7 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 {
        struct v4l2_fh *vfh = file->private_data;
        struct vsp1_video *video = to_vsp1_video(vfh->vdev);
+       struct media_device *mdev = &video->vsp1->media_dev;
        struct vsp1_pipeline *pipe;
        int ret;
 
@@ -745,18 +807,25 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 
        video->sequence = 0;
 
-       /* Start streaming on the pipeline. No link touching an entity in the
-        * pipeline can be activated or deactivated once streaming is started.
-        *
-        * Use the VSP1 pipeline object embedded in the first video object that
-        * starts streaming.
+       /* Get a pipeline for the video node and start streaming on it. No link
+        * touching an entity in the pipeline can be activated or deactivated
+        * once streaming is started.
         */
-       pipe = video->video.entity.pipe
-            ? to_vsp1_pipeline(&video->video.entity) : &video->pipe;
+       mutex_lock(&mdev->graph_mutex);
 
-       ret = media_entity_pipeline_start(&video->video.entity, &pipe->pipe);
-       if (ret < 0)
-               return ret;
+       pipe = vsp1_video_pipeline_get(video);
+       if (IS_ERR(pipe)) {
+               mutex_unlock(&mdev->graph_mutex);
+               return PTR_ERR(pipe);
+       }
+
+       ret = __media_entity_pipeline_start(&video->video.entity, &pipe->pipe);
+       if (ret < 0) {
+               mutex_unlock(&mdev->graph_mutex);
+               goto err_pipe;
+       }
+
+       mutex_unlock(&mdev->graph_mutex);
 
        /* Verify that the configured format matches the output of the connected
         * subdev.
@@ -765,21 +834,17 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
        if (ret < 0)
                goto err_stop;
 
-       ret = vsp1_video_pipeline_init(pipe, video);
-       if (ret < 0)
-               goto err_stop;
-
        /* Start the queue. */
        ret = vb2_streamon(&video->queue, type);
        if (ret < 0)
-               goto err_cleanup;
+               goto err_stop;
 
        return 0;
 
-err_cleanup:
-       vsp1_video_pipeline_cleanup(pipe);
 err_stop:
        media_entity_pipeline_stop(&video->video.entity);
+err_pipe:
+       vsp1_video_pipeline_put(pipe);
        return ret;
 }
 
@@ -895,26 +960,16 @@ struct vsp1_video *vsp1_video_create(struct vsp1_device *vsp1,
        spin_lock_init(&video->irqlock);
        INIT_LIST_HEAD(&video->irqqueue);
 
-       vsp1_pipeline_init(&video->pipe);
-       video->pipe.frame_end = vsp1_video_pipeline_frame_end;
-
        /* Initialize the media entity... */
        ret = media_entity_pads_init(&video->video.entity, 1, &video->pad);
        if (ret < 0)
                return ERR_PTR(ret);
 
        /* ... and the format ... */
-       rwpf->fmtinfo = vsp1_get_format_info(VSP1_VIDEO_DEF_FORMAT);
-       rwpf->format.pixelformat = rwpf->fmtinfo->fourcc;
-       rwpf->format.colorspace = V4L2_COLORSPACE_SRGB;
-       rwpf->format.field = V4L2_FIELD_NONE;
+       rwpf->format.pixelformat = VSP1_VIDEO_DEF_FORMAT;
        rwpf->format.width = VSP1_VIDEO_DEF_WIDTH;
        rwpf->format.height = VSP1_VIDEO_DEF_HEIGHT;
-       rwpf->format.num_planes = 1;
-       rwpf->format.plane_fmt[0].bytesperline =
-               rwpf->format.width * rwpf->fmtinfo->bpp[0] / 8;
-       rwpf->format.plane_fmt[0].sizeimage =
-               rwpf->format.plane_fmt[0].bytesperline * rwpf->format.height;
+       __vsp1_video_try_format(video, &rwpf->format, &rwpf->fmtinfo);
 
        /* ... and the video node... */
        video->video.v4l2_dev = &video->vsp1->v4l2_dev;
index 64abd39..867b008 100644 (file)
@@ -18,7 +18,6 @@
 
 #include <media/videobuf2-v4l2.h>
 
-#include "vsp1_pipe.h"
 #include "vsp1_rwpf.h"
 
 struct vsp1_vb2_buffer {
@@ -44,7 +43,6 @@ struct vsp1_video {
 
        struct mutex lock;
 
-       struct vsp1_pipeline pipe;
        unsigned int pipe_index;
 
        struct vb2_queue queue;
index c78d4af..6c91eaa 100644 (file)
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
+#include "vsp1_pipe.h"
 #include "vsp1_rwpf.h"
 #include "vsp1_video.h"
 
-#define WPF_MAX_WIDTH                          2048
-#define WPF_MAX_HEIGHT                         2048
+#define WPF_GEN2_MAX_WIDTH                     2048U
+#define WPF_GEN2_MAX_HEIGHT                    2048U
+#define WPF_GEN3_MAX_WIDTH                     8190U
+#define WPF_GEN3_MAX_HEIGHT                    8190U
 
 /* -----------------------------------------------------------------------------
  * Device Access
  */
 
-static inline u32 vsp1_wpf_read(struct vsp1_rwpf *wpf, u32 reg)
+static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf,
+                                 struct vsp1_dl_list *dl, u32 reg, u32 data)
 {
-       return vsp1_read(wpf->entity.vsp1,
-                        reg + wpf->entity.index * VI6_WPF_OFFSET);
-}
-
-static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf, u32 reg, u32 data)
-{
-       vsp1_mod_write(&wpf->entity,
-                      reg + wpf->entity.index * VI6_WPF_OFFSET, data);
+       vsp1_dl_list_write(dl, reg + wpf->entity.index * VI6_WPF_OFFSET, data);
 }
 
 /* -----------------------------------------------------------------------------
- * Controls
+ * V4L2 Subdevice Core Operations
  */
 
-static int wpf_s_ctrl(struct v4l2_ctrl *ctrl)
+static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 {
-       struct vsp1_rwpf *wpf =
-               container_of(ctrl->handler, struct vsp1_rwpf, ctrls);
-       u32 value;
+       struct vsp1_rwpf *wpf = to_rwpf(subdev);
+       struct vsp1_device *vsp1 = wpf->entity.vsp1;
 
-       if (!vsp1_entity_is_streaming(&wpf->entity))
+       if (enable)
                return 0;
 
-       switch (ctrl->id) {
-       case V4L2_CID_ALPHA_COMPONENT:
-               value = vsp1_wpf_read(wpf, VI6_WPF_OUTFMT);
-               value &= ~VI6_WPF_OUTFMT_PDV_MASK;
-               value |= ctrl->val << VI6_WPF_OUTFMT_PDV_SHIFT;
-               vsp1_wpf_write(wpf, VI6_WPF_OUTFMT, value);
-               break;
-       }
+       /* Write to registers directly when stopping the stream as there will be
+        * no pipeline run to apply the display list.
+        */
+       vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0);
+       vsp1_write(vsp1, wpf->entity.index * VI6_WPF_OFFSET +
+                  VI6_WPF_SRCRPF, 0);
 
        return 0;
 }
 
-static const struct v4l2_ctrl_ops wpf_ctrl_ops = {
-       .s_ctrl = wpf_s_ctrl,
-};
-
 /* -----------------------------------------------------------------------------
- * V4L2 Subdevice Core Operations
+ * V4L2 Subdevice Operations
  */
 
-static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
-{
-       struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity);
-       struct vsp1_rwpf *wpf = to_rwpf(subdev);
-       struct vsp1_device *vsp1 = wpf->entity.vsp1;
-       const struct v4l2_rect *crop = &wpf->crop;
-       unsigned int i;
-       u32 srcrpf = 0;
-       u32 outfmt = 0;
-       int ret;
-
-       ret = vsp1_entity_set_streaming(&wpf->entity, enable);
-       if (ret < 0)
-               return ret;
+static struct v4l2_subdev_video_ops wpf_video_ops = {
+       .s_stream = wpf_s_stream,
+};
 
-       if (!enable) {
-               vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0);
-               vsp1_write(vsp1, wpf->entity.index * VI6_WPF_OFFSET +
-                          VI6_WPF_SRCRPF, 0);
-               return 0;
-       }
+static struct v4l2_subdev_ops wpf_ops = {
+       .video  = &wpf_video_ops,
+       .pad    = &vsp1_rwpf_pad_ops,
+};
 
-       /* Sources. If the pipeline has a single input and BRU is not used,
-        * configure it as the master layer. Otherwise configure all
-        * inputs as sub-layers and select the virtual RPF as the master
-        * layer.
-        */
-       for (i = 0; i < vsp1->info->rpf_count; ++i) {
-               struct vsp1_rwpf *input = pipe->inputs[i];
+/* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
 
-               if (!input)
-                       continue;
+static void vsp1_wpf_destroy(struct vsp1_entity *entity)
+{
+       struct vsp1_rwpf *wpf = entity_to_rwpf(entity);
 
-               srcrpf |= (!pipe->bru && pipe->num_inputs == 1)
-                       ? VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index)
-                       : VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index);
-       }
+       vsp1_dlm_destroy(wpf->dlm);
+}
 
-       if (pipe->bru || pipe->num_inputs > 1)
-               srcrpf |= VI6_WPF_SRCRPF_VIRACT_MST;
+static void wpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl)
+{
+       struct vsp1_rwpf *wpf = entity_to_rwpf(entity);
 
-       vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf);
+       vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, wpf->mem.addr[0]);
+       vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, wpf->mem.addr[1]);
+       vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, wpf->mem.addr[2]);
+}
 
-       /* Destination stride. */
-       if (!pipe->lif) {
-               struct v4l2_pix_format_mplane *format = &wpf->format;
+static void wpf_configure(struct vsp1_entity *entity,
+                         struct vsp1_pipeline *pipe,
+                         struct vsp1_dl_list *dl)
+{
+       struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
+       struct vsp1_device *vsp1 = wpf->entity.vsp1;
+       const struct v4l2_mbus_framefmt *source_format;
+       const struct v4l2_mbus_framefmt *sink_format;
+       const struct v4l2_rect *crop;
+       unsigned int i;
+       u32 outfmt = 0;
+       u32 srcrpf = 0;
 
-               vsp1_wpf_write(wpf, VI6_WPF_DSTM_STRIDE_Y,
-                              format->plane_fmt[0].bytesperline);
-               if (format->num_planes > 1)
-                       vsp1_wpf_write(wpf, VI6_WPF_DSTM_STRIDE_C,
-                                      format->plane_fmt[1].bytesperline);
-       }
+       /* Cropping */
+       crop = vsp1_rwpf_get_crop(wpf, wpf->entity.config);
 
-       vsp1_wpf_write(wpf, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
+       vsp1_wpf_write(wpf, dl, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
                       (crop->left << VI6_WPF_SZCLIP_OFST_SHIFT) |
                       (crop->width << VI6_WPF_SZCLIP_SIZE_SHIFT));
-       vsp1_wpf_write(wpf, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN |
+       vsp1_wpf_write(wpf, dl, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN |
                       (crop->top << VI6_WPF_SZCLIP_OFST_SHIFT) |
                       (crop->height << VI6_WPF_SZCLIP_SIZE_SHIFT));
 
        /* Format */
+       sink_format = vsp1_entity_get_pad_format(&wpf->entity,
+                                                wpf->entity.config,
+                                                RWPF_PAD_SINK);
+       source_format = vsp1_entity_get_pad_format(&wpf->entity,
+                                                  wpf->entity.config,
+                                                  RWPF_PAD_SOURCE);
+
        if (!pipe->lif) {
+               const struct v4l2_pix_format_mplane *format = &wpf->format;
                const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
 
                outfmt = fmtinfo->hwfmt << VI6_WPF_OUTFMT_WRFMT_SHIFT;
@@ -145,73 +135,58 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
                if (fmtinfo->swap_uv)
                        outfmt |= VI6_WPF_OUTFMT_SPUVS;
 
-               vsp1_wpf_write(wpf, VI6_WPF_DSWAP, fmtinfo->swap);
+               /* Destination stride and byte swapping. */
+               vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_STRIDE_Y,
+                              format->plane_fmt[0].bytesperline);
+               if (format->num_planes > 1)
+                       vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_STRIDE_C,
+                                      format->plane_fmt[1].bytesperline);
+
+               vsp1_wpf_write(wpf, dl, VI6_WPF_DSWAP, fmtinfo->swap);
        }
 
-       if (wpf->entity.formats[RWPF_PAD_SINK].code !=
-           wpf->entity.formats[RWPF_PAD_SOURCE].code)
+       if (sink_format->code != source_format->code)
                outfmt |= VI6_WPF_OUTFMT_CSC;
 
-       /* Take the control handler lock to ensure that the PDV value won't be
-        * changed behind our back by a set control operation.
-        */
-       if (vsp1->info->uapi)
-               mutex_lock(wpf->ctrls.lock);
-       outfmt |= wpf->alpha->cur.val << VI6_WPF_OUTFMT_PDV_SHIFT;
-       vsp1_wpf_write(wpf, VI6_WPF_OUTFMT, outfmt);
-       if (vsp1->info->uapi)
-               mutex_unlock(wpf->ctrls.lock);
-
-       vsp1_mod_write(&wpf->entity, VI6_DPR_WPF_FPORCH(wpf->entity.index),
-                      VI6_DPR_WPF_FPORCH_FP_WPFN);
+       outfmt |= wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT;
+       vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, outfmt);
 
-       vsp1_mod_write(&wpf->entity, VI6_WPF_WRBCK_CTRL, 0);
+       vsp1_dl_list_write(dl, VI6_DPR_WPF_FPORCH(wpf->entity.index),
+                          VI6_DPR_WPF_FPORCH_FP_WPFN);
 
-       /* Enable interrupts */
-       vsp1_write(vsp1, VI6_WPF_IRQ_STA(wpf->entity.index), 0);
-       vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index),
-                  VI6_WFP_IRQ_ENB_FREE);
-
-       return 0;
-}
+       vsp1_dl_list_write(dl, VI6_WPF_WRBCK_CTRL, 0);
 
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Operations
- */
+       /* Sources. If the pipeline has a single input and BRU is not used,
+        * configure it as the master layer. Otherwise configure all
+        * inputs as sub-layers and select the virtual RPF as the master
+        * layer.
+        */
+       for (i = 0; i < vsp1->info->rpf_count; ++i) {
+               struct vsp1_rwpf *input = pipe->inputs[i];
 
-static struct v4l2_subdev_video_ops wpf_video_ops = {
-       .s_stream = wpf_s_stream,
-};
+               if (!input)
+                       continue;
 
-static struct v4l2_subdev_pad_ops wpf_pad_ops = {
-       .enum_mbus_code = vsp1_rwpf_enum_mbus_code,
-       .enum_frame_size = vsp1_rwpf_enum_frame_size,
-       .get_fmt = vsp1_rwpf_get_format,
-       .set_fmt = vsp1_rwpf_set_format,
-       .get_selection = vsp1_rwpf_get_selection,
-       .set_selection = vsp1_rwpf_set_selection,
-};
+               srcrpf |= (!pipe->bru && pipe->num_inputs == 1)
+                       ? VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index)
+                       : VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index);
+       }
 
-static struct v4l2_subdev_ops wpf_ops = {
-       .video  = &wpf_video_ops,
-       .pad    = &wpf_pad_ops,
-};
+       if (pipe->bru || pipe->num_inputs > 1)
+               srcrpf |= VI6_WPF_SRCRPF_VIRACT_MST;
 
-/* -----------------------------------------------------------------------------
- * Video Device Operations
- */
+       vsp1_wpf_write(wpf, dl, VI6_WPF_SRCRPF, srcrpf);
 
-static void wpf_set_memory(struct vsp1_rwpf *wpf, struct vsp1_rwpf_memory *mem)
-{
-       vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_Y, mem->addr[0]);
-       if (mem->num_planes > 1)
-               vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C0, mem->addr[1]);
-       if (mem->num_planes > 2)
-               vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, mem->addr[2]);
+       /* Enable interrupts */
+       vsp1_dl_list_write(dl, VI6_WPF_IRQ_STA(wpf->entity.index), 0);
+       vsp1_dl_list_write(dl, VI6_WPF_IRQ_ENB(wpf->entity.index),
+                          VI6_WFP_IRQ_ENB_FREE);
 }
 
-static const struct vsp1_rwpf_operations wpf_vdev_ops = {
+static const struct vsp1_entity_operations wpf_entity_ops = {
+       .destroy = vsp1_wpf_destroy,
        .set_memory = wpf_set_memory,
+       .configure = wpf_configure,
 };
 
 /* -----------------------------------------------------------------------------
@@ -220,51 +195,43 @@ static const struct vsp1_rwpf_operations wpf_vdev_ops = {
 
 struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 {
-       struct v4l2_subdev *subdev;
        struct vsp1_rwpf *wpf;
+       char name[6];
        int ret;
 
        wpf = devm_kzalloc(vsp1->dev, sizeof(*wpf), GFP_KERNEL);
        if (wpf == NULL)
                return ERR_PTR(-ENOMEM);
 
-       wpf->ops = &wpf_vdev_ops;
-
-       wpf->max_width = WPF_MAX_WIDTH;
-       wpf->max_height = WPF_MAX_HEIGHT;
+       if (vsp1->info->gen == 2) {
+               wpf->max_width = WPF_GEN2_MAX_WIDTH;
+               wpf->max_height = WPF_GEN2_MAX_HEIGHT;
+       } else {
+               wpf->max_width = WPF_GEN3_MAX_WIDTH;
+               wpf->max_height = WPF_GEN3_MAX_HEIGHT;
+       }
 
+       wpf->entity.ops = &wpf_entity_ops;
        wpf->entity.type = VSP1_ENTITY_WPF;
        wpf->entity.index = index;
 
-       ret = vsp1_entity_init(vsp1, &wpf->entity, 2);
+       sprintf(name, "wpf.%u", index);
+       ret = vsp1_entity_init(vsp1, &wpf->entity, name, 2, &wpf_ops);
        if (ret < 0)
                return ERR_PTR(ret);
 
-       /* Initialize the V4L2 subdev. */
-       subdev = &wpf->entity.subdev;
-       v4l2_subdev_init(subdev, &wpf_ops);
-
-       subdev->entity.ops = &vsp1->media_ops;
-       subdev->internal_ops = &vsp1_subdev_internal_ops;
-       snprintf(subdev->name, sizeof(subdev->name), "%s wpf.%u",
-                dev_name(vsp1->dev), index);
-       v4l2_set_subdevdata(subdev, wpf);
-       subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-       vsp1_entity_init_formats(subdev, NULL);
+       /* Initialize the display list manager. */
+       wpf->dlm = vsp1_dlm_create(vsp1, index, 4);
+       if (!wpf->dlm) {
+               ret = -ENOMEM;
+               goto error;
+       }
 
        /* Initialize the control handler. */
-       v4l2_ctrl_handler_init(&wpf->ctrls, 1);
-       wpf->alpha = v4l2_ctrl_new_std(&wpf->ctrls, &wpf_ctrl_ops,
-                                      V4L2_CID_ALPHA_COMPONENT,
-                                      0, 255, 1, 255);
-
-       wpf->entity.subdev.ctrl_handler = &wpf->ctrls;
-
-       if (wpf->ctrls.error) {
+       ret = vsp1_rwpf_init_ctrls(wpf);
+       if (ret < 0) {
                dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n",
                        index);
-               ret = wpf->ctrls.error;
                goto error;
        }
 
index e795a45..feb3b2f 100644 (file)
@@ -351,19 +351,15 @@ static int xvip_graph_parse_one(struct xvip_composite_device *xdev,
        struct xvip_graph_entity *entity;
        struct device_node *remote;
        struct device_node *ep = NULL;
-       struct device_node *next;
        int ret = 0;
 
        dev_dbg(xdev->dev, "parsing node %s\n", node->full_name);
 
        while (1) {
-               next = of_graph_get_next_endpoint(node, ep);
-               if (next == NULL)
+               ep = of_graph_get_next_endpoint(node, ep);
+               if (ep == NULL)
                        break;
 
-               of_node_put(ep);
-               ep = next;
-
                dev_dbg(xdev->dev, "handling endpoint %s\n", ep->full_name);
 
                remote = of_graph_get_remote_port_parent(ep);
index 3f61d77..9f5b597 100644 (file)
@@ -873,13 +873,10 @@ static int ati_remote_probe(struct usb_interface *interface,
        strlcat(ati_remote->rc_phys, "/input0", sizeof(ati_remote->rc_phys));
        strlcat(ati_remote->mouse_phys, "/input1", sizeof(ati_remote->mouse_phys));
 
-       if (udev->manufacturer)
-               strlcpy(ati_remote->rc_name, udev->manufacturer,
-                       sizeof(ati_remote->rc_name));
-
-       if (udev->product)
-               snprintf(ati_remote->rc_name, sizeof(ati_remote->rc_name),
-                        "%s %s", ati_remote->rc_name, udev->product);
+       snprintf(ati_remote->rc_name, sizeof(ati_remote->rc_name), "%s%s%s",
+               udev->manufacturer ?: "",
+               udev->manufacturer && udev->product ? " " : "",
+               udev->product ?: "");
 
        if (!strlen(ati_remote->rc_name))
                snprintf(ati_remote->rc_name, sizeof(ati_remote->rc_name),
index 35155ae..5cf2e74 100644 (file)
 #define VENDOR_TWISTEDMELON    0x2596
 #define VENDOR_HAUPPAUGE       0x2040
 #define VENDOR_PCTV            0x2013
+#define VENDOR_ADAPTEC         0x03f3
 
 enum mceusb_model_type {
        MCE_GEN2 = 0,           /* Most boards */
@@ -302,6 +303,9 @@ static struct usb_device_id mceusb_dev_table[] = {
        /* SMK/I-O Data GV-MC7/RCKIT Receiver */
        { USB_DEVICE(VENDOR_SMK, 0x0353),
          .driver_info = MCE_GEN2_NO_TX },
+       /* SMK RXX6000 Infrared Receiver */
+       { USB_DEVICE(VENDOR_SMK, 0x0357),
+         .driver_info = MCE_GEN2_NO_TX },
        /* Tatung eHome Infrared Transceiver */
        { USB_DEVICE(VENDOR_TATUNG, 0x9150) },
        /* Shuttle eHome Infrared Transceiver */
@@ -405,6 +409,8 @@ static struct usb_device_id mceusb_dev_table[] = {
          .driver_info = HAUPPAUGE_CX_HYBRID_TV },
        { USB_DEVICE(VENDOR_PCTV, 0x025e),
          .driver_info = HAUPPAUGE_CX_HYBRID_TV },
+       /* Adaptec / HP eHome Receiver */
+       { USB_DEVICE(VENDOR_ADAPTEC, 0x0094) },
 
        /* Terminating entry */
        { }
index 4e9bbe7..7dfc7c2 100644 (file)
@@ -1263,6 +1263,9 @@ unlock:
 
 static void rc_dev_release(struct device *device)
 {
+       struct rc_dev *dev = to_rc_dev(device);
+
+       kfree(dev);
 }
 
 #define ADD_HOTPLUG_VAR(fmt, val...)                                   \
@@ -1384,7 +1387,9 @@ void rc_free_device(struct rc_dev *dev)
 
        put_device(&dev->dev);
 
-       kfree(dev);
+       /* kfree(dev) will be called by the callback function
+          rc_dev_release() */
+
        module_put(THIS_MODULE);
 }
 EXPORT_SYMBOL_GPL(rc_free_device);
@@ -1492,9 +1497,7 @@ int rc_register_device(struct rc_dev *dev)
        }
 
        /* Allow the RC sysfs nodes to be accessible */
-       mutex_lock(&dev->lock);
        atomic_set(&dev->initialized, 1);
-       mutex_unlock(&dev->lock);
 
        IR_dprintk(1, "Registered rc%u (driver: %s, remote: %s, mode %s)\n",
                   dev->minor,
index 18bc745..9af2a15 100644 (file)
 #include "qm1d1c0042.h"
 
 #define QM1D1C0042_NUM_REGS 0x20
-
-static const u8 reg_initval[QM1D1C0042_NUM_REGS] = {
-       0x48, 0x1c, 0xa0, 0x10, 0xbc, 0xc5, 0x20, 0x33,
-       0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-       0x00, 0xff, 0xf3, 0x00, 0x2a, 0x64, 0xa6, 0x86,
-       0x8c, 0xcf, 0xb8, 0xf1, 0xa8, 0xf2, 0x89, 0x00
+#define QM1D1C0042_NUM_REG_ROWS 2
+
+static const u8
+reg_initval[QM1D1C0042_NUM_REG_ROWS][QM1D1C0042_NUM_REGS] = { {
+               0x48, 0x1c, 0xa0, 0x10, 0xbc, 0xc5, 0x20, 0x33,
+               0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+               0x00, 0xff, 0xf3, 0x00, 0x2a, 0x64, 0xa6, 0x86,
+               0x8c, 0xcf, 0xb8, 0xf1, 0xa8, 0xf2, 0x89, 0x00
+       }, {
+               0x68, 0x1c, 0xc0, 0x10, 0xbc, 0xc1, 0x11, 0x33,
+               0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+               0x00, 0xff, 0xf3, 0x00, 0x3f, 0x25, 0x5c, 0xd6,
+               0x55, 0xcf, 0x95, 0xf6, 0x36, 0xf2, 0x09, 0x00
+       }
 };
 
+static int reg_index;
+
 static const struct qm1d1c0042_config default_cfg = {
        .xtal_freq = 16000,
        .lpf = 1,
@@ -320,7 +330,6 @@ static int qm1d1c0042_init(struct dvb_frontend *fe)
        int i, ret;
 
        state = fe->tuner_priv;
-       memcpy(state->regs, reg_initval, sizeof(reg_initval));
 
        reg_write(state, 0x01, 0x0c);
        reg_write(state, 0x01, 0x0c);
@@ -330,15 +339,22 @@ static int qm1d1c0042_init(struct dvb_frontend *fe)
                goto failed;
        usleep_range(2000, 3000);
 
-       val = state->regs[0x01] | 0x10;
-       ret = reg_write(state, 0x01, val); /* soft reset off */
+       ret = reg_write(state, 0x01, 0x1c); /* soft reset off */
        if (ret < 0)
                goto failed;
 
-       /* check ID */
+       /* check ID and choose initial registers corresponding ID */
        ret = reg_read(state, 0x00, &val);
-       if (ret < 0 || val != 0x48)
+       if (ret < 0)
+               goto failed;
+       for (reg_index = 0; reg_index < QM1D1C0042_NUM_REG_ROWS;
+            reg_index++) {
+               if (val == reg_initval[reg_index][0x00])
+                       break;
+       }
+       if (reg_index >= QM1D1C0042_NUM_REG_ROWS)
                goto failed;
+       memcpy(state->regs, reg_initval[reg_index], QM1D1C0042_NUM_REGS);
        usleep_range(2000, 3000);
 
        state->regs[0x0c] |= 0x40;
index 243ac38..b07a681 100644 (file)
@@ -84,11 +84,22 @@ static int si2157_init(struct dvb_frontend *fe)
        struct si2157_cmd cmd;
        const struct firmware *fw;
        const char *fw_name;
-       unsigned int chip_id;
+       unsigned int uitmp, chip_id;
 
        dev_dbg(&client->dev, "\n");
 
-       if (dev->fw_loaded)
+       /* Returned IF frequency is garbage when firmware is not running */
+       memcpy(cmd.args, "\x15\x00\x06\x07", 4);
+       cmd.wlen = 4;
+       cmd.rlen = 4;
+       ret = si2157_cmd_execute(client, &cmd);
+       if (ret)
+               goto err;
+
+       uitmp = cmd.args[2] << 0 | cmd.args[3] << 8;
+       dev_dbg(&client->dev, "if_frequency kHz=%u\n", uitmp);
+
+       if (uitmp == dev->if_frequency / 1000)
                goto warm;
 
        /* power up */
@@ -203,9 +214,6 @@ skip_fw_download:
 
        dev_info(&client->dev, "firmware version: %c.%c.%d\n",
                        cmd.args[6], cmd.args[7], cmd.args[8]);
-
-       dev->fw_loaded = true;
-
 warm:
        /* init statistics in order signal app which are supported */
        c->strength.len = 1;
@@ -422,7 +430,6 @@ static int si2157_probe(struct i2c_client *client,
        dev->fe = cfg->fe;
        dev->inversion = cfg->inversion;
        dev->if_port = cfg->if_port;
-       dev->fw_loaded = false;
        dev->chiptype = (u8)id->driver_data;
        dev->if_frequency = 5000000; /* default value of property 0x0706 */
        mutex_init(&dev->i2c_mutex);
index 589d558..d6b2c7b 100644 (file)
@@ -26,7 +26,6 @@ struct si2157_dev {
        struct mutex i2c_mutex;
        struct dvb_frontend *fe;
        bool active;
-       bool fw_loaded;
        bool inversion;
        u8 chiptype;
        u8 if_port;
index cc22b32..321ea5c 100644 (file)
@@ -131,22 +131,36 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
        return status;
 }
 
+#ifdef CONFIG_MEDIA_CONTROLLER
+static void au0828_media_graph_notify(struct media_entity *new,
+                                     void *notify_data);
+#endif
+
 static void au0828_unregister_media_device(struct au0828_dev *dev)
 {
-
 #ifdef CONFIG_MEDIA_CONTROLLER
-       if (dev->media_dev &&
-               media_devnode_is_registered(&dev->media_dev->devnode)) {
-               /* clear enable_source, disable_source */
-               dev->media_dev->source_priv = NULL;
-               dev->media_dev->enable_source = NULL;
-               dev->media_dev->disable_source = NULL;
-
-               media_device_unregister(dev->media_dev);
-               media_device_cleanup(dev->media_dev);
-               kfree(dev->media_dev);
-               dev->media_dev = NULL;
+       struct media_device *mdev = dev->media_dev;
+       struct media_entity_notify *notify, *nextp;
+
+       if (!mdev || !media_devnode_is_registered(&mdev->devnode))
+               return;
+
+       /* Remove au0828 entity_notify callbacks */
+       list_for_each_entry_safe(notify, nextp, &mdev->entity_notify, list) {
+               if (notify->notify != au0828_media_graph_notify)
+                       continue;
+               media_device_unregister_entity_notify(mdev, notify);
        }
+
+       /* clear enable_source, disable_source */
+       dev->media_dev->source_priv = NULL;
+       dev->media_dev->enable_source = NULL;
+       dev->media_dev->disable_source = NULL;
+
+       media_device_unregister(dev->media_dev);
+       media_device_cleanup(dev->media_dev);
+       kfree(dev->media_dev);
+       dev->media_dev = NULL;
 #endif
 }
 
index 32d7db9..7d0ec4c 100644 (file)
@@ -679,8 +679,6 @@ int au0828_v4l2_device_register(struct usb_interface *interface,
        if (retval) {
                pr_err("%s() v4l2_device_register failed\n",
                       __func__);
-               mutex_unlock(&dev->lock);
-               kfree(dev);
                return retval;
        }
 
@@ -691,8 +689,6 @@ int au0828_v4l2_device_register(struct usb_interface *interface,
        if (retval) {
                pr_err("%s() v4l2_ctrl_handler_init failed\n",
                       __func__);
-               mutex_unlock(&dev->lock);
-               kfree(dev);
                return retval;
        }
        dev->v4l2_dev.ctrl_handler = &dev->v4l2_ctrl_hdl;
index 87f3284..dd7b378 100644 (file)
@@ -55,7 +55,6 @@
 #define NTSC_STD_H      480
 
 #define AU0828_INTERLACED_DEFAULT       1
-#define V4L2_CID_PRIVATE_SHARPNESS  (V4L2_CID_PRIVATE_BASE + 0)
 
 /* Defination for AU0828 USB transfer */
 #define AU0828_MAX_ISO_BUFS    12  /* maybe resize this value in the future */
index c9320d6..00da024 100644 (file)
@@ -360,7 +360,7 @@ static int wait_for_mci_complete(struct cx231xx *dev)
 
                if (count++ > 100) {
                        dprintk(3, "ERROR: Timeout - gpio=%x\n", gpio);
-                       return -1;
+                       return -EIO;
                }
        }
        return 0;
@@ -856,7 +856,7 @@ static int cx231xx_find_mailbox(struct cx231xx *dev)
                }
        }
        dprintk(3, "Mailbox signature values not found!\n");
-       return -1;
+       return -EIO;
 }
 
 static void mci_write_memory_to_gpio(struct cx231xx *dev, u32 address, u32 value,
@@ -960,13 +960,14 @@ static int cx231xx_load_firmware(struct cx231xx *dev)
        p_fw = p_current_fw;
        if (p_current_fw == NULL) {
                dprintk(2, "FAIL!!!\n");
-               return -1;
+               return -ENOMEM;
        }
 
        p_buffer = vmalloc(4096);
        if (p_buffer == NULL) {
                dprintk(2, "FAIL!!!\n");
-               return -1;
+               vfree(p_current_fw);
+               return -ENOMEM;
        }
 
        dprintk(2, "%s()\n", __func__);
@@ -989,7 +990,9 @@ static int cx231xx_load_firmware(struct cx231xx *dev)
        if (retval != 0) {
                dev_err(dev->dev,
                        "%s: Error with mc417_register_write\n", __func__);
-               return -1;
+               vfree(p_current_fw);
+               vfree(p_buffer);
+               return retval;
        }
 
        retval = request_firmware(&firmware, CX231xx_FIRM_IMAGE_NAME,
@@ -1001,7 +1004,9 @@ static int cx231xx_load_firmware(struct cx231xx *dev)
                        CX231xx_FIRM_IMAGE_NAME);
                dev_err(dev->dev,
                        "Please fix your hotplug setup, the board will not work without firmware loaded!\n");
-               return -1;
+               vfree(p_current_fw);
+               vfree(p_buffer);
+               return retval;
        }
 
        if (firmware->size != CX231xx_FIRM_IMAGE_SIZE) {
@@ -1009,14 +1014,18 @@ static int cx231xx_load_firmware(struct cx231xx *dev)
                        "ERROR: Firmware size mismatch (have %zd, expected %d)\n",
                        firmware->size, CX231xx_FIRM_IMAGE_SIZE);
                release_firmware(firmware);
-               return -1;
+               vfree(p_current_fw);
+               vfree(p_buffer);
+               return -EINVAL;
        }
 
        if (0 != memcmp(firmware->data, magic, 8)) {
                dev_err(dev->dev,
                        "ERROR: Firmware magic mismatch, wrong file?\n");
                release_firmware(firmware);
-               return -1;
+               vfree(p_current_fw);
+               vfree(p_buffer);
+               return -EINVAL;
        }
 
        initGPIO(dev);
@@ -1131,21 +1140,21 @@ static int cx231xx_initialize_codec(struct cx231xx *dev)
                if (retval < 0) {
                        dev_err(dev->dev, "%s: mailbox < 0, error\n",
                                __func__);
-                       return -1;
+                       return retval;
                }
                dev->cx23417_mailbox = retval;
                retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0);
                if (retval < 0) {
                        dev_err(dev->dev,
                                "ERROR: cx23417 firmware ping failed!\n");
-                       return -1;
+                       return retval;
                }
                retval = cx231xx_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1,
                        &version);
                if (retval < 0) {
                        dev_err(dev->dev,
                                "ERROR: cx23417 firmware get encoder: version failed!\n");
-                       return -1;
+                       return retval;
                }
                dprintk(1, "cx23417 firmware version is 0x%08x\n", version);
                msleep(200);
index f497888..6741fd0 100644 (file)
@@ -752,7 +752,8 @@ EXPORT_SYMBOL_GPL(cx231xx_set_mode);
 int cx231xx_ep5_bulkout(struct cx231xx *dev, u8 *firmware, u16 size)
 {
        int errCode = 0;
-       int actlen, ret = -ENOMEM;
+       int actlen = -1;
+       int ret = -ENOMEM;
        u32 *buffer;
 
        buffer = kzalloc(4096, GFP_KERNEL);
index df22001..89e629a 100644 (file)
@@ -118,20 +118,20 @@ static const u32 clock_lut_it9135[] = {
  * Values 0, 3 and 5 are seen to this day. 0 for single TS and 3/5 for dual TS.
  */
 
-#define EEPROM_BASE_AF9035        0x42fd
-#define EEPROM_BASE_IT9135        0x499c
+#define EEPROM_BASE_AF9035        0x42f5
+#define EEPROM_BASE_IT9135        0x4994
 #define EEPROM_SHIFT                0x10
 
-#define EEPROM_IR_MODE              0x10
-#define EEPROM_TS_MODE              0x29
-#define EEPROM_2ND_DEMOD_ADDR       0x2a
-#define EEPROM_IR_TYPE              0x2c
-#define EEPROM_1_IF_L               0x30
-#define EEPROM_1_IF_H               0x31
-#define EEPROM_1_TUNER_ID           0x34
-#define EEPROM_2_IF_L               0x40
-#define EEPROM_2_IF_H               0x41
-#define EEPROM_2_TUNER_ID           0x44
+#define EEPROM_IR_MODE              0x18
+#define EEPROM_TS_MODE              0x31
+#define EEPROM_2ND_DEMOD_ADDR       0x32
+#define EEPROM_IR_TYPE              0x34
+#define EEPROM_1_IF_L               0x38
+#define EEPROM_1_IF_H               0x39
+#define EEPROM_1_TUNER_ID           0x3c
+#define EEPROM_2_IF_L               0x48
+#define EEPROM_2_IF_H               0x49
+#define EEPROM_2_TUNER_ID           0x4c
 
 /* USB commands */
 #define CMD_MEM_RD                  0x00
index 92e47d6..2e71136 100644 (file)
@@ -1090,6 +1090,7 @@ static struct usb_device_id az6027_usb_table[] = {
        { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V2) },
        { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT) },
        { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT_V2) },
+       { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT_V3) },
        { },
 };
 
@@ -1138,7 +1139,7 @@ static struct dvb_usb_device_properties az6027_properties = {
 
        .i2c_algo         = &az6027_i2c_algo,
 
-       .num_device_descs = 7,
+       .num_device_descs = 8,
        .devices = {
                {
                        .name = "AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)",
@@ -1168,6 +1169,10 @@ static struct dvb_usb_device_properties az6027_properties = {
                        .name = "Elgato EyeTV Sat",
                        .cold_ids = { &az6027_usb_table[6], NULL },
                        .warm_ids = { NULL },
+               }, {
+                       .name = "Elgato EyeTV Sat",
+                       .cold_ids = { &az6027_usb_table[7], NULL },
+                       .warm_ids = { NULL },
                },
                { NULL },
        }
index ea0391e..0857b56 100644 (file)
@@ -3814,6 +3814,7 @@ struct usb_device_id dib0700_usb_id_table[] = {
        { USB_DEVICE(USB_VID_PCTV,      USB_PID_PCTV_2002E) },
        { USB_DEVICE(USB_VID_PCTV,      USB_PID_PCTV_2002E_SE) },
        { USB_DEVICE(USB_VID_PCTV,      USB_PID_DIBCOM_STK8096PVR) },
+       { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK8096PVR) },
        { 0 }           /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -5017,7 +5018,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_device_descs = 1,
                .devices = {
                        {   "DiBcom STK8096-PVR reference design",
-                               { &dib0700_usb_id_table[83], NULL },
+                               { &dib0700_usb_id_table[83],
+                                       &dib0700_usb_id_table[84], NULL},
                                { NULL },
                        },
                },
index 35de609..6eea4e6 100644 (file)
@@ -184,6 +184,8 @@ int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val)
 }
 EXPORT_SYMBOL(dibusb_read_eeprom_byte);
 
+#if IS_ENABLED(CONFIG_DVB_DIB3000MC)
+
 /* 3000MC/P stuff */
 // Config Adjacent channels  Perf -cal22
 static struct dibx000_agc_config dib3000p_mt2060_agc_config = {
@@ -242,8 +244,6 @@ static struct dibx000_agc_config dib3000p_panasonic_agc_config = {
        .agc2_slope2 = 0x1e,
 };
 
-#if IS_ENABLED(CONFIG_DVB_DIB3000MC)
-
 static struct dib3000mc_config mod3000p_dib3000p_config = {
        &dib3000p_panasonic_agc_config,
 
index 6d0dd85..49b55d7 100644 (file)
@@ -13,6 +13,7 @@
  *
  * see Documentation/dvb/README.dvb-usb for more information
  */
+#include "dvb-usb-ids.h"
 #include "dw2102.h"
 #include "si21xx.h"
 #include "stv0299.h"
 /* Max transfer size done by I2C transfer functions */
 #define MAX_XFER_SIZE  64
 
-#ifndef USB_PID_DW2102
-#define USB_PID_DW2102 0x2102
-#endif
-
-#ifndef USB_PID_DW2104
-#define USB_PID_DW2104 0x2104
-#endif
-
-#ifndef USB_PID_DW3101
-#define USB_PID_DW3101 0x3101
-#endif
-
-#ifndef USB_PID_CINERGY_S
-#define USB_PID_CINERGY_S 0x0064
-#endif
-
-#ifndef USB_PID_TEVII_S630
-#define USB_PID_TEVII_S630 0xd630
-#endif
-
-#ifndef USB_PID_TEVII_S650
-#define USB_PID_TEVII_S650 0xd650
-#endif
-
-#ifndef USB_PID_TEVII_S660
-#define USB_PID_TEVII_S660 0xd660
-#endif
-
-#ifndef USB_PID_TEVII_S662
-#define USB_PID_TEVII_S662 0xd662
-#endif
-
-#ifndef USB_PID_TEVII_S480_1
-#define USB_PID_TEVII_S480_1 0xd481
-#endif
-
-#ifndef USB_PID_TEVII_S480_2
-#define USB_PID_TEVII_S480_2 0xd482
-#endif
-
-#ifndef USB_PID_PROF_1100
-#define USB_PID_PROF_1100 0xb012
-#endif
-
-#ifndef USB_PID_TEVII_S421
-#define USB_PID_TEVII_S421 0xd421
-#endif
-
-#ifndef USB_PID_TEVII_S632
-#define USB_PID_TEVII_S632 0xd632
-#endif
-
-#ifndef USB_PID_GOTVIEW_SAT_HD
-#define USB_PID_GOTVIEW_SAT_HD 0x5456
-#endif
 
 #define DW210X_READ_MSG 0
 #define DW210X_WRITE_MSG 1
@@ -1709,7 +1655,7 @@ static struct usb_device_id dw2102_table[] = {
        [CYPRESS_DW2101] = {USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
        [CYPRESS_DW2104] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)},
        [TEVII_S650] = {USB_DEVICE(0x9022, USB_PID_TEVII_S650)},
-       [TERRATEC_CINERGY_S] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
+       [TERRATEC_CINERGY_S] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_S)},
        [CYPRESS_DW3101] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)},
        [TEVII_S630] = {USB_DEVICE(0x9022, USB_PID_TEVII_S630)},
        [PROF_1100] = {USB_DEVICE(0x3011, USB_PID_PROF_1100)},
@@ -1801,7 +1747,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
                        dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
                                        DW210X_WRITE_MSG);
                        break;
-               case USB_PID_CINERGY_S:
+               case USB_PID_TERRATEC_CINERGY_S:
                case USB_PID_DW2102:
                        dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
                                        DW210X_WRITE_MSG);
@@ -1843,6 +1789,9 @@ static int dw2102_load_firmware(struct usb_device *dev,
                msleep(100);
                kfree(p);
        }
+
+       if (le16_to_cpu(dev->descriptor.idProduct) == 0x2101)
+               release_firmware(fw);
        return ret;
 }
 
index ec397c4..c05de1b 100644 (file)
@@ -995,11 +995,11 @@ static struct dvb_usb_device_properties tt_connect_s2_3600_properties = {
                        /* parameter for the MPEG2-data transfer */
                        .stream = {
                                .type = USB_ISOC,
-                               .count = 7,
+                               .count = 4,
                                .endpoint = 0x02,
                                .u = {
                                        .isoc = {
-                                               .framesperurb = 4,
+                                               .framesperurb = 64,
                                                .framesize = 940,
                                                .interval = 1
                                        }
index e382210..d917b0a 100644 (file)
@@ -59,6 +59,8 @@ config VIDEO_EM28XX_DVB
        select DVB_DRX39XYJ if MEDIA_SUBDRV_AUTOSELECT
        select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT
        select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_TC90522 if MEDIA_SUBDRV_AUTOSELECT
+       select MEDIA_TUNER_QM1D1C0042 if MEDIA_SUBDRV_AUTOSELECT
        ---help---
          This adds support for DVB cards based on the
          Empiatech em28xx chips.
index 930e3e3..e397f54 100644 (file)
@@ -492,6 +492,44 @@ static struct em28xx_reg_seq terratec_t2_stick_hd[] = {
        {-1,                             -1,   -1,     -1},
 };
 
+static struct em28xx_reg_seq plex_px_bcud[] = {
+       {EM2874_R80_GPIO_P0_CTRL,       0xff,   0xff,   0},
+       {0x0d,                          0xff,   0xff,   0},
+       {EM2874_R50_IR_CONFIG,          0x01,   0xff,   0},
+       {EM28XX_R06_I2C_CLK,            0x40,   0xff,   0},
+       {EM2874_R80_GPIO_P0_CTRL,       0xfd,   0xff,   100},
+       {EM28XX_R12_VINENABLE,          0x20,   0x20,   0},
+       {0x0d,                          0x42,   0xff,   1000},
+       {EM2874_R80_GPIO_P0_CTRL,       0xfc,   0xff,   10},
+       {EM2874_R80_GPIO_P0_CTRL,       0xfd,   0xff,   10},
+       {0x73,                          0xfd,   0xff,   100},
+       {-1,                            -1,     -1,     -1},
+};
+
+/*
+ * 2040:0265 Hauppauge WinTV-dualHD DVB
+ * reg 0x80/0x84:
+ * GPIO_0: Yellow LED tuner 1, 0=on, 1=off
+ * GPIO_1: Green LED tuner 1, 0=on, 1=off
+ * GPIO_2: Yellow LED tuner 2, 0=on, 1=off
+ * GPIO_3: Green LED tuner 2, 0=on, 1=off
+ * GPIO_5: Reset #2, 0=active
+ * GPIO_6: Reset #1, 0=active
+ */
+static struct em28xx_reg_seq hauppauge_dualhd_dvb[] = {
+       {EM2874_R80_GPIO_P0_CTRL,      0xff, 0xff,      0},
+       {0x0d,                         0xff, 0xff,    200},
+       {0x50,                         0x04, 0xff,    300},
+       {EM2874_R80_GPIO_P0_CTRL,      0xbf, 0xff,    100}, /* demod 1 reset */
+       {EM2874_R80_GPIO_P0_CTRL,      0xff, 0xff,    100},
+       {EM2874_R80_GPIO_P0_CTRL,      0xdf, 0xff,    100}, /* demod 2 reset */
+       {EM2874_R80_GPIO_P0_CTRL,      0xff, 0xff,    100},
+       {EM2874_R5F_TS_ENABLE,         0x44, 0xff,     50},
+       {EM2874_R5D_TS1_PKT_SIZE,      0x05, 0xff,     50},
+       {EM2874_R5E_TS2_PKT_SIZE,      0x05, 0xff,     50},
+       {-1,                             -1,   -1,     -1},
+};
+
 /*
  *  Button definitions
  */
@@ -571,6 +609,22 @@ static struct em28xx_led terratec_grabby_leds[] = {
        {-1, 0, 0, 0},
 };
 
+static struct em28xx_led hauppauge_dualhd_leds[] = {
+       {
+               .role      = EM28XX_LED_DIGITAL_CAPTURING,
+               .gpio_reg  = EM2874_R80_GPIO_P0_CTRL,
+               .gpio_mask = EM_GPIO_1,
+               .inverted  = 1,
+       },
+       {
+               .role      = EM28XX_LED_DIGITAL_CAPTURING_TS2,
+               .gpio_reg  = EM2874_R80_GPIO_P0_CTRL,
+               .gpio_mask = EM_GPIO_3,
+               .inverted  = 1,
+       },
+       {-1, 0, 0, 0},
+};
+
 /*
  *  Board definitions
  */
@@ -2306,6 +2360,35 @@ struct em28xx_board em28xx_boards[] = {
                .has_dvb       = 1,
                .ir_codes      = RC_MAP_TERRATEC_SLIM_2,
        },
+
+       /*
+        * 3275:0085 PLEX PX-BCUD.
+        * Empia EM28178, TOSHIBA TC90532XBG, Sharp QM1D1C0042
+        */
+       [EM28178_BOARD_PLEX_PX_BCUD] = {
+               .name          = "PLEX PX-BCUD",
+               .xclk          = EM28XX_XCLK_FREQUENCY_4_3MHZ,
+               .def_i2c_bus   = 1,
+               .i2c_speed     = EM28XX_I2C_CLK_WAIT_ENABLE,
+               .tuner_type    = TUNER_ABSENT,
+               .tuner_gpio    = plex_px_bcud,
+               .has_dvb       = 1,
+       },
+       /*
+        * 2040:0265 Hauppauge WinTV-dualHD (DVB version).
+        * Empia EM28274, 2x Silicon Labs Si2168, 2x Silicon Labs Si2157
+        */
+       [EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB] = {
+               .name          = "Hauppauge WinTV-dualHD DVB",
+               .def_i2c_bus   = 1,
+               .i2c_speed     = EM28XX_I2C_CLK_WAIT_ENABLE |
+                                EM28XX_I2C_FREQ_400_KHZ,
+               .tuner_type    = TUNER_ABSENT,
+               .tuner_gpio    = hauppauge_dualhd_dvb,
+               .has_dvb       = 1,
+               .ir_codes      = RC_MAP_HAUPPAUGE,
+               .leds          = hauppauge_dualhd_leds,
+       },
 };
 EXPORT_SYMBOL_GPL(em28xx_boards);
 
@@ -2429,6 +2512,8 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 },
        { USB_DEVICE(0x2040, 0x651f),
                        .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 },
+       { USB_DEVICE(0x2040, 0x0265),
+                       .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB },
        { USB_DEVICE(0x0438, 0xb002),
                        .driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 },
        { USB_DEVICE(0x2001, 0xf112),
@@ -2495,6 +2580,8 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM2861_BOARD_LEADTEK_VC100 },
        { USB_DEVICE(0xeb1a, 0x8179),
                        .driver_info = EM28178_BOARD_TERRATEC_T2_STICK_HD },
+       { USB_DEVICE(0x3275, 0x0085),
+                       .driver_info = EM28178_BOARD_PLEX_PX_BCUD },
        { },
 };
 MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -2861,6 +2948,7 @@ static void em28xx_card_setup(struct em28xx *dev)
        case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
        case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
        case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C:
+       case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB:
        {
                struct tveeprom tv;
 
index 5d209c7..1a5c012 100644 (file)
@@ -58,6 +58,8 @@
 #include "ts2020.h"
 #include "si2168.h"
 #include "si2157.h"
+#include "tc90522.h"
+#include "qm1d1c0042.h"
 
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
 MODULE_LICENSE("GPL");
@@ -787,6 +789,68 @@ static int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe)
        return 0;
 }
 
+static void px_bcud_init(struct em28xx *dev)
+{
+       int i;
+       struct {
+               unsigned char r[4];
+               int len;
+       } regs1[] = {
+               {{ 0x0e, 0x77 }, 2},
+               {{ 0x0f, 0x77 }, 2},
+               {{ 0x03, 0x90 }, 2},
+       }, regs2[] = {
+               {{ 0x07, 0x01 }, 2},
+               {{ 0x08, 0x10 }, 2},
+               {{ 0x13, 0x00 }, 2},
+               {{ 0x17, 0x00 }, 2},
+               {{ 0x03, 0x01 }, 2},
+               {{ 0x10, 0xb1 }, 2},
+               {{ 0x11, 0x40 }, 2},
+               {{ 0x85, 0x7a }, 2},
+               {{ 0x87, 0x04 }, 2},
+       };
+       static struct em28xx_reg_seq gpio[] = {
+               {EM28XX_R06_I2C_CLK,            0x40,   0xff,   300},
+               {EM2874_R80_GPIO_P0_CTRL,       0xfd,   0xff,   60},
+               {EM28XX_R15_RGAIN,              0x20,   0xff,   0},
+               {EM28XX_R16_GGAIN,              0x20,   0xff,   0},
+               {EM28XX_R17_BGAIN,              0x20,   0xff,   0},
+               {EM28XX_R18_ROFFSET,            0x00,   0xff,   0},
+               {EM28XX_R19_GOFFSET,            0x00,   0xff,   0},
+               {EM28XX_R1A_BOFFSET,            0x00,   0xff,   0},
+               {EM28XX_R23_UOFFSET,            0x00,   0xff,   0},
+               {EM28XX_R24_VOFFSET,            0x00,   0xff,   0},
+               {EM28XX_R26_COMPR,              0x00,   0xff,   0},
+               {0x13,                          0x08,   0xff,   0},
+               {EM28XX_R12_VINENABLE,          0x27,   0xff,   0},
+               {EM28XX_R0C_USBSUSP,            0x10,   0xff,   0},
+               {EM28XX_R27_OUTFMT,             0x00,   0xff,   0},
+               {EM28XX_R10_VINMODE,            0x00,   0xff,   0},
+               {EM28XX_R11_VINCTRL,            0x11,   0xff,   0},
+               {EM2874_R50_IR_CONFIG,          0x01,   0xff,   0},
+               {EM2874_R5F_TS_ENABLE,          0x80,   0xff,   0},
+               {EM28XX_R06_I2C_CLK,            0x46,   0xff,   0},
+       };
+       em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x46);
+       /* sleeping ISDB-T */
+       dev->dvb->i2c_client_demod->addr = 0x14;
+       for (i = 0; i < ARRAY_SIZE(regs1); i++)
+               i2c_master_send(dev->dvb->i2c_client_demod, regs1[i].r,
+                               regs1[i].len);
+       /* sleeping ISDB-S */
+       dev->dvb->i2c_client_demod->addr = 0x15;
+       for (i = 0; i < ARRAY_SIZE(regs2); i++)
+               i2c_master_send(dev->dvb->i2c_client_demod, regs2[i].r,
+                               regs2[i].len);
+       for (i = 0; i < ARRAY_SIZE(gpio); i++) {
+               em28xx_write_reg_bits(dev, gpio[i].reg, gpio[i].val,
+                                     gpio[i].mask);
+               if (gpio[i].sleep > 0)
+                       msleep(gpio[i].sleep);
+       }
+};
+
 static struct mt352_config terratec_xs_mt352_cfg = {
        .demod_address = (0x1e >> 1),
        .no_tuner = 1,
@@ -1762,6 +1826,127 @@ static int em28xx_dvb_init(struct em28xx *dev)
                        dvb->i2c_client_tuner = client;
                }
                break;
+
+       case EM28178_BOARD_PLEX_PX_BCUD:
+               {
+                       struct i2c_client *client;
+                       struct i2c_board_info info;
+                       struct tc90522_config tc90522_config;
+                       struct qm1d1c0042_config qm1d1c0042_config;
+
+                       /* attach demod */
+                       memset(&tc90522_config, 0, sizeof(tc90522_config));
+                       memset(&info, 0, sizeof(struct i2c_board_info));
+                       strlcpy(info.type, "tc90522sat", I2C_NAME_SIZE);
+                       info.addr = 0x15;
+                       info.platform_data = &tc90522_config;
+                       request_module("tc90522");
+                       client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
+                       if (client == NULL || client->dev.driver == NULL) {
+                               result = -ENODEV;
+                               goto out_free;
+                       }
+                       dvb->i2c_client_demod = client;
+                       if (!try_module_get(client->dev.driver->owner)) {
+                               i2c_unregister_device(client);
+                               result = -ENODEV;
+                               goto out_free;
+                       }
+
+                       /* attach tuner */
+                       memset(&qm1d1c0042_config, 0,
+                              sizeof(qm1d1c0042_config));
+                       qm1d1c0042_config.fe = tc90522_config.fe;
+                       qm1d1c0042_config.lpf = 1;
+                       memset(&info, 0, sizeof(struct i2c_board_info));
+                       strlcpy(info.type, "qm1d1c0042", I2C_NAME_SIZE);
+                       info.addr = 0x61;
+                       info.platform_data = &qm1d1c0042_config;
+                       request_module(info.type);
+                       client = i2c_new_device(tc90522_config.tuner_i2c,
+                                               &info);
+                       if (client == NULL || client->dev.driver == NULL) {
+                               module_put(dvb->i2c_client_demod->dev.driver->owner);
+                               i2c_unregister_device(dvb->i2c_client_demod);
+                               result = -ENODEV;
+                               goto out_free;
+                       }
+                       dvb->i2c_client_tuner = client;
+                       if (!try_module_get(client->dev.driver->owner)) {
+                               i2c_unregister_device(client);
+                               module_put(dvb->i2c_client_demod->dev.driver->owner);
+                               i2c_unregister_device(dvb->i2c_client_demod);
+                               result = -ENODEV;
+                               goto out_free;
+                       }
+                       dvb->fe[0] = tc90522_config.fe;
+                       px_bcud_init(dev);
+               }
+               break;
+       case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB:
+               {
+                       struct i2c_adapter *adapter;
+                       struct i2c_client *client;
+                       struct i2c_board_info info;
+                       struct si2168_config si2168_config;
+                       struct si2157_config si2157_config;
+
+                       /* attach demod */
+                       memset(&si2168_config, 0, sizeof(si2168_config));
+                       si2168_config.i2c_adapter = &adapter;
+                       si2168_config.fe = &dvb->fe[0];
+                       si2168_config.ts_mode = SI2168_TS_SERIAL;
+                       memset(&info, 0, sizeof(struct i2c_board_info));
+                       strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+                       info.addr = 0x64;
+                       info.platform_data = &si2168_config;
+                       request_module(info.type);
+                       client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
+                       if (client == NULL || client->dev.driver == NULL) {
+                               result = -ENODEV;
+                               goto out_free;
+                       }
+
+                       if (!try_module_get(client->dev.driver->owner)) {
+                               i2c_unregister_device(client);
+                               result = -ENODEV;
+                               goto out_free;
+                       }
+
+                       dvb->i2c_client_demod = client;
+
+                       /* attach tuner */
+                       memset(&si2157_config, 0, sizeof(si2157_config));
+                       si2157_config.fe = dvb->fe[0];
+                       si2157_config.if_port = 1;
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+                       si2157_config.mdev = dev->media_dev;
+#endif
+                       memset(&info, 0, sizeof(struct i2c_board_info));
+                       strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+                       info.addr = 0x60;
+                       info.platform_data = &si2157_config;
+                       request_module(info.type);
+                       client = i2c_new_device(adapter, &info);
+                       if (client == NULL || client->dev.driver == NULL) {
+                               module_put(dvb->i2c_client_demod->dev.driver->owner);
+                               i2c_unregister_device(dvb->i2c_client_demod);
+                               result = -ENODEV;
+                               goto out_free;
+                       }
+
+                       if (!try_module_get(client->dev.driver->owner)) {
+                               i2c_unregister_device(client);
+                               module_put(dvb->i2c_client_demod->dev.driver->owner);
+                               i2c_unregister_device(dvb->i2c_client_demod);
+                               result = -ENODEV;
+                               goto out_free;
+                       }
+
+                       dvb->i2c_client_tuner = client;
+
+               }
+               break;
        default:
                em28xx_errdev("/2: The frontend of your DVB/ATSC card"
                                " isn't supported yet\n");
index 13cbb7f..afe7a66 100644 (file)
 /* em2874 registers */
 #define EM2874_R50_IR_CONFIG    0x50
 #define EM2874_R51_IR           0x51
+#define EM2874_R5D_TS1_PKT_SIZE 0x5d
+#define EM2874_R5E_TS2_PKT_SIZE 0x5e
+       /*
+        * For both TS1 and TS2, In isochronous mode:
+        *  0x01  188 bytes
+        *  0x02  376 bytes
+        *  0x03  564 bytes
+        *  0x04  752 bytes
+        *  0x05  940 bytes
+        * In bulk mode:
+        *  0x01..0xff  total packet count in 188-byte
+        */
+
 #define EM2874_R5F_TS_ENABLE    0x5f
 
 /* em2874/174/84, em25xx, em276x/7x/8x GPIO registers */
index 2674449..d148463 100644 (file)
 #define EM2861_BOARD_LEADTEK_VC100                95
 #define EM28178_BOARD_TERRATEC_T2_STICK_HD        96
 #define EM2884_BOARD_ELGATO_EYETV_HYBRID_2008     97
+#define EM28178_BOARD_PLEX_PX_BCUD                98
+#define EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB  99
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
@@ -406,6 +408,7 @@ enum em28xx_adecoder {
 enum em28xx_led_role {
        EM28XX_LED_ANALOG_CAPTURING = 0,
        EM28XX_LED_DIGITAL_CAPTURING,
+       EM28XX_LED_DIGITAL_CAPTURING_TS2,
        EM28XX_LED_ILLUMINATION,
        EM28XX_NUM_LED_ROLES, /* must be the last */
 };
index 358c1c1..ea01ee5 100644 (file)
@@ -1125,7 +1125,7 @@ int go7007_v4l2_init(struct go7007 *go)
        vdev->queue = &go->vidq;
        video_set_drvdata(vdev, go);
        vdev->v4l2_dev = &go->v4l2_dev;
-       if (!v4l2_device_has_op(&go->v4l2_dev, video, querystd))
+       if (!v4l2_device_has_op(&go->v4l2_dev, 0, video, querystd))
                v4l2_disable_ioctl(vdev, VIDIOC_QUERYSTD);
        if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) {
                v4l2_disable_ioctl(vdev, VIDIOC_S_FREQUENCY);
index 1a093e5..83e9a3e 100644 (file)
@@ -3672,11 +3672,10 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
 
 
        hdw->cmd_debug_state = 1;
-       if (write_len) {
+       if (write_len && write_data)
                hdw->cmd_debug_code = ((unsigned char *)write_data)[0];
-       } else {
+       else
                hdw->cmd_debug_code = 0;
-       }
        hdw->cmd_debug_write_len = write_len;
        hdw->cmd_debug_read_len = read_len;
 
@@ -3688,7 +3687,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
        setup_timer(&timer, pvr2_ctl_timeout, (unsigned long)hdw);
        timer.expires = jiffies + timeout;
 
-       if (write_len) {
+       if (write_len && write_data) {
                hdw->cmd_debug_state = 2;
                /* Transfer write data to internal buffer */
                for (idx = 0; idx < write_len; idx++) {
@@ -3795,7 +3794,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
                        goto done;
                }
        }
-       if (read_len) {
+       if (read_len && read_data) {
                /* Validate results of read request */
                if ((hdw->ctl_read_urb->status != 0) &&
                    (hdw->ctl_read_urb->status != -ENOENT) &&
index 019644f..bacecbd 100644 (file)
@@ -280,7 +280,8 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
 static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
 {
        if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) ||
-           copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)))
+           copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)) ||
+           copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
                return -EFAULT;
        return __put_v4l2_format32(&kp->format, &up->format);
 }
index d8e5994..70b559d 100644 (file)
@@ -735,6 +735,7 @@ static int video_register_media_controller(struct video_device *vdev, int type)
        if (!vdev->v4l2_dev->mdev)
                return 0;
 
+       vdev->entity.obj_type = MEDIA_ENTITY_TYPE_VIDEO_DEVICE;
        vdev->entity.function = MEDIA_ENT_F_UNKNOWN;
 
        switch (type) {
index 170dd68..28e5be2 100644 (file)
@@ -1020,9 +1020,12 @@ static int v4l_querycap(const struct v4l2_ioctl_ops *ops,
                                struct file *file, void *fh, void *arg)
 {
        struct v4l2_capability *cap = (struct v4l2_capability *)arg;
+       struct video_device *vfd = video_devdata(file);
        int ret;
 
        cap->version = LINUX_VERSION_CODE;
+       cap->device_caps = vfd->device_caps;
+       cap->capabilities = vfd->device_caps | V4L2_CAP_DEVICE_CAPS;
 
        ret = ops->vidioc_querycap(file, fh, cap);
 
@@ -2157,40 +2160,56 @@ static int v4l_cropcap(const struct v4l2_ioctl_ops *ops,
                                struct file *file, void *fh, void *arg)
 {
        struct v4l2_cropcap *p = arg;
+       struct v4l2_selection s = { .type = p->type };
+       int ret = 0;
 
-       if (ops->vidioc_g_selection) {
-               struct v4l2_selection s = { .type = p->type };
-               int ret;
+       /* setting trivial pixelaspect */
+       p->pixelaspect.numerator = 1;
+       p->pixelaspect.denominator = 1;
 
-               /* obtaining bounds */
-               if (V4L2_TYPE_IS_OUTPUT(p->type))
-                       s.target = V4L2_SEL_TGT_COMPOSE_BOUNDS;
-               else
-                       s.target = V4L2_SEL_TGT_CROP_BOUNDS;
+       /*
+        * The determine_valid_ioctls() call already should ensure
+        * that this can never happen, but just in case...
+        */
+       if (WARN_ON(!ops->vidioc_cropcap && !ops->vidioc_cropcap))
+               return -ENOTTY;
 
-               ret = ops->vidioc_g_selection(file, fh, &s);
-               if (ret)
-                       return ret;
-               p->bounds = s.r;
+       if (ops->vidioc_cropcap)
+               ret = ops->vidioc_cropcap(file, fh, p);
 
-               /* obtaining defrect */
-               if (V4L2_TYPE_IS_OUTPUT(p->type))
-                       s.target = V4L2_SEL_TGT_COMPOSE_DEFAULT;
-               else
-                       s.target = V4L2_SEL_TGT_CROP_DEFAULT;
+       if (!ops->vidioc_g_selection)
+               return ret;
 
-               ret = ops->vidioc_g_selection(file, fh, &s);
-               if (ret)
-                       return ret;
-               p->defrect = s.r;
-       }
+       /*
+        * Ignore ENOTTY or ENOIOCTLCMD error returns, just use the
+        * square pixel aspect ratio in that case.
+        */
+       if (ret && ret != -ENOTTY && ret != -ENOIOCTLCMD)
+               return ret;
 
-       /* setting trivial pixelaspect */
-       p->pixelaspect.numerator = 1;
-       p->pixelaspect.denominator = 1;
+       /* Use g_selection() to fill in the bounds and defrect rectangles */
 
-       if (ops->vidioc_cropcap)
-               return ops->vidioc_cropcap(file, fh, p);
+       /* obtaining bounds */
+       if (V4L2_TYPE_IS_OUTPUT(p->type))
+               s.target = V4L2_SEL_TGT_COMPOSE_BOUNDS;
+       else
+               s.target = V4L2_SEL_TGT_CROP_BOUNDS;
+
+       ret = ops->vidioc_g_selection(file, fh, &s);
+       if (ret)
+               return ret;
+       p->bounds = s.r;
+
+       /* obtaining defrect */
+       if (V4L2_TYPE_IS_OUTPUT(p->type))
+               s.target = V4L2_SEL_TGT_COMPOSE_DEFAULT;
+       else
+               s.target = V4L2_SEL_TGT_CROP_DEFAULT;
+
+       ret = ops->vidioc_g_selection(file, fh, &s);
+       if (ret)
+               return ret;
+       p->defrect = s.r;
 
        return 0;
 }
index 2228cd3..ca94bde 100644 (file)
@@ -263,7 +263,7 @@ static int pipeline_pm_use_count(struct media_entity *entity,
        media_entity_graph_walk_start(graph, entity);
 
        while ((entity = media_entity_graph_walk_next(graph))) {
-               if (is_media_entity_v4l2_io(entity))
+               if (is_media_entity_v4l2_video_device(entity))
                        use += entity->use_count;
        }
 
index d630838..953eab0 100644 (file)
 static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
 {
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-       fh->pad = kzalloc(sizeof(*fh->pad) * sd->entity.num_pads, GFP_KERNEL);
-       if (fh->pad == NULL)
-               return -ENOMEM;
+       if (sd->entity.num_pads) {
+               fh->pad = v4l2_subdev_alloc_pad_config(sd);
+               if (fh->pad == NULL)
+                       return -ENOMEM;
+       }
 #endif
        return 0;
 }
@@ -45,7 +47,7 @@ static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
 static void subdev_fh_free(struct v4l2_subdev_fh *fh)
 {
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-       kfree(fh->pad);
+       v4l2_subdev_free_pad_config(fh->pad);
        fh->pad = NULL;
 #endif
 }
@@ -508,7 +510,7 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
        if (source_fmt->format.width != sink_fmt->format.width
            || source_fmt->format.height != sink_fmt->format.height
            || source_fmt->format.code != sink_fmt->format.code)
-               return -EINVAL;
+               return -EPIPE;
 
        /* The field order must match, or the sink field order must be NONE
         * to support interlaced hardware connected to bridges that support
@@ -516,7 +518,7 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
         */
        if (source_fmt->format.field != sink_fmt->format.field &&
            sink_fmt->format.field != V4L2_FIELD_NONE)
-               return -EINVAL;
+               return -EPIPE;
 
        return 0;
 }
@@ -569,6 +571,35 @@ int v4l2_subdev_link_validate(struct media_link *link)
                sink, link, &source_fmt, &sink_fmt);
 }
 EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate);
+
+struct v4l2_subdev_pad_config *
+v4l2_subdev_alloc_pad_config(struct v4l2_subdev *sd)
+{
+       struct v4l2_subdev_pad_config *cfg;
+       int ret;
+
+       if (!sd->entity.num_pads)
+               return NULL;
+
+       cfg = kcalloc(sd->entity.num_pads, sizeof(*cfg), GFP_KERNEL);
+       if (!cfg)
+               return NULL;
+
+       ret = v4l2_subdev_call(sd, pad, init_cfg, cfg);
+       if (ret < 0 && ret != -ENOIOCTLCMD) {
+               kfree(cfg);
+               return NULL;
+       }
+
+       return cfg;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_alloc_pad_config);
+
+void v4l2_subdev_free_pad_config(struct v4l2_subdev_pad_config *cfg)
+{
+       kfree(cfg);
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_free_pad_config);
 #endif /* CONFIG_MEDIA_CONTROLLER */
 
 void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
@@ -584,6 +615,7 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
        sd->host_priv = NULL;
 #if defined(CONFIG_MEDIA_CONTROLLER)
        sd->entity.name = sd->name;
+       sd->entity.obj_type = MEDIA_ENTITY_TYPE_V4L2_SUBDEV;
        sd->entity.function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
 #endif
 }
index 0078b6a..de7e9f5 100644 (file)
@@ -37,6 +37,8 @@ source "drivers/staging/media/omap4iss/Kconfig"
 
 source "drivers/staging/media/timb/Kconfig"
 
+source "drivers/staging/media/tw686x-kh/Kconfig"
+
 # Keep LIRC at the end, as it has sub-menus
 source "drivers/staging/media/lirc/Kconfig"
 
index 9149588..60a35b3 100644 (file)
@@ -8,3 +8,4 @@ obj-$(CONFIG_VIDEO_OMAP1)       += omap1/
 obj-$(CONFIG_VIDEO_OMAP4)      += omap4iss/
 obj-$(CONFIG_DVB_MN88472)       += mn88472/
 obj-$(CONFIG_VIDEO_TIMBERDALE)  += timb/
+obj-$(CONFIG_VIDEO_TW686X_KH)  += tw686x-kh/
index abf330f..8dade19 100644 (file)
@@ -308,7 +308,7 @@ module_param(radio_nr, int, 0);
 MODULE_PARM_DESC(radio_nr,
                 "Minor number for radio device (-1 ==> auto assign)");
 
-static struct region_info region_configs[] = {
+static const struct region_info region_configs[] = {
        /* USA */
        {
                .channel_spacing        = 20,
index be72a8e..ea3ddec 100644 (file)
@@ -154,7 +154,7 @@ static int vpfe_prepare_pipeline(struct vpfe_video_device *video)
        while ((entity = media_entity_graph_walk_next(&graph))) {
                if (entity == &video->video_dev.entity)
                        continue;
-               if (!is_media_entity_v4l2_io(entity))
+               if (!is_media_entity_v4l2_video_device(entity))
                        continue;
                far_end = to_vpfe_video(media_entity_to_video_device(entity));
                if (far_end->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
index f54349b..cf8da23 100644 (file)
@@ -223,7 +223,7 @@ iss_video_far_end(struct iss_video *video)
                if (entity == &video->video.entity)
                        continue;
 
-               if (!is_media_entity_v4l2_io(entity))
+               if (!is_media_entity_v4l2_video_device(entity))
                        continue;
 
                far_end = to_iss_video(media_entity_to_video_device(entity));
diff --git a/drivers/staging/media/tw686x-kh/Kconfig b/drivers/staging/media/tw686x-kh/Kconfig
new file mode 100644 (file)
index 0000000..6264d30
--- /dev/null
@@ -0,0 +1,17 @@
+config VIDEO_TW686X_KH
+       tristate "Intersil/Techwell TW686x Video For Linux"
+       depends on VIDEO_DEV && PCI && VIDEO_V4L2
+       depends on !(VIDEO_TW686X=y || VIDEO_TW686X=m) || COMPILE_TEST
+       select VIDEOBUF2_DMA_SG
+       help
+         Support for Intersil/Techwell TW686x-based frame grabber cards.
+
+         Currently supported chips:
+         - TW6864 (4 video channels),
+         - TW6865 (4 video channels, not tested, second generation chip),
+         - TW6868 (8 video channels but only 4 first channels using
+           built-in video decoder are supported, not tested),
+         - TW6869 (8 video channels, second generation chip).
+
+         To compile this driver as a module, choose M here: the module
+         will be named tw686x-kh.
diff --git a/drivers/staging/media/tw686x-kh/Makefile b/drivers/staging/media/tw686x-kh/Makefile
new file mode 100644 (file)
index 0000000..2a36a38
--- /dev/null
@@ -0,0 +1,3 @@
+tw686x-kh-objs := tw686x-kh-core.o tw686x-kh-video.o
+
+obj-$(CONFIG_VIDEO_TW686X_KH) += tw686x-kh.o
diff --git a/drivers/staging/media/tw686x-kh/TODO b/drivers/staging/media/tw686x-kh/TODO
new file mode 100644 (file)
index 0000000..480a495
--- /dev/null
@@ -0,0 +1,6 @@
+TODO:
+
+- implement V4L2_FIELD_INTERLACED* mode(s).
+- add audio support
+
+Please Cc: patches to Krzysztof Halasa <khalasa@piap.pl>.
diff --git a/drivers/staging/media/tw686x-kh/tw686x-kh-core.c b/drivers/staging/media/tw686x-kh/tw686x-kh-core.c
new file mode 100644 (file)
index 0000000..03b3b62
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2015 Industrial Research Institute for Automation
+ * and Measurements PIAP
+ *
+ * Written by Krzysztof Ha?asa.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "tw686x-kh.h"
+#include "tw686x-kh-regs.h"
+
+static irqreturn_t tw686x_irq(int irq, void *dev_id)
+{
+       struct tw686x_dev *dev = (struct tw686x_dev *)dev_id;
+       u32 int_status = reg_read(dev, INT_STATUS); /* cleared on read */
+       unsigned long flags;
+       unsigned int handled = 0;
+
+       if (int_status) {
+               spin_lock_irqsave(&dev->irq_lock, flags);
+               dev->dma_requests |= int_status;
+               spin_unlock_irqrestore(&dev->irq_lock, flags);
+
+               if (int_status & 0xFF0000FF)
+                       handled = tw686x_kh_video_irq(dev);
+       }
+
+       return IRQ_RETVAL(handled);
+}
+
+static int tw686x_probe(struct pci_dev *pci_dev,
+                       const struct pci_device_id *pci_id)
+{
+       struct tw686x_dev *dev;
+       int err;
+
+       dev = devm_kzalloc(&pci_dev->dev, sizeof(*dev) +
+                          (pci_id->driver_data & TYPE_MAX_CHANNELS) *
+                          sizeof(dev->video_channels[0]), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+
+       sprintf(dev->name, "TW%04X", pci_dev->device);
+       dev->type = pci_id->driver_data;
+
+       pr_info("%s: PCI %s, IRQ %d, MMIO 0x%lx\n", dev->name,
+               pci_name(pci_dev), pci_dev->irq,
+               (unsigned long)pci_resource_start(pci_dev, 0));
+
+       dev->pci_dev = pci_dev;
+       if (pcim_enable_device(pci_dev))
+               return -EIO;
+
+       pci_set_master(pci_dev);
+
+       if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32))) {
+               pr_err("%s: 32-bit PCI DMA not supported\n", dev->name);
+               return -EIO;
+       }
+
+       err = pci_request_regions(pci_dev, dev->name);
+       if (err < 0) {
+               pr_err("%s: Unable to get MMIO region\n", dev->name);
+               return err;
+       }
+
+       dev->mmio = pci_ioremap_bar(pci_dev, 0);
+       if (!dev->mmio) {
+               pr_err("%s: Unable to remap MMIO region\n", dev->name);
+               return -EIO;
+       }
+
+       reg_write(dev, SYS_SOFT_RST, 0x0F); /* Reset all subsystems */
+       mdelay(1);
+
+       reg_write(dev, SRST[0], 0x3F);
+       if (max_channels(dev) > 4)
+               reg_write(dev, SRST[1], 0x3F);
+       reg_write(dev, DMA_CMD, 0);
+       reg_write(dev, DMA_CHANNEL_ENABLE, 0);
+       reg_write(dev, DMA_CHANNEL_TIMEOUT, 0x3EFF0FF0);
+       reg_write(dev, DMA_TIMER_INTERVAL, 0x38000);
+       reg_write(dev, DMA_CONFIG, 0xFFFFFF04);
+
+       spin_lock_init(&dev->irq_lock);
+
+       err = devm_request_irq(&pci_dev->dev, pci_dev->irq, tw686x_irq,
+                              IRQF_SHARED, dev->name, dev);
+       if (err < 0) {
+               pr_err("%s: Unable to get IRQ\n", dev->name);
+               return err;
+       }
+
+       err = tw686x_kh_video_init(dev);
+       if (err)
+               return err;
+
+       pci_set_drvdata(pci_dev, dev);
+       return 0;
+}
+
+static void tw686x_remove(struct pci_dev *pci_dev)
+{
+       struct tw686x_dev *dev = pci_get_drvdata(pci_dev);
+
+       tw686x_kh_video_free(dev);
+}
+
+/* driver_data is number of A/V channels */
+static const struct pci_device_id tw686x_pci_tbl[] = {
+       {PCI_DEVICE(0x1797, 0x6864), .driver_data = 4},
+       /* not tested */
+       {PCI_DEVICE(0x1797, 0x6865), .driver_data = 4 | TYPE_SECOND_GEN},
+       /* TW6868 supports 8 A/V channels with an external TW2865 chip -
+          not supported by the driver */
+       {PCI_DEVICE(0x1797, 0x6868), .driver_data = 4}, /* not tested */
+       {PCI_DEVICE(0x1797, 0x6869), .driver_data = 8 | TYPE_SECOND_GEN},
+       {}
+};
+
+static struct pci_driver tw686x_pci_driver = {
+       .name = "tw686x-kh",
+       .id_table = tw686x_pci_tbl,
+       .probe = tw686x_probe,
+       .remove = tw686x_remove,
+};
+
+MODULE_DESCRIPTION("Driver for video frame grabber cards based on Intersil/Techwell TW686[4589]");
+MODULE_AUTHOR("Krzysztof Halasa");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(pci, tw686x_pci_tbl);
+module_pci_driver(tw686x_pci_driver);
diff --git a/drivers/staging/media/tw686x-kh/tw686x-kh-regs.h b/drivers/staging/media/tw686x-kh/tw686x-kh-regs.h
new file mode 100644 (file)
index 0000000..53e1889
--- /dev/null
@@ -0,0 +1,103 @@
+/* DMA controller registers */
+#define REG8_1(a0) ((const u16[8]) {a0, a0 + 1, a0 + 2, a0 + 3,        \
+                                  a0 + 4, a0 + 5, a0 + 6, a0 + 7})
+#define REG8_2(a0) ((const u16[8]) {a0, a0 + 2, a0 + 4, a0 + 6,        \
+                                  a0 + 8, a0 + 0xA, a0 + 0xC, a0 + 0xE})
+#define REG8_8(a0) ((const u16[8]) {a0, a0 + 8, a0 + 0x10, a0 + 0x18,  \
+                                  a0 + 0x20, a0 + 0x28, a0 + 0x30, a0 + 0x38})
+#define INT_STATUS             0x00
+#define PB_STATUS              0x01
+#define DMA_CMD                        0x02
+#define VIDEO_FIFO_STATUS      0x03
+#define VIDEO_CHANNEL_ID       0x04
+#define VIDEO_PARSER_STATUS    0x05
+#define SYS_SOFT_RST           0x06
+#define DMA_PAGE_TABLE0_ADDR   ((const u16[8]) {0x08, 0xD0, 0xD2, 0xD4, \
+                                               0xD6, 0xD8, 0xDA, 0xDC})
+#define DMA_PAGE_TABLE1_ADDR   ((const u16[8]) {0x09, 0xD1, 0xD3, 0xD5, \
+                                               0xD7, 0xD9, 0xDB, 0xDD})
+#define DMA_CHANNEL_ENABLE     0x0A
+#define DMA_CONFIG             0x0B
+#define DMA_TIMER_INTERVAL     0x0C
+#define DMA_CHANNEL_TIMEOUT    0x0D
+#define VDMA_CHANNEL_CONFIG    REG8_1(0x10)
+#define ADMA_P_ADDR            REG8_2(0x18)
+#define ADMA_B_ADDR            REG8_2(0x19)
+#define DMA10_P_ADDR           0x28 /* ??? */
+#define DMA10_B_ADDR           0x29
+#define VIDEO_CONTROL1         0x2A
+#define VIDEO_CONTROL2         0x2B
+#define AUDIO_CONTROL1         0x2C
+#define AUDIO_CONTROL2         0x2D
+#define PHASE_REF              0x2E
+#define GPIO_REG               0x2F
+#define INTL_HBAR_CTRL         REG8_1(0x30)
+#define AUDIO_CONTROL3         0x38
+#define VIDEO_FIELD_CTRL       REG8_1(0x39)
+#define HSCALER_CTRL           REG8_1(0x42)
+#define VIDEO_SIZE             REG8_1(0x4A)
+#define VIDEO_SIZE_F2          REG8_1(0x52)
+#define MD_CONF                        REG8_1(0x60)
+#define MD_INIT                        REG8_1(0x68)
+#define MD_MAP0                        REG8_1(0x70)
+#define VDMA_P_ADDR            REG8_8(0x80) /* not used in DMA SG mode */
+#define VDMA_WHP               REG8_8(0x81)
+#define VDMA_B_ADDR            REG8_8(0x82)
+#define VDMA_F2_P_ADDR         REG8_8(0x84)
+#define VDMA_F2_WHP            REG8_8(0x85)
+#define VDMA_F2_B_ADDR         REG8_8(0x86)
+#define EP_REG_ADDR            0xFE
+#define EP_REG_DATA            0xFF
+
+/* Video decoder registers */
+#define VDREG8(a0) ((const u16[8]) {                   \
+       a0 + 0x000, a0 + 0x010, a0 + 0x020, a0 + 0x030, \
+       a0 + 0x100, a0 + 0x110, a0 + 0x120, a0 + 0x130})
+#define VIDSTAT                        VDREG8(0x100)
+#define BRIGHT                 VDREG8(0x101)
+#define CONTRAST               VDREG8(0x102)
+#define SHARPNESS              VDREG8(0x103)
+#define SAT_U                  VDREG8(0x104)
+#define SAT_V                  VDREG8(0x105)
+#define HUE                    VDREG8(0x106)
+#define CROP_HI                        VDREG8(0x107)
+#define VDELAY_LO              VDREG8(0x108)
+#define VACTIVE_LO             VDREG8(0x109)
+#define HDELAY_LO              VDREG8(0x10A)
+#define HACTIVE_LO             VDREG8(0x10B)
+#define MVSN                   VDREG8(0x10C)
+#define STATUS2                        VDREG8(0x10C)
+#define SDT                    VDREG8(0x10E)
+#define SDT_EN                 VDREG8(0x10F)
+
+#define VSCALE_LO              VDREG8(0x144)
+#define SCALE_HI               VDREG8(0x145)
+#define HSCALE_LO              VDREG8(0x146)
+#define F2CROP_HI              VDREG8(0x147)
+#define F2VDELAY_LO            VDREG8(0x148)
+#define F2VACTIVE_LO           VDREG8(0x149)
+#define F2HDELAY_LO            VDREG8(0x14A)
+#define F2HACTIVE_LO           VDREG8(0x14B)
+#define F2VSCALE_LO            VDREG8(0x14C)
+#define F2SCALE_HI             VDREG8(0x14D)
+#define F2HSCALE_LO            VDREG8(0x14E)
+#define F2CNT                  VDREG8(0x14F)
+
+#define VDREG2(a0) ((const u16[2]) {a0, a0 + 0x100})
+#define SRST                   VDREG2(0x180)
+#define ACNTL                  VDREG2(0x181)
+#define ACNTL2                 VDREG2(0x182)
+#define CNTRL1                 VDREG2(0x183)
+#define CKHY                   VDREG2(0x184)
+#define SHCOR                  VDREG2(0x185)
+#define CORING                 VDREG2(0x186)
+#define CLMPG                  VDREG2(0x187)
+#define IAGC                   VDREG2(0x188)
+#define VCTRL1                 VDREG2(0x18F)
+#define MISC1                  VDREG2(0x194)
+#define LOOP                   VDREG2(0x195)
+#define MISC2                  VDREG2(0x196)
+
+#define CLMD                   VDREG2(0x197)
+#define AIGAIN                 ((const u16[8]) {0x1D0, 0x1D1, 0x1D2, 0x1D3, \
+                                                0x2D0, 0x2D1, 0x2D2, 0x2D3})
diff --git a/drivers/staging/media/tw686x-kh/tw686x-kh-video.c b/drivers/staging/media/tw686x-kh/tw686x-kh-video.c
new file mode 100644 (file)
index 0000000..6ecb504
--- /dev/null
@@ -0,0 +1,821 @@
+/*
+ * Copyright (C) 2015 Industrial Research Institute for Automation
+ * and Measurements PIAP
+ *
+ * Written by Krzysztof Ha?asa.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include "tw686x-kh.h"
+#include "tw686x-kh-regs.h"
+
+#define MAX_SG_ENTRY_SIZE (/* 8192 - 128 */ 4096)
+#define MAX_SG_DESC_COUNT 256 /* PAL 704x576 needs up to 198 4-KB pages */
+
+static const struct tw686x_format formats[] = {
+       {
+               .name = "4:2:2 packed, UYVY", /* aka Y422 */
+               .fourcc = V4L2_PIX_FMT_UYVY,
+               .mode = 0,
+               .depth = 16,
+       }, {
+#if 0
+               .name = "4:2:0 packed, YUV",
+               .mode = 1,      /* non-standard */
+               .depth = 12,
+       }, {
+               .name = "4:1:1 packed, YUV",
+               .mode = 2,      /* non-standard */
+               .depth = 12,
+       }, {
+#endif
+               .name = "4:1:1 packed, YUV",
+               .fourcc = V4L2_PIX_FMT_Y41P,
+               .mode = 3,
+               .depth = 12,
+       }, {
+               .name = "15 bpp RGB",
+               .fourcc = V4L2_PIX_FMT_RGB555,
+               .mode = 4,
+               .depth = 16,
+       }, {
+               .name = "16 bpp RGB",
+               .fourcc = V4L2_PIX_FMT_RGB565,
+               .mode = 5,
+               .depth = 16,
+       }, {
+               .name = "4:2:2 packed, YUYV",
+               .fourcc = V4L2_PIX_FMT_YUYV,
+               .mode = 6,
+               .depth = 16,
+       }
+       /* mode 7 is "reserved" */
+};
+
+static const v4l2_std_id video_standards[7] = {
+       V4L2_STD_NTSC,
+       V4L2_STD_PAL,
+       V4L2_STD_SECAM,
+       V4L2_STD_NTSC_443,
+       V4L2_STD_PAL_M,
+       V4L2_STD_PAL_N,
+       V4L2_STD_PAL_60,
+};
+
+static const struct tw686x_format *format_by_fourcc(unsigned int fourcc)
+{
+       unsigned int cnt;
+
+       for (cnt = 0; cnt < ARRAY_SIZE(formats); cnt++)
+               if (formats[cnt].fourcc == fourcc)
+                       return &formats[cnt];
+       return NULL;
+}
+
+static void tw686x_get_format(struct tw686x_video_channel *vc,
+                             struct v4l2_format *f)
+{
+       const struct tw686x_format *format;
+       unsigned int width, height, height_div = 1;
+
+       format = format_by_fourcc(f->fmt.pix.pixelformat);
+       if (!format) {
+               format = &formats[0];
+               f->fmt.pix.pixelformat = format->fourcc;
+       }
+
+       width = 704;
+       if (f->fmt.pix.width < width * 3 / 4 /* halfway */)
+               width /= 2;
+
+       height = (vc->video_standard & V4L2_STD_625_50) ? 576 : 480;
+       if (f->fmt.pix.height < height * 3 / 4 /* halfway */)
+               height_div = 2;
+
+       switch (f->fmt.pix.field) {
+       case V4L2_FIELD_TOP:
+       case V4L2_FIELD_BOTTOM:
+               height_div = 2;
+               break;
+       case V4L2_FIELD_SEQ_BT:
+               if (height_div > 1)
+                       f->fmt.pix.field = V4L2_FIELD_BOTTOM;
+               break;
+       default:
+               if (height_div > 1)
+                       f->fmt.pix.field = V4L2_FIELD_TOP;
+               else
+                       f->fmt.pix.field = V4L2_FIELD_SEQ_TB;
+       }
+       height /= height_div;
+
+       f->fmt.pix.width = width;
+       f->fmt.pix.height = height;
+       f->fmt.pix.bytesperline = f->fmt.pix.width * format->depth / 8;
+       f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+       f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+}
+
+/* video queue operations */
+
+static int tw686x_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+                             unsigned int *nplanes, unsigned int sizes[],
+                             void *alloc_ctxs[])
+{
+       struct tw686x_video_channel *vc = vb2_get_drv_priv(vq);
+       unsigned int size = vc->width * vc->height * vc->format->depth / 8;
+
+       alloc_ctxs[0] = vc->alloc_ctx;
+       if (*nbuffers < 2)
+               *nbuffers = 2;
+
+       if (*nplanes)
+               return sizes[0] < size ? -EINVAL : 0;
+
+       sizes[0] = size;
+       *nplanes = 1;           /* packed formats only */
+       return 0;
+}
+
+static void tw686x_buf_queue(struct vb2_buffer *vb)
+{
+       struct tw686x_video_channel *vc = vb2_get_drv_priv(vb->vb2_queue);
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+       struct tw686x_vb2_buf *buf;
+
+       buf = container_of(vbuf, struct tw686x_vb2_buf, vb);
+
+       spin_lock(&vc->qlock);
+       list_add_tail(&buf->list, &vc->vidq_queued);
+       spin_unlock(&vc->qlock);
+}
+
+static void setup_descs(struct tw686x_video_channel *vc, unsigned int n)
+{
+loop:
+       while (!list_empty(&vc->vidq_queued)) {
+               struct vdma_desc *descs = vc->sg_descs[n];
+               struct tw686x_vb2_buf *buf;
+               struct sg_table *vbuf;
+               struct scatterlist *sg;
+               unsigned int buf_len, count = 0;
+               int i;
+
+               buf = list_first_entry(&vc->vidq_queued, struct tw686x_vb2_buf,
+                                      list);
+               list_del(&buf->list);
+
+               buf_len = vc->width * vc->height * vc->format->depth / 8;
+               if (vb2_plane_size(&buf->vb.vb2_buf, 0) < buf_len) {
+                       pr_err("Video buffer size too small\n");
+                       vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+                       goto loop; /* try another */
+               }
+
+               vbuf = vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0);
+               for_each_sg(vbuf->sgl, sg, vbuf->nents, i) {
+                       dma_addr_t phys = sg_dma_address(sg);
+                       unsigned int len = sg_dma_len(sg);
+
+                       while (len && buf_len) {
+                               unsigned int entry_len = min_t(unsigned int, len,
+                                                          MAX_SG_ENTRY_SIZE);
+                               entry_len = min(entry_len, buf_len);
+                               if (count == MAX_SG_DESC_COUNT) {
+                                       pr_err("Video buffer size too fragmented\n");
+                                       vb2_buffer_done(&buf->vb.vb2_buf,
+                                                       VB2_BUF_STATE_ERROR);
+                                       goto loop;
+                               }
+                               descs[count].phys = cpu_to_le32(phys);
+                               descs[count++].flags_length =
+                                       cpu_to_le32(0x40000000 /* available */ |
+                                                   entry_len);
+                               phys += entry_len;
+                               len -= entry_len;
+                               buf_len -= entry_len;
+                       }
+                       if (!buf_len)
+                               break;
+               }
+
+               /* clear the remaining entries */
+               while (count < MAX_SG_DESC_COUNT) {
+                       descs[count].phys = 0;
+                       descs[count++].flags_length = 0; /* unavailable */
+               }
+
+               buf->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE;
+               vc->curr_bufs[n] = buf;
+               return;
+       }
+       vc->curr_bufs[n] = NULL;
+}
+
+/* On TW6864 and TW6868, all channels share the pair of video DMA SG tables,
+   with 10-bit start_idx and end_idx determining start and end of frame buffer
+   for particular channel.
+   TW6868 with all its 8 channels would be problematic (only 127 SG entries per
+   channel) but we support only 4 channels on this chip anyway (the first
+   4 channels are driven with internal video decoder, the other 4 would require
+   an external TW286x part).
+
+   On TW6865 and TW6869, each channel has its own DMA SG table, with indexes
+   starting with 0. Both chips have complete sets of internal video decoders
+   (respectively 4 or 8-channel).
+
+   All chips have separate SG tables for two video frames. */
+
+static void setup_dma_cfg(struct tw686x_video_channel *vc)
+{
+       unsigned int field_width = 704;
+       unsigned int field_height = (vc->video_standard & V4L2_STD_625_50) ?
+               288 : 240;
+       unsigned int start_idx = is_second_gen(vc->dev) ? 0 :
+               vc->ch * MAX_SG_DESC_COUNT;
+       unsigned int end_idx = start_idx + MAX_SG_DESC_COUNT - 1;
+       u32 dma_cfg = (0 << 30) /* input selection */ |
+               (1 << 29) /* field2 dropped (if any) */ |
+               ((vc->height < 300) << 28) /* field dropping */ |
+               (1 << 27) /* master */ |
+               (0 << 25) /* master channel (for slave only) */ |
+               (0 << 24) /* (no) vertical (line) decimation */ |
+               ((vc->width < 400) << 23) /* horizontal decimation */ |
+               (vc->format->mode << 20) /* output video format */ |
+               (end_idx << 10) /* DMA end index */ |
+               start_idx /* DMA start index */;
+       u32 reg;
+
+       reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], dma_cfg);
+       reg_write(vc->dev, VIDEO_SIZE[vc->ch], (1 << 31) | (field_height << 16)
+                 | field_width);
+       reg = reg_read(vc->dev, VIDEO_CONTROL1);
+       if (vc->video_standard & V4L2_STD_625_50)
+               reg |= 1 << (vc->ch + 13);
+       else
+               reg &= ~(1 << (vc->ch + 13));
+       reg_write(vc->dev, VIDEO_CONTROL1, reg);
+}
+
+static int tw686x_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+       struct tw686x_video_channel *vc = vb2_get_drv_priv(vq);
+       struct tw686x_dev *dev = vc->dev;
+       u32 dma_ch_mask;
+       unsigned int n;
+
+       setup_dma_cfg(vc);
+
+       /* queue video buffers if available */
+       spin_lock(&vc->qlock);
+       for (n = 0; n < 2; n++)
+               setup_descs(vc, n);
+       spin_unlock(&vc->qlock);
+
+       dev->video_active |= 1 << vc->ch;
+       vc->seq = 0;
+       dma_ch_mask = reg_read(dev, DMA_CHANNEL_ENABLE) | (1 << vc->ch);
+       reg_write(dev, DMA_CHANNEL_ENABLE, dma_ch_mask);
+       reg_write(dev, DMA_CMD, (1 << 31) | dma_ch_mask);
+       return 0;
+}
+
+static void tw686x_stop_streaming(struct vb2_queue *vq)
+{
+       struct tw686x_video_channel *vc = vb2_get_drv_priv(vq);
+       struct tw686x_dev *dev = vc->dev;
+       u32 dma_ch_mask = reg_read(dev, DMA_CHANNEL_ENABLE);
+       u32 dma_cmd = reg_read(dev, DMA_CMD);
+       unsigned int n;
+
+       dma_ch_mask &= ~(1 << vc->ch);
+       reg_write(dev, DMA_CHANNEL_ENABLE, dma_ch_mask);
+
+       dev->video_active &= ~(1 << vc->ch);
+
+       dma_cmd &= ~(1 << vc->ch);
+       reg_write(dev, DMA_CMD, dma_cmd);
+
+       if (!dev->video_active) {
+               reg_write(dev, DMA_CMD, 0);
+               reg_write(dev, DMA_CHANNEL_ENABLE, 0);
+       }
+
+       spin_lock(&vc->qlock);
+       while (!list_empty(&vc->vidq_queued)) {
+               struct tw686x_vb2_buf *buf;
+
+               buf = list_entry(vc->vidq_queued.next, struct tw686x_vb2_buf,
+                                list);
+               list_del(&buf->list);
+               vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+       }
+
+       for (n = 0; n < 2; n++)
+               if (vc->curr_bufs[n])
+                       vb2_buffer_done(&vc->curr_bufs[n]->vb.vb2_buf,
+                                       VB2_BUF_STATE_ERROR);
+
+       spin_unlock(&vc->qlock);
+}
+
+static struct vb2_ops tw686x_video_qops = {
+       .queue_setup            = tw686x_queue_setup,
+       .buf_queue              = tw686x_buf_queue,
+       .start_streaming        = tw686x_start_streaming,
+       .stop_streaming         = tw686x_stop_streaming,
+       .wait_prepare           = vb2_ops_wait_prepare,
+       .wait_finish            = vb2_ops_wait_finish,
+};
+
+static int tw686x_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct tw686x_video_channel *vc;
+       struct tw686x_dev *dev;
+       unsigned int ch;
+
+       vc = container_of(ctrl->handler, struct tw686x_video_channel,
+                         ctrl_handler);
+       dev = vc->dev;
+       ch = vc->ch;
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               reg_write(dev, BRIGHT[ch], ctrl->val & 0xFF);
+               return 0;
+
+       case V4L2_CID_CONTRAST:
+               reg_write(dev, CONTRAST[ch], ctrl->val);
+               return 0;
+
+       case V4L2_CID_SATURATION:
+               reg_write(dev, SAT_U[ch], ctrl->val);
+               reg_write(dev, SAT_V[ch], ctrl->val);
+               return 0;
+
+       case V4L2_CID_HUE:
+               reg_write(dev, HUE[ch], ctrl->val & 0xFF);
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static const struct v4l2_ctrl_ops ctrl_ops = {
+       .s_ctrl = tw686x_s_ctrl,
+};
+
+static int tw686x_g_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct tw686x_video_channel *vc = video_drvdata(file);
+
+       f->fmt.pix.width = vc->width;
+       f->fmt.pix.height = vc->height;
+       f->fmt.pix.field = vc->field;
+       f->fmt.pix.pixelformat = vc->format->fourcc;
+       f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+       f->fmt.pix.bytesperline = f->fmt.pix.width * vc->format->depth / 8;
+       f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+       return 0;
+}
+
+static int tw686x_try_fmt_vid_cap(struct file *file, void *priv,
+                                 struct v4l2_format *f)
+{
+       tw686x_get_format(video_drvdata(file), f);
+       return 0;
+}
+
+static int tw686x_s_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct tw686x_video_channel *vc = video_drvdata(file);
+
+       tw686x_get_format(vc, f);
+       vc->format = format_by_fourcc(f->fmt.pix.pixelformat);
+       vc->field = f->fmt.pix.field;
+       vc->width = f->fmt.pix.width;
+       vc->height = f->fmt.pix.height;
+       return 0;
+}
+
+static int tw686x_querycap(struct file *file, void *priv,
+                          struct v4l2_capability *cap)
+{
+       struct tw686x_video_channel *vc = video_drvdata(file);
+       struct tw686x_dev *dev = vc->dev;
+
+       strcpy(cap->driver, "tw686x-kh");
+       strcpy(cap->card, dev->name);
+       sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci_dev));
+       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+       return 0;
+}
+
+static int tw686x_s_std(struct file *file, void *priv, v4l2_std_id id)
+{
+       struct tw686x_video_channel *vc = video_drvdata(file);
+       unsigned int cnt;
+       u32 sdt = 0; /* default */
+
+       for (cnt = 0; cnt < ARRAY_SIZE(video_standards); cnt++)
+               if (id & video_standards[cnt]) {
+                       sdt = cnt;
+                       break;
+               }
+
+       reg_write(vc->dev, SDT[vc->ch], sdt);
+       vc->video_standard = video_standards[sdt];
+       return 0;
+}
+
+static int tw686x_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct tw686x_video_channel *vc = video_drvdata(file);
+
+       *id = vc->video_standard;
+       return 0;
+}
+
+static int tw686x_enum_fmt_vid_cap(struct file *file, void *priv,
+                                  struct v4l2_fmtdesc *f)
+{
+       if (f->index >= ARRAY_SIZE(formats))
+               return -EINVAL;
+
+       strlcpy(f->description, formats[f->index].name, sizeof(f->description));
+       f->pixelformat = formats[f->index].fourcc;
+       return 0;
+}
+
+static int tw686x_g_parm(struct file *file, void *priv,
+                        struct v4l2_streamparm *sp)
+{
+       struct tw686x_video_channel *vc = video_drvdata(file);
+
+       if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       memset(&sp->parm.capture, 0, sizeof(sp->parm.capture));
+       sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+       v4l2_video_std_frame_period(vc->video_standard,
+                                   &sp->parm.capture.timeperframe);
+
+       return 0;
+}
+
+static int tw686x_enum_input(struct file *file, void *priv,
+                            struct v4l2_input *inp)
+{
+       /* the chip has internal multiplexer, support can be added
+          if the actual hw uses it */
+       if (inp->index)
+               return -EINVAL;
+
+       snprintf(inp->name, sizeof(inp->name), "Composite");
+       inp->type = V4L2_INPUT_TYPE_CAMERA;
+       inp->std = V4L2_STD_ALL;
+       inp->capabilities = V4L2_IN_CAP_STD;
+       return 0;
+}
+
+static int tw686x_g_input(struct file *file, void *priv, unsigned int *v)
+{
+       *v = 0;
+       return 0;
+}
+
+static int tw686x_s_input(struct file *file, void *priv, unsigned int v)
+{
+       if (v)
+               return -EINVAL;
+       return 0;
+}
+
+static const struct v4l2_file_operations tw686x_video_fops = {
+       .owner          = THIS_MODULE,
+       .open           = v4l2_fh_open,
+       .unlocked_ioctl = video_ioctl2,
+       .release        = vb2_fop_release,
+       .poll           = vb2_fop_poll,
+       .read           = vb2_fop_read,
+       .mmap           = vb2_fop_mmap,
+};
+
+static const struct v4l2_ioctl_ops tw686x_video_ioctl_ops = {
+       .vidioc_querycap                = tw686x_querycap,
+       .vidioc_enum_fmt_vid_cap        = tw686x_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap           = tw686x_g_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap           = tw686x_s_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap         = tw686x_try_fmt_vid_cap,
+       .vidioc_reqbufs                 = vb2_ioctl_reqbufs,
+       .vidioc_querybuf                = vb2_ioctl_querybuf,
+       .vidioc_qbuf                    = vb2_ioctl_qbuf,
+       .vidioc_dqbuf                   = vb2_ioctl_dqbuf,
+       .vidioc_create_bufs             = vb2_ioctl_create_bufs,
+       .vidioc_streamon                = vb2_ioctl_streamon,
+       .vidioc_streamoff               = vb2_ioctl_streamoff,
+       .vidioc_g_std                   = tw686x_g_std,
+       .vidioc_s_std                   = tw686x_s_std,
+       .vidioc_g_parm                  = tw686x_g_parm,
+       .vidioc_enum_input              = tw686x_enum_input,
+       .vidioc_g_input                 = tw686x_g_input,
+       .vidioc_s_input                 = tw686x_s_input,
+       .vidioc_subscribe_event         = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
+};
+
+static int video_thread(void *arg)
+{
+       struct tw686x_dev *dev = arg;
+       DECLARE_WAITQUEUE(wait, current);
+
+       set_freezable();
+       add_wait_queue(&dev->video_thread_wait, &wait);
+
+       while (1) {
+               long timeout = schedule_timeout_interruptible(HZ);
+               unsigned int ch;
+
+               if (timeout == -ERESTARTSYS || kthread_should_stop())
+                       break;
+
+               for (ch = 0; ch < max_channels(dev); ch++) {
+                       struct tw686x_video_channel *vc;
+                       unsigned long flags;
+                       u32 request, n, stat = VB2_BUF_STATE_DONE;
+
+                       vc = &dev->video_channels[ch];
+                       if (!(dev->video_active & (1 << ch)))
+                               continue;
+
+                       spin_lock_irq(&dev->irq_lock);
+                       request = dev->dma_requests & (0x01000001 << ch);
+                       if (request)
+                               dev->dma_requests &= ~request;
+                       spin_unlock_irq(&dev->irq_lock);
+
+                       if (!request)
+                               continue;
+
+                       request >>= ch;
+
+                       /* handle channel events */
+                       if ((request & 0x01000000) |
+                           (reg_read(dev, VIDEO_FIFO_STATUS) & (0x01010001 << ch)) |
+                           (reg_read(dev, VIDEO_PARSER_STATUS) & (0x00000101 << ch))) {
+                               /* DMA Errors - reset channel */
+                               u32 reg;
+
+                               spin_lock_irqsave(&dev->irq_lock, flags);
+                               reg = reg_read(dev, DMA_CMD);
+                               /* Reset DMA channel */
+                               reg_write(dev, DMA_CMD, reg & ~(1 << ch));
+                               reg_write(dev, DMA_CMD, reg);
+                               spin_unlock_irqrestore(&dev->irq_lock, flags);
+                               stat = VB2_BUF_STATE_ERROR;
+                       }
+
+                       /* handle video stream */
+                       mutex_lock(&vc->vb_mutex);
+                       spin_lock(&vc->qlock);
+                       n = !!(reg_read(dev, PB_STATUS) & (1 << ch));
+                       if (vc->curr_bufs[n]) {
+                               struct vb2_v4l2_buffer *vb;
+
+                               vb = &vc->curr_bufs[n]->vb;
+                               vb->vb2_buf.timestamp = ktime_get_ns();
+                               vb->field = vc->field;
+                               if (V4L2_FIELD_HAS_BOTH(vc->field))
+                                       vb->sequence = vc->seq++;
+                               else
+                                       vb->sequence = (vc->seq++) / 2;
+                               vb2_set_plane_payload(&vb->vb2_buf, 0,
+                                     vc->width * vc->height * vc->format->depth / 8);
+                               vb2_buffer_done(&vb->vb2_buf, stat);
+                       }
+                       setup_descs(vc, n);
+                       spin_unlock(&vc->qlock);
+                       mutex_unlock(&vc->vb_mutex);
+               }
+               try_to_freeze();
+       }
+
+       remove_wait_queue(&dev->video_thread_wait, &wait);
+       return 0;
+}
+
+int tw686x_kh_video_irq(struct tw686x_dev *dev)
+{
+       unsigned long flags, handled = 0;
+       u32 requests;
+
+       spin_lock_irqsave(&dev->irq_lock, flags);
+       requests = dev->dma_requests;
+       spin_unlock_irqrestore(&dev->irq_lock, flags);
+
+       if (requests & dev->video_active) {
+               wake_up_interruptible_all(&dev->video_thread_wait);
+               handled = 1;
+       }
+       return handled;
+}
+
+void tw686x_kh_video_free(struct tw686x_dev *dev)
+{
+       unsigned int ch, n;
+
+       if (dev->video_thread)
+               kthread_stop(dev->video_thread);
+
+       for (ch = 0; ch < max_channels(dev); ch++) {
+               struct tw686x_video_channel *vc = &dev->video_channels[ch];
+
+               v4l2_ctrl_handler_free(&vc->ctrl_handler);
+               if (vc->device)
+                       video_unregister_device(vc->device);
+               vb2_dma_sg_cleanup_ctx(vc->alloc_ctx);
+               for (n = 0; n < 2; n++) {
+                       struct dma_desc *descs = &vc->sg_tables[n];
+
+                       if (descs->virt)
+                               pci_free_consistent(dev->pci_dev, descs->size,
+                                                   descs->virt, descs->phys);
+               }
+       }
+
+       v4l2_device_unregister(&dev->v4l2_dev);
+}
+
+#define SG_TABLE_SIZE (MAX_SG_DESC_COUNT * sizeof(struct vdma_desc))
+
+int tw686x_kh_video_init(struct tw686x_dev *dev)
+{
+       unsigned int ch, n;
+       int err;
+
+       init_waitqueue_head(&dev->video_thread_wait);
+
+       err = v4l2_device_register(&dev->pci_dev->dev, &dev->v4l2_dev);
+       if (err)
+               return err;
+
+       reg_write(dev, VIDEO_CONTROL1, 0); /* NTSC, disable scaler */
+       reg_write(dev, PHASE_REF, 0x00001518); /* Scatter-gather DMA mode */
+
+       /* setup required SG table sizes */
+       for (n = 0; n < 2; n++)
+               if (is_second_gen(dev)) {
+                       /* TW 6865, TW6869 - each channel needs a pair of
+                          descriptor tables */
+                       for (ch = 0; ch < max_channels(dev); ch++)
+                               dev->video_channels[ch].sg_tables[n].size =
+                                       SG_TABLE_SIZE;
+
+               } else
+                       /* TW 6864, TW6868 - we need to allocate a pair of
+                          descriptor tables, common for all channels.
+                          Each table will be bigger than 4 KB. */
+                       dev->video_channels[0].sg_tables[n].size =
+                               max_channels(dev) * SG_TABLE_SIZE;
+
+       /* allocate SG tables and initialize video channels */
+       for (ch = 0; ch < max_channels(dev); ch++) {
+               struct tw686x_video_channel *vc = &dev->video_channels[ch];
+               struct video_device *vdev;
+
+               mutex_init(&vc->vb_mutex);
+               spin_lock_init(&vc->qlock);
+               INIT_LIST_HEAD(&vc->vidq_queued);
+
+               vc->dev = dev;
+               vc->ch = ch;
+
+               /* default settings: NTSC */
+               vc->format = &formats[0];
+               vc->video_standard = V4L2_STD_NTSC;
+               reg_write(vc->dev, SDT[vc->ch], 0);
+               vc->field = V4L2_FIELD_SEQ_BT;
+               vc->width = 704;
+               vc->height = 480;
+
+               for (n = 0; n < 2; n++) {
+                       void *cpu;
+
+                       if (vc->sg_tables[n].size) {
+                               unsigned int reg = n ? DMA_PAGE_TABLE1_ADDR[ch] :
+                                       DMA_PAGE_TABLE0_ADDR[ch];
+
+                               cpu = pci_alloc_consistent(dev->pci_dev,
+                                                          vc->sg_tables[n].size,
+                                                          &vc->sg_tables[n].phys);
+                               if (!cpu) {
+                                       pr_err("Error allocating video DMA scatter-gather tables\n");
+                                       err = -ENOMEM;
+                                       goto error;
+                               }
+                               vc->sg_tables[n].virt = cpu;
+                               reg_write(dev, reg, vc->sg_tables[n].phys);
+                       } else
+                               cpu = dev->video_channels[0].sg_tables[n].virt +
+                                       ch * SG_TABLE_SIZE;
+
+                       vc->sg_descs[n] = cpu;
+               }
+
+               reg_write(dev, VCTRL1[0], 0x24);
+               reg_write(dev, LOOP[0], 0xA5);
+               if (max_channels(dev) > 4) {
+                       reg_write(dev, VCTRL1[1], 0x24);
+                       reg_write(dev, LOOP[1], 0xA5);
+               }
+               reg_write(dev, VIDEO_FIELD_CTRL[ch], 0);
+               reg_write(dev, VDELAY_LO[ch], 0x14);
+
+               vdev = video_device_alloc();
+               if (!vdev) {
+                       pr_warn("Unable to allocate video device\n");
+                       err = -ENOMEM;
+                       goto error;
+               }
+
+               vc->alloc_ctx = vb2_dma_sg_init_ctx(&dev->pci_dev->dev);
+               if (IS_ERR(vc->alloc_ctx)) {
+                       pr_warn("Unable to initialize DMA scatter-gather context\n");
+                       err = PTR_ERR(vc->alloc_ctx);
+                       goto error;
+               }
+
+               vc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               vc->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+               vc->vidq.drv_priv = vc;
+               vc->vidq.buf_struct_size = sizeof(struct tw686x_vb2_buf);
+               vc->vidq.ops = &tw686x_video_qops;
+               vc->vidq.mem_ops = &vb2_dma_sg_memops;
+               vc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+               vc->vidq.min_buffers_needed = 2;
+               vc->vidq.lock = &vc->vb_mutex;
+               vc->vidq.gfp_flags = GFP_DMA32;
+
+               err = vb2_queue_init(&vc->vidq);
+               if (err)
+                       goto error;
+
+               strcpy(vdev->name, "TW686x-video");
+               snprintf(vdev->name, sizeof(vdev->name), "%s video", dev->name);
+               vdev->fops = &tw686x_video_fops;
+               vdev->ioctl_ops = &tw686x_video_ioctl_ops;
+               vdev->release = video_device_release;
+               vdev->v4l2_dev = &dev->v4l2_dev;
+               vdev->queue = &vc->vidq;
+               vdev->tvnorms = V4L2_STD_ALL;
+               vdev->minor = -1;
+               vdev->lock = &vc->vb_mutex;
+
+               dev->video_channels[ch].device = vdev;
+               video_set_drvdata(vdev, vc);
+               err = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+               if (err < 0)
+                       goto error;
+
+               v4l2_ctrl_handler_init(&vc->ctrl_handler,
+                                      4 /* number of controls */);
+               vdev->ctrl_handler = &vc->ctrl_handler;
+               v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops,
+                                 V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
+               v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops,
+                                 V4L2_CID_CONTRAST, 0, 255, 1, 64);
+               v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops,
+                                 V4L2_CID_SATURATION, 0, 255, 1, 128);
+               v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops, V4L2_CID_HUE,
+                                 -124, 127, 1, 0);
+               err = vc->ctrl_handler.error;
+               if (err)
+                       goto error;
+
+               v4l2_ctrl_handler_setup(&vc->ctrl_handler);
+       }
+
+       dev->video_thread = kthread_run(video_thread, dev, "tw686x_video");
+       if (IS_ERR(dev->video_thread)) {
+               err = PTR_ERR(dev->video_thread);
+               goto error;
+       }
+
+       return 0;
+
+error:
+       tw686x_kh_video_free(dev);
+       return err;
+}
diff --git a/drivers/staging/media/tw686x-kh/tw686x-kh.h b/drivers/staging/media/tw686x-kh/tw686x-kh.h
new file mode 100644 (file)
index 0000000..dc25796
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2015 Industrial Research Institute for Automation
+ * and Measurements PIAP
+ *
+ * Written by Krzysztof Ha?asa.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/freezer.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/pci.h>
+#include <media/videobuf2-dma-sg.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+
+#define TYPE_MAX_CHANNELS 0x0F
+#define TYPE_SECOND_GEN   0x10
+
+struct tw686x_format {
+       char *name;
+       unsigned int fourcc;
+       unsigned int depth;
+       unsigned int mode;
+};
+
+struct dma_desc {
+       dma_addr_t phys;
+       void *virt;
+       unsigned int size;
+};
+
+struct vdma_desc {
+       __le32 flags_length;    /* 3 MSBits for flags, 13 LSBits for length */
+       __le32 phys;
+};
+
+struct tw686x_vb2_buf {
+       struct vb2_v4l2_buffer vb;
+       struct list_head list;
+};
+
+struct tw686x_video_channel {
+       struct tw686x_dev *dev;
+
+       struct vb2_queue vidq;
+       struct list_head vidq_queued;
+       struct video_device *device;
+       struct dma_desc sg_tables[2];
+       struct tw686x_vb2_buf *curr_bufs[2];
+       void *alloc_ctx;
+       struct vdma_desc *sg_descs[2];
+
+       struct v4l2_ctrl_handler ctrl_handler;
+       const struct tw686x_format *format;
+       struct mutex vb_mutex;
+       spinlock_t qlock;
+       v4l2_std_id video_standard;
+       unsigned int width, height;
+       enum v4l2_field field; /* supported TOP, BOTTOM, SEQ_TB and SEQ_BT */
+       unsigned int seq;              /* video field or frame counter */
+       unsigned int ch;
+};
+
+/* global device status */
+struct tw686x_dev {
+       spinlock_t irq_lock;
+
+       struct v4l2_device v4l2_dev;
+       struct snd_card *card;  /* sound card */
+
+       unsigned int video_active;      /* active video channel mask */
+
+       char name[32];
+       unsigned int type;
+       struct pci_dev *pci_dev;
+       __u32 __iomem *mmio;
+
+       struct task_struct *video_thread;
+       wait_queue_head_t video_thread_wait;
+       u32 dma_requests;
+
+       struct tw686x_video_channel video_channels[0];
+};
+
+static inline uint32_t reg_read(struct tw686x_dev *dev, unsigned int reg)
+{
+       return readl(dev->mmio + reg);
+}
+
+static inline void reg_write(struct tw686x_dev *dev, unsigned int reg,
+                            uint32_t value)
+{
+       writel(value, dev->mmio + reg);
+}
+
+static inline unsigned int max_channels(struct tw686x_dev *dev)
+{
+       return dev->type & TYPE_MAX_CHANNELS; /* 4 or 8 channels */
+}
+
+static inline unsigned int is_second_gen(struct tw686x_dev *dev)
+{
+       /* each channel has its own DMA SG table */
+       return dev->type & TYPE_SECOND_GEN;
+}
+
+int tw686x_kh_video_irq(struct tw686x_dev *dev);
+int tw686x_kh_video_init(struct tw686x_dev *dev);
+void tw686x_kh_video_free(struct tw686x_dev *dev);
index df74cfa..a9b33c4 100644 (file)
@@ -25,7 +25,6 @@
 
 #include <linux/list.h>
 #include <linux/mutex.h>
-#include <linux/spinlock.h>
 
 #include <media/media-devnode.h>
 #include <media/media-entity.h>
@@ -304,8 +303,7 @@ struct media_entity_notify {
  * @pads:      List of registered pads
  * @links:     List of registered links
  * @entity_notify: List of registered entity_notify callbacks
- * @lock:      Entities list lock
- * @graph_mutex: Entities graph operation lock
+ * @graph_mutex: Protects access to struct media_device data
  * @pm_count_walk: Graph walk for power state walk. Access serialised using
  *                graph_mutex.
  *
@@ -313,7 +311,8 @@ struct media_entity_notify {
  * @enable_source: Enable Source Handler function pointer
  * @disable_source: Disable Source Handler function pointer
  *
- * @link_notify: Link state change notification callback
+ * @link_notify: Link state change notification callback. This callback is
+ *              called with the graph_mutex held.
  *
  * This structure represents an abstract high-level media device. It allows easy
  * access to entities and provides basic media device-level support. The
@@ -357,7 +356,7 @@ struct media_device {
        u32 hw_revision;
        u32 driver_version;
 
-       u32 topology_version;
+       u64 topology_version;
 
        u32 id;
        struct ida entity_internal_idx;
@@ -371,8 +370,6 @@ struct media_device {
        /* notify callback list invoked when a new entity is registered */
        struct list_head entity_notify;
 
-       /* Protects the graph objects creation/removal */
-       spinlock_t lock;
        /* Serializes graph operations. */
        struct mutex graph_mutex;
        struct media_entity_graph pm_count_walk;
@@ -494,7 +491,7 @@ int __must_check __media_device_register(struct media_device *mdev,
 #define media_device_register(mdev) __media_device_register(mdev, THIS_MODULE)
 
 /**
- * __media_device_unregister() - Unegisters a media device element
+ * media_device_unregister() - Unregisters a media device element
  *
  * @mdev:      pointer to struct &media_device
  *
index 6dc9e4e..cbb266f 100644 (file)
@@ -179,6 +179,9 @@ struct media_pad {
  * @link_validate:     Return whether a link is valid from the entity point of
  *                     view. The media_entity_pipeline_start() function
  *                     validates all links by calling this operation. Optional.
+ *
+ * Note: Those these callbacks are called with struct media_device.@graph_mutex
+ * mutex held.
  */
 struct media_entity_operations {
        int (*link_setup)(struct media_entity *entity,
@@ -187,11 +190,39 @@ struct media_entity_operations {
        int (*link_validate)(struct media_link *link);
 };
 
+/**
+ * enum media_entity_type - Media entity type
+ *
+ * @MEDIA_ENTITY_TYPE_BASE:
+ *     The entity isn't embedded in another subsystem structure.
+ * @MEDIA_ENTITY_TYPE_VIDEO_DEVICE:
+ *     The entity is embedded in a struct video_device instance.
+ * @MEDIA_ENTITY_TYPE_V4L2_SUBDEV:
+ *     The entity is embedded in a struct v4l2_subdev instance.
+ *
+ * Media entity objects are often not instantiated directly, but the media
+ * entity structure is inherited by (through embedding) other subsystem-specific
+ * structures. The media entity type identifies the type of the subclass
+ * structure that implements a media entity instance.
+ *
+ * This allows runtime type identification of media entities and safe casting to
+ * the correct object type. For instance, a media entity structure instance
+ * embedded in a v4l2_subdev structure instance will have the type
+ * MEDIA_ENTITY_TYPE_V4L2_SUBDEV and can safely be cast to a v4l2_subdev
+ * structure using the container_of() macro.
+ */
+enum media_entity_type {
+       MEDIA_ENTITY_TYPE_BASE,
+       MEDIA_ENTITY_TYPE_VIDEO_DEVICE,
+       MEDIA_ENTITY_TYPE_V4L2_SUBDEV,
+};
+
 /**
  * struct media_entity - A media entity graph object.
  *
  * @graph_obj: Embedded structure containing the media object common data.
  * @name:      Entity name.
+ * @obj_type:  Type of the object that implements the media_entity.
  * @function:  Entity main function, as defined in uapi/media.h
  *             (MEDIA_ENT_F_*)
  * @flags:     Entity flags, as defined in uapi/media.h (MEDIA_ENT_FL_*)
@@ -220,6 +251,7 @@ struct media_entity_operations {
 struct media_entity {
        struct media_gobj graph_obj;    /* must be first field in struct */
        const char *name;
+       enum media_entity_type obj_type;
        u32 function;
        unsigned long flags;
 
@@ -329,56 +361,29 @@ static inline u32 media_gobj_gen_id(enum media_gobj_type type, u64 local_id)
 }
 
 /**
- * is_media_entity_v4l2_io() - identify if the entity main function
- *                            is a V4L2 I/O
- *
+ * is_media_entity_v4l2_video_device() - Check if the entity is a video_device
  * @entity:    pointer to entity
  *
- * Return: true if the entity main function is one of the V4L2 I/O types
- *     (video, VBI or SDR radio); false otherwise.
+ * Return: true if the entity is an instance of a video_device object and can
+ * safely be cast to a struct video_device using the container_of() macro, or
+ * false otherwise.
  */
-static inline bool is_media_entity_v4l2_io(struct media_entity *entity)
+static inline bool is_media_entity_v4l2_video_device(struct media_entity *entity)
 {
-       if (!entity)
-               return false;
-
-       switch (entity->function) {
-       case MEDIA_ENT_F_IO_V4L:
-       case MEDIA_ENT_F_IO_VBI:
-       case MEDIA_ENT_F_IO_SWRADIO:
-               return true;
-       default:
-               return false;
-       }
+       return entity && entity->obj_type == MEDIA_ENTITY_TYPE_VIDEO_DEVICE;
 }
 
 /**
- * is_media_entity_v4l2_subdev - return true if the entity main function is
- *                              associated with the V4L2 API subdev usage
- *
+ * is_media_entity_v4l2_subdev() - Check if the entity is a v4l2_subdev
  * @entity:    pointer to entity
  *
- * This is an ancillary function used by subdev-based V4L2 drivers.
- * It checks if the entity function is one of functions used by a V4L2 subdev,
- * e. g. camera-relatef functions, analog TV decoder, TV tuner, V4L2 DSPs.
+ * Return: true if the entity is an instance of a v4l2_subdev object and can
+ * safely be cast to a struct v4l2_subdev using the container_of() macro, or
+ * false otherwise.
  */
 static inline bool is_media_entity_v4l2_subdev(struct media_entity *entity)
 {
-       if (!entity)
-               return false;
-
-       switch (entity->function) {
-       case MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN:
-       case MEDIA_ENT_F_CAM_SENSOR:
-       case MEDIA_ENT_F_FLASH:
-       case MEDIA_ENT_F_LENS:
-       case MEDIA_ENT_F_ATV_DECODER:
-       case MEDIA_ENT_F_TUNER:
-               return true;
-
-       default:
-               return false;
-       }
+       return entity && entity->obj_type == MEDIA_ENTITY_TYPE_V4L2_SUBDEV;
 }
 
 /**
index 0f77b3d..b6586a9 100644 (file)
@@ -215,12 +215,9 @@ enum raw_event_type {
 struct ir_raw_event {
        union {
                u32             duration;
-
-               struct {
-                       u32     carrier;
-                       u8      duty_cycle;
-               };
+               u32             carrier;
        };
+       u8                      duty_cycle;
 
        unsigned                pulse:1;
        unsigned                reset:1;
@@ -228,13 +225,7 @@ struct ir_raw_event {
        unsigned                carrier_report:1;
 };
 
-#define DEFINE_IR_RAW_EVENT(event) \
-       struct ir_raw_event event = { \
-               { .duration = 0 } , \
-               .pulse = 0, \
-               .reset = 0, \
-               .timeout = 0, \
-               .carrier_report = 0 }
+#define DEFINE_IR_RAW_EVENT(event) struct ir_raw_event event = {}
 
 static inline void init_ir_raw_event(struct ir_raw_event *ev)
 {
@@ -256,8 +247,7 @@ void ir_raw_event_set_idle(struct rc_dev *dev, bool idle);
 
 static inline void ir_raw_event_reset(struct rc_dev *dev)
 {
-       DEFINE_IR_RAW_EVENT(ev);
-       ev.reset = true;
+       struct ir_raw_event ev = { .reset = true };
 
        ir_raw_event_store(dev, &ev);
        ir_raw_event_handle(dev);
index 76056ab..25a3190 100644 (file)
@@ -92,6 +92,9 @@ struct video_device
        /* device ops */
        const struct v4l2_file_operations *fops;
 
+       /* device capabilities as used in v4l2_capabilities */
+       u32 device_caps;
+
        /* sysfs */
        struct device dev;              /* v4l device */
        struct cdev *cdev;              /* character device */
index 9c58157..d5d45a8 100644 (file)
@@ -196,11 +196,64 @@ static inline void v4l2_subdev_notify(struct v4l2_subdev *sd,
                        ##args);                                        \
 })
 
-#define v4l2_device_has_op(v4l2_dev, o, f)                             \
+/*
+ * Call the specified callback for all subdevs where grp_id & grpmsk != 0
+ * (if grpmsk == `0, then match them all). Ignore any errors. Note that you
+ * cannot add or delete a subdev while walking the subdevs list.
+ */
+#define v4l2_device_mask_call_all(v4l2_dev, grpmsk, o, f, args...)     \
+       do {                                                            \
+               struct v4l2_subdev *__sd;                               \
+                                                                       \
+               __v4l2_device_call_subdevs_p(v4l2_dev, __sd,            \
+                       !(grpmsk) || (__sd->grp_id & (grpmsk)), o, f ,  \
+                       ##args);                                        \
+       } while (0)
+
+/*
+ * Call the specified callback for all subdevs where grp_id & grpmsk != 0
+ * (if grpmsk == `0, then match them all). If the callback returns an error
+ * other than 0 or -ENOIOCTLCMD, then return with that error code. Note that
+ * you cannot add or delete a subdev while walking the subdevs list.
+ */
+#define v4l2_device_mask_call_until_err(v4l2_dev, grpmsk, o, f, args...) \
+({                                                                     \
+       struct v4l2_subdev *__sd;                                       \
+       __v4l2_device_call_subdevs_until_err_p(v4l2_dev, __sd,          \
+                       !(grpmsk) || (__sd->grp_id & (grpmsk)), o, f ,  \
+                       ##args);                                        \
+})
+
+/*
+ * Does any subdev with matching grpid (or all if grpid == 0) has the given
+ * op?
+ */
+#define v4l2_device_has_op(v4l2_dev, grpid, o, f)                      \
+({                                                                     \
+       struct v4l2_subdev *__sd;                                       \
+       bool __result = false;                                          \
+       list_for_each_entry(__sd, &(v4l2_dev)->subdevs, list) {         \
+               if ((grpid) && __sd->grp_id != (grpid))                 \
+                       continue;                                       \
+               if (v4l2_subdev_has_op(__sd, o, f)) {                   \
+                       __result = true;                                \
+                       break;                                          \
+               }                                                       \
+       }                                                               \
+       __result;                                                       \
+})
+
+/*
+ * Does any subdev with matching grpmsk (or all if grpmsk == 0) has the given
+ * op?
+ */
+#define v4l2_device_mask_has_op(v4l2_dev, grpmsk, o, f)                        \
 ({                                                                     \
        struct v4l2_subdev *__sd;                                       \
        bool __result = false;                                          \
        list_for_each_entry(__sd, &(v4l2_dev)->subdevs, list) {         \
+               if ((grpmsk) && !(__sd->grp_id & (grpmsk)))             \
+                       continue;                                       \
                if (v4l2_subdev_has_op(__sd, o, f)) {                   \
                        __result = true;                                \
                        break;                                          \
diff --git a/include/media/v4l2-rect.h b/include/media/v4l2-rect.h
new file mode 100644 (file)
index 0000000..d2125f0
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * v4l2-rect.h - v4l2_rect helper functions
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _V4L2_RECT_H_
+#define _V4L2_RECT_H_
+
+#include <linux/videodev2.h>
+
+/**
+ * v4l2_rect_set_size_to() - copy the width/height values.
+ * @r: rect whose width and height fields will be set
+ * @size: rect containing the width and height fields you need.
+ */
+static inline void v4l2_rect_set_size_to(struct v4l2_rect *r,
+                                        const struct v4l2_rect *size)
+{
+       r->width = size->width;
+       r->height = size->height;
+}
+
+/**
+ * v4l2_rect_set_min_size() - width and height of r should be >= min_size.
+ * @r: rect whose width and height will be modified
+ * @min_size: rect containing the minimal width and height
+ */
+static inline void v4l2_rect_set_min_size(struct v4l2_rect *r,
+                                         const struct v4l2_rect *min_size)
+{
+       if (r->width < min_size->width)
+               r->width = min_size->width;
+       if (r->height < min_size->height)
+               r->height = min_size->height;
+}
+
+/**
+ * v4l2_rect_set_max_size() - width and height of r should be <= max_size
+ * @r: rect whose width and height will be modified
+ * @max_size: rect containing the maximum width and height
+ */
+static inline void v4l2_rect_set_max_size(struct v4l2_rect *r,
+                                         const struct v4l2_rect *max_size)
+{
+       if (r->width > max_size->width)
+               r->width = max_size->width;
+       if (r->height > max_size->height)
+               r->height = max_size->height;
+}
+
+/**
+ * v4l2_rect_map_inside()- r should be inside boundary.
+ * @r: rect that will be modified
+ * @boundary: rect containing the boundary for @r
+ */
+static inline void v4l2_rect_map_inside(struct v4l2_rect *r,
+                                       const struct v4l2_rect *boundary)
+{
+       v4l2_rect_set_max_size(r, boundary);
+       if (r->left < boundary->left)
+               r->left = boundary->left;
+       if (r->top < boundary->top)
+               r->top = boundary->top;
+       if (r->left + r->width > boundary->width)
+               r->left = boundary->width - r->width;
+       if (r->top + r->height > boundary->height)
+               r->top = boundary->height - r->height;
+}
+
+/**
+ * v4l2_rect_same_size() - return true if r1 has the same size as r2
+ * @r1: rectangle.
+ * @r2: rectangle.
+ *
+ * Return true if both rectangles have the same size.
+ */
+static inline bool v4l2_rect_same_size(const struct v4l2_rect *r1,
+                                      const struct v4l2_rect *r2)
+{
+       return r1->width == r2->width && r1->height == r2->height;
+}
+
+/**
+ * v4l2_rect_intersect() - calculate the intersection of two rects.
+ * @r: intersection of @r1 and @r2.
+ * @r1: rectangle.
+ * @r2: rectangle.
+ */
+static inline void v4l2_rect_intersect(struct v4l2_rect *r,
+                                      const struct v4l2_rect *r1,
+                                      const struct v4l2_rect *r2)
+{
+       int right, bottom;
+
+       r->top = max(r1->top, r2->top);
+       r->left = max(r1->left, r2->left);
+       bottom = min(r1->top + r1->height, r2->top + r2->height);
+       right = min(r1->left + r1->width, r2->left + r2->width);
+       r->height = max(0, bottom - r->top);
+       r->width = max(0, right - r->left);
+}
+
+/**
+ * v4l2_rect_scale() - scale rect r by to/from
+ * @r: rect to be scaled.
+ * @from: from rectangle.
+ * @to: to rectangle.
+ *
+ * This scales rectangle @r horizontally by @to->width / @from->width and
+ * vertically by @to->height / @from->height.
+ *
+ * Typically @r is a rectangle inside @from and you want the rectangle as
+ * it would appear after scaling @from to @to. So the resulting @r will
+ * be the scaled rectangle inside @to.
+ */
+static inline void v4l2_rect_scale(struct v4l2_rect *r,
+                                  const struct v4l2_rect *from,
+                                  const struct v4l2_rect *to)
+{
+       if (from->width == 0 || from->height == 0) {
+               r->left = r->top = r->width = r->height = 0;
+               return;
+       }
+       r->left = (((r->left - from->left) * to->width) / from->width) & ~1;
+       r->width = ((r->width * to->width) / from->width) & ~1;
+       r->top = ((r->top - from->top) * to->height) / from->height;
+       r->height = (r->height * to->height) / from->height;
+}
+
+/**
+ * v4l2_rect_overlap() - do r1 and r2 overlap?
+ * @r1: rectangle.
+ * @r2: rectangle.
+ *
+ * Returns true if @r1 and @r2 overlap.
+ */
+static inline bool v4l2_rect_overlap(const struct v4l2_rect *r1,
+                                    const struct v4l2_rect *r2)
+{
+       /*
+        * IF the left side of r1 is to the right of the right side of r2 OR
+        *    the left side of r2 is to the right of the right side of r1 THEN
+        * they do not overlap.
+        */
+       if (r1->left >= r2->left + r2->width ||
+           r2->left >= r1->left + r1->width)
+               return false;
+       /*
+        * IF the top side of r1 is below the bottom of r2 OR
+        *    the top side of r2 is below the bottom of r1 THEN
+        * they do not overlap.
+        */
+       if (r1->top >= r2->top + r2->height ||
+           r2->top >= r1->top + r1->height)
+               return false;
+       return true;
+}
+
+#endif
index 11e2dfe..32fc7a4 100644 (file)
@@ -572,6 +572,7 @@ struct v4l2_subdev_pad_config {
 /**
  * struct v4l2_subdev_pad_ops - v4l2-subdev pad level operations
  *
+ * @init_cfg: initialize the pad config to default values
  * @enum_mbus_code: callback for VIDIOC_SUBDEV_ENUM_MBUS_CODE ioctl handler
  *                 code.
  * @enum_frame_size: callback for VIDIOC_SUBDEV_ENUM_FRAME_SIZE ioctl handler
@@ -607,6 +608,8 @@ struct v4l2_subdev_pad_config {
  *                  may be adjusted by the subdev driver to device capabilities.
  */
 struct v4l2_subdev_pad_ops {
+       int (*init_cfg)(struct v4l2_subdev *sd,
+                       struct v4l2_subdev_pad_config *cfg);
        int (*enum_mbus_code)(struct v4l2_subdev *sd,
                              struct v4l2_subdev_pad_config *cfg,
                              struct v4l2_subdev_mbus_code_enum *code);
@@ -801,7 +804,12 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
                                      struct v4l2_subdev_format *source_fmt,
                                      struct v4l2_subdev_format *sink_fmt);
 int v4l2_subdev_link_validate(struct media_link *link);
+
+struct v4l2_subdev_pad_config *
+v4l2_subdev_alloc_pad_config(struct v4l2_subdev *sd);
+void v4l2_subdev_free_pad_config(struct v4l2_subdev_pad_config *cfg);
 #endif /* CONFIG_MEDIA_CONTROLLER */
+
 void v4l2_subdev_init(struct v4l2_subdev *sd,
                      const struct v4l2_subdev_ops *ops);
 
diff --git a/include/media/v4l2-tpg-colors.h b/include/media/v4l2-tpg-colors.h
new file mode 100644 (file)
index 0000000..2a88d1f
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * v4l2-tpg-colors.h - Color definitions for the test pattern generator
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _V4L2_TPG_COLORS_H_
+#define _V4L2_TPG_COLORS_H_
+
+struct color {
+       unsigned char r, g, b;
+};
+
+struct color16 {
+       int r, g, b;
+};
+
+enum tpg_color {
+       TPG_COLOR_CSC_WHITE,
+       TPG_COLOR_CSC_YELLOW,
+       TPG_COLOR_CSC_CYAN,
+       TPG_COLOR_CSC_GREEN,
+       TPG_COLOR_CSC_MAGENTA,
+       TPG_COLOR_CSC_RED,
+       TPG_COLOR_CSC_BLUE,
+       TPG_COLOR_CSC_BLACK,
+       TPG_COLOR_75_YELLOW,
+       TPG_COLOR_75_CYAN,
+       TPG_COLOR_75_GREEN,
+       TPG_COLOR_75_MAGENTA,
+       TPG_COLOR_75_RED,
+       TPG_COLOR_75_BLUE,
+       TPG_COLOR_100_WHITE,
+       TPG_COLOR_100_YELLOW,
+       TPG_COLOR_100_CYAN,
+       TPG_COLOR_100_GREEN,
+       TPG_COLOR_100_MAGENTA,
+       TPG_COLOR_100_RED,
+       TPG_COLOR_100_BLUE,
+       TPG_COLOR_100_BLACK,
+       TPG_COLOR_TEXTFG,
+       TPG_COLOR_TEXTBG,
+       TPG_COLOR_RANDOM,
+       TPG_COLOR_RAMP,
+       TPG_COLOR_MAX = TPG_COLOR_RAMP + 256
+};
+
+extern const struct color tpg_colors[TPG_COLOR_MAX];
+extern const unsigned short tpg_rec709_to_linear[255 * 16 + 1];
+extern const unsigned short tpg_linear_to_rec709[255 * 16 + 1];
+extern const struct color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1]
+                                         [V4L2_XFER_FUNC_SMPTE2084 + 1]
+                                         [TPG_COLOR_CSC_BLACK + 1];
+
+#endif
diff --git a/include/media/v4l2-tpg.h b/include/media/v4l2-tpg.h
new file mode 100644 (file)
index 0000000..329bebf
--- /dev/null
@@ -0,0 +1,597 @@
+/*
+ * v4l2-tpg.h - Test Pattern Generator
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _V4L2_TPG_H_
+#define _V4L2_TPG_H_
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-tpg-colors.h>
+
+enum tpg_pattern {
+       TPG_PAT_75_COLORBAR,
+       TPG_PAT_100_COLORBAR,
+       TPG_PAT_CSC_COLORBAR,
+       TPG_PAT_100_HCOLORBAR,
+       TPG_PAT_100_COLORSQUARES,
+       TPG_PAT_BLACK,
+       TPG_PAT_WHITE,
+       TPG_PAT_RED,
+       TPG_PAT_GREEN,
+       TPG_PAT_BLUE,
+       TPG_PAT_CHECKERS_16X16,
+       TPG_PAT_CHECKERS_2X2,
+       TPG_PAT_CHECKERS_1X1,
+       TPG_PAT_COLOR_CHECKERS_2X2,
+       TPG_PAT_COLOR_CHECKERS_1X1,
+       TPG_PAT_ALTERNATING_HLINES,
+       TPG_PAT_ALTERNATING_VLINES,
+       TPG_PAT_CROSS_1_PIXEL,
+       TPG_PAT_CROSS_2_PIXELS,
+       TPG_PAT_CROSS_10_PIXELS,
+       TPG_PAT_GRAY_RAMP,
+
+       /* Must be the last pattern */
+       TPG_PAT_NOISE,
+};
+
+extern const char * const tpg_pattern_strings[];
+
+enum tpg_quality {
+       TPG_QUAL_COLOR,
+       TPG_QUAL_GRAY,
+       TPG_QUAL_NOISE
+};
+
+enum tpg_video_aspect {
+       TPG_VIDEO_ASPECT_IMAGE,
+       TPG_VIDEO_ASPECT_4X3,
+       TPG_VIDEO_ASPECT_14X9_CENTRE,
+       TPG_VIDEO_ASPECT_16X9_CENTRE,
+       TPG_VIDEO_ASPECT_16X9_ANAMORPHIC,
+};
+
+enum tpg_pixel_aspect {
+       TPG_PIXEL_ASPECT_SQUARE,
+       TPG_PIXEL_ASPECT_NTSC,
+       TPG_PIXEL_ASPECT_PAL,
+};
+
+enum tpg_move_mode {
+       TPG_MOVE_NEG_FAST,
+       TPG_MOVE_NEG,
+       TPG_MOVE_NEG_SLOW,
+       TPG_MOVE_NONE,
+       TPG_MOVE_POS_SLOW,
+       TPG_MOVE_POS,
+       TPG_MOVE_POS_FAST,
+};
+
+extern const char * const tpg_aspect_strings[];
+
+#define TPG_MAX_PLANES 3
+#define TPG_MAX_PAT_LINES 8
+
+struct tpg_data {
+       /* Source frame size */
+       unsigned                        src_width, src_height;
+       /* Buffer height */
+       unsigned                        buf_height;
+       /* Scaled output frame size */
+       unsigned                        scaled_width;
+       u32                             field;
+       bool                            field_alternate;
+       /* crop coordinates are frame-based */
+       struct v4l2_rect                crop;
+       /* compose coordinates are format-based */
+       struct v4l2_rect                compose;
+       /* border and square coordinates are frame-based */
+       struct v4l2_rect                border;
+       struct v4l2_rect                square;
+
+       /* Color-related fields */
+       enum tpg_quality                qual;
+       unsigned                        qual_offset;
+       u8                              alpha_component;
+       bool                            alpha_red_only;
+       u8                              brightness;
+       u8                              contrast;
+       u8                              saturation;
+       s16                             hue;
+       u32                             fourcc;
+       bool                            is_yuv;
+       u32                             colorspace;
+       u32                             xfer_func;
+       u32                             ycbcr_enc;
+       /*
+        * Stores the actual transfer function, i.e. will never be
+        * V4L2_XFER_FUNC_DEFAULT.
+        */
+       u32                             real_xfer_func;
+       /*
+        * Stores the actual Y'CbCr encoding, i.e. will never be
+        * V4L2_YCBCR_ENC_DEFAULT.
+        */
+       u32                             real_ycbcr_enc;
+       u32                             quantization;
+       /*
+        * Stores the actual quantization, i.e. will never be
+        * V4L2_QUANTIZATION_DEFAULT.
+        */
+       u32                             real_quantization;
+       enum tpg_video_aspect           vid_aspect;
+       enum tpg_pixel_aspect           pix_aspect;
+       unsigned                        rgb_range;
+       unsigned                        real_rgb_range;
+       unsigned                        buffers;
+       unsigned                        planes;
+       bool                            interleaved;
+       u8                              vdownsampling[TPG_MAX_PLANES];
+       u8                              hdownsampling[TPG_MAX_PLANES];
+       /*
+        * horizontal positions must be ANDed with this value to enforce
+        * correct boundaries for packed YUYV values.
+        */
+       unsigned                        hmask[TPG_MAX_PLANES];
+       /* Used to store the colors in native format, either RGB or YUV */
+       u8                              colors[TPG_COLOR_MAX][3];
+       u8                              textfg[TPG_MAX_PLANES][8], textbg[TPG_MAX_PLANES][8];
+       /* size in bytes for two pixels in each plane */
+       unsigned                        twopixelsize[TPG_MAX_PLANES];
+       unsigned                        bytesperline[TPG_MAX_PLANES];
+
+       /* Configuration */
+       enum tpg_pattern                pattern;
+       bool                            hflip;
+       bool                            vflip;
+       unsigned                        perc_fill;
+       bool                            perc_fill_blank;
+       bool                            show_border;
+       bool                            show_square;
+       bool                            insert_sav;
+       bool                            insert_eav;
+
+       /* Test pattern movement */
+       enum tpg_move_mode              mv_hor_mode;
+       int                             mv_hor_count;
+       int                             mv_hor_step;
+       enum tpg_move_mode              mv_vert_mode;
+       int                             mv_vert_count;
+       int                             mv_vert_step;
+
+       bool                            recalc_colors;
+       bool                            recalc_lines;
+       bool                            recalc_square_border;
+
+       /* Used to store TPG_MAX_PAT_LINES lines, each with up to two planes */
+       unsigned                        max_line_width;
+       u8                              *lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES];
+       u8                              *downsampled_lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES];
+       u8                              *random_line[TPG_MAX_PLANES];
+       u8                              *contrast_line[TPG_MAX_PLANES];
+       u8                              *black_line[TPG_MAX_PLANES];
+};
+
+void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h);
+int tpg_alloc(struct tpg_data *tpg, unsigned max_w);
+void tpg_free(struct tpg_data *tpg);
+void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
+                      u32 field);
+void tpg_log_status(struct tpg_data *tpg);
+
+void tpg_set_font(const u8 *f);
+void tpg_gen_text(const struct tpg_data *tpg,
+               u8 *basep[TPG_MAX_PLANES][2], int y, int x, char *text);
+void tpg_calc_text_basep(struct tpg_data *tpg,
+               u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf);
+unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line);
+void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,
+                          unsigned p, u8 *vbuf);
+void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std,
+                   unsigned p, u8 *vbuf);
+bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc);
+void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
+               const struct v4l2_rect *compose);
+
+static inline void tpg_s_pattern(struct tpg_data *tpg, enum tpg_pattern pattern)
+{
+       if (tpg->pattern == pattern)
+               return;
+       tpg->pattern = pattern;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_quality(struct tpg_data *tpg,
+                                   enum tpg_quality qual, unsigned qual_offset)
+{
+       if (tpg->qual == qual && tpg->qual_offset == qual_offset)
+               return;
+       tpg->qual = qual;
+       tpg->qual_offset = qual_offset;
+       tpg->recalc_colors = true;
+}
+
+static inline enum tpg_quality tpg_g_quality(const struct tpg_data *tpg)
+{
+       return tpg->qual;
+}
+
+static inline void tpg_s_alpha_component(struct tpg_data *tpg,
+                                           u8 alpha_component)
+{
+       if (tpg->alpha_component == alpha_component)
+               return;
+       tpg->alpha_component = alpha_component;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_alpha_mode(struct tpg_data *tpg,
+                                           bool red_only)
+{
+       if (tpg->alpha_red_only == red_only)
+               return;
+       tpg->alpha_red_only = red_only;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_brightness(struct tpg_data *tpg,
+                                       u8 brightness)
+{
+       if (tpg->brightness == brightness)
+               return;
+       tpg->brightness = brightness;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_contrast(struct tpg_data *tpg,
+                                       u8 contrast)
+{
+       if (tpg->contrast == contrast)
+               return;
+       tpg->contrast = contrast;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_saturation(struct tpg_data *tpg,
+                                       u8 saturation)
+{
+       if (tpg->saturation == saturation)
+               return;
+       tpg->saturation = saturation;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_hue(struct tpg_data *tpg,
+                                       s16 hue)
+{
+       if (tpg->hue == hue)
+               return;
+       tpg->hue = hue;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_rgb_range(struct tpg_data *tpg,
+                                       unsigned rgb_range)
+{
+       if (tpg->rgb_range == rgb_range)
+               return;
+       tpg->rgb_range = rgb_range;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_real_rgb_range(struct tpg_data *tpg,
+                                       unsigned rgb_range)
+{
+       if (tpg->real_rgb_range == rgb_range)
+               return;
+       tpg->real_rgb_range = rgb_range;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_colorspace(struct tpg_data *tpg, u32 colorspace)
+{
+       if (tpg->colorspace == colorspace)
+               return;
+       tpg->colorspace = colorspace;
+       tpg->recalc_colors = true;
+}
+
+static inline u32 tpg_g_colorspace(const struct tpg_data *tpg)
+{
+       return tpg->colorspace;
+}
+
+static inline void tpg_s_ycbcr_enc(struct tpg_data *tpg, u32 ycbcr_enc)
+{
+       if (tpg->ycbcr_enc == ycbcr_enc)
+               return;
+       tpg->ycbcr_enc = ycbcr_enc;
+       tpg->recalc_colors = true;
+}
+
+static inline u32 tpg_g_ycbcr_enc(const struct tpg_data *tpg)
+{
+       return tpg->ycbcr_enc;
+}
+
+static inline void tpg_s_xfer_func(struct tpg_data *tpg, u32 xfer_func)
+{
+       if (tpg->xfer_func == xfer_func)
+               return;
+       tpg->xfer_func = xfer_func;
+       tpg->recalc_colors = true;
+}
+
+static inline u32 tpg_g_xfer_func(const struct tpg_data *tpg)
+{
+       return tpg->xfer_func;
+}
+
+static inline void tpg_s_quantization(struct tpg_data *tpg, u32 quantization)
+{
+       if (tpg->quantization == quantization)
+               return;
+       tpg->quantization = quantization;
+       tpg->recalc_colors = true;
+}
+
+static inline u32 tpg_g_quantization(const struct tpg_data *tpg)
+{
+       return tpg->quantization;
+}
+
+static inline unsigned tpg_g_buffers(const struct tpg_data *tpg)
+{
+       return tpg->buffers;
+}
+
+static inline unsigned tpg_g_planes(const struct tpg_data *tpg)
+{
+       return tpg->interleaved ? 1 : tpg->planes;
+}
+
+static inline bool tpg_g_interleaved(const struct tpg_data *tpg)
+{
+       return tpg->interleaved;
+}
+
+static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned plane)
+{
+       return tpg->twopixelsize[plane];
+}
+
+static inline unsigned tpg_hdiv(const struct tpg_data *tpg,
+                                 unsigned plane, unsigned x)
+{
+       return ((x / tpg->hdownsampling[plane]) & tpg->hmask[plane]) *
+               tpg->twopixelsize[plane] / 2;
+}
+
+static inline unsigned tpg_hscale(const struct tpg_data *tpg, unsigned x)
+{
+       return (x * tpg->scaled_width) / tpg->src_width;
+}
+
+static inline unsigned tpg_hscale_div(const struct tpg_data *tpg,
+                                     unsigned plane, unsigned x)
+{
+       return tpg_hdiv(tpg, plane, tpg_hscale(tpg, x));
+}
+
+static inline unsigned tpg_g_bytesperline(const struct tpg_data *tpg, unsigned plane)
+{
+       return tpg->bytesperline[plane];
+}
+
+static inline void tpg_s_bytesperline(struct tpg_data *tpg, unsigned plane, unsigned bpl)
+{
+       unsigned p;
+
+       if (tpg->buffers > 1) {
+               tpg->bytesperline[plane] = bpl;
+               return;
+       }
+
+       for (p = 0; p < tpg_g_planes(tpg); p++) {
+               unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0];
+
+               tpg->bytesperline[p] = plane_w / tpg->hdownsampling[p];
+       }
+       if (tpg_g_interleaved(tpg))
+               tpg->bytesperline[1] = tpg->bytesperline[0];
+}
+
+
+static inline unsigned tpg_g_line_width(const struct tpg_data *tpg, unsigned plane)
+{
+       unsigned w = 0;
+       unsigned p;
+
+       if (tpg->buffers > 1)
+               return tpg_g_bytesperline(tpg, plane);
+       for (p = 0; p < tpg_g_planes(tpg); p++) {
+               unsigned plane_w = tpg_g_bytesperline(tpg, p);
+
+               w += plane_w / tpg->vdownsampling[p];
+       }
+       return w;
+}
+
+static inline unsigned tpg_calc_line_width(const struct tpg_data *tpg,
+                                          unsigned plane, unsigned bpl)
+{
+       unsigned w = 0;
+       unsigned p;
+
+       if (tpg->buffers > 1)
+               return bpl;
+       for (p = 0; p < tpg_g_planes(tpg); p++) {
+               unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0];
+
+               plane_w /= tpg->hdownsampling[p];
+               w += plane_w / tpg->vdownsampling[p];
+       }
+       return w;
+}
+
+static inline unsigned tpg_calc_plane_size(const struct tpg_data *tpg, unsigned plane)
+{
+       if (plane >= tpg_g_planes(tpg))
+               return 0;
+
+       return tpg_g_bytesperline(tpg, plane) * tpg->buf_height /
+              tpg->vdownsampling[plane];
+}
+
+static inline void tpg_s_buf_height(struct tpg_data *tpg, unsigned h)
+{
+       tpg->buf_height = h;
+}
+
+static inline void tpg_s_field(struct tpg_data *tpg, unsigned field, bool alternate)
+{
+       tpg->field = field;
+       tpg->field_alternate = alternate;
+}
+
+static inline void tpg_s_perc_fill(struct tpg_data *tpg,
+                                     unsigned perc_fill)
+{
+       tpg->perc_fill = perc_fill;
+}
+
+static inline unsigned tpg_g_perc_fill(const struct tpg_data *tpg)
+{
+       return tpg->perc_fill;
+}
+
+static inline void tpg_s_perc_fill_blank(struct tpg_data *tpg,
+                                        bool perc_fill_blank)
+{
+       tpg->perc_fill_blank = perc_fill_blank;
+}
+
+static inline void tpg_s_video_aspect(struct tpg_data *tpg,
+                                       enum tpg_video_aspect vid_aspect)
+{
+       if (tpg->vid_aspect == vid_aspect)
+               return;
+       tpg->vid_aspect = vid_aspect;
+       tpg->recalc_square_border = true;
+}
+
+static inline enum tpg_video_aspect tpg_g_video_aspect(const struct tpg_data *tpg)
+{
+       return tpg->vid_aspect;
+}
+
+static inline void tpg_s_pixel_aspect(struct tpg_data *tpg,
+                                       enum tpg_pixel_aspect pix_aspect)
+{
+       if (tpg->pix_aspect == pix_aspect)
+               return;
+       tpg->pix_aspect = pix_aspect;
+       tpg->recalc_square_border = true;
+}
+
+static inline void tpg_s_show_border(struct tpg_data *tpg,
+                                       bool show_border)
+{
+       tpg->show_border = show_border;
+}
+
+static inline void tpg_s_show_square(struct tpg_data *tpg,
+                                       bool show_square)
+{
+       tpg->show_square = show_square;
+}
+
+static inline void tpg_s_insert_sav(struct tpg_data *tpg, bool insert_sav)
+{
+       tpg->insert_sav = insert_sav;
+}
+
+static inline void tpg_s_insert_eav(struct tpg_data *tpg, bool insert_eav)
+{
+       tpg->insert_eav = insert_eav;
+}
+
+void tpg_update_mv_step(struct tpg_data *tpg);
+
+static inline void tpg_s_mv_hor_mode(struct tpg_data *tpg,
+                               enum tpg_move_mode mv_hor_mode)
+{
+       tpg->mv_hor_mode = mv_hor_mode;
+       tpg_update_mv_step(tpg);
+}
+
+static inline void tpg_s_mv_vert_mode(struct tpg_data *tpg,
+                               enum tpg_move_mode mv_vert_mode)
+{
+       tpg->mv_vert_mode = mv_vert_mode;
+       tpg_update_mv_step(tpg);
+}
+
+static inline void tpg_init_mv_count(struct tpg_data *tpg)
+{
+       tpg->mv_hor_count = tpg->mv_vert_count = 0;
+}
+
+static inline void tpg_update_mv_count(struct tpg_data *tpg, bool frame_is_field)
+{
+       tpg->mv_hor_count += tpg->mv_hor_step * (frame_is_field ? 1 : 2);
+       tpg->mv_vert_count += tpg->mv_vert_step * (frame_is_field ? 1 : 2);
+}
+
+static inline void tpg_s_hflip(struct tpg_data *tpg, bool hflip)
+{
+       if (tpg->hflip == hflip)
+               return;
+       tpg->hflip = hflip;
+       tpg_update_mv_step(tpg);
+       tpg->recalc_lines = true;
+}
+
+static inline bool tpg_g_hflip(const struct tpg_data *tpg)
+{
+       return tpg->hflip;
+}
+
+static inline void tpg_s_vflip(struct tpg_data *tpg, bool vflip)
+{
+       tpg->vflip = vflip;
+}
+
+static inline bool tpg_g_vflip(const struct tpg_data *tpg)
+{
+       return tpg->vflip;
+}
+
+static inline bool tpg_pattern_is_static(const struct tpg_data *tpg)
+{
+       return tpg->pattern != TPG_PAT_NOISE &&
+              tpg->mv_hor_mode == TPG_MOVE_NONE &&
+              tpg->mv_vert_mode == TPG_MOVE_NONE;
+}
+
+#endif
index cc54175..3e654a0 100644 (file)
@@ -23,11 +23,22 @@ int vsp1_du_init(struct device *dev);
 int vsp1_du_setup_lif(struct device *dev, unsigned int width,
                      unsigned int height);
 
-int vsp1_du_atomic_begin(struct device *dev);
-int vsp1_du_atomic_update(struct device *dev, unsigned int rpf, u32 pixelformat,
-                         unsigned int pitch, dma_addr_t mem[2],
-                         const struct v4l2_rect *src,
-                         const struct v4l2_rect *dst);
-int vsp1_du_atomic_flush(struct device *dev);
+void vsp1_du_atomic_begin(struct device *dev);
+int vsp1_du_atomic_update_ext(struct device *dev, unsigned int rpf,
+                             u32 pixelformat, unsigned int pitch,
+                             dma_addr_t mem[2], const struct v4l2_rect *src,
+                             const struct v4l2_rect *dst, unsigned int alpha,
+                             unsigned int zpos);
+void vsp1_du_atomic_flush(struct device *dev);
+
+static inline int vsp1_du_atomic_update(struct device *dev,
+                                       unsigned int rpf_index, u32 pixelformat,
+                                       unsigned int pitch, dma_addr_t mem[2],
+                                       const struct v4l2_rect *src,
+                                       const struct v4l2_rect *dst)
+{
+       return vsp1_du_atomic_update_ext(dev, rpf_index, pixelformat, pitch,
+                                        mem, src, dst, 255, 0);
+}
 
 #endif /* __MEDIA_VSP1_H__ */
index e895975..8f95191 100644 (file)
@@ -138,10 +138,7 @@ enum v4l2_buf_type {
        V4L2_BUF_TYPE_VBI_OUTPUT           = 5,
        V4L2_BUF_TYPE_SLICED_VBI_CAPTURE   = 6,
        V4L2_BUF_TYPE_SLICED_VBI_OUTPUT    = 7,
-#if 1
-       /* Experimental */
        V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,
-#endif
        V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 9,
        V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE  = 10,
        V4L2_BUF_TYPE_SDR_CAPTURE          = 11,
@@ -657,8 +654,7 @@ struct v4l2_fmtdesc {
 #define V4L2_FMT_FLAG_COMPRESSED 0x0001
 #define V4L2_FMT_FLAG_EMULATED   0x0002
 
-#if 1
-       /* Experimental Frame Size and frame rate enumeration */
+       /* Frame Size and frame rate enumeration */
 /*
  *     F R A M E   S I Z E   E N U M E R A T I O N
  */
@@ -724,7 +720,6 @@ struct v4l2_frmivalenum {
 
        __u32   reserved[2];                    /* Reserved space for future use */
 };
-#endif
 
 /*
  *     T I M E C O D E
@@ -1728,8 +1723,6 @@ struct v4l2_audioout {
 
 /*
  *     M P E G   S E R V I C E S
- *
- *     NOTE: EXPERIMENTAL API
  */
 #if 1
 #define V4L2_ENC_IDX_FRAME_I    (0)
@@ -2259,46 +2252,35 @@ struct v4l2_create_buffers {
 #define VIDIOC_ENCODER_CMD      _IOWR('V', 77, struct v4l2_encoder_cmd)
 #define VIDIOC_TRY_ENCODER_CMD  _IOWR('V', 78, struct v4l2_encoder_cmd)
 
-/* Experimental, meant for debugging, testing and internal use.
-   Only implemented if CONFIG_VIDEO_ADV_DEBUG is defined.
-   You must be root to use these ioctls. Never use these in applications! */
+/*
+ * Experimental, meant for debugging, testing and internal use.
+ * Only implemented if CONFIG_VIDEO_ADV_DEBUG is defined.
+ * You must be root to use these ioctls. Never use these in applications!
+ */
 #define        VIDIOC_DBG_S_REGISTER    _IOW('V', 79, struct v4l2_dbg_register)
 #define        VIDIOC_DBG_G_REGISTER   _IOWR('V', 80, struct v4l2_dbg_register)
 
 #define VIDIOC_S_HW_FREQ_SEEK   _IOW('V', 82, struct v4l2_hw_freq_seek)
-
 #define        VIDIOC_S_DV_TIMINGS     _IOWR('V', 87, struct v4l2_dv_timings)
 #define        VIDIOC_G_DV_TIMINGS     _IOWR('V', 88, struct v4l2_dv_timings)
 #define        VIDIOC_DQEVENT           _IOR('V', 89, struct v4l2_event)
 #define        VIDIOC_SUBSCRIBE_EVENT   _IOW('V', 90, struct v4l2_event_subscription)
 #define        VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 91, struct v4l2_event_subscription)
-
-/* Experimental, the below two ioctls may change over the next couple of kernel
-   versions */
 #define VIDIOC_CREATE_BUFS     _IOWR('V', 92, struct v4l2_create_buffers)
 #define VIDIOC_PREPARE_BUF     _IOWR('V', 93, struct v4l2_buffer)
-
-/* Experimental selection API */
 #define VIDIOC_G_SELECTION     _IOWR('V', 94, struct v4l2_selection)
 #define VIDIOC_S_SELECTION     _IOWR('V', 95, struct v4l2_selection)
-
-/* Experimental, these two ioctls may change over the next couple of kernel
-   versions. */
 #define VIDIOC_DECODER_CMD     _IOWR('V', 96, struct v4l2_decoder_cmd)
 #define VIDIOC_TRY_DECODER_CMD _IOWR('V', 97, struct v4l2_decoder_cmd)
-
-/* Experimental, these three ioctls may change over the next couple of kernel
-   versions. */
 #define VIDIOC_ENUM_DV_TIMINGS  _IOWR('V', 98, struct v4l2_enum_dv_timings)
 #define VIDIOC_QUERY_DV_TIMINGS  _IOR('V', 99, struct v4l2_dv_timings)
 #define VIDIOC_DV_TIMINGS_CAP   _IOWR('V', 100, struct v4l2_dv_timings_cap)
-
-/* Experimental, this ioctl may change over the next couple of kernel
-   versions. */
 #define VIDIOC_ENUM_FREQ_BANDS _IOWR('V', 101, struct v4l2_frequency_band)
 
-/* Experimental, meant for debugging, testing and internal use.
-   Never use these in applications! */
+/*
+ * Experimental, meant for debugging, testing and internal use.
+ * Never use this in applications!
+ */
 #define VIDIOC_DBG_G_CHIP_INFO  _IOWR('V', 102, struct v4l2_dbg_chip_info)
 
 #define VIDIOC_QUERY_EXT_CTRL  _IOWR('V', 103, struct v4l2_query_ext_ctrl)
index 48001d7..ad440d6 100644 (file)
@@ -2,4 +2,4 @@
 
 obj-$(CONFIG_SAMPLES)  += kobject/ kprobes/ trace_events/ livepatch/ \
                           hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \
-                          configfs/
+                          configfs/ v4l/
diff --git a/samples/v4l/Makefile b/samples/v4l/Makefile
new file mode 100644 (file)
index 0000000..65a351d
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_VIDEO_PCI_SKELETON) := v4l2-pci-skeleton.o
diff --git a/samples/v4l/v4l2-pci-skeleton.c b/samples/v4l/v4l2-pci-skeleton.c
new file mode 100644 (file)
index 0000000..a55cf94
--- /dev/null
@@ -0,0 +1,922 @@
+/*
+ * This is a V4L2 PCI Skeleton Driver. It gives an initial skeleton source
+ * for use with other PCI drivers.
+ *
+ * This skeleton PCI driver assumes that the card has an S-Video connector as
+ * input 0 and an HDMI connector as input 1.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/mutex.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-dma-contig.h>
+
+MODULE_DESCRIPTION("V4L2 PCI Skeleton Driver");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL v2");
+
+/**
+ * struct skeleton - All internal data for one instance of device
+ * @pdev: PCI device
+ * @v4l2_dev: top-level v4l2 device struct
+ * @vdev: video node structure
+ * @ctrl_handler: control handler structure
+ * @lock: ioctl serialization mutex
+ * @std: current SDTV standard
+ * @timings: current HDTV timings
+ * @format: current pix format
+ * @input: current video input (0 = SDTV, 1 = HDTV)
+ * @queue: vb2 video capture queue
+ * @alloc_ctx: vb2 contiguous DMA context
+ * @qlock: spinlock controlling access to buf_list and sequence
+ * @buf_list: list of buffers queued for DMA
+ * @sequence: frame sequence counter
+ */
+struct skeleton {
+       struct pci_dev *pdev;
+       struct v4l2_device v4l2_dev;
+       struct video_device vdev;
+       struct v4l2_ctrl_handler ctrl_handler;
+       struct mutex lock;
+       v4l2_std_id std;
+       struct v4l2_dv_timings timings;
+       struct v4l2_pix_format format;
+       unsigned input;
+
+       struct vb2_queue queue;
+       struct vb2_alloc_ctx *alloc_ctx;
+
+       spinlock_t qlock;
+       struct list_head buf_list;
+       unsigned field;
+       unsigned sequence;
+};
+
+struct skel_buffer {
+       struct vb2_buffer vb;
+       struct list_head list;
+};
+
+static inline struct skel_buffer *to_skel_buffer(struct vb2_buffer *vb2)
+{
+       return container_of(vb2, struct skel_buffer, vb);
+}
+
+static const struct pci_device_id skeleton_pci_tbl[] = {
+       /* { PCI_DEVICE(PCI_VENDOR_ID_, PCI_DEVICE_ID_) }, */
+       { 0, }
+};
+MODULE_DEVICE_TABLE(pci, skeleton_pci_tbl);
+
+/*
+ * HDTV: this structure has the capabilities of the HDTV receiver.
+ * It is used to constrain the huge list of possible formats based
+ * upon the hardware capabilities.
+ */
+static const struct v4l2_dv_timings_cap skel_timings_cap = {
+       .type = V4L2_DV_BT_656_1120,
+       /* keep this initialization for compatibility with GCC < 4.4.6 */
+       .reserved = { 0 },
+       V4L2_INIT_BT_TIMINGS(
+               720, 1920,              /* min/max width */
+               480, 1080,              /* min/max height */
+               27000000, 74250000,     /* min/max pixelclock*/
+               V4L2_DV_BT_STD_CEA861,  /* Supported standards */
+               /* capabilities */
+               V4L2_DV_BT_CAP_INTERLACED | V4L2_DV_BT_CAP_PROGRESSIVE
+       )
+};
+
+/*
+ * Supported SDTV standards. This does the same job as skel_timings_cap, but
+ * for standard TV formats.
+ */
+#define SKEL_TVNORMS V4L2_STD_ALL
+
+/*
+ * Interrupt handler: typically interrupts happen after a new frame has been
+ * captured. It is the job of the handler to remove the new frame from the
+ * internal list and give it back to the vb2 framework, updating the sequence
+ * counter, field and timestamp at the same time.
+ */
+static irqreturn_t skeleton_irq(int irq, void *dev_id)
+{
+#ifdef TODO
+       struct skeleton *skel = dev_id;
+
+       /* handle interrupt */
+
+       /* Once a new frame has been captured, mark it as done like this: */
+       if (captured_new_frame) {
+               ...
+               spin_lock(&skel->qlock);
+               list_del(&new_buf->list);
+               spin_unlock(&skel->qlock);
+               v4l2_get_timestamp(&new_buf->vb.v4l2_buf.timestamp);
+               new_buf->vb.v4l2_buf.sequence = skel->sequence++;
+               new_buf->vb.v4l2_buf.field = skel->field;
+               if (skel->format.field == V4L2_FIELD_ALTERNATE) {
+                       if (skel->field == V4L2_FIELD_BOTTOM)
+                               skel->field = V4L2_FIELD_TOP;
+                       else if (skel->field == V4L2_FIELD_TOP)
+                               skel->field = V4L2_FIELD_BOTTOM;
+               }
+               vb2_buffer_done(&new_buf->vb, VB2_BUF_STATE_DONE);
+       }
+#endif
+       return IRQ_HANDLED;
+}
+
+/*
+ * Setup the constraints of the queue: besides setting the number of planes
+ * per buffer and the size and allocation context of each plane, it also
+ * checks if sufficient buffers have been allocated. Usually 3 is a good
+ * minimum number: many DMA engines need a minimum of 2 buffers in the
+ * queue and you need to have another available for userspace processing.
+ */
+static int queue_setup(struct vb2_queue *vq,
+                      unsigned int *nbuffers, unsigned int *nplanes,
+                      unsigned int sizes[], void *alloc_ctxs[])
+{
+       struct skeleton *skel = vb2_get_drv_priv(vq);
+
+       skel->field = skel->format.field;
+       if (skel->field == V4L2_FIELD_ALTERNATE) {
+               /*
+                * You cannot use read() with FIELD_ALTERNATE since the field
+                * information (TOP/BOTTOM) cannot be passed back to the user.
+                */
+               if (vb2_fileio_is_active(vq))
+                       return -EINVAL;
+               skel->field = V4L2_FIELD_TOP;
+       }
+
+       if (vq->num_buffers + *nbuffers < 3)
+               *nbuffers = 3 - vq->num_buffers;
+       alloc_ctxs[0] = skel->alloc_ctx;
+
+       if (*nplanes)
+               return sizes[0] < skel->format.sizeimage ? -EINVAL : 0;
+       *nplanes = 1;
+       sizes[0] = skel->format.sizeimage;
+       return 0;
+}
+
+/*
+ * Prepare the buffer for queueing to the DMA engine: check and set the
+ * payload size.
+ */
+static int buffer_prepare(struct vb2_buffer *vb)
+{
+       struct skeleton *skel = vb2_get_drv_priv(vb->vb2_queue);
+       unsigned long size = skel->format.sizeimage;
+
+       if (vb2_plane_size(vb, 0) < size) {
+               dev_err(&skel->pdev->dev, "buffer too small (%lu < %lu)\n",
+                        vb2_plane_size(vb, 0), size);
+               return -EINVAL;
+       }
+
+       vb2_set_plane_payload(vb, 0, size);
+       return 0;
+}
+
+/*
+ * Queue this buffer to the DMA engine.
+ */
+static void buffer_queue(struct vb2_buffer *vb)
+{
+       struct skeleton *skel = vb2_get_drv_priv(vb->vb2_queue);
+       struct skel_buffer *buf = to_skel_buffer(vb);
+       unsigned long flags;
+
+       spin_lock_irqsave(&skel->qlock, flags);
+       list_add_tail(&buf->list, &skel->buf_list);
+
+       /* TODO: Update any DMA pointers if necessary */
+
+       spin_unlock_irqrestore(&skel->qlock, flags);
+}
+
+static void return_all_buffers(struct skeleton *skel,
+                              enum vb2_buffer_state state)
+{
+       struct skel_buffer *buf, *node;
+       unsigned long flags;
+
+       spin_lock_irqsave(&skel->qlock, flags);
+       list_for_each_entry_safe(buf, node, &skel->buf_list, list) {
+               vb2_buffer_done(&buf->vb, state);
+               list_del(&buf->list);
+       }
+       spin_unlock_irqrestore(&skel->qlock, flags);
+}
+
+/*
+ * Start streaming. First check if the minimum number of buffers have been
+ * queued. If not, then return -ENOBUFS and the vb2 framework will call
+ * this function again the next time a buffer has been queued until enough
+ * buffers are available to actually start the DMA engine.
+ */
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+       struct skeleton *skel = vb2_get_drv_priv(vq);
+       int ret = 0;
+
+       skel->sequence = 0;
+
+       /* TODO: start DMA */
+
+       if (ret) {
+               /*
+                * In case of an error, return all active buffers to the
+                * QUEUED state
+                */
+               return_all_buffers(skel, VB2_BUF_STATE_QUEUED);
+       }
+       return ret;
+}
+
+/*
+ * Stop the DMA engine. Any remaining buffers in the DMA queue are dequeued
+ * and passed on to the vb2 framework marked as STATE_ERROR.
+ */
+static void stop_streaming(struct vb2_queue *vq)
+{
+       struct skeleton *skel = vb2_get_drv_priv(vq);
+
+       /* TODO: stop DMA */
+
+       /* Release all active buffers */
+       return_all_buffers(skel, VB2_BUF_STATE_ERROR);
+}
+
+/*
+ * The vb2 queue ops. Note that since q->lock is set we can use the standard
+ * vb2_ops_wait_prepare/finish helper functions. If q->lock would be NULL,
+ * then this driver would have to provide these ops.
+ */
+static struct vb2_ops skel_qops = {
+       .queue_setup            = queue_setup,
+       .buf_prepare            = buffer_prepare,
+       .buf_queue              = buffer_queue,
+       .start_streaming        = start_streaming,
+       .stop_streaming         = stop_streaming,
+       .wait_prepare           = vb2_ops_wait_prepare,
+       .wait_finish            = vb2_ops_wait_finish,
+};
+
+/*
+ * Required ioctl querycap. Note that the version field is prefilled with
+ * the version of the kernel.
+ */
+static int skeleton_querycap(struct file *file, void *priv,
+                            struct v4l2_capability *cap)
+{
+       struct skeleton *skel = video_drvdata(file);
+
+       strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
+       strlcpy(cap->card, "V4L2 PCI Skeleton", sizeof(cap->card));
+       snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
+                pci_name(skel->pdev));
+       return 0;
+}
+
+/*
+ * Helper function to check and correct struct v4l2_pix_format. It's used
+ * not only in VIDIOC_TRY/S_FMT, but also elsewhere if changes to the SDTV
+ * standard, HDTV timings or the video input would require updating the
+ * current format.
+ */
+static void skeleton_fill_pix_format(struct skeleton *skel,
+                                    struct v4l2_pix_format *pix)
+{
+       pix->pixelformat = V4L2_PIX_FMT_YUYV;
+       if (skel->input == 0) {
+               /* S-Video input */
+               pix->width = 720;
+               pix->height = (skel->std & V4L2_STD_525_60) ? 480 : 576;
+               pix->field = V4L2_FIELD_INTERLACED;
+               pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+       } else {
+               /* HDMI input */
+               pix->width = skel->timings.bt.width;
+               pix->height = skel->timings.bt.height;
+               if (skel->timings.bt.interlaced) {
+                       pix->field = V4L2_FIELD_ALTERNATE;
+                       pix->height /= 2;
+               } else {
+                       pix->field = V4L2_FIELD_NONE;
+               }
+               pix->colorspace = V4L2_COLORSPACE_REC709;
+       }
+
+       /*
+        * The YUYV format is four bytes for every two pixels, so bytesperline
+        * is width * 2.
+        */
+       pix->bytesperline = pix->width * 2;
+       pix->sizeimage = pix->bytesperline * pix->height;
+       pix->priv = 0;
+}
+
+static int skeleton_try_fmt_vid_cap(struct file *file, void *priv,
+                                   struct v4l2_format *f)
+{
+       struct skeleton *skel = video_drvdata(file);
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+
+       /*
+        * Due to historical reasons providing try_fmt with an unsupported
+        * pixelformat will return -EINVAL for video receivers. Webcam drivers,
+        * however, will silently correct the pixelformat. Some video capture
+        * applications rely on this behavior...
+        */
+       if (pix->pixelformat != V4L2_PIX_FMT_YUYV)
+               return -EINVAL;
+       skeleton_fill_pix_format(skel, pix);
+       return 0;
+}
+
+static int skeleton_s_fmt_vid_cap(struct file *file, void *priv,
+                                 struct v4l2_format *f)
+{
+       struct skeleton *skel = video_drvdata(file);
+       int ret;
+
+       ret = skeleton_try_fmt_vid_cap(file, priv, f);
+       if (ret)
+               return ret;
+
+       /*
+        * It is not allowed to change the format while buffers for use with
+        * streaming have already been allocated.
+        */
+       if (vb2_is_busy(&skel->queue))
+               return -EBUSY;
+
+       /* TODO: change format */
+       skel->format = f->fmt.pix;
+       return 0;
+}
+
+static int skeleton_g_fmt_vid_cap(struct file *file, void *priv,
+                                 struct v4l2_format *f)
+{
+       struct skeleton *skel = video_drvdata(file);
+
+       f->fmt.pix = skel->format;
+       return 0;
+}
+
+static int skeleton_enum_fmt_vid_cap(struct file *file, void *priv,
+                                    struct v4l2_fmtdesc *f)
+{
+       if (f->index != 0)
+               return -EINVAL;
+
+       f->pixelformat = V4L2_PIX_FMT_YUYV;
+       return 0;
+}
+
+static int skeleton_s_std(struct file *file, void *priv, v4l2_std_id std)
+{
+       struct skeleton *skel = video_drvdata(file);
+
+       /* S_STD is not supported on the HDMI input */
+       if (skel->input)
+               return -ENODATA;
+
+       /*
+        * No change, so just return. Some applications call S_STD again after
+        * the buffers for streaming have been set up, so we have to allow for
+        * this behavior.
+        */
+       if (std == skel->std)
+               return 0;
+
+       /*
+        * Changing the standard implies a format change, which is not allowed
+        * while buffers for use with streaming have already been allocated.
+        */
+       if (vb2_is_busy(&skel->queue))
+               return -EBUSY;
+
+       /* TODO: handle changing std */
+
+       skel->std = std;
+
+       /* Update the internal format */
+       skeleton_fill_pix_format(skel, &skel->format);
+       return 0;
+}
+
+static int skeleton_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+       struct skeleton *skel = video_drvdata(file);
+
+       /* G_STD is not supported on the HDMI input */
+       if (skel->input)
+               return -ENODATA;
+
+       *std = skel->std;
+       return 0;
+}
+
+/*
+ * Query the current standard as seen by the hardware. This function shall
+ * never actually change the standard, it just detects and reports.
+ * The framework will initially set *std to tvnorms (i.e. the set of
+ * supported standards by this input), and this function should just AND
+ * this value. If there is no signal, then *std should be set to 0.
+ */
+static int skeleton_querystd(struct file *file, void *priv, v4l2_std_id *std)
+{
+       struct skeleton *skel = video_drvdata(file);
+
+       /* QUERY_STD is not supported on the HDMI input */
+       if (skel->input)
+               return -ENODATA;
+
+#ifdef TODO
+       /*
+        * Query currently seen standard. Initial value of *std is
+        * V4L2_STD_ALL. This function should look something like this:
+        */
+       get_signal_info();
+       if (no_signal) {
+               *std = 0;
+               return 0;
+       }
+       /* Use signal information to reduce the number of possible standards */
+       if (signal_has_525_lines)
+               *std &= V4L2_STD_525_60;
+       else
+               *std &= V4L2_STD_625_50;
+#endif
+       return 0;
+}
+
+static int skeleton_s_dv_timings(struct file *file, void *_fh,
+                                struct v4l2_dv_timings *timings)
+{
+       struct skeleton *skel = video_drvdata(file);
+
+       /* S_DV_TIMINGS is not supported on the S-Video input */
+       if (skel->input == 0)
+               return -ENODATA;
+
+       /* Quick sanity check */
+       if (!v4l2_valid_dv_timings(timings, &skel_timings_cap, NULL, NULL))
+               return -EINVAL;
+
+       /* Check if the timings are part of the CEA-861 timings. */
+       if (!v4l2_find_dv_timings_cap(timings, &skel_timings_cap,
+                                     0, NULL, NULL))
+               return -EINVAL;
+
+       /* Return 0 if the new timings are the same as the current timings. */
+       if (v4l2_match_dv_timings(timings, &skel->timings, 0, false))
+               return 0;
+
+       /*
+        * Changing the timings implies a format change, which is not allowed
+        * while buffers for use with streaming have already been allocated.
+        */
+       if (vb2_is_busy(&skel->queue))
+               return -EBUSY;
+
+       /* TODO: Configure new timings */
+
+       /* Save timings */
+       skel->timings = *timings;
+
+       /* Update the internal format */
+       skeleton_fill_pix_format(skel, &skel->format);
+       return 0;
+}
+
+static int skeleton_g_dv_timings(struct file *file, void *_fh,
+                                struct v4l2_dv_timings *timings)
+{
+       struct skeleton *skel = video_drvdata(file);
+
+       /* G_DV_TIMINGS is not supported on the S-Video input */
+       if (skel->input == 0)
+               return -ENODATA;
+
+       *timings = skel->timings;
+       return 0;
+}
+
+static int skeleton_enum_dv_timings(struct file *file, void *_fh,
+                                   struct v4l2_enum_dv_timings *timings)
+{
+       struct skeleton *skel = video_drvdata(file);
+
+       /* ENUM_DV_TIMINGS is not supported on the S-Video input */
+       if (skel->input == 0)
+               return -ENODATA;
+
+       return v4l2_enum_dv_timings_cap(timings, &skel_timings_cap,
+                                       NULL, NULL);
+}
+
+/*
+ * Query the current timings as seen by the hardware. This function shall
+ * never actually change the timings, it just detects and reports.
+ * If no signal is detected, then return -ENOLINK. If the hardware cannot
+ * lock to the signal, then return -ENOLCK. If the signal is out of range
+ * of the capabilities of the system (e.g., it is possible that the receiver
+ * can lock but that the DMA engine it is connected to cannot handle
+ * pixelclocks above a certain frequency), then -ERANGE is returned.
+ */
+static int skeleton_query_dv_timings(struct file *file, void *_fh,
+                                    struct v4l2_dv_timings *timings)
+{
+       struct skeleton *skel = video_drvdata(file);
+
+       /* QUERY_DV_TIMINGS is not supported on the S-Video input */
+       if (skel->input == 0)
+               return -ENODATA;
+
+#ifdef TODO
+       /*
+        * Query currently seen timings. This function should look
+        * something like this:
+        */
+       detect_timings();
+       if (no_signal)
+               return -ENOLINK;
+       if (cannot_lock_to_signal)
+               return -ENOLCK;
+       if (signal_out_of_range_of_capabilities)
+               return -ERANGE;
+
+       /* Useful for debugging */
+       v4l2_print_dv_timings(skel->v4l2_dev.name, "query_dv_timings:",
+                       timings, true);
+#endif
+       return 0;
+}
+
+static int skeleton_dv_timings_cap(struct file *file, void *fh,
+                                  struct v4l2_dv_timings_cap *cap)
+{
+       struct skeleton *skel = video_drvdata(file);
+
+       /* DV_TIMINGS_CAP is not supported on the S-Video input */
+       if (skel->input == 0)
+               return -ENODATA;
+       *cap = skel_timings_cap;
+       return 0;
+}
+
+static int skeleton_enum_input(struct file *file, void *priv,
+                              struct v4l2_input *i)
+{
+       if (i->index > 1)
+               return -EINVAL;
+
+       i->type = V4L2_INPUT_TYPE_CAMERA;
+       if (i->index == 0) {
+               i->std = SKEL_TVNORMS;
+               strlcpy(i->name, "S-Video", sizeof(i->name));
+               i->capabilities = V4L2_IN_CAP_STD;
+       } else {
+               i->std = 0;
+               strlcpy(i->name, "HDMI", sizeof(i->name));
+               i->capabilities = V4L2_IN_CAP_DV_TIMINGS;
+       }
+       return 0;
+}
+
+static int skeleton_s_input(struct file *file, void *priv, unsigned int i)
+{
+       struct skeleton *skel = video_drvdata(file);
+
+       if (i > 1)
+               return -EINVAL;
+
+       /*
+        * Changing the input implies a format change, which is not allowed
+        * while buffers for use with streaming have already been allocated.
+        */
+       if (vb2_is_busy(&skel->queue))
+               return -EBUSY;
+
+       skel->input = i;
+       /*
+        * Update tvnorms. The tvnorms value is used by the core to implement
+        * VIDIOC_ENUMSTD so it has to be correct. If tvnorms == 0, then
+        * ENUMSTD will return -ENODATA.
+        */
+       skel->vdev.tvnorms = i ? 0 : SKEL_TVNORMS;
+
+       /* Update the internal format */
+       skeleton_fill_pix_format(skel, &skel->format);
+       return 0;
+}
+
+static int skeleton_g_input(struct file *file, void *priv, unsigned int *i)
+{
+       struct skeleton *skel = video_drvdata(file);
+
+       *i = skel->input;
+       return 0;
+}
+
+/* The control handler. */
+static int skeleton_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       /*struct skeleton *skel =
+               container_of(ctrl->handler, struct skeleton, ctrl_handler);*/
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               /* TODO: set brightness to ctrl->val */
+               break;
+       case V4L2_CID_CONTRAST:
+               /* TODO: set contrast to ctrl->val */
+               break;
+       case V4L2_CID_SATURATION:
+               /* TODO: set saturation to ctrl->val */
+               break;
+       case V4L2_CID_HUE:
+               /* TODO: set hue to ctrl->val */
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* ------------------------------------------------------------------
+       File operations for the device
+   ------------------------------------------------------------------*/
+
+static const struct v4l2_ctrl_ops skel_ctrl_ops = {
+       .s_ctrl = skeleton_s_ctrl,
+};
+
+/*
+ * The set of all supported ioctls. Note that all the streaming ioctls
+ * use the vb2 helper functions that take care of all the locking and
+ * that also do ownership tracking (i.e. only the filehandle that requested
+ * the buffers can call the streaming ioctls, all other filehandles will
+ * receive -EBUSY if they attempt to call the same streaming ioctls).
+ *
+ * The last three ioctls also use standard helper functions: these implement
+ * standard behavior for drivers with controls.
+ */
+static const struct v4l2_ioctl_ops skel_ioctl_ops = {
+       .vidioc_querycap = skeleton_querycap,
+       .vidioc_try_fmt_vid_cap = skeleton_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap = skeleton_s_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap = skeleton_g_fmt_vid_cap,
+       .vidioc_enum_fmt_vid_cap = skeleton_enum_fmt_vid_cap,
+
+       .vidioc_g_std = skeleton_g_std,
+       .vidioc_s_std = skeleton_s_std,
+       .vidioc_querystd = skeleton_querystd,
+
+       .vidioc_s_dv_timings = skeleton_s_dv_timings,
+       .vidioc_g_dv_timings = skeleton_g_dv_timings,
+       .vidioc_enum_dv_timings = skeleton_enum_dv_timings,
+       .vidioc_query_dv_timings = skeleton_query_dv_timings,
+       .vidioc_dv_timings_cap = skeleton_dv_timings_cap,
+
+       .vidioc_enum_input = skeleton_enum_input,
+       .vidioc_g_input = skeleton_g_input,
+       .vidioc_s_input = skeleton_s_input,
+
+       .vidioc_reqbufs = vb2_ioctl_reqbufs,
+       .vidioc_create_bufs = vb2_ioctl_create_bufs,
+       .vidioc_querybuf = vb2_ioctl_querybuf,
+       .vidioc_qbuf = vb2_ioctl_qbuf,
+       .vidioc_dqbuf = vb2_ioctl_dqbuf,
+       .vidioc_expbuf = vb2_ioctl_expbuf,
+       .vidioc_streamon = vb2_ioctl_streamon,
+       .vidioc_streamoff = vb2_ioctl_streamoff,
+
+       .vidioc_log_status = v4l2_ctrl_log_status,
+       .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+/*
+ * The set of file operations. Note that all these ops are standard core
+ * helper functions.
+ */
+static const struct v4l2_file_operations skel_fops = {
+       .owner = THIS_MODULE,
+       .open = v4l2_fh_open,
+       .release = vb2_fop_release,
+       .unlocked_ioctl = video_ioctl2,
+       .read = vb2_fop_read,
+       .mmap = vb2_fop_mmap,
+       .poll = vb2_fop_poll,
+};
+
+/*
+ * The initial setup of this device instance. Note that the initial state of
+ * the driver should be complete. So the initial format, standard, timings
+ * and video input should all be initialized to some reasonable value.
+ */
+static int skeleton_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       /* The initial timings are chosen to be 720p60. */
+       static const struct v4l2_dv_timings timings_def =
+               V4L2_DV_BT_CEA_1280X720P60;
+       struct skeleton *skel;
+       struct video_device *vdev;
+       struct v4l2_ctrl_handler *hdl;
+       struct vb2_queue *q;
+       int ret;
+
+       /* Enable PCI */
+       ret = pci_enable_device(pdev);
+       if (ret)
+               return ret;
+       ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+       if (ret) {
+               dev_err(&pdev->dev, "no suitable DMA available.\n");
+               goto disable_pci;
+       }
+
+       /* Allocate a new instance */
+       skel = devm_kzalloc(&pdev->dev, sizeof(struct skeleton), GFP_KERNEL);
+       if (!skel)
+               return -ENOMEM;
+
+       /* Allocate the interrupt */
+       ret = devm_request_irq(&pdev->dev, pdev->irq,
+                              skeleton_irq, 0, KBUILD_MODNAME, skel);
+       if (ret) {
+               dev_err(&pdev->dev, "request_irq failed\n");
+               goto disable_pci;
+       }
+       skel->pdev = pdev;
+
+       /* Fill in the initial format-related settings */
+       skel->timings = timings_def;
+       skel->std = V4L2_STD_625_50;
+       skeleton_fill_pix_format(skel, &skel->format);
+
+       /* Initialize the top-level structure */
+       ret = v4l2_device_register(&pdev->dev, &skel->v4l2_dev);
+       if (ret)
+               goto disable_pci;
+
+       mutex_init(&skel->lock);
+
+       /* Add the controls */
+       hdl = &skel->ctrl_handler;
+       v4l2_ctrl_handler_init(hdl, 4);
+       v4l2_ctrl_new_std(hdl, &skel_ctrl_ops,
+                         V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
+       v4l2_ctrl_new_std(hdl, &skel_ctrl_ops,
+                         V4L2_CID_CONTRAST, 0, 255, 1, 16);
+       v4l2_ctrl_new_std(hdl, &skel_ctrl_ops,
+                         V4L2_CID_SATURATION, 0, 255, 1, 127);
+       v4l2_ctrl_new_std(hdl, &skel_ctrl_ops,
+                         V4L2_CID_HUE, -128, 127, 1, 0);
+       if (hdl->error) {
+               ret = hdl->error;
+               goto free_hdl;
+       }
+       skel->v4l2_dev.ctrl_handler = hdl;
+
+       /* Initialize the vb2 queue */
+       q = &skel->queue;
+       q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
+       q->drv_priv = skel;
+       q->buf_struct_size = sizeof(struct skel_buffer);
+       q->ops = &skel_qops;
+       q->mem_ops = &vb2_dma_contig_memops;
+       q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+       /*
+        * Assume that this DMA engine needs to have at least two buffers
+        * available before it can be started. The start_streaming() op
+        * won't be called until at least this many buffers are queued up.
+        */
+       q->min_buffers_needed = 2;
+       /*
+        * The serialization lock for the streaming ioctls. This is the same
+        * as the main serialization lock, but if some of the non-streaming
+        * ioctls could take a long time to execute, then you might want to
+        * have a different lock here to prevent VIDIOC_DQBUF from being
+        * blocked while waiting for another action to finish. This is
+        * generally not needed for PCI devices, but USB devices usually do
+        * want a separate lock here.
+        */
+       q->lock = &skel->lock;
+       /*
+        * Since this driver can only do 32-bit DMA we must make sure that
+        * the vb2 core will allocate the buffers in 32-bit DMA memory.
+        */
+       q->gfp_flags = GFP_DMA32;
+       ret = vb2_queue_init(q);
+       if (ret)
+               goto free_hdl;
+
+       skel->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+       if (IS_ERR(skel->alloc_ctx)) {
+               dev_err(&pdev->dev, "Can't allocate buffer context");
+               ret = PTR_ERR(skel->alloc_ctx);
+               goto free_hdl;
+       }
+       INIT_LIST_HEAD(&skel->buf_list);
+       spin_lock_init(&skel->qlock);
+
+       /* Initialize the video_device structure */
+       vdev = &skel->vdev;
+       strlcpy(vdev->name, KBUILD_MODNAME, sizeof(vdev->name));
+       /*
+        * There is nothing to clean up, so release is set to an empty release
+        * function. The release callback must be non-NULL.
+        */
+       vdev->release = video_device_release_empty;
+       vdev->fops = &skel_fops,
+       vdev->ioctl_ops = &skel_ioctl_ops,
+       vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+                           V4L2_CAP_STREAMING;
+       /*
+        * The main serialization lock. All ioctls are serialized by this
+        * lock. Exception: if q->lock is set, then the streaming ioctls
+        * are serialized by that separate lock.
+        */
+       vdev->lock = &skel->lock;
+       vdev->queue = q;
+       vdev->v4l2_dev = &skel->v4l2_dev;
+       /* Supported SDTV standards, if any */
+       vdev->tvnorms = SKEL_TVNORMS;
+       video_set_drvdata(vdev, skel);
+
+       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       if (ret)
+               goto free_ctx;
+
+       dev_info(&pdev->dev, "V4L2 PCI Skeleton Driver loaded\n");
+       return 0;
+
+free_ctx:
+       vb2_dma_contig_cleanup_ctx(skel->alloc_ctx);
+free_hdl:
+       v4l2_ctrl_handler_free(&skel->ctrl_handler);
+       v4l2_device_unregister(&skel->v4l2_dev);
+disable_pci:
+       pci_disable_device(pdev);
+       return ret;
+}
+
+static void skeleton_remove(struct pci_dev *pdev)
+{
+       struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
+       struct skeleton *skel = container_of(v4l2_dev, struct skeleton, v4l2_dev);
+
+       video_unregister_device(&skel->vdev);
+       v4l2_ctrl_handler_free(&skel->ctrl_handler);
+       vb2_dma_contig_cleanup_ctx(skel->alloc_ctx);
+       v4l2_device_unregister(&skel->v4l2_dev);
+       pci_disable_device(skel->pdev);
+}
+
+static struct pci_driver skeleton_driver = {
+       .name = KBUILD_MODNAME,
+       .probe = skeleton_probe,
+       .remove = skeleton_remove,
+       .id_table = skeleton_pci_tbl,
+};
+
+module_pci_driver(skeleton_driver);