Merge branch 'v4l_for_2.6.35' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6

* 'v4l_for_2.6.35' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (534 commits)
  V4L/DVB (13554a): v4l: Use the video_drvdata function in drivers
  V4L/DVB: vivi and mem2mem_testdev need slab.h to build
  V4L/DVB: tm6000: bugfix image position
  V4L/DVB: IR/imon: remove dead IMON_KEY_RELEASE_OFFSET
  V4L/DVB: tm6000: README - add vbi
  V4L/DVB: Fix unlock logic at medusa_video_init
  V4L/DVB: fix dvb frontend lockup
  V4L/DVB: s2255drv: remove dead code
  V4L/DVB: s2255drv: return if vdev not found
  V4L/DVB: ov511: cleanup: remove unneeded null check
  V4L/DVB: media/mem2mem: dereferencing free memory
  V4L/DVB: media/IR: Add missing include file to rc-map.c
  V4L/DVB: dvb/stv6110x: cleanup error handling
  V4L/DVB: ngene: Add lgdt3303 and mt2131 deps to Kconfig
  V4L/DVB: ngene: start separating out DVB functions into separate file
  V4L/DVB: ngene: split out card specific code into a separate file
  V4L/DVB: ngene: split out i2c code into a separate file
  V4L/DVB: ngene: add initial support for digital side of Avermedia m780
  V4L/DVB: ngene: properly support boards where channel 0 isn't a TS input
  V4L-DVB: ngene: make sure that tuner headers are included
  ...
diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
index c725cb8..5d4d40f4 100644
--- a/Documentation/DocBook/media-entities.tmpl
+++ b/Documentation/DocBook/media-entities.tmpl
@@ -17,6 +17,7 @@
 <!ENTITY VIDIOC-DBG-G-REGISTER "<link linkend='vidioc-dbg-g-register'><constant>VIDIOC_DBG_G_REGISTER</constant></link>">
 <!ENTITY VIDIOC-DBG-S-REGISTER "<link linkend='vidioc-dbg-g-register'><constant>VIDIOC_DBG_S_REGISTER</constant></link>">
 <!ENTITY VIDIOC-DQBUF "<link linkend='vidioc-qbuf'><constant>VIDIOC_DQBUF</constant></link>">
+<!ENTITY VIDIOC-DQEVENT "<link linkend='vidioc-dqevent'><constant>VIDIOC_DQEVENT</constant></link>">
 <!ENTITY VIDIOC-ENCODER-CMD "<link linkend='vidioc-encoder-cmd'><constant>VIDIOC_ENCODER_CMD</constant></link>">
 <!ENTITY VIDIOC-ENUMAUDIO "<link linkend='vidioc-enumaudio'><constant>VIDIOC_ENUMAUDIO</constant></link>">
 <!ENTITY VIDIOC-ENUMAUDOUT "<link linkend='vidioc-enumaudioout'><constant>VIDIOC_ENUMAUDOUT</constant></link>">
@@ -60,6 +61,7 @@
 <!ENTITY VIDIOC-REQBUFS "<link linkend='vidioc-reqbufs'><constant>VIDIOC_REQBUFS</constant></link>">
 <!ENTITY VIDIOC-STREAMOFF "<link linkend='vidioc-streamon'><constant>VIDIOC_STREAMOFF</constant></link>">
 <!ENTITY VIDIOC-STREAMON "<link linkend='vidioc-streamon'><constant>VIDIOC_STREAMON</constant></link>">
+<!ENTITY VIDIOC-SUBSCRIBE-EVENT "<link linkend='vidioc-subscribe-event'><constant>VIDIOC_SUBSCRIBE_EVENT</constant></link>">
 <!ENTITY VIDIOC-S-AUDIO "<link linkend='vidioc-g-audio'><constant>VIDIOC_S_AUDIO</constant></link>">
 <!ENTITY VIDIOC-S-AUDOUT "<link linkend='vidioc-g-audioout'><constant>VIDIOC_S_AUDOUT</constant></link>">
 <!ENTITY VIDIOC-S-CROP "<link linkend='vidioc-g-crop'><constant>VIDIOC_S_CROP</constant></link>">
@@ -83,6 +85,7 @@
 <!ENTITY VIDIOC-TRY-ENCODER-CMD "<link linkend='vidioc-encoder-cmd'><constant>VIDIOC_TRY_ENCODER_CMD</constant></link>">
 <!ENTITY VIDIOC-TRY-EXT-CTRLS "<link linkend='vidioc-g-ext-ctrls'><constant>VIDIOC_TRY_EXT_CTRLS</constant></link>">
 <!ENTITY VIDIOC-TRY-FMT "<link linkend='vidioc-g-fmt'><constant>VIDIOC_TRY_FMT</constant></link>">
+<!ENTITY VIDIOC-UNSUBSCRIBE-EVENT "<link linkend='vidioc-subscribe-event'><constant>VIDIOC_UNSUBSCRIBE_EVENT</constant></link>">
 
 <!-- Types -->
 <!ENTITY v4l2-std-id "<link linkend='v4l2-std-id'>v4l2_std_id</link>">
@@ -141,6 +144,9 @@
 <!ENTITY v4l2-enc-idx "struct&nbsp;<link linkend='v4l2-enc-idx'>v4l2_enc_idx</link>">
 <!ENTITY v4l2-enc-idx-entry "struct&nbsp;<link linkend='v4l2-enc-idx-entry'>v4l2_enc_idx_entry</link>">
 <!ENTITY v4l2-encoder-cmd "struct&nbsp;<link linkend='v4l2-encoder-cmd'>v4l2_encoder_cmd</link>">
+<!ENTITY v4l2-event "struct&nbsp;<link linkend='v4l2-event'>v4l2_event</link>">
+<!ENTITY v4l2-event-subscription "struct&nbsp;<link linkend='v4l2-event-subscription'>v4l2_event_subscription</link>">
+<!ENTITY v4l2-event-vsync "struct&nbsp;<link linkend='v4l2-event-vsync'>v4l2_event_vsync</link>">
 <!ENTITY v4l2-ext-control "struct&nbsp;<link linkend='v4l2-ext-control'>v4l2_ext_control</link>">
 <!ENTITY v4l2-ext-controls "struct&nbsp;<link linkend='v4l2-ext-controls'>v4l2_ext_controls</link>">
 <!ENTITY v4l2-fmtdesc "struct&nbsp;<link linkend='v4l2-fmtdesc'>v4l2_fmtdesc</link>">
@@ -200,6 +206,7 @@
 <!ENTITY sub-controls SYSTEM "v4l/controls.xml">
 <!ENTITY sub-dev-capture SYSTEM "v4l/dev-capture.xml">
 <!ENTITY sub-dev-codec SYSTEM "v4l/dev-codec.xml">
+<!ENTITY sub-dev-event SYSTEM "v4l/dev-event.xml">
 <!ENTITY sub-dev-effect SYSTEM "v4l/dev-effect.xml">
 <!ENTITY sub-dev-osd SYSTEM "v4l/dev-osd.xml">
 <!ENTITY sub-dev-output SYSTEM "v4l/dev-output.xml">
@@ -292,6 +299,8 @@
 <!ENTITY sub-v4l2grab-c SYSTEM "v4l/v4l2grab.c.xml">
 <!ENTITY sub-videodev2-h SYSTEM "v4l/videodev2.h.xml">
 <!ENTITY sub-v4l2 SYSTEM "v4l/v4l2.xml">
+<!ENTITY sub-dqevent SYSTEM "v4l/vidioc-dqevent.xml">
+<!ENTITY sub-subscribe-event SYSTEM "v4l/vidioc-subscribe-event.xml">
 <!ENTITY sub-intro SYSTEM "dvb/intro.xml">
 <!ENTITY sub-frontend SYSTEM "dvb/frontend.xml">
 <!ENTITY sub-dvbproperty SYSTEM "dvb/dvbproperty.xml">
@@ -381,3 +390,5 @@
 <!ENTITY reqbufs SYSTEM "v4l/vidioc-reqbufs.xml">
 <!ENTITY s-hw-freq-seek SYSTEM "v4l/vidioc-s-hw-freq-seek.xml">
 <!ENTITY streamon SYSTEM "v4l/vidioc-streamon.xml">
+<!ENTITY dqevent SYSTEM "v4l/vidioc-dqevent.xml">
+<!ENTITY subscribe_event SYSTEM "v4l/vidioc-subscribe-event.xml">
diff --git a/Documentation/DocBook/v4l/compat.xml b/Documentation/DocBook/v4l/compat.xml
index b9dbdf9..b42b935 100644
--- a/Documentation/DocBook/v4l/compat.xml
+++ b/Documentation/DocBook/v4l/compat.xml
@@ -2332,15 +2332,26 @@
 	</listitem>
       </orderedlist>
     </section>
-   </section>
+    <section>
+      <title>V4L2 in Linux 2.6.34</title>
+      <orderedlist>
+	<listitem>
+	  <para>Added
+<constant>V4L2_CID_IRIS_ABSOLUTE</constant> and
+<constant>V4L2_CID_IRIS_RELATIVE</constant> controls to the
+	    <link linkend="camera-controls">Camera controls class</link>.
+	  </para>
+	</listitem>
+      </orderedlist>
+    </section>
 
-   <section id="other">
-     <title>Relation of V4L2 to other Linux multimedia APIs</title>
+    <section id="other">
+      <title>Relation of V4L2 to other Linux multimedia APIs</title>
 
-    <section id="xvideo">
-      <title>X Video Extension</title>
+      <section id="xvideo">
+        <title>X Video Extension</title>
 
-      <para>The X Video Extension (abbreviated XVideo or just Xv) is
+        <para>The X Video Extension (abbreviated XVideo or just Xv) is
 an extension of the X Window system, implemented for example by the
 XFree86 project. Its scope is similar to V4L2, an API to video capture
 and output devices for X clients. Xv allows applications to display
@@ -2351,7 +2362,7 @@
 extension available across many operating systems and
 architectures.</para>
 
-      <para>Because the driver is embedded into the X server Xv has a
+        <para>Because the driver is embedded into the X server Xv has a
 number of advantages over the V4L2 <link linkend="overlay">video
 overlay interface</link>. The driver can easily determine the overlay
 target, &ie; visible graphics memory or off-screen buffers for a
@@ -2360,16 +2371,16 @@
 video capture hardware, always in sync with drawing operations or
 windows moving or changing their stacking order.</para>
 
-      <para>To combine the advantages of Xv and V4L a special Xv
+        <para>To combine the advantages of Xv and V4L a special Xv
 driver exists in XFree86 and XOrg, just programming any overlay capable
 Video4Linux device it finds. To enable it
 <filename>/etc/X11/XF86Config</filename> must contain these lines:</para>
-      <para><screen>
+        <para><screen>
 Section "Module"
     Load "v4l"
 EndSection</screen></para>
 
-      <para>As of XFree86 4.2 this driver still supports only V4L
+        <para>As of XFree86 4.2 this driver still supports only V4L
 ioctls, however it should work just fine with all V4L2 devices through
 the V4L2 backward-compatibility layer. Since V4L2 permits multiple
 opens it is possible (if supported by the V4L2 driver) to capture
@@ -2377,83 +2388,84 @@
 simultaneous capturing and overlay are discussed in <xref
 	  linkend="overlay" /> apply.</para>
 
-      <para>Only marginally related to V4L2, XFree86 extended Xv to
+        <para>Only marginally related to V4L2, XFree86 extended Xv to
 support hardware YUV to RGB conversion and scaling for faster video
 playback, and added an interface to MPEG-2 decoding hardware. This API
 is useful to display images captured with V4L2 devices.</para>
-    </section>
+      </section>
 
-    <section>
-      <title>Digital Video</title>
+      <section>
+        <title>Digital Video</title>
 
-      <para>V4L2 does not support digital terrestrial, cable or
+        <para>V4L2 does not support digital terrestrial, cable or
 satellite broadcast. A separate project aiming at digital receivers
 exists. You can find its homepage at <ulink
 url="http://linuxtv.org">http://linuxtv.org</ulink>. The Linux DVB API
 has no connection to the V4L2 API except that drivers for hybrid
 hardware may support both.</para>
+      </section>
+
+      <section>
+        <title>Audio Interfaces</title>
+
+        <para>[to do - OSS/ALSA]</para>
+      </section>
     </section>
 
-    <section>
-      <title>Audio Interfaces</title>
+    <section id="experimental">
+      <title>Experimental API Elements</title>
 
-      <para>[to do - OSS/ALSA]</para>
-    </section>
-  </section>
-
-  <section id="experimental">
-    <title>Experimental API Elements</title>
-
-    <para>The following V4L2 API elements are currently experimental
+      <para>The following V4L2 API elements are currently experimental
 and may change in the future.</para>
 
-    <itemizedlist>
-      <listitem>
-	<para>Video Output Overlay (OSD) Interface, <xref
+      <itemizedlist>
+        <listitem>
+	  <para>Video Output Overlay (OSD) Interface, <xref
 	    linkend="osd" />.</para>
-      </listitem>
+        </listitem>
 	<listitem>
-	<para><constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY</constant>,
+	  <para><constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY</constant>,
 	&v4l2-buf-type;, <xref linkend="v4l2-buf-type" />.</para>
-      </listitem>
-      <listitem>
-	<para><constant>V4L2_CAP_VIDEO_OUTPUT_OVERLAY</constant>,
+        </listitem>
+        <listitem>
+	  <para><constant>V4L2_CAP_VIDEO_OUTPUT_OVERLAY</constant>,
 &VIDIOC-QUERYCAP; ioctl, <xref linkend="device-capabilities" />.</para>
-      </listitem>
-      <listitem>
-	<para>&VIDIOC-ENUM-FRAMESIZES; and
+        </listitem>
+        <listitem>
+	  <para>&VIDIOC-ENUM-FRAMESIZES; and
 &VIDIOC-ENUM-FRAMEINTERVALS; ioctls.</para>
-      </listitem>
-      <listitem>
-	<para>&VIDIOC-G-ENC-INDEX; ioctl.</para>
-      </listitem>
-      <listitem>
-	<para>&VIDIOC-ENCODER-CMD; and &VIDIOC-TRY-ENCODER-CMD;
+        </listitem>
+        <listitem>
+	  <para>&VIDIOC-G-ENC-INDEX; ioctl.</para>
+        </listitem>
+        <listitem>
+	  <para>&VIDIOC-ENCODER-CMD; and &VIDIOC-TRY-ENCODER-CMD;
 ioctls.</para>
-      </listitem>
-      <listitem>
-	<para>&VIDIOC-DBG-G-REGISTER; and &VIDIOC-DBG-S-REGISTER;
+        </listitem>
+        <listitem>
+	  <para>&VIDIOC-DBG-G-REGISTER; and &VIDIOC-DBG-S-REGISTER;
 ioctls.</para>
-      </listitem>
-      <listitem>
-	<para>&VIDIOC-DBG-G-CHIP-IDENT; ioctl.</para>
-      </listitem>
-    </itemizedlist>
-  </section>
+        </listitem>
+        <listitem>
+	  <para>&VIDIOC-DBG-G-CHIP-IDENT; ioctl.</para>
+        </listitem>
+      </itemizedlist>
+    </section>
 
-  <section id="obsolete">
-    <title>Obsolete API Elements</title>
+    <section id="obsolete">
+      <title>Obsolete API Elements</title>
 
-    <para>The following V4L2 API elements were superseded by new
+      <para>The following V4L2 API elements were superseded by new
 interfaces and should not be implemented in new drivers.</para>
 
-    <itemizedlist>
-      <listitem>
-	<para><constant>VIDIOC_G_MPEGCOMP</constant> and
+      <itemizedlist>
+        <listitem>
+	  <para><constant>VIDIOC_G_MPEGCOMP</constant> and
 <constant>VIDIOC_S_MPEGCOMP</constant> ioctls. Use Extended Controls,
 <xref linkend="extended-controls" />.</para>
-      </listitem>
-    </itemizedlist>
+        </listitem>
+      </itemizedlist>
+    </section>
   </section>
 
   <!--
diff --git a/Documentation/DocBook/v4l/controls.xml b/Documentation/DocBook/v4l/controls.xml
index f4645061..8408caa 100644
--- a/Documentation/DocBook/v4l/controls.xml
+++ b/Documentation/DocBook/v4l/controls.xml
@@ -267,6 +267,12 @@
 	    <entry>Chroma automatic gain control.</entry>
 	  </row>
 	  <row>
+	    <entry><constant>V4L2_CID_CHROMA_GAIN</constant></entry>
+	    <entry>integer</entry>
+	    <entry>Adjusts the Chroma gain control (for use when chroma AGC
+	    is disabled).</entry>
+	  </row>
+	  <row>
 	    <entry><constant>V4L2_CID_COLOR_KILLER</constant></entry>
 	    <entry>boolean</entry>
 	    <entry>Enable the color killer (&ie; force a black &amp; white image in case of a weak video signal).</entry>
@@ -277,8 +283,15 @@
 	    <entry>Selects a color effect. Possible values for
 <constant>enum v4l2_colorfx</constant> are:
 <constant>V4L2_COLORFX_NONE</constant> (0),
-<constant>V4L2_COLORFX_BW</constant> (1) and
-<constant>V4L2_COLORFX_SEPIA</constant> (2).</entry>
+<constant>V4L2_COLORFX_BW</constant> (1),
+<constant>V4L2_COLORFX_SEPIA</constant> (2),
+<constant>V4L2_COLORFX_NEGATIVE</constant> (3),
+<constant>V4L2_COLORFX_EMBOSS</constant> (4),
+<constant>V4L2_COLORFX_SKETCH</constant> (5),
+<constant>V4L2_COLORFX_SKY_BLUE</constant> (6),
+<constant>V4L2_COLORFX_GRASS_GREEN</constant> (7),
+<constant>V4L2_COLORFX_SKIN_WHITEN</constant> (8) and
+<constant>V4L2_COLORFX_VIVID</constant> (9).</entry>
 	  </row>
 	  <row>
 	    <entry><constant>V4L2_CID_ROTATE</constant></entry>
@@ -1825,6 +1838,25 @@
 	  <row><entry></entry></row>
 
 	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_IRIS_ABSOLUTE</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row><row><entry spanname="descr">This control sets the
+camera's aperture to the specified value. The unit is undefined.
+Larger values open the iris wider, smaller values close it.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_IRIS_RELATIVE</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row><row><entry spanname="descr">This control modifies the
+camera's aperture by the specified amount. The unit is undefined.
+Positive values open the iris one step further, negative values close
+it one step further. This is a write-only control.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
 	    <entry spanname="id"><constant>V4L2_CID_PRIVACY</constant>&nbsp;</entry>
 	    <entry>boolean</entry>
 	  </row><row><entry spanname="descr">Prevent video from being acquired
diff --git a/Documentation/DocBook/v4l/dev-event.xml b/Documentation/DocBook/v4l/dev-event.xml
new file mode 100644
index 0000000..be5a98f
--- /dev/null
+++ b/Documentation/DocBook/v4l/dev-event.xml
@@ -0,0 +1,31 @@
+  <title>Event Interface</title>
+
+  <para>The V4L2 event interface provides means for user to get
+  immediately notified on certain conditions taking place on a device.
+  This might include start of frame or loss of signal events, for
+  example.
+  </para>
+
+  <para>To receive events, the events the user is interested in first must
+  be subscribed using the &VIDIOC-SUBSCRIBE-EVENT; ioctl. Once an event is
+  subscribed, the events of subscribed types are dequeueable using the
+  &VIDIOC-DQEVENT; ioctl. Events may be unsubscribed using
+  VIDIOC_UNSUBSCRIBE_EVENT ioctl. The special event type V4L2_EVENT_ALL may
+  be used to unsubscribe all the events the driver supports.</para>
+
+  <para>The event subscriptions and event queues are specific to file
+  handles. Subscribing an event on one file handle does not affect
+  other file handles.
+  </para>
+
+  <para>The information on dequeueable events is obtained by using select or
+  poll system calls on video devices. The V4L2 events use POLLPRI events on
+  poll system call and exceptions on select system call.  </para>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/v4l/io.xml b/Documentation/DocBook/v4l/io.xml
index e870330..d424886 100644
--- a/Documentation/DocBook/v4l/io.xml
+++ b/Documentation/DocBook/v4l/io.xml
@@ -702,6 +702,16 @@
 state, in the application domain to say so.</entry>
 	  </row>
 	  <row>
+	    <entry><constant>V4L2_BUF_FLAG_ERROR</constant></entry>
+	    <entry>0x0040</entry>
+	    <entry>When this flag is set, the buffer has been dequeued
+	    successfully, although the data might have been corrupted.
+	    This is recoverable, streaming may continue as normal and
+	    the buffer may be reused normally.
+	    Drivers set this flag when the <constant>VIDIOC_DQBUF</constant>
+	    ioctl is called.</entry>
+	  </row>
+	  <row>
 	    <entry><constant>V4L2_BUF_FLAG_KEYFRAME</constant></entry>
 	    <entry>0x0008</entry>
 	  <entry>Drivers set or clear this flag when calling the
@@ -918,8 +928,8 @@
 
     <para>When the driver provides or accepts images field by field
 rather than interleaved, it is also important applications understand
-how the fields combine to frames. We distinguish between top and
-bottom fields, the <emphasis>spatial order</emphasis>: The first line
+how the fields combine to frames. We distinguish between top (aka odd) and
+bottom (aka even) fields, the <emphasis>spatial order</emphasis>: The first line
 of the top field is the first line of an interlaced frame, the first
 line of the bottom field is the second line of that frame.</para>
 
@@ -972,12 +982,12 @@
 	  <row>
 	    <entry><constant>V4L2_FIELD_TOP</constant></entry>
 	    <entry>2</entry>
-	    <entry>Images consist of the top field only.</entry>
+	    <entry>Images consist of the top (aka odd) field only.</entry>
 	  </row>
 	  <row>
 	    <entry><constant>V4L2_FIELD_BOTTOM</constant></entry>
 	    <entry>3</entry>
-	    <entry>Images consist of the bottom field only.
+	    <entry>Images consist of the bottom (aka even) field only.
 Applications may wish to prevent a device from capturing interlaced
 images because they will have "comb" or "feathering" artefacts around
 moving objects.</entry>
diff --git a/Documentation/DocBook/v4l/pixfmt.xml b/Documentation/DocBook/v4l/pixfmt.xml
index 885968d..c4ad0a8 100644
--- a/Documentation/DocBook/v4l/pixfmt.xml
+++ b/Documentation/DocBook/v4l/pixfmt.xml
@@ -792,6 +792,18 @@
 	    <entry>'YYUV'</entry>
 	    <entry>unknown</entry>
 	  </row>
+	  <row id="V4L2-PIX-FMT-Y4">
+	    <entry><constant>V4L2_PIX_FMT_Y4</constant></entry>
+	    <entry>'Y04 '</entry>
+	    <entry>Old 4-bit greyscale format. Only the least significant 4 bits of each byte are used,
+the other bits are set to 0.</entry>
+	  </row>
+	  <row id="V4L2-PIX-FMT-Y6">
+	    <entry><constant>V4L2_PIX_FMT_Y6</constant></entry>
+	    <entry>'Y06 '</entry>
+	    <entry>Old 6-bit greyscale format. Only the least significant 6 bits of each byte are used,
+the other bits are set to 0.</entry>
+	  </row>
 	</tbody>
       </tgroup>
     </table>
diff --git a/Documentation/DocBook/v4l/v4l2.xml b/Documentation/DocBook/v4l/v4l2.xml
index 060105a..9737243 100644
--- a/Documentation/DocBook/v4l/v4l2.xml
+++ b/Documentation/DocBook/v4l/v4l2.xml
@@ -401,6 +401,7 @@
     <section id="ttx"> &sub-dev-teletext; </section>
     <section id="radio"> &sub-dev-radio; </section>
     <section id="rds"> &sub-dev-rds; </section>
+    <section id="event"> &sub-dev-event; </section>
   </chapter>
 
   <chapter id="driver">
@@ -426,6 +427,7 @@
     &sub-cropcap;
     &sub-dbg-g-chip-ident;
     &sub-dbg-g-register;
+    &sub-dqevent;
     &sub-encoder-cmd;
     &sub-enumaudio;
     &sub-enumaudioout;
@@ -467,6 +469,7 @@
     &sub-reqbufs;
     &sub-s-hw-freq-seek;
     &sub-streamon;
+    &sub-subscribe-event;
     <!-- End of ioctls. -->
     &sub-mmap;
     &sub-munmap;
diff --git a/Documentation/DocBook/v4l/videodev2.h.xml b/Documentation/DocBook/v4l/videodev2.h.xml
index 0683259..865b06d 100644
--- a/Documentation/DocBook/v4l/videodev2.h.xml
+++ b/Documentation/DocBook/v4l/videodev2.h.xml
@@ -1018,6 +1018,13 @@
         V4L2_COLORFX_NONE       = 0,
         V4L2_COLORFX_BW         = 1,
         V4L2_COLORFX_SEPIA      = 2,
+        V4L2_COLORFX_NEGATIVE   = 3,
+        V4L2_COLORFX_EMBOSS     = 4,
+        V4L2_COLORFX_SKETCH     = 5,
+        V4L2_COLORFX_SKY_BLUE   = 6,
+        V4L2_COLORFX_GRASS_GREEN = 7,
+        V4L2_COLORFX_SKIN_WHITEN = 8,
+        V4L2_COLORFX_VIVID      = 9.
 };
 #define V4L2_CID_AUTOBRIGHTNESS                 (V4L2_CID_BASE+32)
 #define V4L2_CID_BAND_STOP_FILTER               (V4L2_CID_BASE+33)
@@ -1271,6 +1278,9 @@
 
 #define V4L2_CID_PRIVACY                        (V4L2_CID_CAMERA_CLASS_BASE+16)
 
+#define V4L2_CID_IRIS_ABSOLUTE                  (V4L2_CID_CAMERA_CLASS_BASE+17)
+#define V4L2_CID_IRIS_RELATIVE                  (V4L2_CID_CAMERA_CLASS_BASE+18)
+
 /* FM Modulator class control IDs */
 #define V4L2_CID_FM_TX_CLASS_BASE               (V4L2_CTRL_CLASS_FM_TX | 0x900)
 #define V4L2_CID_FM_TX_CLASS                    (V4L2_CTRL_CLASS_FM_TX | 1)
diff --git a/Documentation/DocBook/v4l/vidioc-dqevent.xml b/Documentation/DocBook/v4l/vidioc-dqevent.xml
new file mode 100644
index 0000000..4e0a7cc
--- /dev/null
+++ b/Documentation/DocBook/v4l/vidioc-dqevent.xml
@@ -0,0 +1,131 @@
+<refentry id="vidioc-dqevent">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_DQEVENT</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_DQEVENT</refname>
+    <refpurpose>Dequeue event</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+	<funcdef>int <function>ioctl</function></funcdef>
+	<paramdef>int <parameter>fd</parameter></paramdef>
+	<paramdef>int <parameter>request</parameter></paramdef>
+	<paramdef>struct v4l2_event
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+	<term><parameter>fd</parameter></term>
+	<listitem>
+	  <para>&fd;</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>request</parameter></term>
+	<listitem>
+	  <para>VIDIOC_DQEVENT</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>Dequeue an event from a video device. No input is required
+    for this ioctl. All the fields of the &v4l2-event; structure are
+    filled by the driver. The file handle will also receive exceptions
+    which the application may get by e.g. using the select system
+    call.</para>
+
+    <table frame="none" pgwide="1" id="v4l2-event">
+      <title>struct <structname>v4l2_event</structname></title>
+      <tgroup cols="4">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>type</structfield></entry>
+            <entry></entry>
+	    <entry>Type of the event.</entry>
+	  </row>
+	  <row>
+	    <entry>union</entry>
+	    <entry><structfield>u</structfield></entry>
+            <entry></entry>
+	    <entry></entry>
+	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry>&v4l2-event-vsync;</entry>
+            <entry><structfield>vsync</structfield></entry>
+	    <entry>Event data for event V4L2_EVENT_VSYNC.
+            </entry>
+	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry>__u8</entry>
+            <entry><structfield>data</structfield>[64]</entry>
+	    <entry>Event data. Defined by the event type. The union
+            should be used to define easily accessible type for
+            events.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>pending</structfield></entry>
+            <entry></entry>
+	    <entry>Number of pending events excluding this one.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>sequence</structfield></entry>
+            <entry></entry>
+	    <entry>Event sequence number. The sequence number is
+	    incremented for every subscribed event that takes place.
+	    If sequence numbers are not contiguous it means that
+	    events have been lost.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry>struct timespec</entry>
+	    <entry><structfield>timestamp</structfield></entry>
+            <entry></entry>
+	    <entry>Event timestamp.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>reserved</structfield>[9]</entry>
+            <entry></entry>
+	    <entry>Reserved for future extensions. Drivers must set
+	    the array to zero.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+  </refsect1>
+</refentry>
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/v4l/vidioc-enuminput.xml b/Documentation/DocBook/v4l/vidioc-enuminput.xml
index 71b868e..476fe1d 100644
--- a/Documentation/DocBook/v4l/vidioc-enuminput.xml
+++ b/Documentation/DocBook/v4l/vidioc-enuminput.xml
@@ -283,7 +283,7 @@
 	    <entry>This input supports setting DV presets by using VIDIOC_S_DV_PRESET.</entry>
 	  </row>
 	  <row>
-	    <entry><constant>V4L2_OUT_CAP_CUSTOM_TIMINGS</constant></entry>
+	    <entry><constant>V4L2_IN_CAP_CUSTOM_TIMINGS</constant></entry>
 	    <entry>0x00000002</entry>
 	    <entry>This input supports setting custom video timings by using VIDIOC_S_DV_TIMINGS.</entry>
 	  </row>
diff --git a/Documentation/DocBook/v4l/vidioc-qbuf.xml b/Documentation/DocBook/v4l/vidioc-qbuf.xml
index b843bd7..ab691eb 100644
--- a/Documentation/DocBook/v4l/vidioc-qbuf.xml
+++ b/Documentation/DocBook/v4l/vidioc-qbuf.xml
@@ -111,7 +111,11 @@
 and <structfield>reserved</structfield>
 fields of a &v4l2-buffer; as above, when <constant>VIDIOC_DQBUF</constant>
 is called with a pointer to this structure the driver fills the
-remaining fields or returns an error code.</para>
+remaining fields or returns an error code. The driver may also set
+<constant>V4L2_BUF_FLAG_ERROR</constant> in the <structfield>flags</structfield>
+field. It indicates a non-critical (recoverable) streaming error. In such case
+the application may continue as normal, but should be aware that data in the
+dequeued buffer might be corrupted.</para>
 
     <para>By default <constant>VIDIOC_DQBUF</constant> blocks when no
 buffer is in the outgoing queue. When the
@@ -158,7 +162,13 @@
 	  <para><constant>VIDIOC_DQBUF</constant> failed due to an
 internal error. Can also indicate temporary problems like signal
 loss. Note the driver might dequeue an (empty) buffer despite
-returning an error, or even stop capturing.</para>
+returning an error, or even stop capturing. Reusing such buffer may be unsafe
+though and its details (e.g. <structfield>index</structfield>) may not be
+returned either. It is recommended that drivers indicate recoverable errors
+by setting the <constant>V4L2_BUF_FLAG_ERROR</constant> and returning 0 instead.
+In that case the application should be able to safely reuse the buffer and
+continue streaming.
+	</para>
 	</listitem>
       </varlistentry>
     </variablelist>
diff --git a/Documentation/DocBook/v4l/vidioc-queryctrl.xml b/Documentation/DocBook/v4l/vidioc-queryctrl.xml
index 4876ff1..8e0e055 100644
--- a/Documentation/DocBook/v4l/vidioc-queryctrl.xml
+++ b/Documentation/DocBook/v4l/vidioc-queryctrl.xml
@@ -325,7 +325,7 @@
 	    <entry>n/a</entry>
 	    <entry>This is not a control. When
 <constant>VIDIOC_QUERYCTRL</constant> is called with a control ID
-equal to a control class code (see <xref linkend="ctrl-class" />), the
+equal to a control class code (see <xref linkend="ctrl-class" />) + 1, the
 ioctl returns the name of the control class and this control type.
 Older drivers which do not support this feature return an
 &EINVAL;.</entry>
diff --git a/Documentation/DocBook/v4l/vidioc-reqbufs.xml b/Documentation/DocBook/v4l/vidioc-reqbufs.xml
index 1c08163..69800ae 100644
--- a/Documentation/DocBook/v4l/vidioc-reqbufs.xml
+++ b/Documentation/DocBook/v4l/vidioc-reqbufs.xml
@@ -61,7 +61,7 @@
 They set the <structfield>type</structfield> field to the respective
 stream or buffer type, the <structfield>count</structfield> field to
 the desired number of buffers, <structfield>memory</structfield>
-must be set to the requested I/O method and the reserved array
+must be set to the requested I/O method and the <structfield>reserved</structfield> array
 must be zeroed. When the ioctl
 is called with a pointer to this structure the driver will attempt to allocate
 the requested number of buffers and it stores the actual number
diff --git a/Documentation/DocBook/v4l/vidioc-subscribe-event.xml b/Documentation/DocBook/v4l/vidioc-subscribe-event.xml
new file mode 100644
index 0000000..8b50179
--- /dev/null
+++ b/Documentation/DocBook/v4l/vidioc-subscribe-event.xml
@@ -0,0 +1,133 @@
+<refentry id="vidioc-subscribe-event">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT</refname>
+    <refpurpose>Subscribe or unsubscribe event</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+	<funcdef>int <function>ioctl</function></funcdef>
+	<paramdef>int <parameter>fd</parameter></paramdef>
+	<paramdef>int <parameter>request</parameter></paramdef>
+	<paramdef>struct v4l2_event_subscription
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+	<term><parameter>fd</parameter></term>
+	<listitem>
+	  <para>&fd;</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>request</parameter></term>
+	<listitem>
+	  <para>VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>Subscribe or unsubscribe V4L2 event. Subscribed events are
+    dequeued by using the &VIDIOC-DQEVENT; ioctl.</para>
+
+    <table frame="none" pgwide="1" id="v4l2-event-subscription">
+      <title>struct <structname>v4l2_event_subscription</structname></title>
+      <tgroup cols="3">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>type</structfield></entry>
+	    <entry>Type of the event.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>reserved</structfield>[7]</entry>
+	    <entry>Reserved for future extensions. Drivers and applications
+	    must set the array to zero.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="event-type">
+      <title>Event Types</title>
+      <tgroup cols="3">
+	&cs-def;
+	<tbody valign="top">
+	  <row>
+	    <entry><constant>V4L2_EVENT_ALL</constant></entry>
+	    <entry>0</entry>
+	    <entry>All events. V4L2_EVENT_ALL is valid only for
+	    VIDIOC_UNSUBSCRIBE_EVENT for unsubscribing all events at once.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_EVENT_VSYNC</constant></entry>
+	    <entry>1</entry>
+	    <entry>This event is triggered on the vertical sync.
+	    This event has &v4l2-event-vsync; associated with it.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_EVENT_EOS</constant></entry>
+	    <entry>2</entry>
+	    <entry>This event is triggered when the end of a stream is reached.
+	    This is typically used with MPEG decoders to report to the application
+	    when the last of the MPEG stream has been decoded.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_EVENT_PRIVATE_START</constant></entry>
+	    <entry>0x08000000</entry>
+	    <entry>Base event number for driver-private events.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="v4l2-event-vsync">
+      <title>struct <structname>v4l2_event_vsync</structname></title>
+      <tgroup cols="3">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u8</entry>
+	    <entry><structfield>field</structfield></entry>
+	    <entry>The upcoming field. See &v4l2-field;.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+  </refsect1>
+</refentry>
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv
index f11c583..4739d56 100644
--- a/Documentation/video4linux/CARDLIST.bttv
+++ b/Documentation/video4linux/CARDLIST.bttv
@@ -100,7 +100,7 @@
  99 -> AD-TVK503
 100 -> Hercules Smart TV Stereo
 101 -> Pace TV & Radio Card
-102 -> IVC-200                                             [0000:a155,0001:a155,0002:a155,0003:a155,0100:a155,0101:a155,0102:a155,0103:a155]
+102 -> IVC-200                                             [0000:a155,0001:a155,0002:a155,0003:a155,0100:a155,0101:a155,0102:a155,0103:a155,0800:a155,0801:a155,0802:a155,0803:a155]
 103 -> Grand X-Guard / Trust 814PCI                        [0304:0102]
 104 -> Nebula Electronics DigiTV                           [0071:0101]
 105 -> ProVideo PV143                                      [aa00:1430,aa00:1431,aa00:1432,aa00:1433,aa03:1433]
diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88
index 7ec3c4e..f251054 100644
--- a/Documentation/video4linux/CARDLIST.cx88
+++ b/Documentation/video4linux/CARDLIST.cx88
@@ -82,3 +82,4 @@
  81 -> Leadtek WinFast DTV1800 Hybrid                      [107d:6654]
  82 -> WinFast DTV2000 H rev. J                            [107d:6f2b]
  83 -> Prof 7301 DVB-S/S2                                  [b034:3034]
+ 84 -> Samsung SMT 7020 DVB-S                              [18ac:dc00,18ac:dccd]
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
index 0c166ff..3a623aa 100644
--- a/Documentation/video4linux/CARDLIST.em28xx
+++ b/Documentation/video4linux/CARDLIST.em28xx
@@ -1,5 +1,5 @@
   0 -> Unknown EM2800 video grabber             (em2800)        [eb1a:2800]
-  1 -> Unknown EM2750/28xx video grabber        (em2820/em2840) [eb1a:2710,eb1a:2820,eb1a:2821,eb1a:2860,eb1a:2861,eb1a:2862,eb1a:2870,eb1a:2881,eb1a:2883,eb1a:2868]
+  1 -> Unknown EM2750/28xx video grabber        (em2820/em2840) [eb1a:2710,eb1a:2820,eb1a:2821,eb1a:2860,eb1a:2861,eb1a:2862,eb1a:2863,eb1a:2870,eb1a:2881,eb1a:2883,eb1a:2868]
   2 -> Terratec Cinergy 250 USB                 (em2820/em2840) [0ccd:0036]
   3 -> Pinnacle PCTV USB 2                      (em2820/em2840) [2304:0208]
   4 -> Hauppauge WinTV USB 2                    (em2820/em2840) [2040:4200,2040:4201]
@@ -27,6 +27,7 @@
  26 -> Hercules Smart TV USB 2.0                (em2820/em2840)
  27 -> Pinnacle PCTV USB 2 (Philips FM1216ME)   (em2820/em2840)
  28 -> Leadtek Winfast USB II Deluxe            (em2820/em2840)
+ 29 -> EM2860/TVP5150 Reference Design          (em2860)
  30 -> Videology 20K14XUSB USB2.0               (em2820/em2840)
  31 -> Usbgear VD204v9                          (em2821)
  32 -> Supercomp USB 2.0 TV                     (em2821)
@@ -70,3 +71,4 @@
  72 -> Gadmei UTV330+                           (em2861)
  73 -> Reddo DVB-C USB TV Box                   (em2870)
  74 -> Actionmaster/LinXcel/Digitus VC211A      (em2800)
+ 75 -> Dikom DK300                              (em2882)
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index b4a7670..070f257 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -175,3 +175,6 @@
 174 -> Asus Europa Hybrid OEM                   [1043:4847]
 175 -> Leadtek Winfast DTV1000S                 [107d:6655]
 176 -> Beholder BeholdTV 505 RDS                [0000:5051]
+177 -> Hawell HW-404M7
+179 -> Beholder BeholdTV H7			[5ace:7190]
+180 -> Beholder BeholdTV A7			[5ace:7090]
diff --git a/Documentation/video4linux/extract_xc3028.pl b/Documentation/video4linux/extract_xc3028.pl
index 2cb8160..47877de 100644
--- a/Documentation/video4linux/extract_xc3028.pl
+++ b/Documentation/video4linux/extract_xc3028.pl
@@ -5,12 +5,18 @@
 #
 # In order to use, you need to:
 #	1) Download the windows driver with something like:
+#	Version 2.4
+#		wget http://www.twinhan.com/files/AW/BDA T/20080303_V1.0.6.7.zip
+#		or wget http://www.stefanringel.de/pub/20080303_V1.0.6.7.zip
+#	Version 2.7
 #		wget http://www.steventoth.net/linux/xc5000/HVR-12x0-14x0-17x0_1_25_25271_WHQL.zip
-#	2) Extract the file hcw85bda.sys from the zip into the current dir:
+#	2) Extract the files from the zip into the current dir:
+#		unzip -j 20080303_V1.0.6.7.zip 20080303_v1.0.6.7/UDXTTM6000.sys
 #		unzip -j HVR-12x0-14x0-17x0_1_25_25271_WHQL.zip Driver85/hcw85bda.sys
 #	3) run the script:
 #		./extract_xc3028.pl
-#	4) copy the generated file:
+#	4) copy the generated files:
+#		cp xc3028-v24.fw /lib/firmware
 #		cp xc3028-v27.fw /lib/firmware
 
 #use strict;
@@ -135,7 +141,7 @@
 	}
 }
 
-sub main_firmware($$$$)
+sub main_firmware_24($$$$)
 {
 	my $out;
 	my $j=0;
@@ -146,8 +152,774 @@
 
 	for ($j = length($name); $j <32; $j++) {
 		$name = $name.chr(0);
+	}
+
+	open OUTFILE, ">$outfile";
+	syswrite(OUTFILE, $name);
+	write_le16($version);
+	write_le16($nr_desc);
+
+	#
+	# Firmware 0, type: BASE FW   F8MHZ (0x00000003), id: (0000000000000000), size: 6635
+	#
+
+	write_le32(0x00000003);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(6635);			# Size
+	write_hunk_fix_endian(257752, 6635);
+
+	#
+	# Firmware 1, type: BASE FW   F8MHZ MTS (0x00000007), id: (0000000000000000), size: 6635
+	#
+
+	write_le32(0x00000007);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(6635);			# Size
+	write_hunk_fix_endian(264392, 6635);
+
+	#
+	# Firmware 2, type: BASE FW   FM (0x00000401), id: (0000000000000000), size: 6525
+	#
+
+	write_le32(0x00000401);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(6525);			# Size
+	write_hunk_fix_endian(271040, 6525);
+
+	#
+	# Firmware 3, type: BASE FW   FM INPUT1 (0x00000c01), id: (0000000000000000), size: 6539
+	#
+
+	write_le32(0x00000c01);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(6539);			# Size
+	write_hunk_fix_endian(277568, 6539);
+
+	#
+	# Firmware 4, type: BASE FW   (0x00000001), id: (0000000000000000), size: 6633
+	#
+
+	write_le32(0x00000001);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(6633);			# Size
+	write_hunk_fix_endian(284120, 6633);
+
+	#
+	# Firmware 5, type: BASE FW   MTS (0x00000005), id: (0000000000000000), size: 6617
+	#
+
+	write_le32(0x00000005);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(6617);			# Size
+	write_hunk_fix_endian(290760, 6617);
+
+	#
+	# Firmware 6, type: STD FW    (0x00000000), id: PAL/BG A2/A (0000000100000007), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000001, 0x00000007);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(297384, 161);
+
+	#
+	# Firmware 7, type: STD FW    MTS (0x00000004), id: PAL/BG A2/A (0000000100000007), size: 169
+	#
+
+	write_le32(0x00000004);			# Type
+	write_le64(0x00000001, 0x00000007);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(297552, 169);
+
+	#
+	# Firmware 8, type: STD FW    (0x00000000), id: PAL/BG A2/B (0000000200000007), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000002, 0x00000007);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(297728, 161);
+
+	#
+	# Firmware 9, type: STD FW    MTS (0x00000004), id: PAL/BG A2/B (0000000200000007), size: 169
+	#
+
+	write_le32(0x00000004);			# Type
+	write_le64(0x00000002, 0x00000007);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(297896, 169);
+
+	#
+	# Firmware 10, type: STD FW    (0x00000000), id: PAL/BG NICAM/A (0000000400000007), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000004, 0x00000007);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(298072, 161);
+
+	#
+	# Firmware 11, type: STD FW    MTS (0x00000004), id: PAL/BG NICAM/A (0000000400000007), size: 169
+	#
+
+	write_le32(0x00000004);			# Type
+	write_le64(0x00000004, 0x00000007);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(298240, 169);
+
+	#
+	# Firmware 12, type: STD FW    (0x00000000), id: PAL/BG NICAM/B (0000000800000007), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000008, 0x00000007);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(298416, 161);
+
+	#
+	# Firmware 13, type: STD FW    MTS (0x00000004), id: PAL/BG NICAM/B (0000000800000007), size: 169
+	#
+
+	write_le32(0x00000004);			# Type
+	write_le64(0x00000008, 0x00000007);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(298584, 169);
+
+	#
+	# Firmware 14, type: STD FW    (0x00000000), id: PAL/DK A2 (00000003000000e0), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000003, 0x000000e0);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(298760, 161);
+
+	#
+	# Firmware 15, type: STD FW    MTS (0x00000004), id: PAL/DK A2 (00000003000000e0), size: 169
+	#
+
+	write_le32(0x00000004);			# Type
+	write_le64(0x00000003, 0x000000e0);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(298928, 169);
+
+	#
+	# Firmware 16, type: STD FW    (0x00000000), id: PAL/DK NICAM (0000000c000000e0), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x0000000c, 0x000000e0);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(299104, 161);
+
+	#
+	# Firmware 17, type: STD FW    MTS (0x00000004), id: PAL/DK NICAM (0000000c000000e0), size: 169
+	#
+
+	write_le32(0x00000004);			# Type
+	write_le64(0x0000000c, 0x000000e0);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(299272, 169);
+
+	#
+	# Firmware 18, type: STD FW    (0x00000000), id: SECAM/K1 (0000000000200000), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000000, 0x00200000);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(299448, 161);
+
+	#
+	# Firmware 19, type: STD FW    MTS (0x00000004), id: SECAM/K1 (0000000000200000), size: 169
+	#
+
+	write_le32(0x00000004);			# Type
+	write_le64(0x00000000, 0x00200000);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(299616, 169);
+
+	#
+	# Firmware 20, type: STD FW    (0x00000000), id: SECAM/K3 (0000000004000000), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000000, 0x04000000);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(299792, 161);
+
+	#
+	# Firmware 21, type: STD FW    MTS (0x00000004), id: SECAM/K3 (0000000004000000), size: 169
+	#
+
+	write_le32(0x00000004);			# Type
+	write_le64(0x00000000, 0x04000000);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(299960, 169);
+
+	#
+	# Firmware 22, type: STD FW    D2633 DTV6 ATSC (0x00010030), id: (0000000000000000), size: 149
+	#
+
+	write_le32(0x00010030);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(149);			# Size
+	write_hunk_fix_endian(300136, 149);
+
+	#
+	# Firmware 23, type: STD FW    D2620 DTV6 QAM (0x00000068), id: (0000000000000000), size: 149
+	#
+
+	write_le32(0x00000068);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(149);			# Size
+	write_hunk_fix_endian(300296, 149);
+
+	#
+	# Firmware 24, type: STD FW    D2633 DTV6 QAM (0x00000070), id: (0000000000000000), size: 149
+	#
+
+	write_le32(0x00000070);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(149);			# Size
+	write_hunk_fix_endian(300448, 149);
+
+	#
+	# Firmware 25, type: STD FW    D2620 DTV7 (0x00000088), id: (0000000000000000), size: 149
+	#
+
+	write_le32(0x00000088);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(149);			# Size
+	write_hunk_fix_endian(300608, 149);
+
+	#
+	# Firmware 26, type: STD FW    D2633 DTV7 (0x00000090), id: (0000000000000000), size: 149
+	#
+
+	write_le32(0x00000090);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(149);			# Size
+	write_hunk_fix_endian(300760, 149);
+
+	#
+	# Firmware 27, type: STD FW    D2620 DTV78 (0x00000108), id: (0000000000000000), size: 149
+	#
+
+	write_le32(0x00000108);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(149);			# Size
+	write_hunk_fix_endian(300920, 149);
+
+	#
+	# Firmware 28, type: STD FW    D2633 DTV78 (0x00000110), id: (0000000000000000), size: 149
+	#
+
+	write_le32(0x00000110);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(149);			# Size
+	write_hunk_fix_endian(301072, 149);
+
+	#
+	# Firmware 29, type: STD FW    D2620 DTV8 (0x00000208), id: (0000000000000000), size: 149
+	#
+
+	write_le32(0x00000208);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(149);			# Size
+	write_hunk_fix_endian(301232, 149);
+
+	#
+	# Firmware 30, type: STD FW    D2633 DTV8 (0x00000210), id: (0000000000000000), size: 149
+	#
+
+	write_le32(0x00000210);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(149);			# Size
+	write_hunk_fix_endian(301384, 149);
+
+	#
+	# Firmware 31, type: STD FW    FM (0x00000400), id: (0000000000000000), size: 135
+	#
+
+	write_le32(0x00000400);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(135);			# Size
+	write_hunk_fix_endian(301554, 135);
+
+	#
+	# Firmware 32, type: STD FW    (0x00000000), id: PAL/I (0000000000000010), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000000, 0x00000010);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(301688, 161);
+
+	#
+	# Firmware 33, type: STD FW    MTS (0x00000004), id: PAL/I (0000000000000010), size: 169
+	#
+
+	write_le32(0x00000004);			# Type
+	write_le64(0x00000000, 0x00000010);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(301856, 169);
+
+	#
+	# Firmware 34, type: STD FW    (0x00000000), id: SECAM/L AM (0000001000400000), size: 169
+	#
+
+	#
+	# Firmware 35, type: STD FW    (0x00000000), id: SECAM/L NICAM (0000000c00400000), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x0000000c, 0x00400000);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(302032, 161);
+
+	#
+	# Firmware 36, type: STD FW    (0x00000000), id: SECAM/Lc (0000000000800000), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000000, 0x00800000);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(302200, 161);
+
+	#
+	# Firmware 37, type: STD FW    (0x00000000), id: NTSC/M Kr (0000000000008000), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000000, 0x00008000);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(302368, 161);
+
+	#
+	# Firmware 38, type: STD FW    LCD (0x00001000), id: NTSC/M Kr (0000000000008000), size: 161
+	#
+
+	write_le32(0x00001000);			# Type
+	write_le64(0x00000000, 0x00008000);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(302536, 161);
+
+	#
+	# Firmware 39, type: STD FW    LCD NOGD (0x00003000), id: NTSC/M Kr (0000000000008000), size: 161
+	#
+
+	write_le32(0x00003000);			# Type
+	write_le64(0x00000000, 0x00008000);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(302704, 161);
+
+	#
+	# Firmware 40, type: STD FW    MTS (0x00000004), id: NTSC/M Kr (0000000000008000), size: 169
+	#
+
+	write_le32(0x00000004);			# Type
+	write_le64(0x00000000, 0x00008000);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(302872, 169);
+
+	#
+	# Firmware 41, type: STD FW    (0x00000000), id: NTSC PAL/M PAL/N (000000000000b700), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000000, 0x0000b700);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(303048, 161);
+
+	#
+	# Firmware 42, type: STD FW    LCD (0x00001000), id: NTSC PAL/M PAL/N (000000000000b700), size: 161
+	#
+
+	write_le32(0x00001000);			# Type
+	write_le64(0x00000000, 0x0000b700);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(303216, 161);
+
+	#
+	# Firmware 43, type: STD FW    LCD NOGD (0x00003000), id: NTSC PAL/M PAL/N (000000000000b700), size: 161
+	#
+
+	write_le32(0x00003000);			# Type
+	write_le64(0x00000000, 0x0000b700);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(303384, 161);
+
+	#
+	# Firmware 44, type: STD FW    (0x00000000), id: NTSC/M Jp (0000000000002000), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000000, 0x00002000);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(303552, 161);
+
+	#
+	# Firmware 45, type: STD FW    MTS (0x00000004), id: NTSC PAL/M PAL/N (000000000000b700), size: 169
+	#
+
+	write_le32(0x00000004);			# Type
+	write_le64(0x00000000, 0x0000b700);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(303720, 169);
+
+	#
+	# Firmware 46, type: STD FW    MTS LCD (0x00001004), id: NTSC PAL/M PAL/N (000000000000b700), size: 169
+	#
+
+	write_le32(0x00001004);			# Type
+	write_le64(0x00000000, 0x0000b700);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(303896, 169);
+
+	#
+	# Firmware 47, type: STD FW    MTS LCD NOGD (0x00003004), id: NTSC PAL/M PAL/N (000000000000b700), size: 169
+	#
+
+	write_le32(0x00003004);			# Type
+	write_le64(0x00000000, 0x0000b700);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(304072, 169);
+
+	#
+	# Firmware 48, type: SCODE FW  HAS IF (0x60000000), IF = 3.28 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(3280);			# IF
+	write_le32(192);			# Size
+	write_hunk(309048, 192);
+
+	#
+	# Firmware 49, type: SCODE FW  HAS IF (0x60000000), IF = 3.30 MHz id: (0000000000000000), size: 192
+	#
+
+#	write_le32(0x60000000);			# Type
+#	write_le64(0x00000000, 0x00000000);	# ID
+#	write_le16(3300);			# IF
+#	write_le32(192);			# Size
+#	write_hunk(304440, 192);
+
+	#
+	# Firmware 50, type: SCODE FW  HAS IF (0x60000000), IF = 3.44 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(3440);			# IF
+	write_le32(192);			# Size
+	write_hunk(309432, 192);
+
+	#
+	# Firmware 51, type: SCODE FW  HAS IF (0x60000000), IF = 3.46 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(3460);			# IF
+	write_le32(192);			# Size
+	write_hunk(309624, 192);
+
+	#
+	# Firmware 52, type: SCODE FW  DTV6 ATSC OREN36 HAS IF (0x60210020), IF = 3.80 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60210020);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(3800);			# IF
+	write_le32(192);			# Size
+	write_hunk(306936, 192);
+
+	#
+	# Firmware 53, type: SCODE FW  HAS IF (0x60000000), IF = 4.00 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(4000);			# IF
+	write_le32(192);			# Size
+	write_hunk(309240, 192);
+
+	#
+	# Firmware 54, type: SCODE FW  DTV6 ATSC TOYOTA388 HAS IF (0x60410020), IF = 4.08 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60410020);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(4080);			# IF
+	write_le32(192);			# Size
+	write_hunk(307128, 192);
+
+	#
+	# Firmware 55, type: SCODE FW  HAS IF (0x60000000), IF = 4.20 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(4200);			# IF
+	write_le32(192);			# Size
+	write_hunk(308856, 192);
+
+	#
+	# Firmware 56, type: SCODE FW  MONO HAS IF (0x60008000), IF = 4.32 MHz id: NTSC/M Kr (0000000000008000), size: 192
+	#
+
+	write_le32(0x60008000);			# Type
+	write_le64(0x00000000, 0x00008000);	# ID
+	write_le16(4320);			# IF
+	write_le32(192);			# Size
+	write_hunk(305208, 192);
+
+	#
+	# Firmware 57, type: SCODE FW  HAS IF (0x60000000), IF = 4.45 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(4450);			# IF
+	write_le32(192);			# Size
+	write_hunk(309816, 192);
+
+	#
+	# Firmware 58, type: SCODE FW  MTS LCD NOGD MONO IF HAS IF (0x6002b004), IF = 4.50 MHz id: NTSC PAL/M PAL/N (000000000000b700), size: 192
+	#
+
+	write_le32(0x6002b004);			# Type
+	write_le64(0x00000000, 0x0000b700);	# ID
+	write_le16(4500);			# IF
+	write_le32(192);			# Size
+	write_hunk(304824, 192);
+
+	#
+	# Firmware 59, type: SCODE FW  LCD NOGD IF HAS IF (0x60023000), IF = 4.60 MHz id: NTSC/M Kr (0000000000008000), size: 192
+	#
+
+	write_le32(0x60023000);			# Type
+	write_le64(0x00000000, 0x00008000);	# ID
+	write_le16(4600);			# IF
+	write_le32(192);			# Size
+	write_hunk(305016, 192);
+
+	#
+	# Firmware 60, type: SCODE FW  DTV6 QAM DTV7 DTV78 DTV8 ZARLINK456 HAS IF (0x620003e0), IF = 4.76 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x620003e0);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(4760);			# IF
+	write_le32(192);			# Size
+	write_hunk(304440, 192);
+
+	#
+	# Firmware 61, type: SCODE FW  HAS IF (0x60000000), IF = 4.94 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(4940);			# IF
+	write_le32(192);			# Size
+	write_hunk(308664, 192);
+
+	#
+	# Firmware 62, type: SCODE FW  HAS IF (0x60000000), IF = 5.26 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(5260);			# IF
+	write_le32(192);			# Size
+	write_hunk(307704, 192);
+
+	#
+	# Firmware 63, type: SCODE FW  MONO HAS IF (0x60008000), IF = 5.32 MHz id: PAL/BG A2 NICAM (0000000f00000007), size: 192
+	#
+
+	write_le32(0x60008000);			# Type
+	write_le64(0x0000000f, 0x00000007);	# ID
+	write_le16(5320);			# IF
+	write_le32(192);			# Size
+	write_hunk(307896, 192);
+
+	#
+	# Firmware 64, type: SCODE FW  DTV7 DTV78 DTV8 DIBCOM52 CHINA HAS IF (0x65000380), IF = 5.40 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x65000380);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(5400);			# IF
+	write_le32(192);			# Size
+	write_hunk(304248, 192);
+
+	#
+	# Firmware 65, type: SCODE FW  DTV6 ATSC OREN538 HAS IF (0x60110020), IF = 5.58 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60110020);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(5580);			# IF
+	write_le32(192);			# Size
+	write_hunk(306744, 192);
+
+	#
+	# Firmware 66, type: SCODE FW  HAS IF (0x60000000), IF = 5.64 MHz id: PAL/BG A2 (0000000300000007), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000003, 0x00000007);	# ID
+	write_le16(5640);			# IF
+	write_le32(192);			# Size
+	write_hunk(305592, 192);
+
+	#
+	# Firmware 67, type: SCODE FW  HAS IF (0x60000000), IF = 5.74 MHz id: PAL/BG NICAM (0000000c00000007), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x0000000c, 0x00000007);	# ID
+	write_le16(5740);			# IF
+	write_le32(192);			# Size
+	write_hunk(305784, 192);
+
+	#
+	# Firmware 68, type: SCODE FW  HAS IF (0x60000000), IF = 5.90 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(5900);			# IF
+	write_le32(192);			# Size
+	write_hunk(307512, 192);
+
+	#
+	# Firmware 69, type: SCODE FW  MONO HAS IF (0x60008000), IF = 6.00 MHz id: PAL/DK PAL/I SECAM/K3 SECAM/L SECAM/Lc NICAM (0000000c04c000f0), size: 192
+	#
+
+	write_le32(0x60008000);			# Type
+	write_le64(0x0000000c, 0x04c000f0);	# ID
+	write_le16(6000);			# IF
+	write_le32(192);			# Size
+	write_hunk(305576, 192);
+
+	#
+	# Firmware 70, type: SCODE FW  DTV6 QAM ATSC LG60 F6MHZ HAS IF (0x68050060), IF = 6.20 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x68050060);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(6200);			# IF
+	write_le32(192);			# Size
+	write_hunk(306552, 192);
+
+	#
+	# Firmware 71, type: SCODE FW  HAS IF (0x60000000), IF = 6.24 MHz id: PAL/I (0000000000000010), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00000010);	# ID
+	write_le16(6240);			# IF
+	write_le32(192);			# Size
+	write_hunk(305400, 192);
+
+	#
+	# Firmware 72, type: SCODE FW  MONO HAS IF (0x60008000), IF = 6.32 MHz id: SECAM/K1 (0000000000200000), size: 192
+	#
+
+	write_le32(0x60008000);			# Type
+	write_le64(0x00000000, 0x00200000);	# ID
+	write_le16(6320);			# IF
+	write_le32(192);			# Size
+	write_hunk(308472, 192);
+
+	#
+	# Firmware 73, type: SCODE FW  HAS IF (0x60000000), IF = 6.34 MHz id: SECAM/K1 (0000000000200000), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00200000);	# ID
+	write_le16(6340);			# IF
+	write_le32(192);			# Size
+	write_hunk(306360, 192);
+
+	#
+	# Firmware 74, type: SCODE FW  MONO HAS IF (0x60008000), IF = 6.50 MHz id: PAL/DK SECAM/K3 SECAM/L NICAM (0000000c044000e0), size: 192
+	#
+
+	write_le32(0x60008000);			# Type
+	write_le64(0x0000000c, 0x044000e0);	# ID
+	write_le16(6500);			# IF
+	write_le32(192);			# Size
+	write_hunk(308280, 192);
+
+	#
+	# Firmware 75, type: SCODE FW  DTV6 ATSC ATI638 HAS IF (0x60090020), IF = 6.58 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60090020);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(6580);			# IF
+	write_le32(192);			# Size
+	write_hunk(304632, 192);
+
+	#
+	# Firmware 76, type: SCODE FW  HAS IF (0x60000000), IF = 6.60 MHz id: PAL/DK A2 (00000003000000e0), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000003, 0x000000e0);	# ID
+	write_le16(6600);			# IF
+	write_le32(192);			# Size
+	write_hunk(306168, 192);
+
+	#
+	# Firmware 77, type: SCODE FW  MONO HAS IF (0x60008000), IF = 6.68 MHz id: PAL/DK A2 (00000003000000e0), size: 192
+	#
+
+	write_le32(0x60008000);			# Type
+	write_le64(0x00000003, 0x000000e0);	# ID
+	write_le16(6680);			# IF
+	write_le32(192);			# Size
+	write_hunk(308088, 192);
+
+	#
+	# Firmware 78, type: SCODE FW  DTV6 ATSC TOYOTA794 HAS IF (0x60810020), IF = 8.14 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60810020);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(8140);			# IF
+	write_le32(192);			# Size
+	write_hunk(307320, 192);
+
+	#
+	# Firmware 79, type: SCODE FW  HAS IF (0x60000000), IF = 8.20 MHz id: (0000000000000000), size: 192
+	#
+
+#	write_le32(0x60000000);			# Type
+#	write_le64(0x00000000, 0x00000000);	# ID
+#	write_le16(8200);			# IF
+#	write_le32(192);			# Size
+#	write_hunk(308088, 192);
 }
 
+sub main_firmware_27($$$$)
+{
+	my $out;
+	my $j=0;
+	my $outfile = shift;
+	my $name    = shift;
+	my $version = shift;
+	my $nr_desc = shift;
+
+	for ($j = length($name); $j <32; $j++) {
+		$name = $name.chr(0);
+	}
+
 	open OUTFILE, ">$outfile";
 	syswrite(OUTFILE, $name);
 	write_le16($version);
@@ -906,20 +1678,39 @@
 	write_hunk(812856, 192);
 }
 
+
 sub extract_firmware {
-	my $sourcefile = "hcw85bda.sys";
-	my $hash = "0e44dbf63bb0169d57446aec21881ff2";
-	my $outfile = "xc3028-v27.fw";
-	my $name = "xc2028 firmware";
-	my $version = 519;
-	my $nr_desc = 80;
+	my $sourcefile_24 = "UDXTTM6000.sys";
+	my $hash_24 = "cb9deb5508a5e150af2880f5b0066d78";
+	my $outfile_24 = "xc3028-v24.fw";
+	my $name_24 = "xc2028 firmware";
+	my $version_24 = 516;
+	my $nr_desc_24 = 77;
 	my $out;
 
-	verify($sourcefile, $hash);
+	my $sourcefile_27 = "hcw85bda.sys";
+	my $hash_27 = "0e44dbf63bb0169d57446aec21881ff2";
+	my $outfile_27 = "xc3028-v27.fw";
+	my $name_27 = "xc2028 firmware";
+	my $version_27 = 519;
+	my $nr_desc_27 = 80;
+	my $out;
 
-	open INFILE, "<$sourcefile";
-	main_firmware($outfile, $name, $version, $nr_desc);
-	close INFILE;
+	if (-e $sourcefile_24) {
+		verify($sourcefile_24, $hash_24);
+
+		open INFILE, "<$sourcefile_24";
+		main_firmware_24($outfile_24, $name_24, $version_24, $nr_desc_24);
+		close INFILE;
+	}
+
+	if (-e $sourcefile_27) {
+		verify($sourcefile_27, $hash_27);
+
+		open INFILE, "<$sourcefile_27";
+		main_firmware_27($outfile_27, $name_27, $version_27, $nr_desc_27);
+		close INFILE;
+	}
 }
 
 extract_firmware;
diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt
index 181b9e6..8f3f5d3 100644
--- a/Documentation/video4linux/gspca.txt
+++ b/Documentation/video4linux/gspca.txt
@@ -50,6 +50,8 @@
 sonixj		0458:7025	Genius Eye 311Q
 sn9c20x		0458:7029	Genius Look 320s
 sonixj		0458:702e	Genius Slim 310 NB
+sn9c20x		0458:704a	Genius Slim 1320
+sn9c20x		0458:704c	Genius i-Look 1321
 sn9c20x		045e:00f4	LifeCam VX-6000 (SN9C20x + OV9650)
 sonixj		045e:00f5	MicroSoft VX3000
 sonixj		045e:00f7	MicroSoft VX1000
@@ -305,12 +307,14 @@
 sonixj		0c45:613a	Microdia Sonix PC Camera
 sonixj		0c45:613b	Surfer SN-206
 sonixj		0c45:613c	Sonix Pccam168
+sonixj		0c45:6142	Hama PC-Webcam AC-150
 sonixj		0c45:6143	Sonix Pccam168
 sonixj		0c45:6148	Digitus DA-70811/ZSMC USB PC Camera ZS211/Microdia
 sonixj		0c45:614a	Frontech E-Ccam (JIL-2225)
 sn9c20x		0c45:6240	PC Camera (SN9C201 + MT9M001)
 sn9c20x		0c45:6242	PC Camera (SN9C201 + MT9M111)
 sn9c20x		0c45:6248	PC Camera (SN9C201 + OV9655)
+sn9c20x		0c45:624c	PC Camera (SN9C201 + MT9M112)
 sn9c20x		0c45:624e	PC Camera (SN9C201 + SOI968)
 sn9c20x		0c45:624f	PC Camera (SN9C201 + OV9650)
 sn9c20x		0c45:6251	PC Camera (SN9C201 + OV9650)
@@ -323,6 +327,7 @@
 sn9c20x		0c45:6280	PC Camera (SN9C202 + MT9M001)
 sn9c20x		0c45:6282	PC Camera (SN9C202 + MT9M111)
 sn9c20x		0c45:6288	PC Camera (SN9C202 + OV9655)
+sn9c20x		0c45:628c	PC Camera (SN9C201 + MT9M112)
 sn9c20x		0c45:628e	PC Camera (SN9C202 + SOI968)
 sn9c20x		0c45:628f	PC Camera (SN9C202 + OV9650)
 sn9c20x		0c45:62a0	PC Camera (SN9C202 + OV7670)
diff --git a/Documentation/video4linux/sh_mobile_ceu_camera.txt b/Documentation/video4linux/sh_mobile_ceu_camera.txt
index 2ae1634..cb47e72 100644
--- a/Documentation/video4linux/sh_mobile_ceu_camera.txt
+++ b/Documentation/video4linux/sh_mobile_ceu_camera.txt
@@ -17,18 +17,18 @@
 -2-- -\
 |      --\
 |         --\
-+-5-- -\     -- -3--
-|       ---\
-|           --- -4-- -\
-|                      -\
-|                        - -6--
++-5-- .      -- -3-- -\
+|      `...            -\
+|          `... -4-- .   - -7..
+|                     `.
+|                       `. .6--
 |
-|                        - -6'-
-|                      -/
-|           --- -4'- -/
-|       ---/
-+-5'- -/
-|            -- -3'-
+|                        . .6'-
+|                      .´
+|           ... -4'- .´
+|       ...´             - -7'.
++-5'- .´               -/
+|            -- -3'- -/
 |         --/
 |      --/
 -2'- -/
@@ -36,7 +36,11 @@
 |
 -1'-
 
-Produced by user requests:
+In the above chart minuses and slashes represent "real" data amounts, points and
+accents represent "useful" data, basically, CEU scaled amd cropped output,
+mapped back onto the client's source plane.
+
+Such a configuration can be produced by user requests:
 
 S_CROP(left / top = (5) - (1), width / height = (5') - (5))
 S_FMT(width / height = (6') - (6))
@@ -106,52 +110,30 @@
 S_CROP
 ------
 
-If old scale applied to new crop is invalid produce nearest new scale possible
+The API at http://v4l2spec.bytesex.org/spec/x1904.htm says:
 
-1. Calculate current combined scales.
+"...specification does not define an origin or units. However by convention
+drivers should horizontally count unscaled samples relative to 0H."
 
-	scale_comb = (((4') - (4)) / ((6') - (6))) * (((2') - (2)) / ((3') - (3)))
+We choose to follow the advise and interpret cropping units as client input
+pixels.
 
-2. Apply iterative sensor S_CROP for new input window.
+Cropping is performed in the following 6 steps:
 
-3. If old combined scales applied to new crop produce an impossible user window,
-adjust scales to produce nearest possible window.
+1. Request exactly user rectangle from the sensor.
 
-	width_u_out = ((5') - (5)) / scale_comb
+2. If smaller - iterate until a larger one is obtained. Result: sensor cropped
+   to 2 : 2', target crop 5 : 5', current output format 6' - 6.
 
-	if (width_u_out > max)
-		scale_comb = ((5') - (5)) / max;
-	else if (width_u_out < min)
-		scale_comb = ((5') - (5)) / min;
+3. In the previous step the sensor has tried to preserve its output frame as
+   good as possible, but it could have changed. Retrieve it again.
 
-4. Issue G_CROP to retrieve actual input window.
+4. Sensor scaled to 3 : 3'. Sensor's scale is (2' - 2) / (3' - 3). Calculate
+   intermediate window: 4' - 4 = (5' - 5) * (3' - 3) / (2' - 2)
 
-5. Using actual input window and calculated combined scales calculate sensor
-target output window.
+5. Calculate and apply host scale = (6' - 6) / (4' - 4)
 
-	width_s_out = ((3') - (3)) = ((2') - (2)) / scale_comb
-
-6. Apply iterative S_FMT for new sensor target output window.
-
-7. Issue G_FMT to retrieve the actual sensor output window.
-
-8. Calculate sensor scales.
-
-	scale_s = ((3') - (3)) / ((2') - (2))
-
-9. Calculate sensor output subwindow to be cropped on CEU by applying sensor
-scales to the requested window.
-
-	width_ceu = ((5') - (5)) / scale_s
-
-10. Use CEU cropping for above calculated window.
-
-11. Calculate CEU scales from sensor scales from results of (10) and user window
-from (3)
-
-	scale_ceu = calc_scale(((5') - (5)), &width_u_out)
-
-12. Apply CEU scales.
+6. Calculate and apply host crop: 6 - 7 = (5 - 2) * (6' - 6) / (5' - 5)
 
 --
 Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
index 5155700..e831aac 100644
--- a/Documentation/video4linux/v4l2-framework.txt
+++ b/Documentation/video4linux/v4l2-framework.txt
@@ -545,12 +545,11 @@
 This will remove the device nodes from sysfs (causing udev to remove them
 from /dev).
 
-After video_unregister_device() returns no new opens can be done.
-
-However, in the case of USB devices some application might still have one
-of these device nodes open. You should block all new accesses to read,
-write, poll, etc. except possibly for certain ioctl operations like
-queueing buffers.
+After video_unregister_device() returns no new opens can be done. However,
+in the case of USB devices some application might still have one of these
+device nodes open. So after the unregister all file operations will return
+an error as well, except for the ioctl and unlocked_ioctl file operations:
+those will still be passed on since some buffer ioctls may still be needed.
 
 When the last user of the video device node exits, then the vdev->release()
 callback is called and you can do the final cleanup there.
@@ -609,3 +608,135 @@
 
 Please see Documentation/video4linux/videobuf for more information on how
 to use the videobuf layer.
+
+struct v4l2_fh
+--------------
+
+struct v4l2_fh provides a way to easily keep file handle specific data
+that is used by the V4L2 framework. Using v4l2_fh is optional for
+drivers.
+
+The users of v4l2_fh (in the V4L2 framework, not the driver) know
+whether a driver uses v4l2_fh as its file->private_data pointer by
+testing the V4L2_FL_USES_V4L2_FH bit in video_device->flags.
+
+Useful functions:
+
+- v4l2_fh_init()
+
+  Initialise the file handle. This *MUST* be performed in the driver's
+  v4l2_file_operations->open() handler.
+
+- v4l2_fh_add()
+
+  Add a v4l2_fh to video_device file handle list. May be called after
+  initialising the file handle.
+
+- v4l2_fh_del()
+
+  Unassociate the file handle from video_device(). The file handle
+  exit function may now be called.
+
+- v4l2_fh_exit()
+
+  Uninitialise the file handle. After uninitialisation the v4l2_fh
+  memory can be freed.
+
+struct v4l2_fh is allocated as a part of the driver's own file handle
+structure and is set to file->private_data in the driver's open
+function by the driver. Drivers can extract their own file handle
+structure by using the container_of macro. Example:
+
+struct my_fh {
+	int blah;
+	struct v4l2_fh fh;
+};
+
+...
+
+int my_open(struct file *file)
+{
+	struct my_fh *my_fh;
+	struct video_device *vfd;
+	int ret;
+
+	...
+
+	ret = v4l2_fh_init(&my_fh->fh, vfd);
+	if (ret)
+		return ret;
+
+	v4l2_fh_add(&my_fh->fh);
+
+	file->private_data = &my_fh->fh;
+
+	...
+}
+
+int my_release(struct file *file)
+{
+	struct v4l2_fh *fh = file->private_data;
+	struct my_fh *my_fh = container_of(fh, struct my_fh, fh);
+
+	...
+}
+
+V4L2 events
+-----------
+
+The V4L2 events provide a generic way to pass events to user space.
+The driver must use v4l2_fh to be able to support V4L2 events.
+
+Useful functions:
+
+- v4l2_event_alloc()
+
+  To use events, the driver must allocate events for the file handle. By
+  calling the function more than once, the driver may assure that at least n
+  events in total have been allocated. The function may not be called in
+  atomic context.
+
+- v4l2_event_queue()
+
+  Queue events to video device. The driver's only responsibility is to fill
+  in the type and the data fields. The other fields will be filled in by
+  V4L2.
+
+- v4l2_event_subscribe()
+
+  The video_device->ioctl_ops->vidioc_subscribe_event must check the driver
+  is able to produce events with specified event id. Then it calls
+  v4l2_event_subscribe() to subscribe the event.
+
+- v4l2_event_unsubscribe()
+
+  vidioc_unsubscribe_event in struct v4l2_ioctl_ops. A driver may use
+  v4l2_event_unsubscribe() directly unless it wants to be involved in
+  unsubscription process.
+
+  The special type V4L2_EVENT_ALL may be used to unsubscribe all events. The
+  drivers may want to handle this in a special way.
+
+- v4l2_event_pending()
+
+  Returns the number of pending events. Useful when implementing poll.
+
+Drivers do not initialise events directly. The events are initialised
+through v4l2_fh_init() if video_device->ioctl_ops->vidioc_subscribe_event is
+non-NULL. This *MUST* be performed in the driver's
+v4l2_file_operations->open() handler.
+
+Events are delivered to user space through the poll system call. The driver
+can use v4l2_fh->events->wait wait_queue_head_t as the argument for
+poll_wait().
+
+There are standard and private events. New standard events must use the
+smallest available event type. The drivers must allocate their events from
+their own class starting from class base. Class base is
+V4L2_EVENT_PRIVATE_START + n * 1000 where n is the lowest available number.
+The first event type in the class is reserved for future use, so the first
+available event type is 'class base + 1'.
+
+An example on how the V4L2 events may be used can be found in the OMAP
+3 ISP driver available at <URL:http://gitorious.org/omap3camera> as of
+writing this.
diff --git a/MAINTAINERS b/MAINTAINERS
index 2f5510c..f860e2e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5963,7 +5963,7 @@
 L:	linux-uvc-devel@lists.berlios.de (subscribers-only)
 L:	linux-media@vger.kernel.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
-W:	http://linux-uvc.berlios.de
+W:	http://www.ideasonboard.org/uvc/
 S:	Maintained
 F:	drivers/media/video/uvc/
 
diff --git a/drivers/media/IR/Kconfig b/drivers/media/IR/Kconfig
index 4dde7d1..195c6cf 100644
--- a/drivers/media/IR/Kconfig
+++ b/drivers/media/IR/Kconfig
@@ -7,3 +7,62 @@
 	tristate
 	depends on IR_CORE
 	default IR_CORE
+
+source "drivers/media/IR/keymaps/Kconfig"
+
+config IR_NEC_DECODER
+	tristate "Enable IR raw decoder for the NEC protocol"
+	depends on IR_CORE
+	default y
+
+	---help---
+	   Enable this option if you have IR with NEC protocol, and
+	   if the IR is decoded in software
+
+config IR_RC5_DECODER
+	tristate "Enable IR raw decoder for the RC-5 protocol"
+	depends on IR_CORE
+	default y
+
+	---help---
+	   Enable this option if you have IR with RC-5 protocol, and
+	   if the IR is decoded in software
+
+config IR_RC6_DECODER
+	tristate "Enable IR raw decoder for the RC6 protocol"
+	depends on IR_CORE
+	default y
+
+	---help---
+	   Enable this option if you have an infrared remote control which
+	   uses the RC6 protocol, and you need software decoding support.
+
+config IR_JVC_DECODER
+	tristate "Enable IR raw decoder for the JVC protocol"
+	depends on IR_CORE
+	default y
+
+	---help---
+	   Enable this option if you have an infrared remote control which
+	   uses the JVC protocol, and you need software decoding support.
+
+config IR_SONY_DECODER
+	tristate "Enable IR raw decoder for the Sony protocol"
+	depends on IR_CORE
+	default y
+
+	---help---
+	   Enable this option if you have an infrared remote control which
+	   uses the Sony protocol, and you need software decoding support.
+
+config IR_IMON
+	tristate "SoundGraph iMON Receiver and Display"
+	depends on USB_ARCH_HAS_HCD
+	depends on IR_CORE
+	select USB
+	---help---
+	   Say Y here if you want to use a SoundGraph iMON (aka Antec Veris)
+	   IR Receiver and/or LCD/VFD/VGA display.
+
+	   To compile this driver as a module, choose M here: the
+	   module will be called imon.
diff --git a/drivers/media/IR/Makefile b/drivers/media/IR/Makefile
index 171890e..b998fcc 100644
--- a/drivers/media/IR/Makefile
+++ b/drivers/media/IR/Makefile
@@ -1,5 +1,15 @@
-ir-common-objs  := ir-functions.o ir-keymaps.o
-ir-core-objs	:= ir-keytable.o ir-sysfs.o
+ir-common-objs  := ir-functions.o
+ir-core-objs	:= ir-keytable.o ir-sysfs.o ir-raw-event.o rc-map.o
+
+obj-y += keymaps/
 
 obj-$(CONFIG_IR_CORE) += ir-core.o
 obj-$(CONFIG_VIDEO_IR) += ir-common.o
+obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o
+obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o
+obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
+obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
+obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
+
+# stand-alone IR receivers/transmitters
+obj-$(CONFIG_IR_IMON) += imon.o
diff --git a/drivers/media/IR/imon.c b/drivers/media/IR/imon.c
new file mode 100644
index 0000000..5e20456
--- /dev/null
+++ b/drivers/media/IR/imon.c
@@ -0,0 +1,2396 @@
+/*
+ *   imon.c:	input and display driver for SoundGraph iMON IR/VFD/LCD
+ *
+ *   Copyright(C) 2009  Jarod Wilson <jarod@wilsonet.com>
+ *   Portions based on the original lirc_imon driver,
+ *	Copyright(C) 2004  Venky Raju(dev@venky.ws)
+ *
+ *   Huge thanks to R. Geoff Newbury for invaluable debugging on the
+ *   0xffdc iMON devices, and for sending me one to hack on, without
+ *   which the support for them wouldn't be nearly as good. Thanks
+ *   also to the numerous 0xffdc device owners that tested auto-config
+ *   support for me and provided debug dumps from their devices.
+ *
+ *   imon is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+#include <media/ir-core.h>
+
+#include <linux/time.h>
+#include <linux/timer.h>
+
+#define MOD_AUTHOR	"Jarod Wilson <jarod@wilsonet.com>"
+#define MOD_DESC	"Driver for SoundGraph iMON MultiMedia IR/Display"
+#define MOD_NAME	"imon"
+#define MOD_VERSION	"0.9.1"
+
+#define DISPLAY_MINOR_BASE	144
+#define DEVICE_NAME	"lcd%d"
+
+#define BUF_CHUNK_SIZE	8
+#define BUF_SIZE	128
+
+#define BIT_DURATION	250	/* each bit received is 250us */
+
+#define IMON_CLOCK_ENABLE_PACKETS	2
+
+/*** P R O T O T Y P E S ***/
+
+/* USB Callback prototypes */
+static int imon_probe(struct usb_interface *interface,
+		      const struct usb_device_id *id);
+static void imon_disconnect(struct usb_interface *interface);
+static void usb_rx_callback_intf0(struct urb *urb);
+static void usb_rx_callback_intf1(struct urb *urb);
+static void usb_tx_callback(struct urb *urb);
+
+/* suspend/resume support */
+static int imon_resume(struct usb_interface *intf);
+static int imon_suspend(struct usb_interface *intf, pm_message_t message);
+
+/* Display file_operations function prototypes */
+static int display_open(struct inode *inode, struct file *file);
+static int display_close(struct inode *inode, struct file *file);
+
+/* VFD write operation */
+static ssize_t vfd_write(struct file *file, const char *buf,
+			 size_t n_bytes, loff_t *pos);
+
+/* LCD file_operations override function prototypes */
+static ssize_t lcd_write(struct file *file, const char *buf,
+			 size_t n_bytes, loff_t *pos);
+
+/*** G L O B A L S ***/
+
+struct imon_context {
+	struct device *dev;
+	struct ir_dev_props *props;
+	struct ir_input_dev *ir;
+	/* Newer devices have two interfaces */
+	struct usb_device *usbdev_intf0;
+	struct usb_device *usbdev_intf1;
+
+	bool display_supported;		/* not all controllers do */
+	bool display_isopen;		/* display port has been opened */
+	bool rf_isassociating;		/* RF remote associating */
+	bool dev_present_intf0;		/* USB device presence, interface 0 */
+	bool dev_present_intf1;		/* USB device presence, interface 1 */
+
+	struct mutex lock;		/* to lock this object */
+	wait_queue_head_t remove_ok;	/* For unexpected USB disconnects */
+
+	struct usb_endpoint_descriptor *rx_endpoint_intf0;
+	struct usb_endpoint_descriptor *rx_endpoint_intf1;
+	struct usb_endpoint_descriptor *tx_endpoint;
+	struct urb *rx_urb_intf0;
+	struct urb *rx_urb_intf1;
+	struct urb *tx_urb;
+	bool tx_control;
+	unsigned char usb_rx_buf[8];
+	unsigned char usb_tx_buf[8];
+
+	struct tx_t {
+		unsigned char data_buf[35];	/* user data buffer */
+		struct completion finished;	/* wait for write to finish */
+		bool busy;			/* write in progress */
+		int status;			/* status of tx completion */
+	} tx;
+
+	u16 vendor;			/* usb vendor ID */
+	u16 product;			/* usb product ID */
+
+	struct input_dev *idev;		/* input device for remote */
+	struct input_dev *touch;	/* input device for touchscreen */
+
+	u32 kc;				/* current input keycode */
+	u32 last_keycode;		/* last reported input keycode */
+	u64 ir_type;			/* iMON or MCE (RC6) IR protocol? */
+	u8 mce_toggle_bit;		/* last mce toggle bit */
+	bool release_code;		/* some keys send a release code */
+
+	u8 display_type;		/* store the display type */
+	bool pad_mouse;			/* toggle kbd(0)/mouse(1) mode */
+
+	char name_idev[128];		/* input device name */
+	char phys_idev[64];		/* input device phys path */
+	struct timer_list itimer;	/* input device timer, need for rc6 */
+
+	char name_touch[128];		/* touch screen name */
+	char phys_touch[64];		/* touch screen phys path */
+	struct timer_list ttimer;	/* touch screen timer */
+	int touch_x;			/* x coordinate on touchscreen */
+	int touch_y;			/* y coordinate on touchscreen */
+};
+
+#define TOUCH_TIMEOUT	(HZ/30)
+
+/* vfd character device file operations */
+static const struct file_operations vfd_fops = {
+	.owner		= THIS_MODULE,
+	.open		= &display_open,
+	.write		= &vfd_write,
+	.release	= &display_close
+};
+
+/* lcd character device file operations */
+static const struct file_operations lcd_fops = {
+	.owner		= THIS_MODULE,
+	.open		= &display_open,
+	.write		= &lcd_write,
+	.release	= &display_close
+};
+
+enum {
+	IMON_DISPLAY_TYPE_AUTO = 0,
+	IMON_DISPLAY_TYPE_VFD  = 1,
+	IMON_DISPLAY_TYPE_LCD  = 2,
+	IMON_DISPLAY_TYPE_VGA  = 3,
+	IMON_DISPLAY_TYPE_NONE = 4,
+};
+
+enum {
+	IMON_KEY_IMON	= 0,
+	IMON_KEY_MCE	= 1,
+	IMON_KEY_PANEL	= 2,
+};
+
+/*
+ * USB Device ID for iMON USB Control Boards
+ *
+ * The Windows drivers contain 6 different inf files, more or less one for
+ * each new device until the 0x0034-0x0046 devices, which all use the same
+ * driver. Some of the devices in the 34-46 range haven't been definitively
+ * identified yet. Early devices have either a TriGem Computer, Inc. or a
+ * Samsung vendor ID (0x0aa8 and 0x04e8 respectively), while all later
+ * devices use the SoundGraph vendor ID (0x15c2). This driver only supports
+ * the ffdc and later devices, which do onboard decoding.
+ */
+static struct usb_device_id imon_usb_id_table[] = {
+	/*
+	 * Several devices with this same device ID, all use iMON_PAD.inf
+	 * SoundGraph iMON PAD (IR & VFD)
+	 * SoundGraph iMON PAD (IR & LCD)
+	 * SoundGraph iMON Knob (IR only)
+	 */
+	{ USB_DEVICE(0x15c2, 0xffdc) },
+
+	/*
+	 * Newer devices, all driven by the latest iMON Windows driver, full
+	 * list of device IDs extracted via 'strings Setup/data1.hdr |grep 15c2'
+	 * Need user input to fill in details on unknown devices.
+	 */
+	/* SoundGraph iMON OEM Touch LCD (IR & 7" VGA LCD) */
+	{ USB_DEVICE(0x15c2, 0x0034) },
+	/* SoundGraph iMON OEM Touch LCD (IR & 4.3" VGA LCD) */
+	{ USB_DEVICE(0x15c2, 0x0035) },
+	/* SoundGraph iMON OEM VFD (IR & VFD) */
+	{ USB_DEVICE(0x15c2, 0x0036) },
+	/* device specifics unknown */
+	{ USB_DEVICE(0x15c2, 0x0037) },
+	/* SoundGraph iMON OEM LCD (IR & LCD) */
+	{ USB_DEVICE(0x15c2, 0x0038) },
+	/* SoundGraph iMON UltraBay (IR & LCD) */
+	{ USB_DEVICE(0x15c2, 0x0039) },
+	/* device specifics unknown */
+	{ USB_DEVICE(0x15c2, 0x003a) },
+	/* device specifics unknown */
+	{ USB_DEVICE(0x15c2, 0x003b) },
+	/* SoundGraph iMON OEM Inside (IR only) */
+	{ USB_DEVICE(0x15c2, 0x003c) },
+	/* device specifics unknown */
+	{ USB_DEVICE(0x15c2, 0x003d) },
+	/* device specifics unknown */
+	{ USB_DEVICE(0x15c2, 0x003e) },
+	/* device specifics unknown */
+	{ USB_DEVICE(0x15c2, 0x003f) },
+	/* device specifics unknown */
+	{ USB_DEVICE(0x15c2, 0x0040) },
+	/* SoundGraph iMON MINI (IR only) */
+	{ USB_DEVICE(0x15c2, 0x0041) },
+	/* Antec Veris Multimedia Station EZ External (IR only) */
+	{ USB_DEVICE(0x15c2, 0x0042) },
+	/* Antec Veris Multimedia Station Basic Internal (IR only) */
+	{ USB_DEVICE(0x15c2, 0x0043) },
+	/* Antec Veris Multimedia Station Elite (IR & VFD) */
+	{ USB_DEVICE(0x15c2, 0x0044) },
+	/* Antec Veris Multimedia Station Premiere (IR & LCD) */
+	{ USB_DEVICE(0x15c2, 0x0045) },
+	/* device specifics unknown */
+	{ USB_DEVICE(0x15c2, 0x0046) },
+	{}
+};
+
+/* USB Device data */
+static struct usb_driver imon_driver = {
+	.name		= MOD_NAME,
+	.probe		= imon_probe,
+	.disconnect	= imon_disconnect,
+	.suspend	= imon_suspend,
+	.resume		= imon_resume,
+	.id_table	= imon_usb_id_table,
+};
+
+static struct usb_class_driver imon_vfd_class = {
+	.name		= DEVICE_NAME,
+	.fops		= &vfd_fops,
+	.minor_base	= DISPLAY_MINOR_BASE,
+};
+
+static struct usb_class_driver imon_lcd_class = {
+	.name		= DEVICE_NAME,
+	.fops		= &lcd_fops,
+	.minor_base	= DISPLAY_MINOR_BASE,
+};
+
+/* imon receiver front panel/knob key table */
+static const struct {
+	u64 hw_code;
+	u32 keycode;
+} imon_panel_key_table[] = {
+	{ 0x000000000f00ffeell, KEY_PROG1 }, /* Go */
+	{ 0x000000001f00ffeell, KEY_AUDIO },
+	{ 0x000000002000ffeell, KEY_VIDEO },
+	{ 0x000000002100ffeell, KEY_CAMERA },
+	{ 0x000000002700ffeell, KEY_DVD },
+	{ 0x000000002300ffeell, KEY_TV },
+	{ 0x000000000500ffeell, KEY_PREVIOUS },
+	{ 0x000000000700ffeell, KEY_REWIND },
+	{ 0x000000000400ffeell, KEY_STOP },
+	{ 0x000000003c00ffeell, KEY_PLAYPAUSE },
+	{ 0x000000000800ffeell, KEY_FASTFORWARD },
+	{ 0x000000000600ffeell, KEY_NEXT },
+	{ 0x000000010000ffeell, KEY_RIGHT },
+	{ 0x000001000000ffeell, KEY_LEFT },
+	{ 0x000000003d00ffeell, KEY_SELECT },
+	{ 0x000100000000ffeell, KEY_VOLUMEUP },
+	{ 0x010000000000ffeell, KEY_VOLUMEDOWN },
+	{ 0x000000000100ffeell, KEY_MUTE },
+	/* iMON Knob values */
+	{ 0x000100ffffffffeell, KEY_VOLUMEUP },
+	{ 0x010000ffffffffeell, KEY_VOLUMEDOWN },
+	{ 0x000008ffffffffeell, KEY_MUTE },
+};
+
+/* to prevent races between open() and disconnect(), probing, etc */
+static DEFINE_MUTEX(driver_lock);
+
+/* Module bookkeeping bits */
+MODULE_AUTHOR(MOD_AUTHOR);
+MODULE_DESCRIPTION(MOD_DESC);
+MODULE_VERSION(MOD_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(usb, imon_usb_id_table);
+
+static bool debug;
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes(default: no)");
+
+/* lcd, vfd, vga or none? should be auto-detected, but can be overridden... */
+static int display_type;
+module_param(display_type, int, S_IRUGO);
+MODULE_PARM_DESC(display_type, "Type of attached display. 0=autodetect, "
+		 "1=vfd, 2=lcd, 3=vga, 4=none (default: autodetect)");
+
+static int pad_stabilize = 1;
+module_param(pad_stabilize, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(pad_stabilize, "Apply stabilization algorithm to iMON PAD "
+		 "presses in arrow key mode. 0=disable, 1=enable (default).");
+
+/*
+ * In certain use cases, mouse mode isn't really helpful, and could actually
+ * cause confusion, so allow disabling it when the IR device is open.
+ */
+static bool nomouse;
+module_param(nomouse, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(nomouse, "Disable mouse input device mode when IR device is "
+		 "open. 0=don't disable, 1=disable. (default: don't disable)");
+
+/* threshold at which a pad push registers as an arrow key in kbd mode */
+static int pad_thresh;
+module_param(pad_thresh, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(pad_thresh, "Threshold at which a pad push registers as an "
+		 "arrow key in kbd mode (default: 28)");
+
+
+static void free_imon_context(struct imon_context *ictx)
+{
+	struct device *dev = ictx->dev;
+
+	usb_free_urb(ictx->tx_urb);
+	usb_free_urb(ictx->rx_urb_intf0);
+	usb_free_urb(ictx->rx_urb_intf1);
+	kfree(ictx);
+
+	dev_dbg(dev, "%s: iMON context freed\n", __func__);
+}
+
+/**
+ * Called when the Display device (e.g. /dev/lcd0)
+ * is opened by the application.
+ */
+static int display_open(struct inode *inode, struct file *file)
+{
+	struct usb_interface *interface;
+	struct imon_context *ictx = NULL;
+	int subminor;
+	int retval = 0;
+
+	/* prevent races with disconnect */
+	mutex_lock(&driver_lock);
+
+	subminor = iminor(inode);
+	interface = usb_find_interface(&imon_driver, subminor);
+	if (!interface) {
+		err("%s: could not find interface for minor %d",
+		    __func__, subminor);
+		retval = -ENODEV;
+		goto exit;
+	}
+	ictx = usb_get_intfdata(interface);
+
+	if (!ictx) {
+		err("%s: no context found for minor %d", __func__, subminor);
+		retval = -ENODEV;
+		goto exit;
+	}
+
+	mutex_lock(&ictx->lock);
+
+	if (!ictx->display_supported) {
+		err("%s: display not supported by device", __func__);
+		retval = -ENODEV;
+	} else if (ictx->display_isopen) {
+		err("%s: display port is already open", __func__);
+		retval = -EBUSY;
+	} else {
+		ictx->display_isopen = 1;
+		file->private_data = ictx;
+		dev_dbg(ictx->dev, "display port opened\n");
+	}
+
+	mutex_unlock(&ictx->lock);
+
+exit:
+	mutex_unlock(&driver_lock);
+	return retval;
+}
+
+/**
+ * Called when the display device (e.g. /dev/lcd0)
+ * is closed by the application.
+ */
+static int display_close(struct inode *inode, struct file *file)
+{
+	struct imon_context *ictx = NULL;
+	int retval = 0;
+
+	ictx = (struct imon_context *)file->private_data;
+
+	if (!ictx) {
+		err("%s: no context for device", __func__);
+		return -ENODEV;
+	}
+
+	mutex_lock(&ictx->lock);
+
+	if (!ictx->display_supported) {
+		err("%s: display not supported by device", __func__);
+		retval = -ENODEV;
+	} else if (!ictx->display_isopen) {
+		err("%s: display is not open", __func__);
+		retval = -EIO;
+	} else {
+		ictx->display_isopen = 0;
+		dev_dbg(ictx->dev, "display port closed\n");
+		if (!ictx->dev_present_intf0) {
+			/*
+			 * Device disconnected before close and IR port is not
+			 * open. If IR port is open, context will be deleted by
+			 * ir_close.
+			 */
+			mutex_unlock(&ictx->lock);
+			free_imon_context(ictx);
+			return retval;
+		}
+	}
+
+	mutex_unlock(&ictx->lock);
+	return retval;
+}
+
+/**
+ * Sends a packet to the device -- this function must be called
+ * with ictx->lock held.
+ */
+static int send_packet(struct imon_context *ictx)
+{
+	unsigned int pipe;
+	unsigned long timeout;
+	int interval = 0;
+	int retval = 0;
+	struct usb_ctrlrequest *control_req = NULL;
+
+	/* Check if we need to use control or interrupt urb */
+	if (!ictx->tx_control) {
+		pipe = usb_sndintpipe(ictx->usbdev_intf0,
+				      ictx->tx_endpoint->bEndpointAddress);
+		interval = ictx->tx_endpoint->bInterval;
+
+		usb_fill_int_urb(ictx->tx_urb, ictx->usbdev_intf0, pipe,
+				 ictx->usb_tx_buf,
+				 sizeof(ictx->usb_tx_buf),
+				 usb_tx_callback, ictx, interval);
+
+		ictx->tx_urb->actual_length = 0;
+	} else {
+		/* fill request into kmalloc'ed space: */
+		control_req = kmalloc(sizeof(struct usb_ctrlrequest),
+				      GFP_KERNEL);
+		if (control_req == NULL)
+			return -ENOMEM;
+
+		/* setup packet is '21 09 0200 0001 0008' */
+		control_req->bRequestType = 0x21;
+		control_req->bRequest = 0x09;
+		control_req->wValue = cpu_to_le16(0x0200);
+		control_req->wIndex = cpu_to_le16(0x0001);
+		control_req->wLength = cpu_to_le16(0x0008);
+
+		/* control pipe is endpoint 0x00 */
+		pipe = usb_sndctrlpipe(ictx->usbdev_intf0, 0);
+
+		/* build the control urb */
+		usb_fill_control_urb(ictx->tx_urb, ictx->usbdev_intf0,
+				     pipe, (unsigned char *)control_req,
+				     ictx->usb_tx_buf,
+				     sizeof(ictx->usb_tx_buf),
+				     usb_tx_callback, ictx);
+		ictx->tx_urb->actual_length = 0;
+	}
+
+	init_completion(&ictx->tx.finished);
+	ictx->tx.busy = 1;
+	smp_rmb(); /* ensure later readers know we're busy */
+
+	retval = usb_submit_urb(ictx->tx_urb, GFP_KERNEL);
+	if (retval) {
+		ictx->tx.busy = 0;
+		smp_rmb(); /* ensure later readers know we're not busy */
+		err("%s: error submitting urb(%d)", __func__, retval);
+	} else {
+		/* Wait for transmission to complete (or abort) */
+		mutex_unlock(&ictx->lock);
+		retval = wait_for_completion_interruptible(
+				&ictx->tx.finished);
+		if (retval)
+			err("%s: task interrupted", __func__);
+		mutex_lock(&ictx->lock);
+
+		retval = ictx->tx.status;
+		if (retval)
+			err("%s: packet tx failed (%d)", __func__, retval);
+	}
+
+	kfree(control_req);
+
+	/*
+	 * Induce a mandatory 5ms delay before returning, as otherwise,
+	 * send_packet can get called so rapidly as to overwhelm the device,
+	 * particularly on faster systems and/or those with quirky usb.
+	 */
+	timeout = msecs_to_jiffies(5);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(timeout);
+
+	return retval;
+}
+
+/**
+ * Sends an associate packet to the iMON 2.4G.
+ *
+ * This might not be such a good idea, since it has an id collision with
+ * some versions of the "IR & VFD" combo. The only way to determine if it
+ * is an RF version is to look at the product description string. (Which
+ * we currently do not fetch).
+ */
+static int send_associate_24g(struct imon_context *ictx)
+{
+	int retval;
+	const unsigned char packet[8] = { 0x01, 0x00, 0x00, 0x00,
+					  0x00, 0x00, 0x00, 0x20 };
+
+	if (!ictx) {
+		err("%s: no context for device", __func__);
+		return -ENODEV;
+	}
+
+	if (!ictx->dev_present_intf0) {
+		err("%s: no iMON device present", __func__);
+		return -ENODEV;
+	}
+
+	memcpy(ictx->usb_tx_buf, packet, sizeof(packet));
+	retval = send_packet(ictx);
+
+	return retval;
+}
+
+/**
+ * Sends packets to setup and show clock on iMON display
+ *
+ * Arguments: year - last 2 digits of year, month - 1..12,
+ * day - 1..31, dow - day of the week (0-Sun...6-Sat),
+ * hour - 0..23, minute - 0..59, second - 0..59
+ */
+static int send_set_imon_clock(struct imon_context *ictx,
+			       unsigned int year, unsigned int month,
+			       unsigned int day, unsigned int dow,
+			       unsigned int hour, unsigned int minute,
+			       unsigned int second)
+{
+	unsigned char clock_enable_pkt[IMON_CLOCK_ENABLE_PACKETS][8];
+	int retval = 0;
+	int i;
+
+	if (!ictx) {
+		err("%s: no context for device", __func__);
+		return -ENODEV;
+	}
+
+	switch (ictx->display_type) {
+	case IMON_DISPLAY_TYPE_LCD:
+		clock_enable_pkt[0][0] = 0x80;
+		clock_enable_pkt[0][1] = year;
+		clock_enable_pkt[0][2] = month-1;
+		clock_enable_pkt[0][3] = day;
+		clock_enable_pkt[0][4] = hour;
+		clock_enable_pkt[0][5] = minute;
+		clock_enable_pkt[0][6] = second;
+
+		clock_enable_pkt[1][0] = 0x80;
+		clock_enable_pkt[1][1] = 0;
+		clock_enable_pkt[1][2] = 0;
+		clock_enable_pkt[1][3] = 0;
+		clock_enable_pkt[1][4] = 0;
+		clock_enable_pkt[1][5] = 0;
+		clock_enable_pkt[1][6] = 0;
+
+		if (ictx->product == 0xffdc) {
+			clock_enable_pkt[0][7] = 0x50;
+			clock_enable_pkt[1][7] = 0x51;
+		} else {
+			clock_enable_pkt[0][7] = 0x88;
+			clock_enable_pkt[1][7] = 0x8a;
+		}
+
+		break;
+
+	case IMON_DISPLAY_TYPE_VFD:
+		clock_enable_pkt[0][0] = year;
+		clock_enable_pkt[0][1] = month-1;
+		clock_enable_pkt[0][2] = day;
+		clock_enable_pkt[0][3] = dow;
+		clock_enable_pkt[0][4] = hour;
+		clock_enable_pkt[0][5] = minute;
+		clock_enable_pkt[0][6] = second;
+		clock_enable_pkt[0][7] = 0x40;
+
+		clock_enable_pkt[1][0] = 0;
+		clock_enable_pkt[1][1] = 0;
+		clock_enable_pkt[1][2] = 1;
+		clock_enable_pkt[1][3] = 0;
+		clock_enable_pkt[1][4] = 0;
+		clock_enable_pkt[1][5] = 0;
+		clock_enable_pkt[1][6] = 0;
+		clock_enable_pkt[1][7] = 0x42;
+
+		break;
+
+	default:
+		return -ENODEV;
+	}
+
+	for (i = 0; i < IMON_CLOCK_ENABLE_PACKETS; i++) {
+		memcpy(ictx->usb_tx_buf, clock_enable_pkt[i], 8);
+		retval = send_packet(ictx);
+		if (retval) {
+			err("%s: send_packet failed for packet %d",
+			    __func__, i);
+			break;
+		}
+	}
+
+	return retval;
+}
+
+/**
+ * These are the sysfs functions to handle the association on the iMON 2.4G LT.
+ */
+static ssize_t show_associate_remote(struct device *d,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct imon_context *ictx = dev_get_drvdata(d);
+
+	if (!ictx)
+		return -ENODEV;
+
+	mutex_lock(&ictx->lock);
+	if (ictx->rf_isassociating)
+		strcpy(buf, "associating\n");
+	else
+		strcpy(buf, "closed\n");
+
+	dev_info(d, "Visit http://www.lirc.org/html/imon-24g.html for "
+		 "instructions on how to associate your iMON 2.4G DT/LT "
+		 "remote\n");
+	mutex_unlock(&ictx->lock);
+	return strlen(buf);
+}
+
+static ssize_t store_associate_remote(struct device *d,
+				      struct device_attribute *attr,
+				      const char *buf, size_t count)
+{
+	struct imon_context *ictx;
+
+	ictx = dev_get_drvdata(d);
+
+	if (!ictx)
+		return -ENODEV;
+
+	mutex_lock(&ictx->lock);
+	ictx->rf_isassociating = 1;
+	send_associate_24g(ictx);
+	mutex_unlock(&ictx->lock);
+
+	return count;
+}
+
+/**
+ * sysfs functions to control internal imon clock
+ */
+static ssize_t show_imon_clock(struct device *d,
+			       struct device_attribute *attr, char *buf)
+{
+	struct imon_context *ictx = dev_get_drvdata(d);
+	size_t len;
+
+	if (!ictx)
+		return -ENODEV;
+
+	mutex_lock(&ictx->lock);
+
+	if (!ictx->display_supported) {
+		len = snprintf(buf, PAGE_SIZE, "Not supported.");
+	} else {
+		len = snprintf(buf, PAGE_SIZE,
+			"To set the clock on your iMON display:\n"
+			"# date \"+%%y %%m %%d %%w %%H %%M %%S\" > imon_clock\n"
+			"%s", ictx->display_isopen ?
+			"\nNOTE: imon device must be closed\n" : "");
+	}
+
+	mutex_unlock(&ictx->lock);
+
+	return len;
+}
+
+static ssize_t store_imon_clock(struct device *d,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct imon_context *ictx = dev_get_drvdata(d);
+	ssize_t retval;
+	unsigned int year, month, day, dow, hour, minute, second;
+
+	if (!ictx)
+		return -ENODEV;
+
+	mutex_lock(&ictx->lock);
+
+	if (!ictx->display_supported) {
+		retval = -ENODEV;
+		goto exit;
+	} else if (ictx->display_isopen) {
+		retval = -EBUSY;
+		goto exit;
+	}
+
+	if (sscanf(buf, "%u %u %u %u %u %u %u",	&year, &month, &day, &dow,
+		   &hour, &minute, &second) != 7) {
+		retval = -EINVAL;
+		goto exit;
+	}
+
+	if ((month < 1 || month > 12) ||
+	    (day < 1 || day > 31) || (dow > 6) ||
+	    (hour > 23) || (minute > 59) || (second > 59)) {
+		retval = -EINVAL;
+		goto exit;
+	}
+
+	retval = send_set_imon_clock(ictx, year, month, day, dow,
+				     hour, minute, second);
+	if (retval)
+		goto exit;
+
+	retval = count;
+exit:
+	mutex_unlock(&ictx->lock);
+
+	return retval;
+}
+
+
+static DEVICE_ATTR(imon_clock, S_IWUSR | S_IRUGO, show_imon_clock,
+		   store_imon_clock);
+
+static DEVICE_ATTR(associate_remote, S_IWUSR | S_IRUGO, show_associate_remote,
+		   store_associate_remote);
+
+static struct attribute *imon_display_sysfs_entries[] = {
+	&dev_attr_imon_clock.attr,
+	NULL
+};
+
+static struct attribute_group imon_display_attribute_group = {
+	.attrs = imon_display_sysfs_entries
+};
+
+static struct attribute *imon_rf_sysfs_entries[] = {
+	&dev_attr_associate_remote.attr,
+	NULL
+};
+
+static struct attribute_group imon_rf_attribute_group = {
+	.attrs = imon_rf_sysfs_entries
+};
+
+/**
+ * Writes data to the VFD.  The iMON VFD is 2x16 characters
+ * and requires data in 5 consecutive USB interrupt packets,
+ * each packet but the last carrying 7 bytes.
+ *
+ * I don't know if the VFD board supports features such as
+ * scrolling, clearing rows, blanking, etc. so at
+ * the caller must provide a full screen of data.  If fewer
+ * than 32 bytes are provided spaces will be appended to
+ * generate a full screen.
+ */
+static ssize_t vfd_write(struct file *file, const char *buf,
+			 size_t n_bytes, loff_t *pos)
+{
+	int i;
+	int offset;
+	int seq;
+	int retval = 0;
+	struct imon_context *ictx;
+	const unsigned char vfd_packet6[] = {
+		0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF };
+
+	ictx = (struct imon_context *)file->private_data;
+	if (!ictx) {
+		err("%s: no context for device", __func__);
+		return -ENODEV;
+	}
+
+	mutex_lock(&ictx->lock);
+
+	if (!ictx->dev_present_intf0) {
+		err("%s: no iMON device present", __func__);
+		retval = -ENODEV;
+		goto exit;
+	}
+
+	if (n_bytes <= 0 || n_bytes > 32) {
+		err("%s: invalid payload size", __func__);
+		retval = -EINVAL;
+		goto exit;
+	}
+
+	if (copy_from_user(ictx->tx.data_buf, buf, n_bytes)) {
+		retval = -EFAULT;
+		goto exit;
+	}
+
+	/* Pad with spaces */
+	for (i = n_bytes; i < 32; ++i)
+		ictx->tx.data_buf[i] = ' ';
+
+	for (i = 32; i < 35; ++i)
+		ictx->tx.data_buf[i] = 0xFF;
+
+	offset = 0;
+	seq = 0;
+
+	do {
+		memcpy(ictx->usb_tx_buf, ictx->tx.data_buf + offset, 7);
+		ictx->usb_tx_buf[7] = (unsigned char) seq;
+
+		retval = send_packet(ictx);
+		if (retval) {
+			err("%s: send packet failed for packet #%d",
+					__func__, seq/2);
+			goto exit;
+		} else {
+			seq += 2;
+			offset += 7;
+		}
+
+	} while (offset < 35);
+
+	/* Send packet #6 */
+	memcpy(ictx->usb_tx_buf, &vfd_packet6, sizeof(vfd_packet6));
+	ictx->usb_tx_buf[7] = (unsigned char) seq;
+	retval = send_packet(ictx);
+	if (retval)
+		err("%s: send packet failed for packet #%d",
+		    __func__, seq / 2);
+
+exit:
+	mutex_unlock(&ictx->lock);
+
+	return (!retval) ? n_bytes : retval;
+}
+
+/**
+ * Writes data to the LCD.  The iMON OEM LCD screen expects 8-byte
+ * packets. We accept data as 16 hexadecimal digits, followed by a
+ * newline (to make it easy to drive the device from a command-line
+ * -- even though the actual binary data is a bit complicated).
+ *
+ * The device itself is not a "traditional" text-mode display. It's
+ * actually a 16x96 pixel bitmap display. That means if you want to
+ * display text, you've got to have your own "font" and translate the
+ * text into bitmaps for display. This is really flexible (you can
+ * display whatever diacritics you need, and so on), but it's also
+ * a lot more complicated than most LCDs...
+ */
+static ssize_t lcd_write(struct file *file, const char *buf,
+			 size_t n_bytes, loff_t *pos)
+{
+	int retval = 0;
+	struct imon_context *ictx;
+
+	ictx = (struct imon_context *)file->private_data;
+	if (!ictx) {
+		err("%s: no context for device", __func__);
+		return -ENODEV;
+	}
+
+	mutex_lock(&ictx->lock);
+
+	if (!ictx->display_supported) {
+		err("%s: no iMON display present", __func__);
+		retval = -ENODEV;
+		goto exit;
+	}
+
+	if (n_bytes != 8) {
+		err("%s: invalid payload size: %d (expecting 8)",
+		    __func__, (int) n_bytes);
+		retval = -EINVAL;
+		goto exit;
+	}
+
+	if (copy_from_user(ictx->usb_tx_buf, buf, 8)) {
+		retval = -EFAULT;
+		goto exit;
+	}
+
+	retval = send_packet(ictx);
+	if (retval) {
+		err("%s: send packet failed!", __func__);
+		goto exit;
+	} else {
+		dev_dbg(ictx->dev, "%s: write %d bytes to LCD\n",
+			__func__, (int) n_bytes);
+	}
+exit:
+	mutex_unlock(&ictx->lock);
+	return (!retval) ? n_bytes : retval;
+}
+
+/**
+ * Callback function for USB core API: transmit data
+ */
+static void usb_tx_callback(struct urb *urb)
+{
+	struct imon_context *ictx;
+
+	if (!urb)
+		return;
+	ictx = (struct imon_context *)urb->context;
+	if (!ictx)
+		return;
+
+	ictx->tx.status = urb->status;
+
+	/* notify waiters that write has finished */
+	ictx->tx.busy = 0;
+	smp_rmb(); /* ensure later readers know we're not busy */
+	complete(&ictx->tx.finished);
+}
+
+/**
+ * mce/rc6 keypresses have no distinct release code, use timer
+ */
+static void imon_mce_timeout(unsigned long data)
+{
+	struct imon_context *ictx = (struct imon_context *)data;
+
+	input_report_key(ictx->idev, ictx->last_keycode, 0);
+	input_sync(ictx->idev);
+}
+
+/**
+ * report touchscreen input
+ */
+static void imon_touch_display_timeout(unsigned long data)
+{
+	struct imon_context *ictx = (struct imon_context *)data;
+
+	if (ictx->display_type != IMON_DISPLAY_TYPE_VGA)
+		return;
+
+	input_report_abs(ictx->touch, ABS_X, ictx->touch_x);
+	input_report_abs(ictx->touch, ABS_Y, ictx->touch_y);
+	input_report_key(ictx->touch, BTN_TOUCH, 0x00);
+	input_sync(ictx->touch);
+}
+
+/**
+ * iMON IR receivers support two different signal sets -- those used by
+ * the iMON remotes, and those used by the Windows MCE remotes (which is
+ * really just RC-6), but only one or the other at a time, as the signals
+ * are decoded onboard the receiver.
+ */
+int imon_ir_change_protocol(void *priv, u64 ir_type)
+{
+	int retval;
+	struct imon_context *ictx = priv;
+	struct device *dev = ictx->dev;
+	bool pad_mouse;
+	unsigned char ir_proto_packet[] = {
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 };
+
+	if (ir_type && !(ir_type & ictx->props->allowed_protos))
+		dev_warn(dev, "Looks like you're trying to use an IR protocol "
+			 "this device does not support\n");
+
+	switch (ir_type) {
+	case IR_TYPE_RC6:
+		dev_dbg(dev, "Configuring IR receiver for MCE protocol\n");
+		ir_proto_packet[0] = 0x01;
+		pad_mouse = false;
+		init_timer(&ictx->itimer);
+		ictx->itimer.data = (unsigned long)ictx;
+		ictx->itimer.function = imon_mce_timeout;
+		break;
+	case IR_TYPE_UNKNOWN:
+	case IR_TYPE_OTHER:
+		dev_dbg(dev, "Configuring IR receiver for iMON protocol\n");
+		if (pad_stabilize)
+			pad_mouse = true;
+		else {
+			dev_dbg(dev, "PAD stabilize functionality disabled\n");
+			pad_mouse = false;
+		}
+		/* ir_proto_packet[0] = 0x00; // already the default */
+		ir_type = IR_TYPE_OTHER;
+		break;
+	default:
+		dev_warn(dev, "Unsupported IR protocol specified, overriding "
+			 "to iMON IR protocol\n");
+		if (pad_stabilize)
+			pad_mouse = true;
+		else {
+			dev_dbg(dev, "PAD stabilize functionality disabled\n");
+			pad_mouse = false;
+		}
+		/* ir_proto_packet[0] = 0x00; // already the default */
+		ir_type = IR_TYPE_OTHER;
+		break;
+	}
+
+	memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet));
+
+	retval = send_packet(ictx);
+	if (retval)
+		goto out;
+
+	ictx->ir_type = ir_type;
+	ictx->pad_mouse = pad_mouse;
+
+out:
+	return retval;
+}
+
+static inline int tv2int(const struct timeval *a, const struct timeval *b)
+{
+	int usecs = 0;
+	int sec   = 0;
+
+	if (b->tv_usec > a->tv_usec) {
+		usecs = 1000000;
+		sec--;
+	}
+
+	usecs += a->tv_usec - b->tv_usec;
+
+	sec += a->tv_sec - b->tv_sec;
+	sec *= 1000;
+	usecs /= 1000;
+	sec += usecs;
+
+	if (sec < 0)
+		sec = 1000;
+
+	return sec;
+}
+
+/**
+ * The directional pad behaves a bit differently, depending on whether this is
+ * one of the older ffdc devices or a newer device. Newer devices appear to
+ * have a higher resolution matrix for more precise mouse movement, but it
+ * makes things overly sensitive in keyboard mode, so we do some interesting
+ * contortions to make it less touchy. Older devices run through the same
+ * routine with shorter timeout and a smaller threshold.
+ */
+static int stabilize(int a, int b, u16 timeout, u16 threshold)
+{
+	struct timeval ct;
+	static struct timeval prev_time = {0, 0};
+	static struct timeval hit_time  = {0, 0};
+	static int x, y, prev_result, hits;
+	int result = 0;
+	int msec, msec_hit;
+
+	do_gettimeofday(&ct);
+	msec = tv2int(&ct, &prev_time);
+	msec_hit = tv2int(&ct, &hit_time);
+
+	if (msec > 100) {
+		x = 0;
+		y = 0;
+		hits = 0;
+	}
+
+	x += a;
+	y += b;
+
+	prev_time = ct;
+
+	if (abs(x) > threshold || abs(y) > threshold) {
+		if (abs(y) > abs(x))
+			result = (y > 0) ? 0x7F : 0x80;
+		else
+			result = (x > 0) ? 0x7F00 : 0x8000;
+
+		x = 0;
+		y = 0;
+
+		if (result == prev_result) {
+			hits++;
+
+			if (hits > 3) {
+				switch (result) {
+				case 0x7F:
+					y = 17 * threshold / 30;
+					break;
+				case 0x80:
+					y -= 17 * threshold / 30;
+					break;
+				case 0x7F00:
+					x = 17 * threshold / 30;
+					break;
+				case 0x8000:
+					x -= 17 * threshold / 30;
+					break;
+				}
+			}
+
+			if (hits == 2 && msec_hit < timeout) {
+				result = 0;
+				hits = 1;
+			}
+		} else {
+			prev_result = result;
+			hits = 1;
+			hit_time = ct;
+		}
+	}
+
+	return result;
+}
+
+static u32 imon_remote_key_lookup(struct imon_context *ictx, u32 hw_code)
+{
+	u32 scancode = be32_to_cpu(hw_code);
+	u32 keycode;
+	u32 release;
+	bool is_release_code = false;
+
+	/* Look for the initial press of a button */
+	keycode = ir_g_keycode_from_table(ictx->idev, scancode);
+
+	/* Look for the release of a button */
+	if (keycode == KEY_RESERVED) {
+		release = scancode & ~0x4000;
+		keycode = ir_g_keycode_from_table(ictx->idev, release);
+		if (keycode != KEY_RESERVED)
+			is_release_code = true;
+	}
+
+	ictx->release_code = is_release_code;
+
+	return keycode;
+}
+
+static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 hw_code)
+{
+	u32 scancode = be32_to_cpu(hw_code);
+	u32 keycode;
+
+#define MCE_KEY_MASK 0x7000
+#define MCE_TOGGLE_BIT 0x8000
+
+	/*
+	 * On some receivers, mce keys decode to 0x8000f04xx and 0x8000f84xx
+	 * (the toggle bit flipping between alternating key presses), while
+	 * on other receivers, we see 0x8000f74xx and 0x8000ff4xx. To keep
+	 * the table trim, we always or in the bits to look up 0x8000ff4xx,
+	 * but we can't or them into all codes, as some keys are decoded in
+	 * a different way w/o the same use of the toggle bit...
+	 */
+	if ((scancode >> 24) & 0x80)
+		scancode = scancode | MCE_KEY_MASK | MCE_TOGGLE_BIT;
+
+	keycode = ir_g_keycode_from_table(ictx->idev, scancode);
+
+	return keycode;
+}
+
+static u32 imon_panel_key_lookup(u64 hw_code)
+{
+	int i;
+	u64 code = be64_to_cpu(hw_code);
+	u32 keycode = KEY_RESERVED;
+
+	for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) {
+		if (imon_panel_key_table[i].hw_code == (code | 0xffee)) {
+			keycode = imon_panel_key_table[i].keycode;
+			break;
+		}
+	}
+
+	return keycode;
+}
+
+static bool imon_mouse_event(struct imon_context *ictx,
+			     unsigned char *buf, int len)
+{
+	char rel_x = 0x00, rel_y = 0x00;
+	u8 right_shift = 1;
+	bool mouse_input = 1;
+	int dir = 0;
+
+	/* newer iMON device PAD or mouse button */
+	if (ictx->product != 0xffdc && (buf[0] & 0x01) && len == 5) {
+		rel_x = buf[2];
+		rel_y = buf[3];
+		right_shift = 1;
+	/* 0xffdc iMON PAD or mouse button input */
+	} else if (ictx->product == 0xffdc && (buf[0] & 0x40) &&
+			!((buf[1] & 0x01) || ((buf[1] >> 2) & 0x01))) {
+		rel_x = (buf[1] & 0x08) | (buf[1] & 0x10) >> 2 |
+			(buf[1] & 0x20) >> 4 | (buf[1] & 0x40) >> 6;
+		if (buf[0] & 0x02)
+			rel_x |= ~0x0f;
+		rel_x = rel_x + rel_x / 2;
+		rel_y = (buf[2] & 0x08) | (buf[2] & 0x10) >> 2 |
+			(buf[2] & 0x20) >> 4 | (buf[2] & 0x40) >> 6;
+		if (buf[0] & 0x01)
+			rel_y |= ~0x0f;
+		rel_y = rel_y + rel_y / 2;
+		right_shift = 2;
+	/* some ffdc devices decode mouse buttons differently... */
+	} else if (ictx->product == 0xffdc && (buf[0] == 0x68)) {
+		right_shift = 2;
+	/* ch+/- buttons, which we use for an emulated scroll wheel */
+	} else if (ictx->kc == KEY_CHANNELUP && (buf[2] & 0x40) != 0x40) {
+		dir = 1;
+	} else if (ictx->kc == KEY_CHANNELDOWN && (buf[2] & 0x40) != 0x40) {
+		dir = -1;
+	} else
+		mouse_input = 0;
+
+	if (mouse_input) {
+		dev_dbg(ictx->dev, "sending mouse data via input subsystem\n");
+
+		if (dir) {
+			input_report_rel(ictx->idev, REL_WHEEL, dir);
+		} else if (rel_x || rel_y) {
+			input_report_rel(ictx->idev, REL_X, rel_x);
+			input_report_rel(ictx->idev, REL_Y, rel_y);
+		} else {
+			input_report_key(ictx->idev, BTN_LEFT, buf[1] & 0x1);
+			input_report_key(ictx->idev, BTN_RIGHT,
+					 buf[1] >> right_shift & 0x1);
+		}
+		input_sync(ictx->idev);
+		ictx->last_keycode = ictx->kc;
+	}
+
+	return mouse_input;
+}
+
+static void imon_touch_event(struct imon_context *ictx, unsigned char *buf)
+{
+	mod_timer(&ictx->ttimer, jiffies + TOUCH_TIMEOUT);
+	ictx->touch_x = (buf[0] << 4) | (buf[1] >> 4);
+	ictx->touch_y = 0xfff - ((buf[2] << 4) | (buf[1] & 0xf));
+	input_report_abs(ictx->touch, ABS_X, ictx->touch_x);
+	input_report_abs(ictx->touch, ABS_Y, ictx->touch_y);
+	input_report_key(ictx->touch, BTN_TOUCH, 0x01);
+	input_sync(ictx->touch);
+}
+
+static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
+{
+	int dir = 0;
+	char rel_x = 0x00, rel_y = 0x00;
+	u16 timeout, threshold;
+	u64 temp_key;
+	u32 remote_key;
+
+	/*
+	 * The imon directional pad functions more like a touchpad. Bytes 3 & 4
+	 * contain a position coordinate (x,y), with each component ranging
+	 * from -14 to 14. We want to down-sample this to only 4 discrete values
+	 * for up/down/left/right arrow keys. Also, when you get too close to
+	 * diagonals, it has a tendancy to jump back and forth, so lets try to
+	 * ignore when they get too close.
+	 */
+	if (ictx->product != 0xffdc) {
+		/* first, pad to 8 bytes so it conforms with everything else */
+		buf[5] = buf[6] = buf[7] = 0;
+		timeout = 500;	/* in msecs */
+		/* (2*threshold) x (2*threshold) square */
+		threshold = pad_thresh ? pad_thresh : 28;
+		rel_x = buf[2];
+		rel_y = buf[3];
+
+		if (ictx->ir_type == IR_TYPE_OTHER && pad_stabilize) {
+			if ((buf[1] == 0) && ((rel_x != 0) || (rel_y != 0))) {
+				dir = stabilize((int)rel_x, (int)rel_y,
+						timeout, threshold);
+				if (!dir) {
+					ictx->kc = KEY_UNKNOWN;
+					return;
+				}
+				buf[2] = dir & 0xFF;
+				buf[3] = (dir >> 8) & 0xFF;
+				memcpy(&temp_key, buf, sizeof(temp_key));
+				remote_key = (u32) (le64_to_cpu(temp_key)
+						    & 0xffffffff);
+				ictx->kc = imon_remote_key_lookup(ictx,
+								  remote_key);
+			}
+		} else {
+			if (abs(rel_y) > abs(rel_x)) {
+				buf[2] = (rel_y > 0) ? 0x7F : 0x80;
+				buf[3] = 0;
+				ictx->kc = (rel_y > 0) ? KEY_DOWN : KEY_UP;
+			} else {
+				buf[2] = 0;
+				buf[3] = (rel_x > 0) ? 0x7F : 0x80;
+				ictx->kc = (rel_x > 0) ? KEY_RIGHT : KEY_LEFT;
+			}
+		}
+
+	/*
+	 * Handle on-board decoded pad events for e.g. older VFD/iMON-Pad
+	 * device (15c2:ffdc). The remote generates various codes from
+	 * 0x68nnnnB7 to 0x6AnnnnB7, the left mouse button generates
+	 * 0x688301b7 and the right one 0x688481b7. All other keys generate
+	 * 0x2nnnnnnn. Position coordinate is encoded in buf[1] and buf[2] with
+	 * reversed endianess. Extract direction from buffer, rotate endianess,
+	 * adjust sign and feed the values into stabilize(). The resulting codes
+	 * will be 0x01008000, 0x01007F00, which match the newer devices.
+	 */
+	} else {
+		timeout = 10;	/* in msecs */
+		/* (2*threshold) x (2*threshold) square */
+		threshold = pad_thresh ? pad_thresh : 15;
+
+		/* buf[1] is x */
+		rel_x = (buf[1] & 0x08) | (buf[1] & 0x10) >> 2 |
+			(buf[1] & 0x20) >> 4 | (buf[1] & 0x40) >> 6;
+		if (buf[0] & 0x02)
+			rel_x |= ~0x10+1;
+		/* buf[2] is y */
+		rel_y = (buf[2] & 0x08) | (buf[2] & 0x10) >> 2 |
+			(buf[2] & 0x20) >> 4 | (buf[2] & 0x40) >> 6;
+		if (buf[0] & 0x01)
+			rel_y |= ~0x10+1;
+
+		buf[0] = 0x01;
+		buf[1] = buf[4] = buf[5] = buf[6] = buf[7] = 0;
+
+		if (ictx->ir_type == IR_TYPE_OTHER && pad_stabilize) {
+			dir = stabilize((int)rel_x, (int)rel_y,
+					timeout, threshold);
+			if (!dir) {
+				ictx->kc = KEY_UNKNOWN;
+				return;
+			}
+			buf[2] = dir & 0xFF;
+			buf[3] = (dir >> 8) & 0xFF;
+			memcpy(&temp_key, buf, sizeof(temp_key));
+			remote_key = (u32) (le64_to_cpu(temp_key) & 0xffffffff);
+			ictx->kc = imon_remote_key_lookup(ictx, remote_key);
+		} else {
+			if (abs(rel_y) > abs(rel_x)) {
+				buf[2] = (rel_y > 0) ? 0x7F : 0x80;
+				buf[3] = 0;
+				ictx->kc = (rel_y > 0) ? KEY_DOWN : KEY_UP;
+			} else {
+				buf[2] = 0;
+				buf[3] = (rel_x > 0) ? 0x7F : 0x80;
+				ictx->kc = (rel_x > 0) ? KEY_RIGHT : KEY_LEFT;
+			}
+		}
+	}
+}
+
+static int imon_parse_press_type(struct imon_context *ictx,
+				 unsigned char *buf, u8 ktype)
+{
+	int press_type = 0;
+	int rep_delay = ictx->idev->rep[REP_DELAY];
+	int rep_period = ictx->idev->rep[REP_PERIOD];
+
+	/* key release of 0x02XXXXXX key */
+	if (ictx->kc == KEY_RESERVED && buf[0] == 0x02 && buf[3] == 0x00)
+		ictx->kc = ictx->last_keycode;
+
+	/* mouse button release on (some) 0xffdc devices */
+	else if (ictx->kc == KEY_RESERVED && buf[0] == 0x68 && buf[1] == 0x82 &&
+		 buf[2] == 0x81 && buf[3] == 0xb7)
+		ictx->kc = ictx->last_keycode;
+
+	/* mouse button release on (some other) 0xffdc devices */
+	else if (ictx->kc == KEY_RESERVED && buf[0] == 0x01 && buf[1] == 0x00 &&
+		 buf[2] == 0x81 && buf[3] == 0xb7)
+		ictx->kc = ictx->last_keycode;
+
+	/* mce-specific button handling */
+	else if (ktype == IMON_KEY_MCE) {
+		/* initial press */
+		if (ictx->kc != ictx->last_keycode
+		    || buf[2] != ictx->mce_toggle_bit) {
+			ictx->last_keycode = ictx->kc;
+			ictx->mce_toggle_bit = buf[2];
+			press_type = 1;
+			mod_timer(&ictx->itimer,
+				  jiffies + msecs_to_jiffies(rep_delay));
+		/* repeat */
+		} else {
+			press_type = 2;
+			mod_timer(&ictx->itimer,
+				  jiffies + msecs_to_jiffies(rep_period));
+		}
+
+	/* incoherent or irrelevant data */
+	} else if (ictx->kc == KEY_RESERVED)
+		press_type = -EINVAL;
+
+	/* key release of 0xXXXXXXb7 key */
+	else if (ictx->release_code)
+		press_type = 0;
+
+	/* this is a button press */
+	else
+		press_type = 1;
+
+	return press_type;
+}
+
+/**
+ * Process the incoming packet
+ */
+static void imon_incoming_packet(struct imon_context *ictx,
+				 struct urb *urb, int intf)
+{
+	int len = urb->actual_length;
+	unsigned char *buf = urb->transfer_buffer;
+	struct device *dev = ictx->dev;
+	u32 kc;
+	bool norelease = 0;
+	int i;
+	u64 temp_key;
+	u64 panel_key = 0;
+	u32 remote_key = 0;
+	struct input_dev *idev = NULL;
+	int press_type = 0;
+	int msec;
+	struct timeval t;
+	static struct timeval prev_time = { 0, 0 };
+	u8 ktype = IMON_KEY_IMON;
+
+	idev = ictx->idev;
+
+	/* filter out junk data on the older 0xffdc imon devices */
+	if ((buf[0] == 0xff) && (buf[7] == 0xff))
+		return;
+
+	/* Figure out what key was pressed */
+	memcpy(&temp_key, buf, sizeof(temp_key));
+	if (len == 8 && buf[7] == 0xee) {
+		ktype = IMON_KEY_PANEL;
+		panel_key = le64_to_cpu(temp_key);
+		kc = imon_panel_key_lookup(panel_key);
+	} else {
+		remote_key = (u32) (le64_to_cpu(temp_key) & 0xffffffff);
+		if (ictx->ir_type == IR_TYPE_RC6) {
+			if (buf[0] == 0x80)
+				ktype = IMON_KEY_MCE;
+			kc = imon_mce_key_lookup(ictx, remote_key);
+		} else
+			kc = imon_remote_key_lookup(ictx, remote_key);
+	}
+
+	/* keyboard/mouse mode toggle button */
+	if (kc == KEY_KEYBOARD && !ictx->release_code) {
+		ictx->last_keycode = kc;
+		if (!nomouse) {
+			ictx->pad_mouse = ~(ictx->pad_mouse) & 0x1;
+			dev_dbg(dev, "toggling to %s mode\n",
+				ictx->pad_mouse ? "mouse" : "keyboard");
+			return;
+		} else {
+			ictx->pad_mouse = 0;
+			dev_dbg(dev, "mouse mode disabled, passing key value\n");
+		}
+	}
+
+	ictx->kc = kc;
+
+	/* send touchscreen events through input subsystem if touchpad data */
+	if (ictx->display_type == IMON_DISPLAY_TYPE_VGA && len == 8 &&
+	    buf[7] == 0x86) {
+		imon_touch_event(ictx, buf);
+
+	/* look for mouse events with pad in mouse mode */
+	} else if (ictx->pad_mouse) {
+		if (imon_mouse_event(ictx, buf, len))
+			return;
+	}
+
+	/* Now for some special handling to convert pad input to arrow keys */
+	if (((len == 5) && (buf[0] == 0x01) && (buf[4] == 0x00)) ||
+	    ((len == 8) && (buf[0] & 0x40) &&
+	     !(buf[1] & 0x1 || buf[1] >> 2 & 0x1))) {
+		len = 8;
+		imon_pad_to_keys(ictx, buf);
+		norelease = 1;
+	}
+
+	if (debug) {
+		printk(KERN_INFO "intf%d decoded packet: ", intf);
+		for (i = 0; i < len; ++i)
+			printk("%02x ", buf[i]);
+		printk("\n");
+	}
+
+	press_type = imon_parse_press_type(ictx, buf, ktype);
+	if (press_type < 0)
+		goto not_input_data;
+
+	if (ictx->kc == KEY_UNKNOWN)
+		goto unknown_key;
+
+	/* KEY_MUTE repeats from MCE and knob need to be suppressed */
+	if ((ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode)
+	    && (buf[7] == 0xee || ktype == IMON_KEY_MCE)) {
+		do_gettimeofday(&t);
+		msec = tv2int(&t, &prev_time);
+		prev_time = t;
+		if (msec < idev->rep[REP_DELAY])
+			return;
+	}
+
+	input_report_key(idev, ictx->kc, press_type);
+	input_sync(idev);
+
+	/* panel keys and some remote keys don't generate a release */
+	if (panel_key || norelease) {
+		input_report_key(idev, ictx->kc, 0);
+		input_sync(idev);
+	}
+
+	ictx->last_keycode = ictx->kc;
+
+	return;
+
+unknown_key:
+	dev_info(dev, "%s: unknown keypress, code 0x%llx\n", __func__,
+		 (panel_key ? be64_to_cpu(panel_key) :
+			      be32_to_cpu(remote_key)));
+	return;
+
+not_input_data:
+	if (len != 8) {
+		dev_warn(dev, "imon %s: invalid incoming packet "
+			 "size (len = %d, intf%d)\n", __func__, len, intf);
+		return;
+	}
+
+	/* iMON 2.4G associate frame */
+	if (buf[0] == 0x00 &&
+	    buf[2] == 0xFF &&				/* REFID */
+	    buf[3] == 0xFF &&
+	    buf[4] == 0xFF &&
+	    buf[5] == 0xFF &&				/* iMON 2.4G */
+	   ((buf[6] == 0x4E && buf[7] == 0xDF) ||	/* LT */
+	    (buf[6] == 0x5E && buf[7] == 0xDF))) {	/* DT */
+		dev_warn(dev, "%s: remote associated refid=%02X\n",
+			 __func__, buf[1]);
+		ictx->rf_isassociating = 0;
+	}
+}
+
+/**
+ * Callback function for USB core API: receive data
+ */
+static void usb_rx_callback_intf0(struct urb *urb)
+{
+	struct imon_context *ictx;
+	int intfnum = 0;
+
+	if (!urb)
+		return;
+
+	ictx = (struct imon_context *)urb->context;
+	if (!ictx)
+		return;
+
+	switch (urb->status) {
+	case -ENOENT:		/* usbcore unlink successful! */
+		return;
+
+	case -ESHUTDOWN:	/* transport endpoint was shut down */
+		break;
+
+	case 0:
+		imon_incoming_packet(ictx, urb, intfnum);
+		break;
+
+	default:
+		dev_warn(ictx->dev, "imon %s: status(%d): ignored\n",
+			 __func__, urb->status);
+		break;
+	}
+
+	usb_submit_urb(ictx->rx_urb_intf0, GFP_ATOMIC);
+}
+
+static void usb_rx_callback_intf1(struct urb *urb)
+{
+	struct imon_context *ictx;
+	int intfnum = 1;
+
+	if (!urb)
+		return;
+
+	ictx = (struct imon_context *)urb->context;
+	if (!ictx)
+		return;
+
+	switch (urb->status) {
+	case -ENOENT:		/* usbcore unlink successful! */
+		return;
+
+	case -ESHUTDOWN:	/* transport endpoint was shut down */
+		break;
+
+	case 0:
+		imon_incoming_packet(ictx, urb, intfnum);
+		break;
+
+	default:
+		dev_warn(ictx->dev, "imon %s: status(%d): ignored\n",
+			 __func__, urb->status);
+		break;
+	}
+
+	usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC);
+}
+
+static struct input_dev *imon_init_idev(struct imon_context *ictx)
+{
+	struct input_dev *idev;
+	struct ir_dev_props *props;
+	struct ir_input_dev *ir;
+	int ret, i;
+
+	idev = input_allocate_device();
+	if (!idev) {
+		dev_err(ictx->dev, "remote input dev allocation failed\n");
+		goto idev_alloc_failed;
+	}
+
+	props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL);
+	if (!props) {
+		dev_err(ictx->dev, "remote ir dev props allocation failed\n");
+		goto props_alloc_failed;
+	}
+
+	ir = kzalloc(sizeof(struct ir_input_dev), GFP_KERNEL);
+	if (!ir) {
+		dev_err(ictx->dev, "remote ir input dev allocation failed\n");
+		goto ir_dev_alloc_failed;
+	}
+
+	snprintf(ictx->name_idev, sizeof(ictx->name_idev),
+		 "iMON Remote (%04x:%04x)", ictx->vendor, ictx->product);
+	idev->name = ictx->name_idev;
+
+	usb_make_path(ictx->usbdev_intf0, ictx->phys_idev,
+		      sizeof(ictx->phys_idev));
+	strlcat(ictx->phys_idev, "/input0", sizeof(ictx->phys_idev));
+	idev->phys = ictx->phys_idev;
+
+	idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | BIT_MASK(EV_REL);
+
+	idev->keybit[BIT_WORD(BTN_MOUSE)] =
+		BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
+	idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y) |
+		BIT_MASK(REL_WHEEL);
+
+	/* panel and/or knob code support */
+	for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) {
+		u32 kc = imon_panel_key_table[i].keycode;
+		__set_bit(kc, idev->keybit);
+	}
+
+	props->priv = ictx;
+	props->driver_type = RC_DRIVER_SCANCODE;
+	/* IR_TYPE_OTHER maps to iMON PAD remote, IR_TYPE_RC6 to MCE remote */
+	props->allowed_protos = IR_TYPE_OTHER | IR_TYPE_RC6;
+	props->change_protocol = imon_ir_change_protocol;
+	ictx->props = props;
+
+	ictx->ir = ir;
+	memcpy(&ir->dev, ictx->dev, sizeof(struct device));
+
+	usb_to_input_id(ictx->usbdev_intf0, &idev->id);
+	idev->dev.parent = ictx->dev;
+
+	input_set_drvdata(idev, ir);
+
+	ret = ir_input_register(idev, RC_MAP_IMON_PAD, props, MOD_NAME);
+	if (ret < 0) {
+		dev_err(ictx->dev, "remote input dev register failed\n");
+		goto idev_register_failed;
+	}
+
+	return idev;
+
+idev_register_failed:
+	kfree(ir);
+ir_dev_alloc_failed:
+	kfree(props);
+props_alloc_failed:
+	input_free_device(idev);
+idev_alloc_failed:
+
+	return NULL;
+}
+
+static struct input_dev *imon_init_touch(struct imon_context *ictx)
+{
+	struct input_dev *touch;
+	int ret;
+
+	touch = input_allocate_device();
+	if (!touch) {
+		dev_err(ictx->dev, "touchscreen input dev allocation failed\n");
+		goto touch_alloc_failed;
+	}
+
+	snprintf(ictx->name_touch, sizeof(ictx->name_touch),
+		 "iMON USB Touchscreen (%04x:%04x)",
+		 ictx->vendor, ictx->product);
+	touch->name = ictx->name_touch;
+
+	usb_make_path(ictx->usbdev_intf1, ictx->phys_touch,
+		      sizeof(ictx->phys_touch));
+	strlcat(ictx->phys_touch, "/input1", sizeof(ictx->phys_touch));
+	touch->phys = ictx->phys_touch;
+
+	touch->evbit[0] =
+		BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	touch->keybit[BIT_WORD(BTN_TOUCH)] =
+		BIT_MASK(BTN_TOUCH);
+	input_set_abs_params(touch, ABS_X,
+			     0x00, 0xfff, 0, 0);
+	input_set_abs_params(touch, ABS_Y,
+			     0x00, 0xfff, 0, 0);
+
+	input_set_drvdata(touch, ictx);
+
+	usb_to_input_id(ictx->usbdev_intf1, &touch->id);
+	touch->dev.parent = ictx->dev;
+	ret = input_register_device(touch);
+	if (ret <  0) {
+		dev_info(ictx->dev, "touchscreen input dev register failed\n");
+		goto touch_register_failed;
+	}
+
+	return touch;
+
+touch_register_failed:
+	input_free_device(ictx->touch);
+
+touch_alloc_failed:
+	return NULL;
+}
+
+static bool imon_find_endpoints(struct imon_context *ictx,
+				struct usb_host_interface *iface_desc)
+{
+	struct usb_endpoint_descriptor *ep;
+	struct usb_endpoint_descriptor *rx_endpoint = NULL;
+	struct usb_endpoint_descriptor *tx_endpoint = NULL;
+	int ifnum = iface_desc->desc.bInterfaceNumber;
+	int num_endpts = iface_desc->desc.bNumEndpoints;
+	int i, ep_dir, ep_type;
+	bool ir_ep_found = 0;
+	bool display_ep_found = 0;
+	bool tx_control = 0;
+
+	/*
+	 * Scan the endpoint list and set:
+	 *	first input endpoint = IR endpoint
+	 *	first output endpoint = display endpoint
+	 */
+	for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) {
+		ep = &iface_desc->endpoint[i].desc;
+		ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
+		ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+		if (!ir_ep_found && ep_dir == USB_DIR_IN &&
+		    ep_type == USB_ENDPOINT_XFER_INT) {
+
+			rx_endpoint = ep;
+			ir_ep_found = 1;
+			dev_dbg(ictx->dev, "%s: found IR endpoint\n", __func__);
+
+		} else if (!display_ep_found && ep_dir == USB_DIR_OUT &&
+			   ep_type == USB_ENDPOINT_XFER_INT) {
+			tx_endpoint = ep;
+			display_ep_found = 1;
+			dev_dbg(ictx->dev, "%s: found display endpoint\n", __func__);
+		}
+	}
+
+	if (ifnum == 0) {
+		ictx->rx_endpoint_intf0 = rx_endpoint;
+		/*
+		 * tx is used to send characters to lcd/vfd, associate RF
+		 * remotes, set IR protocol, and maybe more...
+		 */
+		ictx->tx_endpoint = tx_endpoint;
+	} else {
+		ictx->rx_endpoint_intf1 = rx_endpoint;
+	}
+
+	/*
+	 * If we didn't find a display endpoint, this is probably one of the
+	 * newer iMON devices that use control urb instead of interrupt
+	 */
+	if (!display_ep_found) {
+		tx_control = 1;
+		display_ep_found = 1;
+		dev_dbg(ictx->dev, "%s: device uses control endpoint, not "
+			"interface OUT endpoint\n", __func__);
+	}
+
+	/*
+	 * Some iMON receivers have no display. Unfortunately, it seems
+	 * that SoundGraph recycles device IDs between devices both with
+	 * and without... :\
+	 */
+	if (ictx->display_type == IMON_DISPLAY_TYPE_NONE) {
+		display_ep_found = 0;
+		dev_dbg(ictx->dev, "%s: device has no display\n", __func__);
+	}
+
+	/*
+	 * iMON Touch devices have a VGA touchscreen, but no "display", as
+	 * that refers to e.g. /dev/lcd0 (a character device LCD or VFD).
+	 */
+	if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) {
+		display_ep_found = 0;
+		dev_dbg(ictx->dev, "%s: iMON Touch device found\n", __func__);
+	}
+
+	/* Input endpoint is mandatory */
+	if (!ir_ep_found)
+		err("%s: no valid input (IR) endpoint found.", __func__);
+
+	ictx->tx_control = tx_control;
+
+	if (display_ep_found)
+		ictx->display_supported = true;
+
+	return ir_ep_found;
+
+}
+
+static struct imon_context *imon_init_intf0(struct usb_interface *intf)
+{
+	struct imon_context *ictx;
+	struct urb *rx_urb;
+	struct urb *tx_urb;
+	struct device *dev = &intf->dev;
+	struct usb_host_interface *iface_desc;
+	int ret = -ENOMEM;
+
+	ictx = kzalloc(sizeof(struct imon_context), GFP_KERNEL);
+	if (!ictx) {
+		dev_err(dev, "%s: kzalloc failed for context", __func__);
+		goto exit;
+	}
+	rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!rx_urb) {
+		dev_err(dev, "%s: usb_alloc_urb failed for IR urb", __func__);
+		goto rx_urb_alloc_failed;
+	}
+	tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!tx_urb) {
+		dev_err(dev, "%s: usb_alloc_urb failed for display urb",
+			__func__);
+		goto tx_urb_alloc_failed;
+	}
+
+	mutex_init(&ictx->lock);
+
+	mutex_lock(&ictx->lock);
+
+	ictx->dev = dev;
+	ictx->usbdev_intf0 = usb_get_dev(interface_to_usbdev(intf));
+	ictx->dev_present_intf0 = 1;
+	ictx->rx_urb_intf0 = rx_urb;
+	ictx->tx_urb = tx_urb;
+
+	ictx->vendor  = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor);
+	ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct);
+
+	ret = -ENODEV;
+	iface_desc = intf->cur_altsetting;
+	if (!imon_find_endpoints(ictx, iface_desc)) {
+		goto find_endpoint_failed;
+	}
+
+	ictx->idev = imon_init_idev(ictx);
+	if (!ictx->idev) {
+		dev_err(dev, "%s: input device setup failed\n", __func__);
+		goto idev_setup_failed;
+	}
+
+	usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0,
+		usb_rcvintpipe(ictx->usbdev_intf0,
+			ictx->rx_endpoint_intf0->bEndpointAddress),
+		ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf),
+		usb_rx_callback_intf0, ictx,
+		ictx->rx_endpoint_intf0->bInterval);
+
+	ret = usb_submit_urb(ictx->rx_urb_intf0, GFP_KERNEL);
+	if (ret) {
+		err("%s: usb_submit_urb failed for intf0 (%d)",
+		    __func__, ret);
+		goto urb_submit_failed;
+	}
+
+	return ictx;
+
+urb_submit_failed:
+	input_unregister_device(ictx->idev);
+	input_free_device(ictx->idev);
+idev_setup_failed:
+find_endpoint_failed:
+	mutex_unlock(&ictx->lock);
+	usb_free_urb(tx_urb);
+tx_urb_alloc_failed:
+	usb_free_urb(rx_urb);
+rx_urb_alloc_failed:
+	kfree(ictx);
+exit:
+	dev_err(dev, "unable to initialize intf0, err %d\n", ret);
+
+	return NULL;
+}
+
+static struct imon_context *imon_init_intf1(struct usb_interface *intf,
+					    struct imon_context *ictx)
+{
+	struct urb *rx_urb;
+	struct usb_host_interface *iface_desc;
+	int ret = -ENOMEM;
+
+	rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!rx_urb) {
+		err("%s: usb_alloc_urb failed for IR urb", __func__);
+		goto rx_urb_alloc_failed;
+	}
+
+	mutex_lock(&ictx->lock);
+
+	if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) {
+		init_timer(&ictx->ttimer);
+		ictx->ttimer.data = (unsigned long)ictx;
+		ictx->ttimer.function = imon_touch_display_timeout;
+	}
+
+	ictx->usbdev_intf1 = usb_get_dev(interface_to_usbdev(intf));
+	ictx->dev_present_intf1 = 1;
+	ictx->rx_urb_intf1 = rx_urb;
+
+	ret = -ENODEV;
+	iface_desc = intf->cur_altsetting;
+	if (!imon_find_endpoints(ictx, iface_desc))
+		goto find_endpoint_failed;
+
+	if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) {
+		ictx->touch = imon_init_touch(ictx);
+		if (!ictx->touch)
+			goto touch_setup_failed;
+	} else
+		ictx->touch = NULL;
+
+	usb_fill_int_urb(ictx->rx_urb_intf1, ictx->usbdev_intf1,
+		usb_rcvintpipe(ictx->usbdev_intf1,
+			ictx->rx_endpoint_intf1->bEndpointAddress),
+		ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf),
+		usb_rx_callback_intf1, ictx,
+		ictx->rx_endpoint_intf1->bInterval);
+
+	ret = usb_submit_urb(ictx->rx_urb_intf1, GFP_KERNEL);
+
+	if (ret) {
+		err("%s: usb_submit_urb failed for intf1 (%d)",
+		    __func__, ret);
+		goto urb_submit_failed;
+	}
+
+	return ictx;
+
+urb_submit_failed:
+	if (ictx->touch) {
+		input_unregister_device(ictx->touch);
+		input_free_device(ictx->touch);
+	}
+touch_setup_failed:
+find_endpoint_failed:
+	mutex_unlock(&ictx->lock);
+	usb_free_urb(rx_urb);
+rx_urb_alloc_failed:
+	dev_err(ictx->dev, "unable to initialize intf0, err %d\n", ret);
+
+	return NULL;
+}
+
+/*
+ * The 0x15c2:0xffdc device ID was used for umpteen different imon
+ * devices, and all of them constantly spew interrupts, even when there
+ * is no actual data to report. However, byte 6 of this buffer looks like
+ * its unique across device variants, so we're trying to key off that to
+ * figure out which display type (if any) and what IR protocol the device
+ * actually supports. These devices have their IR protocol hard-coded into
+ * their firmware, they can't be changed on the fly like the newer hardware.
+ */
+static void imon_get_ffdc_type(struct imon_context *ictx)
+{
+	u8 ffdc_cfg_byte = ictx->usb_rx_buf[6];
+	u8 detected_display_type = IMON_DISPLAY_TYPE_NONE;
+	u64 allowed_protos = IR_TYPE_OTHER;
+
+	switch (ffdc_cfg_byte) {
+	/* iMON Knob, no display, iMON IR + vol knob */
+	case 0x21:
+		dev_info(ictx->dev, "0xffdc iMON Knob, iMON IR");
+		ictx->display_supported = false;
+		break;
+	/* iMON VFD, no IR (does have vol knob tho) */
+	case 0x35:
+		dev_info(ictx->dev, "0xffdc iMON VFD + knob, no IR");
+		detected_display_type = IMON_DISPLAY_TYPE_VFD;
+		break;
+	/* iMON VFD, iMON IR */
+	case 0x24:
+	case 0x85:
+		dev_info(ictx->dev, "0xffdc iMON VFD, iMON IR");
+		detected_display_type = IMON_DISPLAY_TYPE_VFD;
+		break;
+	/* iMON LCD, MCE IR */
+	case 0x9f:
+		dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR");
+		detected_display_type = IMON_DISPLAY_TYPE_LCD;
+		allowed_protos = IR_TYPE_RC6;
+		break;
+	default:
+		dev_info(ictx->dev, "Unknown 0xffdc device, "
+			 "defaulting to VFD and iMON IR");
+		detected_display_type = IMON_DISPLAY_TYPE_VFD;
+		break;
+	}
+
+	printk(KERN_CONT " (id 0x%02x)\n", ffdc_cfg_byte);
+
+	ictx->display_type = detected_display_type;
+	ictx->props->allowed_protos = allowed_protos;
+	ictx->ir_type = allowed_protos;
+}
+
+static void imon_set_display_type(struct imon_context *ictx,
+				  struct usb_interface *intf)
+{
+	u8 configured_display_type = IMON_DISPLAY_TYPE_VFD;
+
+	/*
+	 * Try to auto-detect the type of display if the user hasn't set
+	 * it by hand via the display_type modparam. Default is VFD.
+	 */
+
+	if (display_type == IMON_DISPLAY_TYPE_AUTO) {
+		switch (ictx->product) {
+		case 0xffdc:
+			/* set in imon_get_ffdc_type() */
+			configured_display_type = ictx->display_type;
+			break;
+		case 0x0034:
+		case 0x0035:
+			configured_display_type = IMON_DISPLAY_TYPE_VGA;
+			break;
+		case 0x0038:
+		case 0x0039:
+		case 0x0045:
+			configured_display_type = IMON_DISPLAY_TYPE_LCD;
+			break;
+		case 0x003c:
+		case 0x0041:
+		case 0x0042:
+		case 0x0043:
+			configured_display_type = IMON_DISPLAY_TYPE_NONE;
+			ictx->display_supported = false;
+			break;
+		case 0x0036:
+		case 0x0044:
+		default:
+			configured_display_type = IMON_DISPLAY_TYPE_VFD;
+			break;
+		}
+	} else {
+		configured_display_type = display_type;
+		if (display_type == IMON_DISPLAY_TYPE_NONE)
+			ictx->display_supported = false;
+		else
+			ictx->display_supported = true;
+		dev_info(ictx->dev, "%s: overriding display type to %d via "
+			 "modparam\n", __func__, display_type);
+	}
+
+	ictx->display_type = configured_display_type;
+}
+
+static void imon_init_display(struct imon_context *ictx,
+			      struct usb_interface *intf)
+{
+	int ret;
+
+	dev_dbg(ictx->dev, "Registering iMON display with sysfs\n");
+
+	/* set up sysfs entry for built-in clock */
+	ret = sysfs_create_group(&intf->dev.kobj,
+				 &imon_display_attribute_group);
+	if (ret)
+		dev_err(ictx->dev, "Could not create display sysfs "
+			"entries(%d)", ret);
+
+	if (ictx->display_type == IMON_DISPLAY_TYPE_LCD)
+		ret = usb_register_dev(intf, &imon_lcd_class);
+	else
+		ret = usb_register_dev(intf, &imon_vfd_class);
+	if (ret)
+		/* Not a fatal error, so ignore */
+		dev_info(ictx->dev, "could not get a minor number for "
+			 "display\n");
+
+}
+
+/**
+ * Callback function for USB core API: Probe
+ */
+static int __devinit imon_probe(struct usb_interface *interface,
+				const struct usb_device_id *id)
+{
+	struct usb_device *usbdev = NULL;
+	struct usb_host_interface *iface_desc = NULL;
+	struct usb_interface *first_if;
+	struct device *dev = &interface->dev;
+	int ifnum, code_length, sysfs_err;
+	int ret = 0;
+	struct imon_context *ictx = NULL;
+	struct imon_context *first_if_ctx = NULL;
+	u16 vendor, product;
+	const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00,
+					    0x00, 0x00, 0x00, 0x88 };
+
+	code_length = BUF_CHUNK_SIZE * 8;
+
+	usbdev     = usb_get_dev(interface_to_usbdev(interface));
+	iface_desc = interface->cur_altsetting;
+	ifnum      = iface_desc->desc.bInterfaceNumber;
+	vendor     = le16_to_cpu(usbdev->descriptor.idVendor);
+	product    = le16_to_cpu(usbdev->descriptor.idProduct);
+
+	dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n",
+		__func__, vendor, product, ifnum);
+
+	/* prevent races probing devices w/multiple interfaces */
+	mutex_lock(&driver_lock);
+
+	first_if = usb_ifnum_to_if(usbdev, 0);
+	first_if_ctx = (struct imon_context *)usb_get_intfdata(first_if);
+
+	if (ifnum == 0) {
+		ictx = imon_init_intf0(interface);
+		if (!ictx) {
+			err("%s: failed to initialize context!\n", __func__);
+			ret = -ENODEV;
+			goto fail;
+		}
+
+		if (product == 0xffdc) {
+			/* RF products *also* use 0xffdc... sigh... */
+			sysfs_err = sysfs_create_group(&interface->dev.kobj,
+						       &imon_rf_attribute_group);
+			if (sysfs_err)
+				err("%s: Could not create RF sysfs entries(%d)",
+				    __func__, sysfs_err);
+		}
+
+	} else {
+	/* this is the secondary interface on the device */
+		ictx = imon_init_intf1(interface, first_if_ctx);
+		if (!ictx) {
+			err("%s: failed to attach to context!\n", __func__);
+			ret = -ENODEV;
+			goto fail;
+		}
+
+	}
+
+	usb_set_intfdata(interface, ictx);
+
+	if (ifnum == 0) {
+		/* Enable front-panel buttons and/or knobs */
+		memcpy(ictx->usb_tx_buf, &fp_packet, sizeof(fp_packet));
+		ret = send_packet(ictx);
+		/* Not fatal, but warn about it */
+		if (ret)
+			dev_info(dev, "failed to enable panel buttons "
+				 "and/or knobs\n");
+
+		if (product == 0xffdc)
+			imon_get_ffdc_type(ictx);
+
+		imon_set_display_type(ictx, interface);
+
+		if (ictx->display_supported)
+			imon_init_display(ictx, interface);
+	}
+
+	/* set IR protocol/remote type */
+	ret = imon_ir_change_protocol(ictx, ictx->ir_type);
+	if (ret) {
+		dev_warn(dev, "%s: failed to set IR protocol, falling back "
+			 "to standard iMON protocol mode\n", __func__);
+		ictx->ir_type = IR_TYPE_OTHER;
+	}
+
+	dev_info(dev, "iMON device (%04x:%04x, intf%d) on "
+		 "usb<%d:%d> initialized\n", vendor, product, ifnum,
+		 usbdev->bus->busnum, usbdev->devnum);
+
+	mutex_unlock(&ictx->lock);
+	mutex_unlock(&driver_lock);
+
+	return 0;
+
+fail:
+	mutex_unlock(&driver_lock);
+	dev_err(dev, "unable to register, err %d\n", ret);
+
+	return ret;
+}
+
+/**
+ * Callback function for USB core API: disconnect
+ */
+static void __devexit imon_disconnect(struct usb_interface *interface)
+{
+	struct imon_context *ictx;
+	struct device *dev;
+	int ifnum;
+
+	/* prevent races with multi-interface device probing and display_open */
+	mutex_lock(&driver_lock);
+
+	ictx = usb_get_intfdata(interface);
+	dev = ictx->dev;
+	ifnum = interface->cur_altsetting->desc.bInterfaceNumber;
+
+	mutex_lock(&ictx->lock);
+
+	/*
+	 * sysfs_remove_group is safe to call even if sysfs_create_group
+	 * hasn't been called
+	 */
+	sysfs_remove_group(&interface->dev.kobj,
+			   &imon_display_attribute_group);
+	sysfs_remove_group(&interface->dev.kobj,
+			   &imon_rf_attribute_group);
+
+	usb_set_intfdata(interface, NULL);
+
+	/* Abort ongoing write */
+	if (ictx->tx.busy) {
+		usb_kill_urb(ictx->tx_urb);
+		complete_all(&ictx->tx.finished);
+	}
+
+	if (ifnum == 0) {
+		ictx->dev_present_intf0 = 0;
+		usb_kill_urb(ictx->rx_urb_intf0);
+		input_unregister_device(ictx->idev);
+		if (ictx->display_supported) {
+			if (ictx->display_type == IMON_DISPLAY_TYPE_LCD)
+				usb_deregister_dev(interface, &imon_lcd_class);
+			else
+				usb_deregister_dev(interface, &imon_vfd_class);
+		}
+	} else {
+		ictx->dev_present_intf1 = 0;
+		usb_kill_urb(ictx->rx_urb_intf1);
+		if (ictx->display_type == IMON_DISPLAY_TYPE_VGA)
+			input_unregister_device(ictx->touch);
+	}
+
+	if (!ictx->dev_present_intf0 && !ictx->dev_present_intf1) {
+		if (ictx->display_type == IMON_DISPLAY_TYPE_VGA)
+			del_timer_sync(&ictx->ttimer);
+		mutex_unlock(&ictx->lock);
+		if (!ictx->display_isopen)
+			free_imon_context(ictx);
+	} else {
+		if (ictx->ir_type == IR_TYPE_RC6)
+			del_timer_sync(&ictx->itimer);
+		mutex_unlock(&ictx->lock);
+	}
+
+	mutex_unlock(&driver_lock);
+
+	dev_dbg(dev, "%s: iMON device (intf%d) disconnected\n",
+		__func__, ifnum);
+}
+
+static int imon_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct imon_context *ictx = usb_get_intfdata(intf);
+	int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
+
+	if (ifnum == 0)
+		usb_kill_urb(ictx->rx_urb_intf0);
+	else
+		usb_kill_urb(ictx->rx_urb_intf1);
+
+	return 0;
+}
+
+static int imon_resume(struct usb_interface *intf)
+{
+	int rc = 0;
+	struct imon_context *ictx = usb_get_intfdata(intf);
+	int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
+
+	if (ifnum == 0) {
+		usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0,
+			usb_rcvintpipe(ictx->usbdev_intf0,
+				ictx->rx_endpoint_intf0->bEndpointAddress),
+			ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf),
+			usb_rx_callback_intf0, ictx,
+			ictx->rx_endpoint_intf0->bInterval);
+
+		rc = usb_submit_urb(ictx->rx_urb_intf0, GFP_ATOMIC);
+
+	} else {
+		usb_fill_int_urb(ictx->rx_urb_intf1, ictx->usbdev_intf1,
+			usb_rcvintpipe(ictx->usbdev_intf1,
+				ictx->rx_endpoint_intf1->bEndpointAddress),
+			ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf),
+			usb_rx_callback_intf1, ictx,
+			ictx->rx_endpoint_intf1->bInterval);
+
+		rc = usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC);
+	}
+
+	return rc;
+}
+
+static int __init imon_init(void)
+{
+	int rc;
+
+	rc = usb_register(&imon_driver);
+	if (rc) {
+		err("%s: usb register failed(%d)", __func__, rc);
+		rc = -ENODEV;
+	}
+
+	return rc;
+}
+
+static void __exit imon_exit(void)
+{
+	usb_deregister(&imon_driver);
+}
+
+module_init(imon_init);
+module_exit(imon_exit);
diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/IR/ir-core-priv.h
new file mode 100644
index 0000000..9a5e65a
--- /dev/null
+++ b/drivers/media/IR/ir-core-priv.h
@@ -0,0 +1,126 @@
+/*
+ * Remote Controller core raw events header
+ *
+ * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+
+#ifndef _IR_RAW_EVENT
+#define _IR_RAW_EVENT
+
+#include <linux/slab.h>
+#include <media/ir-core.h>
+
+struct ir_raw_handler {
+	struct list_head list;
+
+	int (*decode)(struct input_dev *input_dev, struct ir_raw_event event);
+	int (*raw_register)(struct input_dev *input_dev);
+	int (*raw_unregister)(struct input_dev *input_dev);
+};
+
+struct ir_raw_event_ctrl {
+	struct work_struct		rx_work;	/* for the rx decoding workqueue */
+	struct kfifo			kfifo;		/* fifo for the pulse/space durations */
+	ktime_t				last_event;	/* when last event occurred */
+	enum raw_event_type		last_type;	/* last event type */
+	struct input_dev		*input_dev;	/* pointer to the parent input_dev */
+};
+
+/* macros for IR decoders */
+static inline bool geq_margin(unsigned d1, unsigned d2, unsigned margin)
+{
+	return d1 > (d2 - margin);
+}
+
+static inline bool eq_margin(unsigned d1, unsigned d2, unsigned margin)
+{
+	return ((d1 > (d2 - margin)) && (d1 < (d2 + margin)));
+}
+
+static inline bool is_transition(struct ir_raw_event *x, struct ir_raw_event *y)
+{
+	return x->pulse != y->pulse;
+}
+
+static inline void decrease_duration(struct ir_raw_event *ev, unsigned duration)
+{
+	if (duration > ev->duration)
+		ev->duration = 0;
+	else
+		ev->duration -= duration;
+}
+
+#define TO_US(duration)			(((duration) + 500) / 1000)
+#define TO_STR(is_pulse)		((is_pulse) ? "pulse" : "space")
+#define IS_RESET(ev)			(ev.duration == 0)
+
+/*
+ * Routines from ir-sysfs.c - Meant to be called only internally inside
+ * ir-core
+ */
+
+int ir_register_class(struct input_dev *input_dev);
+void ir_unregister_class(struct input_dev *input_dev);
+
+/*
+ * Routines from ir-raw-event.c to be used internally and by decoders
+ */
+int ir_raw_event_register(struct input_dev *input_dev);
+void ir_raw_event_unregister(struct input_dev *input_dev);
+int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler);
+void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler);
+void ir_raw_init(void);
+
+
+/*
+ * Decoder initialization code
+ *
+ * Those load logic are called during ir-core init, and automatically
+ * loads the compiled decoders for their usage with IR raw events
+ */
+
+/* from ir-nec-decoder.c */
+#ifdef CONFIG_IR_NEC_DECODER_MODULE
+#define load_nec_decode()	request_module("ir-nec-decoder")
+#else
+#define load_nec_decode()	0
+#endif
+
+/* from ir-rc5-decoder.c */
+#ifdef CONFIG_IR_RC5_DECODER_MODULE
+#define load_rc5_decode()	request_module("ir-rc5-decoder")
+#else
+#define load_rc5_decode()	0
+#endif
+
+/* from ir-rc6-decoder.c */
+#ifdef CONFIG_IR_RC6_DECODER_MODULE
+#define load_rc6_decode()	request_module("ir-rc6-decoder")
+#else
+#define load_rc6_decode()	0
+#endif
+
+/* from ir-jvc-decoder.c */
+#ifdef CONFIG_IR_JVC_DECODER_MODULE
+#define load_jvc_decode()	request_module("ir-jvc-decoder")
+#else
+#define load_jvc_decode()	0
+#endif
+
+/* from ir-sony-decoder.c */
+#ifdef CONFIG_IR_SONY_DECODER_MODULE
+#define load_sony_decode()	request_module("ir-sony-decoder")
+#else
+#define load_sony_decode()	0
+#endif
+
+#endif /* _IR_RAW_EVENT */
diff --git a/drivers/media/IR/ir-functions.c b/drivers/media/IR/ir-functions.c
index ab06919..db591e4 100644
--- a/drivers/media/IR/ir-functions.c
+++ b/drivers/media/IR/ir-functions.c
@@ -24,6 +24,7 @@
 #include <linux/string.h>
 #include <linux/jiffies.h>
 #include <media/ir-common.h>
+#include "ir-core-priv.h"
 
 /* -------------------------------------------------------------------------- */
 
diff --git a/drivers/media/IR/ir-jvc-decoder.c b/drivers/media/IR/ir-jvc-decoder.c
new file mode 100644
index 0000000..0b80494
--- /dev/null
+++ b/drivers/media/IR/ir-jvc-decoder.c
@@ -0,0 +1,320 @@
+/* ir-jvc-decoder.c - handle JVC IR Pulse/Space protocol
+ *
+ * Copyright (C) 2010 by David Härdeman <david@hardeman.nu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/bitrev.h>
+#include "ir-core-priv.h"
+
+#define JVC_NBITS		16		/* dev(8) + func(8) */
+#define JVC_UNIT		525000		/* ns */
+#define JVC_HEADER_PULSE	(16 * JVC_UNIT) /* lack of header -> repeat */
+#define JVC_HEADER_SPACE	(8  * JVC_UNIT)
+#define JVC_BIT_PULSE		(1  * JVC_UNIT)
+#define JVC_BIT_0_SPACE		(1  * JVC_UNIT)
+#define JVC_BIT_1_SPACE		(3  * JVC_UNIT)
+#define JVC_TRAILER_PULSE	(1  * JVC_UNIT)
+#define	JVC_TRAILER_SPACE	(35 * JVC_UNIT)
+
+/* Used to register jvc_decoder clients */
+static LIST_HEAD(decoder_list);
+DEFINE_SPINLOCK(decoder_lock);
+
+enum jvc_state {
+	STATE_INACTIVE,
+	STATE_HEADER_SPACE,
+	STATE_BIT_PULSE,
+	STATE_BIT_SPACE,
+	STATE_TRAILER_PULSE,
+	STATE_TRAILER_SPACE,
+};
+
+struct decoder_data {
+	struct list_head	list;
+	struct ir_input_dev	*ir_dev;
+	int			enabled:1;
+
+	/* State machine control */
+	enum jvc_state		state;
+	u16			jvc_bits;
+	u16			jvc_old_bits;
+	unsigned		count;
+	bool			first;
+	bool			toggle;
+};
+
+
+/**
+ * get_decoder_data()	- gets decoder data
+ * @input_dev:	input device
+ *
+ * Returns the struct decoder_data that corresponds to a device
+ */
+static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
+{
+	struct decoder_data *data = NULL;
+
+	spin_lock(&decoder_lock);
+	list_for_each_entry(data, &decoder_list, list) {
+		if (data->ir_dev == ir_dev)
+			break;
+	}
+	spin_unlock(&decoder_lock);
+	return data;
+}
+
+static ssize_t store_enabled(struct device *d,
+			     struct device_attribute *mattr,
+			     const char *buf,
+			     size_t len)
+{
+	unsigned long value;
+	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
+	struct decoder_data *data = get_decoder_data(ir_dev);
+
+	if (!data)
+		return -EINVAL;
+
+	if (strict_strtoul(buf, 10, &value) || value > 1)
+		return -EINVAL;
+
+	data->enabled = value;
+
+	return len;
+}
+
+static ssize_t show_enabled(struct device *d,
+			     struct device_attribute *mattr, char *buf)
+{
+	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
+	struct decoder_data *data = get_decoder_data(ir_dev);
+
+	if (!data)
+		return -EINVAL;
+
+	if (data->enabled)
+		return sprintf(buf, "1\n");
+	else
+	return sprintf(buf, "0\n");
+}
+
+static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
+
+static struct attribute *decoder_attributes[] = {
+	&dev_attr_enabled.attr,
+	NULL
+};
+
+static struct attribute_group decoder_attribute_group = {
+	.name	= "jvc_decoder",
+	.attrs	= decoder_attributes,
+};
+
+/**
+ * ir_jvc_decode() - Decode one JVC pulse or space
+ * @input_dev:	the struct input_dev descriptor of the device
+ * @duration:   the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This function returns -EINVAL if the pulse violates the state machine
+ */
+static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+{
+	struct decoder_data *data;
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+
+	data = get_decoder_data(ir_dev);
+	if (!data)
+		return -EINVAL;
+
+	if (!data->enabled)
+		return 0;
+
+	if (IS_RESET(ev)) {
+		data->state = STATE_INACTIVE;
+		return 0;
+	}
+
+	if (!geq_margin(ev.duration, JVC_UNIT, JVC_UNIT / 2))
+		goto out;
+
+	IR_dprintk(2, "JVC decode started at state %d (%uus %s)\n",
+		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+
+	switch (data->state) {
+
+	case STATE_INACTIVE:
+		if (!ev.pulse)
+			break;
+
+		if (!eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2))
+			break;
+
+		data->count = 0;
+		data->first = true;
+		data->toggle = !data->toggle;
+		data->state = STATE_HEADER_SPACE;
+		return 0;
+
+	case STATE_HEADER_SPACE:
+		if (ev.pulse)
+			break;
+
+		if (!eq_margin(ev.duration, JVC_HEADER_SPACE, JVC_UNIT / 2))
+			break;
+
+		data->state = STATE_BIT_PULSE;
+		return 0;
+
+	case STATE_BIT_PULSE:
+		if (!ev.pulse)
+			break;
+
+		if (!eq_margin(ev.duration, JVC_BIT_PULSE, JVC_UNIT / 2))
+			break;
+
+		data->state = STATE_BIT_SPACE;
+		return 0;
+
+	case STATE_BIT_SPACE:
+		if (ev.pulse)
+			break;
+
+		data->jvc_bits <<= 1;
+		if (eq_margin(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) {
+			data->jvc_bits |= 1;
+			decrease_duration(&ev, JVC_BIT_1_SPACE);
+		} else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2))
+			decrease_duration(&ev, JVC_BIT_0_SPACE);
+		else
+			break;
+		data->count++;
+
+		if (data->count == JVC_NBITS)
+			data->state = STATE_TRAILER_PULSE;
+		else
+			data->state = STATE_BIT_PULSE;
+		return 0;
+
+	case STATE_TRAILER_PULSE:
+		if (!ev.pulse)
+			break;
+
+		if (!eq_margin(ev.duration, JVC_TRAILER_PULSE, JVC_UNIT / 2))
+			break;
+
+		data->state = STATE_TRAILER_SPACE;
+		return 0;
+
+	case STATE_TRAILER_SPACE:
+		if (ev.pulse)
+			break;
+
+		if (!geq_margin(ev.duration, JVC_TRAILER_SPACE, JVC_UNIT / 2))
+			break;
+
+		if (data->first) {
+			u32 scancode;
+			scancode = (bitrev8((data->jvc_bits >> 8) & 0xff) << 8) |
+				   (bitrev8((data->jvc_bits >> 0) & 0xff) << 0);
+			IR_dprintk(1, "JVC scancode 0x%04x\n", scancode);
+			ir_keydown(input_dev, scancode, data->toggle);
+			data->first = false;
+			data->jvc_old_bits = data->jvc_bits;
+		} else if (data->jvc_bits == data->jvc_old_bits) {
+			IR_dprintk(1, "JVC repeat\n");
+			ir_repeat(input_dev);
+		} else {
+			IR_dprintk(1, "JVC invalid repeat msg\n");
+			break;
+		}
+
+		data->count = 0;
+		data->state = STATE_BIT_PULSE;
+		return 0;
+	}
+
+out:
+	IR_dprintk(1, "JVC decode failed at state %d (%uus %s)\n",
+		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+	data->state = STATE_INACTIVE;
+	return -EINVAL;
+}
+
+static int ir_jvc_register(struct input_dev *input_dev)
+{
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+	struct decoder_data *data;
+	int rc;
+
+	rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+	if (rc < 0)
+		return rc;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+		return -ENOMEM;
+	}
+
+	data->ir_dev = ir_dev;
+	data->enabled = 1;
+
+	spin_lock(&decoder_lock);
+	list_add_tail(&data->list, &decoder_list);
+	spin_unlock(&decoder_lock);
+
+	return 0;
+}
+
+static int ir_jvc_unregister(struct input_dev *input_dev)
+{
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+	static struct decoder_data *data;
+
+	data = get_decoder_data(ir_dev);
+	if (!data)
+		return 0;
+
+	sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+
+	spin_lock(&decoder_lock);
+	list_del(&data->list);
+	spin_unlock(&decoder_lock);
+
+	return 0;
+}
+
+static struct ir_raw_handler jvc_handler = {
+	.decode		= ir_jvc_decode,
+	.raw_register	= ir_jvc_register,
+	.raw_unregister	= ir_jvc_unregister,
+};
+
+static int __init ir_jvc_decode_init(void)
+{
+	ir_raw_handler_register(&jvc_handler);
+
+	printk(KERN_INFO "IR JVC protocol handler initialized\n");
+	return 0;
+}
+
+static void __exit ir_jvc_decode_exit(void)
+{
+	ir_raw_handler_unregister(&jvc_handler);
+}
+
+module_init(ir_jvc_decode_init);
+module_exit(ir_jvc_decode_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");
+MODULE_DESCRIPTION("JVC IR protocol decoder");
diff --git a/drivers/media/IR/ir-keymaps.c b/drivers/media/IR/ir-keymaps.c
deleted file mode 100644
index 0efdefe..0000000
--- a/drivers/media/IR/ir-keymaps.c
+++ /dev/null
@@ -1,3494 +0,0 @@
-/*
-    Keytables for supported remote controls, used on drivers/media
-    devices.
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-/*
- * NOTICE FOR DEVELOPERS:
- *   The IR mappings should be as close as possible to what's
- *   specified at:
- *      http://linuxtv.org/wiki/index.php/Remote_Controllers
- */
-#include <linux/module.h>
-
-#include <linux/input.h>
-#include <media/ir-common.h>
-
-/* empty keytable, can be used as placeholder for not-yet created keytables */
-static struct ir_scancode ir_codes_empty[] = {
-	{ 0x2a, KEY_COFFEE },
-};
-
-struct ir_scancode_table ir_codes_empty_table = {
-	.scan = ir_codes_empty,
-	.size = ARRAY_SIZE(ir_codes_empty),
-};
-EXPORT_SYMBOL_GPL(ir_codes_empty_table);
-
-/* Michal Majchrowicz <mmajchrowicz@gmail.com> */
-static struct ir_scancode ir_codes_proteus_2309[] = {
-	/* numeric */
-	{ 0x00, KEY_0 },
-	{ 0x01, KEY_1 },
-	{ 0x02, KEY_2 },
-	{ 0x03, KEY_3 },
-	{ 0x04, KEY_4 },
-	{ 0x05, KEY_5 },
-	{ 0x06, KEY_6 },
-	{ 0x07, KEY_7 },
-	{ 0x08, KEY_8 },
-	{ 0x09, KEY_9 },
-
-	{ 0x5c, KEY_POWER },		/* power       */
-	{ 0x20, KEY_ZOOM },		/* full screen */
-	{ 0x0f, KEY_BACKSPACE },	/* recall      */
-	{ 0x1b, KEY_ENTER },		/* mute        */
-	{ 0x41, KEY_RECORD },		/* record      */
-	{ 0x43, KEY_STOP },		/* stop        */
-	{ 0x16, KEY_S },
-	{ 0x1a, KEY_POWER2 },		/* off         */
-	{ 0x2e, KEY_RED },
-	{ 0x1f, KEY_CHANNELDOWN },	/* channel -   */
-	{ 0x1c, KEY_CHANNELUP },	/* channel +   */
-	{ 0x10, KEY_VOLUMEDOWN },	/* volume -    */
-	{ 0x1e, KEY_VOLUMEUP },		/* volume +    */
-	{ 0x14, KEY_F1 },
-};
-
-struct ir_scancode_table ir_codes_proteus_2309_table = {
-	.scan = ir_codes_proteus_2309,
-	.size = ARRAY_SIZE(ir_codes_proteus_2309),
-};
-EXPORT_SYMBOL_GPL(ir_codes_proteus_2309_table);
-
-/* Matt Jesson <dvb@jesson.eclipse.co.uk */
-static struct ir_scancode ir_codes_avermedia_dvbt[] = {
-	{ 0x28, KEY_0 },		/* '0' / 'enter' */
-	{ 0x22, KEY_1 },		/* '1' */
-	{ 0x12, KEY_2 },		/* '2' / 'up arrow' */
-	{ 0x32, KEY_3 },		/* '3' */
-	{ 0x24, KEY_4 },		/* '4' / 'left arrow' */
-	{ 0x14, KEY_5 },		/* '5' */
-	{ 0x34, KEY_6 },		/* '6' / 'right arrow' */
-	{ 0x26, KEY_7 },		/* '7' */
-	{ 0x16, KEY_8 },		/* '8' / 'down arrow' */
-	{ 0x36, KEY_9 },		/* '9' */
-
-	{ 0x20, KEY_LIST },		/* 'source' */
-	{ 0x10, KEY_TEXT },		/* 'teletext' */
-	{ 0x00, KEY_POWER },		/* 'power' */
-	{ 0x04, KEY_AUDIO },		/* 'audio' */
-	{ 0x06, KEY_ZOOM },		/* 'full screen' */
-	{ 0x18, KEY_VIDEO },		/* 'display' */
-	{ 0x38, KEY_SEARCH },		/* 'loop' */
-	{ 0x08, KEY_INFO },		/* 'preview' */
-	{ 0x2a, KEY_REWIND },		/* 'backward <<' */
-	{ 0x1a, KEY_FASTFORWARD },	/* 'forward >>' */
-	{ 0x3a, KEY_RECORD },		/* 'capture' */
-	{ 0x0a, KEY_MUTE },		/* 'mute' */
-	{ 0x2c, KEY_RECORD },		/* 'record' */
-	{ 0x1c, KEY_PAUSE },		/* 'pause' */
-	{ 0x3c, KEY_STOP },		/* 'stop' */
-	{ 0x0c, KEY_PLAY },		/* 'play' */
-	{ 0x2e, KEY_RED },		/* 'red' */
-	{ 0x01, KEY_BLUE },		/* 'blue' / 'cancel' */
-	{ 0x0e, KEY_YELLOW },		/* 'yellow' / 'ok' */
-	{ 0x21, KEY_GREEN },		/* 'green' */
-	{ 0x11, KEY_CHANNELDOWN },	/* 'channel -' */
-	{ 0x31, KEY_CHANNELUP },	/* 'channel +' */
-	{ 0x1e, KEY_VOLUMEDOWN },	/* 'volume -' */
-	{ 0x3e, KEY_VOLUMEUP },		/* 'volume +' */
-};
-
-struct ir_scancode_table ir_codes_avermedia_dvbt_table = {
-	.scan = ir_codes_avermedia_dvbt,
-	.size = ARRAY_SIZE(ir_codes_avermedia_dvbt),
-};
-EXPORT_SYMBOL_GPL(ir_codes_avermedia_dvbt_table);
-
-/* Mauro Carvalho Chehab <mchehab@infradead.org> */
-static struct ir_scancode ir_codes_avermedia_m135a[] = {
-	{ 0x00, KEY_POWER2 },
-	{ 0x2e, KEY_DOT },		/* '.' */
-	{ 0x01, KEY_MODE },		/* TV/FM */
-
-	{ 0x05, KEY_1 },
-	{ 0x06, KEY_2 },
-	{ 0x07, KEY_3 },
-	{ 0x09, KEY_4 },
-	{ 0x0a, KEY_5 },
-	{ 0x0b, KEY_6 },
-	{ 0x0d, KEY_7 },
-	{ 0x0e, KEY_8 },
-	{ 0x0f, KEY_9 },
-	{ 0x11, KEY_0 },
-
-	{ 0x13, KEY_RIGHT },		/* -> */
-	{ 0x12, KEY_LEFT },		/* <- */
-
-	{ 0x17, KEY_SLEEP },		/* Capturar Imagem */
-	{ 0x10, KEY_SHUFFLE },		/* Amostra */
-
-	/* FIXME: The keys bellow aren't ok */
-
-	{ 0x43, KEY_CHANNELUP },
-	{ 0x42, KEY_CHANNELDOWN },
-	{ 0x1f, KEY_VOLUMEUP },
-	{ 0x1e, KEY_VOLUMEDOWN },
-	{ 0x0c, KEY_ENTER },
-
-	{ 0x14, KEY_MUTE },
-	{ 0x08, KEY_AUDIO },
-
-	{ 0x03, KEY_TEXT },
-	{ 0x04, KEY_EPG },
-	{ 0x2b, KEY_TV2 },		/* TV2 */
-
-	{ 0x1d, KEY_RED },
-	{ 0x1c, KEY_YELLOW },
-	{ 0x41, KEY_GREEN },
-	{ 0x40, KEY_BLUE },
-
-	{ 0x1a, KEY_PLAYPAUSE },
-	{ 0x19, KEY_RECORD },
-	{ 0x18, KEY_PLAY },
-	{ 0x1b, KEY_STOP },
-};
-
-struct ir_scancode_table ir_codes_avermedia_m135a_table = {
-	.scan = ir_codes_avermedia_m135a,
-	.size = ARRAY_SIZE(ir_codes_avermedia_m135a),
-};
-EXPORT_SYMBOL_GPL(ir_codes_avermedia_m135a_table);
-
-/* Oldrich Jedlicka <oldium.pro@seznam.cz> */
-static struct ir_scancode ir_codes_avermedia_cardbus[] = {
-	{ 0x00, KEY_POWER },
-	{ 0x01, KEY_TUNER },		/* TV/FM */
-	{ 0x03, KEY_TEXT },		/* Teletext */
-	{ 0x04, KEY_EPG },
-	{ 0x05, KEY_1 },
-	{ 0x06, KEY_2 },
-	{ 0x07, KEY_3 },
-	{ 0x08, KEY_AUDIO },
-	{ 0x09, KEY_4 },
-	{ 0x0a, KEY_5 },
-	{ 0x0b, KEY_6 },
-	{ 0x0c, KEY_ZOOM },		/* Full screen */
-	{ 0x0d, KEY_7 },
-	{ 0x0e, KEY_8 },
-	{ 0x0f, KEY_9 },
-	{ 0x10, KEY_PAGEUP },		/* 16-CH PREV */
-	{ 0x11, KEY_0 },
-	{ 0x12, KEY_INFO },
-	{ 0x13, KEY_AGAIN },		/* CH RTN - channel return */
-	{ 0x14, KEY_MUTE },
-	{ 0x15, KEY_EDIT },		/* Autoscan */
-	{ 0x17, KEY_SAVE },		/* Screenshot */
-	{ 0x18, KEY_PLAYPAUSE },
-	{ 0x19, KEY_RECORD },
-	{ 0x1a, KEY_PLAY },
-	{ 0x1b, KEY_STOP },
-	{ 0x1c, KEY_FASTFORWARD },
-	{ 0x1d, KEY_REWIND },
-	{ 0x1e, KEY_VOLUMEDOWN },
-	{ 0x1f, KEY_VOLUMEUP },
-	{ 0x22, KEY_SLEEP },		/* Sleep */
-	{ 0x23, KEY_ZOOM },		/* Aspect */
-	{ 0x26, KEY_SCREEN },		/* Pos */
-	{ 0x27, KEY_ANGLE },		/* Size */
-	{ 0x28, KEY_SELECT },		/* Select */
-	{ 0x29, KEY_BLUE },		/* Blue/Picture */
-	{ 0x2a, KEY_BACKSPACE },	/* Back */
-	{ 0x2b, KEY_MEDIA },		/* PIP (Picture-in-picture) */
-	{ 0x2c, KEY_DOWN },
-	{ 0x2e, KEY_DOT },
-	{ 0x2f, KEY_TV },		/* Live TV */
-	{ 0x32, KEY_LEFT },
-	{ 0x33, KEY_CLEAR },		/* Clear */
-	{ 0x35, KEY_RED },		/* Red/TV */
-	{ 0x36, KEY_UP },
-	{ 0x37, KEY_HOME },		/* Home */
-	{ 0x39, KEY_GREEN },		/* Green/Video */
-	{ 0x3d, KEY_YELLOW },		/* Yellow/Music */
-	{ 0x3e, KEY_OK },		/* Ok */
-	{ 0x3f, KEY_RIGHT },
-	{ 0x40, KEY_NEXT },		/* Next */
-	{ 0x41, KEY_PREVIOUS },		/* Previous */
-	{ 0x42, KEY_CHANNELDOWN },	/* Channel down */
-	{ 0x43, KEY_CHANNELUP },	/* Channel up */
-};
-
-struct ir_scancode_table ir_codes_avermedia_cardbus_table = {
-	.scan = ir_codes_avermedia_cardbus,
-	.size = ARRAY_SIZE(ir_codes_avermedia_cardbus),
-};
-EXPORT_SYMBOL_GPL(ir_codes_avermedia_cardbus_table);
-
-/* Attila Kondoros <attila.kondoros@chello.hu> */
-static struct ir_scancode ir_codes_apac_viewcomp[] = {
-
-	{ 0x01, KEY_1 },
-	{ 0x02, KEY_2 },
-	{ 0x03, KEY_3 },
-	{ 0x04, KEY_4 },
-	{ 0x05, KEY_5 },
-	{ 0x06, KEY_6 },
-	{ 0x07, KEY_7 },
-	{ 0x08, KEY_8 },
-	{ 0x09, KEY_9 },
-	{ 0x00, KEY_0 },
-	{ 0x17, KEY_LAST },		/* +100 */
-	{ 0x0a, KEY_LIST },		/* recall */
-
-
-	{ 0x1c, KEY_TUNER },		/* TV/FM */
-	{ 0x15, KEY_SEARCH },		/* scan */
-	{ 0x12, KEY_POWER },		/* power */
-	{ 0x1f, KEY_VOLUMEDOWN },	/* vol up */
-	{ 0x1b, KEY_VOLUMEUP },		/* vol down */
-	{ 0x1e, KEY_CHANNELDOWN },	/* chn up */
-	{ 0x1a, KEY_CHANNELUP },	/* chn down */
-
-	{ 0x11, KEY_VIDEO },		/* video */
-	{ 0x0f, KEY_ZOOM },		/* full screen */
-	{ 0x13, KEY_MUTE },		/* mute/unmute */
-	{ 0x10, KEY_TEXT },		/* min */
-
-	{ 0x0d, KEY_STOP },		/* freeze */
-	{ 0x0e, KEY_RECORD },		/* record */
-	{ 0x1d, KEY_PLAYPAUSE },	/* stop */
-	{ 0x19, KEY_PLAY },		/* play */
-
-	{ 0x16, KEY_GOTO },		/* osd */
-	{ 0x14, KEY_REFRESH },		/* default */
-	{ 0x0c, KEY_KPPLUS },		/* fine tune >>>> */
-	{ 0x18, KEY_KPMINUS },		/* fine tune <<<< */
-};
-
-struct ir_scancode_table ir_codes_apac_viewcomp_table = {
-	.scan = ir_codes_apac_viewcomp,
-	.size = ARRAY_SIZE(ir_codes_apac_viewcomp),
-};
-EXPORT_SYMBOL_GPL(ir_codes_apac_viewcomp_table);
-
-/* ---------------------------------------------------------------------- */
-
-static struct ir_scancode ir_codes_pixelview[] = {
-
-	{ 0x1e, KEY_POWER },	/* power */
-	{ 0x07, KEY_MEDIA },	/* source */
-	{ 0x1c, KEY_SEARCH },	/* scan */
-
-
-	{ 0x03, KEY_TUNER },		/* TV/FM */
-
-	{ 0x00, KEY_RECORD },
-	{ 0x08, KEY_STOP },
-	{ 0x11, KEY_PLAY },
-
-	{ 0x1a, KEY_PLAYPAUSE },	/* freeze */
-	{ 0x19, KEY_ZOOM },		/* zoom */
-	{ 0x0f, KEY_TEXT },		/* min */
-
-	{ 0x01, KEY_1 },
-	{ 0x0b, KEY_2 },
-	{ 0x1b, KEY_3 },
-	{ 0x05, KEY_4 },
-	{ 0x09, KEY_5 },
-	{ 0x15, KEY_6 },
-	{ 0x06, KEY_7 },
-	{ 0x0a, KEY_8 },
-	{ 0x12, KEY_9 },
-	{ 0x02, KEY_0 },
-	{ 0x10, KEY_LAST },		/* +100 */
-	{ 0x13, KEY_LIST },		/* recall */
-
-	{ 0x1f, KEY_CHANNELUP },	/* chn down */
-	{ 0x17, KEY_CHANNELDOWN },	/* chn up */
-	{ 0x16, KEY_VOLUMEUP },		/* vol down */
-	{ 0x14, KEY_VOLUMEDOWN },	/* vol up */
-
-	{ 0x04, KEY_KPMINUS },		/* <<< */
-	{ 0x0e, KEY_SETUP },		/* function */
-	{ 0x0c, KEY_KPPLUS },		/* >>> */
-
-	{ 0x0d, KEY_GOTO },		/* mts */
-	{ 0x1d, KEY_REFRESH },		/* reset */
-	{ 0x18, KEY_MUTE },		/* mute/unmute */
-};
-
-struct ir_scancode_table ir_codes_pixelview_table = {
-	.scan = ir_codes_pixelview,
-	.size = ARRAY_SIZE(ir_codes_pixelview),
-};
-EXPORT_SYMBOL_GPL(ir_codes_pixelview_table);
-
-/*
-   Mauro Carvalho Chehab <mchehab@infradead.org>
-   present on PV MPEG 8000GT
- */
-static struct ir_scancode ir_codes_pixelview_new[] = {
-	{ 0x3c, KEY_TIME },		/* Timeshift */
-	{ 0x12, KEY_POWER },
-
-	{ 0x3d, KEY_1 },
-	{ 0x38, KEY_2 },
-	{ 0x18, KEY_3 },
-	{ 0x35, KEY_4 },
-	{ 0x39, KEY_5 },
-	{ 0x15, KEY_6 },
-	{ 0x36, KEY_7 },
-	{ 0x3a, KEY_8 },
-	{ 0x1e, KEY_9 },
-	{ 0x3e, KEY_0 },
-
-	{ 0x1c, KEY_AGAIN },		/* LOOP	*/
-	{ 0x3f, KEY_MEDIA },		/* Source */
-	{ 0x1f, KEY_LAST },		/* +100 */
-	{ 0x1b, KEY_MUTE },
-
-	{ 0x17, KEY_CHANNELDOWN },
-	{ 0x16, KEY_CHANNELUP },
-	{ 0x10, KEY_VOLUMEUP },
-	{ 0x14, KEY_VOLUMEDOWN },
-	{ 0x13, KEY_ZOOM },
-
-	{ 0x19, KEY_CAMERA },		/* SNAPSHOT */
-	{ 0x1a, KEY_SEARCH },		/* scan */
-
-	{ 0x37, KEY_REWIND },		/* << */
-	{ 0x32, KEY_RECORD },		/* o (red) */
-	{ 0x33, KEY_FORWARD },		/* >> */
-	{ 0x11, KEY_STOP },		/* square */
-	{ 0x3b, KEY_PLAY },		/* > */
-	{ 0x30, KEY_PLAYPAUSE },	/* || */
-
-	{ 0x31, KEY_TV },
-	{ 0x34, KEY_RADIO },
-};
-
-struct ir_scancode_table ir_codes_pixelview_new_table = {
-	.scan = ir_codes_pixelview_new,
-	.size = ARRAY_SIZE(ir_codes_pixelview_new),
-};
-EXPORT_SYMBOL_GPL(ir_codes_pixelview_new_table);
-
-static struct ir_scancode ir_codes_nebula[] = {
-	{ 0x00, KEY_0 },
-	{ 0x01, KEY_1 },
-	{ 0x02, KEY_2 },
-	{ 0x03, KEY_3 },
-	{ 0x04, KEY_4 },
-	{ 0x05, KEY_5 },
-	{ 0x06, KEY_6 },
-	{ 0x07, KEY_7 },
-	{ 0x08, KEY_8 },
-	{ 0x09, KEY_9 },
-	{ 0x0a, KEY_TV },
-	{ 0x0b, KEY_AUX },
-	{ 0x0c, KEY_DVD },
-	{ 0x0d, KEY_POWER },
-	{ 0x0e, KEY_MHP },	/* labelled 'Picture' */
-	{ 0x0f, KEY_AUDIO },
-	{ 0x10, KEY_INFO },
-	{ 0x11, KEY_F13 },	/* 16:9 */
-	{ 0x12, KEY_F14 },	/* 14:9 */
-	{ 0x13, KEY_EPG },
-	{ 0x14, KEY_EXIT },
-	{ 0x15, KEY_MENU },
-	{ 0x16, KEY_UP },
-	{ 0x17, KEY_DOWN },
-	{ 0x18, KEY_LEFT },
-	{ 0x19, KEY_RIGHT },
-	{ 0x1a, KEY_ENTER },
-	{ 0x1b, KEY_CHANNELUP },
-	{ 0x1c, KEY_CHANNELDOWN },
-	{ 0x1d, KEY_VOLUMEUP },
-	{ 0x1e, KEY_VOLUMEDOWN },
-	{ 0x1f, KEY_RED },
-	{ 0x20, KEY_GREEN },
-	{ 0x21, KEY_YELLOW },
-	{ 0x22, KEY_BLUE },
-	{ 0x23, KEY_SUBTITLE },
-	{ 0x24, KEY_F15 },	/* AD */
-	{ 0x25, KEY_TEXT },
-	{ 0x26, KEY_MUTE },
-	{ 0x27, KEY_REWIND },
-	{ 0x28, KEY_STOP },
-	{ 0x29, KEY_PLAY },
-	{ 0x2a, KEY_FASTFORWARD },
-	{ 0x2b, KEY_F16 },	/* chapter */
-	{ 0x2c, KEY_PAUSE },
-	{ 0x2d, KEY_PLAY },
-	{ 0x2e, KEY_RECORD },
-	{ 0x2f, KEY_F17 },	/* picture in picture */
-	{ 0x30, KEY_KPPLUS },	/* zoom in */
-	{ 0x31, KEY_KPMINUS },	/* zoom out */
-	{ 0x32, KEY_F18 },	/* capture */
-	{ 0x33, KEY_F19 },	/* web */
-	{ 0x34, KEY_EMAIL },
-	{ 0x35, KEY_PHONE },
-	{ 0x36, KEY_PC },
-};
-
-struct ir_scancode_table ir_codes_nebula_table = {
-	.scan = ir_codes_nebula,
-	.size = ARRAY_SIZE(ir_codes_nebula),
-};
-EXPORT_SYMBOL_GPL(ir_codes_nebula_table);
-
-/* DigitalNow DNTV Live DVB-T Remote */
-static struct ir_scancode ir_codes_dntv_live_dvb_t[] = {
-	{ 0x00, KEY_ESC },		/* 'go up a level?' */
-	/* Keys 0 to 9 */
-	{ 0x0a, KEY_0 },
-	{ 0x01, KEY_1 },
-	{ 0x02, KEY_2 },
-	{ 0x03, KEY_3 },
-	{ 0x04, KEY_4 },
-	{ 0x05, KEY_5 },
-	{ 0x06, KEY_6 },
-	{ 0x07, KEY_7 },
-	{ 0x08, KEY_8 },
-	{ 0x09, KEY_9 },
-
-	{ 0x0b, KEY_TUNER },		/* tv/fm */
-	{ 0x0c, KEY_SEARCH },		/* scan */
-	{ 0x0d, KEY_STOP },
-	{ 0x0e, KEY_PAUSE },
-	{ 0x0f, KEY_LIST },		/* source */
-
-	{ 0x10, KEY_MUTE },
-	{ 0x11, KEY_REWIND },		/* backward << */
-	{ 0x12, KEY_POWER },
-	{ 0x13, KEY_CAMERA },		/* snap */
-	{ 0x14, KEY_AUDIO },		/* stereo */
-	{ 0x15, KEY_CLEAR },		/* reset */
-	{ 0x16, KEY_PLAY },
-	{ 0x17, KEY_ENTER },
-	{ 0x18, KEY_ZOOM },		/* full screen */
-	{ 0x19, KEY_FASTFORWARD },	/* forward >> */
-	{ 0x1a, KEY_CHANNELUP },
-	{ 0x1b, KEY_VOLUMEUP },
-	{ 0x1c, KEY_INFO },		/* preview */
-	{ 0x1d, KEY_RECORD },		/* record */
-	{ 0x1e, KEY_CHANNELDOWN },
-	{ 0x1f, KEY_VOLUMEDOWN },
-};
-
-struct ir_scancode_table ir_codes_dntv_live_dvb_t_table = {
-	.scan = ir_codes_dntv_live_dvb_t,
-	.size = ARRAY_SIZE(ir_codes_dntv_live_dvb_t),
-};
-EXPORT_SYMBOL_GPL(ir_codes_dntv_live_dvb_t_table);
-
-/* ---------------------------------------------------------------------- */
-
-/* IO-DATA BCTV7E Remote */
-static struct ir_scancode ir_codes_iodata_bctv7e[] = {
-	{ 0x40, KEY_TV },
-	{ 0x20, KEY_RADIO },		/* FM */
-	{ 0x60, KEY_EPG },
-	{ 0x00, KEY_POWER },
-
-	/* Keys 0 to 9 */
-	{ 0x44, KEY_0 },		/* 10 */
-	{ 0x50, KEY_1 },
-	{ 0x30, KEY_2 },
-	{ 0x70, KEY_3 },
-	{ 0x48, KEY_4 },
-	{ 0x28, KEY_5 },
-	{ 0x68, KEY_6 },
-	{ 0x58, KEY_7 },
-	{ 0x38, KEY_8 },
-	{ 0x78, KEY_9 },
-
-	{ 0x10, KEY_L },		/* Live */
-	{ 0x08, KEY_TIME },		/* Time Shift */
-
-	{ 0x18, KEY_PLAYPAUSE },	/* Play */
-
-	{ 0x24, KEY_ENTER },		/* 11 */
-	{ 0x64, KEY_ESC },		/* 12 */
-	{ 0x04, KEY_M },		/* Multi */
-
-	{ 0x54, KEY_VIDEO },
-	{ 0x34, KEY_CHANNELUP },
-	{ 0x74, KEY_VOLUMEUP },
-	{ 0x14, KEY_MUTE },
-
-	{ 0x4c, KEY_VCR },		/* SVIDEO */
-	{ 0x2c, KEY_CHANNELDOWN },
-	{ 0x6c, KEY_VOLUMEDOWN },
-	{ 0x0c, KEY_ZOOM },
-
-	{ 0x5c, KEY_PAUSE },
-	{ 0x3c, KEY_RED },		/* || (red) */
-	{ 0x7c, KEY_RECORD },		/* recording */
-	{ 0x1c, KEY_STOP },
-
-	{ 0x41, KEY_REWIND },		/* backward << */
-	{ 0x21, KEY_PLAY },
-	{ 0x61, KEY_FASTFORWARD },	/* forward >> */
-	{ 0x01, KEY_NEXT },		/* skip >| */
-};
-
-struct ir_scancode_table ir_codes_iodata_bctv7e_table = {
-	.scan = ir_codes_iodata_bctv7e,
-	.size = ARRAY_SIZE(ir_codes_iodata_bctv7e),
-};
-EXPORT_SYMBOL_GPL(ir_codes_iodata_bctv7e_table);
-
-/* ---------------------------------------------------------------------- */
-
-/* ADS Tech Instant TV DVB-T PCI Remote */
-static struct ir_scancode ir_codes_adstech_dvb_t_pci[] = {
-	/* Keys 0 to 9 */
-	{ 0x4d, KEY_0 },
-	{ 0x57, KEY_1 },
-	{ 0x4f, KEY_2 },
-	{ 0x53, KEY_3 },
-	{ 0x56, KEY_4 },
-	{ 0x4e, KEY_5 },
-	{ 0x5e, KEY_6 },
-	{ 0x54, KEY_7 },
-	{ 0x4c, KEY_8 },
-	{ 0x5c, KEY_9 },
-
-	{ 0x5b, KEY_POWER },
-	{ 0x5f, KEY_MUTE },
-	{ 0x55, KEY_GOTO },
-	{ 0x5d, KEY_SEARCH },
-	{ 0x17, KEY_EPG },		/* Guide */
-	{ 0x1f, KEY_MENU },
-	{ 0x0f, KEY_UP },
-	{ 0x46, KEY_DOWN },
-	{ 0x16, KEY_LEFT },
-	{ 0x1e, KEY_RIGHT },
-	{ 0x0e, KEY_SELECT },		/* Enter */
-	{ 0x5a, KEY_INFO },
-	{ 0x52, KEY_EXIT },
-	{ 0x59, KEY_PREVIOUS },
-	{ 0x51, KEY_NEXT },
-	{ 0x58, KEY_REWIND },
-	{ 0x50, KEY_FORWARD },
-	{ 0x44, KEY_PLAYPAUSE },
-	{ 0x07, KEY_STOP },
-	{ 0x1b, KEY_RECORD },
-	{ 0x13, KEY_TUNER },		/* Live */
-	{ 0x0a, KEY_A },
-	{ 0x12, KEY_B },
-	{ 0x03, KEY_PROG1 },		/* 1 */
-	{ 0x01, KEY_PROG2 },		/* 2 */
-	{ 0x00, KEY_PROG3 },		/* 3 */
-	{ 0x06, KEY_DVD },
-	{ 0x48, KEY_AUX },		/* Photo */
-	{ 0x40, KEY_VIDEO },
-	{ 0x19, KEY_AUDIO },		/* Music */
-	{ 0x0b, KEY_CHANNELUP },
-	{ 0x08, KEY_CHANNELDOWN },
-	{ 0x15, KEY_VOLUMEUP },
-	{ 0x1c, KEY_VOLUMEDOWN },
-};
-
-struct ir_scancode_table ir_codes_adstech_dvb_t_pci_table = {
-	.scan = ir_codes_adstech_dvb_t_pci,
-	.size = ARRAY_SIZE(ir_codes_adstech_dvb_t_pci),
-};
-EXPORT_SYMBOL_GPL(ir_codes_adstech_dvb_t_pci_table);
-
-/* ---------------------------------------------------------------------- */
-
-/* MSI TV@nywhere MASTER remote */
-
-static struct ir_scancode ir_codes_msi_tvanywhere[] = {
-	/* Keys 0 to 9 */
-	{ 0x00, KEY_0 },
-	{ 0x01, KEY_1 },
-	{ 0x02, KEY_2 },
-	{ 0x03, KEY_3 },
-	{ 0x04, KEY_4 },
-	{ 0x05, KEY_5 },
-	{ 0x06, KEY_6 },
-	{ 0x07, KEY_7 },
-	{ 0x08, KEY_8 },
-	{ 0x09, KEY_9 },
-
-	{ 0x0c, KEY_MUTE },
-	{ 0x0f, KEY_SCREEN },		/* Full Screen */
-	{ 0x10, KEY_FN },		/* Funtion */
-	{ 0x11, KEY_TIME },		/* Time shift */
-	{ 0x12, KEY_POWER },
-	{ 0x13, KEY_MEDIA },		/* MTS */
-	{ 0x14, KEY_SLOW },
-	{ 0x16, KEY_REWIND },		/* backward << */
-	{ 0x17, KEY_ENTER },		/* Return */
-	{ 0x18, KEY_FASTFORWARD },	/* forward >> */
-	{ 0x1a, KEY_CHANNELUP },
-	{ 0x1b, KEY_VOLUMEUP },
-	{ 0x1e, KEY_CHANNELDOWN },
-	{ 0x1f, KEY_VOLUMEDOWN },
-};
-
-struct ir_scancode_table ir_codes_msi_tvanywhere_table = {
-	.scan = ir_codes_msi_tvanywhere,
-	.size = ARRAY_SIZE(ir_codes_msi_tvanywhere),
-};
-EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere_table);
-
-/* ---------------------------------------------------------------------- */
-
-/*
-  Keycodes for remote on the MSI TV@nywhere Plus. The controller IC on the card
-  is marked "KS003". The controller is I2C at address 0x30, but does not seem
-  to respond to probes until a read is performed from a valid device.
-  I don't know why...
-
-  Note: This remote may be of similar or identical design to the
-  Pixelview remote (?).  The raw codes and duplicate button codes
-  appear to be the same.
-
-  Henry Wong <henry@stuffedcow.net>
-  Some changes to formatting and keycodes by Mark Schultz <n9xmj@yahoo.com>
-
-*/
-
-static struct ir_scancode ir_codes_msi_tvanywhere_plus[] = {
-
-/*  ---- Remote Button Layout ----
-
-    POWER   SOURCE  SCAN    MUTE
-    TV/FM   1       2       3
-    |>      4       5       6
-    <|      7       8       9
-    ^^UP    0       +       RECALL
-    vvDN    RECORD  STOP    PLAY
-
-	MINIMIZE          ZOOM
-
-		  CH+
-      VOL-                   VOL+
-		  CH-
-
-	SNAPSHOT           MTS
-
-     <<      FUNC    >>     RESET
-*/
-
-	{ 0x01, KEY_1 },		/* 1 */
-	{ 0x0b, KEY_2 },		/* 2 */
-	{ 0x1b, KEY_3 },		/* 3 */
-	{ 0x05, KEY_4 },		/* 4 */
-	{ 0x09, KEY_5 },		/* 5 */
-	{ 0x15, KEY_6 },		/* 6 */
-	{ 0x06, KEY_7 },		/* 7 */
-	{ 0x0a, KEY_8 },		/* 8 */
-	{ 0x12, KEY_9 },		/* 9 */
-	{ 0x02, KEY_0 },		/* 0 */
-	{ 0x10, KEY_KPPLUS },		/* + */
-	{ 0x13, KEY_AGAIN },		/* Recall */
-
-	{ 0x1e, KEY_POWER },		/* Power */
-	{ 0x07, KEY_TUNER },		/* Source */
-	{ 0x1c, KEY_SEARCH },		/* Scan */
-	{ 0x18, KEY_MUTE },		/* Mute */
-
-	{ 0x03, KEY_RADIO },		/* TV/FM */
-	/* The next four keys are duplicates that appear to send the
-	   same IR code as Ch+, Ch-, >>, and << .  The raw code assigned
-	   to them is the actual code + 0x20 - they will never be
-	   detected as such unless some way is discovered to distinguish
-	   these buttons from those that have the same code. */
-	{ 0x3f, KEY_RIGHT },		/* |> and Ch+ */
-	{ 0x37, KEY_LEFT },		/* <| and Ch- */
-	{ 0x2c, KEY_UP },		/* ^^Up and >> */
-	{ 0x24, KEY_DOWN },		/* vvDn and << */
-
-	{ 0x00, KEY_RECORD },		/* Record */
-	{ 0x08, KEY_STOP },		/* Stop */
-	{ 0x11, KEY_PLAY },		/* Play */
-
-	{ 0x0f, KEY_CLOSE },		/* Minimize */
-	{ 0x19, KEY_ZOOM },		/* Zoom */
-	{ 0x1a, KEY_CAMERA },		/* Snapshot */
-	{ 0x0d, KEY_LANGUAGE },		/* MTS */
-
-	{ 0x14, KEY_VOLUMEDOWN },	/* Vol- */
-	{ 0x16, KEY_VOLUMEUP },		/* Vol+ */
-	{ 0x17, KEY_CHANNELDOWN },	/* Ch- */
-	{ 0x1f, KEY_CHANNELUP },	/* Ch+ */
-
-	{ 0x04, KEY_REWIND },		/* << */
-	{ 0x0e, KEY_MENU },		/* Function */
-	{ 0x0c, KEY_FASTFORWARD },	/* >> */
-	{ 0x1d, KEY_RESTART },		/* Reset */
-};
-
-struct ir_scancode_table ir_codes_msi_tvanywhere_plus_table = {
-	.scan = ir_codes_msi_tvanywhere_plus,
-	.size = ARRAY_SIZE(ir_codes_msi_tvanywhere_plus),
-};
-EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere_plus_table);
-
-/* ---------------------------------------------------------------------- */
-
-/* Cinergy 1400 DVB-T */
-static struct ir_scancode ir_codes_cinergy_1400[] = {
-	{ 0x01, KEY_POWER },
-	{ 0x02, KEY_1 },
-	{ 0x03, KEY_2 },
-	{ 0x04, KEY_3 },
-	{ 0x05, KEY_4 },
-	{ 0x06, KEY_5 },
-	{ 0x07, KEY_6 },
-	{ 0x08, KEY_7 },
-	{ 0x09, KEY_8 },
-	{ 0x0a, KEY_9 },
-	{ 0x0c, KEY_0 },
-
-	{ 0x0b, KEY_VIDEO },
-	{ 0x0d, KEY_REFRESH },
-	{ 0x0e, KEY_SELECT },
-	{ 0x0f, KEY_EPG },
-	{ 0x10, KEY_UP },
-	{ 0x11, KEY_LEFT },
-	{ 0x12, KEY_OK },
-	{ 0x13, KEY_RIGHT },
-	{ 0x14, KEY_DOWN },
-	{ 0x15, KEY_TEXT },
-	{ 0x16, KEY_INFO },
-
-	{ 0x17, KEY_RED },
-	{ 0x18, KEY_GREEN },
-	{ 0x19, KEY_YELLOW },
-	{ 0x1a, KEY_BLUE },
-
-	{ 0x1b, KEY_CHANNELUP },
-	{ 0x1c, KEY_VOLUMEUP },
-	{ 0x1d, KEY_MUTE },
-	{ 0x1e, KEY_VOLUMEDOWN },
-	{ 0x1f, KEY_CHANNELDOWN },
-
-	{ 0x40, KEY_PAUSE },
-	{ 0x4c, KEY_PLAY },
-	{ 0x58, KEY_RECORD },
-	{ 0x54, KEY_PREVIOUS },
-	{ 0x48, KEY_STOP },
-	{ 0x5c, KEY_NEXT },
-};
-
-struct ir_scancode_table ir_codes_cinergy_1400_table = {
-	.scan = ir_codes_cinergy_1400,
-	.size = ARRAY_SIZE(ir_codes_cinergy_1400),
-};
-EXPORT_SYMBOL_GPL(ir_codes_cinergy_1400_table);
-
-/* ---------------------------------------------------------------------- */
-
-/* AVERTV STUDIO 303 Remote */
-static struct ir_scancode ir_codes_avertv_303[] = {
-	{ 0x2a, KEY_1 },
-	{ 0x32, KEY_2 },
-	{ 0x3a, KEY_3 },
-	{ 0x4a, KEY_4 },
-	{ 0x52, KEY_5 },
-	{ 0x5a, KEY_6 },
-	{ 0x6a, KEY_7 },
-	{ 0x72, KEY_8 },
-	{ 0x7a, KEY_9 },
-	{ 0x0e, KEY_0 },
-
-	{ 0x02, KEY_POWER },
-	{ 0x22, KEY_VIDEO },
-	{ 0x42, KEY_AUDIO },
-	{ 0x62, KEY_ZOOM },
-	{ 0x0a, KEY_TV },
-	{ 0x12, KEY_CD },
-	{ 0x1a, KEY_TEXT },
-
-	{ 0x16, KEY_SUBTITLE },
-	{ 0x1e, KEY_REWIND },
-	{ 0x06, KEY_PRINT },
-
-	{ 0x2e, KEY_SEARCH },
-	{ 0x36, KEY_SLEEP },
-	{ 0x3e, KEY_SHUFFLE },
-	{ 0x26, KEY_MUTE },
-
-	{ 0x4e, KEY_RECORD },
-	{ 0x56, KEY_PAUSE },
-	{ 0x5e, KEY_STOP },
-	{ 0x46, KEY_PLAY },
-
-	{ 0x6e, KEY_RED },
-	{ 0x0b, KEY_GREEN },
-	{ 0x66, KEY_YELLOW },
-	{ 0x03, KEY_BLUE },
-
-	{ 0x76, KEY_LEFT },
-	{ 0x7e, KEY_RIGHT },
-	{ 0x13, KEY_DOWN },
-	{ 0x1b, KEY_UP },
-};
-
-struct ir_scancode_table ir_codes_avertv_303_table = {
-	.scan = ir_codes_avertv_303,
-	.size = ARRAY_SIZE(ir_codes_avertv_303),
-};
-EXPORT_SYMBOL_GPL(ir_codes_avertv_303_table);
-
-/* ---------------------------------------------------------------------- */
-
-/* DigitalNow DNTV Live! DVB-T Pro Remote */
-static struct ir_scancode ir_codes_dntv_live_dvbt_pro[] = {
-	{ 0x16, KEY_POWER },
-	{ 0x5b, KEY_HOME },
-
-	{ 0x55, KEY_TV },		/* live tv */
-	{ 0x58, KEY_TUNER },		/* digital Radio */
-	{ 0x5a, KEY_RADIO },		/* FM radio */
-	{ 0x59, KEY_DVD },		/* dvd menu */
-	{ 0x03, KEY_1 },
-	{ 0x01, KEY_2 },
-	{ 0x06, KEY_3 },
-	{ 0x09, KEY_4 },
-	{ 0x1d, KEY_5 },
-	{ 0x1f, KEY_6 },
-	{ 0x0d, KEY_7 },
-	{ 0x19, KEY_8 },
-	{ 0x1b, KEY_9 },
-	{ 0x0c, KEY_CANCEL },
-	{ 0x15, KEY_0 },
-	{ 0x4a, KEY_CLEAR },
-	{ 0x13, KEY_BACK },
-	{ 0x00, KEY_TAB },
-	{ 0x4b, KEY_UP },
-	{ 0x4e, KEY_LEFT },
-	{ 0x4f, KEY_OK },
-	{ 0x52, KEY_RIGHT },
-	{ 0x51, KEY_DOWN },
-	{ 0x1e, KEY_VOLUMEUP },
-	{ 0x0a, KEY_VOLUMEDOWN },
-	{ 0x02, KEY_CHANNELDOWN },
-	{ 0x05, KEY_CHANNELUP },
-	{ 0x11, KEY_RECORD },
-	{ 0x14, KEY_PLAY },
-	{ 0x4c, KEY_PAUSE },
-	{ 0x1a, KEY_STOP },
-	{ 0x40, KEY_REWIND },
-	{ 0x12, KEY_FASTFORWARD },
-	{ 0x41, KEY_PREVIOUSSONG },	/* replay |< */
-	{ 0x42, KEY_NEXTSONG },		/* skip >| */
-	{ 0x54, KEY_CAMERA },		/* capture */
-	{ 0x50, KEY_LANGUAGE },		/* sap */
-	{ 0x47, KEY_TV2 },		/* pip */
-	{ 0x4d, KEY_SCREEN },
-	{ 0x43, KEY_SUBTITLE },
-	{ 0x10, KEY_MUTE },
-	{ 0x49, KEY_AUDIO },		/* l/r */
-	{ 0x07, KEY_SLEEP },
-	{ 0x08, KEY_VIDEO },		/* a/v */
-	{ 0x0e, KEY_PREVIOUS },		/* recall */
-	{ 0x45, KEY_ZOOM },		/* zoom + */
-	{ 0x46, KEY_ANGLE },		/* zoom - */
-	{ 0x56, KEY_RED },
-	{ 0x57, KEY_GREEN },
-	{ 0x5c, KEY_YELLOW },
-	{ 0x5d, KEY_BLUE },
-};
-
-struct ir_scancode_table ir_codes_dntv_live_dvbt_pro_table = {
-	.scan = ir_codes_dntv_live_dvbt_pro,
-	.size = ARRAY_SIZE(ir_codes_dntv_live_dvbt_pro),
-};
-EXPORT_SYMBOL_GPL(ir_codes_dntv_live_dvbt_pro_table);
-
-static struct ir_scancode ir_codes_em_terratec[] = {
-	{ 0x01, KEY_CHANNEL },
-	{ 0x02, KEY_SELECT },
-	{ 0x03, KEY_MUTE },
-	{ 0x04, KEY_POWER },
-	{ 0x05, KEY_1 },
-	{ 0x06, KEY_2 },
-	{ 0x07, KEY_3 },
-	{ 0x08, KEY_CHANNELUP },
-	{ 0x09, KEY_4 },
-	{ 0x0a, KEY_5 },
-	{ 0x0b, KEY_6 },
-	{ 0x0c, KEY_CHANNELDOWN },
-	{ 0x0d, KEY_7 },
-	{ 0x0e, KEY_8 },
-	{ 0x0f, KEY_9 },
-	{ 0x10, KEY_VOLUMEUP },
-	{ 0x11, KEY_0 },
-	{ 0x12, KEY_MENU },
-	{ 0x13, KEY_PRINT },
-	{ 0x14, KEY_VOLUMEDOWN },
-	{ 0x16, KEY_PAUSE },
-	{ 0x18, KEY_RECORD },
-	{ 0x19, KEY_REWIND },
-	{ 0x1a, KEY_PLAY },
-	{ 0x1b, KEY_FORWARD },
-	{ 0x1c, KEY_BACKSPACE },
-	{ 0x1e, KEY_STOP },
-	{ 0x40, KEY_ZOOM },
-};
-
-struct ir_scancode_table ir_codes_em_terratec_table = {
-	.scan = ir_codes_em_terratec,
-	.size = ARRAY_SIZE(ir_codes_em_terratec),
-};
-EXPORT_SYMBOL_GPL(ir_codes_em_terratec_table);
-
-static struct ir_scancode ir_codes_pinnacle_grey[] = {
-	{ 0x3a, KEY_0 },
-	{ 0x31, KEY_1 },
-	{ 0x32, KEY_2 },
-	{ 0x33, KEY_3 },
-	{ 0x34, KEY_4 },
-	{ 0x35, KEY_5 },
-	{ 0x36, KEY_6 },
-	{ 0x37, KEY_7 },
-	{ 0x38, KEY_8 },
-	{ 0x39, KEY_9 },
-
-	{ 0x2f, KEY_POWER },
-
-	{ 0x2e, KEY_P },
-	{ 0x1f, KEY_L },
-	{ 0x2b, KEY_I },
-
-	{ 0x2d, KEY_SCREEN },
-	{ 0x1e, KEY_ZOOM },
-	{ 0x1b, KEY_VOLUMEUP },
-	{ 0x0f, KEY_VOLUMEDOWN },
-	{ 0x17, KEY_CHANNELUP },
-	{ 0x1c, KEY_CHANNELDOWN },
-	{ 0x25, KEY_INFO },
-
-	{ 0x3c, KEY_MUTE },
-
-	{ 0x3d, KEY_LEFT },
-	{ 0x3b, KEY_RIGHT },
-
-	{ 0x3f, KEY_UP },
-	{ 0x3e, KEY_DOWN },
-	{ 0x1a, KEY_ENTER },
-
-	{ 0x1d, KEY_MENU },
-	{ 0x19, KEY_AGAIN },
-	{ 0x16, KEY_PREVIOUSSONG },
-	{ 0x13, KEY_NEXTSONG },
-	{ 0x15, KEY_PAUSE },
-	{ 0x0e, KEY_REWIND },
-	{ 0x0d, KEY_PLAY },
-	{ 0x0b, KEY_STOP },
-	{ 0x07, KEY_FORWARD },
-	{ 0x27, KEY_RECORD },
-	{ 0x26, KEY_TUNER },
-	{ 0x29, KEY_TEXT },
-	{ 0x2a, KEY_MEDIA },
-	{ 0x18, KEY_EPG },
-};
-
-struct ir_scancode_table ir_codes_pinnacle_grey_table = {
-	.scan = ir_codes_pinnacle_grey,
-	.size = ARRAY_SIZE(ir_codes_pinnacle_grey),
-};
-EXPORT_SYMBOL_GPL(ir_codes_pinnacle_grey_table);
-
-static struct ir_scancode ir_codes_flyvideo[] = {
-	{ 0x0f, KEY_0 },
-	{ 0x03, KEY_1 },
-	{ 0x04, KEY_2 },
-	{ 0x05, KEY_3 },
-	{ 0x07, KEY_4 },
-	{ 0x08, KEY_5 },
-	{ 0x09, KEY_6 },
-	{ 0x0b, KEY_7 },
-	{ 0x0c, KEY_8 },
-	{ 0x0d, KEY_9 },
-
-	{ 0x0e, KEY_MODE },	/* Air/Cable */
-	{ 0x11, KEY_VIDEO },	/* Video */
-	{ 0x15, KEY_AUDIO },	/* Audio */
-	{ 0x00, KEY_POWER },	/* Power */
-	{ 0x18, KEY_TUNER },	/* AV Source */
-	{ 0x02, KEY_ZOOM },	/* Fullscreen */
-	{ 0x1a, KEY_LANGUAGE },	/* Stereo */
-	{ 0x1b, KEY_MUTE },	/* Mute */
-	{ 0x14, KEY_VOLUMEUP },	/* Volume + */
-	{ 0x17, KEY_VOLUMEDOWN },/* Volume - */
-	{ 0x12, KEY_CHANNELUP },/* Channel + */
-	{ 0x13, KEY_CHANNELDOWN },/* Channel - */
-	{ 0x06, KEY_AGAIN },	/* Recall */
-	{ 0x10, KEY_ENTER },	/* Enter */
-
-	{ 0x19, KEY_BACK },	/* Rewind  ( <<< ) */
-	{ 0x1f, KEY_FORWARD },	/* Forward ( >>> ) */
-	{ 0x0a, KEY_ANGLE },	/* no label, may be used as the PAUSE button */
-};
-
-struct ir_scancode_table ir_codes_flyvideo_table = {
-	.scan = ir_codes_flyvideo,
-	.size = ARRAY_SIZE(ir_codes_flyvideo),
-};
-EXPORT_SYMBOL_GPL(ir_codes_flyvideo_table);
-
-static struct ir_scancode ir_codes_flydvb[] = {
-	{ 0x01, KEY_ZOOM },		/* Full Screen */
-	{ 0x00, KEY_POWER },		/* Power */
-
-	{ 0x03, KEY_1 },
-	{ 0x04, KEY_2 },
-	{ 0x05, KEY_3 },
-	{ 0x07, KEY_4 },
-	{ 0x08, KEY_5 },
-	{ 0x09, KEY_6 },
-	{ 0x0b, KEY_7 },
-	{ 0x0c, KEY_8 },
-	{ 0x0d, KEY_9 },
-	{ 0x06, KEY_AGAIN },		/* Recall */
-	{ 0x0f, KEY_0 },
-	{ 0x10, KEY_MUTE },		/* Mute */
-	{ 0x02, KEY_RADIO },		/* TV/Radio */
-	{ 0x1b, KEY_LANGUAGE },		/* SAP (Second Audio Program) */
-
-	{ 0x14, KEY_VOLUMEUP },		/* VOL+ */
-	{ 0x17, KEY_VOLUMEDOWN },	/* VOL- */
-	{ 0x12, KEY_CHANNELUP },	/* CH+ */
-	{ 0x13, KEY_CHANNELDOWN },	/* CH- */
-	{ 0x1d, KEY_ENTER },		/* Enter */
-
-	{ 0x1a, KEY_MODE },		/* PIP */
-	{ 0x18, KEY_TUNER },		/* Source */
-
-	{ 0x1e, KEY_RECORD },		/* Record/Pause */
-	{ 0x15, KEY_ANGLE },		/* Swap (no label on key) */
-	{ 0x1c, KEY_PAUSE },		/* Timeshift/Pause */
-	{ 0x19, KEY_BACK },		/* Rewind << */
-	{ 0x0a, KEY_PLAYPAUSE },	/* Play/Pause */
-	{ 0x1f, KEY_FORWARD },		/* Forward >> */
-	{ 0x16, KEY_PREVIOUS },		/* Back |<< */
-	{ 0x11, KEY_STOP },		/* Stop */
-	{ 0x0e, KEY_NEXT },		/* End >>| */
-};
-
-struct ir_scancode_table ir_codes_flydvb_table = {
-	.scan = ir_codes_flydvb,
-	.size = ARRAY_SIZE(ir_codes_flydvb),
-};
-EXPORT_SYMBOL_GPL(ir_codes_flydvb_table);
-
-static struct ir_scancode ir_codes_cinergy[] = {
-	{ 0x00, KEY_0 },
-	{ 0x01, KEY_1 },
-	{ 0x02, KEY_2 },
-	{ 0x03, KEY_3 },
-	{ 0x04, KEY_4 },
-	{ 0x05, KEY_5 },
-	{ 0x06, KEY_6 },
-	{ 0x07, KEY_7 },
-	{ 0x08, KEY_8 },
-	{ 0x09, KEY_9 },
-
-	{ 0x0a, KEY_POWER },
-	{ 0x0b, KEY_PROG1 },		/* app */
-	{ 0x0c, KEY_ZOOM },		/* zoom/fullscreen */
-	{ 0x0d, KEY_CHANNELUP },	/* channel */
-	{ 0x0e, KEY_CHANNELDOWN },	/* channel- */
-	{ 0x0f, KEY_VOLUMEUP },
-	{ 0x10, KEY_VOLUMEDOWN },
-	{ 0x11, KEY_TUNER },		/* AV */
-	{ 0x12, KEY_NUMLOCK },		/* -/-- */
-	{ 0x13, KEY_AUDIO },		/* audio */
-	{ 0x14, KEY_MUTE },
-	{ 0x15, KEY_UP },
-	{ 0x16, KEY_DOWN },
-	{ 0x17, KEY_LEFT },
-	{ 0x18, KEY_RIGHT },
-	{ 0x19, BTN_LEFT, },
-	{ 0x1a, BTN_RIGHT, },
-	{ 0x1b, KEY_WWW },		/* text */
-	{ 0x1c, KEY_REWIND },
-	{ 0x1d, KEY_FORWARD },
-	{ 0x1e, KEY_RECORD },
-	{ 0x1f, KEY_PLAY },
-	{ 0x20, KEY_PREVIOUSSONG },
-	{ 0x21, KEY_NEXTSONG },
-	{ 0x22, KEY_PAUSE },
-	{ 0x23, KEY_STOP },
-};
-
-struct ir_scancode_table ir_codes_cinergy_table = {
-	.scan = ir_codes_cinergy,
-	.size = ARRAY_SIZE(ir_codes_cinergy),
-};
-EXPORT_SYMBOL_GPL(ir_codes_cinergy_table);
-
-/* Alfons Geser <a.geser@cox.net>
- * updates from Job D. R. Borges <jobdrb@ig.com.br> */
-static struct ir_scancode ir_codes_eztv[] = {
-	{ 0x12, KEY_POWER },
-	{ 0x01, KEY_TV },	/* DVR */
-	{ 0x15, KEY_DVD },	/* DVD */
-	{ 0x17, KEY_AUDIO },	/* music */
-				/* DVR mode / DVD mode / music mode */
-
-	{ 0x1b, KEY_MUTE },	/* mute */
-	{ 0x02, KEY_LANGUAGE },	/* MTS/SAP / audio / autoseek */
-	{ 0x1e, KEY_SUBTITLE },	/* closed captioning / subtitle / seek */
-	{ 0x16, KEY_ZOOM },	/* full screen */
-	{ 0x1c, KEY_VIDEO },	/* video source / eject / delall */
-	{ 0x1d, KEY_RESTART },	/* playback / angle / del */
-	{ 0x2f, KEY_SEARCH },	/* scan / menu / playlist */
-	{ 0x30, KEY_CHANNEL },	/* CH surfing / bookmark / memo */
-
-	{ 0x31, KEY_HELP },	/* help */
-	{ 0x32, KEY_MODE },	/* num/memo */
-	{ 0x33, KEY_ESC },	/* cancel */
-
-	{ 0x0c, KEY_UP },	/* up */
-	{ 0x10, KEY_DOWN },	/* down */
-	{ 0x08, KEY_LEFT },	/* left */
-	{ 0x04, KEY_RIGHT },	/* right */
-	{ 0x03, KEY_SELECT },	/* select */
-
-	{ 0x1f, KEY_REWIND },	/* rewind */
-	{ 0x20, KEY_PLAYPAUSE },/* play/pause */
-	{ 0x29, KEY_FORWARD },	/* forward */
-	{ 0x14, KEY_AGAIN },	/* repeat */
-	{ 0x2b, KEY_RECORD },	/* recording */
-	{ 0x2c, KEY_STOP },	/* stop */
-	{ 0x2d, KEY_PLAY },	/* play */
-	{ 0x2e, KEY_CAMERA },	/* snapshot / shuffle */
-
-	{ 0x00, KEY_0 },
-	{ 0x05, KEY_1 },
-	{ 0x06, KEY_2 },
-	{ 0x07, KEY_3 },
-	{ 0x09, KEY_4 },
-	{ 0x0a, KEY_5 },
-	{ 0x0b, KEY_6 },
-	{ 0x0d, KEY_7 },
-	{ 0x0e, KEY_8 },
-	{ 0x0f, KEY_9 },
-
-	{ 0x2a, KEY_VOLUMEUP },
-	{ 0x11, KEY_VOLUMEDOWN },
-	{ 0x18, KEY_CHANNELUP },/* CH.tracking up */
-	{ 0x19, KEY_CHANNELDOWN },/* CH.tracking down */
-
-	{ 0x13, KEY_ENTER },	/* enter */
-	{ 0x21, KEY_DOT },	/* . (decimal dot) */
-};
-
-struct ir_scancode_table ir_codes_eztv_table = {
-	.scan = ir_codes_eztv,
-	.size = ARRAY_SIZE(ir_codes_eztv),
-};
-EXPORT_SYMBOL_GPL(ir_codes_eztv_table);
-
-/* Alex Hermann <gaaf@gmx.net> */
-static struct ir_scancode ir_codes_avermedia[] = {
-	{ 0x28, KEY_1 },
-	{ 0x18, KEY_2 },
-	{ 0x38, KEY_3 },
-	{ 0x24, KEY_4 },
-	{ 0x14, KEY_5 },
-	{ 0x34, KEY_6 },
-	{ 0x2c, KEY_7 },
-	{ 0x1c, KEY_8 },
-	{ 0x3c, KEY_9 },
-	{ 0x22, KEY_0 },
-
-	{ 0x20, KEY_TV },		/* TV/FM */
-	{ 0x10, KEY_CD },		/* CD */
-	{ 0x30, KEY_TEXT },		/* TELETEXT */
-	{ 0x00, KEY_POWER },		/* POWER */
-
-	{ 0x08, KEY_VIDEO },		/* VIDEO */
-	{ 0x04, KEY_AUDIO },		/* AUDIO */
-	{ 0x0c, KEY_ZOOM },		/* FULL SCREEN */
-
-	{ 0x12, KEY_SUBTITLE },		/* DISPLAY */
-	{ 0x32, KEY_REWIND },		/* LOOP	*/
-	{ 0x02, KEY_PRINT },		/* PREVIEW */
-
-	{ 0x2a, KEY_SEARCH },		/* AUTOSCAN */
-	{ 0x1a, KEY_SLEEP },		/* FREEZE */
-	{ 0x3a, KEY_CAMERA },		/* SNAPSHOT */
-	{ 0x0a, KEY_MUTE },		/* MUTE */
-
-	{ 0x26, KEY_RECORD },		/* RECORD */
-	{ 0x16, KEY_PAUSE },		/* PAUSE */
-	{ 0x36, KEY_STOP },		/* STOP */
-	{ 0x06, KEY_PLAY },		/* PLAY */
-
-	{ 0x2e, KEY_RED },		/* RED */
-	{ 0x21, KEY_GREEN },		/* GREEN */
-	{ 0x0e, KEY_YELLOW },		/* YELLOW */
-	{ 0x01, KEY_BLUE },		/* BLUE */
-
-	{ 0x1e, KEY_VOLUMEDOWN },	/* VOLUME- */
-	{ 0x3e, KEY_VOLUMEUP },		/* VOLUME+ */
-	{ 0x11, KEY_CHANNELDOWN },	/* CHANNEL/PAGE- */
-	{ 0x31, KEY_CHANNELUP }		/* CHANNEL/PAGE+ */
-};
-
-struct ir_scancode_table ir_codes_avermedia_table = {
-	.scan = ir_codes_avermedia,
-	.size = ARRAY_SIZE(ir_codes_avermedia),
-};
-EXPORT_SYMBOL_GPL(ir_codes_avermedia_table);
-
-static struct ir_scancode ir_codes_videomate_tv_pvr[] = {
-	{ 0x14, KEY_MUTE },
-	{ 0x24, KEY_ZOOM },
-
-	{ 0x01, KEY_DVD },
-	{ 0x23, KEY_RADIO },
-	{ 0x00, KEY_TV },
-
-	{ 0x0a, KEY_REWIND },
-	{ 0x08, KEY_PLAYPAUSE },
-	{ 0x0f, KEY_FORWARD },
-
-	{ 0x02, KEY_PREVIOUS },
-	{ 0x07, KEY_STOP },
-	{ 0x06, KEY_NEXT },
-
-	{ 0x0c, KEY_UP },
-	{ 0x0e, KEY_DOWN },
-	{ 0x0b, KEY_LEFT },
-	{ 0x0d, KEY_RIGHT },
-	{ 0x11, KEY_OK },
-
-	{ 0x03, KEY_MENU },
-	{ 0x09, KEY_SETUP },
-	{ 0x05, KEY_VIDEO },
-	{ 0x22, KEY_CHANNEL },
-
-	{ 0x12, KEY_VOLUMEUP },
-	{ 0x15, KEY_VOLUMEDOWN },
-	{ 0x10, KEY_CHANNELUP },
-	{ 0x13, KEY_CHANNELDOWN },
-
-	{ 0x04, KEY_RECORD },
-
-	{ 0x16, KEY_1 },
-	{ 0x17, KEY_2 },
-	{ 0x18, KEY_3 },
-	{ 0x19, KEY_4 },
-	{ 0x1a, KEY_5 },
-	{ 0x1b, KEY_6 },
-	{ 0x1c, KEY_7 },
-	{ 0x1d, KEY_8 },
-	{ 0x1e, KEY_9 },
-	{ 0x1f, KEY_0 },
-
-	{ 0x20, KEY_LANGUAGE },
-	{ 0x21, KEY_SLEEP },
-};
-
-struct ir_scancode_table ir_codes_videomate_tv_pvr_table = {
-	.scan = ir_codes_videomate_tv_pvr,
-	.size = ARRAY_SIZE(ir_codes_videomate_tv_pvr),
-};
-EXPORT_SYMBOL_GPL(ir_codes_videomate_tv_pvr_table);
-
-/* Michael Tokarev <mjt@tls.msk.ru>
-   http://www.corpit.ru/mjt/beholdTV/remote_control.jpg
-   keytable is used by MANLI MTV00[0x0c] and BeholdTV 40[13] at
-   least, and probably other cards too.
-   The "ascii-art picture" below (in comments, first row
-   is the keycode in hex, and subsequent row(s) shows
-   the button labels (several variants when appropriate)
-   helps to descide which keycodes to assign to the buttons.
- */
-static struct ir_scancode ir_codes_manli[] = {
-
-	/*  0x1c            0x12  *
-	 * FUNCTION         POWER *
-	 *   FM              (|)  *
-	 *                        */
-	{ 0x1c, KEY_RADIO },	/*XXX*/
-	{ 0x12, KEY_POWER },
-
-	/*  0x01    0x02    0x03  *
-	 *   1       2       3    *
-	 *                        *
-	 *  0x04    0x05    0x06  *
-	 *   4       5       6    *
-	 *                        *
-	 *  0x07    0x08    0x09  *
-	 *   7       8       9    *
-	 *                        */
-	{ 0x01, KEY_1 },
-	{ 0x02, KEY_2 },
-	{ 0x03, KEY_3 },
-	{ 0x04, KEY_4 },
-	{ 0x05, KEY_5 },
-	{ 0x06, KEY_6 },
-	{ 0x07, KEY_7 },
-	{ 0x08, KEY_8 },
-	{ 0x09, KEY_9 },
-
-	/*  0x0a    0x00    0x17  *
-	 * RECALL    0      +100  *
-	 *                  PLUS  *
-	 *                        */
-	{ 0x0a, KEY_AGAIN },	/*XXX KEY_REWIND? */
-	{ 0x00, KEY_0 },
-	{ 0x17, KEY_DIGITS },	/*XXX*/
-
-	/*  0x14            0x10  *
-	 *  MENU            INFO  *
-	 *  OSD                   */
-	{ 0x14, KEY_MENU },
-	{ 0x10, KEY_INFO },
-
-	/*          0x0b          *
-	 *           Up           *
-	 *                        *
-	 *  0x18    0x16    0x0c  *
-	 *  Left     Ok     Right *
-	 *                        *
-	 *         0x015          *
-	 *         Down           *
-	 *                        */
-	{ 0x0b, KEY_UP },
-	{ 0x18, KEY_LEFT },
-	{ 0x16, KEY_OK },	/*XXX KEY_SELECT? KEY_ENTER? */
-	{ 0x0c, KEY_RIGHT },
-	{ 0x15, KEY_DOWN },
-
-	/*  0x11            0x0d  *
-	 *  TV/AV           MODE  *
-	 *  SOURCE         STEREO *
-	 *                        */
-	{ 0x11, KEY_TV },	/*XXX*/
-	{ 0x0d, KEY_MODE },	/*XXX there's no KEY_STEREO	*/
-
-	/*  0x0f    0x1b    0x1a  *
-	 *  AUDIO   Vol+    Chan+ *
-	 *        TIMESHIFT???    *
-	 *                        *
-	 *  0x0e    0x1f    0x1e  *
-	 *  SLEEP   Vol-    Chan- *
-	 *                        */
-	{ 0x0f, KEY_AUDIO },
-	{ 0x1b, KEY_VOLUMEUP },
-	{ 0x1a, KEY_CHANNELUP },
-	{ 0x0e, KEY_TIME },
-	{ 0x1f, KEY_VOLUMEDOWN },
-	{ 0x1e, KEY_CHANNELDOWN },
-
-	/*         0x13     0x19  *
-	 *         MUTE   SNAPSHOT*
-	 *                        */
-	{ 0x13, KEY_MUTE },
-	{ 0x19, KEY_CAMERA },
-
-	/* 0x1d unused ? */
-};
-
-struct ir_scancode_table ir_codes_manli_table = {
-	.scan = ir_codes_manli,
-	.size = ARRAY_SIZE(ir_codes_manli),
-};
-EXPORT_SYMBOL_GPL(ir_codes_manli_table);
-
-/* Mike Baikov <mike@baikov.com> */
-static struct ir_scancode ir_codes_gotview7135[] = {
-
-	{ 0x11, KEY_POWER },
-	{ 0x35, KEY_TV },
-	{ 0x1b, KEY_0 },
-	{ 0x29, KEY_1 },
-	{ 0x19, KEY_2 },
-	{ 0x39, KEY_3 },
-	{ 0x1f, KEY_4 },
-	{ 0x2c, KEY_5 },
-	{ 0x21, KEY_6 },
-	{ 0x24, KEY_7 },
-	{ 0x18, KEY_8 },
-	{ 0x2b, KEY_9 },
-	{ 0x3b, KEY_AGAIN },	/* LOOP */
-	{ 0x06, KEY_AUDIO },
-	{ 0x31, KEY_PRINT },	/* PREVIEW */
-	{ 0x3e, KEY_VIDEO },
-	{ 0x10, KEY_CHANNELUP },
-	{ 0x20, KEY_CHANNELDOWN },
-	{ 0x0c, KEY_VOLUMEDOWN },
-	{ 0x28, KEY_VOLUMEUP },
-	{ 0x08, KEY_MUTE },
-	{ 0x26, KEY_SEARCH },	/* SCAN */
-	{ 0x3f, KEY_CAMERA },	/* SNAPSHOT */
-	{ 0x12, KEY_RECORD },
-	{ 0x32, KEY_STOP },
-	{ 0x3c, KEY_PLAY },
-	{ 0x1d, KEY_REWIND },
-	{ 0x2d, KEY_PAUSE },
-	{ 0x0d, KEY_FORWARD },
-	{ 0x05, KEY_ZOOM },	/*FULL*/
-
-	{ 0x2a, KEY_F21 },	/* LIVE TIMESHIFT */
-	{ 0x0e, KEY_F22 },	/* MIN TIMESHIFT */
-	{ 0x1e, KEY_TIME },	/* TIMESHIFT */
-	{ 0x38, KEY_F24 },	/* NORMAL TIMESHIFT */
-};
-
-struct ir_scancode_table ir_codes_gotview7135_table = {
-	.scan = ir_codes_gotview7135,
-	.size = ARRAY_SIZE(ir_codes_gotview7135),
-};
-EXPORT_SYMBOL_GPL(ir_codes_gotview7135_table);
-
-static struct ir_scancode ir_codes_purpletv[] = {
-	{ 0x03, KEY_POWER },
-	{ 0x6f, KEY_MUTE },
-	{ 0x10, KEY_BACKSPACE },	/* Recall */
-
-	{ 0x11, KEY_0 },
-	{ 0x04, KEY_1 },
-	{ 0x05, KEY_2 },
-	{ 0x06, KEY_3 },
-	{ 0x08, KEY_4 },
-	{ 0x09, KEY_5 },
-	{ 0x0a, KEY_6 },
-	{ 0x0c, KEY_7 },
-	{ 0x0d, KEY_8 },
-	{ 0x0e, KEY_9 },
-	{ 0x12, KEY_DOT },	/* 100+ */
-
-	{ 0x07, KEY_VOLUMEUP },
-	{ 0x0b, KEY_VOLUMEDOWN },
-	{ 0x1a, KEY_KPPLUS },
-	{ 0x18, KEY_KPMINUS },
-	{ 0x15, KEY_UP },
-	{ 0x1d, KEY_DOWN },
-	{ 0x0f, KEY_CHANNELUP },
-	{ 0x13, KEY_CHANNELDOWN },
-	{ 0x48, KEY_ZOOM },
-
-	{ 0x1b, KEY_VIDEO },	/* Video source */
-	{ 0x1f, KEY_CAMERA },	/* Snapshot */
-	{ 0x49, KEY_LANGUAGE },	/* MTS Select */
-	{ 0x19, KEY_SEARCH },	/* Auto Scan */
-
-	{ 0x4b, KEY_RECORD },
-	{ 0x46, KEY_PLAY },
-	{ 0x45, KEY_PAUSE },	/* Pause */
-	{ 0x44, KEY_STOP },
-	{ 0x43, KEY_TIME },	/* Time Shift */
-	{ 0x17, KEY_CHANNEL },	/* SURF CH */
-	{ 0x40, KEY_FORWARD },	/* Forward ? */
-	{ 0x42, KEY_REWIND },	/* Backward ? */
-
-};
-
-struct ir_scancode_table ir_codes_purpletv_table = {
-	.scan = ir_codes_purpletv,
-	.size = ARRAY_SIZE(ir_codes_purpletv),
-};
-EXPORT_SYMBOL_GPL(ir_codes_purpletv_table);
-
-/* Mapping for the 28 key remote control as seen at
-   http://www.sednacomputer.com/photo/cardbus-tv.jpg
-   Pavel Mihaylov <bin@bash.info>
-   Also for the remote bundled with Kozumi KTV-01C card */
-static struct ir_scancode ir_codes_pctv_sedna[] = {
-	{ 0x00, KEY_0 },
-	{ 0x01, KEY_1 },
-	{ 0x02, KEY_2 },
-	{ 0x03, KEY_3 },
-	{ 0x04, KEY_4 },
-	{ 0x05, KEY_5 },
-	{ 0x06, KEY_6 },
-	{ 0x07, KEY_7 },
-	{ 0x08, KEY_8 },
-	{ 0x09, KEY_9 },
-
-	{ 0x0a, KEY_AGAIN },	/* Recall */
-	{ 0x0b, KEY_CHANNELUP },
-	{ 0x0c, KEY_VOLUMEUP },
-	{ 0x0d, KEY_MODE },	/* Stereo */
-	{ 0x0e, KEY_STOP },
-	{ 0x0f, KEY_PREVIOUSSONG },
-	{ 0x10, KEY_ZOOM },
-	{ 0x11, KEY_TUNER },	/* Source */
-	{ 0x12, KEY_POWER },
-	{ 0x13, KEY_MUTE },
-	{ 0x15, KEY_CHANNELDOWN },
-	{ 0x18, KEY_VOLUMEDOWN },
-	{ 0x19, KEY_CAMERA },	/* Snapshot */
-	{ 0x1a, KEY_NEXTSONG },
-	{ 0x1b, KEY_TIME },	/* Time Shift */
-	{ 0x1c, KEY_RADIO },	/* FM Radio */
-	{ 0x1d, KEY_RECORD },
-	{ 0x1e, KEY_PAUSE },
-	/* additional codes for Kozumi's remote */
-	{ 0x14, KEY_INFO },	/* OSD */
-	{ 0x16, KEY_OK },	/* OK */
-	{ 0x17, KEY_DIGITS },	/* Plus */
-	{ 0x1f, KEY_PLAY },	/* Play */
-};
-
-struct ir_scancode_table ir_codes_pctv_sedna_table = {
-	.scan = ir_codes_pctv_sedna,
-	.size = ARRAY_SIZE(ir_codes_pctv_sedna),
-};
-EXPORT_SYMBOL_GPL(ir_codes_pctv_sedna_table);
-
-/* Mark Phalan <phalanm@o2.ie> */
-static struct ir_scancode ir_codes_pv951[] = {
-	{ 0x00, KEY_0 },
-	{ 0x01, KEY_1 },
-	{ 0x02, KEY_2 },
-	{ 0x03, KEY_3 },
-	{ 0x04, KEY_4 },
-	{ 0x05, KEY_5 },
-	{ 0x06, KEY_6 },
-	{ 0x07, KEY_7 },
-	{ 0x08, KEY_8 },
-	{ 0x09, KEY_9 },
-
-	{ 0x12, KEY_POWER },
-	{ 0x10, KEY_MUTE },
-	{ 0x1f, KEY_VOLUMEDOWN },
-	{ 0x1b, KEY_VOLUMEUP },
-	{ 0x1a, KEY_CHANNELUP },
-	{ 0x1e, KEY_CHANNELDOWN },
-	{ 0x0e, KEY_PAGEUP },
-	{ 0x1d, KEY_PAGEDOWN },
-	{ 0x13, KEY_SOUND },
-
-	{ 0x18, KEY_KPPLUSMINUS },	/* CH +/- */
-	{ 0x16, KEY_SUBTITLE },		/* CC */
-	{ 0x0d, KEY_TEXT },		/* TTX */
-	{ 0x0b, KEY_TV },		/* AIR/CBL */
-	{ 0x11, KEY_PC },		/* PC/TV */
-	{ 0x17, KEY_OK },		/* CH RTN */
-	{ 0x19, KEY_MODE },		/* FUNC */
-	{ 0x0c, KEY_SEARCH },		/* AUTOSCAN */
-
-	/* Not sure what to do with these ones! */
-	{ 0x0f, KEY_SELECT },		/* SOURCE */
-	{ 0x0a, KEY_KPPLUS },		/* +100 */
-	{ 0x14, KEY_EQUAL },		/* SYNC */
-	{ 0x1c, KEY_MEDIA },		/* PC/TV */
-};
-
-struct ir_scancode_table ir_codes_pv951_table = {
-	.scan = ir_codes_pv951,
-	.size = ARRAY_SIZE(ir_codes_pv951),
-};
-EXPORT_SYMBOL_GPL(ir_codes_pv951_table);
-
-/* generic RC5 keytable                                          */
-/* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */
-/* used by old (black) Hauppauge remotes                         */
-static struct ir_scancode ir_codes_rc5_tv[] = {
-	/* Keys 0 to 9 */
-	{ 0x00, KEY_0 },
-	{ 0x01, KEY_1 },
-	{ 0x02, KEY_2 },
-	{ 0x03, KEY_3 },
-	{ 0x04, KEY_4 },
-	{ 0x05, KEY_5 },
-	{ 0x06, KEY_6 },
-	{ 0x07, KEY_7 },
-	{ 0x08, KEY_8 },
-	{ 0x09, KEY_9 },
-
-	{ 0x0b, KEY_CHANNEL },		/* channel / program (japan: 11) */
-	{ 0x0c, KEY_POWER },		/* standby */
-	{ 0x0d, KEY_MUTE },		/* mute / demute */
-	{ 0x0f, KEY_TV },		/* display */
-	{ 0x10, KEY_VOLUMEUP },
-	{ 0x11, KEY_VOLUMEDOWN },
-	{ 0x12, KEY_BRIGHTNESSUP },
-	{ 0x13, KEY_BRIGHTNESSDOWN },
-	{ 0x1e, KEY_SEARCH },		/* search + */
-	{ 0x20, KEY_CHANNELUP },	/* channel / program + */
-	{ 0x21, KEY_CHANNELDOWN },	/* channel / program - */
-	{ 0x22, KEY_CHANNEL },		/* alt / channel */
-	{ 0x23, KEY_LANGUAGE },		/* 1st / 2nd language */
-	{ 0x26, KEY_SLEEP },		/* sleeptimer */
-	{ 0x2e, KEY_MENU },		/* 2nd controls (USA: menu) */
-	{ 0x30, KEY_PAUSE },
-	{ 0x32, KEY_REWIND },
-	{ 0x33, KEY_GOTO },
-	{ 0x35, KEY_PLAY },
-	{ 0x36, KEY_STOP },
-	{ 0x37, KEY_RECORD },		/* recording */
-	{ 0x3c, KEY_TEXT },		/* teletext submode (Japan: 12) */
-	{ 0x3d, KEY_SUSPEND },		/* system standby */
-
-};
-
-struct ir_scancode_table ir_codes_rc5_tv_table = {
-	.scan = ir_codes_rc5_tv,
-	.size = ARRAY_SIZE(ir_codes_rc5_tv),
-};
-EXPORT_SYMBOL_GPL(ir_codes_rc5_tv_table);
-
-/* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */
-static struct ir_scancode ir_codes_winfast[] = {
-	/* Keys 0 to 9 */
-	{ 0x12, KEY_0 },
-	{ 0x05, KEY_1 },
-	{ 0x06, KEY_2 },
-	{ 0x07, KEY_3 },
-	{ 0x09, KEY_4 },
-	{ 0x0a, KEY_5 },
-	{ 0x0b, KEY_6 },
-	{ 0x0d, KEY_7 },
-	{ 0x0e, KEY_8 },
-	{ 0x0f, KEY_9 },
-
-	{ 0x00, KEY_POWER },
-	{ 0x1b, KEY_AUDIO },		/* Audio Source */
-	{ 0x02, KEY_TUNER },		/* TV/FM, not on Y0400052 */
-	{ 0x1e, KEY_VIDEO },		/* Video Source */
-	{ 0x16, KEY_INFO },		/* Display information */
-	{ 0x04, KEY_VOLUMEUP },
-	{ 0x08, KEY_VOLUMEDOWN },
-	{ 0x0c, KEY_CHANNELUP },
-	{ 0x10, KEY_CHANNELDOWN },
-	{ 0x03, KEY_ZOOM },		/* fullscreen */
-	{ 0x1f, KEY_TEXT },		/* closed caption/teletext */
-	{ 0x20, KEY_SLEEP },
-	{ 0x29, KEY_CLEAR },		/* boss key */
-	{ 0x14, KEY_MUTE },
-	{ 0x2b, KEY_RED },
-	{ 0x2c, KEY_GREEN },
-	{ 0x2d, KEY_YELLOW },
-	{ 0x2e, KEY_BLUE },
-	{ 0x18, KEY_KPPLUS },		/* fine tune + , not on Y040052 */
-	{ 0x19, KEY_KPMINUS },		/* fine tune - , not on Y040052 */
-	{ 0x2a, KEY_MEDIA },		/* PIP (Picture in picture */
-	{ 0x21, KEY_DOT },
-	{ 0x13, KEY_ENTER },
-	{ 0x11, KEY_LAST },		/* Recall (last channel */
-	{ 0x22, KEY_PREVIOUS },
-	{ 0x23, KEY_PLAYPAUSE },
-	{ 0x24, KEY_NEXT },
-	{ 0x25, KEY_TIME },		/* Time Shifting */
-	{ 0x26, KEY_STOP },
-	{ 0x27, KEY_RECORD },
-	{ 0x28, KEY_SAVE },		/* Screenshot */
-	{ 0x2f, KEY_MENU },
-	{ 0x30, KEY_CANCEL },
-	{ 0x31, KEY_CHANNEL },		/* Channel Surf */
-	{ 0x32, KEY_SUBTITLE },
-	{ 0x33, KEY_LANGUAGE },
-	{ 0x34, KEY_REWIND },
-	{ 0x35, KEY_FASTFORWARD },
-	{ 0x36, KEY_TV },
-	{ 0x37, KEY_RADIO },		/* FM */
-	{ 0x38, KEY_DVD },
-
-	{ 0x1a, KEY_MODE},		/* change to MCE mode on Y04G0051 */
-	{ 0x3e, KEY_F21 },		/* MCE +VOL, on Y04G0033 */
-	{ 0x3a, KEY_F22 },		/* MCE -VOL, on Y04G0033 */
-	{ 0x3b, KEY_F23 },		/* MCE +CH,  on Y04G0033 */
-	{ 0x3f, KEY_F24 }		/* MCE -CH,  on Y04G0033 */
-};
-
-struct ir_scancode_table ir_codes_winfast_table = {
-	.scan = ir_codes_winfast,
-	.size = ARRAY_SIZE(ir_codes_winfast),
-};
-EXPORT_SYMBOL_GPL(ir_codes_winfast_table);
-
-static struct ir_scancode ir_codes_pinnacle_color[] = {
-	{ 0x59, KEY_MUTE },
-	{ 0x4a, KEY_POWER },
-
-	{ 0x18, KEY_TEXT },
-	{ 0x26, KEY_TV },
-	{ 0x3d, KEY_PRINT },
-
-	{ 0x48, KEY_RED },
-	{ 0x04, KEY_GREEN },
-	{ 0x11, KEY_YELLOW },
-	{ 0x00, KEY_BLUE },
-
-	{ 0x2d, KEY_VOLUMEUP },
-	{ 0x1e, KEY_VOLUMEDOWN },
-
-	{ 0x49, KEY_MENU },
-
-	{ 0x16, KEY_CHANNELUP },
-	{ 0x17, KEY_CHANNELDOWN },
-
-	{ 0x20, KEY_UP },
-	{ 0x21, KEY_DOWN },
-	{ 0x22, KEY_LEFT },
-	{ 0x23, KEY_RIGHT },
-	{ 0x0d, KEY_SELECT },
-
-	{ 0x08, KEY_BACK },
-	{ 0x07, KEY_REFRESH },
-
-	{ 0x2f, KEY_ZOOM },
-	{ 0x29, KEY_RECORD },
-
-	{ 0x4b, KEY_PAUSE },
-	{ 0x4d, KEY_REWIND },
-	{ 0x2e, KEY_PLAY },
-	{ 0x4e, KEY_FORWARD },
-	{ 0x53, KEY_PREVIOUS },
-	{ 0x4c, KEY_STOP },
-	{ 0x54, KEY_NEXT },
-
-	{ 0x69, KEY_0 },
-	{ 0x6a, KEY_1 },
-	{ 0x6b, KEY_2 },
-	{ 0x6c, KEY_3 },
-	{ 0x6d, KEY_4 },
-	{ 0x6e, KEY_5 },
-	{ 0x6f, KEY_6 },
-	{ 0x70, KEY_7 },
-	{ 0x71, KEY_8 },
-	{ 0x72, KEY_9 },
-
-	{ 0x74, KEY_CHANNEL },
-	{ 0x0a, KEY_BACKSPACE },
-};
-
-struct ir_scancode_table ir_codes_pinnacle_color_table = {
-	.scan = ir_codes_pinnacle_color,
-	.size = ARRAY_SIZE(ir_codes_pinnacle_color),
-};
-EXPORT_SYMBOL_GPL(ir_codes_pinnacle_color_table);
-
-/* Hauppauge: the newer, gray remotes (seems there are multiple
- * slightly different versions), shipped with cx88+ivtv cards.
- * almost rc5 coding, but some non-standard keys */
-static struct ir_scancode ir_codes_hauppauge_new[] = {
-	/* Keys 0 to 9 */
-	{ 0x00, KEY_0 },
-	{ 0x01, KEY_1 },
-	{ 0x02, KEY_2 },
-	{ 0x03, KEY_3 },
-	{ 0x04, KEY_4 },
-	{ 0x05, KEY_5 },
-	{ 0x06, KEY_6 },
-	{ 0x07, KEY_7 },
-	{ 0x08, KEY_8 },
-	{ 0x09, KEY_9 },
-
-	{ 0x0a, KEY_TEXT },		/* keypad asterisk as well */
-	{ 0x0b, KEY_RED },		/* red button */
-	{ 0x0c, KEY_RADIO },
-	{ 0x0d, KEY_MENU },
-	{ 0x0e, KEY_SUBTITLE },		/* also the # key */
-	{ 0x0f, KEY_MUTE },
-	{ 0x10, KEY_VOLUMEUP },
-	{ 0x11, KEY_VOLUMEDOWN },
-	{ 0x12, KEY_PREVIOUS },		/* previous channel */
-	{ 0x14, KEY_UP },
-	{ 0x15, KEY_DOWN },
-	{ 0x16, KEY_LEFT },
-	{ 0x17, KEY_RIGHT },
-	{ 0x18, KEY_VIDEO },		/* Videos */
-	{ 0x19, KEY_AUDIO },		/* Music */
-	/* 0x1a: Pictures - presume this means
-	   "Multimedia Home Platform" -
-	   no "PICTURES" key in input.h
-	 */
-	{ 0x1a, KEY_MHP },
-
-	{ 0x1b, KEY_EPG },		/* Guide */
-	{ 0x1c, KEY_TV },
-	{ 0x1e, KEY_NEXTSONG },		/* skip >| */
-	{ 0x1f, KEY_EXIT },		/* back/exit */
-	{ 0x20, KEY_CHANNELUP },	/* channel / program + */
-	{ 0x21, KEY_CHANNELDOWN },	/* channel / program - */
-	{ 0x22, KEY_CHANNEL },		/* source (old black remote) */
-	{ 0x24, KEY_PREVIOUSSONG },	/* replay |< */
-	{ 0x25, KEY_ENTER },		/* OK */
-	{ 0x26, KEY_SLEEP },		/* minimize (old black remote) */
-	{ 0x29, KEY_BLUE },		/* blue key */
-	{ 0x2e, KEY_GREEN },		/* green button */
-	{ 0x30, KEY_PAUSE },		/* pause */
-	{ 0x32, KEY_REWIND },		/* backward << */
-	{ 0x34, KEY_FASTFORWARD },	/* forward >> */
-	{ 0x35, KEY_PLAY },
-	{ 0x36, KEY_STOP },
-	{ 0x37, KEY_RECORD },		/* recording */
-	{ 0x38, KEY_YELLOW },		/* yellow key */
-	{ 0x3b, KEY_SELECT },		/* top right button */
-	{ 0x3c, KEY_ZOOM },		/* full */
-	{ 0x3d, KEY_POWER },		/* system power (green button) */
-};
-
-struct ir_scancode_table ir_codes_hauppauge_new_table = {
-	.scan = ir_codes_hauppauge_new,
-	.size = ARRAY_SIZE(ir_codes_hauppauge_new),
-};
-EXPORT_SYMBOL_GPL(ir_codes_hauppauge_new_table);
-
-static struct ir_scancode ir_codes_npgtech[] = {
-	{ 0x1d, KEY_SWITCHVIDEOMODE },	/* switch inputs */
-	{ 0x2a, KEY_FRONT },
-
-	{ 0x3e, KEY_1 },
-	{ 0x02, KEY_2 },
-	{ 0x06, KEY_3 },
-	{ 0x0a, KEY_4 },
-	{ 0x0e, KEY_5 },
-	{ 0x12, KEY_6 },
-	{ 0x16, KEY_7 },
-	{ 0x1a, KEY_8 },
-	{ 0x1e, KEY_9 },
-	{ 0x3a, KEY_0 },
-	{ 0x22, KEY_NUMLOCK },		/* -/-- */
-	{ 0x20, KEY_REFRESH },
-
-	{ 0x03, KEY_BRIGHTNESSDOWN },
-	{ 0x28, KEY_AUDIO },
-	{ 0x3c, KEY_CHANNELUP },
-	{ 0x3f, KEY_VOLUMEDOWN },
-	{ 0x2e, KEY_MUTE },
-	{ 0x3b, KEY_VOLUMEUP },
-	{ 0x00, KEY_CHANNELDOWN },
-	{ 0x07, KEY_BRIGHTNESSUP },
-	{ 0x2c, KEY_TEXT },
-
-	{ 0x37, KEY_RECORD },
-	{ 0x17, KEY_PLAY },
-	{ 0x13, KEY_PAUSE },
-	{ 0x26, KEY_STOP },
-	{ 0x18, KEY_FASTFORWARD },
-	{ 0x14, KEY_REWIND },
-	{ 0x33, KEY_ZOOM },
-	{ 0x32, KEY_KEYBOARD },
-	{ 0x30, KEY_GOTO },		/* Pointing arrow */
-	{ 0x36, KEY_MACRO },		/* Maximize/Minimize (yellow) */
-	{ 0x0b, KEY_RADIO },
-	{ 0x10, KEY_POWER },
-
-};
-
-struct ir_scancode_table ir_codes_npgtech_table = {
-	.scan = ir_codes_npgtech,
-	.size = ARRAY_SIZE(ir_codes_npgtech),
-};
-EXPORT_SYMBOL_GPL(ir_codes_npgtech_table);
-
-/* Norwood Micro (non-Pro) TV Tuner
-   By Peter Naulls <peter@chocky.org>
-   Key comments are the functions given in the manual */
-static struct ir_scancode ir_codes_norwood[] = {
-	/* Keys 0 to 9 */
-	{ 0x20, KEY_0 },
-	{ 0x21, KEY_1 },
-	{ 0x22, KEY_2 },
-	{ 0x23, KEY_3 },
-	{ 0x24, KEY_4 },
-	{ 0x25, KEY_5 },
-	{ 0x26, KEY_6 },
-	{ 0x27, KEY_7 },
-	{ 0x28, KEY_8 },
-	{ 0x29, KEY_9 },
-
-	{ 0x78, KEY_TUNER },		/* Video Source        */
-	{ 0x2c, KEY_EXIT },		/* Open/Close software */
-	{ 0x2a, KEY_SELECT },		/* 2 Digit Select      */
-	{ 0x69, KEY_AGAIN },		/* Recall              */
-
-	{ 0x32, KEY_BRIGHTNESSUP },	/* Brightness increase */
-	{ 0x33, KEY_BRIGHTNESSDOWN },	/* Brightness decrease */
-	{ 0x6b, KEY_KPPLUS },		/* (not named >>>>>)   */
-	{ 0x6c, KEY_KPMINUS },		/* (not named <<<<<)   */
-
-	{ 0x2d, KEY_MUTE },		/* Mute                */
-	{ 0x30, KEY_VOLUMEUP },		/* Volume up           */
-	{ 0x31, KEY_VOLUMEDOWN },	/* Volume down         */
-	{ 0x60, KEY_CHANNELUP },	/* Channel up          */
-	{ 0x61, KEY_CHANNELDOWN },	/* Channel down        */
-
-	{ 0x3f, KEY_RECORD },		/* Record              */
-	{ 0x37, KEY_PLAY },		/* Play                */
-	{ 0x36, KEY_PAUSE },		/* Pause               */
-	{ 0x2b, KEY_STOP },		/* Stop                */
-	{ 0x67, KEY_FASTFORWARD },	/* Foward              */
-	{ 0x66, KEY_REWIND },		/* Rewind              */
-	{ 0x3e, KEY_SEARCH },		/* Auto Scan           */
-	{ 0x2e, KEY_CAMERA },		/* Capture Video       */
-	{ 0x6d, KEY_MENU },		/* Show/Hide Control   */
-	{ 0x2f, KEY_ZOOM },		/* Full Screen         */
-	{ 0x34, KEY_RADIO },		/* FM                  */
-	{ 0x65, KEY_POWER },		/* Computer power      */
-};
-
-struct ir_scancode_table ir_codes_norwood_table = {
-	.scan = ir_codes_norwood,
-	.size = ARRAY_SIZE(ir_codes_norwood),
-};
-EXPORT_SYMBOL_GPL(ir_codes_norwood_table);
-
-/* From reading the following remotes:
- * Zenith Universal 7 / TV Mode 807 / VCR Mode 837
- * Hauppauge (from NOVA-CI-s box product)
- * This is a "middle of the road" approach, differences are noted
- */
-static struct ir_scancode ir_codes_budget_ci_old[] = {
-	{ 0x00, KEY_0 },
-	{ 0x01, KEY_1 },
-	{ 0x02, KEY_2 },
-	{ 0x03, KEY_3 },
-	{ 0x04, KEY_4 },
-	{ 0x05, KEY_5 },
-	{ 0x06, KEY_6 },
-	{ 0x07, KEY_7 },
-	{ 0x08, KEY_8 },
-	{ 0x09, KEY_9 },
-	{ 0x0a, KEY_ENTER },
-	{ 0x0b, KEY_RED },
-	{ 0x0c, KEY_POWER },		/* RADIO on Hauppauge */
-	{ 0x0d, KEY_MUTE },
-	{ 0x0f, KEY_A },		/* TV on Hauppauge */
-	{ 0x10, KEY_VOLUMEUP },
-	{ 0x11, KEY_VOLUMEDOWN },
-	{ 0x14, KEY_B },
-	{ 0x1c, KEY_UP },
-	{ 0x1d, KEY_DOWN },
-	{ 0x1e, KEY_OPTION },		/* RESERVED on Hauppauge */
-	{ 0x1f, KEY_BREAK },
-	{ 0x20, KEY_CHANNELUP },
-	{ 0x21, KEY_CHANNELDOWN },
-	{ 0x22, KEY_PREVIOUS },		/* Prev Ch on Zenith, SOURCE on Hauppauge */
-	{ 0x24, KEY_RESTART },
-	{ 0x25, KEY_OK },
-	{ 0x26, KEY_CYCLEWINDOWS },	/* MINIMIZE on Hauppauge */
-	{ 0x28, KEY_ENTER },		/* VCR mode on Zenith */
-	{ 0x29, KEY_PAUSE },
-	{ 0x2b, KEY_RIGHT },
-	{ 0x2c, KEY_LEFT },
-	{ 0x2e, KEY_MENU },		/* FULL SCREEN on Hauppauge */
-	{ 0x30, KEY_SLOW },
-	{ 0x31, KEY_PREVIOUS },		/* VCR mode on Zenith */
-	{ 0x32, KEY_REWIND },
-	{ 0x34, KEY_FASTFORWARD },
-	{ 0x35, KEY_PLAY },
-	{ 0x36, KEY_STOP },
-	{ 0x37, KEY_RECORD },
-	{ 0x38, KEY_TUNER },		/* TV/VCR on Zenith */
-	{ 0x3a, KEY_C },
-	{ 0x3c, KEY_EXIT },
-	{ 0x3d, KEY_POWER2 },
-	{ 0x3e, KEY_TUNER },
-};
-
-struct ir_scancode_table ir_codes_budget_ci_old_table = {
-	.scan = ir_codes_budget_ci_old,
-	.size = ARRAY_SIZE(ir_codes_budget_ci_old),
-};
-EXPORT_SYMBOL_GPL(ir_codes_budget_ci_old_table);
-
-/*
- * Marc Fargas <telenieko@telenieko.com>
- * this is the remote control that comes with the asus p7131
- * which has a label saying is "Model PC-39"
- */
-static struct ir_scancode ir_codes_asus_pc39[] = {
-	/* Keys 0 to 9 */
-	{ 0x15, KEY_0 },
-	{ 0x29, KEY_1 },
-	{ 0x2d, KEY_2 },
-	{ 0x2b, KEY_3 },
-	{ 0x09, KEY_4 },
-	{ 0x0d, KEY_5 },
-	{ 0x0b, KEY_6 },
-	{ 0x31, KEY_7 },
-	{ 0x35, KEY_8 },
-	{ 0x33, KEY_9 },
-
-	{ 0x3e, KEY_RADIO },		/* radio */
-	{ 0x03, KEY_MENU },		/* dvd/menu */
-	{ 0x2a, KEY_VOLUMEUP },
-	{ 0x19, KEY_VOLUMEDOWN },
-	{ 0x37, KEY_UP },
-	{ 0x3b, KEY_DOWN },
-	{ 0x27, KEY_LEFT },
-	{ 0x2f, KEY_RIGHT },
-	{ 0x25, KEY_VIDEO },		/* video */
-	{ 0x39, KEY_AUDIO },		/* music */
-
-	{ 0x21, KEY_TV },		/* tv */
-	{ 0x1d, KEY_EXIT },		/* back */
-	{ 0x0a, KEY_CHANNELUP },	/* channel / program + */
-	{ 0x1b, KEY_CHANNELDOWN },	/* channel / program - */
-	{ 0x1a, KEY_ENTER },		/* enter */
-
-	{ 0x06, KEY_PAUSE },		/* play/pause */
-	{ 0x1e, KEY_PREVIOUS },		/* rew */
-	{ 0x26, KEY_NEXT },		/* forward */
-	{ 0x0e, KEY_REWIND },		/* backward << */
-	{ 0x3a, KEY_FASTFORWARD },	/* forward >> */
-	{ 0x36, KEY_STOP },
-	{ 0x2e, KEY_RECORD },		/* recording */
-	{ 0x16, KEY_POWER },		/* the button that reads "close" */
-
-	{ 0x11, KEY_ZOOM },		/* full screen */
-	{ 0x13, KEY_MACRO },		/* recall */
-	{ 0x23, KEY_HOME },		/* home */
-	{ 0x05, KEY_PVR },		/* picture */
-	{ 0x3d, KEY_MUTE },		/* mute */
-	{ 0x01, KEY_DVD },		/* dvd */
-};
-
-struct ir_scancode_table ir_codes_asus_pc39_table = {
-	.scan = ir_codes_asus_pc39,
-	.size = ARRAY_SIZE(ir_codes_asus_pc39),
-};
-EXPORT_SYMBOL_GPL(ir_codes_asus_pc39_table);
-
-
-/* Encore ENLTV-FM  - black plastic, white front cover with white glowing buttons
-    Juan Pablo Sormani <sorman@gmail.com> */
-static struct ir_scancode ir_codes_encore_enltv[] = {
-
-	/* Power button does nothing, neither in Windows app,
-	 although it sends data (used for BIOS wakeup?) */
-	{ 0x0d, KEY_MUTE },
-
-	{ 0x1e, KEY_TV },
-	{ 0x00, KEY_VIDEO },
-	{ 0x01, KEY_AUDIO },		/* music */
-	{ 0x02, KEY_MHP },		/* picture */
-
-	{ 0x1f, KEY_1 },
-	{ 0x03, KEY_2 },
-	{ 0x04, KEY_3 },
-	{ 0x05, KEY_4 },
-	{ 0x1c, KEY_5 },
-	{ 0x06, KEY_6 },
-	{ 0x07, KEY_7 },
-	{ 0x08, KEY_8 },
-	{ 0x1d, KEY_9 },
-	{ 0x0a, KEY_0 },
-
-	{ 0x09, KEY_LIST },		/* -/-- */
-	{ 0x0b, KEY_LAST },		/* recall */
-
-	{ 0x14, KEY_HOME },		/* win start menu */
-	{ 0x15, KEY_EXIT },		/* exit */
-	{ 0x16, KEY_CHANNELUP },	/* UP */
-	{ 0x12, KEY_CHANNELDOWN },	/* DOWN */
-	{ 0x0c, KEY_VOLUMEUP },		/* RIGHT */
-	{ 0x17, KEY_VOLUMEDOWN },	/* LEFT */
-
-	{ 0x18, KEY_ENTER },		/* OK */
-
-	{ 0x0e, KEY_ESC },
-	{ 0x13, KEY_CYCLEWINDOWS },	/* desktop */
-	{ 0x11, KEY_TAB },
-	{ 0x19, KEY_SWITCHVIDEOMODE },	/* switch */
-
-	{ 0x1a, KEY_MENU },
-	{ 0x1b, KEY_ZOOM },		/* fullscreen */
-	{ 0x44, KEY_TIME },		/* time shift */
-	{ 0x40, KEY_MODE },		/* source */
-
-	{ 0x5a, KEY_RECORD },
-	{ 0x42, KEY_PLAY },		/* play/pause */
-	{ 0x45, KEY_STOP },
-	{ 0x43, KEY_CAMERA },		/* camera icon */
-
-	{ 0x48, KEY_REWIND },
-	{ 0x4a, KEY_FASTFORWARD },
-	{ 0x49, KEY_PREVIOUS },
-	{ 0x4b, KEY_NEXT },
-
-	{ 0x4c, KEY_FAVORITES },	/* tv wall */
-	{ 0x4d, KEY_SOUND },		/* DVD sound */
-	{ 0x4e, KEY_LANGUAGE },		/* DVD lang */
-	{ 0x4f, KEY_TEXT },		/* DVD text */
-
-	{ 0x50, KEY_SLEEP },		/* shutdown */
-	{ 0x51, KEY_MODE },		/* stereo > main */
-	{ 0x52, KEY_SELECT },		/* stereo > sap */
-	{ 0x53, KEY_PROG1 },		/* teletext */
-
-
-	{ 0x59, KEY_RED },		/* AP1 */
-	{ 0x41, KEY_GREEN },		/* AP2 */
-	{ 0x47, KEY_YELLOW },		/* AP3 */
-	{ 0x57, KEY_BLUE },		/* AP4 */
-};
-
-struct ir_scancode_table ir_codes_encore_enltv_table = {
-	.scan = ir_codes_encore_enltv,
-	.size = ARRAY_SIZE(ir_codes_encore_enltv),
-};
-EXPORT_SYMBOL_GPL(ir_codes_encore_enltv_table);
-
-/* Encore ENLTV2-FM  - silver plastic - "Wand Media" written at the botton
-    Mauro Carvalho Chehab <mchehab@infradead.org> */
-static struct ir_scancode ir_codes_encore_enltv2[] = {
-	{ 0x4c, KEY_POWER2 },
-	{ 0x4a, KEY_TUNER },
-	{ 0x40, KEY_1 },
-	{ 0x60, KEY_2 },
-	{ 0x50, KEY_3 },
-	{ 0x70, KEY_4 },
-	{ 0x48, KEY_5 },
-	{ 0x68, KEY_6 },
-	{ 0x58, KEY_7 },
-	{ 0x78, KEY_8 },
-	{ 0x44, KEY_9 },
-	{ 0x54, KEY_0 },
-
-	{ 0x64, KEY_LAST },		/* +100 */
-	{ 0x4e, KEY_AGAIN },		/* Recall */
-
-	{ 0x6c, KEY_SWITCHVIDEOMODE },	/* Video Source */
-	{ 0x5e, KEY_MENU },
-	{ 0x56, KEY_SCREEN },
-	{ 0x7a, KEY_SETUP },
-
-	{ 0x46, KEY_MUTE },
-	{ 0x5c, KEY_MODE },		/* Stereo */
-	{ 0x74, KEY_INFO },
-	{ 0x7c, KEY_CLEAR },
-
-	{ 0x55, KEY_UP },
-	{ 0x49, KEY_DOWN },
-	{ 0x7e, KEY_LEFT },
-	{ 0x59, KEY_RIGHT },
-	{ 0x6a, KEY_ENTER },
-
-	{ 0x42, KEY_VOLUMEUP },
-	{ 0x62, KEY_VOLUMEDOWN },
-	{ 0x52, KEY_CHANNELUP },
-	{ 0x72, KEY_CHANNELDOWN },
-
-	{ 0x41, KEY_RECORD },
-	{ 0x51, KEY_CAMERA },		/* Snapshot */
-	{ 0x75, KEY_TIME },		/* Timeshift */
-	{ 0x71, KEY_TV2 },		/* PIP */
-
-	{ 0x45, KEY_REWIND },
-	{ 0x6f, KEY_PAUSE },
-	{ 0x7d, KEY_FORWARD },
-	{ 0x79, KEY_STOP },
-};
-
-struct ir_scancode_table ir_codes_encore_enltv2_table = {
-	.scan = ir_codes_encore_enltv2,
-	.size = ARRAY_SIZE(ir_codes_encore_enltv2),
-};
-EXPORT_SYMBOL_GPL(ir_codes_encore_enltv2_table);
-
-/* for the Technotrend 1500 bundled remotes (grey and black): */
-static struct ir_scancode ir_codes_tt_1500[] = {
-	{ 0x01, KEY_POWER },
-	{ 0x02, KEY_SHUFFLE },		/* ? double-arrow key */
-	{ 0x03, KEY_1 },
-	{ 0x04, KEY_2 },
-	{ 0x05, KEY_3 },
-	{ 0x06, KEY_4 },
-	{ 0x07, KEY_5 },
-	{ 0x08, KEY_6 },
-	{ 0x09, KEY_7 },
-	{ 0x0a, KEY_8 },
-	{ 0x0b, KEY_9 },
-	{ 0x0c, KEY_0 },
-	{ 0x0d, KEY_UP },
-	{ 0x0e, KEY_LEFT },
-	{ 0x0f, KEY_OK },
-	{ 0x10, KEY_RIGHT },
-	{ 0x11, KEY_DOWN },
-	{ 0x12, KEY_INFO },
-	{ 0x13, KEY_EXIT },
-	{ 0x14, KEY_RED },
-	{ 0x15, KEY_GREEN },
-	{ 0x16, KEY_YELLOW },
-	{ 0x17, KEY_BLUE },
-	{ 0x18, KEY_MUTE },
-	{ 0x19, KEY_TEXT },
-	{ 0x1a, KEY_MODE },		/* ? TV/Radio */
-	{ 0x21, KEY_OPTION },
-	{ 0x22, KEY_EPG },
-	{ 0x23, KEY_CHANNELUP },
-	{ 0x24, KEY_CHANNELDOWN },
-	{ 0x25, KEY_VOLUMEUP },
-	{ 0x26, KEY_VOLUMEDOWN },
-	{ 0x27, KEY_SETUP },
-	{ 0x3a, KEY_RECORD },		/* these keys are only in the black remote */
-	{ 0x3b, KEY_PLAY },
-	{ 0x3c, KEY_STOP },
-	{ 0x3d, KEY_REWIND },
-	{ 0x3e, KEY_PAUSE },
-	{ 0x3f, KEY_FORWARD },
-};
-
-struct ir_scancode_table ir_codes_tt_1500_table = {
-	.scan = ir_codes_tt_1500,
-	.size = ARRAY_SIZE(ir_codes_tt_1500),
-};
-EXPORT_SYMBOL_GPL(ir_codes_tt_1500_table);
-
-/* DViCO FUSION HDTV MCE remote */
-static struct ir_scancode ir_codes_fusionhdtv_mce[] = {
-
-	{ 0x0b, KEY_1 },
-	{ 0x17, KEY_2 },
-	{ 0x1b, KEY_3 },
-	{ 0x07, KEY_4 },
-	{ 0x50, KEY_5 },
-	{ 0x54, KEY_6 },
-	{ 0x48, KEY_7 },
-	{ 0x4c, KEY_8 },
-	{ 0x58, KEY_9 },
-	{ 0x03, KEY_0 },
-
-	{ 0x5e, KEY_OK },
-	{ 0x51, KEY_UP },
-	{ 0x53, KEY_DOWN },
-	{ 0x5b, KEY_LEFT },
-	{ 0x5f, KEY_RIGHT },
-
-	{ 0x02, KEY_TV },		/* Labeled DTV on remote */
-	{ 0x0e, KEY_MP3 },
-	{ 0x1a, KEY_DVD },
-	{ 0x1e, KEY_FAVORITES },	/* Labeled CPF on remote */
-	{ 0x16, KEY_SETUP },
-	{ 0x46, KEY_POWER2 },		/* TV On/Off button on remote */
-	{ 0x0a, KEY_EPG },		/* Labeled Guide on remote */
-
-	{ 0x49, KEY_BACK },
-	{ 0x59, KEY_INFO },		/* Labeled MORE on remote */
-	{ 0x4d, KEY_MENU },		/* Labeled DVDMENU on remote */
-	{ 0x55, KEY_CYCLEWINDOWS },	/* Labeled ALT-TAB on remote */
-
-	{ 0x0f, KEY_PREVIOUSSONG },	/* Labeled |<< REPLAY on remote */
-	{ 0x12, KEY_NEXTSONG },		/* Labeled >>| SKIP on remote */
-	{ 0x42, KEY_ENTER },		/* Labeled START with a green
-					   MS windows logo on remote */
-
-	{ 0x15, KEY_VOLUMEUP },
-	{ 0x05, KEY_VOLUMEDOWN },
-	{ 0x11, KEY_CHANNELUP },
-	{ 0x09, KEY_CHANNELDOWN },
-
-	{ 0x52, KEY_CAMERA },
-	{ 0x5a, KEY_TUNER },
-	{ 0x19, KEY_OPEN },
-
-	{ 0x13, KEY_MODE },		/* 4:3 16:9 select */
-	{ 0x1f, KEY_ZOOM },
-
-	{ 0x43, KEY_REWIND },
-	{ 0x47, KEY_PLAYPAUSE },
-	{ 0x4f, KEY_FASTFORWARD },
-	{ 0x57, KEY_MUTE },
-	{ 0x0d, KEY_STOP },
-	{ 0x01, KEY_RECORD },
-	{ 0x4e, KEY_POWER },
-};
-
-struct ir_scancode_table ir_codes_fusionhdtv_mce_table = {
-	.scan = ir_codes_fusionhdtv_mce,
-	.size = ARRAY_SIZE(ir_codes_fusionhdtv_mce),
-};
-EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce_table);
-
-/* Pinnacle PCTV HD 800i mini remote */
-static struct ir_scancode ir_codes_pinnacle_pctv_hd[] = {
-
-	{ 0x0f, KEY_1 },
-	{ 0x15, KEY_2 },
-	{ 0x10, KEY_3 },
-	{ 0x18, KEY_4 },
-	{ 0x1b, KEY_5 },
-	{ 0x1e, KEY_6 },
-	{ 0x11, KEY_7 },
-	{ 0x21, KEY_8 },
-	{ 0x12, KEY_9 },
-	{ 0x27, KEY_0 },
-
-	{ 0x24, KEY_ZOOM },
-	{ 0x2a, KEY_SUBTITLE },
-
-	{ 0x00, KEY_MUTE },
-	{ 0x01, KEY_ENTER },	/* Pinnacle Logo */
-	{ 0x39, KEY_POWER },
-
-	{ 0x03, KEY_VOLUMEUP },
-	{ 0x09, KEY_VOLUMEDOWN },
-	{ 0x06, KEY_CHANNELUP },
-	{ 0x0c, KEY_CHANNELDOWN },
-
-	{ 0x2d, KEY_REWIND },
-	{ 0x30, KEY_PLAYPAUSE },
-	{ 0x33, KEY_FASTFORWARD },
-	{ 0x3c, KEY_STOP },
-	{ 0x36, KEY_RECORD },
-	{ 0x3f, KEY_EPG },	/* Labeled "?" */
-};
-
-struct ir_scancode_table ir_codes_pinnacle_pctv_hd_table = {
-	.scan = ir_codes_pinnacle_pctv_hd,
-	.size = ARRAY_SIZE(ir_codes_pinnacle_pctv_hd),
-};
-EXPORT_SYMBOL_GPL(ir_codes_pinnacle_pctv_hd_table);
-
-/*
- * Igor Kuznetsov <igk72@ya.ru>
- * Andrey J. Melnikov <temnota@kmv.ru>
- *
- * Keytable is used by BeholdTV 60x series, M6 series at
- * least, and probably other cards too.
- * The "ascii-art picture" below (in comments, first row
- * is the keycode in hex, and subsequent row(s) shows
- * the button labels (several variants when appropriate)
- * helps to descide which keycodes to assign to the buttons.
- */
-static struct ir_scancode ir_codes_behold[] = {
-
-	/*  0x1c            0x12  *
-	 *  TV/FM          POWER  *
-	 *                        */
-	{ 0x1c, KEY_TUNER },	/* XXX KEY_TV / KEY_RADIO */
-	{ 0x12, KEY_POWER },
-
-	/*  0x01    0x02    0x03  *
-	 *   1       2       3    *
-	 *                        *
-	 *  0x04    0x05    0x06  *
-	 *   4       5       6    *
-	 *                        *
-	 *  0x07    0x08    0x09  *
-	 *   7       8       9    *
-	 *                        */
-	{ 0x01, KEY_1 },
-	{ 0x02, KEY_2 },
-	{ 0x03, KEY_3 },
-	{ 0x04, KEY_4 },
-	{ 0x05, KEY_5 },
-	{ 0x06, KEY_6 },
-	{ 0x07, KEY_7 },
-	{ 0x08, KEY_8 },
-	{ 0x09, KEY_9 },
-
-	/*  0x0a    0x00    0x17  *
-	 * RECALL    0      MODE  *
-	 *                        */
-	{ 0x0a, KEY_AGAIN },
-	{ 0x00, KEY_0 },
-	{ 0x17, KEY_MODE },
-
-	/*  0x14          0x10    *
-	 * ASPECT      FULLSCREEN *
-	 *                        */
-	{ 0x14, KEY_SCREEN },
-	{ 0x10, KEY_ZOOM },
-
-	/*          0x0b          *
-	 *           Up           *
-	 *                        *
-	 *  0x18    0x16    0x0c  *
-	 *  Left     Ok     Right *
-	 *                        *
-	 *         0x015          *
-	 *         Down           *
-	 *                        */
-	{ 0x0b, KEY_CHANNELUP },
-	{ 0x18, KEY_VOLUMEDOWN },
-	{ 0x16, KEY_OK },		/* XXX KEY_ENTER */
-	{ 0x0c, KEY_VOLUMEUP },
-	{ 0x15, KEY_CHANNELDOWN },
-
-	/*  0x11            0x0d  *
-	 *  MUTE            INFO  *
-	 *                        */
-	{ 0x11, KEY_MUTE },
-	{ 0x0d, KEY_INFO },
-
-	/*  0x0f    0x1b    0x1a  *
-	 * RECORD PLAY/PAUSE STOP *
-	 *                        *
-	 *  0x0e    0x1f    0x1e  *
-	 *TELETEXT  AUDIO  SOURCE *
-	 *           RED   YELLOW *
-	 *                        */
-	{ 0x0f, KEY_RECORD },
-	{ 0x1b, KEY_PLAYPAUSE },
-	{ 0x1a, KEY_STOP },
-	{ 0x0e, KEY_TEXT },
-	{ 0x1f, KEY_RED },	/*XXX KEY_AUDIO	*/
-	{ 0x1e, KEY_YELLOW },	/*XXX KEY_SOURCE	*/
-
-	/*  0x1d   0x13     0x19  *
-	 * SLEEP  PREVIEW   DVB   *
-	 *         GREEN    BLUE  *
-	 *                        */
-	{ 0x1d, KEY_SLEEP },
-	{ 0x13, KEY_GREEN },
-	{ 0x19, KEY_BLUE },	/* XXX KEY_SAT	*/
-
-	/*  0x58           0x5c   *
-	 * FREEZE        SNAPSHOT *
-	 *                        */
-	{ 0x58, KEY_SLOW },
-	{ 0x5c, KEY_CAMERA },
-
-};
-
-struct ir_scancode_table ir_codes_behold_table = {
-	.scan = ir_codes_behold,
-	.size = ARRAY_SIZE(ir_codes_behold),
-};
-EXPORT_SYMBOL_GPL(ir_codes_behold_table);
-
-/* Beholder Intl. Ltd. 2008
- * Dmitry Belimov d.belimov@google.com
- * Keytable is used by BeholdTV Columbus
- * The "ascii-art picture" below (in comments, first row
- * is the keycode in hex, and subsequent row(s) shows
- * the button labels (several variants when appropriate)
- * helps to descide which keycodes to assign to the buttons.
- */
-static struct ir_scancode ir_codes_behold_columbus[] = {
-
-	/*  0x13   0x11   0x1C   0x12  *
-	 *  Mute  Source  TV/FM  Power *
-	 *                             */
-
-	{ 0x13, KEY_MUTE },
-	{ 0x11, KEY_PROPS },
-	{ 0x1C, KEY_TUNER },	/* KEY_TV/KEY_RADIO	*/
-	{ 0x12, KEY_POWER },
-
-	/*  0x01    0x02    0x03  0x0D    *
-	 *   1       2       3   Stereo   *
-	 *                        	  *
-	 *  0x04    0x05    0x06  0x19    *
-	 *   4       5       6   Snapshot *
-	 *                        	  *
-	 *  0x07    0x08    0x09  0x10    *
-	 *   7       8       9    Zoom 	  *
-	 *                                */
-	{ 0x01, KEY_1 },
-	{ 0x02, KEY_2 },
-	{ 0x03, KEY_3 },
-	{ 0x0D, KEY_SETUP },	  /* Setup key */
-	{ 0x04, KEY_4 },
-	{ 0x05, KEY_5 },
-	{ 0x06, KEY_6 },
-	{ 0x19, KEY_CAMERA },	/* Snapshot key */
-	{ 0x07, KEY_7 },
-	{ 0x08, KEY_8 },
-	{ 0x09, KEY_9 },
-	{ 0x10, KEY_ZOOM },
-
-	/*  0x0A    0x00    0x0B       0x0C   *
-	 * RECALL    0    ChannelUp  VolumeUp *
-	 *                                    */
-	{ 0x0A, KEY_AGAIN },
-	{ 0x00, KEY_0 },
-	{ 0x0B, KEY_CHANNELUP },
-	{ 0x0C, KEY_VOLUMEUP },
-
-	/*   0x1B      0x1D      0x15        0x18     *
-	 * Timeshift  Record  ChannelDown  VolumeDown *
-	 *                                            */
-
-	{ 0x1B, KEY_TIME },
-	{ 0x1D, KEY_RECORD },
-	{ 0x15, KEY_CHANNELDOWN },
-	{ 0x18, KEY_VOLUMEDOWN },
-
-	/*   0x0E   0x1E     0x0F     0x1A  *
-	 *   Stop   Pause  Previouse  Next  *
-	 *                                  */
-
-	{ 0x0E, KEY_STOP },
-	{ 0x1E, KEY_PAUSE },
-	{ 0x0F, KEY_PREVIOUS },
-	{ 0x1A, KEY_NEXT },
-
-};
-
-struct ir_scancode_table ir_codes_behold_columbus_table = {
-	.scan = ir_codes_behold_columbus,
-	.size = ARRAY_SIZE(ir_codes_behold_columbus),
-};
-EXPORT_SYMBOL_GPL(ir_codes_behold_columbus_table);
-
-/*
- * Remote control for the Genius TVGO A11MCE
- * Adrian Pardini <pardo.bsso@gmail.com>
- */
-static struct ir_scancode ir_codes_genius_tvgo_a11mce[] = {
-	/* Keys 0 to 9 */
-	{ 0x48, KEY_0 },
-	{ 0x09, KEY_1 },
-	{ 0x1d, KEY_2 },
-	{ 0x1f, KEY_3 },
-	{ 0x19, KEY_4 },
-	{ 0x1b, KEY_5 },
-	{ 0x11, KEY_6 },
-	{ 0x17, KEY_7 },
-	{ 0x12, KEY_8 },
-	{ 0x16, KEY_9 },
-
-	{ 0x54, KEY_RECORD },		/* recording */
-	{ 0x06, KEY_MUTE },		/* mute */
-	{ 0x10, KEY_POWER },
-	{ 0x40, KEY_LAST },		/* recall */
-	{ 0x4c, KEY_CHANNELUP },	/* channel / program + */
-	{ 0x00, KEY_CHANNELDOWN },	/* channel / program - */
-	{ 0x0d, KEY_VOLUMEUP },
-	{ 0x15, KEY_VOLUMEDOWN },
-	{ 0x4d, KEY_OK },		/* also labeled as Pause */
-	{ 0x1c, KEY_ZOOM },		/* full screen and Stop*/
-	{ 0x02, KEY_MODE },		/* AV Source or Rewind*/
-	{ 0x04, KEY_LIST },		/* -/-- */
-	/* small arrows above numbers */
-	{ 0x1a, KEY_NEXT },		/* also Fast Forward */
-	{ 0x0e, KEY_PREVIOUS },		/* also Rewind */
-	/* these are in a rather non standard layout and have
-	an alternate name written */
-	{ 0x1e, KEY_UP },		/* Video Setting */
-	{ 0x0a, KEY_DOWN },		/* Video Default */
-	{ 0x05, KEY_CAMERA },		/* Snapshot */
-	{ 0x0c, KEY_RIGHT },		/* Hide Panel */
-	/* Four buttons without label */
-	{ 0x49, KEY_RED },
-	{ 0x0b, KEY_GREEN },
-	{ 0x13, KEY_YELLOW },
-	{ 0x50, KEY_BLUE },
-};
-
-struct ir_scancode_table ir_codes_genius_tvgo_a11mce_table = {
-	.scan = ir_codes_genius_tvgo_a11mce,
-	.size = ARRAY_SIZE(ir_codes_genius_tvgo_a11mce),
-};
-EXPORT_SYMBOL_GPL(ir_codes_genius_tvgo_a11mce_table);
-
-/*
- * Remote control for Powercolor Real Angel 330
- * Daniel Fraga <fragabr@gmail.com>
- */
-static struct ir_scancode ir_codes_powercolor_real_angel[] = {
-	{ 0x38, KEY_SWITCHVIDEOMODE },	/* switch inputs */
-	{ 0x0c, KEY_MEDIA },		/* Turn ON/OFF App */
-	{ 0x00, KEY_0 },
-	{ 0x01, KEY_1 },
-	{ 0x02, KEY_2 },
-	{ 0x03, KEY_3 },
-	{ 0x04, KEY_4 },
-	{ 0x05, KEY_5 },
-	{ 0x06, KEY_6 },
-	{ 0x07, KEY_7 },
-	{ 0x08, KEY_8 },
-	{ 0x09, KEY_9 },
-	{ 0x0a, KEY_DIGITS },		/* single, double, tripple digit */
-	{ 0x29, KEY_PREVIOUS },		/* previous channel */
-	{ 0x12, KEY_BRIGHTNESSUP },
-	{ 0x13, KEY_BRIGHTNESSDOWN },
-	{ 0x2b, KEY_MODE },		/* stereo/mono */
-	{ 0x2c, KEY_TEXT },		/* teletext */
-	{ 0x20, KEY_CHANNELUP },	/* channel up */
-	{ 0x21, KEY_CHANNELDOWN },	/* channel down */
-	{ 0x10, KEY_VOLUMEUP },		/* volume up */
-	{ 0x11, KEY_VOLUMEDOWN },	/* volume down */
-	{ 0x0d, KEY_MUTE },
-	{ 0x1f, KEY_RECORD },
-	{ 0x17, KEY_PLAY },
-	{ 0x16, KEY_PAUSE },
-	{ 0x0b, KEY_STOP },
-	{ 0x27, KEY_FASTFORWARD },
-	{ 0x26, KEY_REWIND },
-	{ 0x1e, KEY_SEARCH },		/* autoscan */
-	{ 0x0e, KEY_CAMERA },		/* snapshot */
-	{ 0x2d, KEY_SETUP },
-	{ 0x0f, KEY_SCREEN },		/* full screen */
-	{ 0x14, KEY_RADIO },		/* FM radio */
-	{ 0x25, KEY_POWER },		/* power */
-};
-
-struct ir_scancode_table ir_codes_powercolor_real_angel_table = {
-	.scan = ir_codes_powercolor_real_angel,
-	.size = ARRAY_SIZE(ir_codes_powercolor_real_angel),
-};
-EXPORT_SYMBOL_GPL(ir_codes_powercolor_real_angel_table);
-
-/* Kworld Plus TV Analog Lite PCI IR
-   Mauro Carvalho Chehab <mchehab@infradead.org>
- */
-static struct ir_scancode ir_codes_kworld_plus_tv_analog[] = {
-	{ 0x0c, KEY_PROG1 },		/* Kworld key */
-	{ 0x16, KEY_CLOSECD },		/* -> ) */
-	{ 0x1d, KEY_POWER2 },
-
-	{ 0x00, KEY_1 },
-	{ 0x01, KEY_2 },
-	{ 0x02, KEY_3 },		/* Two keys have the same code: 3 and left */
-	{ 0x03, KEY_4 },		/* Two keys have the same code: 3 and right */
-	{ 0x04, KEY_5 },
-	{ 0x05, KEY_6 },
-	{ 0x06, KEY_7 },
-	{ 0x07, KEY_8 },
-	{ 0x08, KEY_9 },
-	{ 0x0a, KEY_0 },
-
-	{ 0x09, KEY_AGAIN },
-	{ 0x14, KEY_MUTE },
-
-	{ 0x20, KEY_UP },
-	{ 0x21, KEY_DOWN },
-	{ 0x0b, KEY_ENTER },
-
-	{ 0x10, KEY_CHANNELUP },
-	{ 0x11, KEY_CHANNELDOWN },
-
-	/* Couldn't map key left/key right since those
-	   conflict with '3' and '4' scancodes
-	   I dunno what the original driver does
-	 */
-
-	{ 0x13, KEY_VOLUMEUP },
-	{ 0x12, KEY_VOLUMEDOWN },
-
-	/* The lower part of the IR
-	   There are several duplicated keycodes there.
-	   Most of them conflict with digits.
-	   Add mappings just to the unused scancodes.
-	   Somehow, the original driver has a way to know,
-	   but this doesn't seem to be on some GPIO.
-	   Also, it is not related to the time between keyup
-	   and keydown.
-	 */
-	{ 0x19, KEY_TIME},		/* Timeshift */
-	{ 0x1a, KEY_STOP},
-	{ 0x1b, KEY_RECORD},
-
-	{ 0x22, KEY_TEXT},
-
-	{ 0x15, KEY_AUDIO},		/* ((*)) */
-	{ 0x0f, KEY_ZOOM},
-	{ 0x1c, KEY_CAMERA},		/* snapshot */
-
-	{ 0x18, KEY_RED},		/* B */
-	{ 0x23, KEY_GREEN},		/* C */
-};
-struct ir_scancode_table ir_codes_kworld_plus_tv_analog_table = {
-	.scan = ir_codes_kworld_plus_tv_analog,
-	.size = ARRAY_SIZE(ir_codes_kworld_plus_tv_analog),
-};
-EXPORT_SYMBOL_GPL(ir_codes_kworld_plus_tv_analog_table);
-
-/* Kaiomy TVnPC U2
-   Mauro Carvalho Chehab <mchehab@infradead.org>
- */
-static struct ir_scancode ir_codes_kaiomy[] = {
-	{ 0x43, KEY_POWER2},
-	{ 0x01, KEY_LIST},
-	{ 0x0b, KEY_ZOOM},
-	{ 0x03, KEY_POWER},
-
-	{ 0x04, KEY_1},
-	{ 0x08, KEY_2},
-	{ 0x02, KEY_3},
-
-	{ 0x0f, KEY_4},
-	{ 0x05, KEY_5},
-	{ 0x06, KEY_6},
-
-	{ 0x0c, KEY_7},
-	{ 0x0d, KEY_8},
-	{ 0x0a, KEY_9},
-
-	{ 0x11, KEY_0},
-
-	{ 0x09, KEY_CHANNELUP},
-	{ 0x07, KEY_CHANNELDOWN},
-
-	{ 0x0e, KEY_VOLUMEUP},
-	{ 0x13, KEY_VOLUMEDOWN},
-
-	{ 0x10, KEY_HOME},
-	{ 0x12, KEY_ENTER},
-
-	{ 0x14, KEY_RECORD},
-	{ 0x15, KEY_STOP},
-	{ 0x16, KEY_PLAY},
-	{ 0x17, KEY_MUTE},
-
-	{ 0x18, KEY_UP},
-	{ 0x19, KEY_DOWN},
-	{ 0x1a, KEY_LEFT},
-	{ 0x1b, KEY_RIGHT},
-
-	{ 0x1c, KEY_RED},
-	{ 0x1d, KEY_GREEN},
-	{ 0x1e, KEY_YELLOW},
-	{ 0x1f, KEY_BLUE},
-};
-struct ir_scancode_table ir_codes_kaiomy_table = {
-	.scan = ir_codes_kaiomy,
-	.size = ARRAY_SIZE(ir_codes_kaiomy),
-};
-EXPORT_SYMBOL_GPL(ir_codes_kaiomy_table);
-
-static struct ir_scancode ir_codes_avermedia_a16d[] = {
-	{ 0x20, KEY_LIST},
-	{ 0x00, KEY_POWER},
-	{ 0x28, KEY_1},
-	{ 0x18, KEY_2},
-	{ 0x38, KEY_3},
-	{ 0x24, KEY_4},
-	{ 0x14, KEY_5},
-	{ 0x34, KEY_6},
-	{ 0x2c, KEY_7},
-	{ 0x1c, KEY_8},
-	{ 0x3c, KEY_9},
-	{ 0x12, KEY_SUBTITLE},
-	{ 0x22, KEY_0},
-	{ 0x32, KEY_REWIND},
-	{ 0x3a, KEY_SHUFFLE},
-	{ 0x02, KEY_PRINT},
-	{ 0x11, KEY_CHANNELDOWN},
-	{ 0x31, KEY_CHANNELUP},
-	{ 0x0c, KEY_ZOOM},
-	{ 0x1e, KEY_VOLUMEDOWN},
-	{ 0x3e, KEY_VOLUMEUP},
-	{ 0x0a, KEY_MUTE},
-	{ 0x04, KEY_AUDIO},
-	{ 0x26, KEY_RECORD},
-	{ 0x06, KEY_PLAY},
-	{ 0x36, KEY_STOP},
-	{ 0x16, KEY_PAUSE},
-	{ 0x2e, KEY_REWIND},
-	{ 0x0e, KEY_FASTFORWARD},
-	{ 0x30, KEY_TEXT},
-	{ 0x21, KEY_GREEN},
-	{ 0x01, KEY_BLUE},
-	{ 0x08, KEY_EPG},
-	{ 0x2a, KEY_MENU},
-};
-struct ir_scancode_table ir_codes_avermedia_a16d_table = {
-	.scan = ir_codes_avermedia_a16d,
-	.size = ARRAY_SIZE(ir_codes_avermedia_a16d),
-};
-EXPORT_SYMBOL_GPL(ir_codes_avermedia_a16d_table);
-
-/* Encore ENLTV-FM v5.3
-   Mauro Carvalho Chehab <mchehab@infradead.org>
- */
-static struct ir_scancode ir_codes_encore_enltv_fm53[] = {
-	{ 0x10, KEY_POWER2},
-	{ 0x06, KEY_MUTE},
-
-	{ 0x09, KEY_1},
-	{ 0x1d, KEY_2},
-	{ 0x1f, KEY_3},
-	{ 0x19, KEY_4},
-	{ 0x1b, KEY_5},
-	{ 0x11, KEY_6},
-	{ 0x17, KEY_7},
-	{ 0x12, KEY_8},
-	{ 0x16, KEY_9},
-	{ 0x48, KEY_0},
-
-	{ 0x04, KEY_LIST},		/* -/-- */
-	{ 0x40, KEY_LAST},		/* recall */
-
-	{ 0x02, KEY_MODE},		/* TV/AV */
-	{ 0x05, KEY_CAMERA},		/* SNAPSHOT */
-
-	{ 0x4c, KEY_CHANNELUP},		/* UP */
-	{ 0x00, KEY_CHANNELDOWN},	/* DOWN */
-	{ 0x0d, KEY_VOLUMEUP},		/* RIGHT */
-	{ 0x15, KEY_VOLUMEDOWN},	/* LEFT */
-	{ 0x49, KEY_ENTER},		/* OK */
-
-	{ 0x54, KEY_RECORD},
-	{ 0x4d, KEY_PLAY},		/* pause */
-
-	{ 0x1e, KEY_MENU},		/* video setting */
-	{ 0x0e, KEY_RIGHT},		/* <- */
-	{ 0x1a, KEY_LEFT},		/* -> */
-
-	{ 0x0a, KEY_CLEAR},		/* video default */
-	{ 0x0c, KEY_ZOOM},		/* hide pannel */
-	{ 0x47, KEY_SLEEP},		/* shutdown */
-};
-struct ir_scancode_table ir_codes_encore_enltv_fm53_table = {
-	.scan = ir_codes_encore_enltv_fm53,
-	.size = ARRAY_SIZE(ir_codes_encore_enltv_fm53),
-};
-EXPORT_SYMBOL_GPL(ir_codes_encore_enltv_fm53_table);
-
-/* Zogis Real Audio 220 - 32 keys IR */
-static struct ir_scancode ir_codes_real_audio_220_32_keys[] = {
-	{ 0x1c, KEY_RADIO},
-	{ 0x12, KEY_POWER2},
-
-	{ 0x01, KEY_1},
-	{ 0x02, KEY_2},
-	{ 0x03, KEY_3},
-	{ 0x04, KEY_4},
-	{ 0x05, KEY_5},
-	{ 0x06, KEY_6},
-	{ 0x07, KEY_7},
-	{ 0x08, KEY_8},
-	{ 0x09, KEY_9},
-	{ 0x00, KEY_0},
-
-	{ 0x0c, KEY_VOLUMEUP},
-	{ 0x18, KEY_VOLUMEDOWN},
-	{ 0x0b, KEY_CHANNELUP},
-	{ 0x15, KEY_CHANNELDOWN},
-	{ 0x16, KEY_ENTER},
-
-	{ 0x11, KEY_LIST},		/* Source */
-	{ 0x0d, KEY_AUDIO},		/* stereo */
-
-	{ 0x0f, KEY_PREVIOUS},		/* Prev */
-	{ 0x1b, KEY_TIME},		/* Timeshift */
-	{ 0x1a, KEY_NEXT},		/* Next */
-
-	{ 0x0e, KEY_STOP},
-	{ 0x1f, KEY_PLAY},
-	{ 0x1e, KEY_PLAYPAUSE},		/* Pause */
-
-	{ 0x1d, KEY_RECORD},
-	{ 0x13, KEY_MUTE},
-	{ 0x19, KEY_CAMERA},		/* Snapshot */
-
-};
-struct ir_scancode_table ir_codes_real_audio_220_32_keys_table = {
-	.scan = ir_codes_real_audio_220_32_keys,
-	.size = ARRAY_SIZE(ir_codes_real_audio_220_32_keys),
-};
-EXPORT_SYMBOL_GPL(ir_codes_real_audio_220_32_keys_table);
-
-/* ATI TV Wonder HD 600 USB
-   Devin Heitmueller <devin.heitmueller@gmail.com>
- */
-static struct ir_scancode ir_codes_ati_tv_wonder_hd_600[] = {
-	{ 0x00, KEY_RECORD},		/* Row 1 */
-	{ 0x01, KEY_PLAYPAUSE},
-	{ 0x02, KEY_STOP},
-	{ 0x03, KEY_POWER},
-	{ 0x04, KEY_PREVIOUS},	/* Row 2 */
-	{ 0x05, KEY_REWIND},
-	{ 0x06, KEY_FORWARD},
-	{ 0x07, KEY_NEXT},
-	{ 0x08, KEY_EPG},		/* Row 3 */
-	{ 0x09, KEY_HOME},
-	{ 0x0a, KEY_MENU},
-	{ 0x0b, KEY_CHANNELUP},
-	{ 0x0c, KEY_BACK},		/* Row 4 */
-	{ 0x0d, KEY_UP},
-	{ 0x0e, KEY_INFO},
-	{ 0x0f, KEY_CHANNELDOWN},
-	{ 0x10, KEY_LEFT},		/* Row 5 */
-	{ 0x11, KEY_SELECT},
-	{ 0x12, KEY_RIGHT},
-	{ 0x13, KEY_VOLUMEUP},
-	{ 0x14, KEY_LAST},		/* Row 6 */
-	{ 0x15, KEY_DOWN},
-	{ 0x16, KEY_MUTE},
-	{ 0x17, KEY_VOLUMEDOWN},
-};
-struct ir_scancode_table ir_codes_ati_tv_wonder_hd_600_table = {
-	.scan = ir_codes_ati_tv_wonder_hd_600,
-	.size = ARRAY_SIZE(ir_codes_ati_tv_wonder_hd_600),
-};
-EXPORT_SYMBOL_GPL(ir_codes_ati_tv_wonder_hd_600_table);
-
-/* DVBWorld remotes
-   Igor M. Liplianin <liplianin@me.by>
- */
-static struct ir_scancode ir_codes_dm1105_nec[] = {
-	{ 0x0a, KEY_POWER2},		/* power */
-	{ 0x0c, KEY_MUTE},		/* mute */
-	{ 0x11, KEY_1},
-	{ 0x12, KEY_2},
-	{ 0x13, KEY_3},
-	{ 0x14, KEY_4},
-	{ 0x15, KEY_5},
-	{ 0x16, KEY_6},
-	{ 0x17, KEY_7},
-	{ 0x18, KEY_8},
-	{ 0x19, KEY_9},
-	{ 0x10, KEY_0},
-	{ 0x1c, KEY_CHANNELUP},		/* ch+ */
-	{ 0x0f, KEY_CHANNELDOWN},	/* ch- */
-	{ 0x1a, KEY_VOLUMEUP},		/* vol+ */
-	{ 0x0e, KEY_VOLUMEDOWN},	/* vol- */
-	{ 0x04, KEY_RECORD},		/* rec */
-	{ 0x09, KEY_CHANNEL},		/* fav */
-	{ 0x08, KEY_BACKSPACE},		/* rewind */
-	{ 0x07, KEY_FASTFORWARD},	/* fast */
-	{ 0x0b, KEY_PAUSE},		/* pause */
-	{ 0x02, KEY_ESC},		/* cancel */
-	{ 0x03, KEY_TAB},		/* tab */
-	{ 0x00, KEY_UP},		/* up */
-	{ 0x1f, KEY_ENTER},		/* ok */
-	{ 0x01, KEY_DOWN},		/* down */
-	{ 0x05, KEY_RECORD},		/* cap */
-	{ 0x06, KEY_STOP},		/* stop */
-	{ 0x40, KEY_ZOOM},		/* full */
-	{ 0x1e, KEY_TV},		/* tvmode */
-	{ 0x1b, KEY_B},			/* recall */
-};
-struct ir_scancode_table ir_codes_dm1105_nec_table = {
-	.scan = ir_codes_dm1105_nec,
-	.size = ARRAY_SIZE(ir_codes_dm1105_nec),
-};
-EXPORT_SYMBOL_GPL(ir_codes_dm1105_nec_table);
-
-static struct ir_scancode ir_codes_tevii_nec[] = {
-	{ 0x0a, KEY_POWER2},
-	{ 0x0c, KEY_MUTE},
-	{ 0x11, KEY_1},
-	{ 0x12, KEY_2},
-	{ 0x13, KEY_3},
-	{ 0x14, KEY_4},
-	{ 0x15, KEY_5},
-	{ 0x16, KEY_6},
-	{ 0x17, KEY_7},
-	{ 0x18, KEY_8},
-	{ 0x19, KEY_9},
-	{ 0x10, KEY_0},
-	{ 0x1c, KEY_MENU},
-	{ 0x0f, KEY_VOLUMEDOWN},
-	{ 0x1a, KEY_LAST},
-	{ 0x0e, KEY_OPEN},
-	{ 0x04, KEY_RECORD},
-	{ 0x09, KEY_VOLUMEUP},
-	{ 0x08, KEY_CHANNELUP},
-	{ 0x07, KEY_PVR},
-	{ 0x0b, KEY_TIME},
-	{ 0x02, KEY_RIGHT},
-	{ 0x03, KEY_LEFT},
-	{ 0x00, KEY_UP},
-	{ 0x1f, KEY_OK},
-	{ 0x01, KEY_DOWN},
-	{ 0x05, KEY_TUNER},
-	{ 0x06, KEY_CHANNELDOWN},
-	{ 0x40, KEY_PLAYPAUSE},
-	{ 0x1e, KEY_REWIND},
-	{ 0x1b, KEY_FAVORITES},
-	{ 0x1d, KEY_BACK},
-	{ 0x4d, KEY_FASTFORWARD},
-	{ 0x44, KEY_EPG},
-	{ 0x4c, KEY_INFO},
-	{ 0x41, KEY_AB},
-	{ 0x43, KEY_AUDIO},
-	{ 0x45, KEY_SUBTITLE},
-	{ 0x4a, KEY_LIST},
-	{ 0x46, KEY_F1},
-	{ 0x47, KEY_F2},
-	{ 0x5e, KEY_F3},
-	{ 0x5c, KEY_F4},
-	{ 0x52, KEY_F5},
-	{ 0x5a, KEY_F6},
-	{ 0x56, KEY_MODE},
-	{ 0x58, KEY_SWITCHVIDEOMODE},
-};
-struct ir_scancode_table ir_codes_tevii_nec_table = {
-	.scan = ir_codes_tevii_nec,
-	.size = ARRAY_SIZE(ir_codes_tevii_nec),
-};
-EXPORT_SYMBOL_GPL(ir_codes_tevii_nec_table);
-
-static struct ir_scancode ir_codes_tbs_nec[] = {
-	{ 0x04, KEY_POWER2},	/*power*/
-	{ 0x14, KEY_MUTE},	/*mute*/
-	{ 0x07, KEY_1},
-	{ 0x06, KEY_2},
-	{ 0x05, KEY_3},
-	{ 0x0b, KEY_4},
-	{ 0x0a, KEY_5},
-	{ 0x09, KEY_6},
-	{ 0x0f, KEY_7},
-	{ 0x0e, KEY_8},
-	{ 0x0d, KEY_9},
-	{ 0x12, KEY_0},
-	{ 0x16, KEY_CHANNELUP},	/*ch+*/
-	{ 0x11, KEY_CHANNELDOWN},/*ch-*/
-	{ 0x13, KEY_VOLUMEUP},	/*vol+*/
-	{ 0x0c, KEY_VOLUMEDOWN},/*vol-*/
-	{ 0x03, KEY_RECORD},	/*rec*/
-	{ 0x18, KEY_PAUSE},	/*pause*/
-	{ 0x19, KEY_OK},	/*ok*/
-	{ 0x1a, KEY_CAMERA},	/* snapshot */
-	{ 0x01, KEY_UP},
-	{ 0x10, KEY_LEFT},
-	{ 0x02, KEY_RIGHT},
-	{ 0x08, KEY_DOWN},
-	{ 0x15, KEY_FAVORITES},
-	{ 0x17, KEY_SUBTITLE},
-	{ 0x1d, KEY_ZOOM},
-	{ 0x1f, KEY_EXIT},
-	{ 0x1e, KEY_MENU},
-	{ 0x1c, KEY_EPG},
-	{ 0x00, KEY_PREVIOUS},
-	{ 0x1b, KEY_MODE},
-};
-struct ir_scancode_table ir_codes_tbs_nec_table = {
-	.scan = ir_codes_tbs_nec,
-	.size = ARRAY_SIZE(ir_codes_tbs_nec),
-};
-EXPORT_SYMBOL_GPL(ir_codes_tbs_nec_table);
-
-/* Terratec Cinergy Hybrid T USB XS
-   Devin Heitmueller <dheitmueller@linuxtv.org>
- */
-static struct ir_scancode ir_codes_terratec_cinergy_xs[] = {
-	{ 0x41, KEY_HOME},
-	{ 0x01, KEY_POWER},
-	{ 0x42, KEY_MENU},
-	{ 0x02, KEY_1},
-	{ 0x03, KEY_2},
-	{ 0x04, KEY_3},
-	{ 0x43, KEY_SUBTITLE},
-	{ 0x05, KEY_4},
-	{ 0x06, KEY_5},
-	{ 0x07, KEY_6},
-	{ 0x44, KEY_TEXT},
-	{ 0x08, KEY_7},
-	{ 0x09, KEY_8},
-	{ 0x0a, KEY_9},
-	{ 0x45, KEY_DELETE},
-	{ 0x0b, KEY_TUNER},
-	{ 0x0c, KEY_0},
-	{ 0x0d, KEY_MODE},
-	{ 0x46, KEY_TV},
-	{ 0x47, KEY_DVD},
-	{ 0x49, KEY_VIDEO},
-	{ 0x4b, KEY_AUX},
-	{ 0x10, KEY_UP},
-	{ 0x11, KEY_LEFT},
-	{ 0x12, KEY_OK},
-	{ 0x13, KEY_RIGHT},
-	{ 0x14, KEY_DOWN},
-	{ 0x0f, KEY_EPG},
-	{ 0x16, KEY_INFO},
-	{ 0x4d, KEY_BACKSPACE},
-	{ 0x1c, KEY_VOLUMEUP},
-	{ 0x4c, KEY_PLAY},
-	{ 0x1b, KEY_CHANNELUP},
-	{ 0x1e, KEY_VOLUMEDOWN},
-	{ 0x1d, KEY_MUTE},
-	{ 0x1f, KEY_CHANNELDOWN},
-	{ 0x17, KEY_RED},
-	{ 0x18, KEY_GREEN},
-	{ 0x19, KEY_YELLOW},
-	{ 0x1a, KEY_BLUE},
-	{ 0x58, KEY_RECORD},
-	{ 0x48, KEY_STOP},
-	{ 0x40, KEY_PAUSE},
-	{ 0x54, KEY_LAST},
-	{ 0x4e, KEY_REWIND},
-	{ 0x4f, KEY_FASTFORWARD},
-	{ 0x5c, KEY_NEXT},
-};
-struct ir_scancode_table ir_codes_terratec_cinergy_xs_table = {
-	.scan = ir_codes_terratec_cinergy_xs,
-	.size = ARRAY_SIZE(ir_codes_terratec_cinergy_xs),
-};
-EXPORT_SYMBOL_GPL(ir_codes_terratec_cinergy_xs_table);
-
-/* EVGA inDtube
-   Devin Heitmueller <devin.heitmueller@gmail.com>
- */
-static struct ir_scancode ir_codes_evga_indtube[] = {
-	{ 0x12, KEY_POWER},
-	{ 0x02, KEY_MODE},	/* TV */
-	{ 0x14, KEY_MUTE},
-	{ 0x1a, KEY_CHANNELUP},
-	{ 0x16, KEY_TV2},	/* PIP */
-	{ 0x1d, KEY_VOLUMEUP},
-	{ 0x05, KEY_CHANNELDOWN},
-	{ 0x0f, KEY_PLAYPAUSE},
-	{ 0x19, KEY_VOLUMEDOWN},
-	{ 0x1c, KEY_REWIND},
-	{ 0x0d, KEY_RECORD},
-	{ 0x18, KEY_FORWARD},
-	{ 0x1e, KEY_PREVIOUS},
-	{ 0x1b, KEY_STOP},
-	{ 0x1f, KEY_NEXT},
-	{ 0x13, KEY_CAMERA},
-};
-struct ir_scancode_table ir_codes_evga_indtube_table = {
-	.scan = ir_codes_evga_indtube,
-	.size = ARRAY_SIZE(ir_codes_evga_indtube),
-};
-EXPORT_SYMBOL_GPL(ir_codes_evga_indtube_table);
-
-static struct ir_scancode ir_codes_videomate_s350[] = {
-	{ 0x00, KEY_TV},
-	{ 0x01, KEY_DVD},
-	{ 0x04, KEY_RECORD},
-	{ 0x05, KEY_VIDEO},	/* TV/Video */
-	{ 0x07, KEY_STOP},
-	{ 0x08, KEY_PLAYPAUSE},
-	{ 0x0a, KEY_REWIND},
-	{ 0x0f, KEY_FASTFORWARD},
-	{ 0x10, KEY_CHANNELUP},
-	{ 0x12, KEY_VOLUMEUP},
-	{ 0x13, KEY_CHANNELDOWN},
-	{ 0x14, KEY_MUTE},
-	{ 0x15, KEY_VOLUMEDOWN},
-	{ 0x16, KEY_1},
-	{ 0x17, KEY_2},
-	{ 0x18, KEY_3},
-	{ 0x19, KEY_4},
-	{ 0x1a, KEY_5},
-	{ 0x1b, KEY_6},
-	{ 0x1c, KEY_7},
-	{ 0x1d, KEY_8},
-	{ 0x1e, KEY_9},
-	{ 0x1f, KEY_0},
-	{ 0x21, KEY_SLEEP},
-	{ 0x24, KEY_ZOOM},
-	{ 0x25, KEY_LAST},	/* Recall */
-	{ 0x26, KEY_SUBTITLE},	/* CC */
-	{ 0x27, KEY_LANGUAGE},	/* MTS */
-	{ 0x29, KEY_CHANNEL},	/* SURF */
-	{ 0x2b, KEY_A},
-	{ 0x2c, KEY_B},
-	{ 0x2f, KEY_CAMERA},	/* Snapshot */
-	{ 0x23, KEY_RADIO},
-	{ 0x02, KEY_PREVIOUSSONG},
-	{ 0x06, KEY_NEXTSONG},
-	{ 0x03, KEY_EPG},
-	{ 0x09, KEY_SETUP},
-	{ 0x22, KEY_BACKSPACE},
-	{ 0x0c, KEY_UP},
-	{ 0x0e, KEY_DOWN},
-	{ 0x0b, KEY_LEFT},
-	{ 0x0d, KEY_RIGHT},
-	{ 0x11, KEY_ENTER},
-	{ 0x20, KEY_TEXT},
-};
-struct ir_scancode_table ir_codes_videomate_s350_table = {
-	.scan = ir_codes_videomate_s350,
-	.size = ARRAY_SIZE(ir_codes_videomate_s350),
-};
-EXPORT_SYMBOL_GPL(ir_codes_videomate_s350_table);
-
-/* GADMEI UTV330+ RM008Z remote
-   Shine Liu <shinel@foxmail.com>
- */
-static struct ir_scancode ir_codes_gadmei_rm008z[] = {
-	{ 0x14, KEY_POWER2},		/* POWER OFF */
-	{ 0x0c, KEY_MUTE},		/* MUTE */
-
-	{ 0x18, KEY_TV},		/* TV */
-	{ 0x0e, KEY_VIDEO},		/* AV */
-	{ 0x0b, KEY_AUDIO},		/* SV */
-	{ 0x0f, KEY_RADIO},		/* FM */
-
-	{ 0x00, KEY_1},
-	{ 0x01, KEY_2},
-	{ 0x02, KEY_3},
-	{ 0x03, KEY_4},
-	{ 0x04, KEY_5},
-	{ 0x05, KEY_6},
-	{ 0x06, KEY_7},
-	{ 0x07, KEY_8},
-	{ 0x08, KEY_9},
-	{ 0x09, KEY_0},
-	{ 0x0a, KEY_INFO},		/* OSD */
-	{ 0x1c, KEY_BACKSPACE},		/* LAST */
-
-	{ 0x0d, KEY_PLAY},		/* PLAY */
-	{ 0x1e, KEY_CAMERA},		/* SNAPSHOT */
-	{ 0x1a, KEY_RECORD},		/* RECORD */
-	{ 0x17, KEY_STOP},		/* STOP */
-
-	{ 0x1f, KEY_UP},		/* UP */
-	{ 0x44, KEY_DOWN},		/* DOWN */
-	{ 0x46, KEY_TAB},		/* BACK */
-	{ 0x4a, KEY_ZOOM},		/* FULLSECREEN */
-
-	{ 0x10, KEY_VOLUMEUP},		/* VOLUMEUP */
-	{ 0x11, KEY_VOLUMEDOWN},	/* VOLUMEDOWN */
-	{ 0x12, KEY_CHANNELUP},		/* CHANNELUP */
-	{ 0x13, KEY_CHANNELDOWN},	/* CHANNELDOWN */
-	{ 0x15, KEY_ENTER},		/* OK */
-};
-struct ir_scancode_table ir_codes_gadmei_rm008z_table = {
-	.scan = ir_codes_gadmei_rm008z,
-	.size = ARRAY_SIZE(ir_codes_gadmei_rm008z),
-};
-EXPORT_SYMBOL_GPL(ir_codes_gadmei_rm008z_table);
-
-/*************************************************************
- *		COMPLETE SCANCODE TABLES
- * Instead of just a partial scancode, the tables bellow
- * contains the complete scancode and the receiver protocol
- *************************************************************/
-
-/*
- * Hauppauge:the newer, gray remotes (seems there are multiple
- * slightly different versions), shipped with cx88+ivtv cards.
- *
- * This table contains the complete RC5 code, instead of just the data part
- */
-static struct ir_scancode ir_codes_rc5_hauppauge_new[] = {
-	/* Keys 0 to 9 */
-	{ 0x1e00, KEY_0 },
-	{ 0x1e01, KEY_1 },
-	{ 0x1e02, KEY_2 },
-	{ 0x1e03, KEY_3 },
-	{ 0x1e04, KEY_4 },
-	{ 0x1e05, KEY_5 },
-	{ 0x1e06, KEY_6 },
-	{ 0x1e07, KEY_7 },
-	{ 0x1e08, KEY_8 },
-	{ 0x1e09, KEY_9 },
-
-	{ 0x1e0a, KEY_TEXT },		/* keypad asterisk as well */
-	{ 0x1e0b, KEY_RED },		/* red button */
-	{ 0x1e0c, KEY_RADIO },
-	{ 0x1e0d, KEY_MENU },
-	{ 0x1e0e, KEY_SUBTITLE },		/* also the # key */
-	{ 0x1e0f, KEY_MUTE },
-	{ 0x1e10, KEY_VOLUMEUP },
-	{ 0x1e11, KEY_VOLUMEDOWN },
-	{ 0x1e12, KEY_PREVIOUS },		/* previous channel */
-	{ 0x1e14, KEY_UP },
-	{ 0x1e15, KEY_DOWN },
-	{ 0x1e16, KEY_LEFT },
-	{ 0x1e17, KEY_RIGHT },
-	{ 0x1e18, KEY_VIDEO },		/* Videos */
-	{ 0x1e19, KEY_AUDIO },		/* Music */
-	/* 0x1e1a: Pictures - presume this means
-	   "Multimedia Home Platform" -
-	   no "PICTURES" key in input.h
-	 */
-	{ 0x1e1a, KEY_MHP },
-
-	{ 0x1e1b, KEY_EPG },		/* Guide */
-	{ 0x1e1c, KEY_TV },
-	{ 0x1e1e, KEY_NEXTSONG },		/* skip >| */
-	{ 0x1e1f, KEY_EXIT },		/* back/exit */
-	{ 0x1e20, KEY_CHANNELUP },	/* channel / program + */
-	{ 0x1e21, KEY_CHANNELDOWN },	/* channel / program - */
-	{ 0x1e22, KEY_CHANNEL },		/* source (old black remote) */
-	{ 0x1e24, KEY_PREVIOUSSONG },	/* replay |< */
-	{ 0x1e25, KEY_ENTER },		/* OK */
-	{ 0x1e26, KEY_SLEEP },		/* minimize (old black remote) */
-	{ 0x1e29, KEY_BLUE },		/* blue key */
-	{ 0x1e2e, KEY_GREEN },		/* green button */
-	{ 0x1e30, KEY_PAUSE },		/* pause */
-	{ 0x1e32, KEY_REWIND },		/* backward << */
-	{ 0x1e34, KEY_FASTFORWARD },	/* forward >> */
-	{ 0x1e35, KEY_PLAY },
-	{ 0x1e36, KEY_STOP },
-	{ 0x1e37, KEY_RECORD },		/* recording */
-	{ 0x1e38, KEY_YELLOW },		/* yellow key */
-	{ 0x1e3b, KEY_SELECT },		/* top right button */
-	{ 0x1e3c, KEY_ZOOM },		/* full */
-	{ 0x1e3d, KEY_POWER },		/* system power (green button) */
-};
-
-struct ir_scancode_table ir_codes_rc5_hauppauge_new_table = {
-	.scan = ir_codes_rc5_hauppauge_new,
-	.size = ARRAY_SIZE(ir_codes_rc5_hauppauge_new),
-	.ir_type = IR_TYPE_RC5,
-};
-EXPORT_SYMBOL_GPL(ir_codes_rc5_hauppauge_new_table);
-
-/* Terratec Cinergy Hybrid T USB XS FM
-   Mauro Carvalho Chehab <mchehab@redhat.com>
- */
-static struct ir_scancode ir_codes_nec_terratec_cinergy_xs[] = {
-	{ 0x1441, KEY_HOME},
-	{ 0x1401, KEY_POWER2},
-
-	{ 0x1442, KEY_MENU},		/* DVD menu */
-	{ 0x1443, KEY_SUBTITLE},
-	{ 0x1444, KEY_TEXT},		/* Teletext */
-	{ 0x1445, KEY_DELETE},
-
-	{ 0x1402, KEY_1},
-	{ 0x1403, KEY_2},
-	{ 0x1404, KEY_3},
-	{ 0x1405, KEY_4},
-	{ 0x1406, KEY_5},
-	{ 0x1407, KEY_6},
-	{ 0x1408, KEY_7},
-	{ 0x1409, KEY_8},
-	{ 0x140a, KEY_9},
-	{ 0x140c, KEY_0},
-
-	{ 0x140b, KEY_TUNER},		/* AV */
-	{ 0x140d, KEY_MODE},		/* A.B */
-
-	{ 0x1446, KEY_TV},
-	{ 0x1447, KEY_DVD},
-	{ 0x1449, KEY_VIDEO},
-	{ 0x144a, KEY_RADIO},		/* Music */
-	{ 0x144b, KEY_CAMERA},		/* PIC */
-
-	{ 0x1410, KEY_UP},
-	{ 0x1411, KEY_LEFT},
-	{ 0x1412, KEY_OK},
-	{ 0x1413, KEY_RIGHT},
-	{ 0x1414, KEY_DOWN},
-
-	{ 0x140f, KEY_EPG},
-	{ 0x1416, KEY_INFO},
-	{ 0x144d, KEY_BACKSPACE},
-
-	{ 0x141c, KEY_VOLUMEUP},
-	{ 0x141e, KEY_VOLUMEDOWN},
-
-	{ 0x144c, KEY_PLAY},
-	{ 0x141d, KEY_MUTE},
-
-	{ 0x141b, KEY_CHANNELUP},
-	{ 0x141f, KEY_CHANNELDOWN},
-
-	{ 0x1417, KEY_RED},
-	{ 0x1418, KEY_GREEN},
-	{ 0x1419, KEY_YELLOW},
-	{ 0x141a, KEY_BLUE},
-
-	{ 0x1458, KEY_RECORD},
-	{ 0x1448, KEY_STOP},
-	{ 0x1440, KEY_PAUSE},
-
-	{ 0x1454, KEY_LAST},
-	{ 0x144e, KEY_REWIND},
-	{ 0x144f, KEY_FASTFORWARD},
-	{ 0x145c, KEY_NEXT},
-};
-struct ir_scancode_table ir_codes_nec_terratec_cinergy_xs_table = {
-	.scan = ir_codes_nec_terratec_cinergy_xs,
-	.size = ARRAY_SIZE(ir_codes_nec_terratec_cinergy_xs),
-	.ir_type = IR_TYPE_NEC,
-};
-EXPORT_SYMBOL_GPL(ir_codes_nec_terratec_cinergy_xs_table);
-
-
-/* Leadtek Winfast TV USB II Deluxe remote
-   Magnus Alm <magnus.alm@gmail.com>
- */
-static struct ir_scancode ir_codes_winfast_usbii_deluxe[] = {
-	{ 0x62, KEY_0},
-	{ 0x75, KEY_1},
-	{ 0x76, KEY_2},
-	{ 0x77, KEY_3},
-	{ 0x79, KEY_4},
-	{ 0x7a, KEY_5},
-	{ 0x7b, KEY_6},
-	{ 0x7d, KEY_7},
-	{ 0x7e, KEY_8},
-	{ 0x7f, KEY_9},
-
-	{ 0x38, KEY_CAMERA},		/* SNAPSHOT */
-	{ 0x37, KEY_RECORD},		/* RECORD */
-	{ 0x35, KEY_TIME},		/* TIMESHIFT */
-
-	{ 0x74, KEY_VOLUMEUP},		/* VOLUMEUP */
-	{ 0x78, KEY_VOLUMEDOWN},	/* VOLUMEDOWN */
-	{ 0x64, KEY_MUTE},		/* MUTE */
-
-	{ 0x21, KEY_CHANNEL},		/* SURF */
-	{ 0x7c, KEY_CHANNELUP},		/* CHANNELUP */
-	{ 0x60, KEY_CHANNELDOWN},	/* CHANNELDOWN */
-	{ 0x61, KEY_LAST},		/* LAST CHANNEL (RECALL) */
-
-	{ 0x72, KEY_VIDEO}, 		/* INPUT MODES (TV/FM) */
-
-	{ 0x70, KEY_POWER2},		/* TV ON/OFF */
-
-	{ 0x39, KEY_CYCLEWINDOWS},	/* MINIMIZE (BOSS) */
-	{ 0x3a, KEY_NEW},		/* PIP */
-	{ 0x73, KEY_ZOOM},		/* FULLSECREEN */
-
-	{ 0x66, KEY_INFO},		/* OSD (DISPLAY) */
-
-	{ 0x31, KEY_DOT},		/* '.' */
-	{ 0x63, KEY_ENTER},		/* ENTER */
-
-};
-struct ir_scancode_table ir_codes_winfast_usbii_deluxe_table = {
-	.scan = ir_codes_winfast_usbii_deluxe,
-	.size = ARRAY_SIZE(ir_codes_winfast_usbii_deluxe),
-};
-EXPORT_SYMBOL_GPL(ir_codes_winfast_usbii_deluxe_table);
-
-/* Kworld 315U
- */
-static struct ir_scancode ir_codes_kworld_315u[] = {
-	{ 0x6143, KEY_POWER },
-	{ 0x6101, KEY_TUNER },		/* source */
-	{ 0x610b, KEY_ZOOM },
-	{ 0x6103, KEY_POWER2 },		/* shutdown */
-
-	{ 0x6104, KEY_1 },
-	{ 0x6108, KEY_2 },
-	{ 0x6102, KEY_3 },
-	{ 0x6109, KEY_CHANNELUP },
-
-	{ 0x610f, KEY_4 },
-	{ 0x6105, KEY_5 },
-	{ 0x6106, KEY_6 },
-	{ 0x6107, KEY_CHANNELDOWN },
-
-	{ 0x610c, KEY_7 },
-	{ 0x610d, KEY_8 },
-	{ 0x610a, KEY_9 },
-	{ 0x610e, KEY_VOLUMEUP },
-
-	{ 0x6110, KEY_LAST },
-	{ 0x6111, KEY_0 },
-	{ 0x6112, KEY_ENTER },
-	{ 0x6113, KEY_VOLUMEDOWN },
-
-	{ 0x6114, KEY_RECORD },
-	{ 0x6115, KEY_STOP },
-	{ 0x6116, KEY_PLAY },
-	{ 0x6117, KEY_MUTE },
-
-	{ 0x6118, KEY_UP },
-	{ 0x6119, KEY_DOWN },
-	{ 0x611a, KEY_LEFT },
-	{ 0x611b, KEY_RIGHT },
-
-	{ 0x611c, KEY_RED },
-	{ 0x611d, KEY_GREEN },
-	{ 0x611e, KEY_YELLOW },
-	{ 0x611f, KEY_BLUE },
-};
-
-struct ir_scancode_table ir_codes_kworld_315u_table = {
-	.scan = ir_codes_kworld_315u,
-	.size = ARRAY_SIZE(ir_codes_kworld_315u),
-	.ir_type = IR_TYPE_NEC,
-};
-EXPORT_SYMBOL_GPL(ir_codes_kworld_315u_table);
diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c
index bfca26d5..9374a00 100644
--- a/drivers/media/IR/ir-keytable.c
+++ b/drivers/media/IR/ir-keytable.c
@@ -1,4 +1,4 @@
-/* ir-register.c - handle IR scancode->keycode tables
+/* ir-keytable.c - handle IR scancode->keycode tables
  *
  * Copyright (C) 2009 by Mauro Carvalho Chehab <mchehab@redhat.com>
  *
@@ -15,346 +15,244 @@
 
 #include <linux/input.h>
 #include <linux/slab.h>
-#include <media/ir-common.h>
+#include "ir-core-priv.h"
 
-#define IR_TAB_MIN_SIZE	32
-#define IR_TAB_MAX_SIZE	1024
+/* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
+#define IR_TAB_MIN_SIZE	256
+#define IR_TAB_MAX_SIZE	8192
+
+/* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */
+#define IR_KEYPRESS_TIMEOUT 250
 
 /**
- * ir_seek_table() - returns the element order on the table
- * @rc_tab:	the ir_scancode_table with the keymap to be used
- * @scancode:	the scancode that we're seeking
+ * ir_resize_table() - resizes a scancode table if necessary
+ * @rc_tab:	the ir_scancode_table to resize
+ * @return:	zero on success or a negative error code
  *
- * This routine is used by the input routines when a key is pressed at the
- * IR. The scancode is received and needs to be converted into a keycode.
- * If the key is not found, it returns KEY_UNKNOWN. Otherwise, returns the
- * corresponding keycode from the table.
+ * This routine will shrink the ir_scancode_table if it has lots of
+ * unused entries and grow it if it is full.
  */
-static int ir_seek_table(struct ir_scancode_table *rc_tab, u32 scancode)
+static int ir_resize_table(struct ir_scancode_table *rc_tab)
+{
+	unsigned int oldalloc = rc_tab->alloc;
+	unsigned int newalloc = oldalloc;
+	struct ir_scancode *oldscan = rc_tab->scan;
+	struct ir_scancode *newscan;
+
+	if (rc_tab->size == rc_tab->len) {
+		/* All entries in use -> grow keytable */
+		if (rc_tab->alloc >= IR_TAB_MAX_SIZE)
+			return -ENOMEM;
+
+		newalloc *= 2;
+		IR_dprintk(1, "Growing table to %u bytes\n", newalloc);
+	}
+
+	if ((rc_tab->len * 3 < rc_tab->size) && (oldalloc > IR_TAB_MIN_SIZE)) {
+		/* Less than 1/3 of entries in use -> shrink keytable */
+		newalloc /= 2;
+		IR_dprintk(1, "Shrinking table to %u bytes\n", newalloc);
+	}
+
+	if (newalloc == oldalloc)
+		return 0;
+
+	newscan = kmalloc(newalloc, GFP_ATOMIC);
+	if (!newscan) {
+		IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc);
+		return -ENOMEM;
+	}
+
+	memcpy(newscan, rc_tab->scan, rc_tab->len * sizeof(struct ir_scancode));
+	rc_tab->scan = newscan;
+	rc_tab->alloc = newalloc;
+	rc_tab->size = rc_tab->alloc / sizeof(struct ir_scancode);
+	kfree(oldscan);
+	return 0;
+}
+
+/**
+ * ir_do_setkeycode() - internal function to set a keycode in the
+ *			scancode->keycode table
+ * @dev:	the struct input_dev device descriptor
+ * @rc_tab:	the struct ir_scancode_table to set the keycode in
+ * @scancode:	the scancode for the ir command
+ * @keycode:	the keycode for the ir command
+ * @resize:	whether the keytable may be shrunk
+ * @return:	-EINVAL if the keycode could not be inserted, otherwise zero.
+ *
+ * This routine is used internally to manipulate the scancode->keycode table.
+ * The caller has to hold @rc_tab->lock.
+ */
+static int ir_do_setkeycode(struct input_dev *dev,
+			    struct ir_scancode_table *rc_tab,
+			    unsigned scancode, unsigned keycode,
+			    bool resize)
+{
+	unsigned int i;
+	int old_keycode = KEY_RESERVED;
+	struct ir_input_dev *ir_dev = input_get_drvdata(dev);
+
+	/*
+	 * Unfortunately, some hardware-based IR decoders don't provide
+	 * all bits for the complete IR code. In general, they provide only
+	 * the command part of the IR code. Yet, as it is possible to replace
+	 * the provided IR with another one, it is needed to allow loading
+	 * IR tables from other remotes. So,
+	 */
+	if (ir_dev->props && ir_dev->props->scanmask) {
+		scancode &= ir_dev->props->scanmask;
+	}
+
+	/* First check if we already have a mapping for this ir command */
+	for (i = 0; i < rc_tab->len; i++) {
+		/* Keytable is sorted from lowest to highest scancode */
+		if (rc_tab->scan[i].scancode > scancode)
+			break;
+		else if (rc_tab->scan[i].scancode < scancode)
+			continue;
+
+		old_keycode = rc_tab->scan[i].keycode;
+		rc_tab->scan[i].keycode = keycode;
+
+		/* Did the user wish to remove the mapping? */
+		if (keycode == KEY_RESERVED || keycode == KEY_UNKNOWN) {
+			IR_dprintk(1, "#%d: Deleting scan 0x%04x\n",
+				   i, scancode);
+			rc_tab->len--;
+			memmove(&rc_tab->scan[i], &rc_tab->scan[i + 1],
+				(rc_tab->len - i) * sizeof(struct ir_scancode));
+		}
+
+		/* Possibly shrink the keytable, failure is not a problem */
+		ir_resize_table(rc_tab);
+		break;
+	}
+
+	if (old_keycode == KEY_RESERVED && keycode != KEY_RESERVED) {
+		/* No previous mapping found, we might need to grow the table */
+		if (resize && ir_resize_table(rc_tab))
+			return -ENOMEM;
+
+		IR_dprintk(1, "#%d: New scan 0x%04x with key 0x%04x\n",
+			   i, scancode, keycode);
+
+		/* i is the proper index to insert our new keycode */
+		memmove(&rc_tab->scan[i + 1], &rc_tab->scan[i],
+			(rc_tab->len - i) * sizeof(struct ir_scancode));
+		rc_tab->scan[i].scancode = scancode;
+		rc_tab->scan[i].keycode = keycode;
+		rc_tab->len++;
+		set_bit(keycode, dev->keybit);
+	} else {
+		IR_dprintk(1, "#%d: Replacing scan 0x%04x with key 0x%04x\n",
+			   i, scancode, keycode);
+		/* A previous mapping was updated... */
+		clear_bit(old_keycode, dev->keybit);
+		/* ...but another scancode might use the same keycode */
+		for (i = 0; i < rc_tab->len; i++) {
+			if (rc_tab->scan[i].keycode == old_keycode) {
+				set_bit(old_keycode, dev->keybit);
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * ir_setkeycode() - set a keycode in the scancode->keycode table
+ * @dev:	the struct input_dev device descriptor
+ * @scancode:	the desired scancode
+ * @keycode:	result
+ * @return:	-EINVAL if the keycode could not be inserted, otherwise zero.
+ *
+ * This routine is used to handle evdev EVIOCSKEY ioctl.
+ */
+static int ir_setkeycode(struct input_dev *dev,
+			 unsigned int scancode, unsigned int keycode)
 {
 	int rc;
 	unsigned long flags;
-	struct ir_scancode *keymap = rc_tab->scan;
+	struct ir_input_dev *ir_dev = input_get_drvdata(dev);
+	struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
 
 	spin_lock_irqsave(&rc_tab->lock, flags);
-
-	/* FIXME: replace it by a binary search */
-
-	for (rc = 0; rc < rc_tab->size; rc++)
-		if (keymap[rc].scancode == scancode)
-			goto exit;
-
-	/* Not found */
-	rc = -EINVAL;
-
-exit:
+	rc = ir_do_setkeycode(dev, rc_tab, scancode, keycode, true);
 	spin_unlock_irqrestore(&rc_tab->lock, flags);
 	return rc;
 }
 
 /**
- * ir_roundup_tablesize() - gets an optimum value for the table size
- * @n_elems:		minimum number of entries to store keycodes
+ * ir_setkeytable() - sets several entries in the scancode->keycode table
+ * @dev:	the struct input_dev device descriptor
+ * @to:		the struct ir_scancode_table to copy entries to
+ * @from:	the struct ir_scancode_table to copy entries from
+ * @return:	-EINVAL if all keycodes could not be inserted, otherwise zero.
  *
- * This routine is used to choose the keycode table size.
- *
- * In order to have some empty space for new keycodes,
- * and knowing in advance that kmalloc allocates only power of two
- * segments, it optimizes the allocated space to have some spare space
- * for those new keycodes by using the maximum number of entries that
- * will be effectively be allocated by kmalloc.
- * In order to reduce the quantity of table resizes, it has a minimum
- * table size of IR_TAB_MIN_SIZE.
+ * This routine is used to handle table initialization.
  */
-static int ir_roundup_tablesize(int n_elems)
+static int ir_setkeytable(struct input_dev *dev,
+			  struct ir_scancode_table *to,
+			  const struct ir_scancode_table *from)
 {
-	size_t size;
+	struct ir_input_dev *ir_dev = input_get_drvdata(dev);
+	struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
+	unsigned long flags;
+	unsigned int i;
+	int rc = 0;
 
-	if (n_elems < IR_TAB_MIN_SIZE)
-		n_elems = IR_TAB_MIN_SIZE;
-
-	/*
-	 * As kmalloc only allocates sizes of power of two, get as
-	 * much entries as possible for the allocated memory segment
-	 */
-	size = roundup_pow_of_two(n_elems * sizeof(struct ir_scancode));
-	n_elems = size / sizeof(struct ir_scancode);
-
-	return n_elems;
-}
-
-/**
- * ir_copy_table() - copies a keytable, discarding the unused entries
- * @destin:	destin table
- * @origin:	origin table
- *
- * Copies all entries where the keycode is not KEY_UNKNOWN/KEY_RESERVED
- * Also copies table size and table protocol.
- * NOTE: It shouldn't copy the lock field
- */
-
-static int ir_copy_table(struct ir_scancode_table *destin,
-		 const struct ir_scancode_table *origin)
-{
-	int i, j = 0;
-
-	for (i = 0; i < origin->size; i++) {
-		if (origin->scan[i].keycode == KEY_UNKNOWN ||
-		   origin->scan[i].keycode == KEY_RESERVED)
-			continue;
-
-		memcpy(&destin->scan[j], &origin->scan[i], sizeof(struct ir_scancode));
-		j++;
+	spin_lock_irqsave(&rc_tab->lock, flags);
+	for (i = 0; i < from->size; i++) {
+		rc = ir_do_setkeycode(dev, to, from->scan[i].scancode,
+				      from->scan[i].keycode, false);
+		if (rc)
+			break;
 	}
-	destin->size = j;
-	destin->ir_type = origin->ir_type;
-
-	IR_dprintk(1, "Copied %d scancodes to the new keycode table\n", destin->size);
-
-	return 0;
+	spin_unlock_irqrestore(&rc_tab->lock, flags);
+	return rc;
 }
 
 /**
- * ir_getkeycode() - get a keycode at the evdev scancode ->keycode table
+ * ir_getkeycode() - get a keycode from the scancode->keycode table
  * @dev:	the struct input_dev device descriptor
  * @scancode:	the desired scancode
- * @keycode:	the keycode to be retorned.
+ * @keycode:	used to return the keycode, if found, or KEY_RESERVED
+ * @return:	always returns zero.
  *
  * This routine is used to handle evdev EVIOCGKEY ioctl.
- * If the key is not found, returns -EINVAL, otherwise, returns 0.
  */
 static int ir_getkeycode(struct input_dev *dev,
 			 unsigned int scancode, unsigned int *keycode)
 {
-	int elem;
+	int start, end, mid;
+	unsigned long flags;
+	int key = KEY_RESERVED;
 	struct ir_input_dev *ir_dev = input_get_drvdata(dev);
 	struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
 
-	elem = ir_seek_table(rc_tab, scancode);
-	if (elem >= 0) {
-		*keycode = rc_tab->scan[elem].keycode;
-		return 0;
-	}
-
-	/*
-	 * Scancode not found and table can't be expanded
-	 */
-	if (elem < 0 && rc_tab->size == IR_TAB_MAX_SIZE)
-		return -EINVAL;
-
-	/*
-	 * If is there extra space, returns KEY_RESERVED,
-	 * otherwise, input core won't let ir_setkeycode to work
-	 */
-	*keycode = KEY_RESERVED;
-	return 0;
-}
-
-/**
- * ir_is_resize_needed() - Check if the table needs rezise
- * @table:		keycode table that may need to resize
- * @n_elems:		minimum number of entries to store keycodes
- *
- * Considering that kmalloc uses power of two storage areas, this
- * routine detects if the real alloced size will change. If not, it
- * just returns without doing nothing. Otherwise, it will extend or
- * reduce the table size to meet the new needs.
- *
- * It returns 0 if no resize is needed, 1 otherwise.
- */
-static int ir_is_resize_needed(struct ir_scancode_table *table, int n_elems)
-{
-	int cur_size = ir_roundup_tablesize(table->size);
-	int new_size = ir_roundup_tablesize(n_elems);
-
-	if (cur_size == new_size)
-		return 0;
-
-	/* Resize is needed */
-	return 1;
-}
-
-/**
- * ir_delete_key() - remove a keycode from the table
- * @rc_tab:		keycode table
- * @elem:		element to be removed
- *
- */
-static void ir_delete_key(struct ir_scancode_table *rc_tab, int elem)
-{
-	unsigned long flags = 0;
-	int newsize = rc_tab->size - 1;
-	int resize = ir_is_resize_needed(rc_tab, newsize);
-	struct ir_scancode *oldkeymap = rc_tab->scan;
-	struct ir_scancode *newkeymap = NULL;
-
-	if (resize)
-		newkeymap = kzalloc(ir_roundup_tablesize(newsize) *
-				    sizeof(*newkeymap), GFP_ATOMIC);
-
-	/* There's no memory for resize. Keep the old table */
-	if (!resize || !newkeymap) {
-		newkeymap = oldkeymap;
-
-		/* We'll modify the live table. Lock it */
-		spin_lock_irqsave(&rc_tab->lock, flags);
-	}
-
-	/*
-	 * Copy the elements before the one that will be deleted
-	 * if (!resize), both oldkeymap and newkeymap points
-	 * to the same place, so, there's no need to copy
-	 */
-	if (resize && elem > 0)
-		memcpy(newkeymap, oldkeymap,
-		       elem * sizeof(*newkeymap));
-
-	/*
-	 * Copy the other elements overwriting the element to be removed
-	 * This operation applies to both resize and non-resize case
-	 */
-	if (elem < newsize)
-		memcpy(&newkeymap[elem], &oldkeymap[elem + 1],
-		       (newsize - elem) * sizeof(*newkeymap));
-
-	if (resize) {
-		/*
-		 * As the copy happened to a temporary table, only here
-		 * it needs to lock while replacing the table pointers
-		 * to use the new table
-		 */
-		spin_lock_irqsave(&rc_tab->lock, flags);
-		rc_tab->size = newsize;
-		rc_tab->scan = newkeymap;
-		spin_unlock_irqrestore(&rc_tab->lock, flags);
-
-		/* Frees the old keytable */
-		kfree(oldkeymap);
-	} else {
-		rc_tab->size = newsize;
-		spin_unlock_irqrestore(&rc_tab->lock, flags);
-	}
-}
-
-/**
- * ir_insert_key() - insert a keycode at the table
- * @rc_tab:		keycode table
- * @scancode:	the desired scancode
- * @keycode:	the keycode to be retorned.
- *
- */
-static int ir_insert_key(struct ir_scancode_table *rc_tab,
-			  int scancode, int keycode)
-{
-	unsigned long flags;
-	int elem = rc_tab->size;
-	int newsize = rc_tab->size + 1;
-	int resize = ir_is_resize_needed(rc_tab, newsize);
-	struct ir_scancode *oldkeymap = rc_tab->scan;
-	struct ir_scancode *newkeymap;
-
-	if (resize) {
-		newkeymap = kzalloc(ir_roundup_tablesize(newsize) *
-				    sizeof(*newkeymap), GFP_ATOMIC);
-		if (!newkeymap)
-			return -ENOMEM;
-
-		memcpy(newkeymap, oldkeymap,
-		       rc_tab->size * sizeof(*newkeymap));
-	} else
-		newkeymap  = oldkeymap;
-
-	/* Stores the new code at the table */
-	IR_dprintk(1, "#%d: New scan 0x%04x with key 0x%04x\n",
-		   rc_tab->size, scancode, keycode);
-
 	spin_lock_irqsave(&rc_tab->lock, flags);
-	rc_tab->size = newsize;
-	if (resize) {
-		rc_tab->scan = newkeymap;
-		kfree(oldkeymap);
+	start = 0;
+	end = rc_tab->len - 1;
+	while (start <= end) {
+		mid = (start + end) / 2;
+		if (rc_tab->scan[mid].scancode < scancode)
+			start = mid + 1;
+		else if (rc_tab->scan[mid].scancode > scancode)
+			end = mid - 1;
+		else {
+			key = rc_tab->scan[mid].keycode;
+			break;
+		}
 	}
-	newkeymap[elem].scancode = scancode;
-	newkeymap[elem].keycode  = keycode;
 	spin_unlock_irqrestore(&rc_tab->lock, flags);
 
-	return 0;
-}
+	if (key == KEY_RESERVED)
+		IR_dprintk(1, "unknown key for scancode 0x%04x\n",
+			   scancode);
 
-/**
- * ir_setkeycode() - set a keycode at the evdev scancode ->keycode table
- * @dev:	the struct input_dev device descriptor
- * @scancode:	the desired scancode
- * @keycode:	the keycode to be retorned.
- *
- * This routine is used to handle evdev EVIOCSKEY ioctl.
- * There's one caveat here: how can we increase the size of the table?
- * If the key is not found, returns -EINVAL, otherwise, returns 0.
- */
-static int ir_setkeycode(struct input_dev *dev,
-			 unsigned int scancode, unsigned int keycode)
-{
-	int rc = 0;
-	struct ir_input_dev *ir_dev = input_get_drvdata(dev);
-	struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
-	struct ir_scancode *keymap = rc_tab->scan;
-	unsigned long flags;
-
-	/*
-	 * Handle keycode table deletions
-	 *
-	 * If userspace is adding a KEY_UNKNOWN or KEY_RESERVED,
-	 * deal as a trial to remove an existing scancode attribution
-	 * if table become too big, reduce it to save space
-	 */
-	if (keycode == KEY_UNKNOWN || keycode == KEY_RESERVED) {
-		rc = ir_seek_table(rc_tab, scancode);
-		if (rc < 0)
-			return 0;
-
-		IR_dprintk(1, "#%d: Deleting scan 0x%04x\n", rc, scancode);
-		clear_bit(keymap[rc].keycode, dev->keybit);
-		ir_delete_key(rc_tab, rc);
-
-		return 0;
-	}
-
-	/*
-	 * Handle keycode replacements
-	 *
-	 * If the scancode exists, just replace by the new value
-	 */
-	rc = ir_seek_table(rc_tab, scancode);
-	if (rc >= 0) {
-		IR_dprintk(1, "#%d: Replacing scan 0x%04x with key 0x%04x\n",
-			rc, scancode, keycode);
-
-		clear_bit(keymap[rc].keycode, dev->keybit);
-
-		spin_lock_irqsave(&rc_tab->lock, flags);
-		keymap[rc].keycode = keycode;
-		spin_unlock_irqrestore(&rc_tab->lock, flags);
-
-		set_bit(keycode, dev->keybit);
-
-		return 0;
-	}
-
-	/*
-	 * Handle new scancode inserts
-	 *
-	 * reallocate table if needed and insert a new keycode
-	 */
-
-	/* Avoid growing the table indefinitely */
-	if (rc_tab->size + 1 > IR_TAB_MAX_SIZE)
-		return -EINVAL;
-
-	rc = ir_insert_key(rc_tab, scancode, keycode);
-	if (rc < 0)
-		return rc;
-	set_bit(keycode, dev->keybit);
-
+	*keycode = key;
 	return 0;
 }
 
@@ -365,34 +263,160 @@
  *
  * This routine is used by the input routines when a key is pressed at the
  * IR. The scancode is received and needs to be converted into a keycode.
- * If the key is not found, it returns KEY_UNKNOWN. Otherwise, returns the
+ * If the key is not found, it returns KEY_RESERVED. Otherwise, returns the
  * corresponding keycode from the table.
  */
 u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode)
 {
-	struct ir_input_dev *ir_dev = input_get_drvdata(dev);
-	struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
-	struct ir_scancode *keymap = rc_tab->scan;
-	int elem;
+	int keycode;
 
-	elem = ir_seek_table(rc_tab, scancode);
-	if (elem >= 0) {
+	ir_getkeycode(dev, scancode, &keycode);
+	if (keycode != KEY_RESERVED)
 		IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n",
-			   dev->name, scancode, keymap[elem].keycode);
-
-		return rc_tab->scan[elem].keycode;
-	}
-
-	printk(KERN_INFO "%s: unknown key for scancode 0x%04x\n",
-	       dev->name, scancode);
-
-	/* Reports userspace that an unknown keycode were got */
-	return KEY_RESERVED;
+			   dev->name, scancode, keycode);
+	return keycode;
 }
 EXPORT_SYMBOL_GPL(ir_g_keycode_from_table);
 
 /**
- * ir_input_register() - sets the IR keycode table and add the handlers
+ * ir_keyup() - generates input event to cleanup a key press
+ * @ir:         the struct ir_input_dev descriptor of the device
+ *
+ * This routine is used to signal that a key has been released on the
+ * remote control. It reports a keyup input event via input_report_key().
+ */
+static void ir_keyup(struct ir_input_dev *ir)
+{
+	if (!ir->keypressed)
+		return;
+
+	IR_dprintk(1, "keyup key 0x%04x\n", ir->last_keycode);
+	input_report_key(ir->input_dev, ir->last_keycode, 0);
+	input_sync(ir->input_dev);
+	ir->keypressed = false;
+}
+
+/**
+ * ir_timer_keyup() - generates a keyup event after a timeout
+ * @cookie:     a pointer to struct ir_input_dev passed to setup_timer()
+ *
+ * This routine will generate a keyup event some time after a keydown event
+ * is generated when no further activity has been detected.
+ */
+static void ir_timer_keyup(unsigned long cookie)
+{
+	struct ir_input_dev *ir = (struct ir_input_dev *)cookie;
+	unsigned long flags;
+
+	/*
+	 * ir->keyup_jiffies is used to prevent a race condition if a
+	 * hardware interrupt occurs at this point and the keyup timer
+	 * event is moved further into the future as a result.
+	 *
+	 * The timer will then be reactivated and this function called
+	 * again in the future. We need to exit gracefully in that case
+	 * to allow the input subsystem to do its auto-repeat magic or
+	 * a keyup event might follow immediately after the keydown.
+	 */
+	spin_lock_irqsave(&ir->keylock, flags);
+	if (time_is_after_eq_jiffies(ir->keyup_jiffies))
+		ir_keyup(ir);
+	spin_unlock_irqrestore(&ir->keylock, flags);
+}
+
+/**
+ * ir_repeat() - notifies the IR core that a key is still pressed
+ * @dev:        the struct input_dev descriptor of the device
+ *
+ * This routine is used by IR decoders when a repeat message which does
+ * not include the necessary bits to reproduce the scancode has been
+ * received.
+ */
+void ir_repeat(struct input_dev *dev)
+{
+	unsigned long flags;
+	struct ir_input_dev *ir = input_get_drvdata(dev);
+
+	spin_lock_irqsave(&ir->keylock, flags);
+
+	if (!ir->keypressed)
+		goto out;
+
+	ir->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
+	mod_timer(&ir->timer_keyup, ir->keyup_jiffies);
+
+out:
+	spin_unlock_irqrestore(&ir->keylock, flags);
+}
+EXPORT_SYMBOL_GPL(ir_repeat);
+
+/**
+ * ir_keydown() - generates input event for a key press
+ * @dev:        the struct input_dev descriptor of the device
+ * @scancode:   the scancode that we're seeking
+ * @toggle:     the toggle value (protocol dependent, if the protocol doesn't
+ *              support toggle values, this should be set to zero)
+ *
+ * This routine is used by the input routines when a key is pressed at the
+ * IR. It gets the keycode for a scancode and reports an input event via
+ * input_report_key().
+ */
+void ir_keydown(struct input_dev *dev, int scancode, u8 toggle)
+{
+	unsigned long flags;
+	struct ir_input_dev *ir = input_get_drvdata(dev);
+
+	u32 keycode = ir_g_keycode_from_table(dev, scancode);
+
+	spin_lock_irqsave(&ir->keylock, flags);
+
+	/* Repeat event? */
+	if (ir->keypressed &&
+	    ir->last_scancode == scancode &&
+	    ir->last_toggle == toggle)
+		goto set_timer;
+
+	/* Release old keypress */
+	ir_keyup(ir);
+
+	ir->last_scancode = scancode;
+	ir->last_toggle = toggle;
+	ir->last_keycode = keycode;
+
+	if (keycode == KEY_RESERVED)
+		goto out;
+
+	/* Register a keypress */
+	ir->keypressed = true;
+	IR_dprintk(1, "%s: key down event, key 0x%04x, scancode 0x%04x\n",
+		   dev->name, keycode, scancode);
+	input_report_key(dev, ir->last_keycode, 1);
+	input_sync(dev);
+
+set_timer:
+	ir->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
+	mod_timer(&ir->timer_keyup, ir->keyup_jiffies);
+out:
+	spin_unlock_irqrestore(&ir->keylock, flags);
+}
+EXPORT_SYMBOL_GPL(ir_keydown);
+
+static int ir_open(struct input_dev *input_dev)
+{
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+
+	return ir_dev->props->open(ir_dev->props->priv);
+}
+
+static void ir_close(struct input_dev *input_dev)
+{
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+
+	ir_dev->props->close(ir_dev->props->priv);
+}
+
+/**
+ * __ir_input_register() - sets the IR keycode table and add the handlers
  *			    for keymap table get/set
  * @input_dev:	the struct input_dev descriptor of the device
  * @rc_tab:	the struct ir_scancode_table table of scancode/keymap
@@ -402,13 +426,13 @@
  * It will register the input/evdev interface for the device and
  * register the syfs code for IR class
  */
-int ir_input_register(struct input_dev *input_dev,
+int __ir_input_register(struct input_dev *input_dev,
 		      const struct ir_scancode_table *rc_tab,
-		      const struct ir_dev_props *props)
+		      const struct ir_dev_props *props,
+		      const char *driver_name)
 {
 	struct ir_input_dev *ir_dev;
-	struct ir_scancode  *keymap    = rc_tab->scan;
-	int i, rc;
+	int rc;
 
 	if (rc_tab->scan == NULL || !rc_tab->size)
 		return -EINVAL;
@@ -417,57 +441,77 @@
 	if (!ir_dev)
 		return -ENOMEM;
 
-	spin_lock_init(&ir_dev->rc_tab.lock);
-
-	ir_dev->rc_tab.size = ir_roundup_tablesize(rc_tab->size);
-	ir_dev->rc_tab.scan = kzalloc(ir_dev->rc_tab.size *
-				    sizeof(struct ir_scancode), GFP_KERNEL);
-	if (!ir_dev->rc_tab.scan) {
-		kfree(ir_dev);
-		return -ENOMEM;
+	ir_dev->driver_name = kasprintf(GFP_KERNEL, "%s", driver_name);
+	if (!ir_dev->driver_name) {
+		rc = -ENOMEM;
+		goto out_dev;
 	}
 
-	IR_dprintk(1, "Allocated space for %d keycode entries (%zd bytes)\n",
-		ir_dev->rc_tab.size,
-		ir_dev->rc_tab.size * sizeof(ir_dev->rc_tab.scan));
-
-	ir_copy_table(&ir_dev->rc_tab, rc_tab);
-	ir_dev->props = props;
-
-	/* set the bits for the keys */
-	IR_dprintk(1, "key map size: %d\n", rc_tab->size);
-	for (i = 0; i < rc_tab->size; i++) {
-		IR_dprintk(1, "#%d: setting bit for keycode 0x%04x\n",
-			i, keymap[i].keycode);
-		set_bit(keymap[i].keycode, input_dev->keybit);
-	}
-	clear_bit(0, input_dev->keybit);
-
-	set_bit(EV_KEY, input_dev->evbit);
-
 	input_dev->getkeycode = ir_getkeycode;
 	input_dev->setkeycode = ir_setkeycode;
 	input_set_drvdata(input_dev, ir_dev);
+	ir_dev->input_dev = input_dev;
 
-	rc = input_register_device(input_dev);
-	if (rc < 0)
-		goto err;
+	spin_lock_init(&ir_dev->rc_tab.lock);
+	spin_lock_init(&ir_dev->keylock);
+	setup_timer(&ir_dev->timer_keyup, ir_timer_keyup, (unsigned long)ir_dev);
+
+	ir_dev->rc_tab.name = rc_tab->name;
+	ir_dev->rc_tab.ir_type = rc_tab->ir_type;
+	ir_dev->rc_tab.alloc = roundup_pow_of_two(rc_tab->size *
+						  sizeof(struct ir_scancode));
+	ir_dev->rc_tab.scan = kmalloc(ir_dev->rc_tab.alloc, GFP_KERNEL);
+	ir_dev->rc_tab.size = ir_dev->rc_tab.alloc / sizeof(struct ir_scancode);
+	if (props) {
+		ir_dev->props = props;
+		if (props->open)
+			input_dev->open = ir_open;
+		if (props->close)
+			input_dev->close = ir_close;
+	}
+
+	if (!ir_dev->rc_tab.scan) {
+		rc = -ENOMEM;
+		goto out_name;
+	}
+
+	IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
+		   ir_dev->rc_tab.size, ir_dev->rc_tab.alloc);
+
+	set_bit(EV_KEY, input_dev->evbit);
+	set_bit(EV_REP, input_dev->evbit);
+
+	if (ir_setkeytable(input_dev, &ir_dev->rc_tab, rc_tab)) {
+		rc = -ENOMEM;
+		goto out_table;
+	}
 
 	rc = ir_register_class(input_dev);
-	if (rc < 0) {
-		input_unregister_device(input_dev);
-		goto err;
+	if (rc < 0)
+		goto out_table;
+
+	if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW) {
+		rc = ir_raw_event_register(input_dev);
+		if (rc < 0)
+			goto out_event;
 	}
 
+	IR_dprintk(1, "Registered input device on %s for %s remote.\n",
+		   driver_name, rc_tab->name);
+
 	return 0;
 
-err:
-	kfree(rc_tab->scan);
+out_event:
+	ir_unregister_class(input_dev);
+out_table:
+	kfree(ir_dev->rc_tab.scan);
+out_name:
+	kfree(ir_dev->driver_name);
+out_dev:
 	kfree(ir_dev);
-	input_set_drvdata(input_dev, NULL);
 	return rc;
 }
-EXPORT_SYMBOL_GPL(ir_input_register);
+EXPORT_SYMBOL_GPL(__ir_input_register);
 
 /**
  * ir_input_unregister() - unregisters IR and frees resources
@@ -475,9 +519,9 @@
 
  * This routine is used to free memory and de-register interfaces.
  */
-void ir_input_unregister(struct input_dev *dev)
+void ir_input_unregister(struct input_dev *input_dev)
 {
-	struct ir_input_dev *ir_dev = input_get_drvdata(dev);
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
 	struct ir_scancode_table *rc_tab;
 
 	if (!ir_dev)
@@ -485,15 +529,18 @@
 
 	IR_dprintk(1, "Freed keycode table\n");
 
+	del_timer_sync(&ir_dev->timer_keyup);
+	if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW)
+		ir_raw_event_unregister(input_dev);
 	rc_tab = &ir_dev->rc_tab;
 	rc_tab->size = 0;
 	kfree(rc_tab->scan);
 	rc_tab->scan = NULL;
 
-	ir_unregister_class(dev);
+	ir_unregister_class(input_dev);
 
+	kfree(ir_dev->driver_name);
 	kfree(ir_dev);
-	input_unregister_device(dev);
 }
 EXPORT_SYMBOL_GPL(ir_input_unregister);
 
diff --git a/drivers/media/IR/ir-nec-decoder.c b/drivers/media/IR/ir-nec-decoder.c
new file mode 100644
index 0000000..ba79233
--- /dev/null
+++ b/drivers/media/IR/ir-nec-decoder.c
@@ -0,0 +1,328 @@
+/* ir-nec-decoder.c - handle NEC IR Pulse/Space protocol
+ *
+ * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+
+#include <linux/bitrev.h>
+#include "ir-core-priv.h"
+
+#define NEC_NBITS		32
+#define NEC_UNIT		562500  /* ns */
+#define NEC_HEADER_PULSE	(16 * NEC_UNIT)
+#define NECX_HEADER_PULSE	(8  * NEC_UNIT) /* Less common NEC variant */
+#define NEC_HEADER_SPACE	(8  * NEC_UNIT)
+#define NEC_REPEAT_SPACE	(8  * NEC_UNIT)
+#define NEC_BIT_PULSE		(1  * NEC_UNIT)
+#define NEC_BIT_0_SPACE		(1  * NEC_UNIT)
+#define NEC_BIT_1_SPACE		(3  * NEC_UNIT)
+#define	NEC_TRAILER_PULSE	(1  * NEC_UNIT)
+#define	NEC_TRAILER_SPACE	(10 * NEC_UNIT) /* even longer in reality */
+
+/* Used to register nec_decoder clients */
+static LIST_HEAD(decoder_list);
+static DEFINE_SPINLOCK(decoder_lock);
+
+enum nec_state {
+	STATE_INACTIVE,
+	STATE_HEADER_SPACE,
+	STATE_BIT_PULSE,
+	STATE_BIT_SPACE,
+	STATE_TRAILER_PULSE,
+	STATE_TRAILER_SPACE,
+};
+
+struct decoder_data {
+	struct list_head	list;
+	struct ir_input_dev	*ir_dev;
+	int			enabled:1;
+
+	/* State machine control */
+	enum nec_state		state;
+	u32			nec_bits;
+	unsigned		count;
+};
+
+
+/**
+ * get_decoder_data()	- gets decoder data
+ * @input_dev:	input device
+ *
+ * Returns the struct decoder_data that corresponds to a device
+ */
+static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
+{
+	struct decoder_data *data = NULL;
+
+	spin_lock(&decoder_lock);
+	list_for_each_entry(data, &decoder_list, list) {
+		if (data->ir_dev == ir_dev)
+			break;
+	}
+	spin_unlock(&decoder_lock);
+	return data;
+}
+
+static ssize_t store_enabled(struct device *d,
+			     struct device_attribute *mattr,
+			     const char *buf,
+			     size_t len)
+{
+	unsigned long value;
+	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
+	struct decoder_data *data = get_decoder_data(ir_dev);
+
+	if (!data)
+		return -EINVAL;
+
+	if (strict_strtoul(buf, 10, &value) || value > 1)
+		return -EINVAL;
+
+	data->enabled = value;
+
+	return len;
+}
+
+static ssize_t show_enabled(struct device *d,
+			     struct device_attribute *mattr, char *buf)
+{
+	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
+	struct decoder_data *data = get_decoder_data(ir_dev);
+
+	if (!data)
+		return -EINVAL;
+
+	if (data->enabled)
+		return sprintf(buf, "1\n");
+	else
+	return sprintf(buf, "0\n");
+}
+
+static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
+
+static struct attribute *decoder_attributes[] = {
+	&dev_attr_enabled.attr,
+	NULL
+};
+
+static struct attribute_group decoder_attribute_group = {
+	.name	= "nec_decoder",
+	.attrs	= decoder_attributes,
+};
+
+/**
+ * ir_nec_decode() - Decode one NEC pulse or space
+ * @input_dev:	the struct input_dev descriptor of the device
+ * @duration:	the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This function returns -EINVAL if the pulse violates the state machine
+ */
+static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+{
+	struct decoder_data *data;
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+	u32 scancode;
+	u8 address, not_address, command, not_command;
+
+	data = get_decoder_data(ir_dev);
+	if (!data)
+		return -EINVAL;
+
+	if (!data->enabled)
+		return 0;
+
+	if (IS_RESET(ev)) {
+		data->state = STATE_INACTIVE;
+		return 0;
+	}
+
+	IR_dprintk(2, "NEC decode started at state %d (%uus %s)\n",
+		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+
+	switch (data->state) {
+
+	case STATE_INACTIVE:
+		if (!ev.pulse)
+			break;
+
+		if (!eq_margin(ev.duration, NEC_HEADER_PULSE, NEC_UNIT / 2) &&
+		    !eq_margin(ev.duration, NECX_HEADER_PULSE, NEC_UNIT / 2))
+			break;
+
+		data->count = 0;
+		data->state = STATE_HEADER_SPACE;
+		return 0;
+
+	case STATE_HEADER_SPACE:
+		if (ev.pulse)
+			break;
+
+		if (eq_margin(ev.duration, NEC_HEADER_SPACE, NEC_UNIT / 2)) {
+			data->state = STATE_BIT_PULSE;
+			return 0;
+		} else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) {
+			ir_repeat(input_dev);
+			IR_dprintk(1, "Repeat last key\n");
+			data->state = STATE_TRAILER_PULSE;
+			return 0;
+		}
+
+		break;
+
+	case STATE_BIT_PULSE:
+		if (!ev.pulse)
+			break;
+
+		if (!eq_margin(ev.duration, NEC_BIT_PULSE, NEC_UNIT / 2))
+			break;
+
+		data->state = STATE_BIT_SPACE;
+		return 0;
+
+	case STATE_BIT_SPACE:
+		if (ev.pulse)
+			break;
+
+		data->nec_bits <<= 1;
+		if (eq_margin(ev.duration, NEC_BIT_1_SPACE, NEC_UNIT / 2))
+			data->nec_bits |= 1;
+		else if (!eq_margin(ev.duration, NEC_BIT_0_SPACE, NEC_UNIT / 2))
+			break;
+		data->count++;
+
+		if (data->count == NEC_NBITS)
+			data->state = STATE_TRAILER_PULSE;
+		else
+			data->state = STATE_BIT_PULSE;
+
+		return 0;
+
+	case STATE_TRAILER_PULSE:
+		if (!ev.pulse)
+			break;
+
+		if (!eq_margin(ev.duration, NEC_TRAILER_PULSE, NEC_UNIT / 2))
+			break;
+
+		data->state = STATE_TRAILER_SPACE;
+		return 0;
+
+	case STATE_TRAILER_SPACE:
+		if (ev.pulse)
+			break;
+
+		if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2))
+			break;
+
+		address     = bitrev8((data->nec_bits >> 24) & 0xff);
+		not_address = bitrev8((data->nec_bits >> 16) & 0xff);
+		command	    = bitrev8((data->nec_bits >>  8) & 0xff);
+		not_command = bitrev8((data->nec_bits >>  0) & 0xff);
+
+		if ((command ^ not_command) != 0xff) {
+			IR_dprintk(1, "NEC checksum error: received 0x%08x\n",
+				   data->nec_bits);
+			break;
+		}
+
+		if ((address ^ not_address) != 0xff) {
+			/* Extended NEC */
+			scancode = address     << 16 |
+				   not_address <<  8 |
+				   command;
+			IR_dprintk(1, "NEC (Ext) scancode 0x%06x\n", scancode);
+		} else {
+			/* Normal NEC */
+			scancode = address << 8 | command;
+			IR_dprintk(1, "NEC scancode 0x%04x\n", scancode);
+		}
+
+		ir_keydown(input_dev, scancode, 0);
+		data->state = STATE_INACTIVE;
+		return 0;
+	}
+
+	IR_dprintk(1, "NEC decode failed at state %d (%uus %s)\n",
+		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+	data->state = STATE_INACTIVE;
+	return -EINVAL;
+}
+
+static int ir_nec_register(struct input_dev *input_dev)
+{
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+	struct decoder_data *data;
+	int rc;
+
+	rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+	if (rc < 0)
+		return rc;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+		return -ENOMEM;
+	}
+
+	data->ir_dev = ir_dev;
+	data->enabled = 1;
+
+	spin_lock(&decoder_lock);
+	list_add_tail(&data->list, &decoder_list);
+	spin_unlock(&decoder_lock);
+
+	return 0;
+}
+
+static int ir_nec_unregister(struct input_dev *input_dev)
+{
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+	static struct decoder_data *data;
+
+	data = get_decoder_data(ir_dev);
+	if (!data)
+		return 0;
+
+	sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+
+	spin_lock(&decoder_lock);
+	list_del(&data->list);
+	spin_unlock(&decoder_lock);
+
+	return 0;
+}
+
+static struct ir_raw_handler nec_handler = {
+	.decode		= ir_nec_decode,
+	.raw_register	= ir_nec_register,
+	.raw_unregister	= ir_nec_unregister,
+};
+
+static int __init ir_nec_decode_init(void)
+{
+	ir_raw_handler_register(&nec_handler);
+
+	printk(KERN_INFO "IR NEC protocol handler initialized\n");
+	return 0;
+}
+
+static void __exit ir_nec_decode_exit(void)
+{
+	ir_raw_handler_unregister(&nec_handler);
+}
+
+module_init(ir_nec_decode_init);
+module_exit(ir_nec_decode_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
+MODULE_DESCRIPTION("NEC IR protocol decoder");
diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c
new file mode 100644
index 0000000..ea68a3f
--- /dev/null
+++ b/drivers/media/IR/ir-raw-event.c
@@ -0,0 +1,251 @@
+/* ir-raw-event.c - handle IR Pulse/Space event
+ *
+ * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include "ir-core-priv.h"
+
+/* Define the max number of pulse/space transitions to buffer */
+#define MAX_IR_EVENT_SIZE      512
+
+/* Used to handle IR raw handler extensions */
+static LIST_HEAD(ir_raw_handler_list);
+static DEFINE_SPINLOCK(ir_raw_handler_lock);
+
+/**
+ * RUN_DECODER()	- runs an operation on all IR decoders
+ * @ops:	IR raw handler operation to be called
+ * @arg:	arguments to be passed to the callback
+ *
+ * Calls ir_raw_handler::ops for all registered IR handlers. It prevents
+ * new decode addition/removal while running, by locking ir_raw_handler_lock
+ * mutex. If an error occurs, it stops the ops. Otherwise, it returns a sum
+ * of the return codes.
+ */
+#define RUN_DECODER(ops, ...) ({					    \
+	struct ir_raw_handler		*_ir_raw_handler;		    \
+	int _sumrc = 0, _rc;						    \
+	spin_lock(&ir_raw_handler_lock);				    \
+	list_for_each_entry(_ir_raw_handler, &ir_raw_handler_list, list) {  \
+		if (_ir_raw_handler->ops) {				    \
+			_rc = _ir_raw_handler->ops(__VA_ARGS__);	    \
+			if (_rc < 0)					    \
+				break;					    \
+			_sumrc += _rc;					    \
+		}							    \
+	}								    \
+	spin_unlock(&ir_raw_handler_lock);				    \
+	_sumrc;								    \
+})
+
+#ifdef MODULE
+/* Used to load the decoders */
+static struct work_struct wq_load;
+#endif
+
+static void ir_raw_event_work(struct work_struct *work)
+{
+	struct ir_raw_event ev;
+	struct ir_raw_event_ctrl *raw =
+		container_of(work, struct ir_raw_event_ctrl, rx_work);
+
+	while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev))
+		RUN_DECODER(decode, raw->input_dev, ev);
+}
+
+int ir_raw_event_register(struct input_dev *input_dev)
+{
+	struct ir_input_dev *ir = input_get_drvdata(input_dev);
+	int rc;
+
+	ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL);
+	if (!ir->raw)
+		return -ENOMEM;
+
+	ir->raw->input_dev = input_dev;
+	INIT_WORK(&ir->raw->rx_work, ir_raw_event_work);
+
+	rc = kfifo_alloc(&ir->raw->kfifo, sizeof(s64) * MAX_IR_EVENT_SIZE,
+			 GFP_KERNEL);
+	if (rc < 0) {
+		kfree(ir->raw);
+		ir->raw = NULL;
+		return rc;
+	}
+
+	rc = RUN_DECODER(raw_register, input_dev);
+	if (rc < 0) {
+		kfifo_free(&ir->raw->kfifo);
+		kfree(ir->raw);
+		ir->raw = NULL;
+		return rc;
+	}
+
+	return rc;
+}
+
+void ir_raw_event_unregister(struct input_dev *input_dev)
+{
+	struct ir_input_dev *ir = input_get_drvdata(input_dev);
+
+	if (!ir->raw)
+		return;
+
+	cancel_work_sync(&ir->raw->rx_work);
+	RUN_DECODER(raw_unregister, input_dev);
+
+	kfifo_free(&ir->raw->kfifo);
+	kfree(ir->raw);
+	ir->raw = NULL;
+}
+
+/**
+ * ir_raw_event_store() - pass a pulse/space duration to the raw ir decoders
+ * @input_dev:	the struct input_dev device descriptor
+ * @ev:		the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This routine (which may be called from an interrupt context) stores a
+ * pulse/space duration for the raw ir decoding state machines. Pulses are
+ * signalled as positive values and spaces as negative values. A zero value
+ * will reset the decoding state machines.
+ */
+int ir_raw_event_store(struct input_dev *input_dev, struct ir_raw_event *ev)
+{
+	struct ir_input_dev *ir = input_get_drvdata(input_dev);
+
+	if (!ir->raw)
+		return -EINVAL;
+
+	if (kfifo_in(&ir->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev))
+		return -ENOMEM;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ir_raw_event_store);
+
+/**
+ * ir_raw_event_store_edge() - notify raw ir decoders of the start of a pulse/space
+ * @input_dev:	the struct input_dev device descriptor
+ * @type:	the type of the event that has occurred
+ *
+ * This routine (which may be called from an interrupt context) is used to
+ * store the beginning of an ir pulse or space (or the start/end of ir
+ * reception) for the raw ir decoding state machines. This is used by
+ * hardware which does not provide durations directly but only interrupts
+ * (or similar events) on state change.
+ */
+int ir_raw_event_store_edge(struct input_dev *input_dev, enum raw_event_type type)
+{
+	struct ir_input_dev	*ir = input_get_drvdata(input_dev);
+	ktime_t			now;
+	s64			delta; /* ns */
+	struct ir_raw_event	ev;
+	int			rc = 0;
+
+	if (!ir->raw)
+		return -EINVAL;
+
+	now = ktime_get();
+	delta = ktime_to_ns(ktime_sub(now, ir->raw->last_event));
+
+	/* Check for a long duration since last event or if we're
+	 * being called for the first time, note that delta can't
+	 * possibly be negative.
+	 */
+	ev.duration = 0;
+	if (delta > IR_MAX_DURATION || !ir->raw->last_type)
+		type |= IR_START_EVENT;
+	else
+		ev.duration = delta;
+
+	if (type & IR_START_EVENT)
+		ir_raw_event_reset(input_dev);
+	else if (ir->raw->last_type & IR_SPACE) {
+		ev.pulse = false;
+		rc = ir_raw_event_store(input_dev, &ev);
+	} else if (ir->raw->last_type & IR_PULSE) {
+		ev.pulse = true;
+		rc = ir_raw_event_store(input_dev, &ev);
+	} else
+		return 0;
+
+	ir->raw->last_event = now;
+	ir->raw->last_type = type;
+	return rc;
+}
+EXPORT_SYMBOL_GPL(ir_raw_event_store_edge);
+
+/**
+ * ir_raw_event_handle() - schedules the decoding of stored ir data
+ * @input_dev:	the struct input_dev device descriptor
+ *
+ * This routine will signal the workqueue to start decoding stored ir data.
+ */
+void ir_raw_event_handle(struct input_dev *input_dev)
+{
+	struct ir_input_dev *ir = input_get_drvdata(input_dev);
+
+	if (!ir->raw)
+		return;
+
+	schedule_work(&ir->raw->rx_work);
+}
+EXPORT_SYMBOL_GPL(ir_raw_event_handle);
+
+/*
+ * Extension interface - used to register the IR decoders
+ */
+
+int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
+{
+	spin_lock(&ir_raw_handler_lock);
+	list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list);
+	spin_unlock(&ir_raw_handler_lock);
+	return 0;
+}
+EXPORT_SYMBOL(ir_raw_handler_register);
+
+void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
+{
+	spin_lock(&ir_raw_handler_lock);
+	list_del(&ir_raw_handler->list);
+	spin_unlock(&ir_raw_handler_lock);
+}
+EXPORT_SYMBOL(ir_raw_handler_unregister);
+
+#ifdef MODULE
+static void init_decoders(struct work_struct *work)
+{
+	/* Load the decoder modules */
+
+	load_nec_decode();
+	load_rc5_decode();
+	load_rc6_decode();
+	load_jvc_decode();
+	load_sony_decode();
+
+	/* If needed, we may later add some init code. In this case,
+	   it is needed to change the CONFIG_MODULE test at ir-core.h
+	 */
+}
+#endif
+
+void ir_raw_init(void)
+{
+#ifdef MODULE
+	INIT_WORK(&wq_load, init_decoders);
+	schedule_work(&wq_load);
+#endif
+}
diff --git a/drivers/media/IR/ir-rc5-decoder.c b/drivers/media/IR/ir-rc5-decoder.c
new file mode 100644
index 0000000..23cdb1b
--- /dev/null
+++ b/drivers/media/IR/ir-rc5-decoder.c
@@ -0,0 +1,324 @@
+/* ir-rc5-decoder.c - handle RC5(x) IR Pulse/Space protocol
+ *
+ * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+
+/*
+ * This code handles 14 bits RC5 protocols and 20 bits RC5x protocols.
+ * There are other variants that use a different number of bits.
+ * This is currently unsupported.
+ * It considers a carrier of 36 kHz, with a total of 14/20 bits, where
+ * the first two bits are start bits, and a third one is a filing bit
+ */
+
+#include "ir-core-priv.h"
+
+#define RC5_NBITS		14
+#define RC5X_NBITS		20
+#define CHECK_RC5X_NBITS	8
+#define RC5_UNIT		888888 /* ns */
+#define RC5_BIT_START		(1 * RC5_UNIT)
+#define RC5_BIT_END		(1 * RC5_UNIT)
+#define RC5X_SPACE		(4 * RC5_UNIT)
+
+/* Used to register rc5_decoder clients */
+static LIST_HEAD(decoder_list);
+static DEFINE_SPINLOCK(decoder_lock);
+
+enum rc5_state {
+	STATE_INACTIVE,
+	STATE_BIT_START,
+	STATE_BIT_END,
+	STATE_CHECK_RC5X,
+	STATE_FINISHED,
+};
+
+struct decoder_data {
+	struct list_head	list;
+	struct ir_input_dev	*ir_dev;
+	int			enabled:1;
+
+	/* State machine control */
+	enum rc5_state		state;
+	u32			rc5_bits;
+	struct ir_raw_event	prev_ev;
+	unsigned		count;
+	unsigned		wanted_bits;
+};
+
+
+/**
+ * get_decoder_data()	- gets decoder data
+ * @input_dev:	input device
+ *
+ * Returns the struct decoder_data that corresponds to a device
+ */
+
+static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
+{
+	struct decoder_data *data = NULL;
+
+	spin_lock(&decoder_lock);
+	list_for_each_entry(data, &decoder_list, list) {
+		if (data->ir_dev == ir_dev)
+			break;
+	}
+	spin_unlock(&decoder_lock);
+	return data;
+}
+
+static ssize_t store_enabled(struct device *d,
+			     struct device_attribute *mattr,
+			     const char *buf,
+			     size_t len)
+{
+	unsigned long value;
+	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
+	struct decoder_data *data = get_decoder_data(ir_dev);
+
+	if (!data)
+		return -EINVAL;
+
+	if (strict_strtoul(buf, 10, &value) || value > 1)
+		return -EINVAL;
+
+	data->enabled = value;
+
+	return len;
+}
+
+static ssize_t show_enabled(struct device *d,
+			     struct device_attribute *mattr, char *buf)
+{
+	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
+	struct decoder_data *data = get_decoder_data(ir_dev);
+
+	if (!data)
+		return -EINVAL;
+
+	if (data->enabled)
+		return sprintf(buf, "1\n");
+	else
+	return sprintf(buf, "0\n");
+}
+
+static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
+
+static struct attribute *decoder_attributes[] = {
+	&dev_attr_enabled.attr,
+	NULL
+};
+
+static struct attribute_group decoder_attribute_group = {
+	.name	= "rc5_decoder",
+	.attrs	= decoder_attributes,
+};
+
+/**
+ * ir_rc5_decode() - Decode one RC-5 pulse or space
+ * @input_dev:	the struct input_dev descriptor of the device
+ * @ev:		the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This function returns -EINVAL if the pulse violates the state machine
+ */
+static int ir_rc5_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+{
+	struct decoder_data *data;
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+	u8 toggle;
+	u32 scancode;
+
+	data = get_decoder_data(ir_dev);
+	if (!data)
+		return -EINVAL;
+
+	if (!data->enabled)
+		return 0;
+
+	if (IS_RESET(ev)) {
+		data->state = STATE_INACTIVE;
+		return 0;
+	}
+
+	if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
+		goto out;
+
+again:
+	IR_dprintk(2, "RC5(x) decode started at state %i (%uus %s)\n",
+		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+
+	if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
+		return 0;
+
+	switch (data->state) {
+
+	case STATE_INACTIVE:
+		if (!ev.pulse)
+			break;
+
+		data->state = STATE_BIT_START;
+		data->count = 1;
+		/* We just need enough bits to get to STATE_CHECK_RC5X */
+		data->wanted_bits = RC5X_NBITS;
+		decrease_duration(&ev, RC5_BIT_START);
+		goto again;
+
+	case STATE_BIT_START:
+		if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
+			break;
+
+		data->rc5_bits <<= 1;
+		if (!ev.pulse)
+			data->rc5_bits |= 1;
+		data->count++;
+		data->prev_ev = ev;
+		data->state = STATE_BIT_END;
+		return 0;
+
+	case STATE_BIT_END:
+		if (!is_transition(&ev, &data->prev_ev))
+			break;
+
+		if (data->count == data->wanted_bits)
+			data->state = STATE_FINISHED;
+		else if (data->count == CHECK_RC5X_NBITS)
+			data->state = STATE_CHECK_RC5X;
+		else
+			data->state = STATE_BIT_START;
+
+		decrease_duration(&ev, RC5_BIT_END);
+		goto again;
+
+	case STATE_CHECK_RC5X:
+		if (!ev.pulse && geq_margin(ev.duration, RC5X_SPACE, RC5_UNIT / 2)) {
+			/* RC5X */
+			data->wanted_bits = RC5X_NBITS;
+			decrease_duration(&ev, RC5X_SPACE);
+		} else {
+			/* RC5 */
+			data->wanted_bits = RC5_NBITS;
+		}
+		data->state = STATE_BIT_START;
+		goto again;
+
+	case STATE_FINISHED:
+		if (ev.pulse)
+			break;
+
+		if (data->wanted_bits == RC5X_NBITS) {
+			/* RC5X */
+			u8 xdata, command, system;
+			xdata    = (data->rc5_bits & 0x0003F) >> 0;
+			command  = (data->rc5_bits & 0x00FC0) >> 6;
+			system   = (data->rc5_bits & 0x1F000) >> 12;
+			toggle   = (data->rc5_bits & 0x20000) ? 1 : 0;
+			command += (data->rc5_bits & 0x01000) ? 0 : 0x40;
+			scancode = system << 16 | command << 8 | xdata;
+
+			IR_dprintk(1, "RC5X scancode 0x%06x (toggle: %u)\n",
+				   scancode, toggle);
+
+		} else {
+			/* RC5 */
+			u8 command, system;
+			command  = (data->rc5_bits & 0x0003F) >> 0;
+			system   = (data->rc5_bits & 0x007C0) >> 6;
+			toggle   = (data->rc5_bits & 0x00800) ? 1 : 0;
+			command += (data->rc5_bits & 0x01000) ? 0 : 0x40;
+			scancode = system << 8 | command;
+
+			IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n",
+				   scancode, toggle);
+		}
+
+		ir_keydown(input_dev, scancode, toggle);
+		data->state = STATE_INACTIVE;
+		return 0;
+	}
+
+out:
+	IR_dprintk(1, "RC5(x) decode failed at state %i (%uus %s)\n",
+		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+	data->state = STATE_INACTIVE;
+	return -EINVAL;
+}
+
+static int ir_rc5_register(struct input_dev *input_dev)
+{
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+	struct decoder_data *data;
+	int rc;
+
+	rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+	if (rc < 0)
+		return rc;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+		return -ENOMEM;
+	}
+
+	data->ir_dev = ir_dev;
+	data->enabled = 1;
+
+	spin_lock(&decoder_lock);
+	list_add_tail(&data->list, &decoder_list);
+	spin_unlock(&decoder_lock);
+
+	return 0;
+}
+
+static int ir_rc5_unregister(struct input_dev *input_dev)
+{
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+	static struct decoder_data *data;
+
+	data = get_decoder_data(ir_dev);
+	if (!data)
+		return 0;
+
+	sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+
+	spin_lock(&decoder_lock);
+	list_del(&data->list);
+	spin_unlock(&decoder_lock);
+
+	return 0;
+}
+
+static struct ir_raw_handler rc5_handler = {
+	.decode		= ir_rc5_decode,
+	.raw_register	= ir_rc5_register,
+	.raw_unregister	= ir_rc5_unregister,
+};
+
+static int __init ir_rc5_decode_init(void)
+{
+	ir_raw_handler_register(&rc5_handler);
+
+	printk(KERN_INFO "IR RC5(x) protocol handler initialized\n");
+	return 0;
+}
+
+static void __exit ir_rc5_decode_exit(void)
+{
+	ir_raw_handler_unregister(&rc5_handler);
+}
+
+module_init(ir_rc5_decode_init);
+module_exit(ir_rc5_decode_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
+MODULE_DESCRIPTION("RC5(x) IR protocol decoder");
diff --git a/drivers/media/IR/ir-rc6-decoder.c b/drivers/media/IR/ir-rc6-decoder.c
new file mode 100644
index 0000000..2bf479f
--- /dev/null
+++ b/drivers/media/IR/ir-rc6-decoder.c
@@ -0,0 +1,419 @@
+/* ir-rc6-decoder.c - A decoder for the RC6 IR protocol
+ *
+ * Copyright (C) 2010 by David Härdeman <david@hardeman.nu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "ir-core-priv.h"
+
+/*
+ * This decoder currently supports:
+ * RC6-0-16	(standard toggle bit in header)
+ * RC6-6A-24	(no toggle bit)
+ * RC6-6A-32	(MCE version with toggle bit in body)
+ */
+
+#define RC6_UNIT		444444	/* us */
+#define RC6_HEADER_NBITS	4	/* not including toggle bit */
+#define RC6_0_NBITS		16
+#define RC6_6A_SMALL_NBITS	24
+#define RC6_6A_LARGE_NBITS	32
+#define RC6_PREFIX_PULSE	(6 * RC6_UNIT)
+#define RC6_PREFIX_SPACE	(2 * RC6_UNIT)
+#define RC6_BIT_START		(1 * RC6_UNIT)
+#define RC6_BIT_END		(1 * RC6_UNIT)
+#define RC6_TOGGLE_START	(2 * RC6_UNIT)
+#define RC6_TOGGLE_END		(2 * RC6_UNIT)
+#define RC6_MODE_MASK		0x07	/* for the header bits */
+#define RC6_STARTBIT_MASK	0x08	/* for the header bits */
+#define RC6_6A_MCE_TOGGLE_MASK	0x8000	/* for the body bits */
+
+/* Used to register rc6_decoder clients */
+static LIST_HEAD(decoder_list);
+static DEFINE_SPINLOCK(decoder_lock);
+
+enum rc6_mode {
+	RC6_MODE_0,
+	RC6_MODE_6A,
+	RC6_MODE_UNKNOWN,
+};
+
+enum rc6_state {
+	STATE_INACTIVE,
+	STATE_PREFIX_SPACE,
+	STATE_HEADER_BIT_START,
+	STATE_HEADER_BIT_END,
+	STATE_TOGGLE_START,
+	STATE_TOGGLE_END,
+	STATE_BODY_BIT_START,
+	STATE_BODY_BIT_END,
+	STATE_FINISHED,
+};
+
+struct decoder_data {
+	struct list_head	list;
+	struct ir_input_dev	*ir_dev;
+	int			enabled:1;
+
+	/* State machine control */
+	enum rc6_state		state;
+	u8			header;
+	u32			body;
+	struct ir_raw_event	prev_ev;
+	bool			toggle;
+	unsigned		count;
+	unsigned		wanted_bits;
+};
+
+
+/**
+ * get_decoder_data()	- gets decoder data
+ * @input_dev:	input device
+ *
+ * Returns the struct decoder_data that corresponds to a device
+ */
+static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
+{
+	struct decoder_data *data = NULL;
+
+	spin_lock(&decoder_lock);
+	list_for_each_entry(data, &decoder_list, list) {
+		if (data->ir_dev == ir_dev)
+			break;
+	}
+	spin_unlock(&decoder_lock);
+	return data;
+}
+
+static ssize_t store_enabled(struct device *d,
+			     struct device_attribute *mattr,
+			     const char *buf,
+			     size_t len)
+{
+	unsigned long value;
+	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
+	struct decoder_data *data = get_decoder_data(ir_dev);
+
+	if (!data)
+		return -EINVAL;
+
+	if (strict_strtoul(buf, 10, &value) || value > 1)
+		return -EINVAL;
+
+	data->enabled = value;
+
+	return len;
+}
+
+static ssize_t show_enabled(struct device *d,
+			     struct device_attribute *mattr, char *buf)
+{
+	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
+	struct decoder_data *data = get_decoder_data(ir_dev);
+
+	if (!data)
+		return -EINVAL;
+
+	if (data->enabled)
+		return sprintf(buf, "1\n");
+	else
+	return sprintf(buf, "0\n");
+}
+
+static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
+
+static struct attribute *decoder_attributes[] = {
+	&dev_attr_enabled.attr,
+	NULL
+};
+
+static struct attribute_group decoder_attribute_group = {
+	.name	= "rc6_decoder",
+	.attrs	= decoder_attributes,
+};
+
+static enum rc6_mode rc6_mode(struct decoder_data *data) {
+	switch (data->header & RC6_MODE_MASK) {
+	case 0:
+		return RC6_MODE_0;
+	case 6:
+		if (!data->toggle)
+			return RC6_MODE_6A;
+		/* fall through */
+	default:
+		return RC6_MODE_UNKNOWN;
+	}
+}
+
+/**
+ * ir_rc6_decode() - Decode one RC6 pulse or space
+ * @input_dev:	the struct input_dev descriptor of the device
+ * @ev:		the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This function returns -EINVAL if the pulse violates the state machine
+ */
+static int ir_rc6_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+{
+	struct decoder_data *data;
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+	u32 scancode;
+	u8 toggle;
+
+	data = get_decoder_data(ir_dev);
+	if (!data)
+		return -EINVAL;
+
+	if (!data->enabled)
+		return 0;
+
+	if (IS_RESET(ev)) {
+		data->state = STATE_INACTIVE;
+		return 0;
+	}
+
+	if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
+		goto out;
+
+again:
+	IR_dprintk(2, "RC6 decode started at state %i (%uus %s)\n",
+		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+
+	if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
+		return 0;
+
+	switch (data->state) {
+
+	case STATE_INACTIVE:
+		if (!ev.pulse)
+			break;
+
+		/* Note: larger margin on first pulse since each RC6_UNIT
+		   is quite short and some hardware takes some time to
+		   adjust to the signal */
+		if (!eq_margin(ev.duration, RC6_PREFIX_PULSE, RC6_UNIT))
+			break;
+
+		data->state = STATE_PREFIX_SPACE;
+		data->count = 0;
+		return 0;
+
+	case STATE_PREFIX_SPACE:
+		if (ev.pulse)
+			break;
+
+		if (!eq_margin(ev.duration, RC6_PREFIX_SPACE, RC6_UNIT / 2))
+			break;
+
+		data->state = STATE_HEADER_BIT_START;
+		return 0;
+
+	case STATE_HEADER_BIT_START:
+		if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2))
+			break;
+
+		data->header <<= 1;
+		if (ev.pulse)
+			data->header |= 1;
+		data->count++;
+		data->prev_ev = ev;
+		data->state = STATE_HEADER_BIT_END;
+		return 0;
+
+	case STATE_HEADER_BIT_END:
+		if (!is_transition(&ev, &data->prev_ev))
+			break;
+
+		if (data->count == RC6_HEADER_NBITS)
+			data->state = STATE_TOGGLE_START;
+		else
+			data->state = STATE_HEADER_BIT_START;
+
+		decrease_duration(&ev, RC6_BIT_END);
+		goto again;
+
+	case STATE_TOGGLE_START:
+		if (!eq_margin(ev.duration, RC6_TOGGLE_START, RC6_UNIT / 2))
+			break;
+
+		data->toggle = ev.pulse;
+		data->prev_ev = ev;
+		data->state = STATE_TOGGLE_END;
+		return 0;
+
+	case STATE_TOGGLE_END:
+		if (!is_transition(&ev, &data->prev_ev) ||
+		    !geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2))
+			break;
+
+		if (!(data->header & RC6_STARTBIT_MASK)) {
+			IR_dprintk(1, "RC6 invalid start bit\n");
+			break;
+		}
+
+		data->state = STATE_BODY_BIT_START;
+		data->prev_ev = ev;
+		decrease_duration(&ev, RC6_TOGGLE_END);
+		data->count = 0;
+
+		switch (rc6_mode(data)) {
+		case RC6_MODE_0:
+			data->wanted_bits = RC6_0_NBITS;
+			break;
+		case RC6_MODE_6A:
+			/* This might look weird, but we basically
+			   check the value of the first body bit to
+			   determine the number of bits in mode 6A */
+			if ((!ev.pulse && !geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) ||
+			    geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
+				data->wanted_bits = RC6_6A_LARGE_NBITS;
+			else
+				data->wanted_bits = RC6_6A_SMALL_NBITS;
+			break;
+		default:
+			IR_dprintk(1, "RC6 unknown mode\n");
+			goto out;
+		}
+		goto again;
+
+	case STATE_BODY_BIT_START:
+		if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2))
+			break;
+
+		data->body <<= 1;
+		if (ev.pulse)
+			data->body |= 1;
+		data->count++;
+		data->prev_ev = ev;
+
+		data->state = STATE_BODY_BIT_END;
+		return 0;
+
+	case STATE_BODY_BIT_END:
+		if (!is_transition(&ev, &data->prev_ev))
+			break;
+
+		if (data->count == data->wanted_bits)
+			data->state = STATE_FINISHED;
+		else
+			data->state = STATE_BODY_BIT_START;
+
+		decrease_duration(&ev, RC6_BIT_END);
+		goto again;
+
+	case STATE_FINISHED:
+		if (ev.pulse)
+			break;
+
+		switch (rc6_mode(data)) {
+		case RC6_MODE_0:
+			scancode = data->body & 0xffff;
+			toggle = data->toggle;
+			IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n",
+				   scancode, toggle);
+			break;
+		case RC6_MODE_6A:
+			if (data->wanted_bits == RC6_6A_LARGE_NBITS) {
+				toggle = data->body & RC6_6A_MCE_TOGGLE_MASK ? 1 : 0;
+				scancode = data->body & ~RC6_6A_MCE_TOGGLE_MASK;
+			} else {
+				toggle = 0;
+				scancode = data->body & 0xffffff;
+			}
+
+			IR_dprintk(1, "RC6(6A) scancode 0x%08x (toggle: %u)\n",
+				   scancode, toggle);
+			break;
+		default:
+			IR_dprintk(1, "RC6 unknown mode\n");
+			goto out;
+		}
+
+		ir_keydown(input_dev, scancode, toggle);
+		data->state = STATE_INACTIVE;
+		return 0;
+	}
+
+out:
+	IR_dprintk(1, "RC6 decode failed at state %i (%uus %s)\n",
+		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+	data->state = STATE_INACTIVE;
+	return -EINVAL;
+}
+
+static int ir_rc6_register(struct input_dev *input_dev)
+{
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+	struct decoder_data *data;
+	int rc;
+
+	rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+	if (rc < 0)
+		return rc;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+		return -ENOMEM;
+	}
+
+	data->ir_dev = ir_dev;
+	data->enabled = 1;
+
+	spin_lock(&decoder_lock);
+	list_add_tail(&data->list, &decoder_list);
+	spin_unlock(&decoder_lock);
+
+	return 0;
+}
+
+static int ir_rc6_unregister(struct input_dev *input_dev)
+{
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+	static struct decoder_data *data;
+
+	data = get_decoder_data(ir_dev);
+	if (!data)
+		return 0;
+
+	sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+
+	spin_lock(&decoder_lock);
+	list_del(&data->list);
+	spin_unlock(&decoder_lock);
+
+	return 0;
+}
+
+static struct ir_raw_handler rc6_handler = {
+	.decode		= ir_rc6_decode,
+	.raw_register	= ir_rc6_register,
+	.raw_unregister	= ir_rc6_unregister,
+};
+
+static int __init ir_rc6_decode_init(void)
+{
+	ir_raw_handler_register(&rc6_handler);
+
+	printk(KERN_INFO "IR RC6 protocol handler initialized\n");
+	return 0;
+}
+
+static void __exit ir_rc6_decode_exit(void)
+{
+	ir_raw_handler_unregister(&rc6_handler);
+}
+
+module_init(ir_rc6_decode_init);
+module_exit(ir_rc6_decode_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");
+MODULE_DESCRIPTION("RC6 IR protocol decoder");
diff --git a/drivers/media/IR/ir-sony-decoder.c b/drivers/media/IR/ir-sony-decoder.c
new file mode 100644
index 0000000..9f440c5
--- /dev/null
+++ b/drivers/media/IR/ir-sony-decoder.c
@@ -0,0 +1,312 @@
+/* ir-sony-decoder.c - handle Sony IR Pulse/Space protocol
+ *
+ * Copyright (C) 2010 by David Härdeman <david@hardeman.nu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/bitrev.h>
+#include "ir-core-priv.h"
+
+#define SONY_UNIT		600000 /* ns */
+#define SONY_HEADER_PULSE	(4 * SONY_UNIT)
+#define	SONY_HEADER_SPACE	(1 * SONY_UNIT)
+#define SONY_BIT_0_PULSE	(1 * SONY_UNIT)
+#define SONY_BIT_1_PULSE	(2 * SONY_UNIT)
+#define SONY_BIT_SPACE		(1 * SONY_UNIT)
+#define SONY_TRAILER_SPACE	(10 * SONY_UNIT) /* minimum */
+
+/* Used to register sony_decoder clients */
+static LIST_HEAD(decoder_list);
+static DEFINE_SPINLOCK(decoder_lock);
+
+enum sony_state {
+	STATE_INACTIVE,
+	STATE_HEADER_SPACE,
+	STATE_BIT_PULSE,
+	STATE_BIT_SPACE,
+	STATE_FINISHED,
+};
+
+struct decoder_data {
+	struct list_head	list;
+	struct ir_input_dev	*ir_dev;
+	int			enabled:1;
+
+	/* State machine control */
+	enum sony_state		state;
+	u32			sony_bits;
+	unsigned		count;
+};
+
+
+/**
+ * get_decoder_data()	- gets decoder data
+ * @input_dev:	input device
+ *
+ * Returns the struct decoder_data that corresponds to a device
+ */
+static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
+{
+	struct decoder_data *data = NULL;
+
+	spin_lock(&decoder_lock);
+	list_for_each_entry(data, &decoder_list, list) {
+		if (data->ir_dev == ir_dev)
+			break;
+	}
+	spin_unlock(&decoder_lock);
+	return data;
+}
+
+static ssize_t store_enabled(struct device *d,
+			     struct device_attribute *mattr,
+			     const char *buf,
+			     size_t len)
+{
+	unsigned long value;
+	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
+	struct decoder_data *data = get_decoder_data(ir_dev);
+
+	if (!data)
+		return -EINVAL;
+
+	if (strict_strtoul(buf, 10, &value) || value > 1)
+		return -EINVAL;
+
+	data->enabled = value;
+
+	return len;
+}
+
+static ssize_t show_enabled(struct device *d,
+			     struct device_attribute *mattr, char *buf)
+{
+	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
+	struct decoder_data *data = get_decoder_data(ir_dev);
+
+	if (!data)
+		return -EINVAL;
+
+	if (data->enabled)
+		return sprintf(buf, "1\n");
+	else
+	return sprintf(buf, "0\n");
+}
+
+static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
+
+static struct attribute *decoder_attributes[] = {
+	&dev_attr_enabled.attr,
+	NULL
+};
+
+static struct attribute_group decoder_attribute_group = {
+	.name	= "sony_decoder",
+	.attrs	= decoder_attributes,
+};
+
+/**
+ * ir_sony_decode() - Decode one Sony pulse or space
+ * @input_dev:	the struct input_dev descriptor of the device
+ * @ev:         the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This function returns -EINVAL if the pulse violates the state machine
+ */
+static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+{
+	struct decoder_data *data;
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+	u32 scancode;
+	u8 device, subdevice, function;
+
+	data = get_decoder_data(ir_dev);
+	if (!data)
+		return -EINVAL;
+
+	if (!data->enabled)
+		return 0;
+
+	if (IS_RESET(ev)) {
+		data->state = STATE_INACTIVE;
+		return 0;
+	}
+
+	if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2))
+		goto out;
+
+	IR_dprintk(2, "Sony decode started at state %d (%uus %s)\n",
+		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+
+	switch (data->state) {
+
+	case STATE_INACTIVE:
+		if (!ev.pulse)
+			break;
+
+		if (!eq_margin(ev.duration, SONY_HEADER_PULSE, SONY_UNIT / 2))
+			break;
+
+		data->count = 0;
+		data->state = STATE_HEADER_SPACE;
+		return 0;
+
+	case STATE_HEADER_SPACE:
+		if (ev.pulse)
+			break;
+
+		if (!eq_margin(ev.duration, SONY_HEADER_SPACE, SONY_UNIT / 2))
+			break;
+
+		data->state = STATE_BIT_PULSE;
+		return 0;
+
+	case STATE_BIT_PULSE:
+		if (!ev.pulse)
+			break;
+
+		data->sony_bits <<= 1;
+		if (eq_margin(ev.duration, SONY_BIT_1_PULSE, SONY_UNIT / 2))
+			data->sony_bits |= 1;
+		else if (!eq_margin(ev.duration, SONY_BIT_0_PULSE, SONY_UNIT / 2))
+			break;
+
+		data->count++;
+		data->state = STATE_BIT_SPACE;
+		return 0;
+
+	case STATE_BIT_SPACE:
+		if (ev.pulse)
+			break;
+
+		if (!geq_margin(ev.duration, SONY_BIT_SPACE, SONY_UNIT / 2))
+			break;
+
+		decrease_duration(&ev, SONY_BIT_SPACE);
+
+		if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2)) {
+			data->state = STATE_BIT_PULSE;
+			return 0;
+		}
+
+		data->state = STATE_FINISHED;
+		/* Fall through */
+
+	case STATE_FINISHED:
+		if (ev.pulse)
+			break;
+
+		if (!geq_margin(ev.duration, SONY_TRAILER_SPACE, SONY_UNIT / 2))
+			break;
+
+		switch (data->count) {
+		case 12:
+			device    = bitrev8((data->sony_bits <<  3) & 0xF8);
+			subdevice = 0;
+			function  = bitrev8((data->sony_bits >>  4) & 0xFE);
+			break;
+		case 15:
+			device    = bitrev8((data->sony_bits >>  0) & 0xFF);
+			subdevice = 0;
+			function  = bitrev8((data->sony_bits >>  7) & 0xFD);
+			break;
+		case 20:
+			device    = bitrev8((data->sony_bits >>  5) & 0xF8);
+			subdevice = bitrev8((data->sony_bits >>  0) & 0xFF);
+			function  = bitrev8((data->sony_bits >> 12) & 0xFE);
+			break;
+		default:
+			IR_dprintk(1, "Sony invalid bitcount %u\n", data->count);
+			goto out;
+		}
+
+		scancode = device << 16 | subdevice << 8 | function;
+		IR_dprintk(1, "Sony(%u) scancode 0x%05x\n", data->count, scancode);
+		ir_keydown(input_dev, scancode, 0);
+		data->state = STATE_INACTIVE;
+		return 0;
+	}
+
+out:
+	IR_dprintk(1, "Sony decode failed at state %d (%uus %s)\n",
+		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+	data->state = STATE_INACTIVE;
+	return -EINVAL;
+}
+
+static int ir_sony_register(struct input_dev *input_dev)
+{
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+	struct decoder_data *data;
+	int rc;
+
+	rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+	if (rc < 0)
+		return rc;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+		return -ENOMEM;
+	}
+
+	data->ir_dev = ir_dev;
+	data->enabled = 1;
+
+	spin_lock(&decoder_lock);
+	list_add_tail(&data->list, &decoder_list);
+	spin_unlock(&decoder_lock);
+
+	return 0;
+}
+
+static int ir_sony_unregister(struct input_dev *input_dev)
+{
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+	static struct decoder_data *data;
+
+	data = get_decoder_data(ir_dev);
+	if (!data)
+		return 0;
+
+	sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+
+	spin_lock(&decoder_lock);
+	list_del(&data->list);
+	spin_unlock(&decoder_lock);
+
+	return 0;
+}
+
+static struct ir_raw_handler sony_handler = {
+	.decode		= ir_sony_decode,
+	.raw_register	= ir_sony_register,
+	.raw_unregister	= ir_sony_unregister,
+};
+
+static int __init ir_sony_decode_init(void)
+{
+	ir_raw_handler_register(&sony_handler);
+
+	printk(KERN_INFO "IR Sony protocol handler initialized\n");
+	return 0;
+}
+
+static void __exit ir_sony_decode_exit(void)
+{
+	ir_raw_handler_unregister(&sony_handler);
+}
+
+module_init(ir_sony_decode_init);
+module_exit(ir_sony_decode_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");
+MODULE_DESCRIPTION("Sony IR protocol decoder");
diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c
index e14e6c48..d7da63e 100644
--- a/drivers/media/IR/ir-sysfs.c
+++ b/drivers/media/IR/ir-sysfs.c
@@ -1,6 +1,6 @@
-/* ir-register.c - handle IR scancode->keycode tables
+/* ir-sysfs.c - sysfs interface for RC devices (/sys/class/rc)
  *
- * Copyright (C) 2009 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2009-2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
  *
  * This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -15,15 +15,23 @@
 #include <linux/slab.h>
 #include <linux/input.h>
 #include <linux/device.h>
-#include <media/ir-core.h>
+#include "ir-core-priv.h"
 
 #define IRRCV_NUM_DEVICES	256
 
 /* bit array to represent IR sysfs device number */
 static unsigned long ir_core_dev_number;
 
-/* class for /sys/class/irrcv */
-static struct class *ir_input_class;
+/* class for /sys/class/rc */
+static char *ir_devnode(struct device *dev, mode_t *mode)
+{
+	return kasprintf(GFP_KERNEL, "rc/%s", dev_name(dev));
+}
+
+static struct class ir_input_class = {
+	.name		= "rc",
+	.devnode	= ir_devnode,
+};
 
 /**
  * show_protocol() - shows the current IR protocol
@@ -32,7 +40,7 @@
  * @buf:	a pointer to the output buffer
  *
  * This routine is a callback routine for input read the IR protocol type.
- * it is trigged by reading /sys/class/irrcv/irrcv?/current_protocol.
+ * it is trigged by reading /sys/class/rc/rc?/current_protocol.
  * It returns the protocol name, as understood by the driver.
  */
 static ssize_t show_protocol(struct device *d,
@@ -48,13 +56,17 @@
 	if (ir_type == IR_TYPE_UNKNOWN)
 		s = "Unknown";
 	else if (ir_type == IR_TYPE_RC5)
-		s = "RC-5";
-	else if (ir_type == IR_TYPE_PD)
-		s = "Pulse/distance";
+		s = "rc-5";
 	else if (ir_type == IR_TYPE_NEC)
-		s = "NEC";
+		s = "nec";
+	else if (ir_type == IR_TYPE_RC6)
+		s = "rc6";
+	else if (ir_type == IR_TYPE_JVC)
+		s = "jvc";
+	else if (ir_type == IR_TYPE_SONY)
+		s = "sony";
 	else
-		s = "Other";
+		s = "other";
 
 	return sprintf(buf, "%s\n", s);
 }
@@ -67,7 +79,7 @@
  * @len:	length of the input buffer
  *
  * This routine is a callback routine for changing the IR protocol type.
- * it is trigged by reading /sys/class/irrcv/irrcv?/current_protocol.
+ * it is trigged by reading /sys/class/rc/rc?/current_protocol.
  * It changes the IR the protocol name, if the IR type is recognized
  * by the driver.
  * If an unknown protocol name is used, returns -EINVAL.
@@ -78,23 +90,24 @@
 			      size_t len)
 {
 	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-	u64 ir_type = IR_TYPE_UNKNOWN;
+	u64 ir_type = 0;
 	int rc = -EINVAL;
 	unsigned long flags;
 	char *buf;
 
-	buf = strsep((char **) &data, "\n");
+	while ((buf = strsep((char **) &data, " \n")) != NULL) {
+		if (!strcasecmp(buf, "rc-5") || !strcasecmp(buf, "rc5"))
+			ir_type |= IR_TYPE_RC5;
+		if (!strcasecmp(buf, "nec"))
+			ir_type |= IR_TYPE_NEC;
+		if (!strcasecmp(buf, "jvc"))
+			ir_type |= IR_TYPE_JVC;
+		if (!strcasecmp(buf, "sony"))
+			ir_type |= IR_TYPE_SONY;
+	}
 
-	if (!strcasecmp(buf, "rc-5"))
-		ir_type = IR_TYPE_RC5;
-	else if (!strcasecmp(buf, "pd"))
-		ir_type = IR_TYPE_PD;
-	else if (!strcasecmp(buf, "nec"))
-		ir_type = IR_TYPE_NEC;
-
-	if (ir_type == IR_TYPE_UNKNOWN) {
-		IR_dprintk(1, "Error setting protocol to %lld\n",
-			   (long long)ir_type);
+	if (!ir_type) {
+		IR_dprintk(1, "Unknown protocol\n");
 		return -EINVAL;
 	}
 
@@ -112,25 +125,87 @@
 	ir_dev->rc_tab.ir_type = ir_type;
 	spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags);
 
-	IR_dprintk(1, "Current protocol is %lld\n",
+	IR_dprintk(1, "Current protocol(s) is(are) %lld\n",
 		   (long long)ir_type);
 
 	return len;
 }
 
+static ssize_t show_supported_protocols(struct device *d,
+			     struct device_attribute *mattr, char *buf)
+{
+	char *orgbuf = buf;
+	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
+
+	/* FIXME: doesn't support multiple protocols at the same time */
+	if (ir_dev->props->allowed_protos == IR_TYPE_UNKNOWN)
+		buf += sprintf(buf, "unknown ");
+	if (ir_dev->props->allowed_protos & IR_TYPE_RC5)
+		buf += sprintf(buf, "rc-5 ");
+	if (ir_dev->props->allowed_protos & IR_TYPE_NEC)
+		buf += sprintf(buf, "nec ");
+	if (buf == orgbuf)
+		buf += sprintf(buf, "other ");
+
+	buf += sprintf(buf - 1, "\n");
+
+	return buf - orgbuf;
+}
+
+#define ADD_HOTPLUG_VAR(fmt, val...)					\
+	do {								\
+		int err = add_uevent_var(env, fmt, val);		\
+		if (err)						\
+			return err;					\
+	} while (0)
+
+static int ir_dev_uevent(struct device *device, struct kobj_uevent_env *env)
+{
+	struct ir_input_dev *ir_dev = dev_get_drvdata(device);
+
+	if (ir_dev->rc_tab.name)
+		ADD_HOTPLUG_VAR("NAME=%s", ir_dev->rc_tab.name);
+	if (ir_dev->driver_name)
+		ADD_HOTPLUG_VAR("DRV_NAME=%s", ir_dev->driver_name);
+
+	return 0;
+}
+
 /*
  * Static device attribute struct with the sysfs attributes for IR's
  */
-static DEVICE_ATTR(current_protocol, S_IRUGO | S_IWUSR,
+static DEVICE_ATTR(protocol, S_IRUGO | S_IWUSR,
 		   show_protocol, store_protocol);
 
-static struct attribute *ir_dev_attrs[] = {
-	&dev_attr_current_protocol.attr,
+static DEVICE_ATTR(supported_protocols, S_IRUGO | S_IWUSR,
+		   show_supported_protocols, NULL);
+
+static struct attribute *ir_hw_dev_attrs[] = {
+	&dev_attr_protocol.attr,
+	&dev_attr_supported_protocols.attr,
 	NULL,
 };
 
+static struct attribute_group ir_hw_dev_attr_grp = {
+	.attrs	= ir_hw_dev_attrs,
+};
+
+static const struct attribute_group *ir_hw_dev_attr_groups[] = {
+	&ir_hw_dev_attr_grp,
+	NULL
+};
+
+static struct device_type rc_dev_type = {
+	.groups		= ir_hw_dev_attr_groups,
+	.uevent		= ir_dev_uevent,
+};
+
+static struct device_type ir_raw_dev_type = {
+	.uevent		= ir_dev_uevent,
+};
+
 /**
- * ir_register_class() - creates the sysfs for /sys/class/irrcv/irrcv?
+ * ir_register_class() - creates the sysfs for /sys/class/rc/rc?
  * @input_dev:	the struct input_dev descriptor of the device
  *
  * This routine is used to register the syfs code for IR class
@@ -138,8 +213,7 @@
 int ir_register_class(struct input_dev *input_dev)
 {
 	int rc;
-	struct kobject *kobj;
-
+	const char *path;
 	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
 	int devno = find_first_zero_bit(&ir_core_dev_number,
 					IRRCV_NUM_DEVICES);
@@ -147,19 +221,36 @@
 	if (unlikely(devno < 0))
 		return devno;
 
-	ir_dev->attr.attrs = ir_dev_attrs;
-	ir_dev->class_dev = device_create(ir_input_class, NULL,
-					  input_dev->dev.devt, ir_dev,
-					  "irrcv%d", devno);
-	kobj = &ir_dev->class_dev->kobj;
+	if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
+		ir_dev->dev.type = &rc_dev_type;
+	else
+		ir_dev->dev.type = &ir_raw_dev_type;
 
-	printk(KERN_WARNING "Creating IR device %s\n", kobject_name(kobj));
-	rc = sysfs_create_group(kobj, &ir_dev->attr);
-	if (unlikely(rc < 0)) {
-		device_destroy(ir_input_class, input_dev->dev.devt);
-		return -ENOMEM;
+	ir_dev->dev.class = &ir_input_class;
+	ir_dev->dev.parent = input_dev->dev.parent;
+	dev_set_name(&ir_dev->dev, "rc%d", devno);
+	dev_set_drvdata(&ir_dev->dev, ir_dev);
+	rc = device_register(&ir_dev->dev);
+	if (rc)
+		return rc;
+
+
+	input_dev->dev.parent = &ir_dev->dev;
+	rc = input_register_device(input_dev);
+	if (rc < 0) {
+		device_del(&ir_dev->dev);
+		return rc;
 	}
 
+	__module_get(THIS_MODULE);
+
+	path = kobject_get_path(&ir_dev->dev.kobj, GFP_KERNEL);
+	printk(KERN_INFO "%s: %s as %s\n",
+		dev_name(&ir_dev->dev),
+		input_dev->name ? input_dev->name : "Unspecified device",
+		path ? path : "N/A");
+	kfree(path);
+
 	ir_dev->devno = devno;
 	set_bit(devno, &ir_core_dev_number);
 
@@ -168,7 +259,7 @@
 
 /**
  * ir_unregister_class() - removes the sysfs for sysfs for
- *			   /sys/class/irrcv/irrcv?
+ *			   /sys/class/rc/rc?
  * @input_dev:	the struct input_dev descriptor of the device
  *
  * This routine is used to unregister the syfs code for IR class
@@ -176,36 +267,35 @@
 void ir_unregister_class(struct input_dev *input_dev)
 {
 	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-	struct kobject *kobj;
 
 	clear_bit(ir_dev->devno, &ir_core_dev_number);
+	input_unregister_device(input_dev);
+	device_del(&ir_dev->dev);
 
-	kobj = &ir_dev->class_dev->kobj;
-
-	sysfs_remove_group(kobj, &ir_dev->attr);
-	device_destroy(ir_input_class, input_dev->dev.devt);
-
-	kfree(ir_dev->attr.name);
+	module_put(THIS_MODULE);
 }
 
 /*
- * Init/exit code for the module. Basically, creates/removes /sys/class/irrcv
+ * Init/exit code for the module. Basically, creates/removes /sys/class/rc
  */
 
 static int __init ir_core_init(void)
 {
-	ir_input_class = class_create(THIS_MODULE, "irrcv");
-	if (IS_ERR(ir_input_class)) {
-		printk(KERN_ERR "ir_core: unable to register irrcv class\n");
-		return PTR_ERR(ir_input_class);
+	int rc = class_register(&ir_input_class);
+	if (rc) {
+		printk(KERN_ERR "ir_core: unable to register rc class\n");
+		return rc;
 	}
 
+	/* Initialize/load the decoders/keymap code that will be used */
+	ir_raw_init();
+
 	return 0;
 }
 
 static void __exit ir_core_exit(void)
 {
-	class_destroy(ir_input_class);
+	class_unregister(&ir_input_class);
 }
 
 module_init(ir_core_init);
diff --git a/drivers/media/IR/keymaps/Kconfig b/drivers/media/IR/keymaps/Kconfig
new file mode 100644
index 0000000..14b22f5
--- /dev/null
+++ b/drivers/media/IR/keymaps/Kconfig
@@ -0,0 +1,15 @@
+config RC_MAP
+	tristate "Compile Remote Controller keymap modules"
+	depends on IR_CORE
+	default y
+
+	---help---
+	   This option enables the compilation of lots of Remote
+	   Controller tables. They are short tables, but if you
+	   don't use a remote controller, or prefer to load the
+	   tables on userspace, you should disable it.
+
+	   The ir-keytable program, available at v4l-utils package
+	   provide the tool and the same RC maps for load from
+	   userspace. Its available at
+			http://git.linuxtv.org/v4l-utils
diff --git a/drivers/media/IR/keymaps/Makefile b/drivers/media/IR/keymaps/Makefile
new file mode 100644
index 0000000..ec25258
--- /dev/null
+++ b/drivers/media/IR/keymaps/Makefile
@@ -0,0 +1,67 @@
+obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
+			rc-apac-viewcomp.o \
+			rc-asus-pc39.o \
+			rc-ati-tv-wonder-hd-600.o \
+			rc-avermedia-a16d.o \
+			rc-avermedia.o \
+			rc-avermedia-cardbus.o \
+			rc-avermedia-dvbt.o \
+			rc-avermedia-m135a-rm-jx.o \
+			rc-avertv-303.o \
+			rc-behold.o \
+			rc-behold-columbus.o \
+			rc-budget-ci-old.o \
+			rc-cinergy-1400.o \
+			rc-cinergy.o \
+			rc-dm1105-nec.o \
+			rc-dntv-live-dvb-t.o \
+			rc-dntv-live-dvbt-pro.o \
+			rc-empty.o \
+			rc-em-terratec.o \
+			rc-encore-enltv2.o \
+			rc-encore-enltv.o \
+			rc-encore-enltv-fm53.o \
+			rc-evga-indtube.o \
+			rc-eztv.o \
+			rc-flydvb.o \
+			rc-flyvideo.o \
+			rc-fusionhdtv-mce.o \
+			rc-gadmei-rm008z.o \
+			rc-genius-tvgo-a11mce.o \
+			rc-gotview7135.o \
+			rc-hauppauge-new.o \
+			rc-imon-mce.o \
+			rc-imon-pad.o \
+			rc-iodata-bctv7e.o \
+			rc-kaiomy.o \
+			rc-kworld-315u.o \
+			rc-kworld-plus-tv-analog.o \
+			rc-manli.o \
+			rc-msi-tvanywhere.o \
+			rc-msi-tvanywhere-plus.o \
+			rc-nebula.o \
+			rc-nec-terratec-cinergy-xs.o \
+			rc-norwood.o \
+			rc-npgtech.o \
+			rc-pctv-sedna.o \
+			rc-pinnacle-color.o \
+			rc-pinnacle-grey.o \
+			rc-pinnacle-pctv-hd.o \
+			rc-pixelview.o \
+			rc-pixelview-mk12.o \
+			rc-pixelview-new.o \
+			rc-powercolor-real-angel.o \
+			rc-proteus-2309.o \
+			rc-purpletv.o \
+			rc-pv951.o \
+			rc-rc5-hauppauge-new.o \
+			rc-rc5-tv.o \
+			rc-real-audio-220-32-keys.o \
+			rc-tbs-nec.o \
+			rc-terratec-cinergy-xs.o \
+			rc-tevii-nec.o \
+			rc-tt-1500.o \
+			rc-videomate-s350.o \
+			rc-videomate-tv-pvr.o \
+			rc-winfast.o \
+			rc-winfast-usbii-deluxe.o
diff --git a/drivers/media/IR/keymaps/rc-adstech-dvb-t-pci.c b/drivers/media/IR/keymaps/rc-adstech-dvb-t-pci.c
new file mode 100644
index 0000000..b172831
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-adstech-dvb-t-pci.c
@@ -0,0 +1,89 @@
+/* adstech-dvb-t-pci.h - Keytable for adstech_dvb_t_pci Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* ADS Tech Instant TV DVB-T PCI Remote */
+
+static struct ir_scancode adstech_dvb_t_pci[] = {
+	/* Keys 0 to 9 */
+	{ 0x4d, KEY_0 },
+	{ 0x57, KEY_1 },
+	{ 0x4f, KEY_2 },
+	{ 0x53, KEY_3 },
+	{ 0x56, KEY_4 },
+	{ 0x4e, KEY_5 },
+	{ 0x5e, KEY_6 },
+	{ 0x54, KEY_7 },
+	{ 0x4c, KEY_8 },
+	{ 0x5c, KEY_9 },
+
+	{ 0x5b, KEY_POWER },
+	{ 0x5f, KEY_MUTE },
+	{ 0x55, KEY_GOTO },
+	{ 0x5d, KEY_SEARCH },
+	{ 0x17, KEY_EPG },		/* Guide */
+	{ 0x1f, KEY_MENU },
+	{ 0x0f, KEY_UP },
+	{ 0x46, KEY_DOWN },
+	{ 0x16, KEY_LEFT },
+	{ 0x1e, KEY_RIGHT },
+	{ 0x0e, KEY_SELECT },		/* Enter */
+	{ 0x5a, KEY_INFO },
+	{ 0x52, KEY_EXIT },
+	{ 0x59, KEY_PREVIOUS },
+	{ 0x51, KEY_NEXT },
+	{ 0x58, KEY_REWIND },
+	{ 0x50, KEY_FORWARD },
+	{ 0x44, KEY_PLAYPAUSE },
+	{ 0x07, KEY_STOP },
+	{ 0x1b, KEY_RECORD },
+	{ 0x13, KEY_TUNER },		/* Live */
+	{ 0x0a, KEY_A },
+	{ 0x12, KEY_B },
+	{ 0x03, KEY_PROG1 },		/* 1 */
+	{ 0x01, KEY_PROG2 },		/* 2 */
+	{ 0x00, KEY_PROG3 },		/* 3 */
+	{ 0x06, KEY_DVD },
+	{ 0x48, KEY_AUX },		/* Photo */
+	{ 0x40, KEY_VIDEO },
+	{ 0x19, KEY_AUDIO },		/* Music */
+	{ 0x0b, KEY_CHANNELUP },
+	{ 0x08, KEY_CHANNELDOWN },
+	{ 0x15, KEY_VOLUMEUP },
+	{ 0x1c, KEY_VOLUMEDOWN },
+};
+
+static struct rc_keymap adstech_dvb_t_pci_map = {
+	.map = {
+		.scan    = adstech_dvb_t_pci,
+		.size    = ARRAY_SIZE(adstech_dvb_t_pci),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_ADSTECH_DVB_T_PCI,
+	}
+};
+
+static int __init init_rc_map_adstech_dvb_t_pci(void)
+{
+	return ir_register_map(&adstech_dvb_t_pci_map);
+}
+
+static void __exit exit_rc_map_adstech_dvb_t_pci(void)
+{
+	ir_unregister_map(&adstech_dvb_t_pci_map);
+}
+
+module_init(init_rc_map_adstech_dvb_t_pci)
+module_exit(exit_rc_map_adstech_dvb_t_pci)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-apac-viewcomp.c b/drivers/media/IR/keymaps/rc-apac-viewcomp.c
new file mode 100644
index 0000000..0ef2b56
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-apac-viewcomp.c
@@ -0,0 +1,80 @@
+/* apac-viewcomp.h - Keytable for apac_viewcomp Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Attila Kondoros <attila.kondoros@chello.hu> */
+
+static struct ir_scancode apac_viewcomp[] = {
+
+	{ 0x01, KEY_1 },
+	{ 0x02, KEY_2 },
+	{ 0x03, KEY_3 },
+	{ 0x04, KEY_4 },
+	{ 0x05, KEY_5 },
+	{ 0x06, KEY_6 },
+	{ 0x07, KEY_7 },
+	{ 0x08, KEY_8 },
+	{ 0x09, KEY_9 },
+	{ 0x00, KEY_0 },
+	{ 0x17, KEY_LAST },		/* +100 */
+	{ 0x0a, KEY_LIST },		/* recall */
+
+
+	{ 0x1c, KEY_TUNER },		/* TV/FM */
+	{ 0x15, KEY_SEARCH },		/* scan */
+	{ 0x12, KEY_POWER },		/* power */
+	{ 0x1f, KEY_VOLUMEDOWN },	/* vol up */
+	{ 0x1b, KEY_VOLUMEUP },		/* vol down */
+	{ 0x1e, KEY_CHANNELDOWN },	/* chn up */
+	{ 0x1a, KEY_CHANNELUP },	/* chn down */
+
+	{ 0x11, KEY_VIDEO },		/* video */
+	{ 0x0f, KEY_ZOOM },		/* full screen */
+	{ 0x13, KEY_MUTE },		/* mute/unmute */
+	{ 0x10, KEY_TEXT },		/* min */
+
+	{ 0x0d, KEY_STOP },		/* freeze */
+	{ 0x0e, KEY_RECORD },		/* record */
+	{ 0x1d, KEY_PLAYPAUSE },	/* stop */
+	{ 0x19, KEY_PLAY },		/* play */
+
+	{ 0x16, KEY_GOTO },		/* osd */
+	{ 0x14, KEY_REFRESH },		/* default */
+	{ 0x0c, KEY_KPPLUS },		/* fine tune >>>> */
+	{ 0x18, KEY_KPMINUS },		/* fine tune <<<< */
+};
+
+static struct rc_keymap apac_viewcomp_map = {
+	.map = {
+		.scan    = apac_viewcomp,
+		.size    = ARRAY_SIZE(apac_viewcomp),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_APAC_VIEWCOMP,
+	}
+};
+
+static int __init init_rc_map_apac_viewcomp(void)
+{
+	return ir_register_map(&apac_viewcomp_map);
+}
+
+static void __exit exit_rc_map_apac_viewcomp(void)
+{
+	ir_unregister_map(&apac_viewcomp_map);
+}
+
+module_init(init_rc_map_apac_viewcomp)
+module_exit(exit_rc_map_apac_viewcomp)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-asus-pc39.c b/drivers/media/IR/keymaps/rc-asus-pc39.c
new file mode 100644
index 0000000..2aa068c
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-asus-pc39.c
@@ -0,0 +1,91 @@
+/* asus-pc39.h - Keytable for asus_pc39 Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/*
+ * Marc Fargas <telenieko@telenieko.com>
+ * this is the remote control that comes with the asus p7131
+ * which has a label saying is "Model PC-39"
+ */
+
+static struct ir_scancode asus_pc39[] = {
+	/* Keys 0 to 9 */
+	{ 0x15, KEY_0 },
+	{ 0x29, KEY_1 },
+	{ 0x2d, KEY_2 },
+	{ 0x2b, KEY_3 },
+	{ 0x09, KEY_4 },
+	{ 0x0d, KEY_5 },
+	{ 0x0b, KEY_6 },
+	{ 0x31, KEY_7 },
+	{ 0x35, KEY_8 },
+	{ 0x33, KEY_9 },
+
+	{ 0x3e, KEY_RADIO },		/* radio */
+	{ 0x03, KEY_MENU },		/* dvd/menu */
+	{ 0x2a, KEY_VOLUMEUP },
+	{ 0x19, KEY_VOLUMEDOWN },
+	{ 0x37, KEY_UP },
+	{ 0x3b, KEY_DOWN },
+	{ 0x27, KEY_LEFT },
+	{ 0x2f, KEY_RIGHT },
+	{ 0x25, KEY_VIDEO },		/* video */
+	{ 0x39, KEY_AUDIO },		/* music */
+
+	{ 0x21, KEY_TV },		/* tv */
+	{ 0x1d, KEY_EXIT },		/* back */
+	{ 0x0a, KEY_CHANNELUP },	/* channel / program + */
+	{ 0x1b, KEY_CHANNELDOWN },	/* channel / program - */
+	{ 0x1a, KEY_ENTER },		/* enter */
+
+	{ 0x06, KEY_PAUSE },		/* play/pause */
+	{ 0x1e, KEY_PREVIOUS },		/* rew */
+	{ 0x26, KEY_NEXT },		/* forward */
+	{ 0x0e, KEY_REWIND },		/* backward << */
+	{ 0x3a, KEY_FASTFORWARD },	/* forward >> */
+	{ 0x36, KEY_STOP },
+	{ 0x2e, KEY_RECORD },		/* recording */
+	{ 0x16, KEY_POWER },		/* the button that reads "close" */
+
+	{ 0x11, KEY_ZOOM },		/* full screen */
+	{ 0x13, KEY_MACRO },		/* recall */
+	{ 0x23, KEY_HOME },		/* home */
+	{ 0x05, KEY_PVR },		/* picture */
+	{ 0x3d, KEY_MUTE },		/* mute */
+	{ 0x01, KEY_DVD },		/* dvd */
+};
+
+static struct rc_keymap asus_pc39_map = {
+	.map = {
+		.scan    = asus_pc39,
+		.size    = ARRAY_SIZE(asus_pc39),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_ASUS_PC39,
+	}
+};
+
+static int __init init_rc_map_asus_pc39(void)
+{
+	return ir_register_map(&asus_pc39_map);
+}
+
+static void __exit exit_rc_map_asus_pc39(void)
+{
+	ir_unregister_map(&asus_pc39_map);
+}
+
+module_init(init_rc_map_asus_pc39)
+module_exit(exit_rc_map_asus_pc39)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-ati-tv-wonder-hd-600.c b/drivers/media/IR/keymaps/rc-ati-tv-wonder-hd-600.c
new file mode 100644
index 0000000..8edfd29
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-ati-tv-wonder-hd-600.c
@@ -0,0 +1,69 @@
+/* ati-tv-wonder-hd-600.h - Keytable for ati_tv_wonder_hd_600 Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* ATI TV Wonder HD 600 USB
+   Devin Heitmueller <devin.heitmueller@gmail.com>
+ */
+
+static struct ir_scancode ati_tv_wonder_hd_600[] = {
+	{ 0x00, KEY_RECORD},		/* Row 1 */
+	{ 0x01, KEY_PLAYPAUSE},
+	{ 0x02, KEY_STOP},
+	{ 0x03, KEY_POWER},
+	{ 0x04, KEY_PREVIOUS},	/* Row 2 */
+	{ 0x05, KEY_REWIND},
+	{ 0x06, KEY_FORWARD},
+	{ 0x07, KEY_NEXT},
+	{ 0x08, KEY_EPG},		/* Row 3 */
+	{ 0x09, KEY_HOME},
+	{ 0x0a, KEY_MENU},
+	{ 0x0b, KEY_CHANNELUP},
+	{ 0x0c, KEY_BACK},		/* Row 4 */
+	{ 0x0d, KEY_UP},
+	{ 0x0e, KEY_INFO},
+	{ 0x0f, KEY_CHANNELDOWN},
+	{ 0x10, KEY_LEFT},		/* Row 5 */
+	{ 0x11, KEY_SELECT},
+	{ 0x12, KEY_RIGHT},
+	{ 0x13, KEY_VOLUMEUP},
+	{ 0x14, KEY_LAST},		/* Row 6 */
+	{ 0x15, KEY_DOWN},
+	{ 0x16, KEY_MUTE},
+	{ 0x17, KEY_VOLUMEDOWN},
+};
+
+static struct rc_keymap ati_tv_wonder_hd_600_map = {
+	.map = {
+		.scan    = ati_tv_wonder_hd_600,
+		.size    = ARRAY_SIZE(ati_tv_wonder_hd_600),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_ATI_TV_WONDER_HD_600,
+	}
+};
+
+static int __init init_rc_map_ati_tv_wonder_hd_600(void)
+{
+	return ir_register_map(&ati_tv_wonder_hd_600_map);
+}
+
+static void __exit exit_rc_map_ati_tv_wonder_hd_600(void)
+{
+	ir_unregister_map(&ati_tv_wonder_hd_600_map);
+}
+
+module_init(init_rc_map_ati_tv_wonder_hd_600)
+module_exit(exit_rc_map_ati_tv_wonder_hd_600)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-avermedia-a16d.c b/drivers/media/IR/keymaps/rc-avermedia-a16d.c
new file mode 100644
index 0000000..12f0435
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-avermedia-a16d.c
@@ -0,0 +1,75 @@
+/* avermedia-a16d.h - Keytable for avermedia_a16d Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode avermedia_a16d[] = {
+	{ 0x20, KEY_LIST},
+	{ 0x00, KEY_POWER},
+	{ 0x28, KEY_1},
+	{ 0x18, KEY_2},
+	{ 0x38, KEY_3},
+	{ 0x24, KEY_4},
+	{ 0x14, KEY_5},
+	{ 0x34, KEY_6},
+	{ 0x2c, KEY_7},
+	{ 0x1c, KEY_8},
+	{ 0x3c, KEY_9},
+	{ 0x12, KEY_SUBTITLE},
+	{ 0x22, KEY_0},
+	{ 0x32, KEY_REWIND},
+	{ 0x3a, KEY_SHUFFLE},
+	{ 0x02, KEY_PRINT},
+	{ 0x11, KEY_CHANNELDOWN},
+	{ 0x31, KEY_CHANNELUP},
+	{ 0x0c, KEY_ZOOM},
+	{ 0x1e, KEY_VOLUMEDOWN},
+	{ 0x3e, KEY_VOLUMEUP},
+	{ 0x0a, KEY_MUTE},
+	{ 0x04, KEY_AUDIO},
+	{ 0x26, KEY_RECORD},
+	{ 0x06, KEY_PLAY},
+	{ 0x36, KEY_STOP},
+	{ 0x16, KEY_PAUSE},
+	{ 0x2e, KEY_REWIND},
+	{ 0x0e, KEY_FASTFORWARD},
+	{ 0x30, KEY_TEXT},
+	{ 0x21, KEY_GREEN},
+	{ 0x01, KEY_BLUE},
+	{ 0x08, KEY_EPG},
+	{ 0x2a, KEY_MENU},
+};
+
+static struct rc_keymap avermedia_a16d_map = {
+	.map = {
+		.scan    = avermedia_a16d,
+		.size    = ARRAY_SIZE(avermedia_a16d),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_AVERMEDIA_A16D,
+	}
+};
+
+static int __init init_rc_map_avermedia_a16d(void)
+{
+	return ir_register_map(&avermedia_a16d_map);
+}
+
+static void __exit exit_rc_map_avermedia_a16d(void)
+{
+	ir_unregister_map(&avermedia_a16d_map);
+}
+
+module_init(init_rc_map_avermedia_a16d)
+module_exit(exit_rc_map_avermedia_a16d)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-avermedia-cardbus.c b/drivers/media/IR/keymaps/rc-avermedia-cardbus.c
new file mode 100644
index 0000000..2a945b0
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-avermedia-cardbus.c
@@ -0,0 +1,97 @@
+/* avermedia-cardbus.h - Keytable for avermedia_cardbus Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Oldrich Jedlicka <oldium.pro@seznam.cz> */
+
+static struct ir_scancode avermedia_cardbus[] = {
+	{ 0x00, KEY_POWER },
+	{ 0x01, KEY_TUNER },		/* TV/FM */
+	{ 0x03, KEY_TEXT },		/* Teletext */
+	{ 0x04, KEY_EPG },
+	{ 0x05, KEY_1 },
+	{ 0x06, KEY_2 },
+	{ 0x07, KEY_3 },
+	{ 0x08, KEY_AUDIO },
+	{ 0x09, KEY_4 },
+	{ 0x0a, KEY_5 },
+	{ 0x0b, KEY_6 },
+	{ 0x0c, KEY_ZOOM },		/* Full screen */
+	{ 0x0d, KEY_7 },
+	{ 0x0e, KEY_8 },
+	{ 0x0f, KEY_9 },
+	{ 0x10, KEY_PAGEUP },		/* 16-CH PREV */
+	{ 0x11, KEY_0 },
+	{ 0x12, KEY_INFO },
+	{ 0x13, KEY_AGAIN },		/* CH RTN - channel return */
+	{ 0x14, KEY_MUTE },
+	{ 0x15, KEY_EDIT },		/* Autoscan */
+	{ 0x17, KEY_SAVE },		/* Screenshot */
+	{ 0x18, KEY_PLAYPAUSE },
+	{ 0x19, KEY_RECORD },
+	{ 0x1a, KEY_PLAY },
+	{ 0x1b, KEY_STOP },
+	{ 0x1c, KEY_FASTFORWARD },
+	{ 0x1d, KEY_REWIND },
+	{ 0x1e, KEY_VOLUMEDOWN },
+	{ 0x1f, KEY_VOLUMEUP },
+	{ 0x22, KEY_SLEEP },		/* Sleep */
+	{ 0x23, KEY_ZOOM },		/* Aspect */
+	{ 0x26, KEY_SCREEN },		/* Pos */
+	{ 0x27, KEY_ANGLE },		/* Size */
+	{ 0x28, KEY_SELECT },		/* Select */
+	{ 0x29, KEY_BLUE },		/* Blue/Picture */
+	{ 0x2a, KEY_BACKSPACE },	/* Back */
+	{ 0x2b, KEY_MEDIA },		/* PIP (Picture-in-picture) */
+	{ 0x2c, KEY_DOWN },
+	{ 0x2e, KEY_DOT },
+	{ 0x2f, KEY_TV },		/* Live TV */
+	{ 0x32, KEY_LEFT },
+	{ 0x33, KEY_CLEAR },		/* Clear */
+	{ 0x35, KEY_RED },		/* Red/TV */
+	{ 0x36, KEY_UP },
+	{ 0x37, KEY_HOME },		/* Home */
+	{ 0x39, KEY_GREEN },		/* Green/Video */
+	{ 0x3d, KEY_YELLOW },		/* Yellow/Music */
+	{ 0x3e, KEY_OK },		/* Ok */
+	{ 0x3f, KEY_RIGHT },
+	{ 0x40, KEY_NEXT },		/* Next */
+	{ 0x41, KEY_PREVIOUS },		/* Previous */
+	{ 0x42, KEY_CHANNELDOWN },	/* Channel down */
+	{ 0x43, KEY_CHANNELUP },	/* Channel up */
+};
+
+static struct rc_keymap avermedia_cardbus_map = {
+	.map = {
+		.scan    = avermedia_cardbus,
+		.size    = ARRAY_SIZE(avermedia_cardbus),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_AVERMEDIA_CARDBUS,
+	}
+};
+
+static int __init init_rc_map_avermedia_cardbus(void)
+{
+	return ir_register_map(&avermedia_cardbus_map);
+}
+
+static void __exit exit_rc_map_avermedia_cardbus(void)
+{
+	ir_unregister_map(&avermedia_cardbus_map);
+}
+
+module_init(init_rc_map_avermedia_cardbus)
+module_exit(exit_rc_map_avermedia_cardbus)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-avermedia-dvbt.c b/drivers/media/IR/keymaps/rc-avermedia-dvbt.c
new file mode 100644
index 0000000..39dde62
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-avermedia-dvbt.c
@@ -0,0 +1,78 @@
+/* avermedia-dvbt.h - Keytable for avermedia_dvbt Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Matt Jesson <dvb@jesson.eclipse.co.uk */
+
+static struct ir_scancode avermedia_dvbt[] = {
+	{ 0x28, KEY_0 },		/* '0' / 'enter' */
+	{ 0x22, KEY_1 },		/* '1' */
+	{ 0x12, KEY_2 },		/* '2' / 'up arrow' */
+	{ 0x32, KEY_3 },		/* '3' */
+	{ 0x24, KEY_4 },		/* '4' / 'left arrow' */
+	{ 0x14, KEY_5 },		/* '5' */
+	{ 0x34, KEY_6 },		/* '6' / 'right arrow' */
+	{ 0x26, KEY_7 },		/* '7' */
+	{ 0x16, KEY_8 },		/* '8' / 'down arrow' */
+	{ 0x36, KEY_9 },		/* '9' */
+
+	{ 0x20, KEY_LIST },		/* 'source' */
+	{ 0x10, KEY_TEXT },		/* 'teletext' */
+	{ 0x00, KEY_POWER },		/* 'power' */
+	{ 0x04, KEY_AUDIO },		/* 'audio' */
+	{ 0x06, KEY_ZOOM },		/* 'full screen' */
+	{ 0x18, KEY_VIDEO },		/* 'display' */
+	{ 0x38, KEY_SEARCH },		/* 'loop' */
+	{ 0x08, KEY_INFO },		/* 'preview' */
+	{ 0x2a, KEY_REWIND },		/* 'backward <<' */
+	{ 0x1a, KEY_FASTFORWARD },	/* 'forward >>' */
+	{ 0x3a, KEY_RECORD },		/* 'capture' */
+	{ 0x0a, KEY_MUTE },		/* 'mute' */
+	{ 0x2c, KEY_RECORD },		/* 'record' */
+	{ 0x1c, KEY_PAUSE },		/* 'pause' */
+	{ 0x3c, KEY_STOP },		/* 'stop' */
+	{ 0x0c, KEY_PLAY },		/* 'play' */
+	{ 0x2e, KEY_RED },		/* 'red' */
+	{ 0x01, KEY_BLUE },		/* 'blue' / 'cancel' */
+	{ 0x0e, KEY_YELLOW },		/* 'yellow' / 'ok' */
+	{ 0x21, KEY_GREEN },		/* 'green' */
+	{ 0x11, KEY_CHANNELDOWN },	/* 'channel -' */
+	{ 0x31, KEY_CHANNELUP },	/* 'channel +' */
+	{ 0x1e, KEY_VOLUMEDOWN },	/* 'volume -' */
+	{ 0x3e, KEY_VOLUMEUP },		/* 'volume +' */
+};
+
+static struct rc_keymap avermedia_dvbt_map = {
+	.map = {
+		.scan    = avermedia_dvbt,
+		.size    = ARRAY_SIZE(avermedia_dvbt),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_AVERMEDIA_DVBT,
+	}
+};
+
+static int __init init_rc_map_avermedia_dvbt(void)
+{
+	return ir_register_map(&avermedia_dvbt_map);
+}
+
+static void __exit exit_rc_map_avermedia_dvbt(void)
+{
+	ir_unregister_map(&avermedia_dvbt_map);
+}
+
+module_init(init_rc_map_avermedia_dvbt)
+module_exit(exit_rc_map_avermedia_dvbt)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-avermedia-m135a-rm-jx.c b/drivers/media/IR/keymaps/rc-avermedia-m135a-rm-jx.c
new file mode 100644
index 0000000..101e7ea
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-avermedia-m135a-rm-jx.c
@@ -0,0 +1,90 @@
+/* avermedia-m135a-rm-jx.h - Keytable for avermedia_m135a_rm_jx Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/*
+ * Avermedia M135A with IR model RM-JX
+ * The same codes exist on both Positivo (BR) and original IR
+ * Mauro Carvalho Chehab <mchehab@infradead.org>
+ */
+
+static struct ir_scancode avermedia_m135a_rm_jx[] = {
+	{ 0x0200, KEY_POWER2 },
+	{ 0x022e, KEY_DOT },		/* '.' */
+	{ 0x0201, KEY_MODE },		/* TV/FM or SOURCE */
+
+	{ 0x0205, KEY_1 },
+	{ 0x0206, KEY_2 },
+	{ 0x0207, KEY_3 },
+	{ 0x0209, KEY_4 },
+	{ 0x020a, KEY_5 },
+	{ 0x020b, KEY_6 },
+	{ 0x020d, KEY_7 },
+	{ 0x020e, KEY_8 },
+	{ 0x020f, KEY_9 },
+	{ 0x0211, KEY_0 },
+
+	{ 0x0213, KEY_RIGHT },		/* -> or L */
+	{ 0x0212, KEY_LEFT },		/* <- or R */
+
+	{ 0x0217, KEY_SLEEP },		/* Capturar Imagem or Snapshot */
+	{ 0x0210, KEY_SHUFFLE },	/* Amostra or 16 chan prev */
+
+	{ 0x0303, KEY_CHANNELUP },
+	{ 0x0302, KEY_CHANNELDOWN },
+	{ 0x021f, KEY_VOLUMEUP },
+	{ 0x021e, KEY_VOLUMEDOWN },
+	{ 0x020c, KEY_ENTER },		/* Full Screen */
+
+	{ 0x0214, KEY_MUTE },
+	{ 0x0208, KEY_AUDIO },
+
+	{ 0x0203, KEY_TEXT },		/* Teletext */
+	{ 0x0204, KEY_EPG },
+	{ 0x022b, KEY_TV2 },		/* TV2 or PIP */
+
+	{ 0x021d, KEY_RED },
+	{ 0x021c, KEY_YELLOW },
+	{ 0x0301, KEY_GREEN },
+	{ 0x0300, KEY_BLUE },
+
+	{ 0x021a, KEY_PLAYPAUSE },
+	{ 0x0219, KEY_RECORD },
+	{ 0x0218, KEY_PLAY },
+	{ 0x021b, KEY_STOP },
+};
+
+static struct rc_keymap avermedia_m135a_rm_jx_map = {
+	.map = {
+		.scan    = avermedia_m135a_rm_jx,
+		.size    = ARRAY_SIZE(avermedia_m135a_rm_jx),
+		.ir_type = IR_TYPE_NEC,
+		.name    = RC_MAP_AVERMEDIA_M135A_RM_JX,
+	}
+};
+
+static int __init init_rc_map_avermedia_m135a_rm_jx(void)
+{
+	return ir_register_map(&avermedia_m135a_rm_jx_map);
+}
+
+static void __exit exit_rc_map_avermedia_m135a_rm_jx(void)
+{
+	ir_unregister_map(&avermedia_m135a_rm_jx_map);
+}
+
+module_init(init_rc_map_avermedia_m135a_rm_jx)
+module_exit(exit_rc_map_avermedia_m135a_rm_jx)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-avermedia.c b/drivers/media/IR/keymaps/rc-avermedia.c
new file mode 100644
index 0000000..21effd5
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-avermedia.c
@@ -0,0 +1,86 @@
+/* avermedia.h - Keytable for avermedia Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Alex Hermann <gaaf@gmx.net> */
+
+static struct ir_scancode avermedia[] = {
+	{ 0x28, KEY_1 },
+	{ 0x18, KEY_2 },
+	{ 0x38, KEY_3 },
+	{ 0x24, KEY_4 },
+	{ 0x14, KEY_5 },
+	{ 0x34, KEY_6 },
+	{ 0x2c, KEY_7 },
+	{ 0x1c, KEY_8 },
+	{ 0x3c, KEY_9 },
+	{ 0x22, KEY_0 },
+
+	{ 0x20, KEY_TV },		/* TV/FM */
+	{ 0x10, KEY_CD },		/* CD */
+	{ 0x30, KEY_TEXT },		/* TELETEXT */
+	{ 0x00, KEY_POWER },		/* POWER */
+
+	{ 0x08, KEY_VIDEO },		/* VIDEO */
+	{ 0x04, KEY_AUDIO },		/* AUDIO */
+	{ 0x0c, KEY_ZOOM },		/* FULL SCREEN */
+
+	{ 0x12, KEY_SUBTITLE },		/* DISPLAY */
+	{ 0x32, KEY_REWIND },		/* LOOP	*/
+	{ 0x02, KEY_PRINT },		/* PREVIEW */
+
+	{ 0x2a, KEY_SEARCH },		/* AUTOSCAN */
+	{ 0x1a, KEY_SLEEP },		/* FREEZE */
+	{ 0x3a, KEY_CAMERA },		/* SNAPSHOT */
+	{ 0x0a, KEY_MUTE },		/* MUTE */
+
+	{ 0x26, KEY_RECORD },		/* RECORD */
+	{ 0x16, KEY_PAUSE },		/* PAUSE */
+	{ 0x36, KEY_STOP },		/* STOP */
+	{ 0x06, KEY_PLAY },		/* PLAY */
+
+	{ 0x2e, KEY_RED },		/* RED */
+	{ 0x21, KEY_GREEN },		/* GREEN */
+	{ 0x0e, KEY_YELLOW },		/* YELLOW */
+	{ 0x01, KEY_BLUE },		/* BLUE */
+
+	{ 0x1e, KEY_VOLUMEDOWN },	/* VOLUME- */
+	{ 0x3e, KEY_VOLUMEUP },		/* VOLUME+ */
+	{ 0x11, KEY_CHANNELDOWN },	/* CHANNEL/PAGE- */
+	{ 0x31, KEY_CHANNELUP }		/* CHANNEL/PAGE+ */
+};
+
+static struct rc_keymap avermedia_map = {
+	.map = {
+		.scan    = avermedia,
+		.size    = ARRAY_SIZE(avermedia),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_AVERMEDIA,
+	}
+};
+
+static int __init init_rc_map_avermedia(void)
+{
+	return ir_register_map(&avermedia_map);
+}
+
+static void __exit exit_rc_map_avermedia(void)
+{
+	ir_unregister_map(&avermedia_map);
+}
+
+module_init(init_rc_map_avermedia)
+module_exit(exit_rc_map_avermedia)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-avertv-303.c b/drivers/media/IR/keymaps/rc-avertv-303.c
new file mode 100644
index 0000000..971c59d
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-avertv-303.c
@@ -0,0 +1,85 @@
+/* avertv-303.h - Keytable for avertv_303 Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* AVERTV STUDIO 303 Remote */
+
+static struct ir_scancode avertv_303[] = {
+	{ 0x2a, KEY_1 },
+	{ 0x32, KEY_2 },
+	{ 0x3a, KEY_3 },
+	{ 0x4a, KEY_4 },
+	{ 0x52, KEY_5 },
+	{ 0x5a, KEY_6 },
+	{ 0x6a, KEY_7 },
+	{ 0x72, KEY_8 },
+	{ 0x7a, KEY_9 },
+	{ 0x0e, KEY_0 },
+
+	{ 0x02, KEY_POWER },
+	{ 0x22, KEY_VIDEO },
+	{ 0x42, KEY_AUDIO },
+	{ 0x62, KEY_ZOOM },
+	{ 0x0a, KEY_TV },
+	{ 0x12, KEY_CD },
+	{ 0x1a, KEY_TEXT },
+
+	{ 0x16, KEY_SUBTITLE },
+	{ 0x1e, KEY_REWIND },
+	{ 0x06, KEY_PRINT },
+
+	{ 0x2e, KEY_SEARCH },
+	{ 0x36, KEY_SLEEP },
+	{ 0x3e, KEY_SHUFFLE },
+	{ 0x26, KEY_MUTE },
+
+	{ 0x4e, KEY_RECORD },
+	{ 0x56, KEY_PAUSE },
+	{ 0x5e, KEY_STOP },
+	{ 0x46, KEY_PLAY },
+
+	{ 0x6e, KEY_RED },
+	{ 0x0b, KEY_GREEN },
+	{ 0x66, KEY_YELLOW },
+	{ 0x03, KEY_BLUE },
+
+	{ 0x76, KEY_LEFT },
+	{ 0x7e, KEY_RIGHT },
+	{ 0x13, KEY_DOWN },
+	{ 0x1b, KEY_UP },
+};
+
+static struct rc_keymap avertv_303_map = {
+	.map = {
+		.scan    = avertv_303,
+		.size    = ARRAY_SIZE(avertv_303),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_AVERTV_303,
+	}
+};
+
+static int __init init_rc_map_avertv_303(void)
+{
+	return ir_register_map(&avertv_303_map);
+}
+
+static void __exit exit_rc_map_avertv_303(void)
+{
+	ir_unregister_map(&avertv_303_map);
+}
+
+module_init(init_rc_map_avertv_303)
+module_exit(exit_rc_map_avertv_303)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-behold-columbus.c b/drivers/media/IR/keymaps/rc-behold-columbus.c
new file mode 100644
index 0000000..9f56c98
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-behold-columbus.c
@@ -0,0 +1,108 @@
+/* behold-columbus.h - Keytable for behold_columbus Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Beholder Intl. Ltd. 2008
+ * Dmitry Belimov d.belimov@google.com
+ * Keytable is used by BeholdTV Columbus
+ * The "ascii-art picture" below (in comments, first row
+ * is the keycode in hex, and subsequent row(s) shows
+ * the button labels (several variants when appropriate)
+ * helps to descide which keycodes to assign to the buttons.
+ */
+
+static struct ir_scancode behold_columbus[] = {
+
+	/*  0x13   0x11   0x1C   0x12  *
+	 *  Mute  Source  TV/FM  Power *
+	 *                             */
+
+	{ 0x13, KEY_MUTE },
+	{ 0x11, KEY_PROPS },
+	{ 0x1C, KEY_TUNER },	/* KEY_TV/KEY_RADIO	*/
+	{ 0x12, KEY_POWER },
+
+	/*  0x01    0x02    0x03  0x0D    *
+	 *   1       2       3   Stereo   *
+	 *                        	  *
+	 *  0x04    0x05    0x06  0x19    *
+	 *   4       5       6   Snapshot *
+	 *                        	  *
+	 *  0x07    0x08    0x09  0x10    *
+	 *   7       8       9    Zoom 	  *
+	 *                                */
+	{ 0x01, KEY_1 },
+	{ 0x02, KEY_2 },
+	{ 0x03, KEY_3 },
+	{ 0x0D, KEY_SETUP },	  /* Setup key */
+	{ 0x04, KEY_4 },
+	{ 0x05, KEY_5 },
+	{ 0x06, KEY_6 },
+	{ 0x19, KEY_CAMERA },	/* Snapshot key */
+	{ 0x07, KEY_7 },
+	{ 0x08, KEY_8 },
+	{ 0x09, KEY_9 },
+	{ 0x10, KEY_ZOOM },
+
+	/*  0x0A    0x00    0x0B       0x0C   *
+	 * RECALL    0    ChannelUp  VolumeUp *
+	 *                                    */
+	{ 0x0A, KEY_AGAIN },
+	{ 0x00, KEY_0 },
+	{ 0x0B, KEY_CHANNELUP },
+	{ 0x0C, KEY_VOLUMEUP },
+
+	/*   0x1B      0x1D      0x15        0x18     *
+	 * Timeshift  Record  ChannelDown  VolumeDown *
+	 *                                            */
+
+	{ 0x1B, KEY_TIME },
+	{ 0x1D, KEY_RECORD },
+	{ 0x15, KEY_CHANNELDOWN },
+	{ 0x18, KEY_VOLUMEDOWN },
+
+	/*   0x0E   0x1E     0x0F     0x1A  *
+	 *   Stop   Pause  Previouse  Next  *
+	 *                                  */
+
+	{ 0x0E, KEY_STOP },
+	{ 0x1E, KEY_PAUSE },
+	{ 0x0F, KEY_PREVIOUS },
+	{ 0x1A, KEY_NEXT },
+
+};
+
+static struct rc_keymap behold_columbus_map = {
+	.map = {
+		.scan    = behold_columbus,
+		.size    = ARRAY_SIZE(behold_columbus),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_BEHOLD_COLUMBUS,
+	}
+};
+
+static int __init init_rc_map_behold_columbus(void)
+{
+	return ir_register_map(&behold_columbus_map);
+}
+
+static void __exit exit_rc_map_behold_columbus(void)
+{
+	ir_unregister_map(&behold_columbus_map);
+}
+
+module_init(init_rc_map_behold_columbus)
+module_exit(exit_rc_map_behold_columbus)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-behold.c b/drivers/media/IR/keymaps/rc-behold.c
new file mode 100644
index 0000000..abc140b
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-behold.c
@@ -0,0 +1,141 @@
+/* behold.h - Keytable for behold Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/*
+ * Igor Kuznetsov <igk72@ya.ru>
+ * Andrey J. Melnikov <temnota@kmv.ru>
+ *
+ * Keytable is used by BeholdTV 60x series, M6 series at
+ * least, and probably other cards too.
+ * The "ascii-art picture" below (in comments, first row
+ * is the keycode in hex, and subsequent row(s) shows
+ * the button labels (several variants when appropriate)
+ * helps to descide which keycodes to assign to the buttons.
+ */
+
+static struct ir_scancode behold[] = {
+
+	/*  0x1c            0x12  *
+	 *  TV/FM          POWER  *
+	 *                        */
+	{ 0x1c, KEY_TUNER },	/* XXX KEY_TV / KEY_RADIO */
+	{ 0x12, KEY_POWER },
+
+	/*  0x01    0x02    0x03  *
+	 *   1       2       3    *
+	 *                        *
+	 *  0x04    0x05    0x06  *
+	 *   4       5       6    *
+	 *                        *
+	 *  0x07    0x08    0x09  *
+	 *   7       8       9    *
+	 *                        */
+	{ 0x01, KEY_1 },
+	{ 0x02, KEY_2 },
+	{ 0x03, KEY_3 },
+	{ 0x04, KEY_4 },
+	{ 0x05, KEY_5 },
+	{ 0x06, KEY_6 },
+	{ 0x07, KEY_7 },
+	{ 0x08, KEY_8 },
+	{ 0x09, KEY_9 },
+
+	/*  0x0a    0x00    0x17  *
+	 * RECALL    0      MODE  *
+	 *                        */
+	{ 0x0a, KEY_AGAIN },
+	{ 0x00, KEY_0 },
+	{ 0x17, KEY_MODE },
+
+	/*  0x14          0x10    *
+	 * ASPECT      FULLSCREEN *
+	 *                        */
+	{ 0x14, KEY_SCREEN },
+	{ 0x10, KEY_ZOOM },
+
+	/*          0x0b          *
+	 *           Up           *
+	 *                        *
+	 *  0x18    0x16    0x0c  *
+	 *  Left     Ok     Right *
+	 *                        *
+	 *         0x015          *
+	 *         Down           *
+	 *                        */
+	{ 0x0b, KEY_CHANNELUP },
+	{ 0x18, KEY_VOLUMEDOWN },
+	{ 0x16, KEY_OK },		/* XXX KEY_ENTER */
+	{ 0x0c, KEY_VOLUMEUP },
+	{ 0x15, KEY_CHANNELDOWN },
+
+	/*  0x11            0x0d  *
+	 *  MUTE            INFO  *
+	 *                        */
+	{ 0x11, KEY_MUTE },
+	{ 0x0d, KEY_INFO },
+
+	/*  0x0f    0x1b    0x1a  *
+	 * RECORD PLAY/PAUSE STOP *
+	 *                        *
+	 *  0x0e    0x1f    0x1e  *
+	 *TELETEXT  AUDIO  SOURCE *
+	 *           RED   YELLOW *
+	 *                        */
+	{ 0x0f, KEY_RECORD },
+	{ 0x1b, KEY_PLAYPAUSE },
+	{ 0x1a, KEY_STOP },
+	{ 0x0e, KEY_TEXT },
+	{ 0x1f, KEY_RED },	/*XXX KEY_AUDIO	*/
+	{ 0x1e, KEY_YELLOW },	/*XXX KEY_SOURCE	*/
+
+	/*  0x1d   0x13     0x19  *
+	 * SLEEP  PREVIEW   DVB   *
+	 *         GREEN    BLUE  *
+	 *                        */
+	{ 0x1d, KEY_SLEEP },
+	{ 0x13, KEY_GREEN },
+	{ 0x19, KEY_BLUE },	/* XXX KEY_SAT	*/
+
+	/*  0x58           0x5c   *
+	 * FREEZE        SNAPSHOT *
+	 *                        */
+	{ 0x58, KEY_SLOW },
+	{ 0x5c, KEY_CAMERA },
+
+};
+
+static struct rc_keymap behold_map = {
+	.map = {
+		.scan    = behold,
+		.size    = ARRAY_SIZE(behold),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_BEHOLD,
+	}
+};
+
+static int __init init_rc_map_behold(void)
+{
+	return ir_register_map(&behold_map);
+}
+
+static void __exit exit_rc_map_behold(void)
+{
+	ir_unregister_map(&behold_map);
+}
+
+module_init(init_rc_map_behold)
+module_exit(exit_rc_map_behold)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-budget-ci-old.c b/drivers/media/IR/keymaps/rc-budget-ci-old.c
new file mode 100644
index 0000000..64c2ac9
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-budget-ci-old.c
@@ -0,0 +1,92 @@
+/* budget-ci-old.h - Keytable for budget_ci_old Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* From reading the following remotes:
+ * Zenith Universal 7 / TV Mode 807 / VCR Mode 837
+ * Hauppauge (from NOVA-CI-s box product)
+ * This is a "middle of the road" approach, differences are noted
+ */
+
+static struct ir_scancode budget_ci_old[] = {
+	{ 0x00, KEY_0 },
+	{ 0x01, KEY_1 },
+	{ 0x02, KEY_2 },
+	{ 0x03, KEY_3 },
+	{ 0x04, KEY_4 },
+	{ 0x05, KEY_5 },
+	{ 0x06, KEY_6 },
+	{ 0x07, KEY_7 },
+	{ 0x08, KEY_8 },
+	{ 0x09, KEY_9 },
+	{ 0x0a, KEY_ENTER },
+	{ 0x0b, KEY_RED },
+	{ 0x0c, KEY_POWER },		/* RADIO on Hauppauge */
+	{ 0x0d, KEY_MUTE },
+	{ 0x0f, KEY_A },		/* TV on Hauppauge */
+	{ 0x10, KEY_VOLUMEUP },
+	{ 0x11, KEY_VOLUMEDOWN },
+	{ 0x14, KEY_B },
+	{ 0x1c, KEY_UP },
+	{ 0x1d, KEY_DOWN },
+	{ 0x1e, KEY_OPTION },		/* RESERVED on Hauppauge */
+	{ 0x1f, KEY_BREAK },
+	{ 0x20, KEY_CHANNELUP },
+	{ 0x21, KEY_CHANNELDOWN },
+	{ 0x22, KEY_PREVIOUS },		/* Prev Ch on Zenith, SOURCE on Hauppauge */
+	{ 0x24, KEY_RESTART },
+	{ 0x25, KEY_OK },
+	{ 0x26, KEY_CYCLEWINDOWS },	/* MINIMIZE on Hauppauge */
+	{ 0x28, KEY_ENTER },		/* VCR mode on Zenith */
+	{ 0x29, KEY_PAUSE },
+	{ 0x2b, KEY_RIGHT },
+	{ 0x2c, KEY_LEFT },
+	{ 0x2e, KEY_MENU },		/* FULL SCREEN on Hauppauge */
+	{ 0x30, KEY_SLOW },
+	{ 0x31, KEY_PREVIOUS },		/* VCR mode on Zenith */
+	{ 0x32, KEY_REWIND },
+	{ 0x34, KEY_FASTFORWARD },
+	{ 0x35, KEY_PLAY },
+	{ 0x36, KEY_STOP },
+	{ 0x37, KEY_RECORD },
+	{ 0x38, KEY_TUNER },		/* TV/VCR on Zenith */
+	{ 0x3a, KEY_C },
+	{ 0x3c, KEY_EXIT },
+	{ 0x3d, KEY_POWER2 },
+	{ 0x3e, KEY_TUNER },
+};
+
+static struct rc_keymap budget_ci_old_map = {
+	.map = {
+		.scan    = budget_ci_old,
+		.size    = ARRAY_SIZE(budget_ci_old),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_BUDGET_CI_OLD,
+	}
+};
+
+static int __init init_rc_map_budget_ci_old(void)
+{
+	return ir_register_map(&budget_ci_old_map);
+}
+
+static void __exit exit_rc_map_budget_ci_old(void)
+{
+	ir_unregister_map(&budget_ci_old_map);
+}
+
+module_init(init_rc_map_budget_ci_old)
+module_exit(exit_rc_map_budget_ci_old)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-cinergy-1400.c b/drivers/media/IR/keymaps/rc-cinergy-1400.c
new file mode 100644
index 0000000..074f2c2
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-cinergy-1400.c
@@ -0,0 +1,84 @@
+/* cinergy-1400.h - Keytable for cinergy_1400 Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Cinergy 1400 DVB-T */
+
+static struct ir_scancode cinergy_1400[] = {
+	{ 0x01, KEY_POWER },
+	{ 0x02, KEY_1 },
+	{ 0x03, KEY_2 },
+	{ 0x04, KEY_3 },
+	{ 0x05, KEY_4 },
+	{ 0x06, KEY_5 },
+	{ 0x07, KEY_6 },
+	{ 0x08, KEY_7 },
+	{ 0x09, KEY_8 },
+	{ 0x0a, KEY_9 },
+	{ 0x0c, KEY_0 },
+
+	{ 0x0b, KEY_VIDEO },
+	{ 0x0d, KEY_REFRESH },
+	{ 0x0e, KEY_SELECT },
+	{ 0x0f, KEY_EPG },
+	{ 0x10, KEY_UP },
+	{ 0x11, KEY_LEFT },
+	{ 0x12, KEY_OK },
+	{ 0x13, KEY_RIGHT },
+	{ 0x14, KEY_DOWN },
+	{ 0x15, KEY_TEXT },
+	{ 0x16, KEY_INFO },
+
+	{ 0x17, KEY_RED },
+	{ 0x18, KEY_GREEN },
+	{ 0x19, KEY_YELLOW },
+	{ 0x1a, KEY_BLUE },
+
+	{ 0x1b, KEY_CHANNELUP },
+	{ 0x1c, KEY_VOLUMEUP },
+	{ 0x1d, KEY_MUTE },
+	{ 0x1e, KEY_VOLUMEDOWN },
+	{ 0x1f, KEY_CHANNELDOWN },
+
+	{ 0x40, KEY_PAUSE },
+	{ 0x4c, KEY_PLAY },
+	{ 0x58, KEY_RECORD },
+	{ 0x54, KEY_PREVIOUS },
+	{ 0x48, KEY_STOP },
+	{ 0x5c, KEY_NEXT },
+};
+
+static struct rc_keymap cinergy_1400_map = {
+	.map = {
+		.scan    = cinergy_1400,
+		.size    = ARRAY_SIZE(cinergy_1400),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_CINERGY_1400,
+	}
+};
+
+static int __init init_rc_map_cinergy_1400(void)
+{
+	return ir_register_map(&cinergy_1400_map);
+}
+
+static void __exit exit_rc_map_cinergy_1400(void)
+{
+	ir_unregister_map(&cinergy_1400_map);
+}
+
+module_init(init_rc_map_cinergy_1400)
+module_exit(exit_rc_map_cinergy_1400)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-cinergy.c b/drivers/media/IR/keymaps/rc-cinergy.c
new file mode 100644
index 0000000..cf84c3d
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-cinergy.c
@@ -0,0 +1,78 @@
+/* cinergy.h - Keytable for cinergy Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode cinergy[] = {
+	{ 0x00, KEY_0 },
+	{ 0x01, KEY_1 },
+	{ 0x02, KEY_2 },
+	{ 0x03, KEY_3 },
+	{ 0x04, KEY_4 },
+	{ 0x05, KEY_5 },
+	{ 0x06, KEY_6 },
+	{ 0x07, KEY_7 },
+	{ 0x08, KEY_8 },
+	{ 0x09, KEY_9 },
+
+	{ 0x0a, KEY_POWER },
+	{ 0x0b, KEY_PROG1 },		/* app */
+	{ 0x0c, KEY_ZOOM },		/* zoom/fullscreen */
+	{ 0x0d, KEY_CHANNELUP },	/* channel */
+	{ 0x0e, KEY_CHANNELDOWN },	/* channel- */
+	{ 0x0f, KEY_VOLUMEUP },
+	{ 0x10, KEY_VOLUMEDOWN },
+	{ 0x11, KEY_TUNER },		/* AV */
+	{ 0x12, KEY_NUMLOCK },		/* -/-- */
+	{ 0x13, KEY_AUDIO },		/* audio */
+	{ 0x14, KEY_MUTE },
+	{ 0x15, KEY_UP },
+	{ 0x16, KEY_DOWN },
+	{ 0x17, KEY_LEFT },
+	{ 0x18, KEY_RIGHT },
+	{ 0x19, BTN_LEFT, },
+	{ 0x1a, BTN_RIGHT, },
+	{ 0x1b, KEY_WWW },		/* text */
+	{ 0x1c, KEY_REWIND },
+	{ 0x1d, KEY_FORWARD },
+	{ 0x1e, KEY_RECORD },
+	{ 0x1f, KEY_PLAY },
+	{ 0x20, KEY_PREVIOUSSONG },
+	{ 0x21, KEY_NEXTSONG },
+	{ 0x22, KEY_PAUSE },
+	{ 0x23, KEY_STOP },
+};
+
+static struct rc_keymap cinergy_map = {
+	.map = {
+		.scan    = cinergy,
+		.size    = ARRAY_SIZE(cinergy),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_CINERGY,
+	}
+};
+
+static int __init init_rc_map_cinergy(void)
+{
+	return ir_register_map(&cinergy_map);
+}
+
+static void __exit exit_rc_map_cinergy(void)
+{
+	ir_unregister_map(&cinergy_map);
+}
+
+module_init(init_rc_map_cinergy)
+module_exit(exit_rc_map_cinergy)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-dm1105-nec.c b/drivers/media/IR/keymaps/rc-dm1105-nec.c
new file mode 100644
index 0000000..90684d0
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-dm1105-nec.c
@@ -0,0 +1,76 @@
+/* dm1105-nec.h - Keytable for dm1105_nec Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* DVBWorld remotes
+   Igor M. Liplianin <liplianin@me.by>
+ */
+
+static struct ir_scancode dm1105_nec[] = {
+	{ 0x0a, KEY_POWER2},		/* power */
+	{ 0x0c, KEY_MUTE},		/* mute */
+	{ 0x11, KEY_1},
+	{ 0x12, KEY_2},
+	{ 0x13, KEY_3},
+	{ 0x14, KEY_4},
+	{ 0x15, KEY_5},
+	{ 0x16, KEY_6},
+	{ 0x17, KEY_7},
+	{ 0x18, KEY_8},
+	{ 0x19, KEY_9},
+	{ 0x10, KEY_0},
+	{ 0x1c, KEY_CHANNELUP},		/* ch+ */
+	{ 0x0f, KEY_CHANNELDOWN},	/* ch- */
+	{ 0x1a, KEY_VOLUMEUP},		/* vol+ */
+	{ 0x0e, KEY_VOLUMEDOWN},	/* vol- */
+	{ 0x04, KEY_RECORD},		/* rec */
+	{ 0x09, KEY_CHANNEL},		/* fav */
+	{ 0x08, KEY_BACKSPACE},		/* rewind */
+	{ 0x07, KEY_FASTFORWARD},	/* fast */
+	{ 0x0b, KEY_PAUSE},		/* pause */
+	{ 0x02, KEY_ESC},		/* cancel */
+	{ 0x03, KEY_TAB},		/* tab */
+	{ 0x00, KEY_UP},		/* up */
+	{ 0x1f, KEY_ENTER},		/* ok */
+	{ 0x01, KEY_DOWN},		/* down */
+	{ 0x05, KEY_RECORD},		/* cap */
+	{ 0x06, KEY_STOP},		/* stop */
+	{ 0x40, KEY_ZOOM},		/* full */
+	{ 0x1e, KEY_TV},		/* tvmode */
+	{ 0x1b, KEY_B},			/* recall */
+};
+
+static struct rc_keymap dm1105_nec_map = {
+	.map = {
+		.scan    = dm1105_nec,
+		.size    = ARRAY_SIZE(dm1105_nec),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_DM1105_NEC,
+	}
+};
+
+static int __init init_rc_map_dm1105_nec(void)
+{
+	return ir_register_map(&dm1105_nec_map);
+}
+
+static void __exit exit_rc_map_dm1105_nec(void)
+{
+	ir_unregister_map(&dm1105_nec_map);
+}
+
+module_init(init_rc_map_dm1105_nec)
+module_exit(exit_rc_map_dm1105_nec)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-dntv-live-dvb-t.c b/drivers/media/IR/keymaps/rc-dntv-live-dvb-t.c
new file mode 100644
index 0000000..8a4027a
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-dntv-live-dvb-t.c
@@ -0,0 +1,78 @@
+/* dntv-live-dvb-t.h - Keytable for dntv_live_dvb_t Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* DigitalNow DNTV Live DVB-T Remote */
+
+static struct ir_scancode dntv_live_dvb_t[] = {
+	{ 0x00, KEY_ESC },		/* 'go up a level?' */
+	/* Keys 0 to 9 */
+	{ 0x0a, KEY_0 },
+	{ 0x01, KEY_1 },
+	{ 0x02, KEY_2 },
+	{ 0x03, KEY_3 },
+	{ 0x04, KEY_4 },
+	{ 0x05, KEY_5 },
+	{ 0x06, KEY_6 },
+	{ 0x07, KEY_7 },
+	{ 0x08, KEY_8 },
+	{ 0x09, KEY_9 },
+
+	{ 0x0b, KEY_TUNER },		/* tv/fm */
+	{ 0x0c, KEY_SEARCH },		/* scan */
+	{ 0x0d, KEY_STOP },
+	{ 0x0e, KEY_PAUSE },
+	{ 0x0f, KEY_LIST },		/* source */
+
+	{ 0x10, KEY_MUTE },
+	{ 0x11, KEY_REWIND },		/* backward << */
+	{ 0x12, KEY_POWER },
+	{ 0x13, KEY_CAMERA },		/* snap */
+	{ 0x14, KEY_AUDIO },		/* stereo */
+	{ 0x15, KEY_CLEAR },		/* reset */
+	{ 0x16, KEY_PLAY },
+	{ 0x17, KEY_ENTER },
+	{ 0x18, KEY_ZOOM },		/* full screen */
+	{ 0x19, KEY_FASTFORWARD },	/* forward >> */
+	{ 0x1a, KEY_CHANNELUP },
+	{ 0x1b, KEY_VOLUMEUP },
+	{ 0x1c, KEY_INFO },		/* preview */
+	{ 0x1d, KEY_RECORD },		/* record */
+	{ 0x1e, KEY_CHANNELDOWN },
+	{ 0x1f, KEY_VOLUMEDOWN },
+};
+
+static struct rc_keymap dntv_live_dvb_t_map = {
+	.map = {
+		.scan    = dntv_live_dvb_t,
+		.size    = ARRAY_SIZE(dntv_live_dvb_t),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_DNTV_LIVE_DVB_T,
+	}
+};
+
+static int __init init_rc_map_dntv_live_dvb_t(void)
+{
+	return ir_register_map(&dntv_live_dvb_t_map);
+}
+
+static void __exit exit_rc_map_dntv_live_dvb_t(void)
+{
+	ir_unregister_map(&dntv_live_dvb_t_map);
+}
+
+module_init(init_rc_map_dntv_live_dvb_t)
+module_exit(exit_rc_map_dntv_live_dvb_t)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-dntv-live-dvbt-pro.c b/drivers/media/IR/keymaps/rc-dntv-live-dvbt-pro.c
new file mode 100644
index 0000000..6f4d607
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-dntv-live-dvbt-pro.c
@@ -0,0 +1,97 @@
+/* dntv-live-dvbt-pro.h - Keytable for dntv_live_dvbt_pro Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* DigitalNow DNTV Live! DVB-T Pro Remote */
+
+static struct ir_scancode dntv_live_dvbt_pro[] = {
+	{ 0x16, KEY_POWER },
+	{ 0x5b, KEY_HOME },
+
+	{ 0x55, KEY_TV },		/* live tv */
+	{ 0x58, KEY_TUNER },		/* digital Radio */
+	{ 0x5a, KEY_RADIO },		/* FM radio */
+	{ 0x59, KEY_DVD },		/* dvd menu */
+	{ 0x03, KEY_1 },
+	{ 0x01, KEY_2 },
+	{ 0x06, KEY_3 },
+	{ 0x09, KEY_4 },
+	{ 0x1d, KEY_5 },
+	{ 0x1f, KEY_6 },
+	{ 0x0d, KEY_7 },
+	{ 0x19, KEY_8 },
+	{ 0x1b, KEY_9 },
+	{ 0x0c, KEY_CANCEL },
+	{ 0x15, KEY_0 },
+	{ 0x4a, KEY_CLEAR },
+	{ 0x13, KEY_BACK },
+	{ 0x00, KEY_TAB },
+	{ 0x4b, KEY_UP },
+	{ 0x4e, KEY_LEFT },
+	{ 0x4f, KEY_OK },
+	{ 0x52, KEY_RIGHT },
+	{ 0x51, KEY_DOWN },
+	{ 0x1e, KEY_VOLUMEUP },
+	{ 0x0a, KEY_VOLUMEDOWN },
+	{ 0x02, KEY_CHANNELDOWN },
+	{ 0x05, KEY_CHANNELUP },
+	{ 0x11, KEY_RECORD },
+	{ 0x14, KEY_PLAY },
+	{ 0x4c, KEY_PAUSE },
+	{ 0x1a, KEY_STOP },
+	{ 0x40, KEY_REWIND },
+	{ 0x12, KEY_FASTFORWARD },
+	{ 0x41, KEY_PREVIOUSSONG },	/* replay |< */
+	{ 0x42, KEY_NEXTSONG },		/* skip >| */
+	{ 0x54, KEY_CAMERA },		/* capture */
+	{ 0x50, KEY_LANGUAGE },		/* sap */
+	{ 0x47, KEY_TV2 },		/* pip */
+	{ 0x4d, KEY_SCREEN },
+	{ 0x43, KEY_SUBTITLE },
+	{ 0x10, KEY_MUTE },
+	{ 0x49, KEY_AUDIO },		/* l/r */
+	{ 0x07, KEY_SLEEP },
+	{ 0x08, KEY_VIDEO },		/* a/v */
+	{ 0x0e, KEY_PREVIOUS },		/* recall */
+	{ 0x45, KEY_ZOOM },		/* zoom + */
+	{ 0x46, KEY_ANGLE },		/* zoom - */
+	{ 0x56, KEY_RED },
+	{ 0x57, KEY_GREEN },
+	{ 0x5c, KEY_YELLOW },
+	{ 0x5d, KEY_BLUE },
+};
+
+static struct rc_keymap dntv_live_dvbt_pro_map = {
+	.map = {
+		.scan    = dntv_live_dvbt_pro,
+		.size    = ARRAY_SIZE(dntv_live_dvbt_pro),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_DNTV_LIVE_DVBT_PRO,
+	}
+};
+
+static int __init init_rc_map_dntv_live_dvbt_pro(void)
+{
+	return ir_register_map(&dntv_live_dvbt_pro_map);
+}
+
+static void __exit exit_rc_map_dntv_live_dvbt_pro(void)
+{
+	ir_unregister_map(&dntv_live_dvbt_pro_map);
+}
+
+module_init(init_rc_map_dntv_live_dvbt_pro)
+module_exit(exit_rc_map_dntv_live_dvbt_pro)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-em-terratec.c b/drivers/media/IR/keymaps/rc-em-terratec.c
new file mode 100644
index 0000000..3130c9c
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-em-terratec.c
@@ -0,0 +1,69 @@
+/* em-terratec.h - Keytable for em_terratec Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode em_terratec[] = {
+	{ 0x01, KEY_CHANNEL },
+	{ 0x02, KEY_SELECT },
+	{ 0x03, KEY_MUTE },
+	{ 0x04, KEY_POWER },
+	{ 0x05, KEY_1 },
+	{ 0x06, KEY_2 },
+	{ 0x07, KEY_3 },
+	{ 0x08, KEY_CHANNELUP },
+	{ 0x09, KEY_4 },
+	{ 0x0a, KEY_5 },
+	{ 0x0b, KEY_6 },
+	{ 0x0c, KEY_CHANNELDOWN },
+	{ 0x0d, KEY_7 },
+	{ 0x0e, KEY_8 },
+	{ 0x0f, KEY_9 },
+	{ 0x10, KEY_VOLUMEUP },
+	{ 0x11, KEY_0 },
+	{ 0x12, KEY_MENU },
+	{ 0x13, KEY_PRINT },
+	{ 0x14, KEY_VOLUMEDOWN },
+	{ 0x16, KEY_PAUSE },
+	{ 0x18, KEY_RECORD },
+	{ 0x19, KEY_REWIND },
+	{ 0x1a, KEY_PLAY },
+	{ 0x1b, KEY_FORWARD },
+	{ 0x1c, KEY_BACKSPACE },
+	{ 0x1e, KEY_STOP },
+	{ 0x40, KEY_ZOOM },
+};
+
+static struct rc_keymap em_terratec_map = {
+	.map = {
+		.scan    = em_terratec,
+		.size    = ARRAY_SIZE(em_terratec),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_EM_TERRATEC,
+	}
+};
+
+static int __init init_rc_map_em_terratec(void)
+{
+	return ir_register_map(&em_terratec_map);
+}
+
+static void __exit exit_rc_map_em_terratec(void)
+{
+	ir_unregister_map(&em_terratec_map);
+}
+
+module_init(init_rc_map_em_terratec)
+module_exit(exit_rc_map_em_terratec)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-empty.c b/drivers/media/IR/keymaps/rc-empty.c
new file mode 100644
index 0000000..3b338d8
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-empty.c
@@ -0,0 +1,44 @@
+/* empty.h - Keytable for empty Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* empty keytable, can be used as placeholder for not-yet created keytables */
+
+static struct ir_scancode empty[] = {
+	{ 0x2a, KEY_COFFEE },
+};
+
+static struct rc_keymap empty_map = {
+	.map = {
+		.scan    = empty,
+		.size    = ARRAY_SIZE(empty),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_EMPTY,
+	}
+};
+
+static int __init init_rc_map_empty(void)
+{
+	return ir_register_map(&empty_map);
+}
+
+static void __exit exit_rc_map_empty(void)
+{
+	ir_unregister_map(&empty_map);
+}
+
+module_init(init_rc_map_empty)
+module_exit(exit_rc_map_empty)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-encore-enltv-fm53.c b/drivers/media/IR/keymaps/rc-encore-enltv-fm53.c
new file mode 100644
index 0000000..4b81696
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-encore-enltv-fm53.c
@@ -0,0 +1,81 @@
+/* encore-enltv-fm53.h - Keytable for encore_enltv_fm53 Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Encore ENLTV-FM v5.3
+   Mauro Carvalho Chehab <mchehab@infradead.org>
+ */
+
+static struct ir_scancode encore_enltv_fm53[] = {
+	{ 0x10, KEY_POWER2},
+	{ 0x06, KEY_MUTE},
+
+	{ 0x09, KEY_1},
+	{ 0x1d, KEY_2},
+	{ 0x1f, KEY_3},
+	{ 0x19, KEY_4},
+	{ 0x1b, KEY_5},
+	{ 0x11, KEY_6},
+	{ 0x17, KEY_7},
+	{ 0x12, KEY_8},
+	{ 0x16, KEY_9},
+	{ 0x48, KEY_0},
+
+	{ 0x04, KEY_LIST},		/* -/-- */
+	{ 0x40, KEY_LAST},		/* recall */
+
+	{ 0x02, KEY_MODE},		/* TV/AV */
+	{ 0x05, KEY_CAMERA},		/* SNAPSHOT */
+
+	{ 0x4c, KEY_CHANNELUP},		/* UP */
+	{ 0x00, KEY_CHANNELDOWN},	/* DOWN */
+	{ 0x0d, KEY_VOLUMEUP},		/* RIGHT */
+	{ 0x15, KEY_VOLUMEDOWN},	/* LEFT */
+	{ 0x49, KEY_ENTER},		/* OK */
+
+	{ 0x54, KEY_RECORD},
+	{ 0x4d, KEY_PLAY},		/* pause */
+
+	{ 0x1e, KEY_MENU},		/* video setting */
+	{ 0x0e, KEY_RIGHT},		/* <- */
+	{ 0x1a, KEY_LEFT},		/* -> */
+
+	{ 0x0a, KEY_CLEAR},		/* video default */
+	{ 0x0c, KEY_ZOOM},		/* hide pannel */
+	{ 0x47, KEY_SLEEP},		/* shutdown */
+};
+
+static struct rc_keymap encore_enltv_fm53_map = {
+	.map = {
+		.scan    = encore_enltv_fm53,
+		.size    = ARRAY_SIZE(encore_enltv_fm53),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_ENCORE_ENLTV_FM53,
+	}
+};
+
+static int __init init_rc_map_encore_enltv_fm53(void)
+{
+	return ir_register_map(&encore_enltv_fm53_map);
+}
+
+static void __exit exit_rc_map_encore_enltv_fm53(void)
+{
+	ir_unregister_map(&encore_enltv_fm53_map);
+}
+
+module_init(init_rc_map_encore_enltv_fm53)
+module_exit(exit_rc_map_encore_enltv_fm53)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-encore-enltv.c b/drivers/media/IR/keymaps/rc-encore-enltv.c
new file mode 100644
index 0000000..9fabffd2
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-encore-enltv.c
@@ -0,0 +1,112 @@
+/* encore-enltv.h - Keytable for encore_enltv Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Encore ENLTV-FM  - black plastic, white front cover with white glowing buttons
+    Juan Pablo Sormani <sorman@gmail.com> */
+
+static struct ir_scancode encore_enltv[] = {
+
+	/* Power button does nothing, neither in Windows app,
+	 although it sends data (used for BIOS wakeup?) */
+	{ 0x0d, KEY_MUTE },
+
+	{ 0x1e, KEY_TV },
+	{ 0x00, KEY_VIDEO },
+	{ 0x01, KEY_AUDIO },		/* music */
+	{ 0x02, KEY_MHP },		/* picture */
+
+	{ 0x1f, KEY_1 },
+	{ 0x03, KEY_2 },
+	{ 0x04, KEY_3 },
+	{ 0x05, KEY_4 },
+	{ 0x1c, KEY_5 },
+	{ 0x06, KEY_6 },
+	{ 0x07, KEY_7 },
+	{ 0x08, KEY_8 },
+	{ 0x1d, KEY_9 },
+	{ 0x0a, KEY_0 },
+
+	{ 0x09, KEY_LIST },		/* -/-- */
+	{ 0x0b, KEY_LAST },		/* recall */
+
+	{ 0x14, KEY_HOME },		/* win start menu */
+	{ 0x15, KEY_EXIT },		/* exit */
+	{ 0x16, KEY_CHANNELUP },	/* UP */
+	{ 0x12, KEY_CHANNELDOWN },	/* DOWN */
+	{ 0x0c, KEY_VOLUMEUP },		/* RIGHT */
+	{ 0x17, KEY_VOLUMEDOWN },	/* LEFT */
+
+	{ 0x18, KEY_ENTER },		/* OK */
+
+	{ 0x0e, KEY_ESC },
+	{ 0x13, KEY_CYCLEWINDOWS },	/* desktop */
+	{ 0x11, KEY_TAB },
+	{ 0x19, KEY_SWITCHVIDEOMODE },	/* switch */
+
+	{ 0x1a, KEY_MENU },
+	{ 0x1b, KEY_ZOOM },		/* fullscreen */
+	{ 0x44, KEY_TIME },		/* time shift */
+	{ 0x40, KEY_MODE },		/* source */
+
+	{ 0x5a, KEY_RECORD },
+	{ 0x42, KEY_PLAY },		/* play/pause */
+	{ 0x45, KEY_STOP },
+	{ 0x43, KEY_CAMERA },		/* camera icon */
+
+	{ 0x48, KEY_REWIND },
+	{ 0x4a, KEY_FASTFORWARD },
+	{ 0x49, KEY_PREVIOUS },
+	{ 0x4b, KEY_NEXT },
+
+	{ 0x4c, KEY_FAVORITES },	/* tv wall */
+	{ 0x4d, KEY_SOUND },		/* DVD sound */
+	{ 0x4e, KEY_LANGUAGE },		/* DVD lang */
+	{ 0x4f, KEY_TEXT },		/* DVD text */
+
+	{ 0x50, KEY_SLEEP },		/* shutdown */
+	{ 0x51, KEY_MODE },		/* stereo > main */
+	{ 0x52, KEY_SELECT },		/* stereo > sap */
+	{ 0x53, KEY_PROG1 },		/* teletext */
+
+
+	{ 0x59, KEY_RED },		/* AP1 */
+	{ 0x41, KEY_GREEN },		/* AP2 */
+	{ 0x47, KEY_YELLOW },		/* AP3 */
+	{ 0x57, KEY_BLUE },		/* AP4 */
+};
+
+static struct rc_keymap encore_enltv_map = {
+	.map = {
+		.scan    = encore_enltv,
+		.size    = ARRAY_SIZE(encore_enltv),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_ENCORE_ENLTV,
+	}
+};
+
+static int __init init_rc_map_encore_enltv(void)
+{
+	return ir_register_map(&encore_enltv_map);
+}
+
+static void __exit exit_rc_map_encore_enltv(void)
+{
+	ir_unregister_map(&encore_enltv_map);
+}
+
+module_init(init_rc_map_encore_enltv)
+module_exit(exit_rc_map_encore_enltv)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-encore-enltv2.c b/drivers/media/IR/keymaps/rc-encore-enltv2.c
new file mode 100644
index 0000000..efefd51
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-encore-enltv2.c
@@ -0,0 +1,90 @@
+/* encore-enltv2.h - Keytable for encore_enltv2 Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Encore ENLTV2-FM  - silver plastic - "Wand Media" written at the botton
+    Mauro Carvalho Chehab <mchehab@infradead.org> */
+
+static struct ir_scancode encore_enltv2[] = {
+	{ 0x4c, KEY_POWER2 },
+	{ 0x4a, KEY_TUNER },
+	{ 0x40, KEY_1 },
+	{ 0x60, KEY_2 },
+	{ 0x50, KEY_3 },
+	{ 0x70, KEY_4 },
+	{ 0x48, KEY_5 },
+	{ 0x68, KEY_6 },
+	{ 0x58, KEY_7 },
+	{ 0x78, KEY_8 },
+	{ 0x44, KEY_9 },
+	{ 0x54, KEY_0 },
+
+	{ 0x64, KEY_LAST },		/* +100 */
+	{ 0x4e, KEY_AGAIN },		/* Recall */
+
+	{ 0x6c, KEY_SWITCHVIDEOMODE },	/* Video Source */
+	{ 0x5e, KEY_MENU },
+	{ 0x56, KEY_SCREEN },
+	{ 0x7a, KEY_SETUP },
+
+	{ 0x46, KEY_MUTE },
+	{ 0x5c, KEY_MODE },		/* Stereo */
+	{ 0x74, KEY_INFO },
+	{ 0x7c, KEY_CLEAR },
+
+	{ 0x55, KEY_UP },
+	{ 0x49, KEY_DOWN },
+	{ 0x7e, KEY_LEFT },
+	{ 0x59, KEY_RIGHT },
+	{ 0x6a, KEY_ENTER },
+
+	{ 0x42, KEY_VOLUMEUP },
+	{ 0x62, KEY_VOLUMEDOWN },
+	{ 0x52, KEY_CHANNELUP },
+	{ 0x72, KEY_CHANNELDOWN },
+
+	{ 0x41, KEY_RECORD },
+	{ 0x51, KEY_CAMERA },		/* Snapshot */
+	{ 0x75, KEY_TIME },		/* Timeshift */
+	{ 0x71, KEY_TV2 },		/* PIP */
+
+	{ 0x45, KEY_REWIND },
+	{ 0x6f, KEY_PAUSE },
+	{ 0x7d, KEY_FORWARD },
+	{ 0x79, KEY_STOP },
+};
+
+static struct rc_keymap encore_enltv2_map = {
+	.map = {
+		.scan    = encore_enltv2,
+		.size    = ARRAY_SIZE(encore_enltv2),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_ENCORE_ENLTV2,
+	}
+};
+
+static int __init init_rc_map_encore_enltv2(void)
+{
+	return ir_register_map(&encore_enltv2_map);
+}
+
+static void __exit exit_rc_map_encore_enltv2(void)
+{
+	ir_unregister_map(&encore_enltv2_map);
+}
+
+module_init(init_rc_map_encore_enltv2)
+module_exit(exit_rc_map_encore_enltv2)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-evga-indtube.c b/drivers/media/IR/keymaps/rc-evga-indtube.c
new file mode 100644
index 0000000..3f3fb13
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-evga-indtube.c
@@ -0,0 +1,61 @@
+/* evga-indtube.h - Keytable for evga_indtube Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* EVGA inDtube
+   Devin Heitmueller <devin.heitmueller@gmail.com>
+ */
+
+static struct ir_scancode evga_indtube[] = {
+	{ 0x12, KEY_POWER},
+	{ 0x02, KEY_MODE},	/* TV */
+	{ 0x14, KEY_MUTE},
+	{ 0x1a, KEY_CHANNELUP},
+	{ 0x16, KEY_TV2},	/* PIP */
+	{ 0x1d, KEY_VOLUMEUP},
+	{ 0x05, KEY_CHANNELDOWN},
+	{ 0x0f, KEY_PLAYPAUSE},
+	{ 0x19, KEY_VOLUMEDOWN},
+	{ 0x1c, KEY_REWIND},
+	{ 0x0d, KEY_RECORD},
+	{ 0x18, KEY_FORWARD},
+	{ 0x1e, KEY_PREVIOUS},
+	{ 0x1b, KEY_STOP},
+	{ 0x1f, KEY_NEXT},
+	{ 0x13, KEY_CAMERA},
+};
+
+static struct rc_keymap evga_indtube_map = {
+	.map = {
+		.scan    = evga_indtube,
+		.size    = ARRAY_SIZE(evga_indtube),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_EVGA_INDTUBE,
+	}
+};
+
+static int __init init_rc_map_evga_indtube(void)
+{
+	return ir_register_map(&evga_indtube_map);
+}
+
+static void __exit exit_rc_map_evga_indtube(void)
+{
+	ir_unregister_map(&evga_indtube_map);
+}
+
+module_init(init_rc_map_evga_indtube)
+module_exit(exit_rc_map_evga_indtube)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-eztv.c b/drivers/media/IR/keymaps/rc-eztv.c
new file mode 100644
index 0000000..660907a
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-eztv.c
@@ -0,0 +1,96 @@
+/* eztv.h - Keytable for eztv Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Alfons Geser <a.geser@cox.net>
+ * updates from Job D. R. Borges <jobdrb@ig.com.br> */
+
+static struct ir_scancode eztv[] = {
+	{ 0x12, KEY_POWER },
+	{ 0x01, KEY_TV },	/* DVR */
+	{ 0x15, KEY_DVD },	/* DVD */
+	{ 0x17, KEY_AUDIO },	/* music */
+				/* DVR mode / DVD mode / music mode */
+
+	{ 0x1b, KEY_MUTE },	/* mute */
+	{ 0x02, KEY_LANGUAGE },	/* MTS/SAP / audio / autoseek */
+	{ 0x1e, KEY_SUBTITLE },	/* closed captioning / subtitle / seek */
+	{ 0x16, KEY_ZOOM },	/* full screen */
+	{ 0x1c, KEY_VIDEO },	/* video source / eject / delall */
+	{ 0x1d, KEY_RESTART },	/* playback / angle / del */
+	{ 0x2f, KEY_SEARCH },	/* scan / menu / playlist */
+	{ 0x30, KEY_CHANNEL },	/* CH surfing / bookmark / memo */
+
+	{ 0x31, KEY_HELP },	/* help */
+	{ 0x32, KEY_MODE },	/* num/memo */
+	{ 0x33, KEY_ESC },	/* cancel */
+
+	{ 0x0c, KEY_UP },	/* up */
+	{ 0x10, KEY_DOWN },	/* down */
+	{ 0x08, KEY_LEFT },	/* left */
+	{ 0x04, KEY_RIGHT },	/* right */
+	{ 0x03, KEY_SELECT },	/* select */
+
+	{ 0x1f, KEY_REWIND },	/* rewind */
+	{ 0x20, KEY_PLAYPAUSE },/* play/pause */
+	{ 0x29, KEY_FORWARD },	/* forward */
+	{ 0x14, KEY_AGAIN },	/* repeat */
+	{ 0x2b, KEY_RECORD },	/* recording */
+	{ 0x2c, KEY_STOP },	/* stop */
+	{ 0x2d, KEY_PLAY },	/* play */
+	{ 0x2e, KEY_CAMERA },	/* snapshot / shuffle */
+
+	{ 0x00, KEY_0 },
+	{ 0x05, KEY_1 },
+	{ 0x06, KEY_2 },
+	{ 0x07, KEY_3 },
+	{ 0x09, KEY_4 },
+	{ 0x0a, KEY_5 },
+	{ 0x0b, KEY_6 },
+	{ 0x0d, KEY_7 },
+	{ 0x0e, KEY_8 },
+	{ 0x0f, KEY_9 },
+
+	{ 0x2a, KEY_VOLUMEUP },
+	{ 0x11, KEY_VOLUMEDOWN },
+	{ 0x18, KEY_CHANNELUP },/* CH.tracking up */
+	{ 0x19, KEY_CHANNELDOWN },/* CH.tracking down */
+
+	{ 0x13, KEY_ENTER },	/* enter */
+	{ 0x21, KEY_DOT },	/* . (decimal dot) */
+};
+
+static struct rc_keymap eztv_map = {
+	.map = {
+		.scan    = eztv,
+		.size    = ARRAY_SIZE(eztv),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_EZTV,
+	}
+};
+
+static int __init init_rc_map_eztv(void)
+{
+	return ir_register_map(&eztv_map);
+}
+
+static void __exit exit_rc_map_eztv(void)
+{
+	ir_unregister_map(&eztv_map);
+}
+
+module_init(init_rc_map_eztv)
+module_exit(exit_rc_map_eztv)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-flydvb.c b/drivers/media/IR/keymaps/rc-flydvb.c
new file mode 100644
index 0000000..a173c81
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-flydvb.c
@@ -0,0 +1,77 @@
+/* flydvb.h - Keytable for flydvb Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode flydvb[] = {
+	{ 0x01, KEY_ZOOM },		/* Full Screen */
+	{ 0x00, KEY_POWER },		/* Power */
+
+	{ 0x03, KEY_1 },
+	{ 0x04, KEY_2 },
+	{ 0x05, KEY_3 },
+	{ 0x07, KEY_4 },
+	{ 0x08, KEY_5 },
+	{ 0x09, KEY_6 },
+	{ 0x0b, KEY_7 },
+	{ 0x0c, KEY_8 },
+	{ 0x0d, KEY_9 },
+	{ 0x06, KEY_AGAIN },		/* Recall */
+	{ 0x0f, KEY_0 },
+	{ 0x10, KEY_MUTE },		/* Mute */
+	{ 0x02, KEY_RADIO },		/* TV/Radio */
+	{ 0x1b, KEY_LANGUAGE },		/* SAP (Second Audio Program) */
+
+	{ 0x14, KEY_VOLUMEUP },		/* VOL+ */
+	{ 0x17, KEY_VOLUMEDOWN },	/* VOL- */
+	{ 0x12, KEY_CHANNELUP },	/* CH+ */
+	{ 0x13, KEY_CHANNELDOWN },	/* CH- */
+	{ 0x1d, KEY_ENTER },		/* Enter */
+
+	{ 0x1a, KEY_MODE },		/* PIP */
+	{ 0x18, KEY_TUNER },		/* Source */
+
+	{ 0x1e, KEY_RECORD },		/* Record/Pause */
+	{ 0x15, KEY_ANGLE },		/* Swap (no label on key) */
+	{ 0x1c, KEY_PAUSE },		/* Timeshift/Pause */
+	{ 0x19, KEY_BACK },		/* Rewind << */
+	{ 0x0a, KEY_PLAYPAUSE },	/* Play/Pause */
+	{ 0x1f, KEY_FORWARD },		/* Forward >> */
+	{ 0x16, KEY_PREVIOUS },		/* Back |<< */
+	{ 0x11, KEY_STOP },		/* Stop */
+	{ 0x0e, KEY_NEXT },		/* End >>| */
+};
+
+static struct rc_keymap flydvb_map = {
+	.map = {
+		.scan    = flydvb,
+		.size    = ARRAY_SIZE(flydvb),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_FLYDVB,
+	}
+};
+
+static int __init init_rc_map_flydvb(void)
+{
+	return ir_register_map(&flydvb_map);
+}
+
+static void __exit exit_rc_map_flydvb(void)
+{
+	ir_unregister_map(&flydvb_map);
+}
+
+module_init(init_rc_map_flydvb)
+module_exit(exit_rc_map_flydvb)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-flyvideo.c b/drivers/media/IR/keymaps/rc-flyvideo.c
new file mode 100644
index 0000000..9c73043
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-flyvideo.c
@@ -0,0 +1,70 @@
+/* flyvideo.h - Keytable for flyvideo Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode flyvideo[] = {
+	{ 0x0f, KEY_0 },
+	{ 0x03, KEY_1 },
+	{ 0x04, KEY_2 },
+	{ 0x05, KEY_3 },
+	{ 0x07, KEY_4 },
+	{ 0x08, KEY_5 },
+	{ 0x09, KEY_6 },
+	{ 0x0b, KEY_7 },
+	{ 0x0c, KEY_8 },
+	{ 0x0d, KEY_9 },
+
+	{ 0x0e, KEY_MODE },	/* Air/Cable */
+	{ 0x11, KEY_VIDEO },	/* Video */
+	{ 0x15, KEY_AUDIO },	/* Audio */
+	{ 0x00, KEY_POWER },	/* Power */
+	{ 0x18, KEY_TUNER },	/* AV Source */
+	{ 0x02, KEY_ZOOM },	/* Fullscreen */
+	{ 0x1a, KEY_LANGUAGE },	/* Stereo */
+	{ 0x1b, KEY_MUTE },	/* Mute */
+	{ 0x14, KEY_VOLUMEUP },	/* Volume + */
+	{ 0x17, KEY_VOLUMEDOWN },/* Volume - */
+	{ 0x12, KEY_CHANNELUP },/* Channel + */
+	{ 0x13, KEY_CHANNELDOWN },/* Channel - */
+	{ 0x06, KEY_AGAIN },	/* Recall */
+	{ 0x10, KEY_ENTER },	/* Enter */
+
+	{ 0x19, KEY_BACK },	/* Rewind  ( <<< ) */
+	{ 0x1f, KEY_FORWARD },	/* Forward ( >>> ) */
+	{ 0x0a, KEY_ANGLE },	/* no label, may be used as the PAUSE button */
+};
+
+static struct rc_keymap flyvideo_map = {
+	.map = {
+		.scan    = flyvideo,
+		.size    = ARRAY_SIZE(flyvideo),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_FLYVIDEO,
+	}
+};
+
+static int __init init_rc_map_flyvideo(void)
+{
+	return ir_register_map(&flyvideo_map);
+}
+
+static void __exit exit_rc_map_flyvideo(void)
+{
+	ir_unregister_map(&flyvideo_map);
+}
+
+module_init(init_rc_map_flyvideo)
+module_exit(exit_rc_map_flyvideo)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-fusionhdtv-mce.c b/drivers/media/IR/keymaps/rc-fusionhdtv-mce.c
new file mode 100644
index 0000000..cdb1038
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-fusionhdtv-mce.c
@@ -0,0 +1,98 @@
+/* fusionhdtv-mce.h - Keytable for fusionhdtv_mce Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* DViCO FUSION HDTV MCE remote */
+
+static struct ir_scancode fusionhdtv_mce[] = {
+
+	{ 0x0b, KEY_1 },
+	{ 0x17, KEY_2 },
+	{ 0x1b, KEY_3 },
+	{ 0x07, KEY_4 },
+	{ 0x50, KEY_5 },
+	{ 0x54, KEY_6 },
+	{ 0x48, KEY_7 },
+	{ 0x4c, KEY_8 },
+	{ 0x58, KEY_9 },
+	{ 0x03, KEY_0 },
+
+	{ 0x5e, KEY_OK },
+	{ 0x51, KEY_UP },
+	{ 0x53, KEY_DOWN },
+	{ 0x5b, KEY_LEFT },
+	{ 0x5f, KEY_RIGHT },
+
+	{ 0x02, KEY_TV },		/* Labeled DTV on remote */
+	{ 0x0e, KEY_MP3 },
+	{ 0x1a, KEY_DVD },
+	{ 0x1e, KEY_FAVORITES },	/* Labeled CPF on remote */
+	{ 0x16, KEY_SETUP },
+	{ 0x46, KEY_POWER2 },		/* TV On/Off button on remote */
+	{ 0x0a, KEY_EPG },		/* Labeled Guide on remote */
+
+	{ 0x49, KEY_BACK },
+	{ 0x59, KEY_INFO },		/* Labeled MORE on remote */
+	{ 0x4d, KEY_MENU },		/* Labeled DVDMENU on remote */
+	{ 0x55, KEY_CYCLEWINDOWS },	/* Labeled ALT-TAB on remote */
+
+	{ 0x0f, KEY_PREVIOUSSONG },	/* Labeled |<< REPLAY on remote */
+	{ 0x12, KEY_NEXTSONG },		/* Labeled >>| SKIP on remote */
+	{ 0x42, KEY_ENTER },		/* Labeled START with a green
+					   MS windows logo on remote */
+
+	{ 0x15, KEY_VOLUMEUP },
+	{ 0x05, KEY_VOLUMEDOWN },
+	{ 0x11, KEY_CHANNELUP },
+	{ 0x09, KEY_CHANNELDOWN },
+
+	{ 0x52, KEY_CAMERA },
+	{ 0x5a, KEY_TUNER },
+	{ 0x19, KEY_OPEN },
+
+	{ 0x13, KEY_MODE },		/* 4:3 16:9 select */
+	{ 0x1f, KEY_ZOOM },
+
+	{ 0x43, KEY_REWIND },
+	{ 0x47, KEY_PLAYPAUSE },
+	{ 0x4f, KEY_FASTFORWARD },
+	{ 0x57, KEY_MUTE },
+	{ 0x0d, KEY_STOP },
+	{ 0x01, KEY_RECORD },
+	{ 0x4e, KEY_POWER },
+};
+
+static struct rc_keymap fusionhdtv_mce_map = {
+	.map = {
+		.scan    = fusionhdtv_mce,
+		.size    = ARRAY_SIZE(fusionhdtv_mce),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_FUSIONHDTV_MCE,
+	}
+};
+
+static int __init init_rc_map_fusionhdtv_mce(void)
+{
+	return ir_register_map(&fusionhdtv_mce_map);
+}
+
+static void __exit exit_rc_map_fusionhdtv_mce(void)
+{
+	ir_unregister_map(&fusionhdtv_mce_map);
+}
+
+module_init(init_rc_map_fusionhdtv_mce)
+module_exit(exit_rc_map_fusionhdtv_mce)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-gadmei-rm008z.c b/drivers/media/IR/keymaps/rc-gadmei-rm008z.c
new file mode 100644
index 0000000..c16c0d1
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-gadmei-rm008z.c
@@ -0,0 +1,81 @@
+/* gadmei-rm008z.h - Keytable for gadmei_rm008z Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* GADMEI UTV330+ RM008Z remote
+   Shine Liu <shinel@foxmail.com>
+ */
+
+static struct ir_scancode gadmei_rm008z[] = {
+	{ 0x14, KEY_POWER2},		/* POWER OFF */
+	{ 0x0c, KEY_MUTE},		/* MUTE */
+
+	{ 0x18, KEY_TV},		/* TV */
+	{ 0x0e, KEY_VIDEO},		/* AV */
+	{ 0x0b, KEY_AUDIO},		/* SV */
+	{ 0x0f, KEY_RADIO},		/* FM */
+
+	{ 0x00, KEY_1},
+	{ 0x01, KEY_2},
+	{ 0x02, KEY_3},
+	{ 0x03, KEY_4},
+	{ 0x04, KEY_5},
+	{ 0x05, KEY_6},
+	{ 0x06, KEY_7},
+	{ 0x07, KEY_8},
+	{ 0x08, KEY_9},
+	{ 0x09, KEY_0},
+	{ 0x0a, KEY_INFO},		/* OSD */
+	{ 0x1c, KEY_BACKSPACE},		/* LAST */
+
+	{ 0x0d, KEY_PLAY},		/* PLAY */
+	{ 0x1e, KEY_CAMERA},		/* SNAPSHOT */
+	{ 0x1a, KEY_RECORD},		/* RECORD */
+	{ 0x17, KEY_STOP},		/* STOP */
+
+	{ 0x1f, KEY_UP},		/* UP */
+	{ 0x44, KEY_DOWN},		/* DOWN */
+	{ 0x46, KEY_TAB},		/* BACK */
+	{ 0x4a, KEY_ZOOM},		/* FULLSECREEN */
+
+	{ 0x10, KEY_VOLUMEUP},		/* VOLUMEUP */
+	{ 0x11, KEY_VOLUMEDOWN},	/* VOLUMEDOWN */
+	{ 0x12, KEY_CHANNELUP},		/* CHANNELUP */
+	{ 0x13, KEY_CHANNELDOWN},	/* CHANNELDOWN */
+	{ 0x15, KEY_ENTER},		/* OK */
+};
+
+static struct rc_keymap gadmei_rm008z_map = {
+	.map = {
+		.scan    = gadmei_rm008z,
+		.size    = ARRAY_SIZE(gadmei_rm008z),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_GADMEI_RM008Z,
+	}
+};
+
+static int __init init_rc_map_gadmei_rm008z(void)
+{
+	return ir_register_map(&gadmei_rm008z_map);
+}
+
+static void __exit exit_rc_map_gadmei_rm008z(void)
+{
+	ir_unregister_map(&gadmei_rm008z_map);
+}
+
+module_init(init_rc_map_gadmei_rm008z)
+module_exit(exit_rc_map_gadmei_rm008z)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-genius-tvgo-a11mce.c b/drivers/media/IR/keymaps/rc-genius-tvgo-a11mce.c
new file mode 100644
index 0000000..89f8e38
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-genius-tvgo-a11mce.c
@@ -0,0 +1,84 @@
+/* genius-tvgo-a11mce.h - Keytable for genius_tvgo_a11mce Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/*
+ * Remote control for the Genius TVGO A11MCE
+ * Adrian Pardini <pardo.bsso@gmail.com>
+ */
+
+static struct ir_scancode genius_tvgo_a11mce[] = {
+	/* Keys 0 to 9 */
+	{ 0x48, KEY_0 },
+	{ 0x09, KEY_1 },
+	{ 0x1d, KEY_2 },
+	{ 0x1f, KEY_3 },
+	{ 0x19, KEY_4 },
+	{ 0x1b, KEY_5 },
+	{ 0x11, KEY_6 },
+	{ 0x17, KEY_7 },
+	{ 0x12, KEY_8 },
+	{ 0x16, KEY_9 },
+
+	{ 0x54, KEY_RECORD },		/* recording */
+	{ 0x06, KEY_MUTE },		/* mute */
+	{ 0x10, KEY_POWER },
+	{ 0x40, KEY_LAST },		/* recall */
+	{ 0x4c, KEY_CHANNELUP },	/* channel / program + */
+	{ 0x00, KEY_CHANNELDOWN },	/* channel / program - */
+	{ 0x0d, KEY_VOLUMEUP },
+	{ 0x15, KEY_VOLUMEDOWN },
+	{ 0x4d, KEY_OK },		/* also labeled as Pause */
+	{ 0x1c, KEY_ZOOM },		/* full screen and Stop*/
+	{ 0x02, KEY_MODE },		/* AV Source or Rewind*/
+	{ 0x04, KEY_LIST },		/* -/-- */
+	/* small arrows above numbers */
+	{ 0x1a, KEY_NEXT },		/* also Fast Forward */
+	{ 0x0e, KEY_PREVIOUS },		/* also Rewind */
+	/* these are in a rather non standard layout and have
+	an alternate name written */
+	{ 0x1e, KEY_UP },		/* Video Setting */
+	{ 0x0a, KEY_DOWN },		/* Video Default */
+	{ 0x05, KEY_CAMERA },		/* Snapshot */
+	{ 0x0c, KEY_RIGHT },		/* Hide Panel */
+	/* Four buttons without label */
+	{ 0x49, KEY_RED },
+	{ 0x0b, KEY_GREEN },
+	{ 0x13, KEY_YELLOW },
+	{ 0x50, KEY_BLUE },
+};
+
+static struct rc_keymap genius_tvgo_a11mce_map = {
+	.map = {
+		.scan    = genius_tvgo_a11mce,
+		.size    = ARRAY_SIZE(genius_tvgo_a11mce),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_GENIUS_TVGO_A11MCE,
+	}
+};
+
+static int __init init_rc_map_genius_tvgo_a11mce(void)
+{
+	return ir_register_map(&genius_tvgo_a11mce_map);
+}
+
+static void __exit exit_rc_map_genius_tvgo_a11mce(void)
+{
+	ir_unregister_map(&genius_tvgo_a11mce_map);
+}
+
+module_init(init_rc_map_genius_tvgo_a11mce)
+module_exit(exit_rc_map_genius_tvgo_a11mce)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-gotview7135.c b/drivers/media/IR/keymaps/rc-gotview7135.c
new file mode 100644
index 0000000..52f025b
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-gotview7135.c
@@ -0,0 +1,79 @@
+/* gotview7135.h - Keytable for gotview7135 Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Mike Baikov <mike@baikov.com> */
+
+static struct ir_scancode gotview7135[] = {
+
+	{ 0x11, KEY_POWER },
+	{ 0x35, KEY_TV },
+	{ 0x1b, KEY_0 },
+	{ 0x29, KEY_1 },
+	{ 0x19, KEY_2 },
+	{ 0x39, KEY_3 },
+	{ 0x1f, KEY_4 },
+	{ 0x2c, KEY_5 },
+	{ 0x21, KEY_6 },
+	{ 0x24, KEY_7 },
+	{ 0x18, KEY_8 },
+	{ 0x2b, KEY_9 },
+	{ 0x3b, KEY_AGAIN },	/* LOOP */
+	{ 0x06, KEY_AUDIO },
+	{ 0x31, KEY_PRINT },	/* PREVIEW */
+	{ 0x3e, KEY_VIDEO },
+	{ 0x10, KEY_CHANNELUP },
+	{ 0x20, KEY_CHANNELDOWN },
+	{ 0x0c, KEY_VOLUMEDOWN },
+	{ 0x28, KEY_VOLUMEUP },
+	{ 0x08, KEY_MUTE },
+	{ 0x26, KEY_SEARCH },	/* SCAN */
+	{ 0x3f, KEY_CAMERA },	/* SNAPSHOT */
+	{ 0x12, KEY_RECORD },
+	{ 0x32, KEY_STOP },
+	{ 0x3c, KEY_PLAY },
+	{ 0x1d, KEY_REWIND },
+	{ 0x2d, KEY_PAUSE },
+	{ 0x0d, KEY_FORWARD },
+	{ 0x05, KEY_ZOOM },	/*FULL*/
+
+	{ 0x2a, KEY_F21 },	/* LIVE TIMESHIFT */
+	{ 0x0e, KEY_F22 },	/* MIN TIMESHIFT */
+	{ 0x1e, KEY_TIME },	/* TIMESHIFT */
+	{ 0x38, KEY_F24 },	/* NORMAL TIMESHIFT */
+};
+
+static struct rc_keymap gotview7135_map = {
+	.map = {
+		.scan    = gotview7135,
+		.size    = ARRAY_SIZE(gotview7135),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_GOTVIEW7135,
+	}
+};
+
+static int __init init_rc_map_gotview7135(void)
+{
+	return ir_register_map(&gotview7135_map);
+}
+
+static void __exit exit_rc_map_gotview7135(void)
+{
+	ir_unregister_map(&gotview7135_map);
+}
+
+module_init(init_rc_map_gotview7135)
+module_exit(exit_rc_map_gotview7135)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-hauppauge-new.c b/drivers/media/IR/keymaps/rc-hauppauge-new.c
new file mode 100644
index 0000000..c6f8cd7
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-hauppauge-new.c
@@ -0,0 +1,100 @@
+/* hauppauge-new.h - Keytable for hauppauge_new Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Hauppauge: the newer, gray remotes (seems there are multiple
+ * slightly different versions), shipped with cx88+ivtv cards.
+ * almost rc5 coding, but some non-standard keys */
+
+static struct ir_scancode hauppauge_new[] = {
+	/* Keys 0 to 9 */
+	{ 0x00, KEY_0 },
+	{ 0x01, KEY_1 },
+	{ 0x02, KEY_2 },
+	{ 0x03, KEY_3 },
+	{ 0x04, KEY_4 },
+	{ 0x05, KEY_5 },
+	{ 0x06, KEY_6 },
+	{ 0x07, KEY_7 },
+	{ 0x08, KEY_8 },
+	{ 0x09, KEY_9 },
+
+	{ 0x0a, KEY_TEXT },		/* keypad asterisk as well */
+	{ 0x0b, KEY_RED },		/* red button */
+	{ 0x0c, KEY_RADIO },
+	{ 0x0d, KEY_MENU },
+	{ 0x0e, KEY_SUBTITLE },		/* also the # key */
+	{ 0x0f, KEY_MUTE },
+	{ 0x10, KEY_VOLUMEUP },
+	{ 0x11, KEY_VOLUMEDOWN },
+	{ 0x12, KEY_PREVIOUS },		/* previous channel */
+	{ 0x14, KEY_UP },
+	{ 0x15, KEY_DOWN },
+	{ 0x16, KEY_LEFT },
+	{ 0x17, KEY_RIGHT },
+	{ 0x18, KEY_VIDEO },		/* Videos */
+	{ 0x19, KEY_AUDIO },		/* Music */
+	/* 0x1a: Pictures - presume this means
+	   "Multimedia Home Platform" -
+	   no "PICTURES" key in input.h
+	 */
+	{ 0x1a, KEY_MHP },
+
+	{ 0x1b, KEY_EPG },		/* Guide */
+	{ 0x1c, KEY_TV },
+	{ 0x1e, KEY_NEXTSONG },		/* skip >| */
+	{ 0x1f, KEY_EXIT },		/* back/exit */
+	{ 0x20, KEY_CHANNELUP },	/* channel / program + */
+	{ 0x21, KEY_CHANNELDOWN },	/* channel / program - */
+	{ 0x22, KEY_CHANNEL },		/* source (old black remote) */
+	{ 0x24, KEY_PREVIOUSSONG },	/* replay |< */
+	{ 0x25, KEY_ENTER },		/* OK */
+	{ 0x26, KEY_SLEEP },		/* minimize (old black remote) */
+	{ 0x29, KEY_BLUE },		/* blue key */
+	{ 0x2e, KEY_GREEN },		/* green button */
+	{ 0x30, KEY_PAUSE },		/* pause */
+	{ 0x32, KEY_REWIND },		/* backward << */
+	{ 0x34, KEY_FASTFORWARD },	/* forward >> */
+	{ 0x35, KEY_PLAY },
+	{ 0x36, KEY_STOP },
+	{ 0x37, KEY_RECORD },		/* recording */
+	{ 0x38, KEY_YELLOW },		/* yellow key */
+	{ 0x3b, KEY_SELECT },		/* top right button */
+	{ 0x3c, KEY_ZOOM },		/* full */
+	{ 0x3d, KEY_POWER },		/* system power (green button) */
+};
+
+static struct rc_keymap hauppauge_new_map = {
+	.map = {
+		.scan    = hauppauge_new,
+		.size    = ARRAY_SIZE(hauppauge_new),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_HAUPPAUGE_NEW,
+	}
+};
+
+static int __init init_rc_map_hauppauge_new(void)
+{
+	return ir_register_map(&hauppauge_new_map);
+}
+
+static void __exit exit_rc_map_hauppauge_new(void)
+{
+	ir_unregister_map(&hauppauge_new_map);
+}
+
+module_init(init_rc_map_hauppauge_new)
+module_exit(exit_rc_map_hauppauge_new)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-imon-mce.c b/drivers/media/IR/keymaps/rc-imon-mce.c
new file mode 100644
index 0000000..e49f350
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-imon-mce.c
@@ -0,0 +1,142 @@
+/* rc5-imon-mce.c - Keytable for Windows Media Center RC-6 remotes for use
+ * with the SoundGraph iMON/Antec Veris hardware IR decoder
+ *
+ * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* mce-mode imon mce remote key table */
+static struct ir_scancode imon_mce[] = {
+	/* keys sorted mostly by frequency of use to optimize lookups */
+	{ 0x800ff415, KEY_REWIND },
+	{ 0x800ff414, KEY_FASTFORWARD },
+	{ 0x800ff41b, KEY_PREVIOUS },
+	{ 0x800ff41a, KEY_NEXT },
+
+	{ 0x800ff416, KEY_PLAY },
+	{ 0x800ff418, KEY_PAUSE },
+	{ 0x800ff419, KEY_STOP },
+	{ 0x800ff417, KEY_RECORD },
+
+	{ 0x02000052, KEY_UP },
+	{ 0x02000051, KEY_DOWN },
+	{ 0x02000050, KEY_LEFT },
+	{ 0x0200004f, KEY_RIGHT },
+
+	{ 0x800ff41e, KEY_UP },
+	{ 0x800ff41f, KEY_DOWN },
+	{ 0x800ff420, KEY_LEFT },
+	{ 0x800ff421, KEY_RIGHT },
+
+	/* 0x800ff40b also KEY_NUMERIC_POUND on some receivers */
+	{ 0x800ff40b, KEY_ENTER },
+	{ 0x02000028, KEY_ENTER },
+/* the OK and Enter buttons decode to the same value on some remotes
+	{ 0x02000028, KEY_OK }, */
+	{ 0x800ff422, KEY_OK },
+	{ 0x0200002a, KEY_EXIT },
+	{ 0x800ff423, KEY_EXIT },
+	{ 0x02000029, KEY_DELETE },
+	/* 0x800ff40a also KEY_NUMERIC_STAR on some receivers */
+	{ 0x800ff40a, KEY_DELETE },
+
+	{ 0x800ff40e, KEY_MUTE },
+	{ 0x800ff410, KEY_VOLUMEUP },
+	{ 0x800ff411, KEY_VOLUMEDOWN },
+	{ 0x800ff412, KEY_CHANNELUP },
+	{ 0x800ff413, KEY_CHANNELDOWN },
+
+	{ 0x0200001e, KEY_NUMERIC_1 },
+	{ 0x0200001f, KEY_NUMERIC_2 },
+	{ 0x02000020, KEY_NUMERIC_3 },
+	{ 0x02000021, KEY_NUMERIC_4 },
+	{ 0x02000022, KEY_NUMERIC_5 },
+	{ 0x02000023, KEY_NUMERIC_6 },
+	{ 0x02000024, KEY_NUMERIC_7 },
+	{ 0x02000025, KEY_NUMERIC_8 },
+	{ 0x02000026, KEY_NUMERIC_9 },
+	{ 0x02000027, KEY_NUMERIC_0 },
+
+	{ 0x800ff401, KEY_NUMERIC_1 },
+	{ 0x800ff402, KEY_NUMERIC_2 },
+	{ 0x800ff403, KEY_NUMERIC_3 },
+	{ 0x800ff404, KEY_NUMERIC_4 },
+	{ 0x800ff405, KEY_NUMERIC_5 },
+	{ 0x800ff406, KEY_NUMERIC_6 },
+	{ 0x800ff407, KEY_NUMERIC_7 },
+	{ 0x800ff408, KEY_NUMERIC_8 },
+	{ 0x800ff409, KEY_NUMERIC_9 },
+	{ 0x800ff400, KEY_NUMERIC_0 },
+
+	{ 0x02200025, KEY_NUMERIC_STAR },
+	{ 0x02200020, KEY_NUMERIC_POUND },
+	/* 0x800ff41d also KEY_BLUE on some receivers */
+	{ 0x800ff41d, KEY_NUMERIC_STAR },
+	/* 0x800ff41c also KEY_PREVIOUS on some receivers */
+	{ 0x800ff41c, KEY_NUMERIC_POUND },
+
+	{ 0x800ff446, KEY_TV },
+	{ 0x800ff447, KEY_AUDIO }, /* My Music */
+	{ 0x800ff448, KEY_PVR }, /* RecordedTV */
+	{ 0x800ff449, KEY_CAMERA },
+	{ 0x800ff44a, KEY_VIDEO },
+	/* 0x800ff424 also KEY_MENU on some receivers */
+	{ 0x800ff424, KEY_DVD },
+	/* 0x800ff425 also KEY_GREEN on some receivers */
+	{ 0x800ff425, KEY_TUNER }, /* LiveTV */
+	{ 0x800ff450, KEY_RADIO },
+
+	{ 0x800ff44c, KEY_LANGUAGE },
+	{ 0x800ff427, KEY_ZOOM }, /* Aspect */
+
+	{ 0x800ff45b, KEY_RED },
+	{ 0x800ff45c, KEY_GREEN },
+	{ 0x800ff45d, KEY_YELLOW },
+	{ 0x800ff45e, KEY_BLUE },
+
+	{ 0x800ff466, KEY_RED },
+	/* { 0x800ff425, KEY_GREEN }, */
+	{ 0x800ff468, KEY_YELLOW },
+	/* { 0x800ff41d, KEY_BLUE }, */
+
+	{ 0x800ff40f, KEY_INFO },
+	{ 0x800ff426, KEY_EPG }, /* Guide */
+	{ 0x800ff45a, KEY_SUBTITLE }, /* Caption/Teletext */
+	{ 0x800ff44d, KEY_TITLE },
+
+	{ 0x800ff40c, KEY_POWER },
+	{ 0x800ff40d, KEY_PROG1 }, /* Windows MCE button */
+
+};
+
+static struct rc_keymap imon_mce_map = {
+	.map = {
+		.scan    = imon_mce,
+		.size    = ARRAY_SIZE(imon_mce),
+		/* its RC6, but w/a hardware decoder */
+		.ir_type = IR_TYPE_RC6,
+		.name    = RC_MAP_IMON_MCE,
+	}
+};
+
+static int __init init_rc_map_imon_mce(void)
+{
+	return ir_register_map(&imon_mce_map);
+}
+
+static void __exit exit_rc_map_imon_mce(void)
+{
+	ir_unregister_map(&imon_mce_map);
+}
+
+module_init(init_rc_map_imon_mce)
+module_exit(exit_rc_map_imon_mce)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-imon-pad.c b/drivers/media/IR/keymaps/rc-imon-pad.c
new file mode 100644
index 0000000..bc4db72
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-imon-pad.c
@@ -0,0 +1,156 @@
+/* rc5-imon-pad.c - Keytable for SoundGraph iMON PAD and Antec Veris
+ * RM-200 Remote Control
+ *
+ * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/*
+ * standard imon remote key table, which isn't really entirely
+ * "standard", as different receivers decode the same key on the
+ * same remote to different hex codes, and the silkscreened names
+ * vary a bit between the SoundGraph and Antec remotes... ugh.
+ */
+static struct ir_scancode imon_pad[] = {
+	/* keys sorted mostly by frequency of use to optimize lookups */
+	{ 0x2a8195b7, KEY_REWIND },
+	{ 0x298315b7, KEY_REWIND },
+	{ 0x2b8115b7, KEY_FASTFORWARD },
+	{ 0x2b8315b7, KEY_FASTFORWARD },
+	{ 0x2b9115b7, KEY_PREVIOUS },
+	{ 0x298195b7, KEY_NEXT },
+
+	{ 0x2a8115b7, KEY_PLAY },
+	{ 0x2a8315b7, KEY_PLAY },
+	{ 0x2a9115b7, KEY_PAUSE },
+	{ 0x2b9715b7, KEY_STOP },
+	{ 0x298115b7, KEY_RECORD },
+
+	{ 0x01008000, KEY_UP },
+	{ 0x01007f00, KEY_DOWN },
+	{ 0x01000080, KEY_LEFT },
+	{ 0x0100007f, KEY_RIGHT },
+
+	{ 0x2aa515b7, KEY_UP },
+	{ 0x289515b7, KEY_DOWN },
+	{ 0x29a515b7, KEY_LEFT },
+	{ 0x2ba515b7, KEY_RIGHT },
+
+	{ 0x0200002c, KEY_SPACE }, /* Select/Space */
+	{ 0x2a9315b7, KEY_SPACE }, /* Select/Space */
+	{ 0x02000028, KEY_ENTER },
+	{ 0x28a195b7, KEY_ENTER },
+	{ 0x288195b7, KEY_EXIT },
+	{ 0x02000029, KEY_ESC },
+	{ 0x2bb715b7, KEY_ESC },
+	{ 0x0200002a, KEY_BACKSPACE },
+	{ 0x28a115b7, KEY_BACKSPACE },
+
+	{ 0x2b9595b7, KEY_MUTE },
+	{ 0x28a395b7, KEY_VOLUMEUP },
+	{ 0x28a595b7, KEY_VOLUMEDOWN },
+	{ 0x289395b7, KEY_CHANNELUP },
+	{ 0x288795b7, KEY_CHANNELDOWN },
+
+	{ 0x0200001e, KEY_NUMERIC_1 },
+	{ 0x0200001f, KEY_NUMERIC_2 },
+	{ 0x02000020, KEY_NUMERIC_3 },
+	{ 0x02000021, KEY_NUMERIC_4 },
+	{ 0x02000022, KEY_NUMERIC_5 },
+	{ 0x02000023, KEY_NUMERIC_6 },
+	{ 0x02000024, KEY_NUMERIC_7 },
+	{ 0x02000025, KEY_NUMERIC_8 },
+	{ 0x02000026, KEY_NUMERIC_9 },
+	{ 0x02000027, KEY_NUMERIC_0 },
+
+	{ 0x28b595b7, KEY_NUMERIC_1 },
+	{ 0x2bb195b7, KEY_NUMERIC_2 },
+	{ 0x28b195b7, KEY_NUMERIC_3 },
+	{ 0x2a8595b7, KEY_NUMERIC_4 },
+	{ 0x299595b7, KEY_NUMERIC_5 },
+	{ 0x2aa595b7, KEY_NUMERIC_6 },
+	{ 0x2b9395b7, KEY_NUMERIC_7 },
+	{ 0x2a8515b7, KEY_NUMERIC_8 },
+	{ 0x2aa115b7, KEY_NUMERIC_9 },
+	{ 0x2ba595b7, KEY_NUMERIC_0 },
+
+	{ 0x02200025, KEY_NUMERIC_STAR },
+	{ 0x28b515b7, KEY_NUMERIC_STAR },
+	{ 0x02200020, KEY_NUMERIC_POUND },
+	{ 0x29a115b7, KEY_NUMERIC_POUND },
+
+	{ 0x2b8515b7, KEY_VIDEO },
+	{ 0x299195b7, KEY_AUDIO },
+	{ 0x2ba115b7, KEY_CAMERA },
+	{ 0x28a515b7, KEY_TV },
+	{ 0x29a395b7, KEY_DVD },
+	{ 0x29a295b7, KEY_DVD },
+
+	/* the Menu key between DVD and Subtitle on the RM-200... */
+	{ 0x2ba385b7, KEY_MENU },
+	{ 0x2ba395b7, KEY_MENU },
+
+	{ 0x288515b7, KEY_BOOKMARKS },
+	{ 0x2ab715b7, KEY_MEDIA }, /* Thumbnail */
+	{ 0x298595b7, KEY_SUBTITLE },
+	{ 0x2b8595b7, KEY_LANGUAGE },
+
+	{ 0x29a595b7, KEY_ZOOM },
+	{ 0x2aa395b7, KEY_SCREEN }, /* FullScreen */
+
+	{ 0x299115b7, KEY_KEYBOARD },
+	{ 0x299135b7, KEY_KEYBOARD },
+
+	{ 0x01010000, BTN_LEFT },
+	{ 0x01020000, BTN_RIGHT },
+	{ 0x01010080, BTN_LEFT },
+	{ 0x01020080, BTN_RIGHT },
+	{ 0x688301b7, BTN_LEFT },
+	{ 0x688481b7, BTN_RIGHT },
+
+	{ 0x2a9395b7, KEY_CYCLEWINDOWS }, /* TaskSwitcher */
+	{ 0x2b8395b7, KEY_TIME }, /* Timer */
+
+	{ 0x289115b7, KEY_POWER },
+	{ 0x29b195b7, KEY_EJECTCD }, /* the one next to play */
+	{ 0x299395b7, KEY_EJECTCLOSECD }, /* eject (by TaskSw) */
+
+	{ 0x02800000, KEY_CONTEXT_MENU }, /* Left Menu */
+	{ 0x2b8195b7, KEY_CONTEXT_MENU }, /* Left Menu*/
+	{ 0x02000065, KEY_COMPOSE }, /* RightMenu */
+	{ 0x28b715b7, KEY_COMPOSE }, /* RightMenu */
+	{ 0x2ab195b7, KEY_PROG1 }, /* Go or MultiMon */
+	{ 0x29b715b7, KEY_DASHBOARD }, /* AppLauncher */
+};
+
+static struct rc_keymap imon_pad_map = {
+	.map = {
+		.scan    = imon_pad,
+		.size    = ARRAY_SIZE(imon_pad),
+		/* actual protocol details unknown, hardware decoder */
+		.ir_type = IR_TYPE_OTHER,
+		.name    = RC_MAP_IMON_PAD,
+	}
+};
+
+static int __init init_rc_map_imon_pad(void)
+{
+	return ir_register_map(&imon_pad_map);
+}
+
+static void __exit exit_rc_map_imon_pad(void)
+{
+	ir_unregister_map(&imon_pad_map);
+}
+
+module_init(init_rc_map_imon_pad)
+module_exit(exit_rc_map_imon_pad)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-iodata-bctv7e.c b/drivers/media/IR/keymaps/rc-iodata-bctv7e.c
new file mode 100644
index 0000000..ef66002
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-iodata-bctv7e.c
@@ -0,0 +1,88 @@
+/* iodata-bctv7e.h - Keytable for iodata_bctv7e Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* IO-DATA BCTV7E Remote */
+
+static struct ir_scancode iodata_bctv7e[] = {
+	{ 0x40, KEY_TV },
+	{ 0x20, KEY_RADIO },		/* FM */
+	{ 0x60, KEY_EPG },
+	{ 0x00, KEY_POWER },
+
+	/* Keys 0 to 9 */
+	{ 0x44, KEY_0 },		/* 10 */
+	{ 0x50, KEY_1 },
+	{ 0x30, KEY_2 },
+	{ 0x70, KEY_3 },
+	{ 0x48, KEY_4 },
+	{ 0x28, KEY_5 },
+	{ 0x68, KEY_6 },
+	{ 0x58, KEY_7 },
+	{ 0x38, KEY_8 },
+	{ 0x78, KEY_9 },
+
+	{ 0x10, KEY_L },		/* Live */
+	{ 0x08, KEY_TIME },		/* Time Shift */
+
+	{ 0x18, KEY_PLAYPAUSE },	/* Play */
+
+	{ 0x24, KEY_ENTER },		/* 11 */
+	{ 0x64, KEY_ESC },		/* 12 */
+	{ 0x04, KEY_M },		/* Multi */
+
+	{ 0x54, KEY_VIDEO },
+	{ 0x34, KEY_CHANNELUP },
+	{ 0x74, KEY_VOLUMEUP },
+	{ 0x14, KEY_MUTE },
+
+	{ 0x4c, KEY_VCR },		/* SVIDEO */
+	{ 0x2c, KEY_CHANNELDOWN },
+	{ 0x6c, KEY_VOLUMEDOWN },
+	{ 0x0c, KEY_ZOOM },
+
+	{ 0x5c, KEY_PAUSE },
+	{ 0x3c, KEY_RED },		/* || (red) */
+	{ 0x7c, KEY_RECORD },		/* recording */
+	{ 0x1c, KEY_STOP },
+
+	{ 0x41, KEY_REWIND },		/* backward << */
+	{ 0x21, KEY_PLAY },
+	{ 0x61, KEY_FASTFORWARD },	/* forward >> */
+	{ 0x01, KEY_NEXT },		/* skip >| */
+};
+
+static struct rc_keymap iodata_bctv7e_map = {
+	.map = {
+		.scan    = iodata_bctv7e,
+		.size    = ARRAY_SIZE(iodata_bctv7e),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_IODATA_BCTV7E,
+	}
+};
+
+static int __init init_rc_map_iodata_bctv7e(void)
+{
+	return ir_register_map(&iodata_bctv7e_map);
+}
+
+static void __exit exit_rc_map_iodata_bctv7e(void)
+{
+	ir_unregister_map(&iodata_bctv7e_map);
+}
+
+module_init(init_rc_map_iodata_bctv7e)
+module_exit(exit_rc_map_iodata_bctv7e)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-kaiomy.c b/drivers/media/IR/keymaps/rc-kaiomy.c
new file mode 100644
index 0000000..4c7883b
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-kaiomy.c
@@ -0,0 +1,87 @@
+/* kaiomy.h - Keytable for kaiomy Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Kaiomy TVnPC U2
+   Mauro Carvalho Chehab <mchehab@infradead.org>
+ */
+
+static struct ir_scancode kaiomy[] = {
+	{ 0x43, KEY_POWER2},
+	{ 0x01, KEY_LIST},
+	{ 0x0b, KEY_ZOOM},
+	{ 0x03, KEY_POWER},
+
+	{ 0x04, KEY_1},
+	{ 0x08, KEY_2},
+	{ 0x02, KEY_3},
+
+	{ 0x0f, KEY_4},
+	{ 0x05, KEY_5},
+	{ 0x06, KEY_6},
+
+	{ 0x0c, KEY_7},
+	{ 0x0d, KEY_8},
+	{ 0x0a, KEY_9},
+
+	{ 0x11, KEY_0},
+
+	{ 0x09, KEY_CHANNELUP},
+	{ 0x07, KEY_CHANNELDOWN},
+
+	{ 0x0e, KEY_VOLUMEUP},
+	{ 0x13, KEY_VOLUMEDOWN},
+
+	{ 0x10, KEY_HOME},
+	{ 0x12, KEY_ENTER},
+
+	{ 0x14, KEY_RECORD},
+	{ 0x15, KEY_STOP},
+	{ 0x16, KEY_PLAY},
+	{ 0x17, KEY_MUTE},
+
+	{ 0x18, KEY_UP},
+	{ 0x19, KEY_DOWN},
+	{ 0x1a, KEY_LEFT},
+	{ 0x1b, KEY_RIGHT},
+
+	{ 0x1c, KEY_RED},
+	{ 0x1d, KEY_GREEN},
+	{ 0x1e, KEY_YELLOW},
+	{ 0x1f, KEY_BLUE},
+};
+
+static struct rc_keymap kaiomy_map = {
+	.map = {
+		.scan    = kaiomy,
+		.size    = ARRAY_SIZE(kaiomy),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_KAIOMY,
+	}
+};
+
+static int __init init_rc_map_kaiomy(void)
+{
+	return ir_register_map(&kaiomy_map);
+}
+
+static void __exit exit_rc_map_kaiomy(void)
+{
+	ir_unregister_map(&kaiomy_map);
+}
+
+module_init(init_rc_map_kaiomy)
+module_exit(exit_rc_map_kaiomy)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-kworld-315u.c b/drivers/media/IR/keymaps/rc-kworld-315u.c
new file mode 100644
index 0000000..618c817
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-kworld-315u.c
@@ -0,0 +1,83 @@
+/* kworld-315u.h - Keytable for kworld_315u Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Kworld 315U
+ */
+
+static struct ir_scancode kworld_315u[] = {
+	{ 0x6143, KEY_POWER },
+	{ 0x6101, KEY_TUNER },		/* source */
+	{ 0x610b, KEY_ZOOM },
+	{ 0x6103, KEY_POWER2 },		/* shutdown */
+
+	{ 0x6104, KEY_1 },
+	{ 0x6108, KEY_2 },
+	{ 0x6102, KEY_3 },
+	{ 0x6109, KEY_CHANNELUP },
+
+	{ 0x610f, KEY_4 },
+	{ 0x6105, KEY_5 },
+	{ 0x6106, KEY_6 },
+	{ 0x6107, KEY_CHANNELDOWN },
+
+	{ 0x610c, KEY_7 },
+	{ 0x610d, KEY_8 },
+	{ 0x610a, KEY_9 },
+	{ 0x610e, KEY_VOLUMEUP },
+
+	{ 0x6110, KEY_LAST },
+	{ 0x6111, KEY_0 },
+	{ 0x6112, KEY_ENTER },
+	{ 0x6113, KEY_VOLUMEDOWN },
+
+	{ 0x6114, KEY_RECORD },
+	{ 0x6115, KEY_STOP },
+	{ 0x6116, KEY_PLAY },
+	{ 0x6117, KEY_MUTE },
+
+	{ 0x6118, KEY_UP },
+	{ 0x6119, KEY_DOWN },
+	{ 0x611a, KEY_LEFT },
+	{ 0x611b, KEY_RIGHT },
+
+	{ 0x611c, KEY_RED },
+	{ 0x611d, KEY_GREEN },
+	{ 0x611e, KEY_YELLOW },
+	{ 0x611f, KEY_BLUE },
+};
+
+static struct rc_keymap kworld_315u_map = {
+	.map = {
+		.scan    = kworld_315u,
+		.size    = ARRAY_SIZE(kworld_315u),
+		.ir_type = IR_TYPE_NEC,
+		.name    = RC_MAP_KWORLD_315U,
+	}
+};
+
+static int __init init_rc_map_kworld_315u(void)
+{
+	return ir_register_map(&kworld_315u_map);
+}
+
+static void __exit exit_rc_map_kworld_315u(void)
+{
+	ir_unregister_map(&kworld_315u_map);
+}
+
+module_init(init_rc_map_kworld_315u)
+module_exit(exit_rc_map_kworld_315u)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-kworld-plus-tv-analog.c b/drivers/media/IR/keymaps/rc-kworld-plus-tv-analog.c
new file mode 100644
index 0000000..366732f
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-kworld-plus-tv-analog.c
@@ -0,0 +1,99 @@
+/* kworld-plus-tv-analog.h - Keytable for kworld_plus_tv_analog Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Kworld Plus TV Analog Lite PCI IR
+   Mauro Carvalho Chehab <mchehab@infradead.org>
+ */
+
+static struct ir_scancode kworld_plus_tv_analog[] = {
+	{ 0x0c, KEY_PROG1 },		/* Kworld key */
+	{ 0x16, KEY_CLOSECD },		/* -> ) */
+	{ 0x1d, KEY_POWER2 },
+
+	{ 0x00, KEY_1 },
+	{ 0x01, KEY_2 },
+	{ 0x02, KEY_3 },		/* Two keys have the same code: 3 and left */
+	{ 0x03, KEY_4 },		/* Two keys have the same code: 3 and right */
+	{ 0x04, KEY_5 },
+	{ 0x05, KEY_6 },
+	{ 0x06, KEY_7 },
+	{ 0x07, KEY_8 },
+	{ 0x08, KEY_9 },
+	{ 0x0a, KEY_0 },
+
+	{ 0x09, KEY_AGAIN },
+	{ 0x14, KEY_MUTE },
+
+	{ 0x20, KEY_UP },
+	{ 0x21, KEY_DOWN },
+	{ 0x0b, KEY_ENTER },
+
+	{ 0x10, KEY_CHANNELUP },
+	{ 0x11, KEY_CHANNELDOWN },
+
+	/* Couldn't map key left/key right since those
+	   conflict with '3' and '4' scancodes
+	   I dunno what the original driver does
+	 */
+
+	{ 0x13, KEY_VOLUMEUP },
+	{ 0x12, KEY_VOLUMEDOWN },
+
+	/* The lower part of the IR
+	   There are several duplicated keycodes there.
+	   Most of them conflict with digits.
+	   Add mappings just to the unused scancodes.
+	   Somehow, the original driver has a way to know,
+	   but this doesn't seem to be on some GPIO.
+	   Also, it is not related to the time between keyup
+	   and keydown.
+	 */
+	{ 0x19, KEY_TIME},		/* Timeshift */
+	{ 0x1a, KEY_STOP},
+	{ 0x1b, KEY_RECORD},
+
+	{ 0x22, KEY_TEXT},
+
+	{ 0x15, KEY_AUDIO},		/* ((*)) */
+	{ 0x0f, KEY_ZOOM},
+	{ 0x1c, KEY_CAMERA},		/* snapshot */
+
+	{ 0x18, KEY_RED},		/* B */
+	{ 0x23, KEY_GREEN},		/* C */
+};
+
+static struct rc_keymap kworld_plus_tv_analog_map = {
+	.map = {
+		.scan    = kworld_plus_tv_analog,
+		.size    = ARRAY_SIZE(kworld_plus_tv_analog),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_KWORLD_PLUS_TV_ANALOG,
+	}
+};
+
+static int __init init_rc_map_kworld_plus_tv_analog(void)
+{
+	return ir_register_map(&kworld_plus_tv_analog_map);
+}
+
+static void __exit exit_rc_map_kworld_plus_tv_analog(void)
+{
+	ir_unregister_map(&kworld_plus_tv_analog_map);
+}
+
+module_init(init_rc_map_kworld_plus_tv_analog)
+module_exit(exit_rc_map_kworld_plus_tv_analog)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-manli.c b/drivers/media/IR/keymaps/rc-manli.c
new file mode 100644
index 0000000..1e9fbfa
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-manli.c
@@ -0,0 +1,135 @@
+/* manli.h - Keytable for manli Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Michael Tokarev <mjt@tls.msk.ru>
+   http://www.corpit.ru/mjt/beholdTV/remote_control.jpg
+   keytable is used by MANLI MTV00[0x0c] and BeholdTV 40[13] at
+   least, and probably other cards too.
+   The "ascii-art picture" below (in comments, first row
+   is the keycode in hex, and subsequent row(s) shows
+   the button labels (several variants when appropriate)
+   helps to descide which keycodes to assign to the buttons.
+ */
+
+static struct ir_scancode manli[] = {
+
+	/*  0x1c            0x12  *
+	 * FUNCTION         POWER *
+	 *   FM              (|)  *
+	 *                        */
+	{ 0x1c, KEY_RADIO },	/*XXX*/
+	{ 0x12, KEY_POWER },
+
+	/*  0x01    0x02    0x03  *
+	 *   1       2       3    *
+	 *                        *
+	 *  0x04    0x05    0x06  *
+	 *   4       5       6    *
+	 *                        *
+	 *  0x07    0x08    0x09  *
+	 *   7       8       9    *
+	 *                        */
+	{ 0x01, KEY_1 },
+	{ 0x02, KEY_2 },
+	{ 0x03, KEY_3 },
+	{ 0x04, KEY_4 },
+	{ 0x05, KEY_5 },
+	{ 0x06, KEY_6 },
+	{ 0x07, KEY_7 },
+	{ 0x08, KEY_8 },
+	{ 0x09, KEY_9 },
+
+	/*  0x0a    0x00    0x17  *
+	 * RECALL    0      +100  *
+	 *                  PLUS  *
+	 *                        */
+	{ 0x0a, KEY_AGAIN },	/*XXX KEY_REWIND? */
+	{ 0x00, KEY_0 },
+	{ 0x17, KEY_DIGITS },	/*XXX*/
+
+	/*  0x14            0x10  *
+	 *  MENU            INFO  *
+	 *  OSD                   */
+	{ 0x14, KEY_MENU },
+	{ 0x10, KEY_INFO },
+
+	/*          0x0b          *
+	 *           Up           *
+	 *                        *
+	 *  0x18    0x16    0x0c  *
+	 *  Left     Ok     Right *
+	 *                        *
+	 *         0x015          *
+	 *         Down           *
+	 *                        */
+	{ 0x0b, KEY_UP },
+	{ 0x18, KEY_LEFT },
+	{ 0x16, KEY_OK },	/*XXX KEY_SELECT? KEY_ENTER? */
+	{ 0x0c, KEY_RIGHT },
+	{ 0x15, KEY_DOWN },
+
+	/*  0x11            0x0d  *
+	 *  TV/AV           MODE  *
+	 *  SOURCE         STEREO *
+	 *                        */
+	{ 0x11, KEY_TV },	/*XXX*/
+	{ 0x0d, KEY_MODE },	/*XXX there's no KEY_STEREO	*/
+
+	/*  0x0f    0x1b    0x1a  *
+	 *  AUDIO   Vol+    Chan+ *
+	 *        TIMESHIFT???    *
+	 *                        *
+	 *  0x0e    0x1f    0x1e  *
+	 *  SLEEP   Vol-    Chan- *
+	 *                        */
+	{ 0x0f, KEY_AUDIO },
+	{ 0x1b, KEY_VOLUMEUP },
+	{ 0x1a, KEY_CHANNELUP },
+	{ 0x0e, KEY_TIME },
+	{ 0x1f, KEY_VOLUMEDOWN },
+	{ 0x1e, KEY_CHANNELDOWN },
+
+	/*         0x13     0x19  *
+	 *         MUTE   SNAPSHOT*
+	 *                        */
+	{ 0x13, KEY_MUTE },
+	{ 0x19, KEY_CAMERA },
+
+	/* 0x1d unused ? */
+};
+
+static struct rc_keymap manli_map = {
+	.map = {
+		.scan    = manli,
+		.size    = ARRAY_SIZE(manli),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_MANLI,
+	}
+};
+
+static int __init init_rc_map_manli(void)
+{
+	return ir_register_map(&manli_map);
+}
+
+static void __exit exit_rc_map_manli(void)
+{
+	ir_unregister_map(&manli_map);
+}
+
+module_init(init_rc_map_manli)
+module_exit(exit_rc_map_manli)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-msi-tvanywhere-plus.c b/drivers/media/IR/keymaps/rc-msi-tvanywhere-plus.c
new file mode 100644
index 0000000..eb8e42c
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-msi-tvanywhere-plus.c
@@ -0,0 +1,123 @@
+/* msi-tvanywhere-plus.h - Keytable for msi_tvanywhere_plus Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/*
+  Keycodes for remote on the MSI TV@nywhere Plus. The controller IC on the card
+  is marked "KS003". The controller is I2C at address 0x30, but does not seem
+  to respond to probes until a read is performed from a valid device.
+  I don't know why...
+
+  Note: This remote may be of similar or identical design to the
+  Pixelview remote (?).  The raw codes and duplicate button codes
+  appear to be the same.
+
+  Henry Wong <henry@stuffedcow.net>
+  Some changes to formatting and keycodes by Mark Schultz <n9xmj@yahoo.com>
+*/
+
+static struct ir_scancode msi_tvanywhere_plus[] = {
+
+/*  ---- Remote Button Layout ----
+
+    POWER   SOURCE  SCAN    MUTE
+    TV/FM   1       2       3
+    |>      4       5       6
+    <|      7       8       9
+    ^^UP    0       +       RECALL
+    vvDN    RECORD  STOP    PLAY
+
+	MINIMIZE          ZOOM
+
+		  CH+
+      VOL-                   VOL+
+		  CH-
+
+	SNAPSHOT           MTS
+
+     <<      FUNC    >>     RESET
+*/
+
+	{ 0x01, KEY_1 },		/* 1 */
+	{ 0x0b, KEY_2 },		/* 2 */
+	{ 0x1b, KEY_3 },		/* 3 */
+	{ 0x05, KEY_4 },		/* 4 */
+	{ 0x09, KEY_5 },		/* 5 */
+	{ 0x15, KEY_6 },		/* 6 */
+	{ 0x06, KEY_7 },		/* 7 */
+	{ 0x0a, KEY_8 },		/* 8 */
+	{ 0x12, KEY_9 },		/* 9 */
+	{ 0x02, KEY_0 },		/* 0 */
+	{ 0x10, KEY_KPPLUS },		/* + */
+	{ 0x13, KEY_AGAIN },		/* Recall */
+
+	{ 0x1e, KEY_POWER },		/* Power */
+	{ 0x07, KEY_TUNER },		/* Source */
+	{ 0x1c, KEY_SEARCH },		/* Scan */
+	{ 0x18, KEY_MUTE },		/* Mute */
+
+	{ 0x03, KEY_RADIO },		/* TV/FM */
+	/* The next four keys are duplicates that appear to send the
+	   same IR code as Ch+, Ch-, >>, and << .  The raw code assigned
+	   to them is the actual code + 0x20 - they will never be
+	   detected as such unless some way is discovered to distinguish
+	   these buttons from those that have the same code. */
+	{ 0x3f, KEY_RIGHT },		/* |> and Ch+ */
+	{ 0x37, KEY_LEFT },		/* <| and Ch- */
+	{ 0x2c, KEY_UP },		/* ^^Up and >> */
+	{ 0x24, KEY_DOWN },		/* vvDn and << */
+
+	{ 0x00, KEY_RECORD },		/* Record */
+	{ 0x08, KEY_STOP },		/* Stop */
+	{ 0x11, KEY_PLAY },		/* Play */
+
+	{ 0x0f, KEY_CLOSE },		/* Minimize */
+	{ 0x19, KEY_ZOOM },		/* Zoom */
+	{ 0x1a, KEY_CAMERA },		/* Snapshot */
+	{ 0x0d, KEY_LANGUAGE },		/* MTS */
+
+	{ 0x14, KEY_VOLUMEDOWN },	/* Vol- */
+	{ 0x16, KEY_VOLUMEUP },		/* Vol+ */
+	{ 0x17, KEY_CHANNELDOWN },	/* Ch- */
+	{ 0x1f, KEY_CHANNELUP },	/* Ch+ */
+
+	{ 0x04, KEY_REWIND },		/* << */
+	{ 0x0e, KEY_MENU },		/* Function */
+	{ 0x0c, KEY_FASTFORWARD },	/* >> */
+	{ 0x1d, KEY_RESTART },		/* Reset */
+};
+
+static struct rc_keymap msi_tvanywhere_plus_map = {
+	.map = {
+		.scan    = msi_tvanywhere_plus,
+		.size    = ARRAY_SIZE(msi_tvanywhere_plus),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_MSI_TVANYWHERE_PLUS,
+	}
+};
+
+static int __init init_rc_map_msi_tvanywhere_plus(void)
+{
+	return ir_register_map(&msi_tvanywhere_plus_map);
+}
+
+static void __exit exit_rc_map_msi_tvanywhere_plus(void)
+{
+	ir_unregister_map(&msi_tvanywhere_plus_map);
+}
+
+module_init(init_rc_map_msi_tvanywhere_plus)
+module_exit(exit_rc_map_msi_tvanywhere_plus)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-msi-tvanywhere.c b/drivers/media/IR/keymaps/rc-msi-tvanywhere.c
new file mode 100644
index 0000000..ef41185
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-msi-tvanywhere.c
@@ -0,0 +1,69 @@
+/* msi-tvanywhere.h - Keytable for msi_tvanywhere Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* MSI TV@nywhere MASTER remote */
+
+static struct ir_scancode msi_tvanywhere[] = {
+	/* Keys 0 to 9 */
+	{ 0x00, KEY_0 },
+	{ 0x01, KEY_1 },
+	{ 0x02, KEY_2 },
+	{ 0x03, KEY_3 },
+	{ 0x04, KEY_4 },
+	{ 0x05, KEY_5 },
+	{ 0x06, KEY_6 },
+	{ 0x07, KEY_7 },
+	{ 0x08, KEY_8 },
+	{ 0x09, KEY_9 },
+
+	{ 0x0c, KEY_MUTE },
+	{ 0x0f, KEY_SCREEN },		/* Full Screen */
+	{ 0x10, KEY_FN },		/* Funtion */
+	{ 0x11, KEY_TIME },		/* Time shift */
+	{ 0x12, KEY_POWER },
+	{ 0x13, KEY_MEDIA },		/* MTS */
+	{ 0x14, KEY_SLOW },
+	{ 0x16, KEY_REWIND },		/* backward << */
+	{ 0x17, KEY_ENTER },		/* Return */
+	{ 0x18, KEY_FASTFORWARD },	/* forward >> */
+	{ 0x1a, KEY_CHANNELUP },
+	{ 0x1b, KEY_VOLUMEUP },
+	{ 0x1e, KEY_CHANNELDOWN },
+	{ 0x1f, KEY_VOLUMEDOWN },
+};
+
+static struct rc_keymap msi_tvanywhere_map = {
+	.map = {
+		.scan    = msi_tvanywhere,
+		.size    = ARRAY_SIZE(msi_tvanywhere),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_MSI_TVANYWHERE,
+	}
+};
+
+static int __init init_rc_map_msi_tvanywhere(void)
+{
+	return ir_register_map(&msi_tvanywhere_map);
+}
+
+static void __exit exit_rc_map_msi_tvanywhere(void)
+{
+	ir_unregister_map(&msi_tvanywhere_map);
+}
+
+module_init(init_rc_map_msi_tvanywhere)
+module_exit(exit_rc_map_msi_tvanywhere)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-nebula.c b/drivers/media/IR/keymaps/rc-nebula.c
new file mode 100644
index 0000000..ccc50eb
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-nebula.c
@@ -0,0 +1,96 @@
+/* nebula.h - Keytable for nebula Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode nebula[] = {
+	{ 0x00, KEY_0 },
+	{ 0x01, KEY_1 },
+	{ 0x02, KEY_2 },
+	{ 0x03, KEY_3 },
+	{ 0x04, KEY_4 },
+	{ 0x05, KEY_5 },
+	{ 0x06, KEY_6 },
+	{ 0x07, KEY_7 },
+	{ 0x08, KEY_8 },
+	{ 0x09, KEY_9 },
+	{ 0x0a, KEY_TV },
+	{ 0x0b, KEY_AUX },
+	{ 0x0c, KEY_DVD },
+	{ 0x0d, KEY_POWER },
+	{ 0x0e, KEY_MHP },	/* labelled 'Picture' */
+	{ 0x0f, KEY_AUDIO },
+	{ 0x10, KEY_INFO },
+	{ 0x11, KEY_F13 },	/* 16:9 */
+	{ 0x12, KEY_F14 },	/* 14:9 */
+	{ 0x13, KEY_EPG },
+	{ 0x14, KEY_EXIT },
+	{ 0x15, KEY_MENU },
+	{ 0x16, KEY_UP },
+	{ 0x17, KEY_DOWN },
+	{ 0x18, KEY_LEFT },
+	{ 0x19, KEY_RIGHT },
+	{ 0x1a, KEY_ENTER },
+	{ 0x1b, KEY_CHANNELUP },
+	{ 0x1c, KEY_CHANNELDOWN },
+	{ 0x1d, KEY_VOLUMEUP },
+	{ 0x1e, KEY_VOLUMEDOWN },
+	{ 0x1f, KEY_RED },
+	{ 0x20, KEY_GREEN },
+	{ 0x21, KEY_YELLOW },
+	{ 0x22, KEY_BLUE },
+	{ 0x23, KEY_SUBTITLE },
+	{ 0x24, KEY_F15 },	/* AD */
+	{ 0x25, KEY_TEXT },
+	{ 0x26, KEY_MUTE },
+	{ 0x27, KEY_REWIND },
+	{ 0x28, KEY_STOP },
+	{ 0x29, KEY_PLAY },
+	{ 0x2a, KEY_FASTFORWARD },
+	{ 0x2b, KEY_F16 },	/* chapter */
+	{ 0x2c, KEY_PAUSE },
+	{ 0x2d, KEY_PLAY },
+	{ 0x2e, KEY_RECORD },
+	{ 0x2f, KEY_F17 },	/* picture in picture */
+	{ 0x30, KEY_KPPLUS },	/* zoom in */
+	{ 0x31, KEY_KPMINUS },	/* zoom out */
+	{ 0x32, KEY_F18 },	/* capture */
+	{ 0x33, KEY_F19 },	/* web */
+	{ 0x34, KEY_EMAIL },
+	{ 0x35, KEY_PHONE },
+	{ 0x36, KEY_PC },
+};
+
+static struct rc_keymap nebula_map = {
+	.map = {
+		.scan    = nebula,
+		.size    = ARRAY_SIZE(nebula),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_NEBULA,
+	}
+};
+
+static int __init init_rc_map_nebula(void)
+{
+	return ir_register_map(&nebula_map);
+}
+
+static void __exit exit_rc_map_nebula(void)
+{
+	ir_unregister_map(&nebula_map);
+}
+
+module_init(init_rc_map_nebula)
+module_exit(exit_rc_map_nebula)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-nec-terratec-cinergy-xs.c b/drivers/media/IR/keymaps/rc-nec-terratec-cinergy-xs.c
new file mode 100644
index 0000000..e1b54d2
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-nec-terratec-cinergy-xs.c
@@ -0,0 +1,105 @@
+/* nec-terratec-cinergy-xs.h - Keytable for nec_terratec_cinergy_xs Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Terratec Cinergy Hybrid T USB XS FM
+   Mauro Carvalho Chehab <mchehab@redhat.com>
+ */
+
+static struct ir_scancode nec_terratec_cinergy_xs[] = {
+	{ 0x1441, KEY_HOME},
+	{ 0x1401, KEY_POWER2},
+
+	{ 0x1442, KEY_MENU},		/* DVD menu */
+	{ 0x1443, KEY_SUBTITLE},
+	{ 0x1444, KEY_TEXT},		/* Teletext */
+	{ 0x1445, KEY_DELETE},
+
+	{ 0x1402, KEY_1},
+	{ 0x1403, KEY_2},
+	{ 0x1404, KEY_3},
+	{ 0x1405, KEY_4},
+	{ 0x1406, KEY_5},
+	{ 0x1407, KEY_6},
+	{ 0x1408, KEY_7},
+	{ 0x1409, KEY_8},
+	{ 0x140a, KEY_9},
+	{ 0x140c, KEY_0},
+
+	{ 0x140b, KEY_TUNER},		/* AV */
+	{ 0x140d, KEY_MODE},		/* A.B */
+
+	{ 0x1446, KEY_TV},
+	{ 0x1447, KEY_DVD},
+	{ 0x1449, KEY_VIDEO},
+	{ 0x144a, KEY_RADIO},		/* Music */
+	{ 0x144b, KEY_CAMERA},		/* PIC */
+
+	{ 0x1410, KEY_UP},
+	{ 0x1411, KEY_LEFT},
+	{ 0x1412, KEY_OK},
+	{ 0x1413, KEY_RIGHT},
+	{ 0x1414, KEY_DOWN},
+
+	{ 0x140f, KEY_EPG},
+	{ 0x1416, KEY_INFO},
+	{ 0x144d, KEY_BACKSPACE},
+
+	{ 0x141c, KEY_VOLUMEUP},
+	{ 0x141e, KEY_VOLUMEDOWN},
+
+	{ 0x144c, KEY_PLAY},
+	{ 0x141d, KEY_MUTE},
+
+	{ 0x141b, KEY_CHANNELUP},
+	{ 0x141f, KEY_CHANNELDOWN},
+
+	{ 0x1417, KEY_RED},
+	{ 0x1418, KEY_GREEN},
+	{ 0x1419, KEY_YELLOW},
+	{ 0x141a, KEY_BLUE},
+
+	{ 0x1458, KEY_RECORD},
+	{ 0x1448, KEY_STOP},
+	{ 0x1440, KEY_PAUSE},
+
+	{ 0x1454, KEY_LAST},
+	{ 0x144e, KEY_REWIND},
+	{ 0x144f, KEY_FASTFORWARD},
+	{ 0x145c, KEY_NEXT},
+};
+
+static struct rc_keymap nec_terratec_cinergy_xs_map = {
+	.map = {
+		.scan    = nec_terratec_cinergy_xs,
+		.size    = ARRAY_SIZE(nec_terratec_cinergy_xs),
+		.ir_type = IR_TYPE_NEC,
+		.name    = RC_MAP_NEC_TERRATEC_CINERGY_XS,
+	}
+};
+
+static int __init init_rc_map_nec_terratec_cinergy_xs(void)
+{
+	return ir_register_map(&nec_terratec_cinergy_xs_map);
+}
+
+static void __exit exit_rc_map_nec_terratec_cinergy_xs(void)
+{
+	ir_unregister_map(&nec_terratec_cinergy_xs_map);
+}
+
+module_init(init_rc_map_nec_terratec_cinergy_xs)
+module_exit(exit_rc_map_nec_terratec_cinergy_xs)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-norwood.c b/drivers/media/IR/keymaps/rc-norwood.c
new file mode 100644
index 0000000..e5849a6
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-norwood.c
@@ -0,0 +1,85 @@
+/* norwood.h - Keytable for norwood Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Norwood Micro (non-Pro) TV Tuner
+   By Peter Naulls <peter@chocky.org>
+   Key comments are the functions given in the manual */
+
+static struct ir_scancode norwood[] = {
+	/* Keys 0 to 9 */
+	{ 0x20, KEY_0 },
+	{ 0x21, KEY_1 },
+	{ 0x22, KEY_2 },
+	{ 0x23, KEY_3 },
+	{ 0x24, KEY_4 },
+	{ 0x25, KEY_5 },
+	{ 0x26, KEY_6 },
+	{ 0x27, KEY_7 },
+	{ 0x28, KEY_8 },
+	{ 0x29, KEY_9 },
+
+	{ 0x78, KEY_TUNER },		/* Video Source        */
+	{ 0x2c, KEY_EXIT },		/* Open/Close software */
+	{ 0x2a, KEY_SELECT },		/* 2 Digit Select      */
+	{ 0x69, KEY_AGAIN },		/* Recall              */
+
+	{ 0x32, KEY_BRIGHTNESSUP },	/* Brightness increase */
+	{ 0x33, KEY_BRIGHTNESSDOWN },	/* Brightness decrease */
+	{ 0x6b, KEY_KPPLUS },		/* (not named >>>>>)   */
+	{ 0x6c, KEY_KPMINUS },		/* (not named <<<<<)   */
+
+	{ 0x2d, KEY_MUTE },		/* Mute                */
+	{ 0x30, KEY_VOLUMEUP },		/* Volume up           */
+	{ 0x31, KEY_VOLUMEDOWN },	/* Volume down         */
+	{ 0x60, KEY_CHANNELUP },	/* Channel up          */
+	{ 0x61, KEY_CHANNELDOWN },	/* Channel down        */
+
+	{ 0x3f, KEY_RECORD },		/* Record              */
+	{ 0x37, KEY_PLAY },		/* Play                */
+	{ 0x36, KEY_PAUSE },		/* Pause               */
+	{ 0x2b, KEY_STOP },		/* Stop                */
+	{ 0x67, KEY_FASTFORWARD },	/* Foward              */
+	{ 0x66, KEY_REWIND },		/* Rewind              */
+	{ 0x3e, KEY_SEARCH },		/* Auto Scan           */
+	{ 0x2e, KEY_CAMERA },		/* Capture Video       */
+	{ 0x6d, KEY_MENU },		/* Show/Hide Control   */
+	{ 0x2f, KEY_ZOOM },		/* Full Screen         */
+	{ 0x34, KEY_RADIO },		/* FM                  */
+	{ 0x65, KEY_POWER },		/* Computer power      */
+};
+
+static struct rc_keymap norwood_map = {
+	.map = {
+		.scan    = norwood,
+		.size    = ARRAY_SIZE(norwood),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_NORWOOD,
+	}
+};
+
+static int __init init_rc_map_norwood(void)
+{
+	return ir_register_map(&norwood_map);
+}
+
+static void __exit exit_rc_map_norwood(void)
+{
+	ir_unregister_map(&norwood_map);
+}
+
+module_init(init_rc_map_norwood)
+module_exit(exit_rc_map_norwood)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-npgtech.c b/drivers/media/IR/keymaps/rc-npgtech.c
new file mode 100644
index 0000000..b9ece1e
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-npgtech.c
@@ -0,0 +1,80 @@
+/* npgtech.h - Keytable for npgtech Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode npgtech[] = {
+	{ 0x1d, KEY_SWITCHVIDEOMODE },	/* switch inputs */
+	{ 0x2a, KEY_FRONT },
+
+	{ 0x3e, KEY_1 },
+	{ 0x02, KEY_2 },
+	{ 0x06, KEY_3 },
+	{ 0x0a, KEY_4 },
+	{ 0x0e, KEY_5 },
+	{ 0x12, KEY_6 },
+	{ 0x16, KEY_7 },
+	{ 0x1a, KEY_8 },
+	{ 0x1e, KEY_9 },
+	{ 0x3a, KEY_0 },
+	{ 0x22, KEY_NUMLOCK },		/* -/-- */
+	{ 0x20, KEY_REFRESH },
+
+	{ 0x03, KEY_BRIGHTNESSDOWN },
+	{ 0x28, KEY_AUDIO },
+	{ 0x3c, KEY_CHANNELUP },
+	{ 0x3f, KEY_VOLUMEDOWN },
+	{ 0x2e, KEY_MUTE },
+	{ 0x3b, KEY_VOLUMEUP },
+	{ 0x00, KEY_CHANNELDOWN },
+	{ 0x07, KEY_BRIGHTNESSUP },
+	{ 0x2c, KEY_TEXT },
+
+	{ 0x37, KEY_RECORD },
+	{ 0x17, KEY_PLAY },
+	{ 0x13, KEY_PAUSE },
+	{ 0x26, KEY_STOP },
+	{ 0x18, KEY_FASTFORWARD },
+	{ 0x14, KEY_REWIND },
+	{ 0x33, KEY_ZOOM },
+	{ 0x32, KEY_KEYBOARD },
+	{ 0x30, KEY_GOTO },		/* Pointing arrow */
+	{ 0x36, KEY_MACRO },		/* Maximize/Minimize (yellow) */
+	{ 0x0b, KEY_RADIO },
+	{ 0x10, KEY_POWER },
+
+};
+
+static struct rc_keymap npgtech_map = {
+	.map = {
+		.scan    = npgtech,
+		.size    = ARRAY_SIZE(npgtech),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_NPGTECH,
+	}
+};
+
+static int __init init_rc_map_npgtech(void)
+{
+	return ir_register_map(&npgtech_map);
+}
+
+static void __exit exit_rc_map_npgtech(void)
+{
+	ir_unregister_map(&npgtech_map);
+}
+
+module_init(init_rc_map_npgtech)
+module_exit(exit_rc_map_npgtech)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-pctv-sedna.c b/drivers/media/IR/keymaps/rc-pctv-sedna.c
new file mode 100644
index 0000000..4129bb4
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-pctv-sedna.c
@@ -0,0 +1,80 @@
+/* pctv-sedna.h - Keytable for pctv_sedna Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Mapping for the 28 key remote control as seen at
+   http://www.sednacomputer.com/photo/cardbus-tv.jpg
+   Pavel Mihaylov <bin@bash.info>
+   Also for the remote bundled with Kozumi KTV-01C card */
+
+static struct ir_scancode pctv_sedna[] = {
+	{ 0x00, KEY_0 },
+	{ 0x01, KEY_1 },
+	{ 0x02, KEY_2 },
+	{ 0x03, KEY_3 },
+	{ 0x04, KEY_4 },
+	{ 0x05, KEY_5 },
+	{ 0x06, KEY_6 },
+	{ 0x07, KEY_7 },
+	{ 0x08, KEY_8 },
+	{ 0x09, KEY_9 },
+
+	{ 0x0a, KEY_AGAIN },	/* Recall */
+	{ 0x0b, KEY_CHANNELUP },
+	{ 0x0c, KEY_VOLUMEUP },
+	{ 0x0d, KEY_MODE },	/* Stereo */
+	{ 0x0e, KEY_STOP },
+	{ 0x0f, KEY_PREVIOUSSONG },
+	{ 0x10, KEY_ZOOM },
+	{ 0x11, KEY_TUNER },	/* Source */
+	{ 0x12, KEY_POWER },
+	{ 0x13, KEY_MUTE },
+	{ 0x15, KEY_CHANNELDOWN },
+	{ 0x18, KEY_VOLUMEDOWN },
+	{ 0x19, KEY_CAMERA },	/* Snapshot */
+	{ 0x1a, KEY_NEXTSONG },
+	{ 0x1b, KEY_TIME },	/* Time Shift */
+	{ 0x1c, KEY_RADIO },	/* FM Radio */
+	{ 0x1d, KEY_RECORD },
+	{ 0x1e, KEY_PAUSE },
+	/* additional codes for Kozumi's remote */
+	{ 0x14, KEY_INFO },	/* OSD */
+	{ 0x16, KEY_OK },	/* OK */
+	{ 0x17, KEY_DIGITS },	/* Plus */
+	{ 0x1f, KEY_PLAY },	/* Play */
+};
+
+static struct rc_keymap pctv_sedna_map = {
+	.map = {
+		.scan    = pctv_sedna,
+		.size    = ARRAY_SIZE(pctv_sedna),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_PCTV_SEDNA,
+	}
+};
+
+static int __init init_rc_map_pctv_sedna(void)
+{
+	return ir_register_map(&pctv_sedna_map);
+}
+
+static void __exit exit_rc_map_pctv_sedna(void)
+{
+	ir_unregister_map(&pctv_sedna_map);
+}
+
+module_init(init_rc_map_pctv_sedna)
+module_exit(exit_rc_map_pctv_sedna)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-pinnacle-color.c b/drivers/media/IR/keymaps/rc-pinnacle-color.c
new file mode 100644
index 0000000..326e023
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-pinnacle-color.c
@@ -0,0 +1,94 @@
+/* pinnacle-color.h - Keytable for pinnacle_color Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode pinnacle_color[] = {
+	{ 0x59, KEY_MUTE },
+	{ 0x4a, KEY_POWER },
+
+	{ 0x18, KEY_TEXT },
+	{ 0x26, KEY_TV },
+	{ 0x3d, KEY_PRINT },
+
+	{ 0x48, KEY_RED },
+	{ 0x04, KEY_GREEN },
+	{ 0x11, KEY_YELLOW },
+	{ 0x00, KEY_BLUE },
+
+	{ 0x2d, KEY_VOLUMEUP },
+	{ 0x1e, KEY_VOLUMEDOWN },
+
+	{ 0x49, KEY_MENU },
+
+	{ 0x16, KEY_CHANNELUP },
+	{ 0x17, KEY_CHANNELDOWN },
+
+	{ 0x20, KEY_UP },
+	{ 0x21, KEY_DOWN },
+	{ 0x22, KEY_LEFT },
+	{ 0x23, KEY_RIGHT },
+	{ 0x0d, KEY_SELECT },
+
+	{ 0x08, KEY_BACK },
+	{ 0x07, KEY_REFRESH },
+
+	{ 0x2f, KEY_ZOOM },
+	{ 0x29, KEY_RECORD },
+
+	{ 0x4b, KEY_PAUSE },
+	{ 0x4d, KEY_REWIND },
+	{ 0x2e, KEY_PLAY },
+	{ 0x4e, KEY_FORWARD },
+	{ 0x53, KEY_PREVIOUS },
+	{ 0x4c, KEY_STOP },
+	{ 0x54, KEY_NEXT },
+
+	{ 0x69, KEY_0 },
+	{ 0x6a, KEY_1 },
+	{ 0x6b, KEY_2 },
+	{ 0x6c, KEY_3 },
+	{ 0x6d, KEY_4 },
+	{ 0x6e, KEY_5 },
+	{ 0x6f, KEY_6 },
+	{ 0x70, KEY_7 },
+	{ 0x71, KEY_8 },
+	{ 0x72, KEY_9 },
+
+	{ 0x74, KEY_CHANNEL },
+	{ 0x0a, KEY_BACKSPACE },
+};
+
+static struct rc_keymap pinnacle_color_map = {
+	.map = {
+		.scan    = pinnacle_color,
+		.size    = ARRAY_SIZE(pinnacle_color),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_PINNACLE_COLOR,
+	}
+};
+
+static int __init init_rc_map_pinnacle_color(void)
+{
+	return ir_register_map(&pinnacle_color_map);
+}
+
+static void __exit exit_rc_map_pinnacle_color(void)
+{
+	ir_unregister_map(&pinnacle_color_map);
+}
+
+module_init(init_rc_map_pinnacle_color)
+module_exit(exit_rc_map_pinnacle_color)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-pinnacle-grey.c b/drivers/media/IR/keymaps/rc-pinnacle-grey.c
new file mode 100644
index 0000000..14cb772
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-pinnacle-grey.c
@@ -0,0 +1,89 @@
+/* pinnacle-grey.h - Keytable for pinnacle_grey Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode pinnacle_grey[] = {
+	{ 0x3a, KEY_0 },
+	{ 0x31, KEY_1 },
+	{ 0x32, KEY_2 },
+	{ 0x33, KEY_3 },
+	{ 0x34, KEY_4 },
+	{ 0x35, KEY_5 },
+	{ 0x36, KEY_6 },
+	{ 0x37, KEY_7 },
+	{ 0x38, KEY_8 },
+	{ 0x39, KEY_9 },
+
+	{ 0x2f, KEY_POWER },
+
+	{ 0x2e, KEY_P },
+	{ 0x1f, KEY_L },
+	{ 0x2b, KEY_I },
+
+	{ 0x2d, KEY_SCREEN },
+	{ 0x1e, KEY_ZOOM },
+	{ 0x1b, KEY_VOLUMEUP },
+	{ 0x0f, KEY_VOLUMEDOWN },
+	{ 0x17, KEY_CHANNELUP },
+	{ 0x1c, KEY_CHANNELDOWN },
+	{ 0x25, KEY_INFO },
+
+	{ 0x3c, KEY_MUTE },
+
+	{ 0x3d, KEY_LEFT },
+	{ 0x3b, KEY_RIGHT },
+
+	{ 0x3f, KEY_UP },
+	{ 0x3e, KEY_DOWN },
+	{ 0x1a, KEY_ENTER },
+
+	{ 0x1d, KEY_MENU },
+	{ 0x19, KEY_AGAIN },
+	{ 0x16, KEY_PREVIOUSSONG },
+	{ 0x13, KEY_NEXTSONG },
+	{ 0x15, KEY_PAUSE },
+	{ 0x0e, KEY_REWIND },
+	{ 0x0d, KEY_PLAY },
+	{ 0x0b, KEY_STOP },
+	{ 0x07, KEY_FORWARD },
+	{ 0x27, KEY_RECORD },
+	{ 0x26, KEY_TUNER },
+	{ 0x29, KEY_TEXT },
+	{ 0x2a, KEY_MEDIA },
+	{ 0x18, KEY_EPG },
+};
+
+static struct rc_keymap pinnacle_grey_map = {
+	.map = {
+		.scan    = pinnacle_grey,
+		.size    = ARRAY_SIZE(pinnacle_grey),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_PINNACLE_GREY,
+	}
+};
+
+static int __init init_rc_map_pinnacle_grey(void)
+{
+	return ir_register_map(&pinnacle_grey_map);
+}
+
+static void __exit exit_rc_map_pinnacle_grey(void)
+{
+	ir_unregister_map(&pinnacle_grey_map);
+}
+
+module_init(init_rc_map_pinnacle_grey)
+module_exit(exit_rc_map_pinnacle_grey)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-pinnacle-pctv-hd.c b/drivers/media/IR/keymaps/rc-pinnacle-pctv-hd.c
new file mode 100644
index 0000000..835bf4e
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-pinnacle-pctv-hd.c
@@ -0,0 +1,73 @@
+/* pinnacle-pctv-hd.h - Keytable for pinnacle_pctv_hd Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Pinnacle PCTV HD 800i mini remote */
+
+static struct ir_scancode pinnacle_pctv_hd[] = {
+
+	{ 0x0f, KEY_1 },
+	{ 0x15, KEY_2 },
+	{ 0x10, KEY_3 },
+	{ 0x18, KEY_4 },
+	{ 0x1b, KEY_5 },
+	{ 0x1e, KEY_6 },
+	{ 0x11, KEY_7 },
+	{ 0x21, KEY_8 },
+	{ 0x12, KEY_9 },
+	{ 0x27, KEY_0 },
+
+	{ 0x24, KEY_ZOOM },
+	{ 0x2a, KEY_SUBTITLE },
+
+	{ 0x00, KEY_MUTE },
+	{ 0x01, KEY_ENTER },	/* Pinnacle Logo */
+	{ 0x39, KEY_POWER },
+
+	{ 0x03, KEY_VOLUMEUP },
+	{ 0x09, KEY_VOLUMEDOWN },
+	{ 0x06, KEY_CHANNELUP },
+	{ 0x0c, KEY_CHANNELDOWN },
+
+	{ 0x2d, KEY_REWIND },
+	{ 0x30, KEY_PLAYPAUSE },
+	{ 0x33, KEY_FASTFORWARD },
+	{ 0x3c, KEY_STOP },
+	{ 0x36, KEY_RECORD },
+	{ 0x3f, KEY_EPG },	/* Labeled "?" */
+};
+
+static struct rc_keymap pinnacle_pctv_hd_map = {
+	.map = {
+		.scan    = pinnacle_pctv_hd,
+		.size    = ARRAY_SIZE(pinnacle_pctv_hd),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_PINNACLE_PCTV_HD,
+	}
+};
+
+static int __init init_rc_map_pinnacle_pctv_hd(void)
+{
+	return ir_register_map(&pinnacle_pctv_hd_map);
+}
+
+static void __exit exit_rc_map_pinnacle_pctv_hd(void)
+{
+	ir_unregister_map(&pinnacle_pctv_hd_map);
+}
+
+module_init(init_rc_map_pinnacle_pctv_hd)
+module_exit(exit_rc_map_pinnacle_pctv_hd)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-pixelview-mk12.c b/drivers/media/IR/keymaps/rc-pixelview-mk12.c
new file mode 100644
index 0000000..5a735d5
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-pixelview-mk12.c
@@ -0,0 +1,83 @@
+/* rc-pixelview-mk12.h - Keytable for pixelview Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/*
+ * Keytable for MK-F12 IR remote provided together with Pixelview
+ * Ultra Pro Remote Controller. Uses NEC extended format.
+ */
+static struct ir_scancode pixelview_mk12[] = {
+	{ 0x866b03, KEY_TUNER },	/* Timeshift */
+	{ 0x866b1e, KEY_POWER2 },	/* power */
+
+	{ 0x866b01, KEY_1 },
+	{ 0x866b0b, KEY_2 },
+	{ 0x866b1b, KEY_3 },
+	{ 0x866b05, KEY_4 },
+	{ 0x866b09, KEY_5 },
+	{ 0x866b15, KEY_6 },
+	{ 0x866b06, KEY_7 },
+	{ 0x866b0a, KEY_8 },
+	{ 0x866b12, KEY_9 },
+	{ 0x866b02, KEY_0 },
+
+	{ 0x866b13, KEY_AGAIN },	/* loop */
+	{ 0x866b10, KEY_DIGITS },	/* +100 */
+
+	{ 0x866b00, KEY_MEDIA },	/* source */
+	{ 0x866b18, KEY_MUTE },		/* mute */
+	{ 0x866b19, KEY_CAMERA },	/* snapshot */
+	{ 0x866b1a, KEY_SEARCH },	/* scan */
+
+	{ 0x866b16, KEY_CHANNELUP },	/* chn + */
+	{ 0x866b14, KEY_CHANNELDOWN },	/* chn - */
+	{ 0x866b1f, KEY_VOLUMEUP },	/* vol + */
+	{ 0x866b17, KEY_VOLUMEDOWN },	/* vol - */
+	{ 0x866b1c, KEY_ZOOM },		/* zoom */
+
+	{ 0x866b04, KEY_REWIND },
+	{ 0x866b0e, KEY_RECORD },
+	{ 0x866b0c, KEY_FORWARD },
+
+	{ 0x866b1d, KEY_STOP },
+	{ 0x866b08, KEY_PLAY },
+	{ 0x866b0f, KEY_PAUSE },
+
+	{ 0x866b0d, KEY_TV },
+	{ 0x866b07, KEY_RADIO },	/* FM */
+};
+
+static struct rc_keymap pixelview_map = {
+	.map = {
+		.scan    = pixelview_mk12,
+		.size    = ARRAY_SIZE(pixelview_mk12),
+		.ir_type = IR_TYPE_NEC,
+		.name    = RC_MAP_PIXELVIEW_MK12,
+	}
+};
+
+static int __init init_rc_map_pixelview(void)
+{
+	return ir_register_map(&pixelview_map);
+}
+
+static void __exit exit_rc_map_pixelview(void)
+{
+	ir_unregister_map(&pixelview_map);
+}
+
+module_init(init_rc_map_pixelview)
+module_exit(exit_rc_map_pixelview)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-pixelview-new.c b/drivers/media/IR/keymaps/rc-pixelview-new.c
new file mode 100644
index 0000000..7bbbbf5
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-pixelview-new.c
@@ -0,0 +1,83 @@
+/* pixelview-new.h - Keytable for pixelview_new Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/*
+   Mauro Carvalho Chehab <mchehab@infradead.org>
+   present on PV MPEG 8000GT
+ */
+
+static struct ir_scancode pixelview_new[] = {
+	{ 0x3c, KEY_TIME },		/* Timeshift */
+	{ 0x12, KEY_POWER },
+
+	{ 0x3d, KEY_1 },
+	{ 0x38, KEY_2 },
+	{ 0x18, KEY_3 },
+	{ 0x35, KEY_4 },
+	{ 0x39, KEY_5 },
+	{ 0x15, KEY_6 },
+	{ 0x36, KEY_7 },
+	{ 0x3a, KEY_8 },
+	{ 0x1e, KEY_9 },
+	{ 0x3e, KEY_0 },
+
+	{ 0x1c, KEY_AGAIN },		/* LOOP	*/
+	{ 0x3f, KEY_MEDIA },		/* Source */
+	{ 0x1f, KEY_LAST },		/* +100 */
+	{ 0x1b, KEY_MUTE },
+
+	{ 0x17, KEY_CHANNELDOWN },
+	{ 0x16, KEY_CHANNELUP },
+	{ 0x10, KEY_VOLUMEUP },
+	{ 0x14, KEY_VOLUMEDOWN },
+	{ 0x13, KEY_ZOOM },
+
+	{ 0x19, KEY_CAMERA },		/* SNAPSHOT */
+	{ 0x1a, KEY_SEARCH },		/* scan */
+
+	{ 0x37, KEY_REWIND },		/* << */
+	{ 0x32, KEY_RECORD },		/* o (red) */
+	{ 0x33, KEY_FORWARD },		/* >> */
+	{ 0x11, KEY_STOP },		/* square */
+	{ 0x3b, KEY_PLAY },		/* > */
+	{ 0x30, KEY_PLAYPAUSE },	/* || */
+
+	{ 0x31, KEY_TV },
+	{ 0x34, KEY_RADIO },
+};
+
+static struct rc_keymap pixelview_new_map = {
+	.map = {
+		.scan    = pixelview_new,
+		.size    = ARRAY_SIZE(pixelview_new),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_PIXELVIEW_NEW,
+	}
+};
+
+static int __init init_rc_map_pixelview_new(void)
+{
+	return ir_register_map(&pixelview_new_map);
+}
+
+static void __exit exit_rc_map_pixelview_new(void)
+{
+	ir_unregister_map(&pixelview_new_map);
+}
+
+module_init(init_rc_map_pixelview_new)
+module_exit(exit_rc_map_pixelview_new)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-pixelview.c b/drivers/media/IR/keymaps/rc-pixelview.c
new file mode 100644
index 0000000..82ff12e
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-pixelview.c
@@ -0,0 +1,82 @@
+/* pixelview.h - Keytable for pixelview Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode pixelview[] = {
+
+	{ 0x1e, KEY_POWER },	/* power */
+	{ 0x07, KEY_MEDIA },	/* source */
+	{ 0x1c, KEY_SEARCH },	/* scan */
+
+
+	{ 0x03, KEY_TUNER },		/* TV/FM */
+
+	{ 0x00, KEY_RECORD },
+	{ 0x08, KEY_STOP },
+	{ 0x11, KEY_PLAY },
+
+	{ 0x1a, KEY_PLAYPAUSE },	/* freeze */
+	{ 0x19, KEY_ZOOM },		/* zoom */
+	{ 0x0f, KEY_TEXT },		/* min */
+
+	{ 0x01, KEY_1 },
+	{ 0x0b, KEY_2 },
+	{ 0x1b, KEY_3 },
+	{ 0x05, KEY_4 },
+	{ 0x09, KEY_5 },
+	{ 0x15, KEY_6 },
+	{ 0x06, KEY_7 },
+	{ 0x0a, KEY_8 },
+	{ 0x12, KEY_9 },
+	{ 0x02, KEY_0 },
+	{ 0x10, KEY_LAST },		/* +100 */
+	{ 0x13, KEY_LIST },		/* recall */
+
+	{ 0x1f, KEY_CHANNELUP },	/* chn down */
+	{ 0x17, KEY_CHANNELDOWN },	/* chn up */
+	{ 0x16, KEY_VOLUMEUP },		/* vol down */
+	{ 0x14, KEY_VOLUMEDOWN },	/* vol up */
+
+	{ 0x04, KEY_KPMINUS },		/* <<< */
+	{ 0x0e, KEY_SETUP },		/* function */
+	{ 0x0c, KEY_KPPLUS },		/* >>> */
+
+	{ 0x0d, KEY_GOTO },		/* mts */
+	{ 0x1d, KEY_REFRESH },		/* reset */
+	{ 0x18, KEY_MUTE },		/* mute/unmute */
+};
+
+static struct rc_keymap pixelview_map = {
+	.map = {
+		.scan    = pixelview,
+		.size    = ARRAY_SIZE(pixelview),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_PIXELVIEW,
+	}
+};
+
+static int __init init_rc_map_pixelview(void)
+{
+	return ir_register_map(&pixelview_map);
+}
+
+static void __exit exit_rc_map_pixelview(void)
+{
+	ir_unregister_map(&pixelview_map);
+}
+
+module_init(init_rc_map_pixelview)
+module_exit(exit_rc_map_pixelview)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-powercolor-real-angel.c b/drivers/media/IR/keymaps/rc-powercolor-real-angel.c
new file mode 100644
index 0000000..7cef819
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-powercolor-real-angel.c
@@ -0,0 +1,81 @@
+/* powercolor-real-angel.h - Keytable for powercolor_real_angel Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/*
+ * Remote control for Powercolor Real Angel 330
+ * Daniel Fraga <fragabr@gmail.com>
+ */
+
+static struct ir_scancode powercolor_real_angel[] = {
+	{ 0x38, KEY_SWITCHVIDEOMODE },	/* switch inputs */
+	{ 0x0c, KEY_MEDIA },		/* Turn ON/OFF App */
+	{ 0x00, KEY_0 },
+	{ 0x01, KEY_1 },
+	{ 0x02, KEY_2 },
+	{ 0x03, KEY_3 },
+	{ 0x04, KEY_4 },
+	{ 0x05, KEY_5 },
+	{ 0x06, KEY_6 },
+	{ 0x07, KEY_7 },
+	{ 0x08, KEY_8 },
+	{ 0x09, KEY_9 },
+	{ 0x0a, KEY_DIGITS },		/* single, double, tripple digit */
+	{ 0x29, KEY_PREVIOUS },		/* previous channel */
+	{ 0x12, KEY_BRIGHTNESSUP },
+	{ 0x13, KEY_BRIGHTNESSDOWN },
+	{ 0x2b, KEY_MODE },		/* stereo/mono */
+	{ 0x2c, KEY_TEXT },		/* teletext */
+	{ 0x20, KEY_CHANNELUP },	/* channel up */
+	{ 0x21, KEY_CHANNELDOWN },	/* channel down */
+	{ 0x10, KEY_VOLUMEUP },		/* volume up */
+	{ 0x11, KEY_VOLUMEDOWN },	/* volume down */
+	{ 0x0d, KEY_MUTE },
+	{ 0x1f, KEY_RECORD },
+	{ 0x17, KEY_PLAY },
+	{ 0x16, KEY_PAUSE },
+	{ 0x0b, KEY_STOP },
+	{ 0x27, KEY_FASTFORWARD },
+	{ 0x26, KEY_REWIND },
+	{ 0x1e, KEY_SEARCH },		/* autoscan */
+	{ 0x0e, KEY_CAMERA },		/* snapshot */
+	{ 0x2d, KEY_SETUP },
+	{ 0x0f, KEY_SCREEN },		/* full screen */
+	{ 0x14, KEY_RADIO },		/* FM radio */
+	{ 0x25, KEY_POWER },		/* power */
+};
+
+static struct rc_keymap powercolor_real_angel_map = {
+	.map = {
+		.scan    = powercolor_real_angel,
+		.size    = ARRAY_SIZE(powercolor_real_angel),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_POWERCOLOR_REAL_ANGEL,
+	}
+};
+
+static int __init init_rc_map_powercolor_real_angel(void)
+{
+	return ir_register_map(&powercolor_real_angel_map);
+}
+
+static void __exit exit_rc_map_powercolor_real_angel(void)
+{
+	ir_unregister_map(&powercolor_real_angel_map);
+}
+
+module_init(init_rc_map_powercolor_real_angel)
+module_exit(exit_rc_map_powercolor_real_angel)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-proteus-2309.c b/drivers/media/IR/keymaps/rc-proteus-2309.c
new file mode 100644
index 0000000..22e92d3
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-proteus-2309.c
@@ -0,0 +1,69 @@
+/* proteus-2309.h - Keytable for proteus_2309 Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Michal Majchrowicz <mmajchrowicz@gmail.com> */
+
+static struct ir_scancode proteus_2309[] = {
+	/* numeric */
+	{ 0x00, KEY_0 },
+	{ 0x01, KEY_1 },
+	{ 0x02, KEY_2 },
+	{ 0x03, KEY_3 },
+	{ 0x04, KEY_4 },
+	{ 0x05, KEY_5 },
+	{ 0x06, KEY_6 },
+	{ 0x07, KEY_7 },
+	{ 0x08, KEY_8 },
+	{ 0x09, KEY_9 },
+
+	{ 0x5c, KEY_POWER },		/* power       */
+	{ 0x20, KEY_ZOOM },		/* full screen */
+	{ 0x0f, KEY_BACKSPACE },	/* recall      */
+	{ 0x1b, KEY_ENTER },		/* mute        */
+	{ 0x41, KEY_RECORD },		/* record      */
+	{ 0x43, KEY_STOP },		/* stop        */
+	{ 0x16, KEY_S },
+	{ 0x1a, KEY_POWER2 },		/* off         */
+	{ 0x2e, KEY_RED },
+	{ 0x1f, KEY_CHANNELDOWN },	/* channel -   */
+	{ 0x1c, KEY_CHANNELUP },	/* channel +   */
+	{ 0x10, KEY_VOLUMEDOWN },	/* volume -    */
+	{ 0x1e, KEY_VOLUMEUP },		/* volume +    */
+	{ 0x14, KEY_F1 },
+};
+
+static struct rc_keymap proteus_2309_map = {
+	.map = {
+		.scan    = proteus_2309,
+		.size    = ARRAY_SIZE(proteus_2309),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_PROTEUS_2309,
+	}
+};
+
+static int __init init_rc_map_proteus_2309(void)
+{
+	return ir_register_map(&proteus_2309_map);
+}
+
+static void __exit exit_rc_map_proteus_2309(void)
+{
+	ir_unregister_map(&proteus_2309_map);
+}
+
+module_init(init_rc_map_proteus_2309)
+module_exit(exit_rc_map_proteus_2309)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-purpletv.c b/drivers/media/IR/keymaps/rc-purpletv.c
new file mode 100644
index 0000000..4e20fc2
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-purpletv.c
@@ -0,0 +1,81 @@
+/* purpletv.h - Keytable for purpletv Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode purpletv[] = {
+	{ 0x03, KEY_POWER },
+	{ 0x6f, KEY_MUTE },
+	{ 0x10, KEY_BACKSPACE },	/* Recall */
+
+	{ 0x11, KEY_0 },
+	{ 0x04, KEY_1 },
+	{ 0x05, KEY_2 },
+	{ 0x06, KEY_3 },
+	{ 0x08, KEY_4 },
+	{ 0x09, KEY_5 },
+	{ 0x0a, KEY_6 },
+	{ 0x0c, KEY_7 },
+	{ 0x0d, KEY_8 },
+	{ 0x0e, KEY_9 },
+	{ 0x12, KEY_DOT },	/* 100+ */
+
+	{ 0x07, KEY_VOLUMEUP },
+	{ 0x0b, KEY_VOLUMEDOWN },
+	{ 0x1a, KEY_KPPLUS },
+	{ 0x18, KEY_KPMINUS },
+	{ 0x15, KEY_UP },
+	{ 0x1d, KEY_DOWN },
+	{ 0x0f, KEY_CHANNELUP },
+	{ 0x13, KEY_CHANNELDOWN },
+	{ 0x48, KEY_ZOOM },
+
+	{ 0x1b, KEY_VIDEO },	/* Video source */
+	{ 0x1f, KEY_CAMERA },	/* Snapshot */
+	{ 0x49, KEY_LANGUAGE },	/* MTS Select */
+	{ 0x19, KEY_SEARCH },	/* Auto Scan */
+
+	{ 0x4b, KEY_RECORD },
+	{ 0x46, KEY_PLAY },
+	{ 0x45, KEY_PAUSE },	/* Pause */
+	{ 0x44, KEY_STOP },
+	{ 0x43, KEY_TIME },	/* Time Shift */
+	{ 0x17, KEY_CHANNEL },	/* SURF CH */
+	{ 0x40, KEY_FORWARD },	/* Forward ? */
+	{ 0x42, KEY_REWIND },	/* Backward ? */
+
+};
+
+static struct rc_keymap purpletv_map = {
+	.map = {
+		.scan    = purpletv,
+		.size    = ARRAY_SIZE(purpletv),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_PURPLETV,
+	}
+};
+
+static int __init init_rc_map_purpletv(void)
+{
+	return ir_register_map(&purpletv_map);
+}
+
+static void __exit exit_rc_map_purpletv(void)
+{
+	ir_unregister_map(&purpletv_map);
+}
+
+module_init(init_rc_map_purpletv)
+module_exit(exit_rc_map_purpletv)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-pv951.c b/drivers/media/IR/keymaps/rc-pv951.c
new file mode 100644
index 0000000..36679e7
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-pv951.c
@@ -0,0 +1,78 @@
+/* pv951.h - Keytable for pv951 Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Mark Phalan <phalanm@o2.ie> */
+
+static struct ir_scancode pv951[] = {
+	{ 0x00, KEY_0 },
+	{ 0x01, KEY_1 },
+	{ 0x02, KEY_2 },
+	{ 0x03, KEY_3 },
+	{ 0x04, KEY_4 },
+	{ 0x05, KEY_5 },
+	{ 0x06, KEY_6 },
+	{ 0x07, KEY_7 },
+	{ 0x08, KEY_8 },
+	{ 0x09, KEY_9 },
+
+	{ 0x12, KEY_POWER },
+	{ 0x10, KEY_MUTE },
+	{ 0x1f, KEY_VOLUMEDOWN },
+	{ 0x1b, KEY_VOLUMEUP },
+	{ 0x1a, KEY_CHANNELUP },
+	{ 0x1e, KEY_CHANNELDOWN },
+	{ 0x0e, KEY_PAGEUP },
+	{ 0x1d, KEY_PAGEDOWN },
+	{ 0x13, KEY_SOUND },
+
+	{ 0x18, KEY_KPPLUSMINUS },	/* CH +/- */
+	{ 0x16, KEY_SUBTITLE },		/* CC */
+	{ 0x0d, KEY_TEXT },		/* TTX */
+	{ 0x0b, KEY_TV },		/* AIR/CBL */
+	{ 0x11, KEY_PC },		/* PC/TV */
+	{ 0x17, KEY_OK },		/* CH RTN */
+	{ 0x19, KEY_MODE },		/* FUNC */
+	{ 0x0c, KEY_SEARCH },		/* AUTOSCAN */
+
+	/* Not sure what to do with these ones! */
+	{ 0x0f, KEY_SELECT },		/* SOURCE */
+	{ 0x0a, KEY_KPPLUS },		/* +100 */
+	{ 0x14, KEY_EQUAL },		/* SYNC */
+	{ 0x1c, KEY_MEDIA },		/* PC/TV */
+};
+
+static struct rc_keymap pv951_map = {
+	.map = {
+		.scan    = pv951,
+		.size    = ARRAY_SIZE(pv951),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_PV951,
+	}
+};
+
+static int __init init_rc_map_pv951(void)
+{
+	return ir_register_map(&pv951_map);
+}
+
+static void __exit exit_rc_map_pv951(void)
+{
+	ir_unregister_map(&pv951_map);
+}
+
+module_init(init_rc_map_pv951)
+module_exit(exit_rc_map_pv951)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-rc5-hauppauge-new.c b/drivers/media/IR/keymaps/rc-rc5-hauppauge-new.c
new file mode 100644
index 0000000..cc6b8f5
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-rc5-hauppauge-new.c
@@ -0,0 +1,103 @@
+/* rc5-hauppauge-new.h - Keytable for rc5_hauppauge_new Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/*
+ * Hauppauge:the newer, gray remotes (seems there are multiple
+ * slightly different versions), shipped with cx88+ivtv cards.
+ *
+ * This table contains the complete RC5 code, instead of just the data part
+ */
+
+static struct ir_scancode rc5_hauppauge_new[] = {
+	/* Keys 0 to 9 */
+	{ 0x1e00, KEY_0 },
+	{ 0x1e01, KEY_1 },
+	{ 0x1e02, KEY_2 },
+	{ 0x1e03, KEY_3 },
+	{ 0x1e04, KEY_4 },
+	{ 0x1e05, KEY_5 },
+	{ 0x1e06, KEY_6 },
+	{ 0x1e07, KEY_7 },
+	{ 0x1e08, KEY_8 },
+	{ 0x1e09, KEY_9 },
+
+	{ 0x1e0a, KEY_TEXT },		/* keypad asterisk as well */
+	{ 0x1e0b, KEY_RED },		/* red button */
+	{ 0x1e0c, KEY_RADIO },
+	{ 0x1e0d, KEY_MENU },
+	{ 0x1e0e, KEY_SUBTITLE },		/* also the # key */
+	{ 0x1e0f, KEY_MUTE },
+	{ 0x1e10, KEY_VOLUMEUP },
+	{ 0x1e11, KEY_VOLUMEDOWN },
+	{ 0x1e12, KEY_PREVIOUS },		/* previous channel */
+	{ 0x1e14, KEY_UP },
+	{ 0x1e15, KEY_DOWN },
+	{ 0x1e16, KEY_LEFT },
+	{ 0x1e17, KEY_RIGHT },
+	{ 0x1e18, KEY_VIDEO },		/* Videos */
+	{ 0x1e19, KEY_AUDIO },		/* Music */
+	/* 0x1e1a: Pictures - presume this means
+	   "Multimedia Home Platform" -
+	   no "PICTURES" key in input.h
+	 */
+	{ 0x1e1a, KEY_MHP },
+
+	{ 0x1e1b, KEY_EPG },		/* Guide */
+	{ 0x1e1c, KEY_TV },
+	{ 0x1e1e, KEY_NEXTSONG },		/* skip >| */
+	{ 0x1e1f, KEY_EXIT },		/* back/exit */
+	{ 0x1e20, KEY_CHANNELUP },	/* channel / program + */
+	{ 0x1e21, KEY_CHANNELDOWN },	/* channel / program - */
+	{ 0x1e22, KEY_CHANNEL },		/* source (old black remote) */
+	{ 0x1e24, KEY_PREVIOUSSONG },	/* replay |< */
+	{ 0x1e25, KEY_ENTER },		/* OK */
+	{ 0x1e26, KEY_SLEEP },		/* minimize (old black remote) */
+	{ 0x1e29, KEY_BLUE },		/* blue key */
+	{ 0x1e2e, KEY_GREEN },		/* green button */
+	{ 0x1e30, KEY_PAUSE },		/* pause */
+	{ 0x1e32, KEY_REWIND },		/* backward << */
+	{ 0x1e34, KEY_FASTFORWARD },	/* forward >> */
+	{ 0x1e35, KEY_PLAY },
+	{ 0x1e36, KEY_STOP },
+	{ 0x1e37, KEY_RECORD },		/* recording */
+	{ 0x1e38, KEY_YELLOW },		/* yellow key */
+	{ 0x1e3b, KEY_SELECT },		/* top right button */
+	{ 0x1e3c, KEY_ZOOM },		/* full */
+	{ 0x1e3d, KEY_POWER },		/* system power (green button) */
+};
+
+static struct rc_keymap rc5_hauppauge_new_map = {
+	.map = {
+		.scan    = rc5_hauppauge_new,
+		.size    = ARRAY_SIZE(rc5_hauppauge_new),
+		.ir_type = IR_TYPE_RC5,
+		.name    = RC_MAP_RC5_HAUPPAUGE_NEW,
+	}
+};
+
+static int __init init_rc_map_rc5_hauppauge_new(void)
+{
+	return ir_register_map(&rc5_hauppauge_new_map);
+}
+
+static void __exit exit_rc_map_rc5_hauppauge_new(void)
+{
+	ir_unregister_map(&rc5_hauppauge_new_map);
+}
+
+module_init(init_rc_map_rc5_hauppauge_new)
+module_exit(exit_rc_map_rc5_hauppauge_new)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-rc5-tv.c b/drivers/media/IR/keymaps/rc-rc5-tv.c
new file mode 100644
index 0000000..73cce2f
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-rc5-tv.c
@@ -0,0 +1,81 @@
+/* rc5-tv.h - Keytable for rc5_tv Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* generic RC5 keytable                                          */
+/* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */
+/* used by old (black) Hauppauge remotes                         */
+
+static struct ir_scancode rc5_tv[] = {
+	/* Keys 0 to 9 */
+	{ 0x00, KEY_0 },
+	{ 0x01, KEY_1 },
+	{ 0x02, KEY_2 },
+	{ 0x03, KEY_3 },
+	{ 0x04, KEY_4 },
+	{ 0x05, KEY_5 },
+	{ 0x06, KEY_6 },
+	{ 0x07, KEY_7 },
+	{ 0x08, KEY_8 },
+	{ 0x09, KEY_9 },
+
+	{ 0x0b, KEY_CHANNEL },		/* channel / program (japan: 11) */
+	{ 0x0c, KEY_POWER },		/* standby */
+	{ 0x0d, KEY_MUTE },		/* mute / demute */
+	{ 0x0f, KEY_TV },		/* display */
+	{ 0x10, KEY_VOLUMEUP },
+	{ 0x11, KEY_VOLUMEDOWN },
+	{ 0x12, KEY_BRIGHTNESSUP },
+	{ 0x13, KEY_BRIGHTNESSDOWN },
+	{ 0x1e, KEY_SEARCH },		/* search + */
+	{ 0x20, KEY_CHANNELUP },	/* channel / program + */
+	{ 0x21, KEY_CHANNELDOWN },	/* channel / program - */
+	{ 0x22, KEY_CHANNEL },		/* alt / channel */
+	{ 0x23, KEY_LANGUAGE },		/* 1st / 2nd language */
+	{ 0x26, KEY_SLEEP },		/* sleeptimer */
+	{ 0x2e, KEY_MENU },		/* 2nd controls (USA: menu) */
+	{ 0x30, KEY_PAUSE },
+	{ 0x32, KEY_REWIND },
+	{ 0x33, KEY_GOTO },
+	{ 0x35, KEY_PLAY },
+	{ 0x36, KEY_STOP },
+	{ 0x37, KEY_RECORD },		/* recording */
+	{ 0x3c, KEY_TEXT },		/* teletext submode (Japan: 12) */
+	{ 0x3d, KEY_SUSPEND },		/* system standby */
+
+};
+
+static struct rc_keymap rc5_tv_map = {
+	.map = {
+		.scan    = rc5_tv,
+		.size    = ARRAY_SIZE(rc5_tv),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_RC5_TV,
+	}
+};
+
+static int __init init_rc_map_rc5_tv(void)
+{
+	return ir_register_map(&rc5_tv_map);
+}
+
+static void __exit exit_rc_map_rc5_tv(void)
+{
+	ir_unregister_map(&rc5_tv_map);
+}
+
+module_init(init_rc_map_rc5_tv)
+module_exit(exit_rc_map_rc5_tv)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-real-audio-220-32-keys.c b/drivers/media/IR/keymaps/rc-real-audio-220-32-keys.c
new file mode 100644
index 0000000..ab1a6d2
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-real-audio-220-32-keys.c
@@ -0,0 +1,78 @@
+/* real-audio-220-32-keys.h - Keytable for real_audio_220_32_keys Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Zogis Real Audio 220 - 32 keys IR */
+
+static struct ir_scancode real_audio_220_32_keys[] = {
+	{ 0x1c, KEY_RADIO},
+	{ 0x12, KEY_POWER2},
+
+	{ 0x01, KEY_1},
+	{ 0x02, KEY_2},
+	{ 0x03, KEY_3},
+	{ 0x04, KEY_4},
+	{ 0x05, KEY_5},
+	{ 0x06, KEY_6},
+	{ 0x07, KEY_7},
+	{ 0x08, KEY_8},
+	{ 0x09, KEY_9},
+	{ 0x00, KEY_0},
+
+	{ 0x0c, KEY_VOLUMEUP},
+	{ 0x18, KEY_VOLUMEDOWN},
+	{ 0x0b, KEY_CHANNELUP},
+	{ 0x15, KEY_CHANNELDOWN},
+	{ 0x16, KEY_ENTER},
+
+	{ 0x11, KEY_LIST},		/* Source */
+	{ 0x0d, KEY_AUDIO},		/* stereo */
+
+	{ 0x0f, KEY_PREVIOUS},		/* Prev */
+	{ 0x1b, KEY_TIME},		/* Timeshift */
+	{ 0x1a, KEY_NEXT},		/* Next */
+
+	{ 0x0e, KEY_STOP},
+	{ 0x1f, KEY_PLAY},
+	{ 0x1e, KEY_PLAYPAUSE},		/* Pause */
+
+	{ 0x1d, KEY_RECORD},
+	{ 0x13, KEY_MUTE},
+	{ 0x19, KEY_CAMERA},		/* Snapshot */
+
+};
+
+static struct rc_keymap real_audio_220_32_keys_map = {
+	.map = {
+		.scan    = real_audio_220_32_keys,
+		.size    = ARRAY_SIZE(real_audio_220_32_keys),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_REAL_AUDIO_220_32_KEYS,
+	}
+};
+
+static int __init init_rc_map_real_audio_220_32_keys(void)
+{
+	return ir_register_map(&real_audio_220_32_keys_map);
+}
+
+static void __exit exit_rc_map_real_audio_220_32_keys(void)
+{
+	ir_unregister_map(&real_audio_220_32_keys_map);
+}
+
+module_init(init_rc_map_real_audio_220_32_keys)
+module_exit(exit_rc_map_real_audio_220_32_keys)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-tbs-nec.c b/drivers/media/IR/keymaps/rc-tbs-nec.c
new file mode 100644
index 0000000..3309631
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-tbs-nec.c
@@ -0,0 +1,73 @@
+/* tbs-nec.h - Keytable for tbs_nec Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode tbs_nec[] = {
+	{ 0x04, KEY_POWER2},	/*power*/
+	{ 0x14, KEY_MUTE},	/*mute*/
+	{ 0x07, KEY_1},
+	{ 0x06, KEY_2},
+	{ 0x05, KEY_3},
+	{ 0x0b, KEY_4},
+	{ 0x0a, KEY_5},
+	{ 0x09, KEY_6},
+	{ 0x0f, KEY_7},
+	{ 0x0e, KEY_8},
+	{ 0x0d, KEY_9},
+	{ 0x12, KEY_0},
+	{ 0x16, KEY_CHANNELUP},	/*ch+*/
+	{ 0x11, KEY_CHANNELDOWN},/*ch-*/
+	{ 0x13, KEY_VOLUMEUP},	/*vol+*/
+	{ 0x0c, KEY_VOLUMEDOWN},/*vol-*/
+	{ 0x03, KEY_RECORD},	/*rec*/
+	{ 0x18, KEY_PAUSE},	/*pause*/
+	{ 0x19, KEY_OK},	/*ok*/
+	{ 0x1a, KEY_CAMERA},	/* snapshot */
+	{ 0x01, KEY_UP},
+	{ 0x10, KEY_LEFT},
+	{ 0x02, KEY_RIGHT},
+	{ 0x08, KEY_DOWN},
+	{ 0x15, KEY_FAVORITES},
+	{ 0x17, KEY_SUBTITLE},
+	{ 0x1d, KEY_ZOOM},
+	{ 0x1f, KEY_EXIT},
+	{ 0x1e, KEY_MENU},
+	{ 0x1c, KEY_EPG},
+	{ 0x00, KEY_PREVIOUS},
+	{ 0x1b, KEY_MODE},
+};
+
+static struct rc_keymap tbs_nec_map = {
+	.map = {
+		.scan    = tbs_nec,
+		.size    = ARRAY_SIZE(tbs_nec),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_TBS_NEC,
+	}
+};
+
+static int __init init_rc_map_tbs_nec(void)
+{
+	return ir_register_map(&tbs_nec_map);
+}
+
+static void __exit exit_rc_map_tbs_nec(void)
+{
+	ir_unregister_map(&tbs_nec_map);
+}
+
+module_init(init_rc_map_tbs_nec)
+module_exit(exit_rc_map_tbs_nec)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-terratec-cinergy-xs.c b/drivers/media/IR/keymaps/rc-terratec-cinergy-xs.c
new file mode 100644
index 0000000..5326a0b
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-terratec-cinergy-xs.c
@@ -0,0 +1,92 @@
+/* terratec-cinergy-xs.h - Keytable for terratec_cinergy_xs Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Terratec Cinergy Hybrid T USB XS
+   Devin Heitmueller <dheitmueller@linuxtv.org>
+ */
+
+static struct ir_scancode terratec_cinergy_xs[] = {
+	{ 0x41, KEY_HOME},
+	{ 0x01, KEY_POWER},
+	{ 0x42, KEY_MENU},
+	{ 0x02, KEY_1},
+	{ 0x03, KEY_2},
+	{ 0x04, KEY_3},
+	{ 0x43, KEY_SUBTITLE},
+	{ 0x05, KEY_4},
+	{ 0x06, KEY_5},
+	{ 0x07, KEY_6},
+	{ 0x44, KEY_TEXT},
+	{ 0x08, KEY_7},
+	{ 0x09, KEY_8},
+	{ 0x0a, KEY_9},
+	{ 0x45, KEY_DELETE},
+	{ 0x0b, KEY_TUNER},
+	{ 0x0c, KEY_0},
+	{ 0x0d, KEY_MODE},
+	{ 0x46, KEY_TV},
+	{ 0x47, KEY_DVD},
+	{ 0x49, KEY_VIDEO},
+	{ 0x4b, KEY_AUX},
+	{ 0x10, KEY_UP},
+	{ 0x11, KEY_LEFT},
+	{ 0x12, KEY_OK},
+	{ 0x13, KEY_RIGHT},
+	{ 0x14, KEY_DOWN},
+	{ 0x0f, KEY_EPG},
+	{ 0x16, KEY_INFO},
+	{ 0x4d, KEY_BACKSPACE},
+	{ 0x1c, KEY_VOLUMEUP},
+	{ 0x4c, KEY_PLAY},
+	{ 0x1b, KEY_CHANNELUP},
+	{ 0x1e, KEY_VOLUMEDOWN},
+	{ 0x1d, KEY_MUTE},
+	{ 0x1f, KEY_CHANNELDOWN},
+	{ 0x17, KEY_RED},
+	{ 0x18, KEY_GREEN},
+	{ 0x19, KEY_YELLOW},
+	{ 0x1a, KEY_BLUE},
+	{ 0x58, KEY_RECORD},
+	{ 0x48, KEY_STOP},
+	{ 0x40, KEY_PAUSE},
+	{ 0x54, KEY_LAST},
+	{ 0x4e, KEY_REWIND},
+	{ 0x4f, KEY_FASTFORWARD},
+	{ 0x5c, KEY_NEXT},
+};
+
+static struct rc_keymap terratec_cinergy_xs_map = {
+	.map = {
+		.scan    = terratec_cinergy_xs,
+		.size    = ARRAY_SIZE(terratec_cinergy_xs),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_TERRATEC_CINERGY_XS,
+	}
+};
+
+static int __init init_rc_map_terratec_cinergy_xs(void)
+{
+	return ir_register_map(&terratec_cinergy_xs_map);
+}
+
+static void __exit exit_rc_map_terratec_cinergy_xs(void)
+{
+	ir_unregister_map(&terratec_cinergy_xs_map);
+}
+
+module_init(init_rc_map_terratec_cinergy_xs)
+module_exit(exit_rc_map_terratec_cinergy_xs)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-tevii-nec.c b/drivers/media/IR/keymaps/rc-tevii-nec.c
new file mode 100644
index 0000000..e30d411
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-tevii-nec.c
@@ -0,0 +1,88 @@
+/* tevii-nec.h - Keytable for tevii_nec Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode tevii_nec[] = {
+	{ 0x0a, KEY_POWER2},
+	{ 0x0c, KEY_MUTE},
+	{ 0x11, KEY_1},
+	{ 0x12, KEY_2},
+	{ 0x13, KEY_3},
+	{ 0x14, KEY_4},
+	{ 0x15, KEY_5},
+	{ 0x16, KEY_6},
+	{ 0x17, KEY_7},
+	{ 0x18, KEY_8},
+	{ 0x19, KEY_9},
+	{ 0x10, KEY_0},
+	{ 0x1c, KEY_MENU},
+	{ 0x0f, KEY_VOLUMEDOWN},
+	{ 0x1a, KEY_LAST},
+	{ 0x0e, KEY_OPEN},
+	{ 0x04, KEY_RECORD},
+	{ 0x09, KEY_VOLUMEUP},
+	{ 0x08, KEY_CHANNELUP},
+	{ 0x07, KEY_PVR},
+	{ 0x0b, KEY_TIME},
+	{ 0x02, KEY_RIGHT},
+	{ 0x03, KEY_LEFT},
+	{ 0x00, KEY_UP},
+	{ 0x1f, KEY_OK},
+	{ 0x01, KEY_DOWN},
+	{ 0x05, KEY_TUNER},
+	{ 0x06, KEY_CHANNELDOWN},
+	{ 0x40, KEY_PLAYPAUSE},
+	{ 0x1e, KEY_REWIND},
+	{ 0x1b, KEY_FAVORITES},
+	{ 0x1d, KEY_BACK},
+	{ 0x4d, KEY_FASTFORWARD},
+	{ 0x44, KEY_EPG},
+	{ 0x4c, KEY_INFO},
+	{ 0x41, KEY_AB},
+	{ 0x43, KEY_AUDIO},
+	{ 0x45, KEY_SUBTITLE},
+	{ 0x4a, KEY_LIST},
+	{ 0x46, KEY_F1},
+	{ 0x47, KEY_F2},
+	{ 0x5e, KEY_F3},
+	{ 0x5c, KEY_F4},
+	{ 0x52, KEY_F5},
+	{ 0x5a, KEY_F6},
+	{ 0x56, KEY_MODE},
+	{ 0x58, KEY_SWITCHVIDEOMODE},
+};
+
+static struct rc_keymap tevii_nec_map = {
+	.map = {
+		.scan    = tevii_nec,
+		.size    = ARRAY_SIZE(tevii_nec),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_TEVII_NEC,
+	}
+};
+
+static int __init init_rc_map_tevii_nec(void)
+{
+	return ir_register_map(&tevii_nec_map);
+}
+
+static void __exit exit_rc_map_tevii_nec(void)
+{
+	ir_unregister_map(&tevii_nec_map);
+}
+
+module_init(init_rc_map_tevii_nec)
+module_exit(exit_rc_map_tevii_nec)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-tt-1500.c b/drivers/media/IR/keymaps/rc-tt-1500.c
new file mode 100644
index 0000000..bc88de0
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-tt-1500.c
@@ -0,0 +1,82 @@
+/* tt-1500.h - Keytable for tt_1500 Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* for the Technotrend 1500 bundled remotes (grey and black): */
+
+static struct ir_scancode tt_1500[] = {
+	{ 0x01, KEY_POWER },
+	{ 0x02, KEY_SHUFFLE },		/* ? double-arrow key */
+	{ 0x03, KEY_1 },
+	{ 0x04, KEY_2 },
+	{ 0x05, KEY_3 },
+	{ 0x06, KEY_4 },
+	{ 0x07, KEY_5 },
+	{ 0x08, KEY_6 },
+	{ 0x09, KEY_7 },
+	{ 0x0a, KEY_8 },
+	{ 0x0b, KEY_9 },
+	{ 0x0c, KEY_0 },
+	{ 0x0d, KEY_UP },
+	{ 0x0e, KEY_LEFT },
+	{ 0x0f, KEY_OK },
+	{ 0x10, KEY_RIGHT },
+	{ 0x11, KEY_DOWN },
+	{ 0x12, KEY_INFO },
+	{ 0x13, KEY_EXIT },
+	{ 0x14, KEY_RED },
+	{ 0x15, KEY_GREEN },
+	{ 0x16, KEY_YELLOW },
+	{ 0x17, KEY_BLUE },
+	{ 0x18, KEY_MUTE },
+	{ 0x19, KEY_TEXT },
+	{ 0x1a, KEY_MODE },		/* ? TV/Radio */
+	{ 0x21, KEY_OPTION },
+	{ 0x22, KEY_EPG },
+	{ 0x23, KEY_CHANNELUP },
+	{ 0x24, KEY_CHANNELDOWN },
+	{ 0x25, KEY_VOLUMEUP },
+	{ 0x26, KEY_VOLUMEDOWN },
+	{ 0x27, KEY_SETUP },
+	{ 0x3a, KEY_RECORD },		/* these keys are only in the black remote */
+	{ 0x3b, KEY_PLAY },
+	{ 0x3c, KEY_STOP },
+	{ 0x3d, KEY_REWIND },
+	{ 0x3e, KEY_PAUSE },
+	{ 0x3f, KEY_FORWARD },
+};
+
+static struct rc_keymap tt_1500_map = {
+	.map = {
+		.scan    = tt_1500,
+		.size    = ARRAY_SIZE(tt_1500),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_TT_1500,
+	}
+};
+
+static int __init init_rc_map_tt_1500(void)
+{
+	return ir_register_map(&tt_1500_map);
+}
+
+static void __exit exit_rc_map_tt_1500(void)
+{
+	ir_unregister_map(&tt_1500_map);
+}
+
+module_init(init_rc_map_tt_1500)
+module_exit(exit_rc_map_tt_1500)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-videomate-s350.c b/drivers/media/IR/keymaps/rc-videomate-s350.c
new file mode 100644
index 0000000..4df7fcd
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-videomate-s350.c
@@ -0,0 +1,85 @@
+/* videomate-s350.h - Keytable for videomate_s350 Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode videomate_s350[] = {
+	{ 0x00, KEY_TV},
+	{ 0x01, KEY_DVD},
+	{ 0x04, KEY_RECORD},
+	{ 0x05, KEY_VIDEO},	/* TV/Video */
+	{ 0x07, KEY_STOP},
+	{ 0x08, KEY_PLAYPAUSE},
+	{ 0x0a, KEY_REWIND},
+	{ 0x0f, KEY_FASTFORWARD},
+	{ 0x10, KEY_CHANNELUP},
+	{ 0x12, KEY_VOLUMEUP},
+	{ 0x13, KEY_CHANNELDOWN},
+	{ 0x14, KEY_MUTE},
+	{ 0x15, KEY_VOLUMEDOWN},
+	{ 0x16, KEY_1},
+	{ 0x17, KEY_2},
+	{ 0x18, KEY_3},
+	{ 0x19, KEY_4},
+	{ 0x1a, KEY_5},
+	{ 0x1b, KEY_6},
+	{ 0x1c, KEY_7},
+	{ 0x1d, KEY_8},
+	{ 0x1e, KEY_9},
+	{ 0x1f, KEY_0},
+	{ 0x21, KEY_SLEEP},
+	{ 0x24, KEY_ZOOM},
+	{ 0x25, KEY_LAST},	/* Recall */
+	{ 0x26, KEY_SUBTITLE},	/* CC */
+	{ 0x27, KEY_LANGUAGE},	/* MTS */
+	{ 0x29, KEY_CHANNEL},	/* SURF */
+	{ 0x2b, KEY_A},
+	{ 0x2c, KEY_B},
+	{ 0x2f, KEY_CAMERA},	/* Snapshot */
+	{ 0x23, KEY_RADIO},
+	{ 0x02, KEY_PREVIOUSSONG},
+	{ 0x06, KEY_NEXTSONG},
+	{ 0x03, KEY_EPG},
+	{ 0x09, KEY_SETUP},
+	{ 0x22, KEY_BACKSPACE},
+	{ 0x0c, KEY_UP},
+	{ 0x0e, KEY_DOWN},
+	{ 0x0b, KEY_LEFT},
+	{ 0x0d, KEY_RIGHT},
+	{ 0x11, KEY_ENTER},
+	{ 0x20, KEY_TEXT},
+};
+
+static struct rc_keymap videomate_s350_map = {
+	.map = {
+		.scan    = videomate_s350,
+		.size    = ARRAY_SIZE(videomate_s350),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_VIDEOMATE_S350,
+	}
+};
+
+static int __init init_rc_map_videomate_s350(void)
+{
+	return ir_register_map(&videomate_s350_map);
+}
+
+static void __exit exit_rc_map_videomate_s350(void)
+{
+	ir_unregister_map(&videomate_s350_map);
+}
+
+module_init(init_rc_map_videomate_s350)
+module_exit(exit_rc_map_videomate_s350)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-videomate-tv-pvr.c b/drivers/media/IR/keymaps/rc-videomate-tv-pvr.c
new file mode 100644
index 0000000..776b0a6
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-videomate-tv-pvr.c
@@ -0,0 +1,87 @@
+/* videomate-tv-pvr.h - Keytable for videomate_tv_pvr Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode videomate_tv_pvr[] = {
+	{ 0x14, KEY_MUTE },
+	{ 0x24, KEY_ZOOM },
+
+	{ 0x01, KEY_DVD },
+	{ 0x23, KEY_RADIO },
+	{ 0x00, KEY_TV },
+
+	{ 0x0a, KEY_REWIND },
+	{ 0x08, KEY_PLAYPAUSE },
+	{ 0x0f, KEY_FORWARD },
+
+	{ 0x02, KEY_PREVIOUS },
+	{ 0x07, KEY_STOP },
+	{ 0x06, KEY_NEXT },
+
+	{ 0x0c, KEY_UP },
+	{ 0x0e, KEY_DOWN },
+	{ 0x0b, KEY_LEFT },
+	{ 0x0d, KEY_RIGHT },
+	{ 0x11, KEY_OK },
+
+	{ 0x03, KEY_MENU },
+	{ 0x09, KEY_SETUP },
+	{ 0x05, KEY_VIDEO },
+	{ 0x22, KEY_CHANNEL },
+
+	{ 0x12, KEY_VOLUMEUP },
+	{ 0x15, KEY_VOLUMEDOWN },
+	{ 0x10, KEY_CHANNELUP },
+	{ 0x13, KEY_CHANNELDOWN },
+
+	{ 0x04, KEY_RECORD },
+
+	{ 0x16, KEY_1 },
+	{ 0x17, KEY_2 },
+	{ 0x18, KEY_3 },
+	{ 0x19, KEY_4 },
+	{ 0x1a, KEY_5 },
+	{ 0x1b, KEY_6 },
+	{ 0x1c, KEY_7 },
+	{ 0x1d, KEY_8 },
+	{ 0x1e, KEY_9 },
+	{ 0x1f, KEY_0 },
+
+	{ 0x20, KEY_LANGUAGE },
+	{ 0x21, KEY_SLEEP },
+};
+
+static struct rc_keymap videomate_tv_pvr_map = {
+	.map = {
+		.scan    = videomate_tv_pvr,
+		.size    = ARRAY_SIZE(videomate_tv_pvr),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_VIDEOMATE_TV_PVR,
+	}
+};
+
+static int __init init_rc_map_videomate_tv_pvr(void)
+{
+	return ir_register_map(&videomate_tv_pvr_map);
+}
+
+static void __exit exit_rc_map_videomate_tv_pvr(void)
+{
+	ir_unregister_map(&videomate_tv_pvr_map);
+}
+
+module_init(init_rc_map_videomate_tv_pvr)
+module_exit(exit_rc_map_videomate_tv_pvr)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-winfast-usbii-deluxe.c b/drivers/media/IR/keymaps/rc-winfast-usbii-deluxe.c
new file mode 100644
index 0000000..9d2d550
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-winfast-usbii-deluxe.c
@@ -0,0 +1,82 @@
+/* winfast-usbii-deluxe.h - Keytable for winfast_usbii_deluxe Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Leadtek Winfast TV USB II Deluxe remote
+   Magnus Alm <magnus.alm@gmail.com>
+ */
+
+static struct ir_scancode winfast_usbii_deluxe[] = {
+	{ 0x62, KEY_0},
+	{ 0x75, KEY_1},
+	{ 0x76, KEY_2},
+	{ 0x77, KEY_3},
+	{ 0x79, KEY_4},
+	{ 0x7a, KEY_5},
+	{ 0x7b, KEY_6},
+	{ 0x7d, KEY_7},
+	{ 0x7e, KEY_8},
+	{ 0x7f, KEY_9},
+
+	{ 0x38, KEY_CAMERA},		/* SNAPSHOT */
+	{ 0x37, KEY_RECORD},		/* RECORD */
+	{ 0x35, KEY_TIME},		/* TIMESHIFT */
+
+	{ 0x74, KEY_VOLUMEUP},		/* VOLUMEUP */
+	{ 0x78, KEY_VOLUMEDOWN},	/* VOLUMEDOWN */
+	{ 0x64, KEY_MUTE},		/* MUTE */
+
+	{ 0x21, KEY_CHANNEL},		/* SURF */
+	{ 0x7c, KEY_CHANNELUP},		/* CHANNELUP */
+	{ 0x60, KEY_CHANNELDOWN},	/* CHANNELDOWN */
+	{ 0x61, KEY_LAST},		/* LAST CHANNEL (RECALL) */
+
+	{ 0x72, KEY_VIDEO}, 		/* INPUT MODES (TV/FM) */
+
+	{ 0x70, KEY_POWER2},		/* TV ON/OFF */
+
+	{ 0x39, KEY_CYCLEWINDOWS},	/* MINIMIZE (BOSS) */
+	{ 0x3a, KEY_NEW},		/* PIP */
+	{ 0x73, KEY_ZOOM},		/* FULLSECREEN */
+
+	{ 0x66, KEY_INFO},		/* OSD (DISPLAY) */
+
+	{ 0x31, KEY_DOT},		/* '.' */
+	{ 0x63, KEY_ENTER},		/* ENTER */
+
+};
+
+static struct rc_keymap winfast_usbii_deluxe_map = {
+	.map = {
+		.scan    = winfast_usbii_deluxe,
+		.size    = ARRAY_SIZE(winfast_usbii_deluxe),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_WINFAST_USBII_DELUXE,
+	}
+};
+
+static int __init init_rc_map_winfast_usbii_deluxe(void)
+{
+	return ir_register_map(&winfast_usbii_deluxe_map);
+}
+
+static void __exit exit_rc_map_winfast_usbii_deluxe(void)
+{
+	ir_unregister_map(&winfast_usbii_deluxe_map);
+}
+
+module_init(init_rc_map_winfast_usbii_deluxe)
+module_exit(exit_rc_map_winfast_usbii_deluxe)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-winfast.c b/drivers/media/IR/keymaps/rc-winfast.c
new file mode 100644
index 0000000..0e90a3b
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-winfast.c
@@ -0,0 +1,102 @@
+/* winfast.h - Keytable for winfast Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */
+
+static struct ir_scancode winfast[] = {
+	/* Keys 0 to 9 */
+	{ 0x12, KEY_0 },
+	{ 0x05, KEY_1 },
+	{ 0x06, KEY_2 },
+	{ 0x07, KEY_3 },
+	{ 0x09, KEY_4 },
+	{ 0x0a, KEY_5 },
+	{ 0x0b, KEY_6 },
+	{ 0x0d, KEY_7 },
+	{ 0x0e, KEY_8 },
+	{ 0x0f, KEY_9 },
+
+	{ 0x00, KEY_POWER },
+	{ 0x1b, KEY_AUDIO },		/* Audio Source */
+	{ 0x02, KEY_TUNER },		/* TV/FM, not on Y0400052 */
+	{ 0x1e, KEY_VIDEO },		/* Video Source */
+	{ 0x16, KEY_INFO },		/* Display information */
+	{ 0x04, KEY_VOLUMEUP },
+	{ 0x08, KEY_VOLUMEDOWN },
+	{ 0x0c, KEY_CHANNELUP },
+	{ 0x10, KEY_CHANNELDOWN },
+	{ 0x03, KEY_ZOOM },		/* fullscreen */
+	{ 0x1f, KEY_TEXT },		/* closed caption/teletext */
+	{ 0x20, KEY_SLEEP },
+	{ 0x29, KEY_CLEAR },		/* boss key */
+	{ 0x14, KEY_MUTE },
+	{ 0x2b, KEY_RED },
+	{ 0x2c, KEY_GREEN },
+	{ 0x2d, KEY_YELLOW },
+	{ 0x2e, KEY_BLUE },
+	{ 0x18, KEY_KPPLUS },		/* fine tune + , not on Y040052 */
+	{ 0x19, KEY_KPMINUS },		/* fine tune - , not on Y040052 */
+	{ 0x2a, KEY_MEDIA },		/* PIP (Picture in picture */
+	{ 0x21, KEY_DOT },
+	{ 0x13, KEY_ENTER },
+	{ 0x11, KEY_LAST },		/* Recall (last channel */
+	{ 0x22, KEY_PREVIOUS },
+	{ 0x23, KEY_PLAYPAUSE },
+	{ 0x24, KEY_NEXT },
+	{ 0x25, KEY_TIME },		/* Time Shifting */
+	{ 0x26, KEY_STOP },
+	{ 0x27, KEY_RECORD },
+	{ 0x28, KEY_SAVE },		/* Screenshot */
+	{ 0x2f, KEY_MENU },
+	{ 0x30, KEY_CANCEL },
+	{ 0x31, KEY_CHANNEL },		/* Channel Surf */
+	{ 0x32, KEY_SUBTITLE },
+	{ 0x33, KEY_LANGUAGE },
+	{ 0x34, KEY_REWIND },
+	{ 0x35, KEY_FASTFORWARD },
+	{ 0x36, KEY_TV },
+	{ 0x37, KEY_RADIO },		/* FM */
+	{ 0x38, KEY_DVD },
+
+	{ 0x1a, KEY_MODE},		/* change to MCE mode on Y04G0051 */
+	{ 0x3e, KEY_F21 },		/* MCE +VOL, on Y04G0033 */
+	{ 0x3a, KEY_F22 },		/* MCE -VOL, on Y04G0033 */
+	{ 0x3b, KEY_F23 },		/* MCE +CH,  on Y04G0033 */
+	{ 0x3f, KEY_F24 }		/* MCE -CH,  on Y04G0033 */
+};
+
+static struct rc_keymap winfast_map = {
+	.map = {
+		.scan    = winfast,
+		.size    = ARRAY_SIZE(winfast),
+		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_WINFAST,
+	}
+};
+
+static int __init init_rc_map_winfast(void)
+{
+	return ir_register_map(&winfast_map);
+}
+
+static void __exit exit_rc_map_winfast(void)
+{
+	ir_unregister_map(&winfast_map);
+}
+
+module_init(init_rc_map_winfast)
+module_exit(exit_rc_map_winfast)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/rc-map.c b/drivers/media/IR/rc-map.c
new file mode 100644
index 0000000..46a8f15
--- /dev/null
+++ b/drivers/media/IR/rc-map.c
@@ -0,0 +1,84 @@
+/* ir-raw-event.c - handle IR Pulse/Space event
+ *
+ * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+
+#include <media/ir-core.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+
+/* Used to handle IR raw handler extensions */
+static LIST_HEAD(rc_map_list);
+static DEFINE_SPINLOCK(rc_map_lock);
+
+static struct rc_keymap *seek_rc_map(const char *name)
+{
+	struct rc_keymap *map = NULL;
+
+	spin_lock(&rc_map_lock);
+	list_for_each_entry(map, &rc_map_list, list) {
+		if (!strcmp(name, map->map.name)) {
+			spin_unlock(&rc_map_lock);
+			return map;
+		}
+	}
+	spin_unlock(&rc_map_lock);
+
+	return NULL;
+}
+
+struct ir_scancode_table *get_rc_map(const char *name)
+{
+
+	struct rc_keymap *map;
+
+	map = seek_rc_map(name);
+#ifdef MODULE
+	if (!map) {
+		int rc = request_module(name);
+		if (rc < 0) {
+			printk(KERN_ERR "Couldn't load IR keymap %s\n", name);
+			return NULL;
+		}
+		msleep(20);	/* Give some time for IR to register */
+
+		map = seek_rc_map(name);
+	}
+#endif
+	if (!map) {
+		printk(KERN_ERR "IR keymap %s not found\n", name);
+		return NULL;
+	}
+
+	printk(KERN_INFO "Registered IR keymap %s\n", map->map.name);
+
+	return &map->map;
+}
+EXPORT_SYMBOL_GPL(get_rc_map);
+
+int ir_register_map(struct rc_keymap *map)
+{
+	spin_lock(&rc_map_lock);
+	list_add_tail(&map->list, &rc_map_list);
+	spin_unlock(&rc_map_lock);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ir_register_map);
+
+void ir_unregister_map(struct rc_keymap *map)
+{
+	spin_lock(&rc_map_lock);
+	list_del(&map->list);
+	spin_unlock(&rc_map_lock);
+}
+EXPORT_SYMBOL_GPL(ir_unregister_map);
+
diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c
index 96d6170..b6ce528 100644
--- a/drivers/media/common/tuners/tuner-xc2028.c
+++ b/drivers/media/common/tuners/tuner-xc2028.c
@@ -100,6 +100,8 @@
 	if (size != _rc)						\
 		tuner_info("i2c output error: rc = %d (should be %d)\n",\
 			   _rc, (int)size);				\
+	if (priv->ctrl.msleep)						\
+		msleep(priv->ctrl.msleep);				\
 	_rc;								\
 })
 
@@ -119,6 +121,8 @@
 	if (isize != _rc)						\
 		tuner_err("i2c input error: rc = %d (should be %d)\n",	\
 			   _rc, (int)isize); 				\
+	if (priv->ctrl.msleep)						\
+		msleep(priv->ctrl.msleep);				\
 	_rc;								\
 })
 
@@ -129,8 +133,8 @@
 			(_rc = tuner_i2c_xfer_send(&priv->i2c_props,	\
 						_val, sizeof(_val)))) {	\
 		tuner_err("Error on line %d: %d\n", __LINE__, _rc);	\
-	} else 								\
-		msleep(10);						\
+	} else if (priv->ctrl.msleep)					\
+		msleep(priv->ctrl.msleep);				\
 	_rc;								\
 })
 
@@ -809,10 +813,20 @@
 		  hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8,
 		  (version & 0xf0) >> 4, version & 0xf);
 
+
+	if (priv->ctrl.read_not_reliable)
+		goto read_not_reliable;
+
 	/* Check firmware version against what we downloaded. */
 	if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) {
-		tuner_err("Incorrect readback of firmware version.\n");
-		goto fail;
+		if (!priv->ctrl.read_not_reliable) {
+			tuner_err("Incorrect readback of firmware version.\n");
+			goto fail;
+		} else {
+			tuner_err("Returned an incorrect version. However, "
+				  "read is not reliable enough. Ignoring it.\n");
+			hwmodel = 3028;
+		}
 	}
 
 	/* Check that the tuner hardware model remains consistent over time. */
@@ -826,6 +840,7 @@
 		goto fail;
 	}
 
+read_not_reliable:
 	memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw));
 
 	/*
@@ -996,6 +1011,8 @@
 	   The reset CLK is needed only with tm6000.
 	   Driver should work fine even if this fails.
 	 */
+	if (priv->ctrl.msleep)
+		msleep(priv->ctrl.msleep);
 	do_tuner_callback(fe, XC2028_RESET_CLK, 1);
 
 	msleep(10);
diff --git a/drivers/media/common/tuners/tuner-xc2028.h b/drivers/media/common/tuners/tuner-xc2028.h
index a90c35d..9778c96 100644
--- a/drivers/media/common/tuners/tuner-xc2028.h
+++ b/drivers/media/common/tuners/tuner-xc2028.h
@@ -33,12 +33,14 @@
 struct xc2028_ctrl {
 	char			*fname;
 	int			max_len;
+	int			msleep;
 	unsigned int		scode_table;
 	unsigned int		mts   :1;
 	unsigned int		input1:1;
 	unsigned int		vhfbw7:1;
 	unsigned int		uhfbw8:1;
 	unsigned int		disable_power_mgmt:1;
+	unsigned int            read_not_reliable:1;
 	unsigned int		demod;
 	enum firmware_type	type:2;
 };
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 8b0cde3..248a2a9 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -930,7 +930,6 @@
 		dprintk(verbose, DST_INFO, 1, "Unsupported Command");
 		return -1;
 	}
-	memset(&state->fw_version, '\0', 8);
 	memcpy(&state->fw_version, &state->rxbuffer, 8);
 	dprintk(verbose, DST_ERROR, 1, "Firmware Ver = %x.%x Build = %02x, on %x:%x, %x-%x-20%02x",
 		state->fw_version[0] >> 4, state->fw_version[0] & 0x0f,
@@ -1053,7 +1052,6 @@
 			goto force;
 		}
 	}
-	memset(&state->board_info, '\0', 8);
 	memcpy(&state->board_info, &state->rxbuffer, 8);
 	if (state->type_flags & DST_TYPE_HAS_MULTI_FE) {
 		dprintk(verbose, DST_ERROR, 1, "DST type has TS=188");
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c
index b6d4696..b762e56 100644
--- a/drivers/media/dvb/dm1105/dm1105.c
+++ b/drivers/media/dvb/dm1105/dm1105.c
@@ -28,7 +28,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/input.h>
 #include <linux/slab.h>
-#include <media/ir-common.h>
+#include <media/ir-core.h>
 
 #include "demux.h"
 #include "dmxdev.h"
@@ -46,6 +46,8 @@
 #include "z0194a.h"
 #include "ds3000.h"
 
+#define MODULE_NAME "dm1105"
+
 #define UNSET (-1U)
 
 #define DM1105_BOARD_NOAUTO		UNSET
@@ -265,7 +267,6 @@
 /* infrared remote control */
 struct infrared {
 	struct input_dev	*input_dev;
-	struct ir_input_state	ir;
 	char			input_phys[32];
 	struct work_struct	work;
 	u32			ir_command;
@@ -531,8 +532,7 @@
 
 	data = (ircom >> 8) & 0x7f;
 
-	ir_input_keydown(ir->input_dev, &ir->ir, data);
-	ir_input_nokey(ir->input_dev, &ir->ir);
+	ir_keydown(ir->input_dev, data, 0);
 }
 
 /* work handler */
@@ -594,8 +594,7 @@
 int __devinit dm1105_ir_init(struct dm1105_dev *dm1105)
 {
 	struct input_dev *input_dev;
-	struct ir_scancode_table *ir_codes = &ir_codes_dm1105_nec_table;
-	u64 ir_type = IR_TYPE_OTHER;
+	char *ir_codes = NULL;
 	int err = -ENOMEM;
 
 	input_dev = input_allocate_device();
@@ -606,12 +605,6 @@
 	snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys),
 		"pci-%s/ir0", pci_name(dm1105->pdev));
 
-	err = ir_input_init(input_dev, &dm1105->ir.ir, ir_type);
-	if (err < 0) {
-		input_free_device(input_dev);
-		return err;
-	}
-
 	input_dev->name = "DVB on-card IR receiver";
 	input_dev->phys = dm1105->ir.input_phys;
 	input_dev->id.bustype = BUS_PCI;
@@ -628,9 +621,13 @@
 
 	INIT_WORK(&dm1105->ir.work, dm1105_emit_key);
 
-	err = ir_input_register(input_dev, ir_codes, NULL);
+	err = ir_input_register(input_dev, ir_codes, NULL, MODULE_NAME);
+	if (err < 0) {
+		input_free_device(input_dev);
+		return err;
+	}
 
-	return err;
+	return 0;
 }
 
 void __devexit dm1105_ir_exit(struct dm1105_dev *dm1105)
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 67f189b..977ddba 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -426,7 +426,7 @@
 		};
 	};
 
-	if (demux->cnt_storage) {
+	if (demux->cnt_storage && dvb_demux_tscheck) {
 		/* check pkt counter */
 		if (pid < MAX_PID) {
 			if (buf[1] & 0x80)
@@ -1248,12 +1248,9 @@
 		dvbdemux->feed[i].index = i;
 	}
 
-	if (dvb_demux_tscheck) {
-		dvbdemux->cnt_storage = vmalloc(MAX_PID + 1);
-
-		if (!dvbdemux->cnt_storage)
-			printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n");
-	}
+	dvbdemux->cnt_storage = vmalloc(MAX_PID + 1);
+	if (!dvbdemux->cnt_storage)
+		printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n");
 
 	INIT_LIST_HEAD(&dvbdemux->frontend_list);
 
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 55ea260..6932def 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -95,6 +95,10 @@
  * FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again.
  */
 
+#define DVB_FE_NO_EXIT	0
+#define DVB_FE_NORMAL_EXIT	1
+#define DVB_FE_DEVICE_REMOVED	2
+
 static DEFINE_MUTEX(frontend_mutex);
 
 struct dvb_frontend_private {
@@ -497,7 +501,7 @@
 {
 	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 
-	if (fepriv->exit)
+	if (fepriv->exit != DVB_FE_NO_EXIT)
 		return 1;
 
 	if (fepriv->dvbdev->writers == 1)
@@ -559,7 +563,7 @@
 
 		if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
 			/* got signal or quitting */
-			fepriv->exit = 1;
+			fepriv->exit = DVB_FE_NORMAL_EXIT;
 			break;
 		}
 
@@ -673,7 +677,10 @@
 	}
 
 	fepriv->thread = NULL;
-	fepriv->exit = 0;
+	if (kthread_should_stop())
+		fepriv->exit = DVB_FE_DEVICE_REMOVED;
+	else
+		fepriv->exit = DVB_FE_NO_EXIT;
 	mb();
 
 	dvb_frontend_wakeup(fe);
@@ -686,7 +693,7 @@
 
 	dprintk ("%s\n", __func__);
 
-	fepriv->exit = 1;
+	fepriv->exit = DVB_FE_NORMAL_EXIT;
 	mb();
 
 	if (!fepriv->thread)
@@ -755,7 +762,7 @@
 	dprintk ("%s\n", __func__);
 
 	if (fepriv->thread) {
-		if (!fepriv->exit)
+		if (fepriv->exit == DVB_FE_NO_EXIT)
 			return 0;
 		else
 			dvb_frontend_stop (fe);
@@ -767,7 +774,7 @@
 		return -EINTR;
 
 	fepriv->state = FESTATE_IDLE;
-	fepriv->exit = 0;
+	fepriv->exit = DVB_FE_NO_EXIT;
 	fepriv->thread = NULL;
 	mb();
 
@@ -1490,7 +1497,7 @@
 
 	dprintk("%s (%d)\n", __func__, _IOC_NR(cmd));
 
-	if (fepriv->exit)
+	if (fepriv->exit != DVB_FE_NO_EXIT)
 		return -ENODEV;
 
 	if ((file->f_flags & O_ACCMODE) == O_RDONLY &&
@@ -1916,6 +1923,8 @@
 	int ret;
 
 	dprintk ("%s\n", __func__);
+	if (fepriv->exit == DVB_FE_DEVICE_REMOVED)
+		return -ENODEV;
 
 	if (adapter->mfe_shared) {
 		mutex_lock (&adapter->mfe_lock);
@@ -2008,7 +2017,7 @@
 	ret = dvb_generic_release (inode, file);
 
 	if (dvbdev->users == -1) {
-		if (fepriv->exit == 1) {
+		if (fepriv->exit != DVB_FE_NO_EXIT) {
 			fops_put(file->f_op);
 			file->f_op = NULL;
 			wake_up(&dvbdev->wait_queue);
diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c
index 6247239..b6cbb1d 100644
--- a/drivers/media/dvb/dvb-usb/a800.c
+++ b/drivers/media/dvb/dvb-usb/a800.c
@@ -37,7 +37,7 @@
 	return 0;
 }
 
-static struct dvb_usb_rc_key a800_rc_keys[] = {
+static struct dvb_usb_rc_key ir_codes_a800_table[] = {
 	{ 0x0201, KEY_PROG1 },       /* SOURCE */
 	{ 0x0200, KEY_POWER },       /* POWER */
 	{ 0x0205, KEY_1 },           /* 1 */
@@ -147,8 +147,8 @@
 	.identify_state   = a800_identify_state,
 
 	.rc_interval      = DEFAULT_RC_INTERVAL,
-	.rc_key_map       = a800_rc_keys,
-	.rc_key_map_size  = ARRAY_SIZE(a800_rc_keys),
+	.rc_key_map       = ir_codes_a800_table,
+	.rc_key_map_size  = ARRAY_SIZE(ir_codes_a800_table),
 	.rc_query         = a800_rc_query,
 
 	.i2c_algo         = &dibusb_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/af9005-remote.c b/drivers/media/dvb/dvb-usb/af9005-remote.c
index f4379c6..b41fa87 100644
--- a/drivers/media/dvb/dvb-usb/af9005-remote.c
+++ b/drivers/media/dvb/dvb-usb/af9005-remote.c
@@ -33,7 +33,7 @@
 
 #define deb_decode(args...)   dprintk(dvb_usb_af9005_remote_debug,0x01,args)
 
-struct dvb_usb_rc_key af9005_rc_keys[] = {
+struct dvb_usb_rc_key ir_codes_af9005_table[] = {
 
 	{0x01b7, KEY_POWER},
 	{0x01a7, KEY_VOLUMEUP},
@@ -74,7 +74,7 @@
 	{0x00d5, KEY_GOTO},	/* marked jump on the remote */
 };
 
-int af9005_rc_keys_size = ARRAY_SIZE(af9005_rc_keys);
+int ir_codes_af9005_table_size = ARRAY_SIZE(ir_codes_af9005_table);
 
 static int repeatable_keys[] = {
 	KEY_VOLUMEUP,
@@ -130,10 +130,10 @@
 				deb_decode("code != inverted code\n");
 				return 0;
 			}
-			for (i = 0; i < af9005_rc_keys_size; i++) {
-				if (rc5_custom(&af9005_rc_keys[i]) == cust
-				    && rc5_data(&af9005_rc_keys[i]) == dat) {
-					*event = af9005_rc_keys[i].event;
+			for (i = 0; i < ir_codes_af9005_table_size; i++) {
+				if (rc5_custom(&ir_codes_af9005_table[i]) == cust
+				    && rc5_data(&ir_codes_af9005_table[i]) == dat) {
+					*event = ir_codes_af9005_table[i].event;
 					*state = REMOTE_KEY_PRESSED;
 					deb_decode
 					    ("key pressed, event %x\n", *event);
@@ -146,8 +146,8 @@
 	return 0;
 }
 
-EXPORT_SYMBOL(af9005_rc_keys);
-EXPORT_SYMBOL(af9005_rc_keys_size);
+EXPORT_SYMBOL(ir_codes_af9005_table);
+EXPORT_SYMBOL(ir_codes_af9005_table_size);
 EXPORT_SYMBOL(af9005_rc_decode);
 
 MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c
index ca5a0a4..cfd6107 100644
--- a/drivers/media/dvb/dvb-usb/af9005.c
+++ b/drivers/media/dvb/dvb-usb/af9005.c
@@ -1109,8 +1109,8 @@
 		return result;
 	}
 	rc_decode = symbol_request(af9005_rc_decode);
-	rc_keys = symbol_request(af9005_rc_keys);
-	rc_keys_size = symbol_request(af9005_rc_keys_size);
+	rc_keys = symbol_request(ir_codes_af9005_table);
+	rc_keys_size = symbol_request(ir_codes_af9005_table_size);
 	if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) {
 		err("af9005_rc_decode function not found, disabling remote");
 		af9005_properties.rc_query = NULL;
@@ -1128,9 +1128,9 @@
 	if (rc_decode != NULL)
 		symbol_put(af9005_rc_decode);
 	if (rc_keys != NULL)
-		symbol_put(af9005_rc_keys);
+		symbol_put(ir_codes_af9005_table);
 	if (rc_keys_size != NULL)
-		symbol_put(af9005_rc_keys_size);
+		symbol_put(ir_codes_af9005_table_size);
 	/* deregister this driver from the USB subsystem */
 	usb_deregister(&af9005_usb_driver);
 }
diff --git a/drivers/media/dvb/dvb-usb/af9005.h b/drivers/media/dvb/dvb-usb/af9005.h
index 0bc48a0..088e708 100644
--- a/drivers/media/dvb/dvb-usb/af9005.h
+++ b/drivers/media/dvb/dvb-usb/af9005.h
@@ -3490,7 +3490,7 @@
 /* remote control decoder */
 extern int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len,
 			    u32 * event, int *state);
-extern struct dvb_usb_rc_key af9005_rc_keys[];
-extern int af9005_rc_keys_size;
+extern struct dvb_usb_rc_key ir_codes_af9005_table[];
+extern int ir_codes_af9005_table_size;
 
 #endif
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
index 74d94e4..66c7c3e 100644
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -752,19 +752,19 @@
 
 static const struct af9015_setup af9015_setup_modparam[] = {
 	{ AF9015_REMOTE_A_LINK_DTU_M,
-		af9015_rc_keys_a_link, ARRAY_SIZE(af9015_rc_keys_a_link),
+		ir_codes_af9015_table_a_link, ARRAY_SIZE(ir_codes_af9015_table_a_link),
 		af9015_ir_table_a_link, ARRAY_SIZE(af9015_ir_table_a_link) },
 	{ AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
-		af9015_rc_keys_msi, ARRAY_SIZE(af9015_rc_keys_msi),
+		ir_codes_af9015_table_msi, ARRAY_SIZE(ir_codes_af9015_table_msi),
 		af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) },
 	{ AF9015_REMOTE_MYGICTV_U718,
-		af9015_rc_keys_mygictv, ARRAY_SIZE(af9015_rc_keys_mygictv),
+		ir_codes_af9015_table_mygictv, ARRAY_SIZE(ir_codes_af9015_table_mygictv),
 		af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) },
 	{ AF9015_REMOTE_DIGITTRADE_DVB_T,
-		af9015_rc_keys_digittrade, ARRAY_SIZE(af9015_rc_keys_digittrade),
+		ir_codes_af9015_table_digittrade, ARRAY_SIZE(ir_codes_af9015_table_digittrade),
 		af9015_ir_table_digittrade, ARRAY_SIZE(af9015_ir_table_digittrade) },
 	{ AF9015_REMOTE_AVERMEDIA_KS,
-		af9015_rc_keys_avermedia, ARRAY_SIZE(af9015_rc_keys_avermedia),
+		ir_codes_af9015_table_avermedia, ARRAY_SIZE(ir_codes_af9015_table_avermedia),
 		af9015_ir_table_avermedia_ks, ARRAY_SIZE(af9015_ir_table_avermedia_ks) },
 	{ }
 };
@@ -772,32 +772,32 @@
 /* don't add new entries here anymore, use hashes instead */
 static const struct af9015_setup af9015_setup_usbids[] = {
 	{ USB_VID_LEADTEK,
-		af9015_rc_keys_leadtek, ARRAY_SIZE(af9015_rc_keys_leadtek),
+		ir_codes_af9015_table_leadtek, ARRAY_SIZE(ir_codes_af9015_table_leadtek),
 		af9015_ir_table_leadtek, ARRAY_SIZE(af9015_ir_table_leadtek) },
 	{ USB_VID_VISIONPLUS,
-		af9015_rc_keys_twinhan, ARRAY_SIZE(af9015_rc_keys_twinhan),
+		ir_codes_af9015_table_twinhan, ARRAY_SIZE(ir_codes_af9015_table_twinhan),
 		af9015_ir_table_twinhan, ARRAY_SIZE(af9015_ir_table_twinhan) },
 	{ USB_VID_KWORLD_2, /* TODO: use correct rc keys */
-		af9015_rc_keys_twinhan, ARRAY_SIZE(af9015_rc_keys_twinhan),
+		ir_codes_af9015_table_twinhan, ARRAY_SIZE(ir_codes_af9015_table_twinhan),
 		af9015_ir_table_kworld, ARRAY_SIZE(af9015_ir_table_kworld) },
 	{ USB_VID_AVERMEDIA,
-		af9015_rc_keys_avermedia, ARRAY_SIZE(af9015_rc_keys_avermedia),
+		ir_codes_af9015_table_avermedia, ARRAY_SIZE(ir_codes_af9015_table_avermedia),
 		af9015_ir_table_avermedia, ARRAY_SIZE(af9015_ir_table_avermedia) },
 	{ USB_VID_MSI_2,
-		af9015_rc_keys_msi_digivox_iii, ARRAY_SIZE(af9015_rc_keys_msi_digivox_iii),
+		ir_codes_af9015_table_msi_digivox_iii, ARRAY_SIZE(ir_codes_af9015_table_msi_digivox_iii),
 		af9015_ir_table_msi_digivox_iii, ARRAY_SIZE(af9015_ir_table_msi_digivox_iii) },
 	{ }
 };
 
 static const struct af9015_setup af9015_setup_hashes[] = {
 	{ 0xb8feb708,
-		af9015_rc_keys_msi, ARRAY_SIZE(af9015_rc_keys_msi),
+		ir_codes_af9015_table_msi, ARRAY_SIZE(ir_codes_af9015_table_msi),
 		af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) },
 	{ 0xa3703d00,
-		af9015_rc_keys_a_link, ARRAY_SIZE(af9015_rc_keys_a_link),
+		ir_codes_af9015_table_a_link, ARRAY_SIZE(ir_codes_af9015_table_a_link),
 		af9015_ir_table_a_link, ARRAY_SIZE(af9015_ir_table_a_link) },
 	{ 0x9b7dc64e,
-		af9015_rc_keys_mygictv, ARRAY_SIZE(af9015_rc_keys_mygictv),
+		ir_codes_af9015_table_mygictv, ARRAY_SIZE(ir_codes_af9015_table_mygictv),
 		af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) },
 	{ }
 };
@@ -836,8 +836,8 @@
 			} else if (udev->descriptor.idProduct ==
 				cpu_to_le16(USB_PID_TREKSTOR_DVBT)) {
 				table = &(const struct af9015_setup){ 0,
-					af9015_rc_keys_trekstor,
-					ARRAY_SIZE(af9015_rc_keys_trekstor),
+					ir_codes_af9015_table_trekstor,
+					ARRAY_SIZE(ir_codes_af9015_table_trekstor),
 					af9015_ir_table_trekstor,
 					ARRAY_SIZE(af9015_ir_table_trekstor)
 				};
@@ -1297,6 +1297,8 @@
 	{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_SVEON_STV20)},
 	{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_TINYTWIN_2)},
 	{USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV2000DS)},
+/* 30 */{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_UB383_T)},
+	{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_395U_4)},
 	{0},
 };
 MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@@ -1500,7 +1502,8 @@
 					"(VS-DVB-T 395U)",
 				.cold_ids = {&af9015_usb_table[16],
 					     &af9015_usb_table[17],
-					     &af9015_usb_table[18], NULL},
+					     &af9015_usb_table[18],
+					     &af9015_usb_table[31], NULL},
 				.warm_ids = {NULL},
 			},
 			{
@@ -1569,7 +1572,7 @@
 
 		.i2c_algo = &af9015_i2c_algo,
 
-		.num_device_descs = 7, /* max 9 */
+		.num_device_descs = 8, /* max 9 */
 		.devices = {
 			{
 				.name = "AverMedia AVerTV Volar GPS 805 (A805)",
@@ -1608,6 +1611,12 @@
 				.cold_ids = {&af9015_usb_table[29], NULL},
 				.warm_ids = {NULL},
 			},
+			{
+				.name = "KWorld USB DVB-T Stick Mobile " \
+					"(UB383-T)",
+				.cold_ids = {&af9015_usb_table[30], NULL},
+				.warm_ids = {NULL},
+			},
 		}
 	},
 };
diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h
index ef36b18..63b2a49 100644
--- a/drivers/media/dvb/dvb-usb/af9015.h
+++ b/drivers/media/dvb/dvb-usb/af9015.h
@@ -123,7 +123,7 @@
 
 /* LeadTek - Y04G0051 */
 /* Leadtek WinFast DTV Dongle Gold */
-static struct dvb_usb_rc_key af9015_rc_keys_leadtek[] = {
+static struct dvb_usb_rc_key ir_codes_af9015_table_leadtek[] = {
 	{ 0x001e, KEY_1 },
 	{ 0x001f, KEY_2 },
 	{ 0x0020, KEY_3 },
@@ -227,7 +227,7 @@
 };
 
 /* TwinHan AzureWave AD-TU700(704J) */
-static struct dvb_usb_rc_key af9015_rc_keys_twinhan[] = {
+static struct dvb_usb_rc_key ir_codes_af9015_table_twinhan[] = {
 	{ 0x053f, KEY_POWER },
 	{ 0x0019, KEY_FAVORITES },    /* Favorite List */
 	{ 0x0004, KEY_TEXT },         /* Teletext */
@@ -338,7 +338,7 @@
 };
 
 /* A-Link DTU(m) */
-static struct dvb_usb_rc_key af9015_rc_keys_a_link[] = {
+static struct dvb_usb_rc_key ir_codes_af9015_table_a_link[] = {
 	{ 0x001e, KEY_1 },
 	{ 0x001f, KEY_2 },
 	{ 0x0020, KEY_3 },
@@ -381,7 +381,7 @@
 };
 
 /* MSI DIGIVOX mini II V3.0 */
-static struct dvb_usb_rc_key af9015_rc_keys_msi[] = {
+static struct dvb_usb_rc_key ir_codes_af9015_table_msi[] = {
 	{ 0x001e, KEY_1 },
 	{ 0x001f, KEY_2 },
 	{ 0x0020, KEY_3 },
@@ -424,7 +424,7 @@
 };
 
 /* MYGICTV U718 */
-static struct dvb_usb_rc_key af9015_rc_keys_mygictv[] = {
+static struct dvb_usb_rc_key ir_codes_af9015_table_mygictv[] = {
 	{ 0x003d, KEY_SWITCHVIDEOMODE },
 					  /* TV / AV */
 	{ 0x0545, KEY_POWER },
@@ -550,7 +550,7 @@
 };
 
 /* AverMedia Volar X */
-static struct dvb_usb_rc_key af9015_rc_keys_avermedia[] = {
+static struct dvb_usb_rc_key ir_codes_af9015_table_avermedia[] = {
 	{ 0x053d, KEY_PROG1 },       /* SOURCE */
 	{ 0x0512, KEY_POWER },       /* POWER */
 	{ 0x051e, KEY_1 },           /* 1 */
@@ -656,7 +656,7 @@
 };
 
 /* Digittrade DVB-T USB Stick */
-static struct dvb_usb_rc_key af9015_rc_keys_digittrade[] = {
+static struct dvb_usb_rc_key ir_codes_af9015_table_digittrade[] = {
 	{ 0x010f, KEY_LAST },	/* RETURN */
 	{ 0x0517, KEY_TEXT },	/* TELETEXT */
 	{ 0x0108, KEY_EPG },	/* EPG */
@@ -719,7 +719,7 @@
 };
 
 /* TREKSTOR DVB-T USB Stick */
-static struct dvb_usb_rc_key af9015_rc_keys_trekstor[] = {
+static struct dvb_usb_rc_key ir_codes_af9015_table_trekstor[] = {
 	{ 0x0704, KEY_AGAIN },		/* Home */
 	{ 0x0705, KEY_MUTE },		/* Mute */
 	{ 0x0706, KEY_UP },			/* Up */
@@ -782,7 +782,7 @@
 };
 
 /* MSI DIGIVOX mini III */
-static struct dvb_usb_rc_key af9015_rc_keys_msi_digivox_iii[] = {
+static struct dvb_usb_rc_key ir_codes_af9015_table_msi_digivox_iii[] = {
 	{ 0x0713, KEY_POWER },       /* [red power button] */
 	{ 0x073b, KEY_VIDEO },       /* Source */
 	{ 0x073e, KEY_ZOOM },        /* Zoom */
diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c
index bb69f37..faca1ad 100644
--- a/drivers/media/dvb/dvb-usb/anysee.c
+++ b/drivers/media/dvb/dvb-usb/anysee.c
@@ -399,7 +399,7 @@
 	return 0;
 }
 
-static struct dvb_usb_rc_key anysee_rc_keys[] = {
+static struct dvb_usb_rc_key ir_codes_anysee_table[] = {
 	{ 0x0100, KEY_0 },
 	{ 0x0101, KEY_1 },
 	{ 0x0102, KEY_2 },
@@ -518,8 +518,8 @@
 		}
 	},
 
-	.rc_key_map       = anysee_rc_keys,
-	.rc_key_map_size  = ARRAY_SIZE(anysee_rc_keys),
+	.rc_key_map       = ir_codes_anysee_table,
+	.rc_key_map_size  = ARRAY_SIZE(ir_codes_anysee_table),
 	.rc_query         = anysee_rc_query,
 	.rc_interval      = 200,  /* windows driver uses 500ms */
 
diff --git a/drivers/media/dvb/dvb-usb/az6027.c b/drivers/media/dvb/dvb-usb/az6027.c
index d7290b2..6681ac1 100644
--- a/drivers/media/dvb/dvb-usb/az6027.c
+++ b/drivers/media/dvb/dvb-usb/az6027.c
@@ -125,12 +125,12 @@
 	{ STB0899_RCOMPC        	, 0xc9 },
 	{ STB0899_AGC1CN        	, 0x01 },
 	{ STB0899_AGC1REF       	, 0x10 },
-	{ STB0899_RTC	        	, 0x23 },
+	{ STB0899_RTC			, 0x23 },
 	{ STB0899_TMGCFG        	, 0x4e },
 	{ STB0899_AGC2REF       	, 0x34 },
 	{ STB0899_TLSR          	, 0x84 },
 	{ STB0899_CFD           	, 0xf7 },
-	{ STB0899_ACLC	        	, 0x87 },
+	{ STB0899_ACLC			, 0x87 },
 	{ STB0899_BCLC          	, 0x94 },
 	{ STB0899_EQON          	, 0x41 },
 	{ STB0899_LDT           	, 0xf1 },
@@ -183,10 +183,10 @@
 	{ STB0899_ECNT3M		, 0x0a },
 	{ STB0899_ECNT3L		, 0xad },
 	{ STB0899_FECAUTO1      	, 0x06 },
-	{ STB0899_FECM	        	, 0x01 },
+	{ STB0899_FECM			, 0x01 },
 	{ STB0899_VTH12         	, 0xb0 },
 	{ STB0899_VTH23         	, 0x7a },
-	{ STB0899_VTH34	        	, 0x58 },
+	{ STB0899_VTH34			, 0x58 },
 	{ STB0899_VTH56         	, 0x38 },
 	{ STB0899_VTH67         	, 0x34 },
 	{ STB0899_VTH78         	, 0x24 },
@@ -195,7 +195,7 @@
 	{ STB0899_RSULC         	, 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
 	{ STB0899_TSULC         	, 0x42 },
 	{ STB0899_RSLLC         	, 0x41 },
-	{ STB0899_TSLPL	        	, 0x12 },
+	{ STB0899_TSLPL			, 0x12 },
 	{ STB0899_TSCFGH        	, 0x0c },
 	{ STB0899_TSCFGM        	, 0x00 },
 	{ STB0899_TSCFGL        	, 0x00 },
@@ -386,7 +386,7 @@
 }
 
 /* keys for the enclosed remote control */
-static struct dvb_usb_rc_key az6027_rc_keys[] = {
+static struct dvb_usb_rc_key ir_codes_az6027_table[] = {
 	{ 0x01, KEY_1 },
 	{ 0x02, KEY_2 },
 };
@@ -417,11 +417,15 @@
 	u16 value;
 	u16 index;
 	int blen;
-	u8 b[12];
+	u8 *b;
 
 	if (slot != 0)
 		return -EINVAL;
 
+	b = kmalloc(12, GFP_KERNEL);
+	if (!b)
+		return -ENOMEM;
+
 	mutex_lock(&state->ca_mutex);
 
 	req = 0xC1;
@@ -438,6 +442,7 @@
 	}
 
 	mutex_unlock(&state->ca_mutex);
+	kfree(b);
 	return ret;
 }
 
@@ -485,11 +490,15 @@
 	u16 value;
 	u16 index;
 	int blen;
-	u8 b[12];
+	u8 *b;
 
 	if (slot != 0)
 		return -EINVAL;
 
+	b = kmalloc(12, GFP_KERNEL);
+	if (!b)
+		return -ENOMEM;
+
 	mutex_lock(&state->ca_mutex);
 
 	req = 0xC3;
@@ -510,6 +519,7 @@
 	}
 
 	mutex_unlock(&state->ca_mutex);
+	kfree(b);
 	return ret;
 }
 
@@ -556,7 +566,11 @@
 	u16 value;
 	u16 index;
 	int blen;
-	u8 b[12];
+	u8 *b;
+
+	b = kmalloc(12, GFP_KERNEL);
+	if (!b)
+		return -ENOMEM;
 
 	req = 0xC8;
 	value = 0;
@@ -570,6 +584,7 @@
 	} else{
 		ret = b[0];
 	}
+	kfree(b);
 	return ret;
 }
 
@@ -667,8 +682,11 @@
 	u16 value;
 	u16 index;
 	int blen;
-	u8 b[12];
+	u8 *b;
 
+	b = kmalloc(12, GFP_KERNEL);
+	if (!b)
+		return -ENOMEM;
 	mutex_lock(&state->ca_mutex);
 
 	req = 0xC5;
@@ -683,15 +701,13 @@
 	} else
 		ret = 0;
 
-	if (b[0] == 0) {
-		ret = 0;
-
-	} else if (b[0] == 1) {
+	if (!ret && b[0] == 1) {
 		ret = DVB_CA_EN50221_POLL_CAM_PRESENT |
 		      DVB_CA_EN50221_POLL_CAM_READY;
 	}
 
 	mutex_unlock(&state->ca_mutex);
+	kfree(b);
 	return ret;
 }
 
@@ -943,10 +959,16 @@
 	u16 value;
 	int length;
 	u8 req;
-	u8 data[256];
+	u8 *data;
 
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+	data = kmalloc(256, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0) {
+		kfree(data);
 		return -EAGAIN;
+	}
 
 	if (num > 2)
 		warn("more than 2 i2c messages at a time is not handled yet. TODO.");
@@ -976,17 +998,14 @@
 				i++;
 			} else {
 
-				if (msg[i].addr == 0xd0) {
-					/* demod 16bit addr */
-					req = 0xBD;
-					index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff));
-					value = msg[i].addr + (2 << 8);
-					length = msg[i].len - 2;
-					len = msg[i].len - 2;
-					for (j = 0; j < len; j++)
-						data[j] = msg[i].buf[j + 2];
-
-				}
+				/* demod 16bit addr */
+				req = 0xBD;
+				index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff));
+				value = msg[i].addr + (2 << 8);
+				length = msg[i].len - 2;
+				len = msg[i].len - 2;
+				for (j = 0; j < len; j++)
+					data[j] = msg[i].buf[j + 2];
 				az6027_usb_out_op(d, req, value, index, data, length);
 			}
 		}
@@ -1019,6 +1038,7 @@
 		}
 	}
 	mutex_unlock(&d->i2c_mutex);
+	kfree(data);
 
 	return i;
 }
@@ -1039,8 +1059,14 @@
 			  struct dvb_usb_device_description **desc,
 			  int *cold)
 {
-	u8 b[16];
-	s16 ret = usb_control_msg(udev,
+	u8 *b;
+	s16 ret;
+
+	b = kmalloc(16, GFP_KERNEL);
+	if (!b)
+		return -ENOMEM;
+
+	ret = usb_control_msg(udev,
 				  usb_rcvctrlpipe(udev, 0),
 				  0xb7,
 				  USB_TYPE_VENDOR | USB_DIR_IN,
@@ -1051,7 +1077,7 @@
 				  USB_CTRL_GET_TIMEOUT);
 
 	*cold = ret <= 0;
-
+	kfree(b);
 	deb_info("cold: %d\n", *cold);
 	return 0;
 }
@@ -1059,8 +1085,10 @@
 
 static struct usb_device_id az6027_usb_table[] = {
 	{ USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_AZ6027) },
-	{ USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_DVBS2CI) },
-	{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI) },
+	{ USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_DVBS2CI_V1) },
+	{ USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_DVBS2CI_V2) },
+	{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V1) },
+	{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V2) },
 	{ },
 };
 
@@ -1097,18 +1125,34 @@
 	.power_ctrl       = az6027_power_ctrl,
 	.read_mac_address = az6027_read_mac_addr,
  */
-	.rc_key_map       = az6027_rc_keys,
-	.rc_key_map_size  = ARRAY_SIZE(az6027_rc_keys),
+	.rc_key_map       = ir_codes_az6027_table,
+	.rc_key_map_size  = ARRAY_SIZE(ir_codes_az6027_table),
 	.rc_interval      = 400,
 	.rc_query         = az6027_rc_query,
 	.i2c_algo         = &az6027_i2c_algo,
 
-	.num_device_descs = 1,
+	.num_device_descs = 5,
 	.devices = {
 		{
 			.name = "AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)",
 			.cold_ids = { &az6027_usb_table[0], NULL },
 			.warm_ids = { NULL },
+		}, {
+			.name = "TERRATEC S7",
+			.cold_ids = { &az6027_usb_table[1], NULL },
+			.warm_ids = { NULL },
+		}, {
+			.name = "TERRATEC S7 MKII",
+			.cold_ids = { &az6027_usb_table[2], NULL },
+			.warm_ids = { NULL },
+		}, {
+			.name = "Technisat SkyStar USB 2 HD CI",
+			.cold_ids = { &az6027_usb_table[3], NULL },
+			.warm_ids = { NULL },
+		}, {
+			.name = "Technisat SkyStar USB 2 HD CI",
+			.cold_ids = { &az6027_usb_table[4], NULL },
+			.warm_ids = { NULL },
 		},
 		{ NULL },
 	}
diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-core.c b/drivers/media/dvb/dvb-usb/cinergyT2-core.c
index e37ac4d..5a9c14b 100644
--- a/drivers/media/dvb/dvb-usb/cinergyT2-core.c
+++ b/drivers/media/dvb/dvb-usb/cinergyT2-core.c
@@ -84,7 +84,7 @@
 	return 0;
 }
 
-static struct dvb_usb_rc_key cinergyt2_rc_keys[] = {
+static struct dvb_usb_rc_key ir_codes_cinergyt2_table[] = {
 	{ 0x0401, KEY_POWER },
 	{ 0x0402, KEY_1 },
 	{ 0x0403, KEY_2 },
@@ -218,8 +218,8 @@
 	.power_ctrl       = cinergyt2_power_ctrl,
 
 	.rc_interval      = 50,
-	.rc_key_map       = cinergyt2_rc_keys,
-	.rc_key_map_size  = ARRAY_SIZE(cinergyt2_rc_keys),
+	.rc_key_map       = ir_codes_cinergyt2_table,
+	.rc_key_map_size  = ARRAY_SIZE(ir_codes_cinergyt2_table),
 	.rc_query         = cinergyt2_rc_query,
 
 	.generic_bulk_ctrl_endpoint = 1,
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 960376d..0eb4908 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -461,7 +461,7 @@
 	return 0;
 }
 
-static struct dvb_usb_rc_key dvico_mce_rc_keys[] = {
+static struct dvb_usb_rc_key ir_codes_dvico_mce_table[] = {
 	{ 0xfe02, KEY_TV },
 	{ 0xfe0e, KEY_MP3 },
 	{ 0xfe1a, KEY_DVD },
@@ -509,7 +509,7 @@
 	{ 0xfe4e, KEY_POWER },
 };
 
-static struct dvb_usb_rc_key dvico_portable_rc_keys[] = {
+static struct dvb_usb_rc_key ir_codes_dvico_portable_table[] = {
 	{ 0xfc02, KEY_SETUP },       /* Profile */
 	{ 0xfc43, KEY_POWER2 },
 	{ 0xfc06, KEY_EPG },
@@ -548,7 +548,7 @@
 	{ 0xfc00, KEY_UNKNOWN },    /* HD */
 };
 
-static struct dvb_usb_rc_key d680_dmb_rc_keys[] = {
+static struct dvb_usb_rc_key ir_codes_d680_dmb_table[] = {
 	{ 0x0038, KEY_UNKNOWN },	/* TV/AV */
 	{ 0x080c, KEY_ZOOM },
 	{ 0x0800, KEY_0 },
@@ -1025,8 +1025,9 @@
 
 	cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
 
-	dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
-				 &cxusb_dualdig4_rev2_config);
+	if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+				 &cxusb_dualdig4_rev2_config) < 0)
+		return -ENODEV;
 
 	adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
 			      &cxusb_dualdig4_rev2_config);
@@ -1449,8 +1450,8 @@
 	.i2c_algo         = &cxusb_i2c_algo,
 
 	.rc_interval      = 100,
-	.rc_key_map       = dvico_portable_rc_keys,
-	.rc_key_map_size  = ARRAY_SIZE(dvico_portable_rc_keys),
+	.rc_key_map       = ir_codes_dvico_portable_table,
+	.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
 	.rc_query         = cxusb_rc_query,
 
 	.generic_bulk_ctrl_endpoint = 0x01,
@@ -1500,8 +1501,8 @@
 	.i2c_algo         = &cxusb_i2c_algo,
 
 	.rc_interval      = 150,
-	.rc_key_map       = dvico_mce_rc_keys,
-	.rc_key_map_size  = ARRAY_SIZE(dvico_mce_rc_keys),
+	.rc_key_map       = ir_codes_dvico_mce_table,
+	.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_mce_table),
 	.rc_query         = cxusb_rc_query,
 
 	.generic_bulk_ctrl_endpoint = 0x01,
@@ -1559,8 +1560,8 @@
 	.i2c_algo         = &cxusb_i2c_algo,
 
 	.rc_interval      = 100,
-	.rc_key_map       = dvico_portable_rc_keys,
-	.rc_key_map_size  = ARRAY_SIZE(dvico_portable_rc_keys),
+	.rc_key_map       = ir_codes_dvico_portable_table,
+	.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
 	.rc_query         = cxusb_rc_query,
 
 	.generic_bulk_ctrl_endpoint = 0x01,
@@ -1609,8 +1610,8 @@
 	.i2c_algo         = &cxusb_i2c_algo,
 
 	.rc_interval      = 100,
-	.rc_key_map       = dvico_portable_rc_keys,
-	.rc_key_map_size  = ARRAY_SIZE(dvico_portable_rc_keys),
+	.rc_key_map       = ir_codes_dvico_portable_table,
+	.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
 	.rc_query         = cxusb_rc_query,
 
 	.generic_bulk_ctrl_endpoint = 0x01,
@@ -1658,8 +1659,8 @@
 	.generic_bulk_ctrl_endpoint = 0x01,
 
 	.rc_interval      = 100,
-	.rc_key_map       = dvico_mce_rc_keys,
-	.rc_key_map_size  = ARRAY_SIZE(dvico_mce_rc_keys),
+	.rc_key_map       = ir_codes_dvico_mce_table,
+	.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_mce_table),
 	.rc_query         = cxusb_bluebird2_rc_query,
 
 	.num_device_descs = 1,
@@ -1706,8 +1707,8 @@
 	.generic_bulk_ctrl_endpoint = 0x01,
 
 	.rc_interval      = 100,
-	.rc_key_map       = dvico_portable_rc_keys,
-	.rc_key_map_size  = ARRAY_SIZE(dvico_portable_rc_keys),
+	.rc_key_map       = ir_codes_dvico_portable_table,
+	.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
 	.rc_query         = cxusb_bluebird2_rc_query,
 
 	.num_device_descs = 1,
@@ -1756,8 +1757,8 @@
 	.generic_bulk_ctrl_endpoint = 0x01,
 
 	.rc_interval      = 100,
-	.rc_key_map       = dvico_portable_rc_keys,
-	.rc_key_map_size  = ARRAY_SIZE(dvico_portable_rc_keys),
+	.rc_key_map       = ir_codes_dvico_portable_table,
+	.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
 	.rc_query         = cxusb_rc_query,
 
 	.num_device_descs = 1,
@@ -1847,8 +1848,8 @@
 	.generic_bulk_ctrl_endpoint = 0x01,
 
 	.rc_interval      = 100,
-	.rc_key_map       = dvico_mce_rc_keys,
-	.rc_key_map_size  = ARRAY_SIZE(dvico_mce_rc_keys),
+	.rc_key_map       = ir_codes_dvico_mce_table,
+	.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_mce_table),
 	.rc_query         = cxusb_rc_query,
 
 	.num_device_descs = 1,
@@ -1895,8 +1896,8 @@
 	.generic_bulk_ctrl_endpoint = 0x01,
 
 	.rc_interval      = 100,
-	.rc_key_map       = d680_dmb_rc_keys,
-	.rc_key_map_size  = ARRAY_SIZE(d680_dmb_rc_keys),
+	.rc_key_map       = ir_codes_d680_dmb_table,
+	.rc_key_map_size  = ARRAY_SIZE(ir_codes_d680_dmb_table),
 	.rc_query         = cxusb_d680_dmb_rc_query,
 
 	.num_device_descs = 1,
@@ -1944,8 +1945,8 @@
 	.generic_bulk_ctrl_endpoint = 0x01,
 
 	.rc_interval      = 100,
-	.rc_key_map       = d680_dmb_rc_keys,
-	.rc_key_map_size  = ARRAY_SIZE(d680_dmb_rc_keys),
+	.rc_key_map       = ir_codes_d680_dmb_table,
+	.rc_key_map_size  = ARRAY_SIZE(ir_codes_d680_dmb_table),
 	.rc_query         = cxusb_d680_dmb_rc_query,
 
 	.num_device_descs = 1,
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 34eab05..800800a 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -562,7 +562,7 @@
 	return 0;
 }
 
-static struct dvb_usb_rc_key dib0700_rc_keys[] = {
+static struct dvb_usb_rc_key ir_codes_dib0700_table[] = {
 	/* Key codes for the tiny Pinnacle remote*/
 	{ 0x0700, KEY_MUTE },
 	{ 0x0701, KEY_MENU }, /* Pinnacle logo */
@@ -794,6 +794,43 @@
 	{ 0x7a13, KEY_VOLUMEDOWN },
 	{ 0x7a40, KEY_POWER },
 	{ 0x7a41, KEY_MUTE },
+
+	/* Key codes for the Elgato EyeTV Diversity silver remote,
+	   set dvb_usb_dib0700_ir_proto=0 */
+	{ 0x4501, KEY_POWER },
+	{ 0x4502, KEY_MUTE },
+	{ 0x4503, KEY_1 },
+	{ 0x4504, KEY_2 },
+	{ 0x4505, KEY_3 },
+	{ 0x4506, KEY_4 },
+	{ 0x4507, KEY_5 },
+	{ 0x4508, KEY_6 },
+	{ 0x4509, KEY_7 },
+	{ 0x450a, KEY_8 },
+	{ 0x450b, KEY_9 },
+	{ 0x450c, KEY_LAST },
+	{ 0x450d, KEY_0 },
+	{ 0x450e, KEY_ENTER },
+	{ 0x450f, KEY_RED },
+	{ 0x4510, KEY_CHANNELUP },
+	{ 0x4511, KEY_GREEN },
+	{ 0x4512, KEY_VOLUMEDOWN },
+	{ 0x4513, KEY_OK },
+	{ 0x4514, KEY_VOLUMEUP },
+	{ 0x4515, KEY_YELLOW },
+	{ 0x4516, KEY_CHANNELDOWN },
+	{ 0x4517, KEY_BLUE },
+	{ 0x4518, KEY_LEFT }, /* Skip backwards */
+	{ 0x4519, KEY_PLAYPAUSE },
+	{ 0x451a, KEY_RIGHT }, /* Skip forward */
+	{ 0x451b, KEY_REWIND },
+	{ 0x451c, KEY_L }, /* Live */
+	{ 0x451d, KEY_FASTFORWARD },
+	{ 0x451e, KEY_STOP }, /* 'Reveal' for Teletext */
+	{ 0x451f, KEY_MENU }, /* KEY_TEXT for Teletext */
+	{ 0x4540, KEY_RECORD }, /* Font 'Size' for Teletext */
+	{ 0x4541, KEY_SCREEN }, /*  Full screen toggle, 'Hold' for Teletext */
+	{ 0x4542, KEY_SELECT }, /* Select video input, 'Select' for Teletext */
 };
 
 /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
@@ -2049,6 +2086,7 @@
 /* 65 */{ USB_DEVICE(USB_VID_PINNACLE,	USB_PID_PINNACLE_PCTV73ESE) },
 	{ USB_DEVICE(USB_VID_PINNACLE,	USB_PID_PINNACLE_PCTV282E) },
 	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK8096GP) },
+	{ USB_DEVICE(USB_VID_ELGATO,    USB_PID_ELGATO_EYETV_DIVERSITY) },
 	{ 0 }		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -2131,8 +2169,8 @@
 		},
 
 		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = dib0700_rc_keys,
-		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+		.rc_key_map       = ir_codes_dib0700_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
 		.rc_query         = dib0700_rc_query
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
@@ -2160,8 +2198,8 @@
 		},
 
 		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = dib0700_rc_keys,
-		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+		.rc_key_map       = ir_codes_dib0700_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
 		.rc_query         = dib0700_rc_query
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
@@ -2214,8 +2252,8 @@
 		},
 
 		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = dib0700_rc_keys,
-		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+		.rc_key_map       = ir_codes_dib0700_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
 		.rc_query         = dib0700_rc_query
 
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -2251,8 +2289,8 @@
 		},
 
 		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = dib0700_rc_keys,
-		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+		.rc_key_map       = ir_codes_dib0700_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
 		.rc_query         = dib0700_rc_query
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
@@ -2321,8 +2359,8 @@
 		},
 
 		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = dib0700_rc_keys,
-		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+		.rc_key_map       = ir_codes_dib0700_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
 		.rc_query         = dib0700_rc_query
 
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -2360,8 +2398,8 @@
 		},
 
 		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = dib0700_rc_keys,
-		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+		.rc_key_map       = ir_codes_dib0700_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
 		.rc_query         = dib0700_rc_query
 
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -2393,7 +2431,7 @@
 			}
 		},
 
-		.num_device_descs = 6,
+		.num_device_descs = 7,
 		.devices = {
 			{   "DiBcom STK7070PD reference design",
 				{ &dib0700_usb_id_table[17], NULL },
@@ -2419,11 +2457,15 @@
 			{  "Sony PlayTV",
 				{ &dib0700_usb_id_table[44], NULL },
 				{ NULL },
-			}
+			},
+			{   "Elgato EyeTV Diversity",
+				{ &dib0700_usb_id_table[68], NULL },
+				{ NULL },
+			},
 		},
 		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = dib0700_rc_keys,
-		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+		.rc_key_map       = ir_codes_dib0700_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
 		.rc_query         = dib0700_rc_query
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
@@ -2484,8 +2526,8 @@
 			},
 		},
 		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = dib0700_rc_keys,
-		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+		.rc_key_map       = ir_codes_dib0700_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
 		.rc_query         = dib0700_rc_query
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 		.num_adapters = 1,
@@ -2513,8 +2555,8 @@
 			},
 		},
 		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = dib0700_rc_keys,
-		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+		.rc_key_map       = ir_codes_dib0700_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
 		.rc_query         = dib0700_rc_query
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 		.num_adapters = 1,
@@ -2574,8 +2616,8 @@
 			},
 		},
 		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = dib0700_rc_keys,
-		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+		.rc_key_map       = ir_codes_dib0700_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
 		.rc_query         = dib0700_rc_query
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 		.num_adapters = 1,
@@ -2612,8 +2654,8 @@
 		},
 
 		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = dib0700_rc_keys,
-		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+		.rc_key_map       = ir_codes_dib0700_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
 		.rc_query         = dib0700_rc_query
 
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -2656,8 +2698,8 @@
 		},
 
 		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = dib0700_rc_keys,
-		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+		.rc_key_map       = ir_codes_dib0700_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
 		.rc_query         = dib0700_rc_query
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 		.num_adapters = 1,
@@ -2687,8 +2729,8 @@
 		},
 
 		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = dib0700_rc_keys,
-		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+		.rc_key_map       = ir_codes_dib0700_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
 		.rc_query         = dib0700_rc_query
 	},
 };
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c
index 9143b56..bc08bc0 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-common.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-common.c
@@ -327,7 +327,7 @@
 /*
  * common remote control stuff
  */
-struct dvb_usb_rc_key dibusb_rc_keys[] = {
+struct dvb_usb_rc_key ir_codes_dibusb_table[] = {
 	/* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
 	{ 0x0016, KEY_POWER },
 	{ 0x0010, KEY_MUTE },
@@ -456,7 +456,7 @@
 	{ 0x804e, KEY_ENTER },
 	{ 0x804f, KEY_VOLUMEDOWN },
 };
-EXPORT_SYMBOL(dibusb_rc_keys);
+EXPORT_SYMBOL(ir_codes_dibusb_table);
 
 int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index 5c0126d..eb2e6f0 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -212,7 +212,7 @@
 	.power_ctrl       = dibusb_power_ctrl,
 
 	.rc_interval      = DEFAULT_RC_INTERVAL,
-	.rc_key_map       = dibusb_rc_keys,
+	.rc_key_map       = ir_codes_dibusb_table,
 	.rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
 	.rc_query         = dibusb_rc_query,
 
@@ -296,7 +296,7 @@
 	.power_ctrl       = dibusb_power_ctrl,
 
 	.rc_interval      = DEFAULT_RC_INTERVAL,
-	.rc_key_map       = dibusb_rc_keys,
+	.rc_key_map       = ir_codes_dibusb_table,
 	.rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
 	.rc_query         = dibusb_rc_query,
 
@@ -360,7 +360,7 @@
 	.power_ctrl       = dibusb2_0_power_ctrl,
 
 	.rc_interval      = DEFAULT_RC_INTERVAL,
-	.rc_key_map       = dibusb_rc_keys,
+	.rc_key_map       = ir_codes_dibusb_table,
 	.rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
 	.rc_query         = dibusb_rc_query,
 
@@ -417,7 +417,7 @@
 	.power_ctrl       = dibusb2_0_power_ctrl,
 
 	.rc_interval      = DEFAULT_RC_INTERVAL,
-	.rc_key_map       = dibusb_rc_keys,
+	.rc_key_map       = ir_codes_dibusb_table,
 	.rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
 	.rc_query         = dibusb_rc_query,
 
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c
index a05b9f8..588308e 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mc.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mc.c
@@ -82,7 +82,7 @@
 	.power_ctrl       = dibusb2_0_power_ctrl,
 
 	.rc_interval      = DEFAULT_RC_INTERVAL,
-	.rc_key_map       = dibusb_rc_keys,
+	.rc_key_map       = ir_codes_dibusb_table,
 	.rc_key_map_size  = 111, /* FIXME */
 	.rc_query         = dibusb_rc_query,
 
diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h
index 8e847aa..3d50ac5 100644
--- a/drivers/media/dvb/dvb-usb/dibusb.h
+++ b/drivers/media/dvb/dvb-usb/dibusb.h
@@ -124,7 +124,7 @@
 #define DEFAULT_RC_INTERVAL 150
 //#define DEFAULT_RC_INTERVAL 100000
 
-extern struct dvb_usb_rc_key dibusb_rc_keys[];
+extern struct dvb_usb_rc_key ir_codes_dibusb_table[];
 extern int dibusb_rc_query(struct dvb_usb_device *, u32 *, int *);
 extern int dibusb_read_eeprom_byte(struct dvb_usb_device *, u8, u8 *);
 
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index 955147d..e826077 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -161,7 +161,7 @@
 	return 0;
 }
 
-static struct dvb_usb_rc_key digitv_rc_keys[] = {
+static struct dvb_usb_rc_key ir_codes_digitv_table[] = {
 	{ 0x5f55, KEY_0 },
 	{ 0x6f55, KEY_1 },
 	{ 0x9f55, KEY_2 },
@@ -311,8 +311,8 @@
 	.identify_state   = digitv_identify_state,
 
 	.rc_interval      = 1000,
-	.rc_key_map       = digitv_rc_keys,
-	.rc_key_map_size  = ARRAY_SIZE(digitv_rc_keys),
+	.rc_key_map       = ir_codes_digitv_table,
+	.rc_key_map_size  = ARRAY_SIZE(ir_codes_digitv_table),
 	.rc_query         = digitv_rc_query,
 
 	.i2c_algo         = &digitv_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c
index a1b12b0..f57e590 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u.c
@@ -57,7 +57,7 @@
 
 /* remote control */
 /* key list for the tiny remote control (Yakumo, don't know about the others) */
-static struct dvb_usb_rc_key dtt200u_rc_keys[] = {
+static struct dvb_usb_rc_key ir_codes_dtt200u_table[] = {
 	{ 0x8001, KEY_MUTE },
 	{ 0x8002, KEY_CHANNELDOWN },
 	{ 0x8003, KEY_VOLUMEDOWN },
@@ -162,8 +162,8 @@
 	.power_ctrl      = dtt200u_power_ctrl,
 
 	.rc_interval     = 300,
-	.rc_key_map      = dtt200u_rc_keys,
-	.rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys),
+	.rc_key_map      = ir_codes_dtt200u_table,
+	.rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
 	.rc_query        = dtt200u_rc_query,
 
 	.generic_bulk_ctrl_endpoint = 0x01,
@@ -207,8 +207,8 @@
 	.power_ctrl      = dtt200u_power_ctrl,
 
 	.rc_interval     = 300,
-	.rc_key_map      = dtt200u_rc_keys,
-	.rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys),
+	.rc_key_map      = ir_codes_dtt200u_table,
+	.rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
 	.rc_query        = dtt200u_rc_query,
 
 	.generic_bulk_ctrl_endpoint = 0x01,
@@ -252,8 +252,8 @@
 	.power_ctrl      = dtt200u_power_ctrl,
 
 	.rc_interval     = 300,
-	.rc_key_map      = dtt200u_rc_keys,
-	.rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys),
+	.rc_key_map      = ir_codes_dtt200u_table,
+	.rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
 	.rc_query        = dtt200u_rc_query,
 
 	.generic_bulk_ctrl_endpoint = 0x01,
@@ -297,8 +297,8 @@
 	.power_ctrl      = dtt200u_power_ctrl,
 
 	.rc_interval     = 300,
-	.rc_key_map      = dtt200u_rc_keys,
-	.rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys),
+	.rc_key_map      = ir_codes_dtt200u_table,
+	.rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
 	.rc_query        = dtt200u_rc_query,
 
 	.generic_bulk_ctrl_endpoint = 0x01,
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index ae8b57a..085c4e4 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -124,9 +124,11 @@
 #define USB_PID_KWORLD_395U				0xe396
 #define USB_PID_KWORLD_395U_2				0xe39b
 #define USB_PID_KWORLD_395U_3				0xe395
+#define USB_PID_KWORLD_395U_4				0xe39a
 #define USB_PID_KWORLD_MC810				0xc810
 #define USB_PID_KWORLD_PC160_2T				0xc160
 #define USB_PID_KWORLD_PC160_T				0xc161
+#define USB_PID_KWORLD_UB383_T				0xe383
 #define USB_PID_KWORLD_VSTREAM_COLD			0x17de
 #define USB_PID_KWORLD_VSTREAM_WARM			0x17df
 #define USB_PID_TERRATEC_CINERGY_T_USB_XE		0x0055
@@ -288,6 +290,7 @@
 #define USB_PID_MSI_DIGI_VOX_MINI_III                   0x8807
 #define USB_PID_SONY_PLAYTV				0x0003
 #define USB_PID_MYGICA_D689				0xd811
+#define USB_PID_ELGATO_EYETV_DIVERSITY			0x0011
 #define USB_PID_ELGATO_EYETV_DTT			0x0021
 #define USB_PID_ELGATO_EYETV_DTT_Dlx			0x0020
 #define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD		0x5000
@@ -296,6 +299,8 @@
 #define USB_PID_TVWAY_PLUS				0x0002
 #define USB_PID_SVEON_STV20				0xe39d
 #define USB_PID_AZUREWAVE_AZ6027			0x3275
-#define USB_PID_TERRATEC_DVBS2CI			0x3275
-#define USB_PID_TECHNISAT_USB2_HDCI			0x0002
+#define USB_PID_TERRATEC_DVBS2CI_V1			0x10a4
+#define USB_PID_TERRATEC_DVBS2CI_V2			0x10ac
+#define USB_PID_TECHNISAT_USB2_HDCI_V1			0x0001
+#define USB_PID_TECHNISAT_USB2_HDCI_V2			0x0002
 #endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
index 6fe71c6..bb46ba6 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
@@ -42,6 +42,8 @@
 			msleep(delay_ms);
 
 		ret = usb_bulk_msg(d->udev,usb_rcvbulkpipe(d->udev,
+				d->props.generic_bulk_ctrl_endpoint_response ?
+				d->props.generic_bulk_ctrl_endpoint_response :
 				d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen,
 				2000);
 
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index 0143aef..4a9f676 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -198,6 +198,12 @@
  *  is non-zero, one can use dvb_usb_generic_rw and dvb_usb_generic_write-
  *  helper functions.
  *
+ * @generic_bulk_ctrl_endpoint_response: some DVB USB devices use a separate
+ *  endpoint for responses to control messages sent with bulk transfers via
+ *  the generic_bulk_ctrl_endpoint. When this is non-zero, this will be used
+ *  instead of the generic_bulk_ctrl_endpoint when reading usb responses in
+ *  the dvb_usb_generic_rw helper function.
+ *
  * @num_device_descs: number of struct dvb_usb_device_description in @devices
  * @devices: array of struct dvb_usb_device_description compatibles with these
  *  properties.
@@ -239,6 +245,7 @@
 	struct i2c_algorithm *i2c_algo;
 
 	int generic_bulk_ctrl_endpoint;
+	int generic_bulk_ctrl_endpoint_response;
 
 	int num_device_descs;
 	struct dvb_usb_device_description devices[12];
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c
index accc655..e8fb853 100644
--- a/drivers/media/dvb/dvb-usb/dw2102.c
+++ b/drivers/media/dvb/dvb-usb/dw2102.c
@@ -73,7 +73,7 @@
 		"Please see linux/Documentation/dvb/ for more details " \
 		"on firmware-problems."
 
-struct dvb_usb_rc_keys_table {
+struct ir_codes_dvb_usb_table_table {
 	struct dvb_usb_rc_key *rc_keys;
 	int rc_keys_size;
 };
@@ -948,7 +948,7 @@
 	return 0;
 }
 
-static struct dvb_usb_rc_key dw210x_rc_keys[] = {
+static struct dvb_usb_rc_key ir_codes_dw210x_table[] = {
 	{ 0xf80a, KEY_Q },		/*power*/
 	{ 0xf80c, KEY_M },		/*mute*/
 	{ 0xf811, KEY_1 },
@@ -982,7 +982,7 @@
 	{ 0xf81b, KEY_B },		/*recall*/
 };
 
-static struct dvb_usb_rc_key tevii_rc_keys[] = {
+static struct dvb_usb_rc_key ir_codes_tevii_table[] = {
 	{ 0xf80a, KEY_POWER },
 	{ 0xf80c, KEY_MUTE },
 	{ 0xf811, KEY_1 },
@@ -1032,7 +1032,7 @@
 	{ 0xf858, KEY_SWITCHVIDEOMODE },
 };
 
-static struct dvb_usb_rc_key tbs_rc_keys[] = {
+static struct dvb_usb_rc_key ir_codes_tbs_table[] = {
 	{ 0xf884, KEY_POWER },
 	{ 0xf894, KEY_MUTE },
 	{ 0xf887, KEY_1 },
@@ -1067,10 +1067,10 @@
 	{ 0xf89b, KEY_MODE }
 };
 
-static struct dvb_usb_rc_keys_table keys_tables[] = {
-	{ dw210x_rc_keys, ARRAY_SIZE(dw210x_rc_keys) },
-	{ tevii_rc_keys, ARRAY_SIZE(tevii_rc_keys) },
-	{ tbs_rc_keys, ARRAY_SIZE(tbs_rc_keys) },
+static struct ir_codes_dvb_usb_table_table keys_tables[] = {
+	{ ir_codes_dw210x_table, ARRAY_SIZE(ir_codes_dw210x_table) },
+	{ ir_codes_tevii_table, ARRAY_SIZE(ir_codes_tevii_table) },
+	{ ir_codes_tbs_table, ARRAY_SIZE(ir_codes_tbs_table) },
 };
 
 static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
@@ -1185,14 +1185,14 @@
 		/* init registers */
 		switch (dev->descriptor.idProduct) {
 		case USB_PID_PROF_1100:
-			s6x0_properties.rc_key_map = tbs_rc_keys;
+			s6x0_properties.rc_key_map = ir_codes_tbs_table;
 			s6x0_properties.rc_key_map_size =
-					ARRAY_SIZE(tbs_rc_keys);
+					ARRAY_SIZE(ir_codes_tbs_table);
 			break;
 		case USB_PID_TEVII_S650:
-			dw2104_properties.rc_key_map = tevii_rc_keys;
+			dw2104_properties.rc_key_map = ir_codes_tevii_table;
 			dw2104_properties.rc_key_map_size =
-					ARRAY_SIZE(tevii_rc_keys);
+					ARRAY_SIZE(ir_codes_tevii_table);
 		case USB_PID_DW2104:
 			reset = 1;
 			dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1,
@@ -1255,8 +1255,8 @@
 	.no_reconnect = 1,
 
 	.i2c_algo = &dw2102_serit_i2c_algo,
-	.rc_key_map = dw210x_rc_keys,
-	.rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys),
+	.rc_key_map = ir_codes_dw210x_table,
+	.rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
 	.rc_interval = 150,
 	.rc_query = dw2102_rc_query,
 
@@ -1306,8 +1306,8 @@
 	.no_reconnect = 1,
 
 	.i2c_algo = &dw2104_i2c_algo,
-	.rc_key_map = dw210x_rc_keys,
-	.rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys),
+	.rc_key_map = ir_codes_dw210x_table,
+	.rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
 	.rc_interval = 150,
 	.rc_query = dw2102_rc_query,
 
@@ -1353,8 +1353,8 @@
 	.no_reconnect = 1,
 
 	.i2c_algo = &dw3101_i2c_algo,
-	.rc_key_map = dw210x_rc_keys,
-	.rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys),
+	.rc_key_map = ir_codes_dw210x_table,
+	.rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
 	.rc_interval = 150,
 	.rc_query = dw2102_rc_query,
 
@@ -1396,8 +1396,8 @@
 	.no_reconnect = 1,
 
 	.i2c_algo = &s6x0_i2c_algo,
-	.rc_key_map = tevii_rc_keys,
-	.rc_key_map_size = ARRAY_SIZE(tevii_rc_keys),
+	.rc_key_map = ir_codes_tevii_table,
+	.rc_key_map_size = ARRAY_SIZE(ir_codes_tevii_table),
 	.rc_interval = 150,
 	.rc_query = dw2102_rc_query,
 
@@ -1459,8 +1459,8 @@
 	/* fill only different fields */
 	p7500->firmware = "dvb-usb-p7500.fw";
 	p7500->devices[0] = d7500;
-	p7500->rc_key_map = tbs_rc_keys;
-	p7500->rc_key_map_size = ARRAY_SIZE(tbs_rc_keys);
+	p7500->rc_key_map = ir_codes_tbs_table;
+	p7500->rc_key_map_size = ARRAY_SIZE(ir_codes_tbs_table);
 	p7500->adapter->frontend_attach = prof_7500_frontend_attach;
 
 	if (0 == dvb_usb_device_init(intf, &dw2102_properties,
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c
index afb444d..45106ac 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk.c
+++ b/drivers/media/dvb/dvb-usb/gp8psk.c
@@ -105,6 +105,10 @@
 
 	ptr = fw->data;
 	buf = kmalloc(64, GFP_KERNEL | GFP_DMA);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto out_rel_fw;
+	}
 
 	while (ptr[0] != 0xff) {
 		u16 buflen = ptr[0] + 4;
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c
index 737ffa3..c211fef 100644
--- a/drivers/media/dvb/dvb-usb/m920x.c
+++ b/drivers/media/dvb/dvb-usb/m920x.c
@@ -589,7 +589,7 @@
 };
 
 /* ir keymaps */
-static struct dvb_usb_rc_key megasky_rc_keys [] = {
+static struct dvb_usb_rc_key ir_codes_megasky_table [] = {
 	{ 0x0012, KEY_POWER },
 	{ 0x001e, KEY_CYCLEWINDOWS }, /* min/max */
 	{ 0x0002, KEY_CHANNELUP },
@@ -608,7 +608,7 @@
 	{ 0x000e, KEY_COFFEE }, /* "MTS" */
 };
 
-static struct dvb_usb_rc_key tvwalkertwin_rc_keys [] = {
+static struct dvb_usb_rc_key ir_codes_tvwalkertwin_table [] = {
 	{ 0x0001, KEY_ZOOM }, /* Full Screen */
 	{ 0x0002, KEY_CAMERA }, /* snapshot */
 	{ 0x0003, KEY_MUTE },
@@ -628,7 +628,7 @@
 	{ 0x001e, KEY_VOLUMEUP },
 };
 
-static struct dvb_usb_rc_key pinnacle310e_rc_keys[] = {
+static struct dvb_usb_rc_key ir_codes_pinnacle310e_table[] = {
 	{ 0x16, KEY_POWER },
 	{ 0x17, KEY_FAVORITES },
 	{ 0x0f, KEY_TEXT },
@@ -785,8 +785,8 @@
 	.download_firmware = m920x_firmware_download,
 
 	.rc_interval      = 100,
-	.rc_key_map       = megasky_rc_keys,
-	.rc_key_map_size  = ARRAY_SIZE(megasky_rc_keys),
+	.rc_key_map       = ir_codes_megasky_table,
+	.rc_key_map_size  = ARRAY_SIZE(ir_codes_megasky_table),
 	.rc_query         = m920x_rc_query,
 
 	.size_of_priv     = sizeof(struct m920x_state),
@@ -886,8 +886,8 @@
 	.download_firmware = m920x_firmware_download,
 
 	.rc_interval      = 100,
-	.rc_key_map       = tvwalkertwin_rc_keys,
-	.rc_key_map_size  = ARRAY_SIZE(tvwalkertwin_rc_keys),
+	.rc_key_map       = ir_codes_tvwalkertwin_table,
+	.rc_key_map_size  = ARRAY_SIZE(ir_codes_tvwalkertwin_table),
 	.rc_query         = m920x_rc_query,
 
 	.size_of_priv     = sizeof(struct m920x_state),
@@ -993,8 +993,8 @@
 	.download_firmware = NULL,
 
 	.rc_interval      = 100,
-	.rc_key_map       = pinnacle310e_rc_keys,
-	.rc_key_map_size  = ARRAY_SIZE(pinnacle310e_rc_keys),
+	.rc_key_map       = ir_codes_pinnacle310e_table,
+	.rc_key_map_size  = ARRAY_SIZE(ir_codes_pinnacle310e_table),
 	.rc_query         = m920x_rc_query,
 
 	.size_of_priv     = sizeof(struct m920x_state),
diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
index b41d66e..d195a58 100644
--- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c
+++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
@@ -21,7 +21,7 @@
 #define deb_ee(args...) dprintk(debug,0x02,args)
 
 /* Hauppauge NOVA-T USB2 keys */
-static struct dvb_usb_rc_key haupp_rc_keys [] = {
+static struct dvb_usb_rc_key ir_codes_haupp_table [] = {
 	{ 0x1e00, KEY_0 },
 	{ 0x1e01, KEY_1 },
 	{ 0x1e02, KEY_2 },
@@ -91,14 +91,14 @@
 
 			deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to c: %02x d: %02x toggle: %d\n",key[1],key[2],key[3],custom,data,toggle);
 
-			for (i = 0; i < ARRAY_SIZE(haupp_rc_keys); i++) {
-				if (rc5_data(&haupp_rc_keys[i]) == data &&
-					rc5_custom(&haupp_rc_keys[i]) == custom) {
+			for (i = 0; i < ARRAY_SIZE(ir_codes_haupp_table); i++) {
+				if (rc5_data(&ir_codes_haupp_table[i]) == data &&
+					rc5_custom(&ir_codes_haupp_table[i]) == custom) {
 
-					deb_rc("c: %x, d: %x\n", rc5_data(&haupp_rc_keys[i]),
-								 rc5_custom(&haupp_rc_keys[i]));
+					deb_rc("c: %x, d: %x\n", rc5_data(&ir_codes_haupp_table[i]),
+								 rc5_custom(&ir_codes_haupp_table[i]));
 
-					*event = haupp_rc_keys[i].event;
+					*event = ir_codes_haupp_table[i].event;
 					*state = REMOTE_KEY_PRESSED;
 					if (st->old_toggle == toggle) {
 						if (st->last_repeat_count++ < 2)
@@ -196,8 +196,8 @@
 	.read_mac_address = nova_t_read_mac_address,
 
 	.rc_interval      = 100,
-	.rc_key_map       = haupp_rc_keys,
-	.rc_key_map_size  = ARRAY_SIZE(haupp_rc_keys),
+	.rc_key_map       = ir_codes_haupp_table,
+	.rc_key_map_size  = ARRAY_SIZE(ir_codes_haupp_table),
 	.rc_query         = nova_t_rc_query,
 
 	.i2c_algo         = &dibusb_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c
index 83055769..dfb81ff 100644
--- a/drivers/media/dvb/dvb-usb/opera1.c
+++ b/drivers/media/dvb/dvb-usb/opera1.c
@@ -35,7 +35,7 @@
 struct opera1_state {
 	u32 last_key_pressed;
 };
-struct opera_rc_keys {
+struct ir_codes_opera_table {
 	u32 keycode;
 	u32 event;
 };
@@ -331,7 +331,7 @@
 	return 0;
 }
 
-static struct dvb_usb_rc_key opera1_rc_keys[] = {
+static struct dvb_usb_rc_key ir_codes_opera1_table[] = {
 	{0x5fa0, KEY_1},
 	{0x51af, KEY_2},
 	{0x5da2, KEY_3},
@@ -404,12 +404,12 @@
 
 		send_key = (send_key & 0xffff) | 0x0100;
 
-		for (i = 0; i < ARRAY_SIZE(opera1_rc_keys); i++) {
-			if (rc5_scan(&opera1_rc_keys[i]) == (send_key & 0xffff)) {
+		for (i = 0; i < ARRAY_SIZE(ir_codes_opera1_table); i++) {
+			if (rc5_scan(&ir_codes_opera1_table[i]) == (send_key & 0xffff)) {
 				*state = REMOTE_KEY_PRESSED;
-				*event = opera1_rc_keys[i].event;
+				*event = ir_codes_opera1_table[i].event;
 				opst->last_key_pressed =
-					opera1_rc_keys[i].event;
+					ir_codes_opera1_table[i].event;
 				break;
 			}
 			opst->last_key_pressed = 0;
@@ -498,8 +498,8 @@
 	.power_ctrl = opera1_power_ctrl,
 	.i2c_algo = &opera1_i2c_algo,
 
-	.rc_key_map = opera1_rc_keys,
-	.rc_key_map_size = ARRAY_SIZE(opera1_rc_keys),
+	.rc_key_map = ir_codes_opera1_table,
+	.rc_key_map_size = ARRAY_SIZE(ir_codes_opera1_table),
 	.rc_interval = 200,
 	.rc_query = opera1_rc_query,
 	.read_mac_address = opera1_read_mac_address,
diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c
index ef4e37d..4d33245 100644
--- a/drivers/media/dvb/dvb-usb/vp702x.c
+++ b/drivers/media/dvb/dvb-usb/vp702x.c
@@ -174,7 +174,7 @@
 }
 
 /* keys for the enclosed remote control */
-static struct dvb_usb_rc_key vp702x_rc_keys[] = {
+static struct dvb_usb_rc_key ir_codes_vp702x_table[] = {
 	{ 0x0001, KEY_1 },
 	{ 0x0002, KEY_2 },
 };
@@ -197,10 +197,10 @@
 		return 0;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(vp702x_rc_keys); i++)
-		if (rc5_custom(&vp702x_rc_keys[i]) == key[1]) {
+	for (i = 0; i < ARRAY_SIZE(ir_codes_vp702x_table); i++)
+		if (rc5_custom(&ir_codes_vp702x_table[i]) == key[1]) {
 			*state = REMOTE_KEY_PRESSED;
-			*event = vp702x_rc_keys[i].event;
+			*event = ir_codes_vp702x_table[i].event;
 			break;
 		}
 	return 0;
@@ -283,8 +283,8 @@
 	},
 	.read_mac_address = vp702x_read_mac_addr,
 
-	.rc_key_map       = vp702x_rc_keys,
-	.rc_key_map_size  = ARRAY_SIZE(vp702x_rc_keys),
+	.rc_key_map       = ir_codes_vp702x_table,
+	.rc_key_map_size  = ARRAY_SIZE(ir_codes_vp702x_table),
 	.rc_interval      = 400,
 	.rc_query         = vp702x_rc_query,
 
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
index a59faa2..036893f 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -99,7 +99,7 @@
 
 /* The keymapping struct. Somehow this should be loaded to the driver, but
  * currently it is hardcoded. */
-static struct dvb_usb_rc_key vp7045_rc_keys[] = {
+static struct dvb_usb_rc_key ir_codes_vp7045_table[] = {
 	{ 0x0016, KEY_POWER },
 	{ 0x0010, KEY_MUTE },
 	{ 0x0003, KEY_1 },
@@ -165,10 +165,10 @@
 		return 0;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(vp7045_rc_keys); i++)
-		if (rc5_data(&vp7045_rc_keys[i]) == key) {
+	for (i = 0; i < ARRAY_SIZE(ir_codes_vp7045_table); i++)
+		if (rc5_data(&ir_codes_vp7045_table[i]) == key) {
 			*state = REMOTE_KEY_PRESSED;
-			*event = vp7045_rc_keys[i].event;
+			*event = ir_codes_vp7045_table[i].event;
 			break;
 		}
 	return 0;
@@ -260,8 +260,8 @@
 	.read_mac_address = vp7045_read_mac_addr,
 
 	.rc_interval      = 400,
-	.rc_key_map       = vp7045_rc_keys,
-	.rc_key_map_size  = ARRAY_SIZE(vp7045_rc_keys),
+	.rc_key_map       = ir_codes_vp7045_table,
+	.rc_key_map_size  = ARRAY_SIZE(ir_codes_vp7045_table),
 	.rc_query         = vp7045_rc_query,
 
 	.num_device_descs = 2,
diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/dvb/firewire/firedtv-avc.c
index 1b31beb..28294af 100644
--- a/drivers/media/dvb/firewire/firedtv-avc.c
+++ b/drivers/media/dvb/firewire/firedtv-avc.c
@@ -1096,7 +1096,7 @@
 
 	c->operand[15] = msg[1]; /* Program number */
 	c->operand[16] = msg[2];
-	c->operand[17] = 0x01; /* Version number=0 + current/next=1 */
+	c->operand[17] = msg[3]; /* Version number and current/next */
 	c->operand[18] = 0x00; /* Section number=0 */
 	c->operand[19] = 0x00; /* Last section number=0 */
 	c->operand[20] = 0x1f; /* PCR_PID=1FFF */
diff --git a/drivers/media/dvb/frontends/atbm8830_priv.h b/drivers/media/dvb/frontends/atbm8830_priv.h
index ce960f7..d460058 100644
--- a/drivers/media/dvb/frontends/atbm8830_priv.h
+++ b/drivers/media/dvb/frontends/atbm8830_priv.h
@@ -18,7 +18,7 @@
  *    along with this program; if not, write to the Free Software
  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
- 
+
 #ifndef __ATBM8830_PRIV_H
 #define __ATBM8830_PRIV_H
 
diff --git a/drivers/media/dvb/frontends/au8522_decoder.c b/drivers/media/dvb/frontends/au8522_decoder.c
index 24268ef..68dba3a 100644
--- a/drivers/media/dvb/frontends/au8522_decoder.c
+++ b/drivers/media/dvb/frontends/au8522_decoder.c
@@ -664,6 +664,13 @@
 {
 	struct au8522_state *state = to_state(sd);
 
+	state->operational_mode = AU8522_ANALOG_MODE;
+
+	/* Clear out any state associated with the digital side of the
+	   chip, so that when it gets powered back up it won't think
+	   that it is already tuned */
+	state->current_frequency = 0;
+
 	au8522_writereg(state, 0xa4, 1 << 5);
 
 	return 0;
diff --git a/drivers/media/dvb/frontends/au8522_dig.c b/drivers/media/dvb/frontends/au8522_dig.c
index a1fed0f..65f6a36 100644
--- a/drivers/media/dvb/frontends/au8522_dig.c
+++ b/drivers/media/dvb/frontends/au8522_dig.c
@@ -84,6 +84,14 @@
 
 	dprintk("%s(%d)\n", __func__, enable);
 
+	if (state->operational_mode == AU8522_ANALOG_MODE) {
+		/* We're being asked to manage the gate even though we're
+		   not in digital mode.  This can occur if we get switched
+		   over to analog mode before the dvb_frontend kernel thread
+		   has completely shutdown */
+		return 0;
+	}
+
 	if (enable)
 		return au8522_writereg(state, 0x106, 1);
 	else
@@ -608,6 +616,13 @@
 	struct au8522_state *state = fe->demodulator_priv;
 	dprintk("%s()\n", __func__);
 
+	state->operational_mode = AU8522_DIGITAL_MODE;
+
+	/* Clear out any state associated with the digital side of the
+	   chip, so that when it gets powered back up it won't think
+	   that it is already tuned */
+	state->current_frequency = 0;
+
 	au8522_writereg(state, 0xa4, 1 << 5);
 
 	au8522_i2c_gate_ctrl(fe, 1);
@@ -704,6 +719,15 @@
 	struct au8522_state *state = fe->demodulator_priv;
 	dprintk("%s()\n", __func__);
 
+	/* Only power down if the digital side is currently using the chip */
+	if (state->operational_mode == AU8522_ANALOG_MODE) {
+		/* We're not in one of the expected power modes, which means
+		   that the DVB thread is probably telling us to go to sleep
+		   even though the analog frontend has already started using
+		   the chip.  So ignore the request */
+		return 0;
+	}
+
 	/* turn off led */
 	au8522_led_ctrl(state, 0);
 
@@ -932,6 +956,8 @@
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
+	state->operational_mode = AU8522_DIGITAL_MODE;
+
 	/* create dvb_frontend */
 	memcpy(&state->frontend.ops, &au8522_ops,
 	       sizeof(struct dvb_frontend_ops));
diff --git a/drivers/media/dvb/frontends/au8522_priv.h b/drivers/media/dvb/frontends/au8522_priv.h
index c74c4e7..609cf04 100644
--- a/drivers/media/dvb/frontends/au8522_priv.h
+++ b/drivers/media/dvb/frontends/au8522_priv.h
@@ -34,10 +34,15 @@
 #include "au8522.h"
 #include "tuner-i2c.h"
 
+#define AU8522_ANALOG_MODE 0
+#define AU8522_DIGITAL_MODE 1
+
 struct au8522_state {
 	struct i2c_client *c;
 	struct i2c_adapter *i2c;
 
+	u8 operational_mode;
+
 	/* Used for sharing of the state between analog and digital mode */
 	struct tuner_i2c_props i2c_props;
 	struct list_head hybrid_tuner_instance_list;
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
index 40a0998..afad252 100644
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ b/drivers/media/dvb/frontends/dib3000mc.c
@@ -814,42 +814,51 @@
 
 int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib3000mc_config cfg[])
 {
-	struct dib3000mc_state st = { .i2c_adap = i2c };
+	struct dib3000mc_state *dmcst;
 	int k;
 	u8 new_addr;
 
 	static u8 DIB3000MC_I2C_ADDRESS[] = {20,22,24,26};
 
+	dmcst = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL);
+	if (dmcst == NULL)
+		return -ENODEV;
+
+	dmcst->i2c_adap = i2c;
+
 	for (k = no_of_demods-1; k >= 0; k--) {
-		st.cfg = &cfg[k];
+		dmcst->cfg = &cfg[k];
 
 		/* designated i2c address */
 		new_addr          = DIB3000MC_I2C_ADDRESS[k];
-		st.i2c_addr = new_addr;
-		if (dib3000mc_identify(&st) != 0) {
-			st.i2c_addr = default_addr;
-			if (dib3000mc_identify(&st) != 0) {
+		dmcst->i2c_addr = new_addr;
+		if (dib3000mc_identify(dmcst) != 0) {
+			dmcst->i2c_addr = default_addr;
+			if (dib3000mc_identify(dmcst) != 0) {
 				dprintk("-E-  DiB3000P/MC #%d: not identified\n", k);
+				kfree(dmcst);
 				return -ENODEV;
 			}
 		}
 
-		dib3000mc_set_output_mode(&st, OUTMODE_MPEG2_PAR_CONT_CLK);
+		dib3000mc_set_output_mode(dmcst, OUTMODE_MPEG2_PAR_CONT_CLK);
 
 		// set new i2c address and force divstr (Bit 1) to value 0 (Bit 0)
-		dib3000mc_write_word(&st, 1024, (new_addr << 3) | 0x1);
-		st.i2c_addr = new_addr;
+		dib3000mc_write_word(dmcst, 1024, (new_addr << 3) | 0x1);
+		dmcst->i2c_addr = new_addr;
 	}
 
 	for (k = 0; k < no_of_demods; k++) {
-		st.cfg = &cfg[k];
-		st.i2c_addr = DIB3000MC_I2C_ADDRESS[k];
+		dmcst->cfg = &cfg[k];
+		dmcst->i2c_addr = DIB3000MC_I2C_ADDRESS[k];
 
-		dib3000mc_write_word(&st, 1024, st.i2c_addr << 3);
+		dib3000mc_write_word(dmcst, 1024, dmcst->i2c_addr << 3);
 
 		/* turn off data output */
-		dib3000mc_set_output_mode(&st, OUTMODE_HIGH_Z);
+		dib3000mc_set_output_mode(dmcst, OUTMODE_HIGH_Z);
 	}
+
+	kfree(dmcst);
 	return 0;
 }
 EXPORT_SYMBOL(dib3000mc_i2c_enumeration);
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
index 85468a4..2e28b97 100644
--- a/drivers/media/dvb/frontends/dib7000p.c
+++ b/drivers/media/dvb/frontends/dib7000p.c
@@ -1324,46 +1324,54 @@
 
 int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
 {
-	struct dib7000p_state st = { .i2c_adap = i2c };
+	struct dib7000p_state *dpst;
 	int k = 0;
 	u8 new_addr = 0;
 
+	dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
+	if (!dpst)
+		return -ENOMEM;
+
+	dpst->i2c_adap = i2c;
+
 	for (k = no_of_demods-1; k >= 0; k--) {
-		st.cfg = cfg[k];
+		dpst->cfg = cfg[k];
 
 		/* designated i2c address */
 		new_addr          = (0x40 + k) << 1;
-		st.i2c_addr = new_addr;
-		dib7000p_write_word(&st, 1287, 0x0003); /* sram lead in, rdy */
-		if (dib7000p_identify(&st) != 0) {
-			st.i2c_addr = default_addr;
-			dib7000p_write_word(&st, 1287, 0x0003); /* sram lead in, rdy */
-			if (dib7000p_identify(&st) != 0) {
+		dpst->i2c_addr = new_addr;
+		dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
+		if (dib7000p_identify(dpst) != 0) {
+			dpst->i2c_addr = default_addr;
+			dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
+			if (dib7000p_identify(dpst) != 0) {
 				dprintk("DiB7000P #%d: not identified\n", k);
+				kfree(dpst);
 				return -EIO;
 			}
 		}
 
 		/* start diversity to pull_down div_str - just for i2c-enumeration */
-		dib7000p_set_output_mode(&st, OUTMODE_DIVERSITY);
+		dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);
 
 		/* set new i2c address and force divstart */
-		dib7000p_write_word(&st, 1285, (new_addr << 2) | 0x2);
+		dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);
 
 		dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
 	}
 
 	for (k = 0; k < no_of_demods; k++) {
-		st.cfg = cfg[k];
-		st.i2c_addr = (0x40 + k) << 1;
+		dpst->cfg = cfg[k];
+		dpst->i2c_addr = (0x40 + k) << 1;
 
 		// unforce divstr
-		dib7000p_write_word(&st, 1285, st.i2c_addr << 2);
+		dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
 
 		/* deactivate div - it was just for i2c-enumeration */
-		dib7000p_set_output_mode(&st, OUTMODE_HIGH_Z);
+		dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);
 	}
 
+	kfree(dpst);
 	return 0;
 }
 EXPORT_SYMBOL(dib7000p_i2c_enumeration);
diff --git a/drivers/media/dvb/frontends/dib8000.h b/drivers/media/dvb/frontends/dib8000.h
index b1ee207..e0a9ded 100644
--- a/drivers/media/dvb/frontends/dib8000.h
+++ b/drivers/media/dvb/frontends/dib8000.h
@@ -109,6 +109,7 @@
 static inline s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
 {
 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return 0;
 }
 #endif
 
diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c
index cff3535..78001e8 100644
--- a/drivers/media/dvb/frontends/ds3000.c
+++ b/drivers/media/dvb/frontends/ds3000.c
@@ -719,7 +719,7 @@
 				(ds3000_readreg(state, 0x8d) << 4);
 		dvbs2_signal_reading = ds3000_readreg(state, 0x8e);
 		tmp = dvbs2_signal_reading * dvbs2_signal_reading >> 1;
-		if (dvbs2_signal_reading == 0) {
+		if (tmp == 0) {
 			*snr = 0x0000;
 			return 0;
 		}
diff --git a/drivers/media/dvb/frontends/stv0900_core.c b/drivers/media/dvb/frontends/stv0900_core.c
index 01f8f1f..4f5e7d3 100644
--- a/drivers/media/dvb/frontends/stv0900_core.c
+++ b/drivers/media/dvb/frontends/stv0900_core.c
@@ -1583,7 +1583,7 @@
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 
 	struct stv0900_search_params p_search;
-	struct stv0900_signal_info p_result;
+	struct stv0900_signal_info p_result = intp->result[demod];
 
 	enum fe_stv0900_error error = STV0900_NO_ERROR;
 
@@ -1842,6 +1842,19 @@
 	kfree(state);
 }
 
+static int stv0900_get_frontend(struct dvb_frontend *fe,
+				struct dvb_frontend_parameters *p)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *intp = state->internal;
+	enum fe_stv0900_demod_num demod = state->demod;
+	struct stv0900_signal_info p_result = intp->result[demod];
+
+	p->frequency = p_result.locked ? p_result.frequency : 0;
+	p->u.qpsk.symbol_rate = p_result.locked ? p_result.symbol_rate : 0;
+	return 0;
+}
+
 static struct dvb_frontend_ops stv0900_ops = {
 
 	.info = {
@@ -1862,6 +1875,7 @@
 	},
 	.release			= stv0900_release,
 	.init				= stv0900_init,
+	.get_frontend                   = stv0900_get_frontend,
 	.get_frontend_algo		= stv0900_frontend_algo,
 	.i2c_gate_ctrl			= stv0900_i2c_gate_ctrl,
 	.diseqc_send_master_cmd		= stv0900_send_master_cmd,
diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c
index 9697280..425e7a4 100644
--- a/drivers/media/dvb/frontends/stv090x.c
+++ b/drivers/media/dvb/frontends/stv090x.c
@@ -754,11 +754,19 @@
 	return stv090x_write_regs(state, reg, &data, 1);
 }
 
-static int stv090x_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable)
 {
-	struct stv090x_state *state = fe->demodulator_priv;
 	u32 reg;
 
+	/*
+	 * NOTE! A lock is used as a FSM to control the state in which
+	 * access is serialized between two tuners on the same demod.
+	 * This has nothing to do with a lock to protect a critical section
+	 * which may in some other cases be confused with protecting I/O
+	 * access to the demodulator gate.
+	 * In case of any error, the lock is unlocked and exit within the
+	 * relevant operations themselves.
+	 */
 	if (enable)
 		mutex_lock(&state->internal->tuner_lock);
 
@@ -1778,7 +1786,7 @@
 				freq -= cur_step * car_step;
 
 			/* Setup tuner */
-			if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+			if (stv090x_i2c_gate_ctrl(state, 1) < 0)
 				goto err;
 
 			if (state->config->tuner_set_frequency) {
@@ -1791,12 +1799,12 @@
 					goto err_gateoff;
 			}
 
-			if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+			if (stv090x_i2c_gate_ctrl(state, 0) < 0)
 				goto err;
 
 			msleep(50);
 
-			if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+			if (stv090x_i2c_gate_ctrl(state, 1) < 0)
 				goto err;
 
 			if (state->config->tuner_get_status) {
@@ -1809,7 +1817,7 @@
 			else
 				dprintk(FE_DEBUG, 1, "Tuner unlocked");
 
-			if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+			if (stv090x_i2c_gate_ctrl(state, 0) < 0)
 				goto err;
 
 		}
@@ -1822,7 +1830,7 @@
 	return srate_coarse;
 
 err_gateoff:
-	stv090x_i2c_gate_ctrl(fe, 0);
+	stv090x_i2c_gate_ctrl(state, 0);
 err:
 	dprintk(FE_ERROR, 1, "I/O error");
 	return -1;
@@ -2167,7 +2175,7 @@
 						freq -= cur_step * car_step;
 
 					/* Setup tuner */
-					if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+					if (stv090x_i2c_gate_ctrl(state, 1) < 0)
 						goto err;
 
 					if (state->config->tuner_set_frequency) {
@@ -2180,12 +2188,12 @@
 							goto err_gateoff;
 					}
 
-					if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+					if (stv090x_i2c_gate_ctrl(state, 0) < 0)
 						goto err;
 
 					msleep(50);
 
-					if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+					if (stv090x_i2c_gate_ctrl(state, 1) < 0)
 						goto err;
 
 					if (state->config->tuner_get_status) {
@@ -2198,7 +2206,7 @@
 					else
 						dprintk(FE_DEBUG, 1, "Tuner unlocked");
 
-					if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+					if (stv090x_i2c_gate_ctrl(state, 0) < 0)
 						goto err;
 
 					STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c);
@@ -2222,7 +2230,7 @@
 	return lock;
 
 err_gateoff:
-	stv090x_i2c_gate_ctrl(fe, 0);
+	stv090x_i2c_gate_ctrl(state, 0);
 err:
 	dprintk(FE_ERROR, 1, "I/O error");
 	return -1;
@@ -2591,7 +2599,7 @@
 	}
 	state->delsys = stv090x_get_std(state);
 
-	if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+	if (stv090x_i2c_gate_ctrl(state, 1) < 0)
 		goto err;
 
 	if (state->config->tuner_get_frequency) {
@@ -2599,7 +2607,7 @@
 			goto err_gateoff;
 	}
 
-	if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+	if (stv090x_i2c_gate_ctrl(state, 0) < 0)
 		goto err;
 
 	offst_freq = stv090x_get_car_freq(state, state->internal->mclk) / 1000;
@@ -2619,7 +2627,7 @@
 
 	if ((state->algo == STV090x_BLIND_SEARCH) || (state->srate < 10000000)) {
 
-		if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+		if (stv090x_i2c_gate_ctrl(state, 1) < 0)
 			goto err;
 
 		if (state->config->tuner_get_frequency) {
@@ -2627,7 +2635,7 @@
 				goto err_gateoff;
 		}
 
-		if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+		if (stv090x_i2c_gate_ctrl(state, 0) < 0)
 			goto err;
 
 		if (abs(offst_freq) <= ((state->search_range / 2000) + 500))
@@ -2646,7 +2654,7 @@
 	return STV090x_OUTOFRANGE;
 
 err_gateoff:
-	stv090x_i2c_gate_ctrl(fe, 0);
+	stv090x_i2c_gate_ctrl(state, 0);
 err:
 	dprintk(FE_ERROR, 1, "I/O error");
 	return -1;
@@ -3000,7 +3008,7 @@
 
 			if (state->algo != STV090x_WARM_SEARCH) {
 
-				if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+				if (stv090x_i2c_gate_ctrl(state, 1) < 0)
 					goto err;
 
 				if (state->config->tuner_set_bandwidth) {
@@ -3008,7 +3016,7 @@
 						goto err_gateoff;
 				}
 
-				if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+				if (stv090x_i2c_gate_ctrl(state, 0) < 0)
 					goto err;
 
 			}
@@ -3059,7 +3067,7 @@
 	return 0;
 
 err_gateoff:
-	stv090x_i2c_gate_ctrl(fe, 0);
+	stv090x_i2c_gate_ctrl(state, 0);
 err:
 	dprintk(FE_ERROR, 1, "I/O error");
 	return -1;
@@ -3235,7 +3243,7 @@
 	}
 
 	/* Setup tuner */
-	if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+	if (stv090x_i2c_gate_ctrl(state, 1) < 0)
 		goto err;
 
 	if (state->config->tuner_set_bbgain) {
@@ -3256,17 +3264,17 @@
 			goto err_gateoff;
 	}
 
-	if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+	if (stv090x_i2c_gate_ctrl(state, 0) < 0)
 		goto err;
 
 	msleep(50);
 
 	if (state->config->tuner_get_status) {
-		if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+		if (stv090x_i2c_gate_ctrl(state, 1) < 0)
 			goto err;
 		if (state->config->tuner_get_status(fe, &reg) < 0)
 			goto err_gateoff;
-		if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+		if (stv090x_i2c_gate_ctrl(state, 0) < 0)
 			goto err;
 
 		if (reg)
@@ -3400,7 +3408,7 @@
 	return signal_state;
 
 err_gateoff:
-	stv090x_i2c_gate_ctrl(fe, 0);
+	stv090x_i2c_gate_ctrl(state, 0);
 err:
 	dprintk(FE_ERROR, 1, "I/O error");
 	return -1;
@@ -3839,6 +3847,17 @@
 	struct stv090x_state *state = fe->demodulator_priv;
 	u32 reg;
 
+	if (stv090x_i2c_gate_ctrl(state, 1) < 0)
+		goto err;
+
+	if (state->config->tuner_sleep) {
+		if (state->config->tuner_sleep(fe) < 0)
+			goto err_gateoff;
+	}
+
+	if (stv090x_i2c_gate_ctrl(state, 0) < 0)
+		goto err;
+
 	dprintk(FE_DEBUG, 1, "Set %s to sleep",
 		state->device == STV0900 ? "STV0900" : "STV0903");
 
@@ -3853,6 +3872,9 @@
 		goto err;
 
 	return 0;
+
+err_gateoff:
+	stv090x_i2c_gate_ctrl(state, 0);
 err:
 	dprintk(FE_ERROR, 1, "I/O error");
 	return -1;
@@ -4311,6 +4333,20 @@
 	u32 reg;
 
 	if (state->internal->mclk == 0) {
+		/* call tuner init to configure the tuner's clock output
+		   divider directly before setting up the master clock of
+		   the stv090x. */
+		if (stv090x_i2c_gate_ctrl(state, 1) < 0)
+			goto err;
+
+		if (config->tuner_init) {
+			if (config->tuner_init(fe) < 0)
+				goto err_gateoff;
+		}
+
+		if (stv090x_i2c_gate_ctrl(state, 0) < 0)
+			goto err;
+
 		stv090x_set_mclk(state, 135000000, config->xtal); /* 135 Mhz */
 		msleep(5);
 		if (stv090x_write_reg(state, STV090x_SYNTCTRL,
@@ -4336,7 +4372,7 @@
 	if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
 		goto err;
 
-	if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+	if (stv090x_i2c_gate_ctrl(state, 1) < 0)
 		goto err;
 
 	if (config->tuner_set_mode) {
@@ -4349,7 +4385,7 @@
 			goto err_gateoff;
 	}
 
-	if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+	if (stv090x_i2c_gate_ctrl(state, 0) < 0)
 		goto err;
 
 	if (stv090x_set_tspath(state) < 0)
@@ -4358,7 +4394,7 @@
 	return 0;
 
 err_gateoff:
-	stv090x_i2c_gate_ctrl(fe, 0);
+	stv090x_i2c_gate_ctrl(state, 0);
 err:
 	dprintk(FE_ERROR, 1, "I/O error");
 	return -1;
@@ -4503,8 +4539,6 @@
 	.sleep				= stv090x_sleep,
 	.get_frontend_algo		= stv090x_frontend_algo,
 
-	.i2c_gate_ctrl			= stv090x_i2c_gate_ctrl,
-
 	.diseqc_send_master_cmd		= stv090x_send_diseqc_msg,
 	.diseqc_send_burst		= stv090x_send_diseqc_burst,
 	.diseqc_recv_slave_reply	= stv090x_recv_slave_reply,
diff --git a/drivers/media/dvb/frontends/stv090x.h b/drivers/media/dvb/frontends/stv090x.h
index 30f01a6..dd1b93a 100644
--- a/drivers/media/dvb/frontends/stv090x.h
+++ b/drivers/media/dvb/frontends/stv090x.h
@@ -87,6 +87,7 @@
 	bool diseqc_envelope_mode;
 
 	int (*tuner_init) (struct dvb_frontend *fe);
+	int (*tuner_sleep) (struct dvb_frontend *fe);
 	int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode);
 	int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency);
 	int (*tuner_get_frequency) (struct dvb_frontend *fe, u32 *frequency);
diff --git a/drivers/media/dvb/frontends/stv6110x.c b/drivers/media/dvb/frontends/stv6110x.c
index dea4245..42591ce 100644
--- a/drivers/media/dvb/frontends/stv6110x.c
+++ b/drivers/media/dvb/frontends/stv6110x.c
@@ -338,14 +338,12 @@
 		.frequency_max	= 2150000,
 		.frequency_step	= 0,
 	},
-
-	.init			= stv6110x_init,
-	.sleep          	= stv6110x_sleep,
 	.release		= stv6110x_release
 };
 
 static struct stv6110x_devctl stv6110x_ctl = {
 	.tuner_init		= stv6110x_init,
+	.tuner_sleep		= stv6110x_sleep,
 	.tuner_set_mode		= stv6110x_set_mode,
 	.tuner_set_frequency	= stv6110x_set_frequency,
 	.tuner_get_frequency	= stv6110x_get_frequency,
@@ -363,11 +361,10 @@
 {
 	struct stv6110x_state *stv6110x;
 	u8 default_regs[] = {0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e};
-	int ret;
 
 	stv6110x = kzalloc(sizeof (struct stv6110x_state), GFP_KERNEL);
-	if (stv6110x == NULL)
-		goto error;
+	if (!stv6110x)
+		return NULL;
 
 	stv6110x->i2c		= i2c;
 	stv6110x->config	= config;
@@ -392,34 +389,11 @@
 		break;
 	}
 
-	if (fe->ops.i2c_gate_ctrl) {
-		ret = fe->ops.i2c_gate_ctrl(fe, 1);
-		if (ret < 0)
-			goto error;
-	}
-
-	ret = stv6110x_write_regs(stv6110x, 0, stv6110x->regs,
-				  ARRAY_SIZE(stv6110x->regs));
-	if (ret < 0) {
-		dprintk(FE_ERROR, 1, "Initialization failed");
-		goto error;
-	}
-
-	if (fe->ops.i2c_gate_ctrl) {
-		ret = fe->ops.i2c_gate_ctrl(fe, 0);
-		if (ret < 0)
-			goto error;
-	}
-
 	fe->tuner_priv		= stv6110x;
 	fe->ops.tuner_ops	= stv6110x_ops;
 
-	printk("%s: Attaching STV6110x \n", __func__);
+	printk(KERN_INFO "%s: Attaching STV6110x\n", __func__);
 	return stv6110x->devctl;
-
-error:
-	kfree(stv6110x);
-	return NULL;
 }
 EXPORT_SYMBOL(stv6110x_attach);
 
diff --git a/drivers/media/dvb/frontends/stv6110x.h b/drivers/media/dvb/frontends/stv6110x.h
index 2429ae6..47516753 100644
--- a/drivers/media/dvb/frontends/stv6110x.h
+++ b/drivers/media/dvb/frontends/stv6110x.h
@@ -40,6 +40,7 @@
 
 struct stv6110x_devctl {
 	int (*tuner_init) (struct dvb_frontend *fe);
+	int (*tuner_sleep) (struct dvb_frontend *fe);
 	int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode);
 	int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency);
 	int (*tuner_get_frequency) (struct dvb_frontend *fe, u32 *frequency);
diff --git a/drivers/media/dvb/mantis/mantis_input.c b/drivers/media/dvb/mantis/mantis_input.c
index 4675a3b..3d4e466 100644
--- a/drivers/media/dvb/mantis/mantis_input.c
+++ b/drivers/media/dvb/mantis/mantis_input.c
@@ -32,6 +32,8 @@
 #include "mantis_reg.h"
 #include "mantis_uart.h"
 
+#define MODULE_NAME "mantis_core"
+
 static struct ir_scancode mantis_ir_table[] = {
 	{ 0x29, KEY_POWER	},
 	{ 0x28, KEY_FAVORITES	},
@@ -126,7 +128,7 @@
 	rc->id.version	= 1;
 	rc->dev		= mantis->pdev->dev;
 
-	err = ir_input_register(rc, &ir_mantis, NULL);
+	err = __ir_input_register(rc, &ir_mantis, NULL, MODULE_NAME);
 	if (err) {
 		dprintk(MANTIS_ERROR, 1, "IR device registration failed, ret = %d", err);
 		input_free_device(rc);
diff --git a/drivers/media/dvb/mantis/mantis_vp1041.c b/drivers/media/dvb/mantis/mantis_vp1041.c
index 515346d..d1aa2bc 100644
--- a/drivers/media/dvb/mantis/mantis_vp1041.c
+++ b/drivers/media/dvb/mantis/mantis_vp1041.c
@@ -136,12 +136,12 @@
 	{ STB0899_RCOMPC        	, 0xc9 },
 	{ STB0899_AGC1CN        	, 0x01 },
 	{ STB0899_AGC1REF       	, 0x10 },
-	{ STB0899_RTC	        	, 0x23 },
+	{ STB0899_RTC			, 0x23 },
 	{ STB0899_TMGCFG        	, 0x4e },
 	{ STB0899_AGC2REF       	, 0x34 },
 	{ STB0899_TLSR          	, 0x84 },
 	{ STB0899_CFD           	, 0xf7 },
-	{ STB0899_ACLC	        	, 0x87 },
+	{ STB0899_ACLC			, 0x87 },
 	{ STB0899_BCLC          	, 0x94 },
 	{ STB0899_EQON          	, 0x41 },
 	{ STB0899_LDT           	, 0xf1 },
@@ -194,10 +194,10 @@
 	{ STB0899_ECNT3M		, 0x0a },
 	{ STB0899_ECNT3L		, 0xad },
 	{ STB0899_FECAUTO1      	, 0x06 },
-	{ STB0899_FECM	        	, 0x01 },
+	{ STB0899_FECM			, 0x01 },
 	{ STB0899_VTH12         	, 0xb0 },
 	{ STB0899_VTH23         	, 0x7a },
-	{ STB0899_VTH34	        	, 0x58 },
+	{ STB0899_VTH34			, 0x58 },
 	{ STB0899_VTH56         	, 0x38 },
 	{ STB0899_VTH67         	, 0x34 },
 	{ STB0899_VTH78         	, 0x24 },
@@ -206,7 +206,7 @@
 	{ STB0899_RSULC         	, 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
 	{ STB0899_TSULC         	, 0x42 },
 	{ STB0899_RSLLC         	, 0x41 },
-	{ STB0899_TSLPL	        	, 0x12 },
+	{ STB0899_TSLPL			, 0x12 },
 	{ STB0899_TSCFGH        	, 0x0c },
 	{ STB0899_TSCFGM        	, 0x00 },
 	{ STB0899_TSCFGL        	, 0x00 },
diff --git a/drivers/media/dvb/ngene/Kconfig b/drivers/media/dvb/ngene/Kconfig
index 3ec8e6f..cec242b 100644
--- a/drivers/media/dvb/ngene/Kconfig
+++ b/drivers/media/dvb/ngene/Kconfig
@@ -4,6 +4,8 @@
 	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
 	select DVB_STV6110x if !DVB_FE_CUSTOMISE
 	select DVB_STV090x if !DVB_FE_CUSTOMISE
+	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE
 	---help---
 	  Support for Micronas PCI express cards with nGene bridge.
 
diff --git a/drivers/media/dvb/ngene/Makefile b/drivers/media/dvb/ngene/Makefile
index 40435ca..0608aab 100644
--- a/drivers/media/dvb/ngene/Makefile
+++ b/drivers/media/dvb/ngene/Makefile
@@ -2,10 +2,10 @@
 # Makefile for the nGene device driver
 #
 
-ngene-objs := ngene-core.o
+ngene-objs := ngene-core.o ngene-i2c.o ngene-cards.o ngene-dvb.o
 
 obj-$(CONFIG_DVB_NGENE) += ngene.o
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
 EXTRA_CFLAGS += -Idrivers/media/dvb/frontends/
-
+EXTRA_CFLAGS += -Idrivers/media/common/tuners/
diff --git a/drivers/media/dvb/ngene/ngene-cards.c b/drivers/media/dvb/ngene/ngene-cards.c
new file mode 100644
index 0000000..692c3e2
--- /dev/null
+++ b/drivers/media/dvb/ngene/ngene-cards.c
@@ -0,0 +1,328 @@
+/*
+ * ngene-cards.c: nGene PCIe bridge driver - card specific info
+ *
+ * Copyright (C) 2005-2007 Micronas
+ *
+ * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
+ *                         Modifications for new nGene firmware,
+ *                         support for EEPROM-copying,
+ *                         support for new dual DVB-S2 card prototype
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+#include "ngene.h"
+
+/* demods/tuners */
+#include "stv6110x.h"
+#include "stv090x.h"
+#include "lnbh24.h"
+#include "lgdt330x.h"
+#include "mt2131.h"
+
+
+/****************************************************************************/
+/* Demod/tuner attachment ***************************************************/
+/****************************************************************************/
+
+static int tuner_attach_stv6110(struct ngene_channel *chan)
+{
+	struct stv090x_config *feconf = (struct stv090x_config *)
+		chan->dev->card_info->fe_config[chan->number];
+	struct stv6110x_config *tunerconf = (struct stv6110x_config *)
+		chan->dev->card_info->tuner_config[chan->number];
+	struct stv6110x_devctl *ctl;
+
+	ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf,
+			 &chan->i2c_adapter);
+	if (ctl == NULL) {
+		printk(KERN_ERR	DEVICE_NAME ": No STV6110X found!\n");
+		return -ENODEV;
+	}
+
+	feconf->tuner_init          = ctl->tuner_init;
+	feconf->tuner_set_mode      = ctl->tuner_set_mode;
+	feconf->tuner_set_frequency = ctl->tuner_set_frequency;
+	feconf->tuner_get_frequency = ctl->tuner_get_frequency;
+	feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth;
+	feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth;
+	feconf->tuner_set_bbgain    = ctl->tuner_set_bbgain;
+	feconf->tuner_get_bbgain    = ctl->tuner_get_bbgain;
+	feconf->tuner_set_refclk    = ctl->tuner_set_refclk;
+	feconf->tuner_get_status    = ctl->tuner_get_status;
+
+	return 0;
+}
+
+
+static int demod_attach_stv0900(struct ngene_channel *chan)
+{
+	struct stv090x_config *feconf = (struct stv090x_config *)
+		chan->dev->card_info->fe_config[chan->number];
+
+	chan->fe = dvb_attach(stv090x_attach,
+			feconf,
+			&chan->i2c_adapter,
+			chan->number == 0 ? STV090x_DEMODULATOR_0 :
+					    STV090x_DEMODULATOR_1);
+	if (chan->fe == NULL) {
+		printk(KERN_ERR	DEVICE_NAME ": No STV0900 found!\n");
+		return -ENODEV;
+	}
+
+	if (!dvb_attach(lnbh24_attach, chan->fe, &chan->i2c_adapter, 0,
+			0, chan->dev->card_info->lnb[chan->number])) {
+		printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n");
+		dvb_frontend_detach(chan->fe);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static struct lgdt330x_config aver_m780 = {
+	.demod_address = 0xb2 >> 1,
+	.demod_chip    = LGDT3303,
+	.serial_mpeg   = 0x00, /* PARALLEL */
+	.clock_polarity_flip = 1,
+};
+
+static struct mt2131_config m780_tunerconfig = {
+	0xc0 >> 1
+};
+
+/* A single func to attach the demo and tuner, rather than
+ * use two sep funcs like the current design mandates.
+ */
+static int demod_attach_lg330x(struct ngene_channel *chan)
+{
+	chan->fe = dvb_attach(lgdt330x_attach, &aver_m780, &chan->i2c_adapter);
+	if (chan->fe == NULL) {
+		printk(KERN_ERR	DEVICE_NAME ": No LGDT330x found!\n");
+		return -ENODEV;
+	}
+
+	dvb_attach(mt2131_attach, chan->fe, &chan->i2c_adapter,
+		   &m780_tunerconfig, 0);
+
+	return (chan->fe) ? 0 : -ENODEV;
+}
+
+/****************************************************************************/
+/* Switch control (I2C gates, etc.) *****************************************/
+/****************************************************************************/
+
+
+static struct stv090x_config fe_cineS2 = {
+	.device         = STV0900,
+	.demod_mode     = STV090x_DUAL,
+	.clk_mode       = STV090x_CLK_EXT,
+
+	.xtal           = 27000000,
+	.address        = 0x68,
+
+	.ts1_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
+	.ts2_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
+
+	.repeater_level = STV090x_RPTLEVEL_16,
+
+	.adc1_range	= STV090x_ADC_1Vpp,
+	.adc2_range	= STV090x_ADC_1Vpp,
+
+	.diseqc_envelope_mode = true,
+};
+
+static struct stv6110x_config tuner_cineS2_0 = {
+	.addr	= 0x60,
+	.refclk	= 27000000,
+	.clk_div = 1,
+};
+
+static struct stv6110x_config tuner_cineS2_1 = {
+	.addr	= 0x63,
+	.refclk	= 27000000,
+	.clk_div = 1,
+};
+
+static struct ngene_info ngene_info_cineS2 = {
+	.type		= NGENE_SIDEWINDER,
+	.name		= "Linux4Media cineS2 DVB-S2 Twin Tuner",
+	.io_type	= {NGENE_IO_TSIN, NGENE_IO_TSIN},
+	.demod_attach	= {demod_attach_stv0900, demod_attach_stv0900},
+	.tuner_attach	= {tuner_attach_stv6110, tuner_attach_stv6110},
+	.fe_config	= {&fe_cineS2, &fe_cineS2},
+	.tuner_config	= {&tuner_cineS2_0, &tuner_cineS2_1},
+	.lnb		= {0x0b, 0x08},
+	.tsf		= {3, 3},
+	.fw_version	= 15,
+};
+
+static struct ngene_info ngene_info_satixS2 = {
+	.type		= NGENE_SIDEWINDER,
+	.name		= "Mystique SaTiX-S2 Dual",
+	.io_type	= {NGENE_IO_TSIN, NGENE_IO_TSIN},
+	.demod_attach	= {demod_attach_stv0900, demod_attach_stv0900},
+	.tuner_attach	= {tuner_attach_stv6110, tuner_attach_stv6110},
+	.fe_config	= {&fe_cineS2, &fe_cineS2},
+	.tuner_config	= {&tuner_cineS2_0, &tuner_cineS2_1},
+	.lnb		= {0x0b, 0x08},
+	.tsf		= {3, 3},
+	.fw_version	= 15,
+};
+
+static struct ngene_info ngene_info_satixS2v2 = {
+	.type		= NGENE_SIDEWINDER,
+	.name		= "Mystique SaTiX-S2 Dual (v2)",
+	.io_type	= {NGENE_IO_TSIN, NGENE_IO_TSIN},
+	.demod_attach	= {demod_attach_stv0900, demod_attach_stv0900},
+	.tuner_attach	= {tuner_attach_stv6110, tuner_attach_stv6110},
+	.fe_config	= {&fe_cineS2, &fe_cineS2},
+	.tuner_config	= {&tuner_cineS2_0, &tuner_cineS2_1},
+	.lnb		= {0x0a, 0x08},
+	.tsf		= {3, 3},
+	.fw_version	= 15,
+};
+
+static struct ngene_info ngene_info_cineS2v5 = {
+	.type		= NGENE_SIDEWINDER,
+	.name		= "Linux4Media cineS2 DVB-S2 Twin Tuner (v5)",
+	.io_type	= {NGENE_IO_TSIN, NGENE_IO_TSIN},
+	.demod_attach	= {demod_attach_stv0900, demod_attach_stv0900},
+	.tuner_attach	= {tuner_attach_stv6110, tuner_attach_stv6110},
+	.fe_config	= {&fe_cineS2, &fe_cineS2},
+	.tuner_config	= {&tuner_cineS2_0, &tuner_cineS2_1},
+	.lnb		= {0x0a, 0x08},
+	.tsf		= {3, 3},
+	.fw_version	= 15,
+};
+
+static struct ngene_info ngene_info_m780 = {
+	.type           = NGENE_APP,
+	.name           = "Aver M780 ATSC/QAM-B",
+
+	/* Channel 0 is analog, which is currently unsupported */
+	.io_type        = { NGENE_IO_NONE, NGENE_IO_TSIN },
+	.demod_attach   = { NULL, demod_attach_lg330x },
+
+	/* Ensure these are NULL else the frame will call them (as funcs) */
+	.tuner_attach   = { 0, 0, 0, 0 },
+	.fe_config      = { NULL, &aver_m780 },
+	.avf            = { 0 },
+
+	/* A custom electrical interface config for the demod to bridge */
+	.tsf		= { 4, 4 },
+	.fw_version	= 15,
+};
+
+/****************************************************************************/
+
+
+
+/****************************************************************************/
+/* PCI Subsystem ID *********************************************************/
+/****************************************************************************/
+
+#define NGENE_ID(_subvend, _subdev, _driverdata) { \
+	.vendor = NGENE_VID, .device = NGENE_PID, \
+	.subvendor = _subvend, .subdevice = _subdev, \
+	.driver_data = (unsigned long) &_driverdata }
+
+/****************************************************************************/
+
+static const struct pci_device_id ngene_id_tbl[] __devinitdata = {
+	NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2),
+	NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2),
+	NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2),
+	NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2),
+	NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5),
+	NGENE_ID(0x1461, 0x062e, ngene_info_m780),
+	{0}
+};
+MODULE_DEVICE_TABLE(pci, ngene_id_tbl);
+
+/****************************************************************************/
+/* Init/Exit ****************************************************************/
+/****************************************************************************/
+
+static pci_ers_result_t ngene_error_detected(struct pci_dev *dev,
+					     enum pci_channel_state state)
+{
+	printk(KERN_ERR DEVICE_NAME ": PCI error\n");
+	if (state == pci_channel_io_perm_failure)
+		return PCI_ERS_RESULT_DISCONNECT;
+	if (state == pci_channel_io_frozen)
+		return PCI_ERS_RESULT_NEED_RESET;
+	return PCI_ERS_RESULT_CAN_RECOVER;
+}
+
+static pci_ers_result_t ngene_link_reset(struct pci_dev *dev)
+{
+	printk(KERN_INFO DEVICE_NAME ": link reset\n");
+	return 0;
+}
+
+static pci_ers_result_t ngene_slot_reset(struct pci_dev *dev)
+{
+	printk(KERN_INFO DEVICE_NAME ": slot reset\n");
+	return 0;
+}
+
+static void ngene_resume(struct pci_dev *dev)
+{
+	printk(KERN_INFO DEVICE_NAME ": resume\n");
+}
+
+static struct pci_error_handlers ngene_errors = {
+	.error_detected = ngene_error_detected,
+	.link_reset = ngene_link_reset,
+	.slot_reset = ngene_slot_reset,
+	.resume = ngene_resume,
+};
+
+static struct pci_driver ngene_pci_driver = {
+	.name        = "ngene",
+	.id_table    = ngene_id_tbl,
+	.probe       = ngene_probe,
+	.remove      = __devexit_p(ngene_remove),
+	.err_handler = &ngene_errors,
+};
+
+static __init int module_init_ngene(void)
+{
+	printk(KERN_INFO
+	       "nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n");
+	return pci_register_driver(&ngene_pci_driver);
+}
+
+static __exit void module_exit_ngene(void)
+{
+	pci_unregister_driver(&ngene_pci_driver);
+}
+
+module_init(module_init_ngene);
+module_exit(module_exit_ngene);
+
+MODULE_DESCRIPTION("nGene");
+MODULE_AUTHOR("Micronas, Ralph Metzler, Manfred Voelkel");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c
index 645e8b8..c8b4dfa 100644
--- a/drivers/media/dvb/ngene/ngene-core.c
+++ b/drivers/media/dvb/ngene/ngene-core.c
@@ -34,20 +34,14 @@
 #include <linux/io.h>
 #include <asm/div64.h>
 #include <linux/pci.h>
-#include <linux/pci_ids.h>
 #include <linux/smp_lock.h>
 #include <linux/timer.h>
-#include <linux/version.h>
 #include <linux/byteorder/generic.h>
 #include <linux/firmware.h>
 #include <linux/vmalloc.h>
 
 #include "ngene.h"
 
-#include "stv6110x.h"
-#include "stv090x.h"
-#include "lnbh24.h"
-
 static int one_adapter = 1;
 module_param(one_adapter, int, 0444);
 MODULE_PARM_DESC(one_adapter, "Use only one adapter.");
@@ -63,8 +57,6 @@
 
 #define dprintk	if (debug) printk
 
-#define DEVICE_NAME "ngene"
-
 #define ngwriteb(dat, adr)         writeb((dat), (char *)(dev->iomem + (adr)))
 #define ngwritel(dat, adr)         writel((dat), (char *)(dev->iomem + (adr)))
 #define ngwriteb(dat, adr)         writeb((dat), (char *)(dev->iomem + (adr)))
@@ -352,7 +344,7 @@
 	return 0;
 }
 
-static int ngene_command(struct ngene *dev, struct ngene_command *com)
+int ngene_command(struct ngene *dev, struct ngene_command *com)
 {
 	int result;
 
@@ -363,55 +355,6 @@
 }
 
 
-static int ngene_command_i2c_read(struct ngene *dev, u8 adr,
-			   u8 *out, u8 outlen, u8 *in, u8 inlen, int flag)
-{
-	struct ngene_command com;
-
-	com.cmd.hdr.Opcode = CMD_I2C_READ;
-	com.cmd.hdr.Length = outlen + 3;
-	com.cmd.I2CRead.Device = adr << 1;
-	memcpy(com.cmd.I2CRead.Data, out, outlen);
-	com.cmd.I2CRead.Data[outlen] = inlen;
-	com.cmd.I2CRead.Data[outlen + 1] = 0;
-	com.in_len = outlen + 3;
-	com.out_len = inlen + 1;
-
-	if (ngene_command(dev, &com) < 0)
-		return -EIO;
-
-	if ((com.cmd.raw8[0] >> 1) != adr)
-		return -EIO;
-
-	if (flag)
-		memcpy(in, com.cmd.raw8, inlen + 1);
-	else
-		memcpy(in, com.cmd.raw8 + 1, inlen);
-	return 0;
-}
-
-static int ngene_command_i2c_write(struct ngene *dev, u8 adr,
-				   u8 *out, u8 outlen)
-{
-	struct ngene_command com;
-
-
-	com.cmd.hdr.Opcode = CMD_I2C_WRITE;
-	com.cmd.hdr.Length = outlen + 1;
-	com.cmd.I2CRead.Device = adr << 1;
-	memcpy(com.cmd.I2CRead.Data, out, outlen);
-	com.in_len = outlen + 1;
-	com.out_len = 1;
-
-	if (ngene_command(dev, &com) < 0)
-		return -EIO;
-
-	if (com.cmd.raw8[0] == 1)
-		return -EIO;
-
-	return 0;
-}
-
 static int ngene_command_load_firmware(struct ngene *dev,
 				       u8 *ngene_fw, u32 size)
 {
@@ -477,7 +420,7 @@
 	return 0;
 }
 
-static int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level)
+int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level)
 {
 	struct ngene_command com;
 
@@ -514,11 +457,12 @@
 
 /****************************************************************************/
 
-static u8 TSFeatureDecoderSetup[8 * 4] = {
+static u8 TSFeatureDecoderSetup[8 * 5] = {
 	0x42, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00,
 	0x40, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00,	/* DRXH */
 	0x71, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00,	/* DRXHser */
 	0x72, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00,	/* S2ser */
+	0x40, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* LGDT3303 */
 };
 
 /* Set NGENE I2S Config to 16 bit packed */
@@ -559,7 +503,7 @@
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x04, 0x00
 };
 
-static void FillTSBuffer(void *Buffer, int Length, u32 Flags)
+void FillTSBuffer(void *Buffer, int Length, u32 Flags)
 {
 	u32 *ptr = Buffer;
 
@@ -772,144 +716,7 @@
 	return 0;
 }
 
-
-/****************************************************************************/
-/* I2C **********************************************************************/
-/****************************************************************************/
-
-static void ngene_i2c_set_bus(struct ngene *dev, int bus)
-{
-	if (!(dev->card_info->i2c_access & 2))
-		return;
-	if (dev->i2c_current_bus == bus)
-		return;
-
-	switch (bus) {
-	case 0:
-		ngene_command_gpio_set(dev, 3, 0);
-		ngene_command_gpio_set(dev, 2, 1);
-		break;
-
-	case 1:
-		ngene_command_gpio_set(dev, 2, 0);
-		ngene_command_gpio_set(dev, 3, 1);
-		break;
-	}
-	dev->i2c_current_bus = bus;
-}
-
-static int ngene_i2c_master_xfer(struct i2c_adapter *adapter,
-				 struct i2c_msg msg[], int num)
-{
-	struct ngene_channel *chan =
-		(struct ngene_channel *)i2c_get_adapdata(adapter);
-	struct ngene *dev = chan->dev;
-
-	down(&dev->i2c_switch_mutex);
-	ngene_i2c_set_bus(dev, chan->number);
-
-	if (num == 2 && msg[1].flags & I2C_M_RD && !(msg[0].flags & I2C_M_RD))
-		if (!ngene_command_i2c_read(dev, msg[0].addr,
-					    msg[0].buf, msg[0].len,
-					    msg[1].buf, msg[1].len, 0))
-			goto done;
-
-	if (num == 1 && !(msg[0].flags & I2C_M_RD))
-		if (!ngene_command_i2c_write(dev, msg[0].addr,
-					     msg[0].buf, msg[0].len))
-			goto done;
-	if (num == 1 && (msg[0].flags & I2C_M_RD))
-		if (!ngene_command_i2c_read(dev, msg[0].addr, 0, 0,
-					    msg[0].buf, msg[0].len, 0))
-			goto done;
-
-	up(&dev->i2c_switch_mutex);
-	return -EIO;
-
-done:
-	up(&dev->i2c_switch_mutex);
-	return num;
-}
-
-
-static u32 ngene_i2c_functionality(struct i2c_adapter *adap)
-{
-	return I2C_FUNC_SMBUS_EMUL;
-}
-
-static struct i2c_algorithm ngene_i2c_algo = {
-	.master_xfer = ngene_i2c_master_xfer,
-	.functionality = ngene_i2c_functionality,
-};
-
-static int ngene_i2c_init(struct ngene *dev, int dev_nr)
-{
-	struct i2c_adapter *adap = &(dev->channel[dev_nr].i2c_adapter);
-
-	i2c_set_adapdata(adap, &(dev->channel[dev_nr]));
-	adap->class = I2C_CLASS_TV_DIGITAL | I2C_CLASS_TV_ANALOG;
-
-	strcpy(adap->name, "nGene");
-
-	adap->algo = &ngene_i2c_algo;
-	adap->algo_data = (void *)&(dev->channel[dev_nr]);
-	adap->dev.parent = &dev->pci_dev->dev;
-
-	return i2c_add_adapter(adap);
-}
-
-
-/****************************************************************************/
-/* DVB functions and API interface ******************************************/
-/****************************************************************************/
-
-static void swap_buffer(u32 *p, u32 len)
-{
-	while (len) {
-		*p = swab32(*p);
-		p++;
-		len -= 4;
-	}
-}
-
-
-static void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
-{
-	struct ngene_channel *chan = priv;
-
-
-#ifdef COMMAND_TIMEOUT_WORKAROUND
-	if (chan->users > 0)
-#endif
-		dvb_dmx_swfilter(&chan->demux, buf, len);
-	return 0;
-}
-
-u8 fill_ts[188] = { 0x47, 0x1f, 0xff, 0x10 };
-
-static void *tsout_exchange(void *priv, void *buf, u32 len,
-			    u32 clock, u32 flags)
-{
-	struct ngene_channel *chan = priv;
-	struct ngene *dev = chan->dev;
-	u32 alen;
-
-	alen = dvb_ringbuffer_avail(&dev->tsout_rbuf);
-	alen -= alen % 188;
-
-	if (alen < len)
-		FillTSBuffer(buf + alen, len - alen, flags);
-	else
-		alen = len;
-	dvb_ringbuffer_read(&dev->tsout_rbuf, buf, alen);
-	if (flags & DF_SWAP32)
-		swap_buffer((u32 *)buf, alen);
-	wake_up_interruptible(&dev->tsout_rbuf.queue);
-	return buf;
-}
-
-
-static void set_transfer(struct ngene_channel *chan, int state)
+void set_transfer(struct ngene_channel *chan, int state)
 {
 	u8 control = 0, mode = 0, flags = 0;
 	struct ngene *dev = chan->dev;
@@ -970,85 +777,12 @@
 		       state);
 	if (!state) {
 		spin_lock_irq(&chan->state_lock);
-		chan->pBufferExchange = 0;
+		chan->pBufferExchange = NULL;
 		dvb_ringbuffer_flush(&dev->tsout_rbuf);
 		spin_unlock_irq(&chan->state_lock);
 	}
 }
 
-static int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-	struct ngene_channel *chan = dvbdmx->priv;
-
-	if (chan->users == 0) {
-#ifdef COMMAND_TIMEOUT_WORKAROUND
-		if (!chan->running)
-#endif
-			set_transfer(chan, 1);
-		/* msleep(10); */
-	}
-
-	return ++chan->users;
-}
-
-static int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-	struct ngene_channel *chan = dvbdmx->priv;
-
-	if (--chan->users)
-		return chan->users;
-
-#ifndef COMMAND_TIMEOUT_WORKAROUND
-	set_transfer(chan, 0);
-#endif
-
-	return 0;
-}
-
-
-
-static int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id,
-				   int (*start_feed)(struct dvb_demux_feed *),
-				   int (*stop_feed)(struct dvb_demux_feed *),
-				   void *priv)
-{
-	dvbdemux->priv = priv;
-
-	dvbdemux->filternum = 256;
-	dvbdemux->feednum = 256;
-	dvbdemux->start_feed = start_feed;
-	dvbdemux->stop_feed = stop_feed;
-	dvbdemux->write_to_decoder = 0;
-	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
-				      DMX_SECTION_FILTERING |
-				      DMX_MEMORY_BASED_FILTERING);
-	return dvb_dmx_init(dvbdemux);
-}
-
-static int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev,
-				      struct dvb_demux *dvbdemux,
-				      struct dmx_frontend *hw_frontend,
-				      struct dmx_frontend *mem_frontend,
-				      struct dvb_adapter *dvb_adapter)
-{
-	int ret;
-
-	dmxdev->filternum = 256;
-	dmxdev->demux = &dvbdemux->dmx;
-	dmxdev->capabilities = 0;
-	ret = dvb_dmxdev_init(dmxdev, dvb_adapter);
-	if (ret < 0)
-		return ret;
-
-	hw_frontend->source = DMX_FRONTEND_0;
-	dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend);
-	mem_frontend->source = DMX_MEMORY_FE;
-	dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend);
-	return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend);
-}
-
 
 /****************************************************************************/
 /* nGene hardware init and release functions ********************************/
@@ -1094,8 +828,8 @@
 		return;
 	free_ringbuffer(dev, rb);
 	for (j = 0; j < tb->NumBuffers; j++, Cur = Cur->Next) {
-		Cur->Buffer2 = 0;
-		Cur->scList2 = 0;
+		Cur->Buffer2 = NULL;
+		Cur->scList2 = NULL;
 		Cur->ngeneBuffer.Address_of_first_entry_2 = 0;
 		Cur->ngeneBuffer.Number_of_entries_2 = 0;
 	}
@@ -1141,7 +875,7 @@
 	u64 PARingBufferNext;
 	struct SBufferHeader *Cur, *Next;
 
-	descr->Head = 0;
+	descr->Head = NULL;
 	descr->MemSize = 0;
 	descr->PAHead = 0;
 	descr->NumBuffers = 0;
@@ -1633,69 +1367,6 @@
 
 
 
-/****************************************************************************/
-/* Switch control (I2C gates, etc.) *****************************************/
-/****************************************************************************/
-
-
-/****************************************************************************/
-/* Demod/tuner attachment ***************************************************/
-/****************************************************************************/
-
-static int tuner_attach_stv6110(struct ngene_channel *chan)
-{
-	struct stv090x_config *feconf = (struct stv090x_config *)
-		chan->dev->card_info->fe_config[chan->number];
-	struct stv6110x_config *tunerconf = (struct stv6110x_config *)
-		chan->dev->card_info->tuner_config[chan->number];
-	struct stv6110x_devctl *ctl;
-
-	ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf,
-			 &chan->i2c_adapter);
-	if (ctl == NULL) {
-		printk(KERN_ERR	DEVICE_NAME ": No STV6110X found!\n");
-		return -ENODEV;
-	}
-
-	feconf->tuner_init          = ctl->tuner_init;
-	feconf->tuner_set_mode      = ctl->tuner_set_mode;
-	feconf->tuner_set_frequency = ctl->tuner_set_frequency;
-	feconf->tuner_get_frequency = ctl->tuner_get_frequency;
-	feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth;
-	feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth;
-	feconf->tuner_set_bbgain    = ctl->tuner_set_bbgain;
-	feconf->tuner_get_bbgain    = ctl->tuner_get_bbgain;
-	feconf->tuner_set_refclk    = ctl->tuner_set_refclk;
-	feconf->tuner_get_status    = ctl->tuner_get_status;
-
-	return 0;
-}
-
-
-static int demod_attach_stv0900(struct ngene_channel *chan)
-{
-	struct stv090x_config *feconf = (struct stv090x_config *)
-		chan->dev->card_info->fe_config[chan->number];
-
-	chan->fe = dvb_attach(stv090x_attach,
-			feconf,
-			&chan->i2c_adapter,
-			chan->number == 0 ? STV090x_DEMODULATOR_0 :
-					    STV090x_DEMODULATOR_1);
-	if (chan->fe == NULL) {
-		printk(KERN_ERR	DEVICE_NAME ": No STV0900 found!\n");
-		return -ENODEV;
-	}
-
-	if (!dvb_attach(lnbh24_attach, chan->fe, &chan->i2c_adapter, 0,
-			0, chan->dev->card_info->lnb[chan->number])) {
-		printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n");
-		dvb_frontend_detach(chan->fe);
-		return -ENODEV;
-	}
-
-	return 0;
-}
 
 /****************************************************************************/
 /****************************************************************************/
@@ -1719,7 +1390,7 @@
 		if (chan->fe) {
 			dvb_unregister_frontend(chan->fe);
 			dvb_frontend_detach(chan->fe);
-			chan->fe = 0;
+			chan->fe = NULL;
 		}
 		dvbdemux->dmx.close(&dvbdemux->dmx);
 		dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
@@ -1751,7 +1422,7 @@
 	if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
 		if (nr >= STREAM_AUDIOIN1)
 			chan->DataFormatFlags = DF_SWAP32;
-		if (nr == 0 || !one_adapter) {
+		if (nr == 0 || !one_adapter || dev->first_adapter == NULL) {
 			adapter = &dev->adapter[nr];
 			ret = dvb_register_adapter(adapter, "nGene",
 						   THIS_MODULE,
@@ -1759,8 +1430,10 @@
 						   adapter_nr);
 			if (ret < 0)
 				return ret;
+			if (dev->first_adapter == NULL)
+				dev->first_adapter = adapter;
 		} else {
-			adapter = &dev->adapter[0];
+			adapter = dev->first_adapter;
 		}
 
 		ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux",
@@ -1797,6 +1470,7 @@
 	int i, j;
 
 	for (i = 0; i < MAX_STREAM; i++) {
+		dev->channel[i].number = i;
 		if (init_channel(&dev->channel[i]) < 0) {
 			for (j = i - 1; j >= 0; j--)
 				release_channel(&dev->channel[j]);
@@ -1810,7 +1484,7 @@
 /* device probe/remove calls ************************************************/
 /****************************************************************************/
 
-static void __devexit ngene_remove(struct pci_dev *pdev)
+void __devexit ngene_remove(struct pci_dev *pdev)
 {
 	struct ngene *dev = (struct ngene *)pci_get_drvdata(pdev);
 	int i;
@@ -1820,12 +1494,12 @@
 		release_channel(&dev->channel[i]);
 	ngene_stop(dev);
 	ngene_release_buffers(dev);
-	pci_set_drvdata(pdev, 0);
+	pci_set_drvdata(pdev, NULL);
 	pci_disable_device(pdev);
 }
 
-static int __devinit ngene_probe(struct pci_dev *pci_dev,
-				 const struct pci_device_id *id)
+int __devinit ngene_probe(struct pci_dev *pci_dev,
+			  const struct pci_device_id *id)
 {
 	struct ngene *dev;
 	int stat = 0;
@@ -1868,156 +1542,6 @@
 	ngene_release_buffers(dev);
 fail0:
 	pci_disable_device(pci_dev);
-	pci_set_drvdata(pci_dev, 0);
+	pci_set_drvdata(pci_dev, NULL);
 	return stat;
 }
-
-/****************************************************************************/
-/* Card configs *************************************************************/
-/****************************************************************************/
-
-static struct stv090x_config fe_cineS2 = {
-	.device         = STV0900,
-	.demod_mode     = STV090x_DUAL,
-	.clk_mode       = STV090x_CLK_EXT,
-
-	.xtal           = 27000000,
-	.address        = 0x68,
-
-	.ts1_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
-	.ts2_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
-
-	.repeater_level = STV090x_RPTLEVEL_16,
-
-	.adc1_range	= STV090x_ADC_1Vpp,
-	.adc2_range	= STV090x_ADC_1Vpp,
-
-	.diseqc_envelope_mode = true,
-};
-
-static struct stv6110x_config tuner_cineS2_0 = {
-	.addr	= 0x60,
-	.refclk	= 27000000,
-	.clk_div = 1,
-};
-
-static struct stv6110x_config tuner_cineS2_1 = {
-	.addr	= 0x63,
-	.refclk	= 27000000,
-	.clk_div = 1,
-};
-
-static struct ngene_info ngene_info_cineS2 = {
-	.type		= NGENE_SIDEWINDER,
-	.name		= "Linux4Media cineS2 DVB-S2 Twin Tuner",
-	.io_type	= {NGENE_IO_TSIN, NGENE_IO_TSIN},
-	.demod_attach	= {demod_attach_stv0900, demod_attach_stv0900},
-	.tuner_attach	= {tuner_attach_stv6110, tuner_attach_stv6110},
-	.fe_config	= {&fe_cineS2, &fe_cineS2},
-	.tuner_config	= {&tuner_cineS2_0, &tuner_cineS2_1},
-	.lnb		= {0x0b, 0x08},
-	.tsf		= {3, 3},
-	.fw_version	= 15,
-};
-
-static struct ngene_info ngene_info_satixs2 = {
-	.type		= NGENE_SIDEWINDER,
-	.name		= "Mystique SaTiX-S2 Dual",
-	.io_type	= {NGENE_IO_TSIN, NGENE_IO_TSIN},
-	.demod_attach	= {demod_attach_stv0900, demod_attach_stv0900},
-	.tuner_attach	= {tuner_attach_stv6110, tuner_attach_stv6110},
-	.fe_config	= {&fe_cineS2, &fe_cineS2},
-	.tuner_config	= {&tuner_cineS2_0, &tuner_cineS2_1},
-	.lnb		= {0x0b, 0x08},
-	.tsf		= {3, 3},
-	.fw_version	= 15,
-};
-
-/****************************************************************************/
-
-
-
-/****************************************************************************/
-/* PCI Subsystem ID *********************************************************/
-/****************************************************************************/
-
-#define NGENE_ID(_subvend, _subdev, _driverdata) { \
-	.vendor = NGENE_VID, .device = NGENE_PID, \
-	.subvendor = _subvend, .subdevice = _subdev, \
-	.driver_data = (unsigned long) &_driverdata }
-
-/****************************************************************************/
-
-static const struct pci_device_id ngene_id_tbl[] __devinitdata = {
-	NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2),
-	NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2),
-	NGENE_ID(0x18c3, 0xdb01, ngene_info_satixs2),
-	{0}
-};
-MODULE_DEVICE_TABLE(pci, ngene_id_tbl);
-
-/****************************************************************************/
-/* Init/Exit ****************************************************************/
-/****************************************************************************/
-
-static pci_ers_result_t ngene_error_detected(struct pci_dev *dev,
-					     enum pci_channel_state state)
-{
-	printk(KERN_ERR DEVICE_NAME ": PCI error\n");
-	if (state == pci_channel_io_perm_failure)
-		return PCI_ERS_RESULT_DISCONNECT;
-	if (state == pci_channel_io_frozen)
-		return PCI_ERS_RESULT_NEED_RESET;
-	return PCI_ERS_RESULT_CAN_RECOVER;
-}
-
-static pci_ers_result_t ngene_link_reset(struct pci_dev *dev)
-{
-	printk(KERN_INFO DEVICE_NAME ": link reset\n");
-	return 0;
-}
-
-static pci_ers_result_t ngene_slot_reset(struct pci_dev *dev)
-{
-	printk(KERN_INFO DEVICE_NAME ": slot reset\n");
-	return 0;
-}
-
-static void ngene_resume(struct pci_dev *dev)
-{
-	printk(KERN_INFO DEVICE_NAME ": resume\n");
-}
-
-static struct pci_error_handlers ngene_errors = {
-	.error_detected = ngene_error_detected,
-	.link_reset = ngene_link_reset,
-	.slot_reset = ngene_slot_reset,
-	.resume = ngene_resume,
-};
-
-static struct pci_driver ngene_pci_driver = {
-	.name        = "ngene",
-	.id_table    = ngene_id_tbl,
-	.probe       = ngene_probe,
-	.remove      = __devexit_p(ngene_remove),
-	.err_handler = &ngene_errors,
-};
-
-static __init int module_init_ngene(void)
-{
-	printk(KERN_INFO
-	       "nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n");
-	return pci_register_driver(&ngene_pci_driver);
-}
-
-static __exit void module_exit_ngene(void)
-{
-	pci_unregister_driver(&ngene_pci_driver);
-}
-
-module_init(module_init_ngene);
-module_exit(module_exit_ngene);
-
-MODULE_DESCRIPTION("nGene");
-MODULE_AUTHOR("Micronas, Ralph Metzler, Manfred Voelkel");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/ngene/ngene-dvb.c b/drivers/media/dvb/ngene/ngene-dvb.c
new file mode 100644
index 0000000..96013eb
--- /dev/null
+++ b/drivers/media/dvb/ngene/ngene-dvb.c
@@ -0,0 +1,172 @@
+/*
+ * ngene-dvb.c: nGene PCIe bridge driver - DVB functions
+ *
+ * Copyright (C) 2005-2007 Micronas
+ *
+ * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
+ *                         Modifications for new nGene firmware,
+ *                         support for EEPROM-copying,
+ *                         support for new dual DVB-S2 card prototype
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/io.h>
+#include <asm/div64.h>
+#include <linux/pci.h>
+#include <linux/smp_lock.h>
+#include <linux/timer.h>
+#include <linux/version.h>
+#include <linux/byteorder/generic.h>
+#include <linux/firmware.h>
+#include <linux/vmalloc.h>
+
+#include "ngene.h"
+
+#define COMMAND_TIMEOUT_WORKAROUND
+
+
+/****************************************************************************/
+/* COMMAND API interface ****************************************************/
+/****************************************************************************/
+
+/****************************************************************************/
+/* DVB functions and API interface ******************************************/
+/****************************************************************************/
+
+static void swap_buffer(u32 *p, u32 len)
+{
+	while (len) {
+		*p = swab32(*p);
+		p++;
+		len -= 4;
+	}
+}
+
+void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
+{
+	struct ngene_channel *chan = priv;
+
+
+#ifdef COMMAND_TIMEOUT_WORKAROUND
+	if (chan->users > 0)
+#endif
+		dvb_dmx_swfilter(&chan->demux, buf, len);
+	return NULL;
+}
+
+u8 fill_ts[188] = { 0x47, 0x1f, 0xff, 0x10 };
+
+void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
+{
+	struct ngene_channel *chan = priv;
+	struct ngene *dev = chan->dev;
+	u32 alen;
+
+	alen = dvb_ringbuffer_avail(&dev->tsout_rbuf);
+	alen -= alen % 188;
+
+	if (alen < len)
+		FillTSBuffer(buf + alen, len - alen, flags);
+	else
+		alen = len;
+	dvb_ringbuffer_read(&dev->tsout_rbuf, buf, alen);
+	if (flags & DF_SWAP32)
+		swap_buffer((u32 *)buf, alen);
+	wake_up_interruptible(&dev->tsout_rbuf.queue);
+	return buf;
+}
+
+
+
+int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	struct ngene_channel *chan = dvbdmx->priv;
+
+	if (chan->users == 0) {
+#ifdef COMMAND_TIMEOUT_WORKAROUND
+		if (!chan->running)
+#endif
+			set_transfer(chan, 1);
+		/* msleep(10); */
+	}
+
+	return ++chan->users;
+}
+
+int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	struct ngene_channel *chan = dvbdmx->priv;
+
+	if (--chan->users)
+		return chan->users;
+
+#ifndef COMMAND_TIMEOUT_WORKAROUND
+	set_transfer(chan, 0);
+#endif
+
+	return 0;
+}
+
+int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id,
+			    int (*start_feed)(struct dvb_demux_feed *),
+			    int (*stop_feed)(struct dvb_demux_feed *),
+			    void *priv)
+{
+	dvbdemux->priv = priv;
+
+	dvbdemux->filternum = 256;
+	dvbdemux->feednum = 256;
+	dvbdemux->start_feed = start_feed;
+	dvbdemux->stop_feed = stop_feed;
+	dvbdemux->write_to_decoder = NULL;
+	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
+				      DMX_SECTION_FILTERING |
+				      DMX_MEMORY_BASED_FILTERING);
+	return dvb_dmx_init(dvbdemux);
+}
+
+int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev,
+			       struct dvb_demux *dvbdemux,
+			       struct dmx_frontend *hw_frontend,
+			       struct dmx_frontend *mem_frontend,
+			       struct dvb_adapter *dvb_adapter)
+{
+	int ret;
+
+	dmxdev->filternum = 256;
+	dmxdev->demux = &dvbdemux->dmx;
+	dmxdev->capabilities = 0;
+	ret = dvb_dmxdev_init(dmxdev, dvb_adapter);
+	if (ret < 0)
+		return ret;
+
+	hw_frontend->source = DMX_FRONTEND_0;
+	dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend);
+	mem_frontend->source = DMX_MEMORY_FE;
+	dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend);
+	return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend);
+}
diff --git a/drivers/media/dvb/ngene/ngene-i2c.c b/drivers/media/dvb/ngene/ngene-i2c.c
new file mode 100644
index 0000000..2ef54ca6
--- /dev/null
+++ b/drivers/media/dvb/ngene/ngene-i2c.c
@@ -0,0 +1,179 @@
+/*
+ * ngene-i2c.c: nGene PCIe bridge driver i2c functions
+ *
+ * Copyright (C) 2005-2007 Micronas
+ *
+ * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
+ *                         Modifications for new nGene firmware,
+ *                         support for EEPROM-copying,
+ *                         support for new dual DVB-S2 card prototype
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+/* FIXME - some of these can probably be removed */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/io.h>
+#include <asm/div64.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/smp_lock.h>
+#include <linux/timer.h>
+#include <linux/version.h>
+#include <linux/byteorder/generic.h>
+#include <linux/firmware.h>
+#include <linux/vmalloc.h>
+
+#include "ngene.h"
+
+/* Firmware command for i2c operations */
+static int ngene_command_i2c_read(struct ngene *dev, u8 adr,
+			   u8 *out, u8 outlen, u8 *in, u8 inlen, int flag)
+{
+	struct ngene_command com;
+
+	com.cmd.hdr.Opcode = CMD_I2C_READ;
+	com.cmd.hdr.Length = outlen + 3;
+	com.cmd.I2CRead.Device = adr << 1;
+	memcpy(com.cmd.I2CRead.Data, out, outlen);
+	com.cmd.I2CRead.Data[outlen] = inlen;
+	com.cmd.I2CRead.Data[outlen + 1] = 0;
+	com.in_len = outlen + 3;
+	com.out_len = inlen + 1;
+
+	if (ngene_command(dev, &com) < 0)
+		return -EIO;
+
+	if ((com.cmd.raw8[0] >> 1) != adr)
+		return -EIO;
+
+	if (flag)
+		memcpy(in, com.cmd.raw8, inlen + 1);
+	else
+		memcpy(in, com.cmd.raw8 + 1, inlen);
+	return 0;
+}
+
+static int ngene_command_i2c_write(struct ngene *dev, u8 adr,
+				   u8 *out, u8 outlen)
+{
+	struct ngene_command com;
+
+
+	com.cmd.hdr.Opcode = CMD_I2C_WRITE;
+	com.cmd.hdr.Length = outlen + 1;
+	com.cmd.I2CRead.Device = adr << 1;
+	memcpy(com.cmd.I2CRead.Data, out, outlen);
+	com.in_len = outlen + 1;
+	com.out_len = 1;
+
+	if (ngene_command(dev, &com) < 0)
+		return -EIO;
+
+	if (com.cmd.raw8[0] == 1)
+		return -EIO;
+
+	return 0;
+}
+
+static void ngene_i2c_set_bus(struct ngene *dev, int bus)
+{
+	if (!(dev->card_info->i2c_access & 2))
+		return;
+	if (dev->i2c_current_bus == bus)
+		return;
+
+	switch (bus) {
+	case 0:
+		ngene_command_gpio_set(dev, 3, 0);
+		ngene_command_gpio_set(dev, 2, 1);
+		break;
+
+	case 1:
+		ngene_command_gpio_set(dev, 2, 0);
+		ngene_command_gpio_set(dev, 3, 1);
+		break;
+	}
+	dev->i2c_current_bus = bus;
+}
+
+static int ngene_i2c_master_xfer(struct i2c_adapter *adapter,
+				 struct i2c_msg msg[], int num)
+{
+	struct ngene_channel *chan =
+		(struct ngene_channel *)i2c_get_adapdata(adapter);
+	struct ngene *dev = chan->dev;
+
+	down(&dev->i2c_switch_mutex);
+	ngene_i2c_set_bus(dev, chan->number);
+
+	if (num == 2 && msg[1].flags & I2C_M_RD && !(msg[0].flags & I2C_M_RD))
+		if (!ngene_command_i2c_read(dev, msg[0].addr,
+					    msg[0].buf, msg[0].len,
+					    msg[1].buf, msg[1].len, 0))
+			goto done;
+
+	if (num == 1 && !(msg[0].flags & I2C_M_RD))
+		if (!ngene_command_i2c_write(dev, msg[0].addr,
+					     msg[0].buf, msg[0].len))
+			goto done;
+	if (num == 1 && (msg[0].flags & I2C_M_RD))
+		if (!ngene_command_i2c_read(dev, msg[0].addr, NULL, 0,
+					    msg[0].buf, msg[0].len, 0))
+			goto done;
+
+	up(&dev->i2c_switch_mutex);
+	return -EIO;
+
+done:
+	up(&dev->i2c_switch_mutex);
+	return num;
+}
+
+
+static u32 ngene_i2c_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm ngene_i2c_algo = {
+	.master_xfer = ngene_i2c_master_xfer,
+	.functionality = ngene_i2c_functionality,
+};
+
+int ngene_i2c_init(struct ngene *dev, int dev_nr)
+{
+	struct i2c_adapter *adap = &(dev->channel[dev_nr].i2c_adapter);
+
+	i2c_set_adapdata(adap, &(dev->channel[dev_nr]));
+	adap->class = I2C_CLASS_TV_DIGITAL | I2C_CLASS_TV_ANALOG;
+
+	strcpy(adap->name, "nGene");
+
+	adap->algo = &ngene_i2c_algo;
+	adap->algo_data = (void *)&(dev->channel[dev_nr]);
+	adap->dev.parent = &dev->pci_dev->dev;
+
+	return i2c_add_adapter(adap);
+}
+
diff --git a/drivers/media/dvb/ngene/ngene.h b/drivers/media/dvb/ngene/ngene.h
index a7eb298..676fcbb 100644
--- a/drivers/media/dvb/ngene/ngene.h
+++ b/drivers/media/dvb/ngene/ngene.h
@@ -39,6 +39,8 @@
 #include "dvb_frontend.h"
 #include "dvb_ringbuffer.h"
 
+#define DEVICE_NAME "ngene"
+
 #define NGENE_VID       0x18c3
 #define NGENE_PID       0x0720
 
@@ -752,6 +754,7 @@
 	spinlock_t            cmd_lock;
 
 	struct dvb_adapter    adapter[MAX_STREAM];
+	struct dvb_adapter    *first_adapter; /* "one_adapter" modprobe opt */
 	struct ngene_channel  channel[MAX_STREAM];
 
 	struct ngene_info    *card_info;
@@ -853,6 +856,33 @@
 #endif
 
 
+/* Provided by ngene-core.c */
+int __devinit ngene_probe(struct pci_dev *pci_dev,
+			  const struct pci_device_id *id);
+void __devexit ngene_remove(struct pci_dev *pdev);
+int ngene_command(struct ngene *dev, struct ngene_command *com);
+int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level);
+void set_transfer(struct ngene_channel *chan, int state);
+void FillTSBuffer(void *Buffer, int Length, u32 Flags);
+
+/* Provided by ngene-i2c.c */
+int ngene_i2c_init(struct ngene *dev, int dev_nr);
+
+/* Provided by ngene-dvb.c */
+void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags);
+void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags);
+int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed);
+int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed);
+int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id,
+			    int (*start_feed)(struct dvb_demux_feed *),
+			    int (*stop_feed)(struct dvb_demux_feed *),
+			    void *priv);
+int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev,
+			       struct dvb_demux *dvbdemux,
+			       struct dmx_frontend *hw_frontend,
+			       struct dmx_frontend *mem_frontend,
+			       struct dvb_adapter *dvb_adapter);
+
 #endif
 
 /*  LocalWords:  Endif
diff --git a/drivers/media/dvb/pt1/pt1.c b/drivers/media/dvb/pt1/pt1.c
index 6aded23..69ad949 100644
--- a/drivers/media/dvb/pt1/pt1.c
+++ b/drivers/media/dvb/pt1/pt1.c
@@ -1,5 +1,5 @@
 /*
- * driver for Earthsoft PT1
+ * driver for Earthsoft PT1/PT2
  *
  * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
  *
@@ -77,6 +77,10 @@
 	struct pt1_adapter *adaps[PT1_NR_ADAPS];
 	struct pt1_table *tables;
 	struct task_struct *kthread;
+
+	struct mutex lock;
+	int power;
+	int reset;
 };
 
 struct pt1_adapter {
@@ -95,6 +99,11 @@
 	struct dvb_frontend *fe;
 	int (*orig_set_voltage)(struct dvb_frontend *fe,
 				fe_sec_voltage_t voltage);
+	int (*orig_sleep)(struct dvb_frontend *fe);
+	int (*orig_init)(struct dvb_frontend *fe);
+
+	fe_sec_voltage_t voltage;
+	int sleep;
 };
 
 #define pt1_printk(level, pt1, format, arg...)	\
@@ -219,8 +228,10 @@
 static int pt1_enable_ram(struct pt1 *pt1)
 {
 	int i, ret;
+	int phase;
 	schedule_timeout_uninterruptible((HZ + 999) / 1000);
-	for (i = 0; i < 10; i++) {
+	phase = pt1->pdev->device == 0x211a ? 128 : 166;
+	for (i = 0; i < phase; i++) {
 		ret = pt1_do_enable_ram(pt1);
 		if (ret < 0)
 			return ret;
@@ -485,33 +496,47 @@
 }
 
 static void
-pt1_set_power(struct pt1 *pt1, int power, int lnb, int reset)
+pt1_update_power(struct pt1 *pt1)
 {
-	pt1_write_reg(pt1, 1, power | lnb << 1 | !reset << 3);
+	int bits;
+	int i;
+	struct pt1_adapter *adap;
+	static const int sleep_bits[] = {
+		1 << 4,
+		1 << 6 | 1 << 7,
+		1 << 5,
+		1 << 6 | 1 << 8,
+	};
+
+	bits = pt1->power | !pt1->reset << 3;
+	mutex_lock(&pt1->lock);
+	for (i = 0; i < PT1_NR_ADAPS; i++) {
+		adap = pt1->adaps[i];
+		switch (adap->voltage) {
+		case SEC_VOLTAGE_13: /* actually 11V */
+			bits |= 1 << 1;
+			break;
+		case SEC_VOLTAGE_18: /* actually 15V */
+			bits |= 1 << 1 | 1 << 2;
+			break;
+		default:
+			break;
+		}
+
+		/* XXX: The bits should be changed depending on adap->sleep. */
+		bits |= sleep_bits[i];
+	}
+	pt1_write_reg(pt1, 1, bits);
+	mutex_unlock(&pt1->lock);
 }
 
 static int pt1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
 	struct pt1_adapter *adap;
-	int lnb;
 
 	adap = container_of(fe->dvb, struct pt1_adapter, adap);
-
-	switch (voltage) {
-	case SEC_VOLTAGE_13: /* actually 11V */
-		lnb = 2;
-		break;
-	case SEC_VOLTAGE_18: /* actually 15V */
-		lnb = 3;
-		break;
-	case SEC_VOLTAGE_OFF:
-		lnb = 0;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	pt1_set_power(adap->pt1, 1, lnb, 0);
+	adap->voltage = voltage;
+	pt1_update_power(adap->pt1);
 
 	if (adap->orig_set_voltage)
 		return adap->orig_set_voltage(fe, voltage);
@@ -519,9 +544,37 @@
 		return 0;
 }
 
+static int pt1_sleep(struct dvb_frontend *fe)
+{
+	struct pt1_adapter *adap;
+
+	adap = container_of(fe->dvb, struct pt1_adapter, adap);
+	adap->sleep = 1;
+	pt1_update_power(adap->pt1);
+
+	if (adap->orig_sleep)
+		return adap->orig_sleep(fe);
+	else
+		return 0;
+}
+
+static int pt1_wakeup(struct dvb_frontend *fe)
+{
+	struct pt1_adapter *adap;
+
+	adap = container_of(fe->dvb, struct pt1_adapter, adap);
+	adap->sleep = 0;
+	pt1_update_power(adap->pt1);
+	schedule_timeout_uninterruptible((HZ + 999) / 1000);
+
+	if (adap->orig_init)
+		return adap->orig_init(fe);
+	else
+		return 0;
+}
+
 static void pt1_free_adapter(struct pt1_adapter *adap)
 {
-	dvb_unregister_frontend(adap->fe);
 	dvb_net_release(&adap->net);
 	adap->demux.dmx.close(&adap->demux.dmx);
 	dvb_dmxdev_release(&adap->dmxdev);
@@ -534,7 +587,7 @@
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 static struct pt1_adapter *
-pt1_alloc_adapter(struct pt1 *pt1, struct dvb_frontend *fe)
+pt1_alloc_adapter(struct pt1 *pt1)
 {
 	struct pt1_adapter *adap;
 	void *buf;
@@ -551,8 +604,8 @@
 
 	adap->pt1 = pt1;
 
-	adap->orig_set_voltage = fe->ops.set_voltage;
-	fe->ops.set_voltage = pt1_set_voltage;
+	adap->voltage = SEC_VOLTAGE_OFF;
+	adap->sleep = 1;
 
 	buf = (u8 *)__get_free_page(GFP_KERNEL);
 	if (!buf) {
@@ -593,17 +646,8 @@
 
 	dvb_net_init(dvb_adap, &adap->net, &demux->dmx);
 
-	ret = dvb_register_frontend(dvb_adap, fe);
-	if (ret < 0)
-		goto err_net_release;
-	adap->fe = fe;
-
 	return adap;
 
-err_net_release:
-	dvb_net_release(&adap->net);
-	adap->demux.dmx.close(&adap->demux.dmx);
-	dvb_dmxdev_release(&adap->dmxdev);
 err_dmx_release:
 	dvb_dmx_release(demux);
 err_unregister_adapter:
@@ -623,6 +667,62 @@
 		pt1_free_adapter(pt1->adaps[i]);
 }
 
+static int pt1_init_adapters(struct pt1 *pt1)
+{
+	int i;
+	struct pt1_adapter *adap;
+	int ret;
+
+	for (i = 0; i < PT1_NR_ADAPS; i++) {
+		adap = pt1_alloc_adapter(pt1);
+		if (IS_ERR(adap)) {
+			ret = PTR_ERR(adap);
+			goto err;
+		}
+
+		adap->index = i;
+		pt1->adaps[i] = adap;
+	}
+	return 0;
+
+err:
+	while (i--)
+		pt1_free_adapter(pt1->adaps[i]);
+
+	return ret;
+}
+
+static void pt1_cleanup_frontend(struct pt1_adapter *adap)
+{
+	dvb_unregister_frontend(adap->fe);
+}
+
+static int pt1_init_frontend(struct pt1_adapter *adap, struct dvb_frontend *fe)
+{
+	int ret;
+
+	adap->orig_set_voltage = fe->ops.set_voltage;
+	adap->orig_sleep = fe->ops.sleep;
+	adap->orig_init = fe->ops.init;
+	fe->ops.set_voltage = pt1_set_voltage;
+	fe->ops.sleep = pt1_sleep;
+	fe->ops.init = pt1_wakeup;
+
+	ret = dvb_register_frontend(&adap->adap, fe);
+	if (ret < 0)
+		return ret;
+
+	adap->fe = fe;
+	return 0;
+}
+
+static void pt1_cleanup_frontends(struct pt1 *pt1)
+{
+	int i;
+	for (i = 0; i < PT1_NR_ADAPS; i++)
+		pt1_cleanup_frontend(pt1->adaps[i]);
+}
+
 struct pt1_config {
 	struct va1j5jf8007s_config va1j5jf8007s_config;
 	struct va1j5jf8007t_config va1j5jf8007t_config;
@@ -630,29 +730,63 @@
 
 static const struct pt1_config pt1_configs[2] = {
 	{
-		{ .demod_address = 0x1b },
-		{ .demod_address = 0x1a },
+		{
+			.demod_address = 0x1b,
+			.frequency = VA1J5JF8007S_20MHZ,
+		},
+		{
+			.demod_address = 0x1a,
+			.frequency = VA1J5JF8007T_20MHZ,
+		},
 	}, {
-		{ .demod_address = 0x19 },
-		{ .demod_address = 0x18 },
+		{
+			.demod_address = 0x19,
+			.frequency = VA1J5JF8007S_20MHZ,
+		},
+		{
+			.demod_address = 0x18,
+			.frequency = VA1J5JF8007T_20MHZ,
+		},
 	},
 };
 
-static int pt1_init_adapters(struct pt1 *pt1)
+static const struct pt1_config pt2_configs[2] = {
+	{
+		{
+			.demod_address = 0x1b,
+			.frequency = VA1J5JF8007S_25MHZ,
+		},
+		{
+			.demod_address = 0x1a,
+			.frequency = VA1J5JF8007T_25MHZ,
+		},
+	}, {
+		{
+			.demod_address = 0x19,
+			.frequency = VA1J5JF8007S_25MHZ,
+		},
+		{
+			.demod_address = 0x18,
+			.frequency = VA1J5JF8007T_25MHZ,
+		},
+	},
+};
+
+static int pt1_init_frontends(struct pt1 *pt1)
 {
 	int i, j;
 	struct i2c_adapter *i2c_adap;
-	const struct pt1_config *config;
+	const struct pt1_config *configs, *config;
 	struct dvb_frontend *fe[4];
-	struct pt1_adapter *adap;
 	int ret;
 
 	i = 0;
 	j = 0;
 
 	i2c_adap = &pt1->i2c_adap;
+	configs = pt1->pdev->device == 0x211a ? pt1_configs : pt2_configs;
 	do {
-		config = &pt1_configs[i / 2];
+		config = &configs[i / 2];
 
 		fe[i] = va1j5jf8007s_attach(&config->va1j5jf8007s_config,
 					    i2c_adap);
@@ -681,11 +815,9 @@
 	} while (i < 4);
 
 	do {
-		adap = pt1_alloc_adapter(pt1, fe[j]);
-		if (IS_ERR(adap))
+		ret = pt1_init_frontend(pt1->adaps[j], fe[j]);
+		if (ret < 0)
 			goto err;
-		adap->index = j;
-		pt1->adaps[j] = adap;
 	} while (++j < 4);
 
 	return 0;
@@ -695,7 +827,7 @@
 		fe[i]->ops.release(fe[i]);
 
 	while (j--)
-		pt1_free_adapter(pt1->adaps[j]);
+		dvb_unregister_frontend(fe[j]);
 
 	return ret;
 }
@@ -890,9 +1022,12 @@
 
 	kthread_stop(pt1->kthread);
 	pt1_cleanup_tables(pt1);
-	pt1_cleanup_adapters(pt1);
+	pt1_cleanup_frontends(pt1);
 	pt1_disable_ram(pt1);
-	pt1_set_power(pt1, 0, 0, 1);
+	pt1->power = 0;
+	pt1->reset = 1;
+	pt1_update_power(pt1);
+	pt1_cleanup_adapters(pt1);
 	i2c_del_adapter(&pt1->i2c_adap);
 	pci_set_drvdata(pdev, NULL);
 	kfree(pt1);
@@ -936,10 +1071,21 @@
 		goto err_pci_iounmap;
 	}
 
+	mutex_init(&pt1->lock);
 	pt1->pdev = pdev;
 	pt1->regs = regs;
 	pci_set_drvdata(pdev, pt1);
 
+	ret = pt1_init_adapters(pt1);
+	if (ret < 0)
+		goto err_kfree;
+
+	mutex_init(&pt1->lock);
+
+	pt1->power = 0;
+	pt1->reset = 1;
+	pt1_update_power(pt1);
+
 	i2c_adap = &pt1->i2c_adap;
 	i2c_adap->class = I2C_CLASS_TV_DIGITAL;
 	i2c_adap->algo = &pt1_i2c_algo;
@@ -948,9 +1094,7 @@
 	i2c_set_adapdata(i2c_adap, pt1);
 	ret = i2c_add_adapter(i2c_adap);
 	if (ret < 0)
-		goto err_kfree;
-
-	pt1_set_power(pt1, 0, 0, 1);
+		goto err_pt1_cleanup_adapters;
 
 	pt1_i2c_init(pt1);
 	pt1_i2c_wait(pt1);
@@ -979,19 +1123,21 @@
 
 	pt1_init_streams(pt1);
 
-	pt1_set_power(pt1, 1, 0, 1);
+	pt1->power = 1;
+	pt1_update_power(pt1);
 	schedule_timeout_uninterruptible((HZ + 49) / 50);
 
-	pt1_set_power(pt1, 1, 0, 0);
+	pt1->reset = 0;
+	pt1_update_power(pt1);
 	schedule_timeout_uninterruptible((HZ + 999) / 1000);
 
-	ret = pt1_init_adapters(pt1);
+	ret = pt1_init_frontends(pt1);
 	if (ret < 0)
 		goto err_pt1_disable_ram;
 
 	ret = pt1_init_tables(pt1);
 	if (ret < 0)
-		goto err_pt1_cleanup_adapters;
+		goto err_pt1_cleanup_frontends;
 
 	kthread = kthread_run(pt1_thread, pt1, "pt1");
 	if (IS_ERR(kthread)) {
@@ -1004,11 +1150,15 @@
 
 err_pt1_cleanup_tables:
 	pt1_cleanup_tables(pt1);
-err_pt1_cleanup_adapters:
-	pt1_cleanup_adapters(pt1);
+err_pt1_cleanup_frontends:
+	pt1_cleanup_frontends(pt1);
 err_pt1_disable_ram:
 	pt1_disable_ram(pt1);
-	pt1_set_power(pt1, 0, 0, 1);
+	pt1->power = 0;
+	pt1->reset = 1;
+	pt1_update_power(pt1);
+err_pt1_cleanup_adapters:
+	pt1_cleanup_adapters(pt1);
 err_i2c_del_adapter:
 	i2c_del_adapter(i2c_adap);
 err_kfree:
@@ -1027,6 +1177,7 @@
 
 static struct pci_device_id pt1_id_table[] = {
 	{ PCI_DEVICE(0x10ee, 0x211a) },
+	{ PCI_DEVICE(0x10ee, 0x222a) },
 	{ },
 };
 MODULE_DEVICE_TABLE(pci, pt1_id_table);
@@ -1054,5 +1205,5 @@
 module_exit(pt1_cleanup);
 
 MODULE_AUTHOR("Takahito HIRANO <hiranotaka@zng.info>");
-MODULE_DESCRIPTION("Earthsoft PT1 Driver");
+MODULE_DESCRIPTION("Earthsoft PT1/PT2 Driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/pt1/va1j5jf8007s.c b/drivers/media/dvb/pt1/va1j5jf8007s.c
index fc65949..451641c 100644
--- a/drivers/media/dvb/pt1/va1j5jf8007s.c
+++ b/drivers/media/dvb/pt1/va1j5jf8007s.c
@@ -1,5 +1,5 @@
 /*
- * ISDB-S driver for VA1J5JF8007
+ * ISDB-S driver for VA1J5JF8007/VA1J5JF8011
  *
  * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
  *
@@ -580,7 +580,7 @@
 
 static struct dvb_frontend_ops va1j5jf8007s_ops = {
 	.info = {
-		.name = "VA1J5JF8007 ISDB-S",
+		.name = "VA1J5JF8007/VA1J5JF8011 ISDB-S",
 		.type = FE_QPSK,
 		.frequency_min = 950000,
 		.frequency_max = 2150000,
@@ -628,28 +628,50 @@
 	return 0;
 }
 
-static const u8 va1j5jf8007s_prepare_bufs[][2] = {
+static const u8 va1j5jf8007s_20mhz_prepare_bufs[][2] = {
 	{0x04, 0x02}, {0x0d, 0x55}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01},
 	{0x1c, 0x0a}, {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0},
 	{0x52, 0x89}, {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69},
 	{0x87, 0x04}, {0x8e, 0x02}, {0xa3, 0xf7}, {0xa5, 0xc0},
 };
 
+static const u8 va1j5jf8007s_25mhz_prepare_bufs[][2] = {
+	{0x04, 0x02}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01}, {0x1c, 0x0a},
+	{0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0}, {0x52, 0x89},
+	{0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69}, {0x87, 0x04},
+	{0x8e, 0x26}, {0xa3, 0xf7}, {0xa5, 0xc0},
+};
+
 static int va1j5jf8007s_prepare_2(struct va1j5jf8007s_state *state)
 {
+	const u8 (*bufs)[2];
+	int size;
 	u8 addr;
 	u8 buf[2];
 	struct i2c_msg msg;
 	int i;
 
+	switch (state->config->frequency) {
+	case VA1J5JF8007S_20MHZ:
+		bufs = va1j5jf8007s_20mhz_prepare_bufs;
+		size = ARRAY_SIZE(va1j5jf8007s_20mhz_prepare_bufs);
+		break;
+	case VA1J5JF8007S_25MHZ:
+		bufs = va1j5jf8007s_25mhz_prepare_bufs;
+		size = ARRAY_SIZE(va1j5jf8007s_25mhz_prepare_bufs);
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	addr = state->config->demod_address;
 
 	msg.addr = addr;
 	msg.flags = 0;
 	msg.len = 2;
 	msg.buf = buf;
-	for (i = 0; i < ARRAY_SIZE(va1j5jf8007s_prepare_bufs); i++) {
-		memcpy(buf, va1j5jf8007s_prepare_bufs[i], sizeof(buf));
+	for (i = 0; i < size; i++) {
+		memcpy(buf, bufs[i], sizeof(buf));
 		if (i2c_transfer(state->adap, &msg, 1) != 1)
 			return -EREMOTEIO;
 	}
diff --git a/drivers/media/dvb/pt1/va1j5jf8007s.h b/drivers/media/dvb/pt1/va1j5jf8007s.h
index aa228a8..b7d6f05 100644
--- a/drivers/media/dvb/pt1/va1j5jf8007s.h
+++ b/drivers/media/dvb/pt1/va1j5jf8007s.h
@@ -1,5 +1,5 @@
 /*
- * ISDB-S driver for VA1J5JF8007
+ * ISDB-S driver for VA1J5JF8007/VA1J5JF8011
  *
  * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
  *
@@ -24,8 +24,14 @@
 #ifndef VA1J5JF8007S_H
 #define VA1J5JF8007S_H
 
+enum va1j5jf8007s_frequency {
+	VA1J5JF8007S_20MHZ,
+	VA1J5JF8007S_25MHZ,
+};
+
 struct va1j5jf8007s_config {
 	u8 demod_address;
+	enum va1j5jf8007s_frequency frequency;
 };
 
 struct i2c_adapter;
diff --git a/drivers/media/dvb/pt1/va1j5jf8007t.c b/drivers/media/dvb/pt1/va1j5jf8007t.c
index 3db4f3e3..0f085c3 100644
--- a/drivers/media/dvb/pt1/va1j5jf8007t.c
+++ b/drivers/media/dvb/pt1/va1j5jf8007t.c
@@ -1,5 +1,5 @@
 /*
- * ISDB-T driver for VA1J5JF8007
+ * ISDB-T driver for VA1J5JF8007/VA1J5JF8011
  *
  * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
  *
@@ -429,7 +429,7 @@
 
 static struct dvb_frontend_ops va1j5jf8007t_ops = {
 	.info = {
-		.name = "VA1J5JF8007 ISDB-T",
+		.name = "VA1J5JF8007/VA1J5JF8011 ISDB-T",
 		.type = FE_OFDM,
 		.frequency_min = 90000000,
 		.frequency_max = 770000000,
@@ -448,29 +448,50 @@
 	.release = va1j5jf8007t_release,
 };
 
-static const u8 va1j5jf8007t_prepare_bufs[][2] = {
+static const u8 va1j5jf8007t_20mhz_prepare_bufs[][2] = {
 	{0x03, 0x90}, {0x14, 0x8f}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2},
 	{0x22, 0x83}, {0x31, 0x0d}, {0x32, 0xe0}, {0x39, 0xd3}, {0x3a, 0x00},
 	{0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x02}, {0x76, 0x4e}, {0x77, 0x03},
 	{0xef, 0x01}
 };
 
+static const u8 va1j5jf8007t_25mhz_prepare_bufs[][2] = {
+	{0x03, 0x90}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2}, {0x22, 0x83},
+	{0x3a, 0x00}, {0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x0a}, {0x76, 0x4c},
+	{0x77, 0x03}, {0xef, 0x01}
+};
+
 int va1j5jf8007t_prepare(struct dvb_frontend *fe)
 {
 	struct va1j5jf8007t_state *state;
+	const u8 (*bufs)[2];
+	int size;
 	u8 buf[2];
 	struct i2c_msg msg;
 	int i;
 
 	state = fe->demodulator_priv;
 
+	switch (state->config->frequency) {
+	case VA1J5JF8007T_20MHZ:
+		bufs = va1j5jf8007t_20mhz_prepare_bufs;
+		size = ARRAY_SIZE(va1j5jf8007t_20mhz_prepare_bufs);
+		break;
+	case VA1J5JF8007T_25MHZ:
+		bufs = va1j5jf8007t_25mhz_prepare_bufs;
+		size = ARRAY_SIZE(va1j5jf8007t_25mhz_prepare_bufs);
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	msg.addr = state->config->demod_address;
 	msg.flags = 0;
 	msg.len = sizeof(buf);
 	msg.buf = buf;
 
-	for (i = 0; i < ARRAY_SIZE(va1j5jf8007t_prepare_bufs); i++) {
-		memcpy(buf, va1j5jf8007t_prepare_bufs[i], sizeof(buf));
+	for (i = 0; i < size; i++) {
+		memcpy(buf, bufs[i], sizeof(buf));
 		if (i2c_transfer(state->adap, &msg, 1) != 1)
 			return -EREMOTEIO;
 	}
diff --git a/drivers/media/dvb/pt1/va1j5jf8007t.h b/drivers/media/dvb/pt1/va1j5jf8007t.h
index ed49906..2903be5 100644
--- a/drivers/media/dvb/pt1/va1j5jf8007t.h
+++ b/drivers/media/dvb/pt1/va1j5jf8007t.h
@@ -1,5 +1,5 @@
 /*
- * ISDB-T driver for VA1J5JF8007
+ * ISDB-T driver for VA1J5JF8007/VA1J5JF8011
  *
  * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
  *
@@ -24,8 +24,14 @@
 #ifndef VA1J5JF8007T_H
 #define VA1J5JF8007T_H
 
+enum va1j5jf8007t_frequency {
+	VA1J5JF8007T_20MHZ,
+	VA1J5JF8007T_25MHZ,
+};
+
 struct va1j5jf8007t_config {
 	u8 demod_address;
+	enum va1j5jf8007t_frequency frequency;
 };
 
 struct i2c_adapter;
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 49c2a81..4617143 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -35,7 +35,7 @@
 #include <linux/interrupt.h>
 #include <linux/input.h>
 #include <linux/spinlock.h>
-#include <media/ir-common.h>
+#include <media/ir-core.h>
 
 #include "budget.h"
 
@@ -54,6 +54,8 @@
 #include "tda1002x.h"
 #include "tda827x.h"
 
+#define MODULE_NAME "budget_ci"
+
 /*
  * Regarding DEBIADDR_IR:
  * Some CI modules hang if random addresses are read.
@@ -80,12 +82,6 @@
 #define SLOTSTATUS_READY	8
 #define SLOTSTATUS_OCCUPIED	(SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
 
-/*
- * Milliseconds during which a key is regarded as pressed.
- * If an identical command arrives within this time, the timer will start over.
- */
-#define IR_KEYPRESS_TIMEOUT	250
-
 /* RC5 device wildcard */
 #define IR_DEVICE_ANY		255
 
@@ -102,12 +98,9 @@
 struct budget_ci_ir {
 	struct input_dev *dev;
 	struct tasklet_struct msp430_irq_tasklet;
-	struct timer_list timer_keyup;
 	char name[72]; /* 40 + 32 for (struct saa7146_dev).name */
 	char phys[32];
-	struct ir_input_state state;
 	int rc5_device;
-	u32 last_raw;
 	u32 ir_key;
 	bool have_command;
 };
@@ -122,18 +115,11 @@
 	u8 tuner_pll_address; /* used for philips_tdm1316l configs */
 };
 
-static void msp430_ir_keyup(unsigned long data)
-{
-	struct budget_ci_ir *ir = (struct budget_ci_ir *) data;
-	ir_input_nokey(ir->dev, &ir->state);
-}
-
 static void msp430_ir_interrupt(unsigned long data)
 {
 	struct budget_ci *budget_ci = (struct budget_ci *) data;
 	struct input_dev *dev = budget_ci->ir.dev;
 	u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
-	u32 raw;
 
 	/*
 	 * The msp430 chip can generate two different bytes, command and device
@@ -169,20 +155,12 @@
 		return;
 	budget_ci->ir.have_command = false;
 
+	/* FIXME: We should generate complete scancodes with device info */
 	if (budget_ci->ir.rc5_device != IR_DEVICE_ANY &&
 	    budget_ci->ir.rc5_device != (command & 0x1f))
 		return;
 
-	/* Is this a repeated key sequence? (same device, command, toggle) */
-	raw = budget_ci->ir.ir_key | (command << 8);
-	if (budget_ci->ir.last_raw != raw || !timer_pending(&budget_ci->ir.timer_keyup)) {
-		ir_input_nokey(dev, &budget_ci->ir.state);
-		ir_input_keydown(dev, &budget_ci->ir.state,
-				 budget_ci->ir.ir_key);
-		budget_ci->ir.last_raw = raw;
-	}
-
-	mod_timer(&budget_ci->ir.timer_keyup, jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT));
+	ir_keydown(dev, budget_ci->ir.ir_key, (command & 0x20) ? 1 : 0);
 }
 
 static int msp430_ir_init(struct budget_ci *budget_ci)
@@ -190,7 +168,7 @@
 	struct saa7146_dev *saa = budget_ci->budget.dev;
 	struct input_dev *input_dev = budget_ci->ir.dev;
 	int error;
-	struct ir_scancode_table *ir_codes;
+	char *ir_codes = NULL;
 
 
 	budget_ci->ir.dev = input_dev = input_allocate_device();
@@ -230,7 +208,7 @@
 	case 0x1011:
 	case 0x1012:
 		/* The hauppauge keymap is a superset of these remotes */
-		ir_codes = &ir_codes_hauppauge_new_table;
+		ir_codes = RC_MAP_HAUPPAUGE_NEW;
 
 		if (rc5_device < 0)
 			budget_ci->ir.rc5_device = 0x1f;
@@ -239,22 +217,15 @@
 	case 0x1017:
 	case 0x101a:
 		/* for the Technotrend 1500 bundled remote */
-		ir_codes = &ir_codes_tt_1500_table;
+		ir_codes = RC_MAP_TT_1500;
 		break;
 	default:
 		/* unknown remote */
-		ir_codes = &ir_codes_budget_ci_old_table;
+		ir_codes = RC_MAP_BUDGET_CI_OLD;
 		break;
 	}
 
-	ir_input_init(input_dev, &budget_ci->ir.state, IR_TYPE_RC5);
-
-	/* initialise the key-up timeout handler */
-	init_timer(&budget_ci->ir.timer_keyup);
-	budget_ci->ir.timer_keyup.function = msp430_ir_keyup;
-	budget_ci->ir.timer_keyup.data = (unsigned long) &budget_ci->ir;
-	budget_ci->ir.last_raw = 0xffff; /* An impossible value */
-	error = ir_input_register(input_dev, ir_codes, NULL);
+	error = ir_input_register(input_dev, ir_codes, NULL, MODULE_NAME);
 	if (error) {
 		printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
 		return error;
@@ -282,9 +253,6 @@
 	saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
 	tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
 
-	del_timer_sync(&dev->timer);
-	ir_input_nokey(dev, &budget_ci->ir.state);
-
 	ir_input_unregister(dev);
 }
 
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index 1500210..874a10a 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -442,6 +442,7 @@
 	.repeater_level		= STV090x_RPTLEVEL_16,
 
 	.tuner_init		= NULL,
+	.tuner_sleep		= NULL,
 	.tuner_set_mode		= NULL,
 	.tuner_set_frequency	= NULL,
 	.tuner_get_frequency	= NULL,
@@ -627,22 +628,36 @@
 						 &tt1600_stv6110x_config,
 						 &budget->i2c_adap);
 
-				tt1600_stv090x_config.tuner_init	  = ctl->tuner_init;
-				tt1600_stv090x_config.tuner_set_mode	  = ctl->tuner_set_mode;
-				tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;
-				tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;
-				tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;
-				tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;
-				tt1600_stv090x_config.tuner_set_bbgain	  = ctl->tuner_set_bbgain;
-				tt1600_stv090x_config.tuner_get_bbgain	  = ctl->tuner_get_bbgain;
-				tt1600_stv090x_config.tuner_set_refclk	  = ctl->tuner_set_refclk;
-				tt1600_stv090x_config.tuner_get_status	  = ctl->tuner_get_status;
+				if (ctl) {
+					tt1600_stv090x_config.tuner_init	  = ctl->tuner_init;
+					tt1600_stv090x_config.tuner_sleep	  = ctl->tuner_sleep;
+					tt1600_stv090x_config.tuner_set_mode	  = ctl->tuner_set_mode;
+					tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;
+					tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;
+					tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;
+					tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;
+					tt1600_stv090x_config.tuner_set_bbgain	  = ctl->tuner_set_bbgain;
+					tt1600_stv090x_config.tuner_get_bbgain	  = ctl->tuner_get_bbgain;
+					tt1600_stv090x_config.tuner_set_refclk	  = ctl->tuner_set_refclk;
+					tt1600_stv090x_config.tuner_get_status	  = ctl->tuner_get_status;
 
-				dvb_attach(isl6423_attach,
-					budget->dvb_frontend,
-					&budget->i2c_adap,
-					&tt1600_isl6423_config);
+					/* call the init function once to initialize
+					   tuner's clock output divider and demod's
+					   master clock */
+					if (budget->dvb_frontend->ops.init)
+						budget->dvb_frontend->ops.init(budget->dvb_frontend);
 
+					if (dvb_attach(isl6423_attach,
+						       budget->dvb_frontend,
+						       &budget->i2c_adap,
+						       &tt1600_isl6423_config) == NULL) {
+						printk(KERN_ERR "%s: No Intersil ISL6423 found!\n", __func__);
+						goto error_out;
+					}
+				} else {
+					printk(KERN_ERR "%s: No STV6110(A) Silicon Tuner found!\n", __func__);
+					goto error_out;
+				}
 			}
 		}
 		break;
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c
index 02a9cef..353b828 100644
--- a/drivers/media/radio/radio-mr800.c
+++ b/drivers/media/radio/radio-mr800.c
@@ -144,7 +144,10 @@
 	int initialized;
 };
 
-#define vdev_to_amradio(r) container_of(r, struct amradio_device, videodev)
+static inline struct amradio_device *to_amradio_dev(struct v4l2_device *v4l2_dev)
+{
+	return container_of(v4l2_dev, struct amradio_device, v4l2_dev);
+}
 
 /* USB Device ID List */
 static struct usb_device_id usb_amradio_device_table[] = {
@@ -284,13 +287,12 @@
  */
 static void usb_amradio_disconnect(struct usb_interface *intf)
 {
-	struct amradio_device *radio = usb_get_intfdata(intf);
+	struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
 
 	mutex_lock(&radio->lock);
 	radio->usbdev = NULL;
 	mutex_unlock(&radio->lock);
 
-	usb_set_intfdata(intf, NULL);
 	v4l2_device_disconnect(&radio->v4l2_dev);
 	video_unregister_device(&radio->videodev);
 }
@@ -500,7 +502,7 @@
 /* open device - amradio_start() and amradio_setfreq() */
 static int usb_amradio_open(struct file *file)
 {
-	struct amradio_device *radio = vdev_to_amradio(video_devdata(file));
+	struct amradio_device *radio = video_drvdata(file);
 	int retval = 0;
 
 	mutex_lock(&radio->lock);
@@ -566,7 +568,7 @@
 /* Suspend device - stop device. Need to be checked and fixed */
 static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
 {
-	struct amradio_device *radio = usb_get_intfdata(intf);
+	struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
 
 	mutex_lock(&radio->lock);
 
@@ -584,7 +586,7 @@
 /* Resume device - start device. Need to be checked and fixed */
 static int usb_amradio_resume(struct usb_interface *intf)
 {
-	struct amradio_device *radio = usb_get_intfdata(intf);
+	struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
 
 	mutex_lock(&radio->lock);
 
@@ -633,9 +635,7 @@
 
 static void usb_amradio_video_device_release(struct video_device *videodev)
 {
-	struct amradio_device *radio = vdev_to_amradio(videodev);
-
-	v4l2_device_unregister(&radio->v4l2_dev);
+	struct amradio_device *radio = video_get_drvdata(videodev);
 
 	/* free rest memory */
 	kfree(radio->buffer);
@@ -693,7 +693,6 @@
 		goto err_vdev;
 	}
 
-	usb_set_intfdata(intf, radio);
 	return 0;
 
 err_vdev:
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 9644cf76..ad9e6f9 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -45,6 +45,10 @@
 	tristate
 	depends on MEDIA_TUNER
 
+config V4L2_MEM2MEM_DEV
+	tristate
+	depends on VIDEOBUF_GEN
+
 #
 # Multimedia Video device configuration
 #
@@ -480,6 +484,12 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called adv7343.
 
+config VIDEO_AK881X
+	tristate "AK8813/AK8814 video encoders"
+	depends on I2C
+	help
+	  Video output driver for AKM AK8813 and AK8814 TV encoders
+
 comment "Video improvement chips"
 
 config VIDEO_UPD64031A
@@ -520,6 +530,13 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called vpif_display.
 
+config VIDEO_SH_VOU
+	tristate "SuperH VOU video output driver"
+	depends on VIDEO_DEV && ARCH_SHMOBILE
+	select VIDEOBUF_DMA_CONTIG
+	help
+	  Support for the Video Output Unit (VOU) on SuperH SoCs.
+
 config CAPTURE_DAVINCI_DM646X_EVM
 	tristate "DM646x EVM Video Capture"
 	depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM
@@ -542,7 +559,8 @@
 
 config VIDEO_VIVI
 	tristate "Virtual Video Driver"
-	depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
+	depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 && FONTS
+	select FONT_8x16
 	select VIDEOBUF_VMALLOC
 	default n
 	---help---
@@ -613,6 +631,8 @@
 	   To compile this driver as a module, choose M here: the
 	   module will be called vpfe.
 
+source "drivers/media/video/omap/Kconfig"
+
 source "drivers/media/video/bt8xx/Kconfig"
 
 config VIDEO_PMS
@@ -647,7 +667,7 @@
 
 config VIDEO_W9966
 	tristate "W9966CF Webcam (FlyCam Supra and others) Video For Linux"
-	depends on PARPORT_1284 && PARPORT && VIDEO_V4L1
+	depends on PARPORT_1284 && PARPORT && VIDEO_V4L2
 	help
 	  Video4linux driver for Winbond's w9966 based Webcams.
 	  Currently tested with the LifeView FlyCam Supra.
@@ -740,7 +760,7 @@
 
 config VIDEO_MEYE
 	tristate "Sony Vaio Picturebook Motion Eye Video For Linux"
-	depends on PCI && SONY_LAPTOP && VIDEO_V4L1
+	depends on PCI && SONY_LAPTOP && VIDEO_V4L2
 	---help---
 	  This is the video4linux driver for the Motion Eye camera found
 	  in the Vaio Picturebook laptops. Please read the material in
@@ -807,7 +827,7 @@
 
 config VIDEO_M32R_AR
 	tristate "AR devices"
-	depends on M32R && VIDEO_V4L1
+	depends on M32R && VIDEO_V4L2
 	---help---
 	  This is a video4linux driver for the Renesas AR (Artificial Retina)
 	  camera module.
@@ -1107,3 +1127,27 @@
 
 endif # V4L_USB_DRIVERS
 endif # VIDEO_CAPTURE_DRIVERS
+
+menuconfig V4L_MEM2MEM_DRIVERS
+	bool "Memory-to-memory multimedia devices"
+	depends on VIDEO_V4L2
+	default n
+	---help---
+	  Say Y here to enable selecting drivers for V4L devices that
+	  use system memory for both source and destination buffers, as opposed
+	  to capture and output drivers, which use memory buffers for just
+	  one of those.
+
+if V4L_MEM2MEM_DRIVERS
+
+config VIDEO_MEM2MEM_TESTDEV
+	tristate "Virtual test device for mem2mem framework"
+	depends on VIDEO_DEV && VIDEO_V4L2
+	select VIDEOBUF_VMALLOC
+	select V4L2_MEM2MEM_DEV
+	default n
+	---help---
+	  This is a virtual test device for the memory-to-memory driver
+	  framework.
+
+endif # V4L_MEM2MEM_DRIVERS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index c51c386..cc93859 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -10,7 +10,8 @@
 
 omap2cam-objs	:=	omap24xxcam.o omap24xxcam-dma.o
 
-videodev-objs	:=	v4l2-dev.o v4l2-ioctl.o v4l2-device.o
+videodev-objs	:=	v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
+			v4l2-event.o
 
 # V4L2 core modules
 
@@ -117,6 +118,8 @@
 obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
 obj-$(CONFIG_VIDEO_BTCX)  += btcx-risc.o
 
+obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o
+
 obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
 
 obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
@@ -149,8 +152,11 @@
 obj-$(CONFIG_VIDEO_CX18) += cx18/
 
 obj-$(CONFIG_VIDEO_VIVI) += vivi.o
+obj-$(CONFIG_VIDEO_MEM2MEM_TESTDEV) += mem2mem_testdev.o
 obj-$(CONFIG_VIDEO_CX23885) += cx23885/
 
+obj-$(CONFIG_VIDEO_AK881X)		+= ak881x.o
+
 obj-$(CONFIG_VIDEO_OMAP2)		+= omap2cam.o
 obj-$(CONFIG_SOC_CAMERA)		+= soc_camera.o soc_mediabus.o
 obj-$(CONFIG_SOC_CAMERA_PLATFORM)	+= soc_camera_platform.o
@@ -160,6 +166,10 @@
 obj-$(CONFIG_VIDEO_PXA27x)		+= pxa_camera.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)	+= sh_mobile_ceu_camera.o
 
+obj-$(CONFIG_ARCH_DAVINCI)		+= davinci/
+
+obj-$(CONFIG_VIDEO_SH_VOU)		+= sh_vou.o
+
 obj-$(CONFIG_VIDEO_AU0828) += au0828/
 
 obj-$(CONFIG_USB_VIDEO_CLASS)	+= uvc/
@@ -169,6 +179,8 @@
 
 obj-$(CONFIG_ARCH_DAVINCI)	+= davinci/
 
+obj-$(CONFIG_ARCH_OMAP)	+= omap/
+
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
 EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
 EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/video/ak881x.c b/drivers/media/video/ak881x.c
new file mode 100644
index 0000000..35390d4
--- /dev/null
+++ b/drivers/media/video/ak881x.c
@@ -0,0 +1,368 @@
+/*
+ * Driver for AK8813 / AK8814 TV-ecoders from Asahi Kasei Microsystems Co., Ltd. (AKM)
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+
+#include <media/ak881x.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+
+#define AK881X_INTERFACE_MODE	0
+#define AK881X_VIDEO_PROCESS1	1
+#define AK881X_VIDEO_PROCESS2	2
+#define AK881X_VIDEO_PROCESS3	3
+#define AK881X_DAC_MODE		5
+#define AK881X_STATUS		0x24
+#define AK881X_DEVICE_ID	0x25
+#define AK881X_DEVICE_REVISION	0x26
+
+struct ak881x {
+	struct v4l2_subdev subdev;
+	struct ak881x_pdata *pdata;
+	unsigned int lines;
+	int id;	/* DEVICE_ID code V4L2_IDENT_AK881X code from v4l2-chip-ident.h */
+	char revision;	/* DEVICE_REVISION content */
+};
+
+static int reg_read(struct i2c_client *client, const u8 reg)
+{
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int reg_write(struct i2c_client *client, const u8 reg,
+		     const u8 data)
+{
+	return i2c_smbus_write_byte_data(client, reg, data);
+}
+
+static int reg_set(struct i2c_client *client, const u8 reg,
+		   const u8 data, u8 mask)
+{
+	int ret = reg_read(client, reg);
+	if (ret < 0)
+		return ret;
+	return reg_write(client, reg, (ret & ~mask) | (data & mask));
+}
+
+static struct ak881x *to_ak881x(const struct i2c_client *client)
+{
+	return container_of(i2c_get_clientdata(client), struct ak881x, subdev);
+}
+
+static int ak881x_g_chip_ident(struct v4l2_subdev *sd,
+			       struct v4l2_dbg_chip_ident *id)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ak881x *ak881x = to_ak881x(client);
+
+	if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+		return -EINVAL;
+
+	if (id->match.addr != client->addr)
+		return -ENODEV;
+
+	id->ident	= ak881x->id;
+	id->revision	= ak881x->revision;
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ak881x_g_register(struct v4l2_subdev *sd,
+			     struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x26)
+		return -EINVAL;
+
+	if (reg->match.addr != client->addr)
+		return -ENODEV;
+
+	reg->val = reg_read(client, reg->reg);
+
+	if (reg->val > 0xffff)
+		return -EIO;
+
+	return 0;
+}
+
+static int ak881x_s_register(struct v4l2_subdev *sd,
+			     struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x26)
+		return -EINVAL;
+
+	if (reg->match.addr != client->addr)
+		return -ENODEV;
+
+	if (reg_write(client, reg->reg, reg->val) < 0)
+		return -EIO;
+
+	return 0;
+}
+#endif
+
+static int ak881x_try_g_mbus_fmt(struct v4l2_subdev *sd,
+				 struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ak881x *ak881x = to_ak881x(client);
+
+	v4l_bound_align_image(&mf->width, 0, 720, 2,
+			      &mf->height, 0, ak881x->lines, 1, 0);
+	mf->field	= V4L2_FIELD_INTERLACED;
+	mf->code	= V4L2_MBUS_FMT_YUYV8_2X8_LE;
+	mf->colorspace	= V4L2_COLORSPACE_SMPTE170M;
+
+	return 0;
+}
+
+static int ak881x_s_mbus_fmt(struct v4l2_subdev *sd,
+			     struct v4l2_mbus_framefmt *mf)
+{
+	if (mf->field != V4L2_FIELD_INTERLACED ||
+	    mf->code != V4L2_MBUS_FMT_YUYV8_2X8_LE)
+		return -EINVAL;
+
+	return ak881x_try_g_mbus_fmt(sd, mf);
+}
+
+static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, int index,
+				enum v4l2_mbus_pixelcode *code)
+{
+	if (index)
+		return -EINVAL;
+
+	*code = V4L2_MBUS_FMT_YUYV8_2X8_LE;
+	return 0;
+}
+
+static int ak881x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ak881x *ak881x = to_ak881x(client);
+
+	a->bounds.left			= 0;
+	a->bounds.top			= 0;
+	a->bounds.width			= 720;
+	a->bounds.height		= ak881x->lines;
+	a->defrect			= a->bounds;
+	a->type				= V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+static int ak881x_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ak881x *ak881x = to_ak881x(client);
+	u8 vp1;
+
+	if (std == V4L2_STD_NTSC_443) {
+		vp1 = 3;
+		ak881x->lines = 480;
+	} else if (std == V4L2_STD_PAL_M) {
+		vp1 = 5;
+		ak881x->lines = 480;
+	} else if (std == V4L2_STD_PAL_60) {
+		vp1 = 7;
+		ak881x->lines = 480;
+	} else if (std && !(std & ~V4L2_STD_PAL)) {
+		vp1 = 0xf;
+		ak881x->lines = 576;
+	} else if (std && !(std & ~V4L2_STD_NTSC)) {
+		vp1 = 0;
+		ak881x->lines = 480;
+	} else {
+		/* No SECAM or PAL_N/Nc supported */
+		return -EINVAL;
+	}
+
+	reg_set(client, AK881X_VIDEO_PROCESS1, vp1, 0xf);
+
+	return 0;
+}
+
+static int ak881x_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ak881x *ak881x = to_ak881x(client);
+
+	if (enable) {
+		u8 dac;
+		/* For colour-bar testing set bit 6 of AK881X_VIDEO_PROCESS1 */
+		/* Default: composite output */
+		if (ak881x->pdata->flags & AK881X_COMPONENT)
+			dac = 3;
+		else
+			dac = 4;
+		/* Turn on the DAC(s) */
+		reg_write(client, AK881X_DAC_MODE, dac);
+		dev_dbg(&client->dev, "chip status 0x%x\n",
+			reg_read(client, AK881X_STATUS));
+	} else {
+		/* ...and clear bit 6 of AK881X_VIDEO_PROCESS1 here */
+		reg_write(client, AK881X_DAC_MODE, 0);
+		dev_dbg(&client->dev, "chip status 0x%x\n",
+			reg_read(client, AK881X_STATUS));
+	}
+
+	return 0;
+}
+
+static struct v4l2_subdev_core_ops ak881x_subdev_core_ops = {
+	.g_chip_ident	= ak881x_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register	= ak881x_g_register,
+	.s_register	= ak881x_s_register,
+#endif
+};
+
+static struct v4l2_subdev_video_ops ak881x_subdev_video_ops = {
+	.s_mbus_fmt	= ak881x_s_mbus_fmt,
+	.g_mbus_fmt	= ak881x_try_g_mbus_fmt,
+	.try_mbus_fmt	= ak881x_try_g_mbus_fmt,
+	.cropcap	= ak881x_cropcap,
+	.enum_mbus_fmt	= ak881x_enum_mbus_fmt,
+	.s_std_output	= ak881x_s_std_output,
+	.s_stream	= ak881x_s_stream,
+};
+
+static struct v4l2_subdev_ops ak881x_subdev_ops = {
+	.core	= &ak881x_subdev_core_ops,
+	.video	= &ak881x_subdev_video_ops,
+};
+
+static int ak881x_probe(struct i2c_client *client,
+			const struct i2c_device_id *did)
+{
+	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+	struct ak881x *ak881x;
+	u8 ifmode, data;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+		dev_warn(&adapter->dev,
+			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+		return -EIO;
+	}
+
+	ak881x = kzalloc(sizeof(struct ak881x), GFP_KERNEL);
+	if (!ak881x)
+		return -ENOMEM;
+
+	v4l2_i2c_subdev_init(&ak881x->subdev, client, &ak881x_subdev_ops);
+
+	data = reg_read(client, AK881X_DEVICE_ID);
+
+	switch (data) {
+	case 0x13:
+		ak881x->id = V4L2_IDENT_AK8813;
+		break;
+	case 0x14:
+		ak881x->id = V4L2_IDENT_AK8814;
+		break;
+	default:
+		dev_err(&client->dev,
+			"No ak881x chip detected, register read %x\n", data);
+		kfree(ak881x);
+		return -ENODEV;
+	}
+
+	ak881x->revision = reg_read(client, AK881X_DEVICE_REVISION);
+	ak881x->pdata = client->dev.platform_data;
+
+	if (ak881x->pdata) {
+		if (ak881x->pdata->flags & AK881X_FIELD)
+			ifmode = 4;
+		else
+			ifmode = 0;
+
+		switch (ak881x->pdata->flags & AK881X_IF_MODE_MASK) {
+		case AK881X_IF_MODE_BT656:
+			ifmode |= 1;
+			break;
+		case AK881X_IF_MODE_MASTER:
+			ifmode |= 2;
+			break;
+		case AK881X_IF_MODE_SLAVE:
+		default:
+			break;
+		}
+
+		dev_dbg(&client->dev, "IF mode %x\n", ifmode);
+
+		/*
+		 * "Line Blanking No." seems to be the same as the number of
+		 * "black" lines on, e.g., SuperH VOU, whose default value of 20
+		 * "incidentally" matches ak881x' default
+		 */
+		reg_write(client, AK881X_INTERFACE_MODE, ifmode | (20 << 3));
+	}
+
+	/* Hardware default: NTSC-M */
+	ak881x->lines = 480;
+
+	dev_info(&client->dev, "Detected an ak881x chip ID %x, revision %x\n",
+		 data, ak881x->revision);
+
+	return 0;
+}
+
+static int ak881x_remove(struct i2c_client *client)
+{
+	struct ak881x *ak881x = to_ak881x(client);
+
+	v4l2_device_unregister_subdev(&ak881x->subdev);
+	kfree(ak881x);
+
+	return 0;
+}
+
+static const struct i2c_device_id ak881x_id[] = {
+	{ "ak8813", 0 },
+	{ "ak8814", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ak881x_id);
+
+static struct i2c_driver ak881x_i2c_driver = {
+	.driver = {
+		.name = "ak881x",
+	},
+	.probe		= ak881x_probe,
+	.remove		= ak881x_remove,
+	.id_table	= ak881x_id,
+};
+
+static int __init ak881x_module_init(void)
+{
+	return i2c_add_driver(&ak881x_i2c_driver);
+}
+
+static void __exit ak881x_module_exit(void)
+{
+	i2c_del_driver(&ak881x_i2c_driver);
+}
+
+module_init(ak881x_module_init);
+module_exit(ak881x_module_exit);
+
+MODULE_DESCRIPTION("TV-output driver for ak8813/ak8814");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index a356d6b..31e7a12 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -27,8 +27,10 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
-#include <linux/videodev.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <linux/mutex.h>
 
@@ -39,7 +41,7 @@
 #include <asm/byteorder.h>
 
 #if 0
-#define DEBUG(n, args...) printk(args)
+#define DEBUG(n, args...) printk(KERN_INFO args)
 #define CHECK_LOST	1
 #else
 #define DEBUG(n, args...)
@@ -52,10 +54,10 @@
  */
 #define USE_INT		0	/* Don't modify */
 
-#define VERSION	"0.03"
+#define VERSION	"0.04"
 
 #define ar_inl(addr) 		inl((unsigned long)(addr))
-#define ar_outl(val, addr)	outl((unsigned long)(val),(unsigned long)(addr))
+#define ar_outl(val, addr)	outl((unsigned long)(val), (unsigned long)(addr))
 
 extern struct cpuinfo_m32r	boot_cpu_data;
 
@@ -79,7 +81,7 @@
 
 /* bits & bytes per pixel */
 #define AR_BITS_PER_PIXEL	16
-#define AR_BYTES_PER_PIXEL	(AR_BITS_PER_PIXEL/8)
+#define AR_BYTES_PER_PIXEL	(AR_BITS_PER_PIXEL / 8)
 
 /* line buffer size */
 #define AR_LINE_BYTES_VGA	(AR_WIDTH_VGA * AR_BYTES_PER_PIXEL)
@@ -104,8 +106,9 @@
 #define AR_MODE_INTERLACE	0
 #define AR_MODE_NORMAL		1
 
-struct ar_device {
-	struct video_device *vdev;
+struct ar {
+	struct v4l2_device v4l2_dev;
+	struct video_device vdev;
 	unsigned int start_capture;	/* duaring capture in INT. mode. */
 #if USE_INT
 	unsigned char *line_buff;	/* DMA line buffer */
@@ -116,12 +119,13 @@
 	int width, height;
 	int frame_bytes, line_bytes;
 	wait_queue_head_t wait;
-	unsigned long in_use;
 	struct mutex lock;
 };
 
+static struct ar ardev;
+
 static int video_nr = -1;	/* video device number (first free) */
-static unsigned char	yuv[MAX_AR_FRAME_BYTES];
+static unsigned char yuv[MAX_AR_FRAME_BYTES];
 
 /* module parameters */
 /* default frequency */
@@ -133,9 +137,7 @@
 module_param(vga, int, 0);
 module_param(vga_interlace, int, 0);
 
-static int ar_initialize(struct video_device *dev);
-
-static inline void wait_for_vsync(void)
+static void wait_for_vsync(void)
 {
 	while (ar_inl(ARVCR0) & ARVCR0_VDS)	/* wait for VSYNC */
 		cpu_relax();
@@ -143,7 +145,7 @@
 		cpu_relax();
 }
 
-static inline void wait_acknowledge(void)
+static void wait_acknowledge(void)
 {
 	int i;
 
@@ -156,7 +158,7 @@
 /*******************************************************************
  * I2C functions
  *******************************************************************/
-void iic(int n, unsigned long addr, unsigned long data1, unsigned long data2,
+static void iic(int n, unsigned long addr, unsigned long data1, unsigned long data2,
 	 unsigned long data3)
 {
 	int i;
@@ -200,7 +202,7 @@
 }
 
 
-void init_iic(void)
+static void init_iic(void)
 {
 	DEBUG(1, "init_iic:\n");
 
@@ -214,13 +216,12 @@
 
 	/* I2C CLK */
 	/* 50MH-100k */
-	if (freq == 75) {
+	if (freq == 75)
 		ar_outl(369, PLDI2CFREQ);	/* BCLK = 75MHz */
-	} else if (freq == 50) {
+	else if (freq == 50)
 		ar_outl(244, PLDI2CFREQ);	/* BCLK = 50MHz */
-	} else {
+	else
 		ar_outl(244, PLDI2CFREQ);	/* default: BCLK = 50MHz */
-	}
 	ar_outl(0x1, PLDI2CCR); 	/* I2CCR Enable */
 }
 
@@ -245,7 +246,7 @@
 	ar_outl(0x8000, M32R_DMAEDET_PORTL);	/* clear status */
 }
 
-static inline void wait_for_vertical_sync(int exp_line)
+static void wait_for_vertical_sync(struct ar *ar, int exp_line)
 {
 #if CHECK_LOST
 	int tmout = 10000;	/* FIXME */
@@ -260,7 +261,7 @@
 			break;
 	}
 	if (tmout < 0)
-		printk("arv: lost %d -> %d\n", exp_line, l);
+		v4l2_err(&ar->v4l2_dev, "lost %d -> %d\n", exp_line, l);
 #else
 	while (ar_inl(ARVHCOUNT) != exp_line)
 		cpu_relax();
@@ -269,15 +270,14 @@
 
 static ssize_t ar_read(struct file *file, char *buf, size_t count, loff_t *ppos)
 {
-	struct video_device *v = video_devdata(file);
-	struct ar_device *ar = video_get_drvdata(v);
+	struct ar *ar = video_drvdata(file);
 	long ret = ar->frame_bytes;		/* return read bytes */
 	unsigned long arvcr1 = 0;
 	unsigned long flags;
 	unsigned char *p;
 	int h, w;
 	unsigned char *py, *pu, *pv;
-#if ! USE_INT
+#if !USE_INT
 	int l;
 #endif
 
@@ -305,7 +305,7 @@
 	ar_outl(ar->line_bytes, M32R_DMA0RBCUT_PORTL); 	/* reload count (bytes) */
 
 	/*
-	 * Okey , kicks AR LSI to invoke an interrupt
+	 * Okay, kick AR LSI to invoke an interrupt
 	 */
 	ar->start_capture = 0;
 	ar_outl(arvcr1 | ARVCR1_HIEN, ARVCR1);
@@ -313,7 +313,7 @@
 	/* .... AR interrupts .... */
 	interruptible_sleep_on(&ar->wait);
 	if (signal_pending(current)) {
-		printk("arv: interrupted while get frame data.\n");
+		printk(KERN_ERR "arv: interrupted while get frame data.\n");
 		ret = -EINTR;
 		goto out_up;
 	}
@@ -334,7 +334,7 @@
 		cpu_relax();
 	if (ar->mode == AR_MODE_INTERLACE && ar->size == AR_SIZE_VGA) {
 		for (h = 0; h < ar->height; h++) {
-			wait_for_vertical_sync(h);
+			wait_for_vertical_sync(ar, h);
 			if (h < (AR_HEIGHT_VGA/2))
 				l = h << 1;
 			else
@@ -349,7 +349,7 @@
 		}
 	} else {
 		for (h = 0; h < ar->height; h++) {
-			wait_for_vertical_sync(h);
+			wait_for_vertical_sync(ar, h);
 			ar_outl(virt_to_phys(ar->frame[h]), M32R_DMA0CDA_PORTL);
 			enable_dma();
 			while (!(ar_inl(M32R_DMAEDET_PORTL) & 0x8000))
@@ -386,7 +386,7 @@
 		}
 	}
 	if (copy_to_user(buf, yuv, ar->frame_bytes)) {
-		printk("arv: failed while copy_to_user yuv.\n");
+		v4l2_err(&ar->v4l2_dev, "failed while copy_to_user yuv.\n");
 		ret = -EFAULT;
 		goto out_up;
 	}
@@ -396,153 +396,127 @@
 	return ret;
 }
 
-static long ar_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static int ar_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *vcap)
 {
-	struct video_device *dev = video_devdata(file);
-	struct ar_device *ar = video_get_drvdata(dev);
+	struct ar *ar = video_drvdata(file);
 
-	DEBUG(1, "ar_ioctl()\n");
-	switch(cmd) {
-	case VIDIOCGCAP:
-	{
-		struct video_capability *b = arg;
-		DEBUG(1, "VIDIOCGCAP:\n");
-		strcpy(b->name, ar->vdev->name);
-		b->type = VID_TYPE_CAPTURE;
-		b->channels = 0;
-		b->audios = 0;
-		b->maxwidth = MAX_AR_WIDTH;
-		b->maxheight = MAX_AR_HEIGHT;
-		b->minwidth = MIN_AR_WIDTH;
-		b->minheight = MIN_AR_HEIGHT;
-		return 0;
-	}
-	case VIDIOCGCHAN:
-		DEBUG(1, "VIDIOCGCHAN:\n");
-		return 0;
-	case VIDIOCSCHAN:
-		DEBUG(1, "VIDIOCSCHAN:\n");
-		return 0;
-	case VIDIOCGTUNER:
-		DEBUG(1, "VIDIOCGTUNER:\n");
-		return 0;
-	case VIDIOCSTUNER:
-		DEBUG(1, "VIDIOCSTUNER:\n");
-		return 0;
-	case VIDIOCGPICT:
-		DEBUG(1, "VIDIOCGPICT:\n");
-		return 0;
-	case VIDIOCSPICT:
-		DEBUG(1, "VIDIOCSPICT:\n");
-		return 0;
-	case VIDIOCCAPTURE:
-		DEBUG(1, "VIDIOCCAPTURE:\n");
-		return -EINVAL;
-	case VIDIOCGWIN:
-	{
-		struct video_window *w = arg;
-		DEBUG(1, "VIDIOCGWIN:\n");
-		memset(w, 0, sizeof(*w));
-		w->width = ar->width;
-		w->height = ar->height;
-		return 0;
-	}
-	case VIDIOCSWIN:
-	{
-		struct video_window *w = arg;
-		DEBUG(1, "VIDIOCSWIN:\n");
-		if ((w->width != AR_WIDTH_VGA || w->height != AR_HEIGHT_VGA) &&
-		    (w->width != AR_WIDTH_QVGA || w->height != AR_HEIGHT_QVGA))
-				return -EINVAL;
-
-		mutex_lock(&ar->lock);
-		ar->width = w->width;
-		ar->height = w->height;
-		if (ar->width == AR_WIDTH_VGA) {
-			ar->size = AR_SIZE_VGA;
-			ar->frame_bytes = AR_FRAME_BYTES_VGA;
-			ar->line_bytes = AR_LINE_BYTES_VGA;
-			if (vga_interlace)
-				ar->mode = AR_MODE_INTERLACE;
-			else
-				ar->mode = AR_MODE_NORMAL;
-		} else {
-			ar->size = AR_SIZE_QVGA;
-			ar->frame_bytes = AR_FRAME_BYTES_QVGA;
-			ar->line_bytes = AR_LINE_BYTES_QVGA;
-			ar->mode = AR_MODE_INTERLACE;
-		}
-		mutex_unlock(&ar->lock);
-		return 0;
-	}
-	case VIDIOCGFBUF:
-		DEBUG(1, "VIDIOCGFBUF:\n");
-		return -EINVAL;
-	case VIDIOCSFBUF:
-		DEBUG(1, "VIDIOCSFBUF:\n");
-		return -EINVAL;
-	case VIDIOCKEY:
-		DEBUG(1, "VIDIOCKEY:\n");
-		return 0;
-	case VIDIOCGFREQ:
-		DEBUG(1, "VIDIOCGFREQ:\n");
-		return -EINVAL;
-	case VIDIOCSFREQ:
-		DEBUG(1, "VIDIOCSFREQ:\n");
-		return -EINVAL;
-	case VIDIOCGAUDIO:
-		DEBUG(1, "VIDIOCGAUDIO:\n");
-		return -EINVAL;
-	case VIDIOCSAUDIO:
-		DEBUG(1, "VIDIOCSAUDIO:\n");
-		return -EINVAL;
-	case VIDIOCSYNC:
-		DEBUG(1, "VIDIOCSYNC:\n");
-		return -EINVAL;
-	case VIDIOCMCAPTURE:
-		DEBUG(1, "VIDIOCMCAPTURE:\n");
-		return -EINVAL;
-	case VIDIOCGMBUF:
-		DEBUG(1, "VIDIOCGMBUF:\n");
-		return -EINVAL;
-	case VIDIOCGUNIT:
-		DEBUG(1, "VIDIOCGUNIT:\n");
-		return -EINVAL;
-	case VIDIOCGCAPTURE:
-		DEBUG(1, "VIDIOCGCAPTURE:\n");
-		return -EINVAL;
-	case VIDIOCSCAPTURE:
-		DEBUG(1, "VIDIOCSCAPTURE:\n");
-		return -EINVAL;
-	case VIDIOCSPLAYMODE:
-		DEBUG(1, "VIDIOCSPLAYMODE:\n");
-		return -EINVAL;
-	case VIDIOCSWRITEMODE:
-		DEBUG(1, "VIDIOCSWRITEMODE:\n");
-		return -EINVAL;
-	case VIDIOCGPLAYINFO:
-		DEBUG(1, "VIDIOCGPLAYINFO:\n");
-		return -EINVAL;
-	case VIDIOCSMICROCODE:
-		DEBUG(1, "VIDIOCSMICROCODE:\n");
-		return -EINVAL;
-	case VIDIOCGVBIFMT:
-		DEBUG(1, "VIDIOCGVBIFMT:\n");
-		return -EINVAL;
-	case VIDIOCSVBIFMT:
-		DEBUG(1, "VIDIOCSVBIFMT:\n");
-		return -EINVAL;
-	default:
-		DEBUG(1, "Unknown ioctl(0x%08x)\n", cmd);
-		return -ENOIOCTLCMD;
-	}
+	strlcpy(vcap->driver, ar->vdev.name, sizeof(vcap->driver));
+	strlcpy(vcap->card, "Colour AR VGA", sizeof(vcap->card));
+	strlcpy(vcap->bus_info, "Platform", sizeof(vcap->bus_info));
+	vcap->version = KERNEL_VERSION(0, 0, 4);
+	vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
 	return 0;
 }
 
-static long ar_ioctl(struct file *file, unsigned int cmd,
-		    unsigned long arg)
+static int ar_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
 {
-	return video_usercopy(file, cmd, arg, ar_do_ioctl);
+	if (vin->index > 0)
+		return -EINVAL;
+	strlcpy(vin->name, "Camera", sizeof(vin->name));
+	vin->type = V4L2_INPUT_TYPE_CAMERA;
+	vin->audioset = 0;
+	vin->tuner = 0;
+	vin->std = V4L2_STD_ALL;
+	vin->status = 0;
+	return 0;
+}
+
+static int ar_g_input(struct file *file, void *fh, unsigned int *inp)
+{
+	*inp = 0;
+	return 0;
+}
+
+static int ar_s_input(struct file *file, void *fh, unsigned int inp)
+{
+	return inp ? -EINVAL : 0;
+}
+
+static int ar_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ar *ar = video_drvdata(file);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+	pix->width = ar->width;
+	pix->height = ar->height;
+	pix->pixelformat = V4L2_PIX_FMT_YUV422P;
+	pix->field = (ar->mode == AR_MODE_NORMAL) ? V4L2_FIELD_NONE : V4L2_FIELD_INTERLACED;
+	pix->bytesperline = ar->width;
+	pix->sizeimage = 2 * ar->width * ar->height;
+	/* Just a guess */
+	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	return 0;
+}
+
+static int ar_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ar *ar = video_drvdata(file);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+	if (pix->height <= AR_HEIGHT_QVGA || pix->width <= AR_WIDTH_QVGA) {
+		pix->height = AR_HEIGHT_QVGA;
+		pix->width = AR_WIDTH_QVGA;
+		pix->field = V4L2_FIELD_INTERLACED;
+	} else {
+		pix->height = AR_HEIGHT_VGA;
+		pix->width = AR_WIDTH_VGA;
+		pix->field = vga_interlace ? V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE;
+	}
+	pix->pixelformat = V4L2_PIX_FMT_YUV422P;
+	pix->bytesperline = ar->width;
+	pix->sizeimage = 2 * ar->width * ar->height;
+	/* Just a guess */
+	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	return 0;
+}
+
+static int ar_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ar *ar = video_drvdata(file);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+	int ret = ar_try_fmt_vid_cap(file, fh, fmt);
+
+	if (ret)
+		return ret;
+	mutex_lock(&ar->lock);
+	ar->width = pix->width;
+	ar->height = pix->height;
+	if (ar->width == AR_WIDTH_VGA) {
+		ar->size = AR_SIZE_VGA;
+		ar->frame_bytes = AR_FRAME_BYTES_VGA;
+		ar->line_bytes = AR_LINE_BYTES_VGA;
+		if (vga_interlace)
+			ar->mode = AR_MODE_INTERLACE;
+		else
+			ar->mode = AR_MODE_NORMAL;
+	} else {
+		ar->size = AR_SIZE_QVGA;
+		ar->frame_bytes = AR_FRAME_BYTES_QVGA;
+		ar->line_bytes = AR_LINE_BYTES_QVGA;
+		ar->mode = AR_MODE_INTERLACE;
+	}
+	/* Ok we figured out what to use from our wide choice */
+	mutex_unlock(&ar->lock);
+	return 0;
+}
+
+static int ar_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
+{
+	static struct v4l2_fmtdesc formats[] = {
+		{ 0, 0, 0,
+		  "YUV 4:2:2 Planar", V4L2_PIX_FMT_YUV422P,
+		  { 0, 0, 0, 0 }
+		},
+	};
+	enum v4l2_buf_type type = fmt->type;
+
+	if (fmt->index > 0)
+		return -EINVAL;
+
+	*fmt = formats[fmt->index];
+	fmt->type = type;
+	return 0;
 }
 
 #if USE_INT
@@ -551,7 +525,7 @@
  */
 static void ar_interrupt(int irq, void *dev)
 {
-	struct ar_device *ar = dev;
+	struct ar *ar = dev;
 	unsigned int line_count;
 	unsigned int line_number;
 	unsigned int arvcr1;
@@ -559,11 +533,11 @@
 	line_count = ar_inl(ARVHCOUNT);			/* line number */
 	if (ar->mode == AR_MODE_INTERLACE && ar->size == AR_SIZE_VGA) {
 		/* operations for interlace mode */
-		if ( line_count < (AR_HEIGHT_VGA/2) ) 	/* even line */
+		if (line_count < (AR_HEIGHT_VGA / 2)) 	/* even line */
 			line_number = (line_count << 1);
 		else 					/* odd line */
 			line_number =
-			(((line_count - (AR_HEIGHT_VGA/2)) << 1) + 1);
+			(((line_count - (AR_HEIGHT_VGA / 2)) << 1) + 1);
 	} else {
 		line_number = line_count;
 	}
@@ -623,11 +597,10 @@
  *	0 is returned in success.
  *
  */
-static int ar_initialize(struct video_device *dev)
+static int ar_initialize(struct ar *ar)
 {
-	struct ar_device *ar = video_get_drvdata(dev);
 	unsigned long cr = 0;
-	int i,found=0;
+	int i, found = 0;
 
 	DEBUG(1, "ar_initialize:\n");
 
@@ -666,129 +639,119 @@
 	if (found == 0)
 		return -ENODEV;
 
-	printk("arv: Initializing ");
+	v4l2_info(&ar->v4l2_dev, "Initializing ");
 
-	iic(2,0x78,0x11,0x01,0x00);	/* start */
-	iic(3,0x78,0x12,0x00,0x06);
-	iic(3,0x78,0x12,0x12,0x30);
-	iic(3,0x78,0x12,0x15,0x58);
-	iic(3,0x78,0x12,0x17,0x30);
-	printk(".");
-	iic(3,0x78,0x12,0x1a,0x97);
-	iic(3,0x78,0x12,0x1b,0xff);
-	iic(3,0x78,0x12,0x1c,0xff);
-	iic(3,0x78,0x12,0x26,0x10);
-	iic(3,0x78,0x12,0x27,0x00);
-	printk(".");
-	iic(2,0x78,0x34,0x02,0x00);
-	iic(2,0x78,0x7a,0x10,0x00);
-	iic(2,0x78,0x80,0x39,0x00);
-	iic(2,0x78,0x81,0xe6,0x00);
-	iic(2,0x78,0x8d,0x00,0x00);
-	printk(".");
-	iic(2,0x78,0x8e,0x0c,0x00);
-	iic(2,0x78,0x8f,0x00,0x00);
+	iic(2, 0x78, 0x11, 0x01, 0x00);	/* start */
+	iic(3, 0x78, 0x12, 0x00, 0x06);
+	iic(3, 0x78, 0x12, 0x12, 0x30);
+	iic(3, 0x78, 0x12, 0x15, 0x58);
+	iic(3, 0x78, 0x12, 0x17, 0x30);
+	printk(KERN_CONT ".");
+	iic(3, 0x78, 0x12, 0x1a, 0x97);
+	iic(3, 0x78, 0x12, 0x1b, 0xff);
+	iic(3, 0x78, 0x12, 0x1c, 0xff);
+	iic(3, 0x78, 0x12, 0x26, 0x10);
+	iic(3, 0x78, 0x12, 0x27, 0x00);
+	printk(KERN_CONT ".");
+	iic(2, 0x78, 0x34, 0x02, 0x00);
+	iic(2, 0x78, 0x7a, 0x10, 0x00);
+	iic(2, 0x78, 0x80, 0x39, 0x00);
+	iic(2, 0x78, 0x81, 0xe6, 0x00);
+	iic(2, 0x78, 0x8d, 0x00, 0x00);
+	printk(KERN_CONT ".");
+	iic(2, 0x78, 0x8e, 0x0c, 0x00);
+	iic(2, 0x78, 0x8f, 0x00, 0x00);
 #if 0
-	iic(2,0x78,0x90,0x00,0x00);	/* AWB on=1 off=0 */
+	iic(2, 0x78, 0x90, 0x00, 0x00);	/* AWB on=1 off=0 */
 #endif
-	iic(2,0x78,0x93,0x01,0x00);
-	iic(2,0x78,0x94,0xcd,0x00);
-	iic(2,0x78,0x95,0x00,0x00);
-	printk(".");
-	iic(2,0x78,0x96,0xa0,0x00);
-	iic(2,0x78,0x97,0x00,0x00);
-	iic(2,0x78,0x98,0x60,0x00);
-	iic(2,0x78,0x99,0x01,0x00);
-	iic(2,0x78,0x9a,0x19,0x00);
-	printk(".");
-	iic(2,0x78,0x9b,0x02,0x00);
-	iic(2,0x78,0x9c,0xe8,0x00);
-	iic(2,0x78,0x9d,0x02,0x00);
-	iic(2,0x78,0x9e,0x2e,0x00);
-	iic(2,0x78,0xb8,0x78,0x00);
-	iic(2,0x78,0xba,0x05,0x00);
+	iic(2, 0x78, 0x93, 0x01, 0x00);
+	iic(2, 0x78, 0x94, 0xcd, 0x00);
+	iic(2, 0x78, 0x95, 0x00, 0x00);
+	printk(KERN_CONT ".");
+	iic(2, 0x78, 0x96, 0xa0, 0x00);
+	iic(2, 0x78, 0x97, 0x00, 0x00);
+	iic(2, 0x78, 0x98, 0x60, 0x00);
+	iic(2, 0x78, 0x99, 0x01, 0x00);
+	iic(2, 0x78, 0x9a, 0x19, 0x00);
+	printk(KERN_CONT ".");
+	iic(2, 0x78, 0x9b, 0x02, 0x00);
+	iic(2, 0x78, 0x9c, 0xe8, 0x00);
+	iic(2, 0x78, 0x9d, 0x02, 0x00);
+	iic(2, 0x78, 0x9e, 0x2e, 0x00);
+	iic(2, 0x78, 0xb8, 0x78, 0x00);
+	iic(2, 0x78, 0xba, 0x05, 0x00);
 #if 0
-	iic(2,0x78,0x83,0x8c,0x00);	/* brightness */
+	iic(2, 0x78, 0x83, 0x8c, 0x00);	/* brightness */
 #endif
-	printk(".");
+	printk(KERN_CONT ".");
 
 	/* color correction */
-	iic(3,0x78,0x49,0x00,0x95);	/* a		*/
-	iic(3,0x78,0x49,0x01,0x96);	/* b		*/
-	iic(3,0x78,0x49,0x03,0x85);	/* c		*/
-	iic(3,0x78,0x49,0x04,0x97);	/* d		*/
-	iic(3,0x78,0x49,0x02,0x7e);	/* e(Lo)	*/
-	iic(3,0x78,0x49,0x05,0xa4);	/* f(Lo)	*/
-	iic(3,0x78,0x49,0x06,0x04);	/* e(Hi)	*/
-	iic(3,0x78,0x49,0x07,0x04);	/* e(Hi)	*/
-	iic(2,0x78,0x48,0x01,0x00);	/* on=1 off=0	*/
+	iic(3, 0x78, 0x49, 0x00, 0x95);	/* a		*/
+	iic(3, 0x78, 0x49, 0x01, 0x96);	/* b		*/
+	iic(3, 0x78, 0x49, 0x03, 0x85);	/* c		*/
+	iic(3, 0x78, 0x49, 0x04, 0x97);	/* d		*/
+	iic(3, 0x78, 0x49, 0x02, 0x7e);	/* e(Lo)	*/
+	iic(3, 0x78, 0x49, 0x05, 0xa4);	/* f(Lo)	*/
+	iic(3, 0x78, 0x49, 0x06, 0x04);	/* e(Hi)	*/
+	iic(3, 0x78, 0x49, 0x07, 0x04);	/* e(Hi)	*/
+	iic(2, 0x78, 0x48, 0x01, 0x00);	/* on=1 off=0	*/
 
-	printk(".");
-	iic(2,0x78,0x11,0x00,0x00);	/* end */
-	printk(" done\n");
+	printk(KERN_CONT ".");
+	iic(2, 0x78, 0x11, 0x00, 0x00);	/* end */
+	printk(KERN_CONT " done\n");
 	return 0;
 }
 
 
-void ar_release(struct video_device *vfd)
-{
-	struct ar_device *ar = video_get_drvdata(vfd);
-	mutex_lock(&ar->lock);
-	video_device_release(vfd);
-}
-
 /****************************************************************************
  *
  * Video4Linux Module functions
  *
  ****************************************************************************/
-static struct ar_device ardev;
-
-static int ar_exclusive_open(struct file *file)
-{
-	return test_and_set_bit(0, &ardev.in_use) ? -EBUSY : 0;
-}
-
-static int ar_exclusive_release(struct file *file)
-{
-	clear_bit(0, &ardev.in_use);
-	return 0;
-}
 
 static const struct v4l2_file_operations ar_fops = {
 	.owner		= THIS_MODULE,
-	.open		= ar_exclusive_open,
-	.release	= ar_exclusive_release,
 	.read		= ar_read,
-	.ioctl		= ar_ioctl,
+	.ioctl		= video_ioctl2,
 };
 
-static struct video_device ar_template = {
-	.name		= "Colour AR VGA",
-	.fops		= &ar_fops,
-	.release	= ar_release,
+static const struct v4l2_ioctl_ops ar_ioctl_ops = {
+	.vidioc_querycap    		    = ar_querycap,
+	.vidioc_g_input      		    = ar_g_input,
+	.vidioc_s_input      		    = ar_s_input,
+	.vidioc_enum_input   		    = ar_enum_input,
+	.vidioc_enum_fmt_vid_cap 	    = ar_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap 		    = ar_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap  		    = ar_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap  	    = ar_try_fmt_vid_cap,
 };
 
 #define ALIGN4(x)	((((int)(x)) & 0x3) == 0)
 
 static int __init ar_init(void)
 {
-	struct ar_device *ar;
+	struct ar *ar;
+	struct v4l2_device *v4l2_dev;
 	int ret;
 	int i;
 
-	DEBUG(1, "ar_init:\n");
-	ret = -EIO;
-	printk(KERN_INFO "arv: Colour AR VGA driver %s\n", VERSION);
-
 	ar = &ardev;
-	memset(ar, 0, sizeof(struct ar_device));
+	v4l2_dev = &ar->v4l2_dev;
+	strlcpy(v4l2_dev->name, "arv", sizeof(v4l2_dev->name));
+	v4l2_info(v4l2_dev, "Colour AR VGA driver %s\n", VERSION);
+
+	ret = v4l2_device_register(NULL, v4l2_dev);
+	if (ret < 0) {
+		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+		return ret;
+	}
+	ret = -EIO;
 
 #if USE_INT
 	/* allocate a DMA buffer for 1 line.  */
 	ar->line_buff = kmalloc(MAX_AR_LINE_BYTES, GFP_KERNEL | GFP_DMA);
-	if (ar->line_buff == NULL || ! ALIGN4(ar->line_buff)) {
-		printk("arv: buffer allocation failed for DMA.\n");
+	if (ar->line_buff == NULL || !ALIGN4(ar->line_buff)) {
+		v4l2_err(v4l2_dev, "buffer allocation failed for DMA.\n");
 		ret = -ENOMEM;
 		goto out_end;
 	}
@@ -796,20 +759,19 @@
 	/* allocate buffers for a frame */
 	for (i = 0; i < MAX_AR_HEIGHT; i++) {
 		ar->frame[i] = kmalloc(MAX_AR_LINE_BYTES, GFP_KERNEL);
-		if (ar->frame[i] == NULL || ! ALIGN4(ar->frame[i])) {
-			printk("arv: buffer allocation failed for frame.\n");
+		if (ar->frame[i] == NULL || !ALIGN4(ar->frame[i])) {
+			v4l2_err(v4l2_dev, "buffer allocation failed for frame.\n");
 			ret = -ENOMEM;
 			goto out_line_buff;
 		}
 	}
 
-	ar->vdev = video_device_alloc();
-	if (!ar->vdev) {
-		printk(KERN_ERR "arv: video_device_alloc() failed\n");
-		return -ENOMEM;
-	}
-	memcpy(ar->vdev, &ar_template, sizeof(ar_template));
-	video_set_drvdata(ar->vdev, ar);
+	strlcpy(ar->vdev.name, "Colour AR VGA", sizeof(ar->vdev.name));
+	ar->vdev.v4l2_dev = v4l2_dev;
+	ar->vdev.fops = &ar_fops;
+	ar->vdev.ioctl_ops = &ar_ioctl_ops;
+	ar->vdev.release = video_device_release_empty;
+	video_set_drvdata(&ar->vdev, ar);
 
 	if (vga) {
 		ar->width 	= AR_WIDTH_VGA;
@@ -834,14 +796,14 @@
 
 #if USE_INT
 	if (request_irq(M32R_IRQ_INT3, ar_interrupt, 0, "arv", ar)) {
-		printk("arv: request_irq(%d) failed.\n", M32R_IRQ_INT3);
+		v4l2_err("request_irq(%d) failed.\n", M32R_IRQ_INT3);
 		ret = -EIO;
 		goto out_irq;
 	}
 #endif
 
-	if (ar_initialize(ar->vdev) != 0) {
-		printk("arv: M64278 not found.\n");
+	if (ar_initialize(ar) != 0) {
+		v4l2_err(v4l2_dev, "M64278 not found.\n");
 		ret = -ENODEV;
 		goto out_dev;
 	}
@@ -852,15 +814,15 @@
 	 * device is named "video[0-64]".
 	 * video_register_device() initializes h/w using ar_initialize().
 	 */
-	if (video_register_device(ar->vdev, VFL_TYPE_GRABBER, video_nr) != 0) {
+	if (video_register_device(&ar->vdev, VFL_TYPE_GRABBER, video_nr) != 0) {
 		/* return -1, -ENFILE(full) or others */
-		printk("arv: register video (Colour AR) failed.\n");
+		v4l2_err(v4l2_dev, "register video (Colour AR) failed.\n");
 		ret = -ENODEV;
 		goto out_dev;
 	}
 
-	printk("%s: Found M64278 VGA (IRQ %d, Freq %dMHz).\n",
-		video_device_node_name(ar->vdev), M32R_IRQ_INT3, freq);
+	v4l2_info(v4l2_dev, "%s: Found M64278 VGA (IRQ %d, Freq %dMHz).\n",
+		video_device_node_name(&ar->vdev), M32R_IRQ_INT3, freq);
 
 	return 0;
 
@@ -879,6 +841,7 @@
 
 out_end:
 #endif
+	v4l2_device_unregister(&ar->v4l2_dev);
 	return ret;
 }
 
@@ -886,7 +849,7 @@
 static int __init ar_init_module(void)
 {
 	freq = (boot_cpu_data.bus_clock / 1000000);
-	printk("arv: Bus clock %d\n", freq);
+	printk(KERN_INFO "arv: Bus clock %d\n", freq);
 	if (freq != 50 && freq != 75)
 		freq = DEFAULT_FREQ;
 	return ar_init();
@@ -894,11 +857,11 @@
 
 static void __exit ar_cleanup_module(void)
 {
-	struct ar_device *ar;
+	struct ar *ar;
 	int i;
 
 	ar = &ardev;
-	video_unregister_device(ar->vdev);
+	video_unregister_device(&ar->vdev);
 #if USE_INT
 	free_irq(M32R_IRQ_INT3, ar);
 #endif
@@ -907,6 +870,7 @@
 #if USE_INT
 	kfree(ar->line_buff);
 #endif
+	v4l2_device_unregister(&ar->v4l2_dev);
 }
 
 module_init(ar_init_module);
diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c
index 8c140c0..6615021 100644
--- a/drivers/media/video/au0828/au0828-video.c
+++ b/drivers/media/video/au0828/au0828-video.c
@@ -1105,7 +1105,7 @@
 
 	tmp = input->index;
 
-	if (tmp > AU0828_MAX_INPUT)
+	if (tmp >= AU0828_MAX_INPUT)
 		return -EINVAL;
 	if (AUVI_INPUT(tmp).type == 0)
 		return -EINVAL;
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 716870a..7af56cd 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -241,6 +241,10 @@
 	{ 0xa1550101, BTTV_BOARD_IVC200,        "IVC-200G" },
 	{ 0xa1550102, BTTV_BOARD_IVC200,        "IVC-200G" },
 	{ 0xa1550103, BTTV_BOARD_IVC200,        "IVC-200G" },
+	{ 0xa1550800, BTTV_BOARD_IVC200,        "IVC-200"  },
+	{ 0xa1550801, BTTV_BOARD_IVC200,        "IVC-200"  },
+	{ 0xa1550802, BTTV_BOARD_IVC200,        "IVC-200"  },
+	{ 0xa1550803, BTTV_BOARD_IVC200,        "IVC-200"  },
 	{ 0xa182ff00, BTTV_BOARD_IVC120,        "IVC-120G" },
 	{ 0xa182ff01, BTTV_BOARD_IVC120,        "IVC-120G" },
 	{ 0xa182ff02, BTTV_BOARD_IVC120,        "IVC-120G" },
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index f4860f0..38c7f78 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -1525,7 +1525,7 @@
 	struct bttv_fh *fh = f;
 	struct bttv *btv = fh->btv;
 
-	err = v4l2_prio_check(&btv->prio, &fh->prio);
+	err = v4l2_prio_check(&btv->prio, fh->prio);
 	if (0 != err)
 		return err;
 
@@ -1806,8 +1806,8 @@
 	*size = fh->fmt->depth*fh->width*fh->height >> 3;
 	if (0 == *count)
 		*count = gbuffers;
-	while (*size * *count > gbuffers * gbufsize)
-		(*count)--;
+	if (*size * *count > gbuffers * gbufsize)
+		*count = (gbuffers * gbufsize) / *size;
 	return 0;
 }
 
@@ -1859,7 +1859,7 @@
 	unsigned int i;
 	int err;
 
-	err = v4l2_prio_check(&btv->prio, &fh->prio);
+	err = v4l2_prio_check(&btv->prio, fh->prio);
 	if (0 != err)
 		return err;
 
@@ -1941,7 +1941,7 @@
 
 	int err;
 
-	err = v4l2_prio_check(&btv->prio, &fh->prio);
+	err = v4l2_prio_check(&btv->prio, fh->prio);
 	if (0 != err)
 		return err;
 
@@ -1961,7 +1961,7 @@
 	struct bttv *btv = fh->btv;
 	int err;
 
-	err = v4l2_prio_check(&btv->prio, &fh->prio);
+	err = v4l2_prio_check(&btv->prio, fh->prio);
 	if (0 != err)
 		return err;
 
@@ -1987,11 +1987,6 @@
 {
 	struct bttv_fh *fh  = priv;
 	struct bttv *btv = fh->btv;
-	int err;
-
-	err = v4l2_prio_check(&btv->prio, &fh->prio);
-	if (0 != err)
-		return err;
 
 	f->type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
 	f->frequency = btv->freq;
@@ -2006,7 +2001,7 @@
 	struct bttv *btv = fh->btv;
 	int err;
 
-	err = v4l2_prio_check(&btv->prio, &fh->prio);
+	err = v4l2_prio_check(&btv->prio, fh->prio);
 	if (0 != err)
 		return err;
 
@@ -3029,7 +3024,7 @@
 	    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
 		return -EINVAL;
 
-	retval = v4l2_prio_check(&btv->prio, &fh->prio);
+	retval = v4l2_prio_check(&btv->prio, fh->prio);
 	if (0 != retval)
 		return retval;
 
@@ -3241,7 +3236,7 @@
 	*fh = btv->init;
 	fh->type = type;
 	fh->ov.setup_ok = 0;
-	v4l2_prio_open(&btv->prio,&fh->prio);
+	v4l2_prio_open(&btv->prio, &fh->prio);
 
 	videobuf_queue_sg_init(&fh->cap, &bttv_video_qops,
 			    &btv->c.pci->dev, &btv->s_lock,
@@ -3312,7 +3307,7 @@
 	/* free stuff */
 	videobuf_mmap_free(&fh->cap);
 	videobuf_mmap_free(&fh->vbi);
-	v4l2_prio_close(&btv->prio,&fh->prio);
+	v4l2_prio_close(&btv->prio, fh->prio);
 	file->private_data = NULL;
 	kfree(fh);
 
@@ -3449,7 +3444,7 @@
 	struct bttv *btv = fh->btv;
 	struct rds_command cmd;
 
-	v4l2_prio_close(&btv->prio,&fh->prio);
+	v4l2_prio_close(&btv->prio, fh->prio);
 	file->private_data = NULL;
 	kfree(fh);
 
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index aa153a9..f68717a 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -49,6 +49,8 @@
 
 #define DEVNAME "bttv-input"
 
+#define MODULE_NAME "bttv"
+
 /* ---------------------------------------------------------------------- */
 
 static void ir_handle_key(struct bttv *btv)
@@ -246,7 +248,7 @@
 int bttv_input_init(struct bttv *btv)
 {
 	struct card_ir *ir;
-	struct ir_scancode_table *ir_codes = NULL;
+	char *ir_codes = NULL;
 	struct input_dev *input_dev;
 	u64 ir_type = IR_TYPE_OTHER;
 	int err = -ENOMEM;
@@ -264,7 +266,7 @@
 	case BTTV_BOARD_AVERMEDIA:
 	case BTTV_BOARD_AVPHONE98:
 	case BTTV_BOARD_AVERMEDIA98:
-		ir_codes         = &ir_codes_avermedia_table;
+		ir_codes         = RC_MAP_AVERMEDIA;
 		ir->mask_keycode = 0xf88000;
 		ir->mask_keydown = 0x010000;
 		ir->polling      = 50; // ms
@@ -272,14 +274,14 @@
 
 	case BTTV_BOARD_AVDVBT_761:
 	case BTTV_BOARD_AVDVBT_771:
-		ir_codes         = &ir_codes_avermedia_dvbt_table;
+		ir_codes         = RC_MAP_AVERMEDIA_DVBT;
 		ir->mask_keycode = 0x0f00c0;
 		ir->mask_keydown = 0x000020;
 		ir->polling      = 50; // ms
 		break;
 
 	case BTTV_BOARD_PXELVWPLTVPAK:
-		ir_codes         = &ir_codes_pixelview_table;
+		ir_codes         = RC_MAP_PIXELVIEW;
 		ir->mask_keycode = 0x003e00;
 		ir->mask_keyup   = 0x010000;
 		ir->polling      = 50; // ms
@@ -287,24 +289,24 @@
 	case BTTV_BOARD_PV_M4900:
 	case BTTV_BOARD_PV_BT878P_9B:
 	case BTTV_BOARD_PV_BT878P_PLUS:
-		ir_codes         = &ir_codes_pixelview_table;
+		ir_codes         = RC_MAP_PIXELVIEW;
 		ir->mask_keycode = 0x001f00;
 		ir->mask_keyup   = 0x008000;
 		ir->polling      = 50; // ms
 		break;
 
 	case BTTV_BOARD_WINFAST2000:
-		ir_codes         = &ir_codes_winfast_table;
+		ir_codes         = RC_MAP_WINFAST;
 		ir->mask_keycode = 0x1f8;
 		break;
 	case BTTV_BOARD_MAGICTVIEW061:
 	case BTTV_BOARD_MAGICTVIEW063:
-		ir_codes         = &ir_codes_winfast_table;
+		ir_codes         = RC_MAP_WINFAST;
 		ir->mask_keycode = 0x0008e000;
 		ir->mask_keydown = 0x00200000;
 		break;
 	case BTTV_BOARD_APAC_VIEWCOMP:
-		ir_codes         = &ir_codes_apac_viewcomp_table;
+		ir_codes         = RC_MAP_APAC_VIEWCOMP;
 		ir->mask_keycode = 0x001f00;
 		ir->mask_keyup   = 0x008000;
 		ir->polling      = 50; // ms
@@ -312,30 +314,30 @@
 	case BTTV_BOARD_ASKEY_CPH03X:
 	case BTTV_BOARD_CONCEPTRONIC_CTVFMI2:
 	case BTTV_BOARD_CONTVFMI:
-		ir_codes         = &ir_codes_pixelview_table;
+		ir_codes         = RC_MAP_PIXELVIEW;
 		ir->mask_keycode = 0x001F00;
 		ir->mask_keyup   = 0x006000;
 		ir->polling      = 50; // ms
 		break;
 	case BTTV_BOARD_NEBULA_DIGITV:
-		ir_codes = &ir_codes_nebula_table;
+		ir_codes = RC_MAP_NEBULA;
 		btv->custom_irq = bttv_rc5_irq;
 		ir->rc5_gpio = 1;
 		break;
 	case BTTV_BOARD_MACHTV_MAGICTV:
-		ir_codes         = &ir_codes_apac_viewcomp_table;
+		ir_codes         = RC_MAP_APAC_VIEWCOMP;
 		ir->mask_keycode = 0x001F00;
 		ir->mask_keyup   = 0x004000;
 		ir->polling      = 50; /* ms */
 		break;
 	case BTTV_BOARD_KOZUMI_KTV_01C:
-		ir_codes         = &ir_codes_pctv_sedna_table;
+		ir_codes         = RC_MAP_PCTV_SEDNA;
 		ir->mask_keycode = 0x001f00;
 		ir->mask_keyup   = 0x006000;
 		ir->polling      = 50; /* ms */
 		break;
 	case BTTV_BOARD_ENLTV_FM_2:
-		ir_codes         = &ir_codes_encore_enltv2_table;
+		ir_codes         = RC_MAP_ENCORE_ENLTV2;
 		ir->mask_keycode = 0x00fd00;
 		ir->mask_keyup   = 0x000080;
 		ir->polling      = 1; /* ms */
@@ -390,7 +392,7 @@
 	bttv_ir_start(btv, ir);
 
 	/* all done */
-	err = ir_input_register(btv->remote->dev, ir_codes, NULL);
+	err = ir_input_register(btv->remote->dev, ir_codes, NULL, MODULE_NAME);
 	if (err)
 		goto err_out_stop;
 
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index 9e39bc5..3c9e754 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -80,8 +80,8 @@
 
 #include "bw-qcam.h"
 
-static unsigned int maxpoll=250;   /* Maximum busy-loop count for qcam I/O */
-static unsigned int yieldlines=4;  /* Yield after this many during capture */
+static unsigned int maxpoll = 250;   /* Maximum busy-loop count for qcam I/O */
+static unsigned int yieldlines = 4;  /* Yield after this many during capture */
 static int video_nr = -1;
 static unsigned int force_init;		/* Whether to probe aggressively */
 
@@ -156,7 +156,7 @@
 		mdelay(1);
 		schedule();
 		count++;
-	} while (value == 0xff && count<2048);
+	} while (value == 0xff && count < 2048);
 
 	q->whitebal = value;
 	return value;
@@ -170,16 +170,15 @@
 	struct qcam_device *q;
 
 	q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL);
-	if(q==NULL)
+	if (q == NULL)
 		return NULL;
 
 	q->pport = port;
 	q->pdev = parport_register_device(port, "bw-qcam", NULL, NULL,
-					  NULL, 0, NULL);
-	if (q->pdev == NULL)
-	{
+			NULL, 0, NULL);
+	if (q->pdev == NULL) {
 		printk(KERN_ERR "bw-qcam: couldn't register for %s.\n",
-		       port->name);
+				port->name);
 		kfree(q);
 		return NULL;
 	}
@@ -247,12 +246,10 @@
 static int qc_waithand(struct qcam_device *q, int val)
 {
 	int status;
-	int runs=0;
+	int runs = 0;
 
-	if (val)
-	{
-		while (!((status = read_lpstatus(q)) & 8))
-		{
+	if (val) {
+		while (!((status = read_lpstatus(q)) & 8)) {
 			/* 1000 is enough spins on the I/O for all normal
 			   cases, at that point we start to poll slowly
 			   until the camera wakes up. However, we are
@@ -260,18 +257,13 @@
 			   setting it lower is much better for interactive
 			   response. */
 
-			if(runs++>maxpoll)
-			{
+			if (runs++ > maxpoll)
 				msleep_interruptible(5);
-			}
-			if(runs>(maxpoll+1000)) /* 5 seconds */
+			if (runs > (maxpoll + 1000)) /* 5 seconds */
 				return -1;
 		}
-	}
-	else
-	{
-		while (((status = read_lpstatus(q)) & 8))
-		{
+	} else {
+		while (((status = read_lpstatus(q)) & 8)) {
 			/* 1000 is enough spins on the I/O for all normal
 			   cases, at that point we start to poll slowly
 			   until the camera wakes up. However, we are
@@ -279,11 +271,9 @@
 			   setting it lower is much better for interactive
 			   response. */
 
-			if(runs++>maxpoll)
-			{
+			if (runs++ > maxpoll)
 				msleep_interruptible(5);
-			}
-			if(runs++>(maxpoll+1000)) /* 5 seconds */
+			if (runs++ > (maxpoll + 1000)) /* 5 seconds */
 				return -1;
 		}
 	}
@@ -299,10 +289,9 @@
 static unsigned int qc_waithand2(struct qcam_device *q, int val)
 {
 	unsigned int status;
-	int runs=0;
+	int runs = 0;
 
-	do
-	{
+	do {
 		status = read_lpdata(q);
 		/* 1000 is enough spins on the I/O for all normal
 		   cases, at that point we start to poll slowly
@@ -311,14 +300,11 @@
 		   setting it lower is much better for interactive
 		   response. */
 
-		if(runs++>maxpoll)
-		{
+		if (runs++ > maxpoll)
 			msleep_interruptible(5);
-		}
-		if(runs++>(maxpoll+1000)) /* 5 seconds */
+		if (runs++ > (maxpoll + 1000)) /* 5 seconds */
 			return 0;
-	}
-	while ((status & 1) != val);
+	} while ((status & 1) != val);
 
 	return status;
 }
@@ -342,8 +328,7 @@
 
 	lastreg = reg = read_lpstatus(q) & 0xf0;
 
-	for (i = 0; i < 500; i++)
-	{
+	for (i = 0; i < 500; i++) {
 		reg = read_lpstatus(q) & 0xf0;
 		if (reg != lastreg)
 			count++;
@@ -357,7 +342,7 @@
 	   won't be flashing these bits. Possibly unloading the module
 	   in the middle of a grab? Or some timeout condition?
 	   I've seen this parameter as low as 19 on my 450Mhz box - mpc */
-	printk("Debugging: QCam detection counter <30-200 counts as detected>: %d\n", count);
+	printk(KERN_DEBUG "Debugging: QCam detection counter <30-200 counts as detected>: %d\n", count);
 	return 1;
 #endif
 
@@ -367,7 +352,7 @@
 		return 1;	/* found */
 	} else {
 		printk(KERN_ERR "No Quickcam found on port %s\n",
-			q->pport->name);
+				q->pport->name);
 		printk(KERN_DEBUG "Quickcam detection counter: %u\n", count);
 		return 0;	/* not found */
 	}
@@ -381,26 +366,24 @@
 
 static void qc_reset(struct qcam_device *q)
 {
-	switch (q->port_mode & QC_FORCE_MASK)
-	{
-		case QC_FORCE_UNIDIR:
-			q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
-			break;
+	switch (q->port_mode & QC_FORCE_MASK) {
+	case QC_FORCE_UNIDIR:
+		q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
+		break;
 
-		case QC_FORCE_BIDIR:
+	case QC_FORCE_BIDIR:
+		q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
+		break;
+
+	case QC_ANY:
+		write_lpcontrol(q, 0x20);
+		write_lpdata(q, 0x75);
+
+		if (read_lpdata(q) != 0x75)
 			q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
-			break;
-
-		case QC_ANY:
-			write_lpcontrol(q, 0x20);
-			write_lpdata(q, 0x75);
-
-			if (read_lpdata(q) != 0x75) {
-				q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
-			} else {
-				q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
-			}
-			break;
+		else
+			q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
+		break;
 	}
 
 	write_lpcontrol(q, 0xb);
@@ -423,36 +406,33 @@
 {
 	int old_mode = q->mode;
 
-	switch (q->transfer_scale)
-	{
-		case 1:
-			q->mode = 0;
-			break;
-		case 2:
-			q->mode = 4;
-			break;
-		case 4:
-			q->mode = 8;
-			break;
+	switch (q->transfer_scale) {
+	case 1:
+		q->mode = 0;
+		break;
+	case 2:
+		q->mode = 4;
+		break;
+	case 4:
+		q->mode = 8;
+		break;
 	}
 
-	switch (q->bpp)
-	{
-		case 4:
-			break;
-		case 6:
-			q->mode += 2;
-			break;
+	switch (q->bpp) {
+	case 4:
+		break;
+	case 6:
+		q->mode += 2;
+		break;
 	}
 
-	switch (q->port_mode & QC_MODE_MASK)
-	{
-		case QC_BIDIR:
-			q->mode += 1;
-			break;
-		case QC_NOTSET:
-		case QC_UNIDIR:
-			break;
+	switch (q->port_mode & QC_MODE_MASK) {
+	case QC_BIDIR:
+		q->mode += 1;
+		break;
+	case QC_NOTSET:
+	case QC_UNIDIR:
+		break;
 	}
 
 	if (q->mode != old_mode)
@@ -493,7 +473,7 @@
 	} else {
 		val = q->width * q->bpp;
 		val2 = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) *
-		    q->transfer_scale;
+			q->transfer_scale;
 	}
 	val = DIV_ROUND_UP(val, val2);
 	qc_command(q, 0x13);
@@ -521,85 +501,80 @@
 
 static inline int qc_readbytes(struct qcam_device *q, char buffer[])
 {
-	int ret=1;
+	int ret = 1;
 	unsigned int hi, lo;
 	unsigned int hi2, lo2;
 	static int state;
 
-	if (buffer == NULL)
-	{
+	if (buffer == NULL) {
 		state = 0;
 		return 0;
 	}
 
-	switch (q->port_mode & QC_MODE_MASK)
-	{
-		case QC_BIDIR:		/* Bi-directional Port */
-			write_lpcontrol(q, 0x26);
-			lo = (qc_waithand2(q, 1) >> 1);
-			hi = (read_lpstatus(q) >> 3) & 0x1f;
-			write_lpcontrol(q, 0x2e);
-			lo2 = (qc_waithand2(q, 0) >> 1);
-			hi2 = (read_lpstatus(q) >> 3) & 0x1f;
-			switch (q->bpp)
-			{
-				case 4:
-					buffer[0] = lo & 0xf;
-					buffer[1] = ((lo & 0x70) >> 4) | ((hi & 1) << 3);
-					buffer[2] = (hi & 0x1e) >> 1;
-					buffer[3] = lo2 & 0xf;
-					buffer[4] = ((lo2 & 0x70) >> 4) | ((hi2 & 1) << 3);
-					buffer[5] = (hi2 & 0x1e) >> 1;
-					ret = 6;
-					break;
-				case 6:
-					buffer[0] = lo & 0x3f;
-					buffer[1] = ((lo & 0x40) >> 6) | (hi << 1);
-					buffer[2] = lo2 & 0x3f;
-					buffer[3] = ((lo2 & 0x40) >> 6) | (hi2 << 1);
-					ret = 4;
-					break;
+	switch (q->port_mode & QC_MODE_MASK) {
+	case QC_BIDIR:		/* Bi-directional Port */
+		write_lpcontrol(q, 0x26);
+		lo = (qc_waithand2(q, 1) >> 1);
+		hi = (read_lpstatus(q) >> 3) & 0x1f;
+		write_lpcontrol(q, 0x2e);
+		lo2 = (qc_waithand2(q, 0) >> 1);
+		hi2 = (read_lpstatus(q) >> 3) & 0x1f;
+		switch (q->bpp) {
+		case 4:
+			buffer[0] = lo & 0xf;
+			buffer[1] = ((lo & 0x70) >> 4) | ((hi & 1) << 3);
+			buffer[2] = (hi & 0x1e) >> 1;
+			buffer[3] = lo2 & 0xf;
+			buffer[4] = ((lo2 & 0x70) >> 4) | ((hi2 & 1) << 3);
+			buffer[5] = (hi2 & 0x1e) >> 1;
+			ret = 6;
+			break;
+		case 6:
+			buffer[0] = lo & 0x3f;
+			buffer[1] = ((lo & 0x40) >> 6) | (hi << 1);
+			buffer[2] = lo2 & 0x3f;
+			buffer[3] = ((lo2 & 0x40) >> 6) | (hi2 << 1);
+			ret = 4;
+			break;
+		}
+		break;
+
+	case QC_UNIDIR:	/* Unidirectional Port */
+		write_lpcontrol(q, 6);
+		lo = (qc_waithand(q, 1) & 0xf0) >> 4;
+		write_lpcontrol(q, 0xe);
+		hi = (qc_waithand(q, 0) & 0xf0) >> 4;
+
+		switch (q->bpp) {
+		case 4:
+			buffer[0] = lo;
+			buffer[1] = hi;
+			ret = 2;
+			break;
+		case 6:
+			switch (state) {
+			case 0:
+				buffer[0] = (lo << 2) | ((hi & 0xc) >> 2);
+				q->saved_bits = (hi & 3) << 4;
+				state = 1;
+				ret = 1;
+				break;
+			case 1:
+				buffer[0] = lo | q->saved_bits;
+				q->saved_bits = hi << 2;
+				state = 2;
+				ret = 1;
+				break;
+			case 2:
+				buffer[0] = ((lo & 0xc) >> 2) | q->saved_bits;
+				buffer[1] = ((lo & 3) << 4) | hi;
+				state = 0;
+				ret = 2;
+				break;
 			}
 			break;
-
-		case QC_UNIDIR:	/* Unidirectional Port */
-			write_lpcontrol(q, 6);
-			lo = (qc_waithand(q, 1) & 0xf0) >> 4;
-			write_lpcontrol(q, 0xe);
-			hi = (qc_waithand(q, 0) & 0xf0) >> 4;
-
-			switch (q->bpp)
-			{
-				case 4:
-					buffer[0] = lo;
-					buffer[1] = hi;
-					ret = 2;
-					break;
-				case 6:
-					switch (state)
-					{
-						case 0:
-							buffer[0] = (lo << 2) | ((hi & 0xc) >> 2);
-							q->saved_bits = (hi & 3) << 4;
-							state = 1;
-							ret = 1;
-							break;
-						case 1:
-							buffer[0] = lo | q->saved_bits;
-							q->saved_bits = hi << 2;
-							state = 2;
-							ret = 1;
-							break;
-						case 2:
-							buffer[0] = ((lo & 0xc) >> 2) | q->saved_bits;
-							buffer[1] = ((lo & 3) << 4) | hi;
-							state = 0;
-							ret = 2;
-							break;
-					}
-					break;
-			}
-			break;
+		}
+		break;
 	}
 	return ret;
 }
@@ -615,7 +590,7 @@
  * n=2^(bit depth)-1.  Ask me for more details if you don't understand
  * this. */
 
-static long qc_capture(struct qcam_device * q, char __user *buf, unsigned long len)
+static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long len)
 {
 	int i, j, k, yield;
 	int bytes;
@@ -623,9 +598,9 @@
 	int divisor;
 	int pixels_per_line;
 	int pixels_read = 0;
-	int got=0;
+	int got = 0;
 	char buffer[6];
-	int  shift=8-q->bpp;
+	int  shift = 8 - q->bpp;
 	char invert;
 
 	if (q->mode == -1)
@@ -634,13 +609,12 @@
 	qc_command(q, 0x7);
 	qc_command(q, q->mode);
 
-	if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR)
-	{
+	if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) {
 		write_lpcontrol(q, 0x2e);	/* turn port around */
 		write_lpcontrol(q, 0x26);
-		(void) qc_waithand(q, 1);
+		qc_waithand(q, 1);
 		write_lpcontrol(q, 0x2e);
-		(void) qc_waithand(q, 0);
+		qc_waithand(q, 0);
 	}
 
 	/* strange -- should be 15:63 below, but 4bpp is odd */
@@ -650,33 +624,28 @@
 	pixels_per_line = q->width / q->transfer_scale;
 	transperline = q->width * q->bpp;
 	divisor = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) *
-	    q->transfer_scale;
+		q->transfer_scale;
 	transperline = DIV_ROUND_UP(transperline, divisor);
 
-	for (i = 0, yield = yieldlines; i < linestotrans; i++)
-	{
-		for (pixels_read = j = 0; j < transperline; j++)
-		{
+	for (i = 0, yield = yieldlines; i < linestotrans; i++) {
+		for (pixels_read = j = 0; j < transperline; j++) {
 			bytes = qc_readbytes(q, buffer);
-			for (k = 0; k < bytes && (pixels_read + k) < pixels_per_line; k++)
-			{
+			for (k = 0; k < bytes && (pixels_read + k) < pixels_per_line; k++) {
 				int o;
-				if (buffer[k] == 0 && invert == 16)
-				{
+				if (buffer[k] == 0 && invert == 16) {
 					/* 4bpp is odd (again) -- inverter is 16, not 15, but output
 					   must be 0-15 -- bls */
 					buffer[k] = 16;
 				}
-				o=i*pixels_per_line + pixels_read + k;
-				if(o<len)
-				{
+				o = i * pixels_per_line + pixels_read + k;
+				if (o < len) {
 					got++;
-					put_user((invert - buffer[k])<<shift, buf+o);
+					put_user((invert - buffer[k]) << shift, buf + o);
 				}
 			}
 			pixels_read += bytes;
 		}
-		(void) qc_readbytes(q, NULL);	/* reset state machine */
+		qc_readbytes(q, NULL);	/* reset state machine */
 
 		/* Grabbing an entire frame from the quickcam is a lengthy
 		   process. We don't (usually) want to busy-block the
@@ -690,14 +659,13 @@
 		}
 	}
 
-	if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR)
-	{
+	if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) {
 		write_lpcontrol(q, 2);
 		write_lpcontrol(q, 6);
 		udelay(3);
 		write_lpcontrol(q, 0xe);
 	}
-	if(got<len)
+	if (got < len)
 		return got;
 	return len;
 }
@@ -709,11 +677,10 @@
 static long qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
 	struct video_device *dev = video_devdata(file);
-	struct qcam_device *qcam=(struct qcam_device *)dev;
+	struct qcam_device *qcam = (struct qcam_device *)dev;
 
-	switch(cmd)
-	{
-		case VIDIOCGCAP:
+	switch (cmd) {
+	case VIDIOCGCAP:
 		{
 			struct video_capability *b = arg;
 			strcpy(b->name, "Quickcam");
@@ -726,73 +693,73 @@
 			b->minheight = 60;
 			return 0;
 		}
-		case VIDIOCGCHAN:
+	case VIDIOCGCHAN:
 		{
 			struct video_channel *v = arg;
-			if(v->channel!=0)
+			if (v->channel != 0)
 				return -EINVAL;
-			v->flags=0;
-			v->tuners=0;
+			v->flags = 0;
+			v->tuners = 0;
 			/* Good question.. its composite or SVHS so.. */
 			v->type = VIDEO_TYPE_CAMERA;
 			strcpy(v->name, "Camera");
 			return 0;
 		}
-		case VIDIOCSCHAN:
+	case VIDIOCSCHAN:
 		{
 			struct video_channel *v = arg;
-			if(v->channel!=0)
+			if (v->channel != 0)
 				return -EINVAL;
 			return 0;
 		}
-		case VIDIOCGTUNER:
+	case VIDIOCGTUNER:
 		{
 			struct video_tuner *v = arg;
-			if(v->tuner)
+			if (v->tuner)
 				return -EINVAL;
 			strcpy(v->name, "Format");
-			v->rangelow=0;
-			v->rangehigh=0;
-			v->flags= 0;
+			v->rangelow = 0;
+			v->rangehigh = 0;
+			v->flags = 0;
 			v->mode = VIDEO_MODE_AUTO;
 			return 0;
 		}
-		case VIDIOCSTUNER:
+	case VIDIOCSTUNER:
 		{
 			struct video_tuner *v = arg;
-			if(v->tuner)
+			if (v->tuner)
 				return -EINVAL;
-			if(v->mode!=VIDEO_MODE_AUTO)
+			if (v->mode != VIDEO_MODE_AUTO)
 				return -EINVAL;
 			return 0;
 		}
-		case VIDIOCGPICT:
+	case VIDIOCGPICT:
 		{
 			struct video_picture *p = arg;
-			p->colour=0x8000;
-			p->hue=0x8000;
-			p->brightness=qcam->brightness<<8;
-			p->contrast=qcam->contrast<<8;
-			p->whiteness=qcam->whitebal<<8;
-			p->depth=qcam->bpp;
-			p->palette=VIDEO_PALETTE_GREY;
+			p->colour = 0x8000;
+			p->hue = 0x8000;
+			p->brightness = qcam->brightness << 8;
+			p->contrast = qcam->contrast << 8;
+			p->whiteness = qcam->whitebal << 8;
+			p->depth = qcam->bpp;
+			p->palette = VIDEO_PALETTE_GREY;
 			return 0;
 		}
-		case VIDIOCSPICT:
+	case VIDIOCSPICT:
 		{
 			struct video_picture *p = arg;
-			if(p->palette!=VIDEO_PALETTE_GREY)
+			if (p->palette != VIDEO_PALETTE_GREY)
 				return -EINVAL;
-			if(p->depth!=4 && p->depth!=6)
+			if (p->depth != 4 && p->depth != 6)
 				return -EINVAL;
 
 			/*
 			 *	Now load the camera.
 			 */
 
-			qcam->brightness = p->brightness>>8;
-			qcam->contrast = p->contrast>>8;
-			qcam->whitebal = p->whiteness>>8;
+			qcam->brightness = p->brightness >> 8;
+			qcam->contrast = p->contrast >> 8;
+			qcam->whitebal = p->whiteness >> 8;
 			qcam->bpp = p->depth;
 
 			mutex_lock(&qcam->lock);
@@ -802,28 +769,25 @@
 
 			return 0;
 		}
-		case VIDIOCSWIN:
+	case VIDIOCSWIN:
 		{
 			struct video_window *vw = arg;
-			if(vw->flags)
+			if (vw->flags)
 				return -EINVAL;
-			if(vw->clipcount)
+			if (vw->clipcount)
 				return -EINVAL;
-			if(vw->height<60||vw->height>240)
+			if (vw->height < 60 || vw->height > 240)
 				return -EINVAL;
-			if(vw->width<80||vw->width>320)
+			if (vw->width < 80 || vw->width > 320)
 				return -EINVAL;
 
 			qcam->width = 320;
 			qcam->height = 240;
 			qcam->transfer_scale = 4;
 
-			if(vw->width>=160 && vw->height>=120)
-			{
+			if (vw->width >= 160 && vw->height >= 120)
 				qcam->transfer_scale = 2;
-			}
-			if(vw->width>=320 && vw->height>=240)
-			{
+			if (vw->width >= 320 && vw->height >= 240) {
 				qcam->width = 320;
 				qcam->height = 240;
 				qcam->transfer_scale = 1;
@@ -839,41 +803,42 @@
 			/* Ok we figured out what to use from our wide choice */
 			return 0;
 		}
-		case VIDIOCGWIN:
+	case VIDIOCGWIN:
 		{
 			struct video_window *vw = arg;
+
 			memset(vw, 0, sizeof(*vw));
-			vw->width=qcam->width/qcam->transfer_scale;
-			vw->height=qcam->height/qcam->transfer_scale;
+			vw->width = qcam->width / qcam->transfer_scale;
+			vw->height = qcam->height / qcam->transfer_scale;
 			return 0;
 		}
-		case VIDIOCKEY:
-			return 0;
-		case VIDIOCCAPTURE:
-		case VIDIOCGFBUF:
-		case VIDIOCSFBUF:
-		case VIDIOCGFREQ:
-		case VIDIOCSFREQ:
-		case VIDIOCGAUDIO:
-		case VIDIOCSAUDIO:
-			return -EINVAL;
-		default:
-			return -ENOIOCTLCMD;
+	case VIDIOCKEY:
+		return 0;
+	case VIDIOCCAPTURE:
+	case VIDIOCGFBUF:
+	case VIDIOCSFBUF:
+	case VIDIOCGFREQ:
+	case VIDIOCSFREQ:
+	case VIDIOCGAUDIO:
+	case VIDIOCSAUDIO:
+		return -EINVAL;
+	default:
+		return -ENOIOCTLCMD;
 	}
 	return 0;
 }
 
 static long qcam_ioctl(struct file *file,
-		     unsigned int cmd, unsigned long arg)
+		unsigned int cmd, unsigned long arg)
 {
 	return video_usercopy(file, cmd, arg, qcam_do_ioctl);
 }
 
 static ssize_t qcam_read(struct file *file, char __user *buf,
-			 size_t count, loff_t *ppos)
+		size_t count, loff_t *ppos)
 {
 	struct video_device *v = video_devdata(file);
-	struct qcam_device *qcam=(struct qcam_device *)v;
+	struct qcam_device *qcam = (struct qcam_device *)v;
 	int len;
 	parport_claim_or_block(qcam->pdev);
 
@@ -885,7 +850,7 @@
 	if (qcam->status & QC_PARAM_CHANGE)
 		qc_set(qcam);
 
-	len=qc_capture(qcam, buf,count);
+	len = qc_capture(qcam, buf, count);
 
 	mutex_unlock(&qcam->lock);
 
@@ -917,8 +882,7 @@
 	.ioctl          = qcam_ioctl,
 	.read		= qcam_read,
 };
-static struct video_device qcam_template=
-{
+static struct video_device qcam_template = {
 	.name		= "Connectix Quickcam",
 	.fops           = &qcam_fops,
 	.release 	= video_device_release_empty,
@@ -932,22 +896,20 @@
 {
 	struct qcam_device *qcam;
 
-	if (num_cams == MAX_CAMS)
-	{
+	if (num_cams == MAX_CAMS) {
 		printk(KERN_ERR "Too many Quickcams (max %d)\n", MAX_CAMS);
 		return -ENOSPC;
 	}
 
-	qcam=qcam_init(port);
-	if(qcam==NULL)
+	qcam = qcam_init(port);
+	if (qcam == NULL)
 		return -ENODEV;
 
 	parport_claim_or_block(qcam->pdev);
 
 	qc_reset(qcam);
 
-	if(qc_detect(qcam)==0)
-	{
+	if (qc_detect(qcam) == 0) {
 		parport_release(qcam->pdev);
 		parport_unregister_device(qcam->pdev);
 		kfree(qcam);
@@ -1045,12 +1007,12 @@
 #ifdef MODULE
 	/* Do some sanity checks on the module parameters. */
 	if (maxpoll > 5000) {
-		printk("Connectix Quickcam max-poll was above 5000. Using 5000.\n");
+		printk(KERN_INFO "Connectix Quickcam max-poll was above 5000. Using 5000.\n");
 		maxpoll = 5000;
 	}
 
 	if (yieldlines < 1) {
-		printk("Connectix Quickcam yieldlines was less than 1. Using 1.\n");
+		printk(KERN_INFO "Connectix Quickcam yieldlines was less than 1. Using 1.\n");
 		yieldlines = 1;
 	}
 #endif
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index e2cbeba..8f1dd88b 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -79,17 +79,17 @@
 {
 	/* note: the QC specs refer to the PCAck pin by voltage, not
 	   software level.  PC ports have builtin inverters. */
-	parport_frob_control(qcam->pport, 8, i?8:0);
+	parport_frob_control(qcam->pport, 8, i ? 8 : 0);
 }
 
 static inline unsigned int qcam_ready1(struct qcam_device *qcam)
 {
-	return (parport_read_status(qcam->pport) & 0x8)?1:0;
+	return (parport_read_status(qcam->pport) & 0x8) ? 1 : 0;
 }
 
 static inline unsigned int qcam_ready2(struct qcam_device *qcam)
 {
-	return (parport_read_data(qcam->pport) & 0x1)?1:0;
+	return (parport_read_data(qcam->pport) & 0x1) ? 1 : 0;
 }
 
 static unsigned int qcam_await_ready1(struct qcam_device *qcam,
@@ -99,14 +99,13 @@
 	unsigned int i;
 
 	for (oldjiffies = jiffies;
-	     time_before(jiffies, oldjiffies + msecs_to_jiffies(40)); )
+	     time_before(jiffies, oldjiffies + msecs_to_jiffies(40));)
 		if (qcam_ready1(qcam) == value)
 			return 0;
 
 	/* If the camera didn't respond within 1/25 second, poll slowly
 	   for a while. */
-	for (i = 0; i < 50; i++)
-	{
+	for (i = 0; i < 50; i++) {
 		if (qcam_ready1(qcam) == value)
 			return 0;
 		msleep_interruptible(100);
@@ -125,14 +124,13 @@
 	unsigned int i;
 
 	for (oldjiffies = jiffies;
-	     time_before(jiffies, oldjiffies + msecs_to_jiffies(40)); )
+	     time_before(jiffies, oldjiffies + msecs_to_jiffies(40));)
 		if (qcam_ready2(qcam) == value)
 			return 0;
 
 	/* If the camera didn't respond within 1/25 second, poll slowly
 	   for a while. */
-	for (i = 0; i < 50; i++)
-	{
+	for (i = 0; i < 50; i++) {
 		if (qcam_ready2(qcam) == value)
 			return 0;
 		msleep_interruptible(100);
@@ -149,22 +147,25 @@
 static int qcam_read_data(struct qcam_device *qcam)
 {
 	unsigned int idata;
+
 	qcam_set_ack(qcam, 0);
-	if (qcam_await_ready1(qcam, 1)) return -1;
+	if (qcam_await_ready1(qcam, 1))
+		return -1;
 	idata = parport_read_status(qcam->pport) & 0xf0;
 	qcam_set_ack(qcam, 1);
-	if (qcam_await_ready1(qcam, 0)) return -1;
-	idata |= (parport_read_status(qcam->pport) >> 4);
+	if (qcam_await_ready1(qcam, 0))
+		return -1;
+	idata |= parport_read_status(qcam->pport) >> 4;
 	return idata;
 }
 
 static int qcam_write_data(struct qcam_device *qcam, unsigned int data)
 {
 	unsigned int idata;
+
 	parport_write_data(qcam->pport, data);
 	idata = qcam_read_data(qcam);
-	if (data != idata)
-	{
+	if (data != idata) {
 		printk(KERN_WARNING "cqcam: sent %x but received %x\n", data,
 		       idata);
 		return 1;
@@ -212,13 +213,12 @@
 
 	/* look for a heartbeat */
 	ostat = stat = parport_read_status(qcam->pport);
-	for (i=0; i<250; i++)
-	{
+	for (i = 0; i < 250; i++) {
 		mdelay(1);
 		stat = parport_read_status(qcam->pport);
-		if (ostat != stat)
-		{
-			if (++count >= 3) return 1;
+		if (ostat != stat) {
+			if (++count >= 3)
+				return 1;
 			ostat = stat;
 		}
 	}
@@ -232,13 +232,12 @@
 	count = 0;
 
 	ostat = stat = parport_read_status(qcam->pport);
-	for (i=0; i<250; i++)
-	{
+	for (i = 0; i < 250; i++) {
 		mdelay(1);
 		stat = parport_read_status(qcam->pport);
-		if (ostat != stat)
-		{
-			if (++count >= 3) return 1;
+		if (ostat != stat) {
+			if (++count >= 3)
+				return 1;
 			ostat = stat;
 		}
 	}
@@ -263,7 +262,7 @@
 {
 	qc_reset(q);
 
-	/* Set the brightness.  */
+	/* Set the brightness. */
 	qcam_set(q, 11, q->brightness);
 
 	/* Set the height and width.  These refer to the actual
@@ -292,25 +291,25 @@
 	unsigned int bytes = 0;
 
 	qcam_set_ack(q, 0);
-	if (q->bidirectional)
-	{
+	if (q->bidirectional) {
 		/* It's a bidirectional port */
-		while (bytes < nbytes)
-		{
+		while (bytes < nbytes) {
 			unsigned int lo1, hi1, lo2, hi2;
 			unsigned char r, g, b;
 
-			if (qcam_await_ready2(q, 1)) return bytes;
+			if (qcam_await_ready2(q, 1))
+				return bytes;
 			lo1 = parport_read_data(q->pport) >> 1;
 			hi1 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;
 			qcam_set_ack(q, 1);
-			if (qcam_await_ready2(q, 0)) return bytes;
+			if (qcam_await_ready2(q, 0))
+				return bytes;
 			lo2 = parport_read_data(q->pport) >> 1;
 			hi2 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;
 			qcam_set_ack(q, 0);
-			r = (lo1 | ((hi1 & 1)<<7));
-			g = ((hi1 & 0x1e)<<3) | ((hi2 & 0x1e)>>1);
-			b = (lo2 | ((hi2 & 1)<<7));
+			r = lo1 | ((hi1 & 1) << 7);
+			g = ((hi1 & 0x1e) << 3) | ((hi2 & 0x1e) >> 1);
+			b = lo2 | ((hi2 & 1) << 7);
 			if (force_rgb) {
 				buf[bytes++] = r;
 				buf[bytes++] = g;
@@ -321,21 +320,20 @@
 				buf[bytes++] = r;
 			}
 		}
-	}
-	else
-	{
+	} else {
 		/* It's a unidirectional port */
 		int i = 0, n = bytes;
 		unsigned char rgb[3];
 
-		while (bytes < nbytes)
-		{
+		while (bytes < nbytes) {
 			unsigned int hi, lo;
 
-			if (qcam_await_ready1(q, 1)) return bytes;
+			if (qcam_await_ready1(q, 1))
+				return bytes;
 			hi = (parport_read_status(q->pport) & 0xf0);
 			qcam_set_ack(q, 1);
-			if (qcam_await_ready1(q, 0)) return bytes;
+			if (qcam_await_ready1(q, 0))
+				return bytes;
 			lo = (parport_read_status(q->pport) & 0xf0);
 			qcam_set_ack(q, 0);
 			/* flip some bits */
@@ -374,28 +372,26 @@
 		return -EFAULT;
 
 	/* Wait for camera to become ready */
-	for (;;)
-	{
+	for (;;) {
 		int i = qcam_get(q, 41);
+
 		if (i == -1) {
 			qc_setup(q);
 			return -EIO;
 		}
 		if ((i & 0x80) == 0)
 			break;
-		else
-			schedule();
+		schedule();
 	}
 
-	if (qcam_set(q, 7, (q->mode | (is_bi_dir?1:0)) + 1))
+	if (qcam_set(q, 7, (q->mode | (is_bi_dir ? 1 : 0)) + 1))
 		return -EIO;
 
 	lines = q->height;
 	pixelsperline = q->width;
 	bitsperxfer = (is_bi_dir) ? 24 : 8;
 
-	if (is_bi_dir)
-	{
+	if (is_bi_dir) {
 		/* Turn the port around */
 		parport_data_reverse(q->pport);
 		mdelay(3);
@@ -413,16 +409,17 @@
 
 	wantlen = lines * pixelsperline * 24 / 8;
 
-	while (wantlen)
-	{
+	while (wantlen) {
 		size_t t, s;
-		s = (wantlen > BUFSZ)?BUFSZ:wantlen;
+
+		s = (wantlen > BUFSZ) ? BUFSZ : wantlen;
 		t = qcam_read_bytes(q, tmpbuf, s);
-		if (outptr < len)
-		{
+		if (outptr < len) {
 			size_t sz = len - outptr;
-			if (sz > t) sz = t;
-			if (__copy_to_user(buf+outptr, tmpbuf, sz))
+
+			if (sz > t)
+				sz = t;
+			if (__copy_to_user(buf + outptr, tmpbuf, sz))
 				break;
 			outptr += sz;
 		}
@@ -434,33 +431,31 @@
 
 	len = outptr;
 
-	if (wantlen)
-	{
-		printk("qcam: short read.\n");
+	if (wantlen) {
+		printk(KERN_ERR "qcam: short read.\n");
 		if (is_bi_dir)
 			parport_data_forward(q->pport);
 		qc_setup(q);
 		return len;
 	}
 
-	if (is_bi_dir)
-	{
+	if (is_bi_dir) {
 		int l;
+
 		do {
 			l = qcam_read_bytes(q, tmpbuf, 3);
 			cond_resched();
 		} while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
 		if (force_rgb) {
 			if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
-				printk("qcam: bad EOF\n");
+				printk(KERN_ERR "qcam: bad EOF\n");
 		} else {
 			if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
-				printk("qcam: bad EOF\n");
+				printk(KERN_ERR "qcam: bad EOF\n");
 		}
 		qcam_set_ack(q, 0);
-		if (qcam_await_ready1(q, 1))
-		{
-			printk("qcam: no ack after EOF\n");
+		if (qcam_await_ready1(q, 1)) {
+			printk(KERN_ERR "qcam: no ack after EOF\n");
 			parport_data_forward(q->pport);
 			qc_setup(q);
 			return len;
@@ -468,27 +463,25 @@
 		parport_data_forward(q->pport);
 		mdelay(3);
 		qcam_set_ack(q, 1);
-		if (qcam_await_ready1(q, 0))
-		{
-			printk("qcam: no ack to port turnaround\n");
+		if (qcam_await_ready1(q, 0)) {
+			printk(KERN_ERR "qcam: no ack to port turnaround\n");
 			qc_setup(q);
 			return len;
 		}
-	}
-	else
-	{
+	} else {
 		int l;
+
 		do {
 			l = qcam_read_bytes(q, tmpbuf, 1);
 			cond_resched();
 		} while (l && tmpbuf[0] == 0x7e);
-		l = qcam_read_bytes(q, tmpbuf+1, 2);
+		l = qcam_read_bytes(q, tmpbuf + 1, 2);
 		if (force_rgb) {
 			if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
-				printk("qcam: bad EOF\n");
+				printk(KERN_ERR "qcam: bad EOF\n");
 		} else {
 			if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
-				printk("qcam: bad EOF\n");
+				printk(KERN_ERR "qcam: bad EOF\n");
 		}
 	}
 
@@ -503,164 +496,166 @@
 static long qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
 	struct video_device *dev = video_devdata(file);
-	struct qcam_device *qcam=(struct qcam_device *)dev;
+	struct qcam_device *qcam = (struct qcam_device *)dev;
 
-	switch(cmd)
+	switch (cmd) {
+	case VIDIOCGCAP:
 	{
-		case VIDIOCGCAP:
-		{
-			struct video_capability *b = arg;
-			strcpy(b->name, "Quickcam");
-			b->type = VID_TYPE_CAPTURE|VID_TYPE_SCALES;
-			b->channels = 1;
-			b->audios = 0;
-			b->maxwidth = 320;
-			b->maxheight = 240;
-			b->minwidth = 80;
-			b->minheight = 60;
-			return 0;
-		}
-		case VIDIOCGCHAN:
-		{
-			struct video_channel *v = arg;
-			if(v->channel!=0)
-				return -EINVAL;
-			v->flags=0;
-			v->tuners=0;
-			/* Good question.. its composite or SVHS so.. */
-			v->type = VIDEO_TYPE_CAMERA;
-			strcpy(v->name, "Camera");
-			return 0;
-		}
-		case VIDIOCSCHAN:
-		{
-			struct video_channel *v = arg;
-			if(v->channel!=0)
-				return -EINVAL;
-			return 0;
-		}
-		case VIDIOCGTUNER:
-		{
-			struct video_tuner *v = arg;
-			if(v->tuner)
-				return -EINVAL;
-			memset(v,0,sizeof(*v));
-			strcpy(v->name, "Format");
-			v->mode = VIDEO_MODE_AUTO;
-			return 0;
-		}
-		case VIDIOCSTUNER:
-		{
-			struct video_tuner *v = arg;
-			if(v->tuner)
-				return -EINVAL;
-			if(v->mode!=VIDEO_MODE_AUTO)
-				return -EINVAL;
-			return 0;
-		}
-		case VIDIOCGPICT:
-		{
-			struct video_picture *p = arg;
-			p->colour=0x8000;
-			p->hue=0x8000;
-			p->brightness=qcam->brightness<<8;
-			p->contrast=qcam->contrast<<8;
-			p->whiteness=qcam->whitebal<<8;
-			p->depth=24;
-			p->palette=VIDEO_PALETTE_RGB24;
-			return 0;
-		}
-		case VIDIOCSPICT:
-		{
-			struct video_picture *p = arg;
+		struct video_capability *b = arg;
 
-			/*
-			 *	Sanity check args
-			 */
-			if (p->depth != 24 || p->palette != VIDEO_PALETTE_RGB24)
-				return -EINVAL;
+		strcpy(b->name, "Quickcam");
+		b->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
+		b->channels = 1;
+		b->audios = 0;
+		b->maxwidth = 320;
+		b->maxheight = 240;
+		b->minwidth = 80;
+		b->minheight = 60;
+		return 0;
+	}
+	case VIDIOCGCHAN:
+	{
+		struct video_channel *v = arg;
 
-			/*
-			 *	Now load the camera.
-			 */
-			qcam->brightness = p->brightness>>8;
-			qcam->contrast = p->contrast>>8;
-			qcam->whitebal = p->whiteness>>8;
-
-			mutex_lock(&qcam->lock);
-			parport_claim_or_block(qcam->pdev);
-			qc_setup(qcam);
-			parport_release(qcam->pdev);
-			mutex_unlock(&qcam->lock);
-			return 0;
-		}
-		case VIDIOCSWIN:
-		{
-			struct video_window *vw = arg;
-
-			if(vw->flags)
-				return -EINVAL;
-			if(vw->clipcount)
-				return -EINVAL;
-			if(vw->height<60||vw->height>240)
-				return -EINVAL;
-			if(vw->width<80||vw->width>320)
-				return -EINVAL;
-
-			qcam->width = 80;
-			qcam->height = 60;
-			qcam->mode = QC_DECIMATION_4;
-
-			if(vw->width>=160 && vw->height>=120)
-			{
-				qcam->width = 160;
-				qcam->height = 120;
-				qcam->mode = QC_DECIMATION_2;
-			}
-			if(vw->width>=320 && vw->height>=240)
-			{
-				qcam->width = 320;
-				qcam->height = 240;
-				qcam->mode = QC_DECIMATION_1;
-			}
-			qcam->mode |= QC_MILLIONS;
-#if 0
-			if(vw->width>=640 && vw->height>=480)
-			{
-				qcam->width = 640;
-				qcam->height = 480;
-				qcam->mode = QC_BILLIONS | QC_DECIMATION_1;
-			}
-#endif
-			/* Ok we figured out what to use from our
-			   wide choice */
-			mutex_lock(&qcam->lock);
-			parport_claim_or_block(qcam->pdev);
-			qc_setup(qcam);
-			parport_release(qcam->pdev);
-			mutex_unlock(&qcam->lock);
-			return 0;
-		}
-		case VIDIOCGWIN:
-		{
-			struct video_window *vw = arg;
-			memset(vw, 0, sizeof(*vw));
-			vw->width=qcam->width;
-			vw->height=qcam->height;
-			return 0;
-		}
-		case VIDIOCKEY:
-			return 0;
-		case VIDIOCCAPTURE:
-		case VIDIOCGFBUF:
-		case VIDIOCSFBUF:
-		case VIDIOCGFREQ:
-		case VIDIOCSFREQ:
-		case VIDIOCGAUDIO:
-		case VIDIOCSAUDIO:
+		if (v->channel != 0)
 			return -EINVAL;
-		default:
-			return -ENOIOCTLCMD;
+		v->flags = 0;
+		v->tuners = 0;
+		/* Good question.. its composite or SVHS so.. */
+		v->type = VIDEO_TYPE_CAMERA;
+		strcpy(v->name, "Camera");
+		return 0;
+	}
+	case VIDIOCSCHAN:
+	{
+		struct video_channel *v = arg;
+
+		if (v->channel != 0)
+			return -EINVAL;
+		return 0;
+	}
+	case VIDIOCGTUNER:
+	{
+		struct video_tuner *v = arg;
+
+		if (v->tuner)
+			return -EINVAL;
+		memset(v, 0, sizeof(*v));
+		strcpy(v->name, "Format");
+		v->mode = VIDEO_MODE_AUTO;
+		return 0;
+	}
+	case VIDIOCSTUNER:
+	{
+		struct video_tuner *v = arg;
+
+		if (v->tuner)
+			return -EINVAL;
+		if (v->mode != VIDEO_MODE_AUTO)
+			return -EINVAL;
+		return 0;
+	}
+	case VIDIOCGPICT:
+	{
+		struct video_picture *p = arg;
+
+		p->colour = 0x8000;
+		p->hue = 0x8000;
+		p->brightness = qcam->brightness << 8;
+		p->contrast = qcam->contrast << 8;
+		p->whiteness = qcam->whitebal << 8;
+		p->depth = 24;
+		p->palette = VIDEO_PALETTE_RGB24;
+		return 0;
+	}
+	case VIDIOCSPICT:
+	{
+		struct video_picture *p = arg;
+
+		/*
+		 *	Sanity check args
+		 */
+		if (p->depth != 24 || p->palette != VIDEO_PALETTE_RGB24)
+			return -EINVAL;
+
+		/*
+		 *	Now load the camera.
+		 */
+		qcam->brightness = p->brightness >> 8;
+		qcam->contrast = p->contrast >> 8;
+		qcam->whitebal = p->whiteness >> 8;
+
+		mutex_lock(&qcam->lock);
+		parport_claim_or_block(qcam->pdev);
+		qc_setup(qcam);
+		parport_release(qcam->pdev);
+		mutex_unlock(&qcam->lock);
+		return 0;
+	}
+	case VIDIOCSWIN:
+	{
+		struct video_window *vw = arg;
+
+		if (vw->flags)
+			return -EINVAL;
+		if (vw->clipcount)
+			return -EINVAL;
+		if (vw->height < 60 || vw->height > 240)
+			return -EINVAL;
+		if (vw->width < 80 || vw->width > 320)
+			return -EINVAL;
+
+		qcam->width = 80;
+		qcam->height = 60;
+		qcam->mode = QC_DECIMATION_4;
+
+		if (vw->width >= 160 && vw->height >= 120) {
+			qcam->width = 160;
+			qcam->height = 120;
+			qcam->mode = QC_DECIMATION_2;
+		}
+		if (vw->width >= 320 && vw->height >= 240) {
+			qcam->width = 320;
+			qcam->height = 240;
+			qcam->mode = QC_DECIMATION_1;
+		}
+		qcam->mode |= QC_MILLIONS;
+#if 0
+		if (vw->width >= 640 && vw->height >= 480) {
+			qcam->width = 640;
+			qcam->height = 480;
+			qcam->mode = QC_BILLIONS | QC_DECIMATION_1;
+		}
+#endif
+		/* Ok we figured out what to use from our
+		   wide choice */
+		mutex_lock(&qcam->lock);
+		parport_claim_or_block(qcam->pdev);
+		qc_setup(qcam);
+		parport_release(qcam->pdev);
+		mutex_unlock(&qcam->lock);
+		return 0;
+	}
+	case VIDIOCGWIN:
+	{
+		struct video_window *vw = arg;
+		memset(vw, 0, sizeof(*vw));
+		vw->width = qcam->width;
+		vw->height = qcam->height;
+		return 0;
+	}
+	case VIDIOCKEY:
+		return 0;
+	case VIDIOCCAPTURE:
+	case VIDIOCGFBUF:
+	case VIDIOCSFBUF:
+	case VIDIOCGFREQ:
+	case VIDIOCSFREQ:
+	case VIDIOCGAUDIO:
+	case VIDIOCSAUDIO:
+		return -EINVAL;
+	default:
+		return -ENOIOCTLCMD;
 	}
 	return 0;
 }
@@ -675,13 +670,13 @@
 			 size_t count, loff_t *ppos)
 {
 	struct video_device *v = video_devdata(file);
-	struct qcam_device *qcam=(struct qcam_device *)v;
+	struct qcam_device *qcam = (struct qcam_device *)v;
 	int len;
 
 	mutex_lock(&qcam->lock);
 	parport_claim_or_block(qcam->pdev);
 	/* Probably should have a semaphore against multiple users */
-	len = qc_capture(qcam, buf,count);
+	len = qc_capture(qcam, buf, count);
 	parport_release(qcam->pdev);
 	mutex_unlock(&qcam->lock);
 	return len;
@@ -713,8 +708,7 @@
 	.read		= qcam_read,
 };
 
-static struct video_device qcam_template=
-{
+static struct video_device qcam_template = {
 	.name		= "Colour QuickCam",
 	.fops           = &qcam_fops,
 	.release 	= video_device_release_empty,
@@ -727,17 +721,16 @@
 	struct qcam_device *q;
 
 	q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL);
-	if(q==NULL)
+	if (q == NULL)
 		return NULL;
 
 	q->pport = port;
 	q->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
 					  NULL, 0, NULL);
 
-	q->bidirectional = (q->pport->modes & PARPORT_MODE_TRISTATE)?1:0;
+	q->bidirectional = (q->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0;
 
-	if (q->pdev == NULL)
-	{
+	if (q->pdev == NULL) {
 		printk(KERN_ERR "c-qcam: couldn't register for %s.\n",
 		       port->name);
 		kfree(q);
@@ -765,12 +758,11 @@
 {
 	struct qcam_device *qcam;
 
-	if (parport[0] != -1)
-	{
+	if (parport[0] != -1) {
 		/* The user gave specific instructions */
 		int i, found = 0;
-		for (i = 0; i < MAX_CAMS && parport[i] != -1; i++)
-		{
+
+		for (i = 0; i < MAX_CAMS && parport[i] != -1; i++) {
 			if (parport[0] == port->number)
 				found = 1;
 		}
@@ -782,15 +774,14 @@
 		return -ENOSPC;
 
 	qcam = qcam_init(port);
-	if (qcam==NULL)
+	if (qcam == NULL)
 		return -ENODEV;
 
 	parport_claim_or_block(qcam->pdev);
 
 	qc_reset(qcam);
 
-	if (probe && qc_detect(qcam)==0)
-	{
+	if (probe && qc_detect(qcam) == 0) {
 		parport_release(qcam->pdev);
 		parport_unregister_device(qcam->pdev);
 		kfree(qcam);
@@ -840,14 +831,14 @@
 	.detach = cq_detach,
 };
 
-static int __init cqcam_init (void)
+static int __init cqcam_init(void)
 {
 	printk(BANNER "\n");
 
 	return parport_register_driver(&cqcam_driver);
 }
 
-static void __exit cqcam_cleanup (void)
+static void __exit cqcam_cleanup(void)
 {
 	unsigned int i;
 
@@ -862,9 +853,9 @@
 MODULE_LICENSE("GPL");
 
 /* FIXME: parport=auto would never have worked, surely? --RR */
-MODULE_PARM_DESC(parport ,"parport=<auto|n[,n]...> for port detection method\n\
-probe=<0|1|2> for camera detection method\n\
-force_rgb=<0|1> for RGB data format (default BGR)");
+MODULE_PARM_DESC(parport, "parport=<auto|n[,n]...> for port detection method\n"
+			  "probe=<0|1|2> for camera detection method\n"
+			  "force_rgb=<0|1> for RGB data format (default BGR)");
 module_param_array(parport, int, NULL, 0);
 module_param(probe, int, 0);
 module_param(force_rgb, bool, 0);
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index 6f91415..5520789 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -324,7 +324,7 @@
 	{
 		if(fh->mmapped)
 			cam->mmapped = 0;
-		v4l2_prio_close(&cam->prio,&fh->prio);
+		v4l2_prio_close(&cam->prio, fh->prio);
 		file->private_data = NULL;
 		kfree(fh);
 	}
@@ -1592,7 +1592,7 @@
 	case VIDIOC_S_FMT:
 	{
 		struct cpia2_fh *fh = file->private_data;
-		retval = v4l2_prio_check(&cam->prio, &fh->prio);
+		retval = v4l2_prio_check(&cam->prio, fh->prio);
 		if(retval) {
 			mutex_unlock(&cam->busy_lock);
 			return retval;
diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c
index 4392c76..0e5006b 100644
--- a/drivers/media/video/cx18/cx18-av-core.c
+++ b/drivers/media/video/cx18/cx18-av-core.c
@@ -579,6 +579,7 @@
 
 	u8 afe_mux_cfg;
 	u8 adc2_cfg;
+	u8 input_mode;
 	u32 afe_cfg;
 	int i;
 
@@ -589,6 +590,30 @@
 	    vid_input <= CX18_AV_COMPOSITE8) {
 		afe_mux_cfg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1);
 		ch[0] = CVBS;
+		input_mode = 0x0;
+	} else if (vid_input >= CX18_AV_COMPONENT_LUMA1) {
+		int luma = vid_input & 0xf000;
+		int r_chroma = vid_input & 0xf0000;
+		int b_chroma = vid_input & 0xf00000;
+
+		if ((vid_input & ~0xfff000) ||
+		    luma < CX18_AV_COMPONENT_LUMA1 ||
+		    luma > CX18_AV_COMPONENT_LUMA8 ||
+		    r_chroma < CX18_AV_COMPONENT_R_CHROMA4 ||
+		    r_chroma > CX18_AV_COMPONENT_R_CHROMA6 ||
+		    b_chroma < CX18_AV_COMPONENT_B_CHROMA7 ||
+		    b_chroma > CX18_AV_COMPONENT_B_CHROMA8) {
+			CX18_ERR_DEV(sd, "0x%06x is not a valid video input!\n",
+				     vid_input);
+			return -EINVAL;
+		}
+		afe_mux_cfg = (luma - CX18_AV_COMPONENT_LUMA1) >> 12;
+		ch[0] = Y;
+		afe_mux_cfg |= (r_chroma - CX18_AV_COMPONENT_R_CHROMA4) >> 12;
+		ch[1] = Pr;
+		afe_mux_cfg |= (b_chroma - CX18_AV_COMPONENT_B_CHROMA7) >> 14;
+		ch[2] = Pb;
+		input_mode = 0x6;
 	} else {
 		int luma = vid_input & 0xf0;
 		int chroma = vid_input & 0xf00;
@@ -598,7 +623,7 @@
 		    luma > CX18_AV_SVIDEO_LUMA8 ||
 		    chroma < CX18_AV_SVIDEO_CHROMA4 ||
 		    chroma > CX18_AV_SVIDEO_CHROMA8) {
-			CX18_ERR_DEV(sd, "0x%04x is not a valid video input!\n",
+			CX18_ERR_DEV(sd, "0x%06x is not a valid video input!\n",
 				     vid_input);
 			return -EINVAL;
 		}
@@ -613,8 +638,8 @@
 			afe_mux_cfg |= (chroma - CX18_AV_SVIDEO_CHROMA4) >> 4;
 			ch[1] = C;
 		}
+		input_mode = 0x2;
 	}
-	/* TODO: LeadTek WinFast DVR3100 H & WinFast PVR2100 can do Y/Pb/Pr */
 
 	switch (aud_input) {
 	case CX18_AV_AUDIO_SERIAL1:
@@ -650,8 +675,8 @@
 
 	/* Set up analog front end multiplexers */
 	cx18_av_write_expect(cx, 0x103, afe_mux_cfg, afe_mux_cfg, 0xf7);
-	/* Set INPUT_MODE to Composite (0) or S-Video (1) */
-	cx18_av_and_or(cx, 0x401, ~0x6, ch[0] == CVBS ? 0 : 0x02);
+	/* Set INPUT_MODE to Composite, S-Video, or Component */
+	cx18_av_and_or(cx, 0x401, ~0x6, input_mode);
 
 	/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
 	adc2_cfg = cx18_av_read(cx, 0x102);
@@ -998,9 +1023,9 @@
 
 static int cx18_av_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
 {
-	struct cx18 *cx = v4l2_get_subdevdata(sd);
-
-	return cx18_av_vbi_g_fmt(cx, fmt);
+	if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+		return -EINVAL;
+	return cx18_av_g_sliced_fmt(sd, &fmt->fmt.sliced);
 }
 
 static int cx18_av_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
@@ -1073,12 +1098,6 @@
 		cx18_av_write(cx, 0x41e, 0x8 | filter);
 		break;
 
-	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-		return cx18_av_vbi_s_fmt(cx, fmt);
-
-	case V4L2_BUF_TYPE_VBI_CAPTURE:
-		return cx18_av_vbi_s_fmt(cx, fmt);
-
 	default:
 		return -EINVAL;
 	}
@@ -1378,17 +1397,24 @@
 
 static const struct v4l2_subdev_video_ops cx18_av_video_ops = {
 	.s_routing = cx18_av_s_video_routing,
-	.decode_vbi_line = cx18_av_decode_vbi_line,
 	.s_stream = cx18_av_s_stream,
 	.g_fmt = cx18_av_g_fmt,
 	.s_fmt = cx18_av_s_fmt,
 };
 
+static const struct v4l2_subdev_vbi_ops cx18_av_vbi_ops = {
+	.decode_vbi_line = cx18_av_decode_vbi_line,
+	.g_sliced_fmt = cx18_av_g_sliced_fmt,
+	.s_sliced_fmt = cx18_av_s_sliced_fmt,
+	.s_raw_fmt = cx18_av_s_raw_fmt,
+};
+
 static const struct v4l2_subdev_ops cx18_av_ops = {
 	.core = &cx18_av_general_ops,
 	.tuner = &cx18_av_tuner_ops,
 	.audio = &cx18_av_audio_ops,
 	.video = &cx18_av_video_ops,
+	.vbi = &cx18_av_vbi_ops,
 };
 
 int cx18_av_probe(struct cx18 *cx)
diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h
index cafb7e9..c106967 100644
--- a/drivers/media/video/cx18/cx18-av-core.h
+++ b/drivers/media/video/cx18/cx18-av-core.h
@@ -61,6 +61,25 @@
 	CX18_AV_SVIDEO2 = 0x620,
 	CX18_AV_SVIDEO3 = 0x730,
 	CX18_AV_SVIDEO4 = 0x840,
+
+	/* Component Video inputs consist of one luma input (In1-In8) ORed
+	   with a red chroma (In4-In6) and blue chroma input (In7-In8) */
+	CX18_AV_COMPONENT_LUMA1 = 0x1000,
+	CX18_AV_COMPONENT_LUMA2 = 0x2000,
+	CX18_AV_COMPONENT_LUMA3 = 0x3000,
+	CX18_AV_COMPONENT_LUMA4 = 0x4000,
+	CX18_AV_COMPONENT_LUMA5 = 0x5000,
+	CX18_AV_COMPONENT_LUMA6 = 0x6000,
+	CX18_AV_COMPONENT_LUMA7 = 0x7000,
+	CX18_AV_COMPONENT_LUMA8 = 0x8000,
+	CX18_AV_COMPONENT_R_CHROMA4 = 0x40000,
+	CX18_AV_COMPONENT_R_CHROMA5 = 0x50000,
+	CX18_AV_COMPONENT_R_CHROMA6 = 0x60000,
+	CX18_AV_COMPONENT_B_CHROMA7 = 0x700000,
+	CX18_AV_COMPONENT_B_CHROMA8 = 0x800000,
+
+	/* Component Video aliases for common combinations */
+	CX18_AV_COMPONENT1 = 0x861000,
 };
 
 enum cx18_av_audio_input {
@@ -359,7 +378,8 @@
 /* cx18_av-vbi.c                                                           */
 int cx18_av_decode_vbi_line(struct v4l2_subdev *sd,
 			   struct v4l2_decode_vbi_line *vbi);
-int cx18_av_vbi_g_fmt(struct cx18 *cx, struct v4l2_format *fmt);
-int cx18_av_vbi_s_fmt(struct cx18 *cx, struct v4l2_format *fmt);
+int cx18_av_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt);
+int cx18_av_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt);
+int cx18_av_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt);
 
 #endif
diff --git a/drivers/media/video/cx18/cx18-av-vbi.c b/drivers/media/video/cx18/cx18-av-vbi.c
index a51732b..baa36fb 100644
--- a/drivers/media/video/cx18/cx18-av-vbi.c
+++ b/drivers/media/video/cx18/cx18-av-vbi.c
@@ -129,10 +129,10 @@
 	return err & 0xf0;
 }
 
-int cx18_av_vbi_g_fmt(struct cx18 *cx, struct v4l2_format *fmt)
+int cx18_av_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
 {
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
 	struct cx18_av_state *state = &cx->av_state;
-	struct v4l2_sliced_vbi_format *svbi;
 	static const u16 lcr2vbi[] = {
 		0, V4L2_SLICED_TELETEXT_B, 0,	/* 1 */
 		0, V4L2_SLICED_WSS_625, 0,	/* 4 */
@@ -143,9 +143,6 @@
 	int is_pal = !(state->std & V4L2_STD_525_60);
 	int i;
 
-	if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
-		return -EINVAL;
-	svbi = &fmt->fmt.sliced;
 	memset(svbi, 0, sizeof(*svbi));
 	/* we're done if raw VBI is active */
 	if ((cx18_av_read(cx, 0x404) & 0x10) == 0)
@@ -173,31 +170,28 @@
 	return 0;
 }
 
-int cx18_av_vbi_s_fmt(struct cx18 *cx, struct v4l2_format *fmt)
+int cx18_av_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt)
 {
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
 	struct cx18_av_state *state = &cx->av_state;
-	struct v4l2_sliced_vbi_format *svbi;
+
+	/* Setup standard */
+	cx18_av_std_setup(cx);
+
+	/* VBI Offset */
+	cx18_av_write(cx, 0x47f, state->slicer_line_delay);
+	cx18_av_write(cx, 0x404, 0x2e);
+	return 0;
+}
+
+int cx18_av_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
+{
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+	struct cx18_av_state *state = &cx->av_state;
 	int is_pal = !(state->std & V4L2_STD_525_60);
 	int i, x;
 	u8 lcr[24];
 
-	if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE &&
-			fmt->type != V4L2_BUF_TYPE_VBI_CAPTURE)
-		return -EINVAL;
-	svbi = &fmt->fmt.sliced;
-	if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-		/* raw VBI */
-		memset(svbi, 0, sizeof(*svbi));
-
-		/* Setup standard */
-		cx18_av_std_setup(cx);
-
-		/* VBI Offset */
-		cx18_av_write(cx, 0x47f, state->slicer_line_delay);
-		cx18_av_write(cx, 0x404, 0x2e);
-		return 0;
-	}
-
 	for (x = 0; x <= 23; x++)
 		lcr[x] = 0x00;
 
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c
index f808fb6..74e122b 100644
--- a/drivers/media/video/cx18/cx18-cards.c
+++ b/drivers/media/video/cx18/cx18-cards.c
@@ -370,6 +370,7 @@
 		{ CX18_CARD_INPUT_SVIDEO1,    1,
 			CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
 		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE7 },
+		{ CX18_CARD_INPUT_COMPONENT1, 1, CX18_AV_COMPONENT1 },
 	},
 	.audio_inputs = {
 		{ CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 	    0 },
@@ -422,6 +423,7 @@
 		{ CX18_CARD_INPUT_SVIDEO1,    1,
 			CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
 		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE7 },
+		{ CX18_CARD_INPUT_COMPONENT1, 1, CX18_AV_COMPONENT1 },
 	},
 	.audio_inputs = {
 		{ CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 	    0 },
@@ -480,7 +482,7 @@
 		"S-Video 2",
 		"Composite 1",
 		"Composite 2",
-		"Composite 3"
+		"Component 1"
 	};
 
 	memset(input, 0, sizeof(*input));
diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h
index af3d716..796e517 100644
--- a/drivers/media/video/cx18/cx18-cards.h
+++ b/drivers/media/video/cx18/cx18-cards.h
@@ -43,7 +43,7 @@
 #define	CX18_CARD_INPUT_SVIDEO2 	3
 #define	CX18_CARD_INPUT_COMPOSITE1 	4
 #define	CX18_CARD_INPUT_COMPOSITE2 	5
-#define	CX18_CARD_INPUT_COMPOSITE3 	6
+#define	CX18_CARD_INPUT_COMPONENT1 	6
 
 /* audio inputs */
 #define	CX18_CARD_INPUT_AUD_TUNER	1
@@ -62,7 +62,7 @@
 struct cx18_card_video_input {
 	u8  video_type; 	/* video input type */
 	u8  audio_index;	/* index in cx18_card_audio_input array */
-	u16 video_input;	/* hardware video input */
+	u32 video_input;	/* hardware video input */
 };
 
 struct cx18_card_audio_input {
diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c
index 7fa5892..4b4b465 100644
--- a/drivers/media/video/cx18/cx18-controls.c
+++ b/drivers/media/video/cx18/cx18-controls.c
@@ -263,7 +263,7 @@
 	int ret;
 	struct v4l2_control ctrl;
 
-	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	ret = v4l2_prio_check(&cx->prio, id->prio);
 	if (ret)
 		return ret;
 
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c
index 863ce77..e12a150 100644
--- a/drivers/media/video/cx18/cx18-fileops.c
+++ b/drivers/media/video/cx18/cx18-fileops.c
@@ -700,7 +700,7 @@
 
 	CX18_DEBUG_IOCTL("close() of %s\n", s->name);
 
-	v4l2_prio_close(&cx->prio, &id->prio);
+	v4l2_prio_close(&cx->prio, id->prio);
 
 	/* Easy case first: this stream was never claimed by us */
 	if (s->id != id->open_id) {
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
index eecf29a..cfa1f28 100644
--- a/drivers/media/video/cx18/cx18-i2c.c
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -109,7 +109,7 @@
 	/* Our default information for ir-kbd-i2c.c to use */
 	switch (hw) {
 	case CX18_HW_Z8F0811_IR_RX_HAUP:
-		init_data->ir_codes = &ir_codes_hauppauge_new_table;
+		init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW;
 		init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
 		init_data->type = IR_TYPE_RC5;
 		init_data->name = cx->card_name;
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index b81dd0e..2530fc5 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -208,7 +208,7 @@
 	 * digitizer/slicer.  Note, cx18_av_vbi() wipes the passed in
 	 * fmt->fmt.sliced under valid calling conditions
 	 */
-	if (v4l2_subdev_call(cx->sd_av, video, g_fmt, fmt))
+	if (v4l2_subdev_call(cx->sd_av, vbi, g_sliced_fmt, &fmt->fmt.sliced))
 		return -EINVAL;
 
 	/* Ensure V4L2 spec compliant output */
@@ -277,7 +277,7 @@
 	int ret;
 	int w, h;
 
-	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	ret = v4l2_prio_check(&cx->prio, id->prio);
 	if (ret)
 		return ret;
 
@@ -306,7 +306,7 @@
 	struct cx18 *cx = id->cx;
 	int ret;
 
-	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	ret = v4l2_prio_check(&cx->prio, id->prio);
 	if (ret)
 		return ret;
 
@@ -322,7 +322,7 @@
 	 * Note cx18_av_vbi_wipes out alot of the passed in fmt under valid
 	 * calling conditions
 	 */
-	ret = v4l2_subdev_call(cx->sd_av, video, s_fmt, fmt);
+	ret = v4l2_subdev_call(cx->sd_av, vbi, s_raw_fmt, &fmt->fmt.vbi);
 	if (ret)
 		return ret;
 
@@ -341,7 +341,7 @@
 	int ret;
 	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
 
-	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	ret = v4l2_prio_check(&cx->prio, id->prio);
 	if (ret)
 		return ret;
 
@@ -359,7 +359,7 @@
 	 * Note, cx18_av_vbi() wipes some "impossible" service lines in the
 	 * passed in fmt->fmt.sliced under valid calling conditions
 	 */
-	ret = v4l2_subdev_call(cx->sd_av, video, s_fmt, fmt);
+	ret = v4l2_subdev_call(cx->sd_av, vbi, s_sliced_fmt, &fmt->fmt.sliced);
 	if (ret)
 		return ret;
 	/* Store our current v4l2 sliced VBI settings */
@@ -549,7 +549,7 @@
 	struct cx18 *cx = id->cx;
 	int ret;
 
-	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	ret = v4l2_prio_check(&cx->prio, id->prio);
 	if (ret)
 		return ret;
 
@@ -601,7 +601,7 @@
 	struct cx18 *cx = id->cx;
 	int ret;
 
-	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	ret = v4l2_prio_check(&cx->prio, id->prio);
 	if (ret)
 		return ret;
 
@@ -647,7 +647,7 @@
 	struct cx18 *cx = id->cx;
 	int ret;
 
-	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	ret = v4l2_prio_check(&cx->prio, id->prio);
 	if (ret)
 		return ret;
 
@@ -675,7 +675,7 @@
 	struct cx18 *cx = id->cx;
 	int ret;
 
-	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	ret = v4l2_prio_check(&cx->prio, id->prio);
 	if (ret)
 		return ret;
 
@@ -715,7 +715,7 @@
 	struct cx18 *cx = id->cx;
 	int ret;
 
-	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	ret = v4l2_prio_check(&cx->prio, id->prio);
 	if (ret)
 		return ret;
 
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index 054450f..f5c9126 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -374,7 +374,10 @@
 	}
 
 	/* setup VBI registers */
-	v4l2_subdev_call(cx->sd_av, video, s_fmt, &cx->vbi.in);
+	if (raw)
+		v4l2_subdev_call(cx->sd_av, vbi, s_raw_fmt, &cx->vbi.in.fmt.vbi);
+	else
+		v4l2_subdev_call(cx->sd_av, vbi, s_sliced_fmt, &cx->vbi.in.fmt.sliced);
 
 	/*
 	 * Send the CX18_CPU_SET_RAW_VBI_PARAM API command to setup Encoder Raw
diff --git a/drivers/media/video/cx18/cx18-vbi.c b/drivers/media/video/cx18/cx18-vbi.c
index 574c1c6..5822275 100644
--- a/drivers/media/video/cx18/cx18-vbi.c
+++ b/drivers/media/video/cx18/cx18-vbi.c
@@ -174,7 +174,7 @@
 		     p[3] != sliced_vbi_eav_rp[1]))
 			continue;
 		vbi.p = p + 4;
-		v4l2_subdev_call(cx->sd_av, video, decode_vbi_line, &vbi);
+		v4l2_subdev_call(cx->sd_av, vbi, decode_vbi_line, &vbi);
 		if (vbi.type) {
 			cx->vbi.sliced_data[line].id = vbi.type;
 			cx->vbi.sliced_data[line].field = vbi.is_second_field;
diff --git a/drivers/media/video/cx231xx/cx231xx-audio.c b/drivers/media/video/cx231xx/cx231xx-audio.c
index 7793d60..7cae95a 100644
--- a/drivers/media/video/cx231xx/cx231xx-audio.c
+++ b/drivers/media/video/cx231xx/cx231xx-audio.c
@@ -495,7 +495,7 @@
 	pcm->info_flags = 0;
 	pcm->private_data = dev;
 	strcpy(pcm->name, "Conexant cx231xx Capture");
-	strcpy(card->driver, "Conexant cx231xx Audio");
+	strcpy(card->driver, "Cx231xx-Audio");
 	strcpy(card->shortname, "Cx231xx Audio");
 	strcpy(card->longname, "Conexant cx231xx Audio");
 
diff --git a/drivers/media/video/cx231xx/cx231xx-core.c b/drivers/media/video/cx231xx/cx231xx-core.c
index b24eee1..f5e1a23 100644
--- a/drivers/media/video/cx231xx/cx231xx-core.c
+++ b/drivers/media/video/cx231xx/cx231xx-core.c
@@ -96,10 +96,9 @@
 	mutex_lock(&cx231xx_devlist_mutex);
 	mutex_lock(&cx231xx_extension_devlist_lock);
 	list_add_tail(&ops->next, &cx231xx_extension_devlist);
-	list_for_each_entry(dev, &cx231xx_devlist, devlist) {
-		if (dev)
-			ops->init(dev);
-	}
+	list_for_each_entry(dev, &cx231xx_devlist, devlist)
+		ops->init(dev);
+
 	printk(KERN_INFO DRIVER_NAME ": %s initialized\n", ops->name);
 	mutex_unlock(&cx231xx_extension_devlist_lock);
 	mutex_unlock(&cx231xx_devlist_mutex);
@@ -112,10 +111,8 @@
 	struct cx231xx *dev = NULL;
 
 	mutex_lock(&cx231xx_devlist_mutex);
-	list_for_each_entry(dev, &cx231xx_devlist, devlist) {
-		if (dev)
-			ops->fini(dev);
-	}
+	list_for_each_entry(dev, &cx231xx_devlist, devlist)
+		ops->fini(dev);
 
 	mutex_lock(&cx231xx_extension_devlist_lock);
 	printk(KERN_INFO DRIVER_NAME ": %s removed\n", ops->name);
diff --git a/drivers/media/video/cx231xx/cx231xx-input.c b/drivers/media/video/cx231xx/cx231xx-input.c
index b473cd8..fd09915 100644
--- a/drivers/media/video/cx231xx/cx231xx-input.c
+++ b/drivers/media/video/cx231xx/cx231xx-input.c
@@ -35,6 +35,8 @@
 module_param(ir_debug, int, 0644);
 MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
 
+#define MODULE_NAME "cx231xx"
+
 #define i2cdprintk(fmt, arg...) \
 	if (ir_debug) { \
 		printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
@@ -59,7 +61,6 @@
 struct cx231xx_IR {
 	struct cx231xx *dev;
 	struct input_dev *input;
-	struct ir_input_state ir;
 	char name[32];
 	char phys[32];
 
@@ -67,9 +68,7 @@
 	int polling;
 	struct work_struct work;
 	struct timer_list timer;
-	unsigned int last_toggle:1;
 	unsigned int last_readcount;
-	unsigned int repeat_interval;
 
 	int (*get_key) (struct cx231xx_IR *, struct cx231xx_ir_poll_result *);
 };
@@ -81,7 +80,6 @@
 static void cx231xx_ir_handle_key(struct cx231xx_IR *ir)
 {
 	int result;
-	int do_sendkey = 0;
 	struct cx231xx_ir_poll_result poll_result;
 
 	/* read the registers containing the IR status */
@@ -95,44 +93,23 @@
 		poll_result.toggle_bit, poll_result.read_count,
 		ir->last_readcount, poll_result.rc_data[0]);
 
-	if (ir->dev->chip_id == CHIP_ID_EM2874) {
+	if (poll_result.read_count > 0 &&
+	    poll_result.read_count != ir->last_readcount)
+		ir_keydown(ir->input,
+			   poll_result.rc_data[0],
+			   poll_result.toggle_bit);
+
+	if (ir->dev->chip_id == CHIP_ID_EM2874)
 		/* The em2874 clears the readcount field every time the
 		   register is read.  The em2860/2880 datasheet says that it
 		   is supposed to clear the readcount, but it doesn't.  So with
 		   the em2874, we are looking for a non-zero read count as
 		   opposed to a readcount that is incrementing */
 		ir->last_readcount = 0;
+	else
+		ir->last_readcount = poll_result.read_count;
+
 	}
-
-	if (poll_result.read_count == 0) {
-		/* The button has not been pressed since the last read */
-	} else if (ir->last_toggle != poll_result.toggle_bit) {
-		/* A button has been pressed */
-		dprintk("button has been pressed\n");
-		ir->last_toggle = poll_result.toggle_bit;
-		ir->repeat_interval = 0;
-		do_sendkey = 1;
-	} else if (poll_result.toggle_bit == ir->last_toggle &&
-		   poll_result.read_count > 0 &&
-		   poll_result.read_count != ir->last_readcount) {
-		/* The button is still being held down */
-		dprintk("button being held down\n");
-
-		/* Debouncer for first keypress */
-		if (ir->repeat_interval++ > 9) {
-			/* Start repeating after 1 second */
-			do_sendkey = 1;
-		}
-	}
-
-	if (do_sendkey) {
-		dprintk("sending keypress\n");
-		ir_input_keydown(ir->input, &ir->ir, poll_result.rc_data[0]);
-		ir_input_nokey(ir->input, &ir->ir);
-	}
-
-	ir->last_readcount = poll_result.read_count;
-	return;
 }
 
 static void ir_timer(unsigned long data)
@@ -198,10 +175,6 @@
 	usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
 	strlcat(ir->phys, "/input0", sizeof(ir->phys));
 
-	err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER);
-	if (err < 0)
-		goto err_out_free;
-
 	input_dev->name = ir->name;
 	input_dev->phys = ir->phys;
 	input_dev->id.bustype = BUS_USB;
@@ -217,7 +190,8 @@
 	cx231xx_ir_start(ir);
 
 	/* all done */
-	err = ir_input_register(ir->input, dev->board.ir_codes, NULL);
+	err = __ir_input_register(ir->input, dev->board.ir_codes,
+				NULL, MODULE_NAME);
 	if (err)
 		goto err_out_stop;
 
diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c
index 16a73ea..2782709 100644
--- a/drivers/media/video/cx231xx/cx231xx-video.c
+++ b/drivers/media/video/cx231xx/cx231xx-video.c
@@ -1669,7 +1669,7 @@
 
 	f->fmt.sliced.service_set = 0;
 
-	call_all(dev, video, g_fmt, f);
+	call_all(dev, vbi, g_sliced_fmt, &f->fmt.sliced);
 
 	if (f->fmt.sliced.service_set == 0)
 		rc = -EINVAL;
@@ -1690,7 +1690,7 @@
 		return rc;
 
 	mutex_lock(&dev->lock);
-	call_all(dev, video, g_fmt, f);
+	call_all(dev, vbi, g_sliced_fmt, &f->fmt.sliced);
 	mutex_unlock(&dev->lock);
 
 	if (f->fmt.sliced.service_set == 0)
@@ -1902,9 +1902,12 @@
 	if (c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1)
 		return -EINVAL;
 	if (c->id == V4L2_CID_AUDIO_MUTE) {
-		for (i = 0; i < CX231XX_CTLS; i++)
+		for (i = 0; i < CX231XX_CTLS; i++) {
 			if (cx231xx_ctls[i].v.id == c->id)
 				break;
+		}
+		if (i == CX231XX_CTLS)
+			return -EINVAL;
 		*c = cx231xx_ctls[i].v;
 	} else
 		*c = no_ctl;
diff --git a/drivers/media/video/cx231xx/cx231xx.h b/drivers/media/video/cx231xx/cx231xx.h
index 17d4d1a..38d4171 100644
--- a/drivers/media/video/cx231xx/cx231xx.h
+++ b/drivers/media/video/cx231xx/cx231xx.h
@@ -32,7 +32,7 @@
 
 #include <media/videobuf-vmalloc.h>
 #include <media/v4l2-device.h>
-#include <media/ir-kbd-i2c.h>
+#include <media/ir-core.h>
 #if defined(CONFIG_VIDEO_CX231XX_DVB) || \
 	defined(CONFIG_VIDEO_CX231XX_DVB_MODULE)
 #include <media/videobuf-dvb.h>
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
index 4c8e958..022b480 100644
--- a/drivers/media/video/cx2341x.c
+++ b/drivers/media/video/cx2341x.c
@@ -1000,20 +1000,6 @@
 				  h, w);
 		if (err) return err;
 	}
-
-	if (new->width != 720 || new->height != (new->is_50hz ? 576 : 480)) {
-		/* Adjust temporal filter if necessary. The problem with the
-		   temporal filter is that it works well with full resolution
-		   capturing, but not when the capture window is scaled (the
-		   filter introduces a ghosting effect). So if the capture
-		   window is scaled, then force the filter to 0.
-
-		   For full resolution the filter really improves the video
-		   quality, especially if the original video quality is
-		   suboptimal. */
-		temporal = 0;
-	}
-
 	if (force || NEQ(stream_type)) {
 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1,
 				  mpeg_stream_type[new->stream_type]);
diff --git a/drivers/media/video/cx23885/cimax2.c b/drivers/media/video/cx23885/cimax2.c
index d4a9d2c..c95e7bc 100644
--- a/drivers/media/video/cx23885/cimax2.c
+++ b/drivers/media/video/cx23885/cimax2.c
@@ -60,12 +60,18 @@
 module_param(ci_dbg, int, 0644);
 MODULE_PARM_DESC(ci_dbg, "Enable CI debugging");
 
+static unsigned int ci_irq_enable;
+module_param(ci_irq_enable, int, 0644);
+MODULE_PARM_DESC(ci_irq_enable, "Enable IRQ from CAM");
+
 #define ci_dbg_print(args...) \
 	do { \
 		if (ci_dbg) \
 			printk(KERN_DEBUG args); \
 	} while (0)
 
+#define ci_irq_flags() (ci_irq_enable ? NETUP_IRQ_IRQAM : 0)
+
 /* stores all private variables for communication with CI */
 struct netup_ci_state {
 	struct dvb_ca_en50221 ca;
@@ -392,7 +398,7 @@
 	if (0 != slot)
 		return -EINVAL;
 
-	netup_ci_set_irq(en50221, open ? (NETUP_IRQ_DETAM | NETUP_IRQ_IRQAM)
+	netup_ci_set_irq(en50221, open ? (NETUP_IRQ_DETAM | ci_irq_flags())
 			: NETUP_IRQ_DETAM);
 
 	return state->status;
@@ -429,7 +435,7 @@
 		0x01, /* power on (use it like store place) */
 		0x00, /* RFU */
 		0x00, /* int status read only */
-		NETUP_IRQ_IRQAM | NETUP_IRQ_DETAM, /* DETAM, IRQAM unmasked */
+		ci_irq_flags() | NETUP_IRQ_DETAM, /* DETAM, IRQAM unmasked */
 		0x05, /* EXTINT=active-high, INT=push-pull */
 		0x00, /* USCG1 */
 		0x04, /* ack active low */
@@ -470,7 +476,7 @@
 	state->ca.poll_slot_status = netup_poll_ci_slot_status;
 	state->ca.data = state;
 	state->priv = port;
-	state->current_irq_mode = NETUP_IRQ_IRQAM | NETUP_IRQ_DETAM;
+	state->current_irq_mode = ci_irq_flags() | NETUP_IRQ_DETAM;
 
 	ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
 						0, &cimax_init[0], 34);
diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c
index a8ddc22..abd64e8 100644
--- a/drivers/media/video/cx23885/cx23885-417.c
+++ b/drivers/media/video/cx23885/cx23885-417.c
@@ -1356,7 +1356,7 @@
 	struct cx23885_dev *dev = fh->dev;
 	struct cx23885_tsport  *tsport = &dev->ts1;
 
-	strcpy(cap->driver, dev->name);
+	strlcpy(cap->driver, dev->name, sizeof(cap->driver));
 	strlcpy(cap->card, cx23885_boards[tsport->dev->board].name,
 		sizeof(cap->card));
 	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index 939079d..9e14608 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -1006,6 +1006,22 @@
 		netup_ci_init(port);
 		break;
 		}
+	case CX23885_BOARD_TEVII_S470: {
+		u8 eeprom[256]; /* 24C02 i2c eeprom */
+
+		if (port->nr != 1)
+			break;
+
+		/* Read entire EEPROM */
+		dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
+		tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom));
+		printk(KERN_INFO "TeVii S470 MAC= "
+				"%02X:%02X:%02X:%02X:%02X:%02X\n",
+				eeprom[0xa0], eeprom[0xa1], eeprom[0xa2],
+				eeprom[0xa3], eeprom[0xa4], eeprom[0xa5]);
+		memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6);
+		break;
+		}
 	}
 
 	return ret;
diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c
index 8e9d990..8d306d8 100644
--- a/drivers/media/video/cx23885/cx23885-input.c
+++ b/drivers/media/video/cx23885/cx23885-input.c
@@ -51,6 +51,8 @@
 
 #define RC5_EXTENDED_COMMAND_OFFSET	64
 
+#define MODULE_NAME "cx23885"
+
 static inline unsigned int rc5_command(u32 rc5_baseband)
 {
 	return RC5_INSTR(rc5_baseband) +
@@ -338,7 +340,7 @@
 {
 	struct card_ir *ir;
 	struct input_dev *input_dev;
-	struct ir_scancode_table *ir_codes = NULL;
+	char *ir_codes = NULL;
 	int ir_type, ir_addr, ir_start;
 	int ret;
 
@@ -353,7 +355,7 @@
 	case CX23885_BOARD_HAUPPAUGE_HVR1850:
 	case CX23885_BOARD_HAUPPAUGE_HVR1290:
 		/* Parameters for the grey Hauppauge remote for the HVR-1850 */
-		ir_codes = &ir_codes_hauppauge_new_table;
+		ir_codes = RC_MAP_HAUPPAUGE_NEW;
 		ir_type = IR_TYPE_RC5;
 		ir_addr = 0x1e; /* RC-5 system bits emitted by the remote */
 		ir_start = RC5_START_BITS_NORMAL; /* A basic RC-5 remote */
@@ -398,7 +400,7 @@
 	dev->ir_input = ir;
 	cx23885_input_ir_start(dev);
 
-	ret = ir_input_register(ir->dev, ir_codes, NULL);
+	ret = ir_input_register(ir->dev, ir_codes, NULL, MODULE_NAME);
 	if (ret)
 		goto err_out_stop;
 
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c
index 2d3ac8b..543b854 100644
--- a/drivers/media/video/cx23885/cx23885-video.c
+++ b/drivers/media/video/cx23885/cx23885-video.c
@@ -514,8 +514,8 @@
 	*size = fh->fmt->depth*fh->width*fh->height >> 3;
 	if (0 == *count)
 		*count = 32;
-	while (*size * *count > vid_limit * 1024 * 1024)
-		(*count)--;
+	if (*size * *count > vid_limit * 1024 * 1024)
+		*count = (vid_limit * 1024 * 1024) / *size;
 	return 0;
 }
 
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index f2461cd..8b6fb35 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -1018,7 +1018,7 @@
 {
 	switch (fmt->type) {
 	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-		return cx25840_vbi_g_fmt(sd, fmt);
+		return cx25840_g_sliced_fmt(sd, &fmt->fmt.sliced);
 	default:
 		return -EINVAL;
 	}
@@ -1079,12 +1079,6 @@
 		cx25840_write(client, 0x41e, 0x8 | filter);
 		break;
 
-	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-		return cx25840_vbi_s_fmt(sd, fmt);
-
-	case V4L2_BUF_TYPE_VBI_CAPTURE:
-		return cx25840_vbi_s_fmt(sd, fmt);
-
 	default:
 		return -EINVAL;
 	}
@@ -1635,15 +1629,22 @@
 	.s_routing = cx25840_s_video_routing,
 	.g_fmt = cx25840_g_fmt,
 	.s_fmt = cx25840_s_fmt,
-	.decode_vbi_line = cx25840_decode_vbi_line,
 	.s_stream = cx25840_s_stream,
 };
 
+static const struct v4l2_subdev_vbi_ops cx25840_vbi_ops = {
+	.decode_vbi_line = cx25840_decode_vbi_line,
+	.s_raw_fmt = cx25840_s_raw_fmt,
+	.s_sliced_fmt = cx25840_s_sliced_fmt,
+	.g_sliced_fmt = cx25840_g_sliced_fmt,
+};
+
 static const struct v4l2_subdev_ops cx25840_ops = {
 	.core = &cx25840_core_ops,
 	.tuner = &cx25840_tuner_ops,
 	.audio = &cx25840_audio_ops,
 	.video = &cx25840_video_ops,
+	.vbi = &cx25840_vbi_ops,
 };
 
 /* ----------------------------------------------------------------------- */
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h
index 5534544..04393b9 100644
--- a/drivers/media/video/cx25840/cx25840-core.h
+++ b/drivers/media/video/cx25840/cx25840-core.h
@@ -99,8 +99,9 @@
 
 /* ----------------------------------------------------------------------- */
 /* cx25850-vbi.c                                                           */
-int cx25840_vbi_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt);
-int cx25840_vbi_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt);
+int cx25840_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt);
+int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt);
+int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt);
 int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi);
 
 #endif
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
index 35f6592..64a4004 100644
--- a/drivers/media/video/cx25840/cx25840-vbi.c
+++ b/drivers/media/video/cx25840/cx25840-vbi.c
@@ -82,11 +82,10 @@
 	return err & 0xf0;
 }
 
-int cx25840_vbi_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	struct cx25840_state *state = to_state(sd);
-	struct v4l2_sliced_vbi_format *svbi;
 	static const u16 lcr2vbi[] = {
 		0, V4L2_SLICED_TELETEXT_B, 0,	/* 1 */
 		0, V4L2_SLICED_WSS_625, 0,	/* 4 */
@@ -97,9 +96,6 @@
 	int is_pal = !(state->std & V4L2_STD_525_60);
 	int i;
 
-	if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
-		return -EINVAL;
-	svbi = &fmt->fmt.sliced;
 	memset(svbi, 0, sizeof(*svbi));
 	/* we're done if raw VBI is active */
 	if ((cx25840_read(client, 0x404) & 0x10) == 0)
@@ -127,33 +123,31 @@
 	return 0;
 }
 
-int cx25840_vbi_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+int cx25840_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	struct cx25840_state *state = to_state(sd);
-	struct v4l2_sliced_vbi_format *svbi;
+	int is_pal = !(state->std & V4L2_STD_525_60);
+	int vbi_offset = is_pal ? 1 : 0;
+
+	/* Setup standard */
+	cx25840_std_setup(client);
+
+	/* VBI Offset */
+	cx25840_write(client, 0x47f, vbi_offset);
+	cx25840_write(client, 0x404, 0x2e);
+	return 0;
+}
+
+int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct cx25840_state *state = to_state(sd);
 	int is_pal = !(state->std & V4L2_STD_525_60);
 	int vbi_offset = is_pal ? 1 : 0;
 	int i, x;
 	u8 lcr[24];
 
-	if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE &&
-			fmt->type != V4L2_BUF_TYPE_VBI_CAPTURE)
-		return -EINVAL;
-	svbi = &fmt->fmt.sliced;
-	if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-		/* raw VBI */
-		memset(svbi, 0, sizeof(*svbi));
-
-		/* Setup standard */
-		cx25840_std_setup(client);
-
-		/* VBI Offset */
-		cx25840_write(client, 0x47f, vbi_offset);
-		cx25840_write(client, 0x404, 0x2e);
-		return 0;
-	}
-
 	for (x = 0; x <= 23; x++)
 		lcr[x] = 0x00;
 
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index b354111..8b21457 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -847,7 +847,8 @@
 {
 	v4l2_std_id norm = core->tvnorm;
 
-	if (CX88_VMUX_TELEVISION != INPUT(core->input).type)
+	if (CX88_VMUX_TELEVISION != INPUT(core->input).type &&
+	    CX88_VMUX_CABLE != INPUT(core->input).type)
 		return 0;
 
 	if (V4L2_STD_PAL_BG & norm) {
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 94ab862..faa8e81 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -1231,7 +1231,7 @@
 				fe->ops.tuner_ops.set_config(fe, &ctl);
 		}
 		break;
-	 case CX88_BOARD_PINNACLE_HYBRID_PCTV:
+	case CX88_BOARD_PINNACLE_HYBRID_PCTV:
 	case CX88_BOARD_WINFAST_DTV1800H:
 		fe0->dvb.frontend = dvb_attach(zl10353_attach,
 					       &cx88_pinnacle_hybrid_pctv,
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index 6b6abf0..e185289 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -32,12 +32,18 @@
 #include "cx88.h"
 #include <media/ir-common.h>
 
+#define MODULE_NAME "cx88xx"
+
 /* ---------------------------------------------------------------------- */
 
 struct cx88_IR {
 	struct cx88_core *core;
 	struct input_dev *input;
 	struct ir_input_state ir;
+	struct ir_dev_props props;
+
+	int users;
+
 	char name[32];
 	char phys[32];
 
@@ -159,8 +165,16 @@
 	return HRTIMER_RESTART;
 }
 
-void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir)
+static int __cx88_ir_start(void *priv)
 {
+	struct cx88_core *core = priv;
+	struct cx88_IR *ir;
+
+	if (!core || !core->ir)
+		return -EINVAL;
+
+	ir = core->ir;
+
 	if (ir->polling) {
 		hrtimer_init(&ir->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 		ir->timer.function = cx88_ir_work;
@@ -173,10 +187,18 @@
 		cx_write(MO_DDS_IO, 0xa80a80);	/* 4 kHz sample rate */
 		cx_write(MO_DDSCFG_IO, 0x5);	/* enable */
 	}
+	return 0;
 }
 
-void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir)
+static void __cx88_ir_stop(void *priv)
 {
+	struct cx88_core *core = priv;
+	struct cx88_IR *ir;
+
+	if (!core || !core->ir)
+		return;
+
+	ir = core->ir;
 	if (ir->sampling) {
 		cx_write(MO_DDSCFG_IO, 0x0);
 		core->pci_irqmask &= ~PCI_INT_IR_SMPINT;
@@ -186,15 +208,49 @@
 		hrtimer_cancel(&ir->timer);
 }
 
+int cx88_ir_start(struct cx88_core *core)
+{
+	if (core->ir->users)
+		return __cx88_ir_start(core);
+
+	return 0;
+}
+
+void cx88_ir_stop(struct cx88_core *core)
+{
+	if (core->ir->users)
+		__cx88_ir_stop(core);
+}
+
+static int cx88_ir_open(void *priv)
+{
+	struct cx88_core *core = priv;
+
+	core->ir->users++;
+	return __cx88_ir_start(core);
+}
+
+static void cx88_ir_close(void *priv)
+{
+	struct cx88_core *core = priv;
+
+	core->ir->users--;
+	if (!core->ir->users)
+		__cx88_ir_stop(core);
+}
+
 /* ---------------------------------------------------------------------- */
 
 int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
 {
 	struct cx88_IR *ir;
 	struct input_dev *input_dev;
-	struct ir_scancode_table *ir_codes = NULL;
+	char *ir_codes = NULL;
 	u64 ir_type = IR_TYPE_OTHER;
 	int err = -ENOMEM;
+	u32 hardware_mask = 0;	/* For devices with a hardware mask, when
+				 * used with a full-code IR table
+				 */
 
 	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
 	input_dev = input_allocate_device();
@@ -208,15 +264,15 @@
 	case CX88_BOARD_DNTV_LIVE_DVB_T:
 	case CX88_BOARD_KWORLD_DVB_T:
 	case CX88_BOARD_KWORLD_DVB_T_CX22702:
-		ir_codes = &ir_codes_dntv_live_dvb_t_table;
+		ir_codes = RC_MAP_DNTV_LIVE_DVB_T;
 		ir->gpio_addr = MO_GP1_IO;
 		ir->mask_keycode = 0x1f;
 		ir->mask_keyup = 0x60;
 		ir->polling = 50; /* ms */
 		break;
 	case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
-		ir_codes = &ir_codes_cinergy_1400_table;
-		ir_type = IR_TYPE_PD;
+		ir_codes = RC_MAP_CINERGY_1400;
+		ir_type = IR_TYPE_NEC;
 		ir->sampling = 0xeb04; /* address */
 		break;
 	case CX88_BOARD_HAUPPAUGE:
@@ -230,14 +286,14 @@
 	case CX88_BOARD_PCHDTV_HD3000:
 	case CX88_BOARD_PCHDTV_HD5500:
 	case CX88_BOARD_HAUPPAUGE_IRONLY:
-		ir_codes = &ir_codes_hauppauge_new_table;
+		ir_codes = RC_MAP_HAUPPAUGE_NEW;
 		ir_type = IR_TYPE_RC5;
 		ir->sampling = 1;
 		break;
 	case CX88_BOARD_WINFAST_DTV2000H:
 	case CX88_BOARD_WINFAST_DTV2000H_J:
 	case CX88_BOARD_WINFAST_DTV1800H:
-		ir_codes = &ir_codes_winfast_table;
+		ir_codes = RC_MAP_WINFAST;
 		ir->gpio_addr = MO_GP0_IO;
 		ir->mask_keycode = 0x8f8;
 		ir->mask_keyup = 0x100;
@@ -246,14 +302,14 @@
 	case CX88_BOARD_WINFAST2000XP_EXPERT:
 	case CX88_BOARD_WINFAST_DTV1000:
 	case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
-		ir_codes = &ir_codes_winfast_table;
+		ir_codes = RC_MAP_WINFAST;
 		ir->gpio_addr = MO_GP0_IO;
 		ir->mask_keycode = 0x8f8;
 		ir->mask_keyup = 0x100;
 		ir->polling = 1; /* ms */
 		break;
 	case CX88_BOARD_IODATA_GVBCTV7E:
-		ir_codes = &ir_codes_iodata_bctv7e_table;
+		ir_codes = RC_MAP_IODATA_BCTV7E;
 		ir->gpio_addr = MO_GP0_IO;
 		ir->mask_keycode = 0xfd;
 		ir->mask_keydown = 0x02;
@@ -261,36 +317,43 @@
 		break;
 	case CX88_BOARD_PROLINK_PLAYTVPVR:
 	case CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO:
-		ir_codes = &ir_codes_pixelview_table;
+		/*
+		 * It seems that this hardware is paired with NEC extended
+		 * address 0x866b. So, unfortunately, its usage with other
+		 * IR's with different address won't work. Still, there are
+		 * other IR's from the same manufacturer that works, like the
+		 * 002-T mini RC, provided with newer PV hardware
+		 */
+		ir_codes = RC_MAP_PIXELVIEW_MK12;
 		ir->gpio_addr = MO_GP1_IO;
-		ir->mask_keycode = 0x1f;
 		ir->mask_keyup = 0x80;
-		ir->polling = 1; /* ms */
+		ir->polling = 10; /* ms */
+		hardware_mask = 0x3f;	/* Hardware returns only 6 bits from command part */
 		break;
 	case CX88_BOARD_PROLINK_PV_8000GT:
 	case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME:
-		ir_codes = &ir_codes_pixelview_new_table;
+		ir_codes = RC_MAP_PIXELVIEW_NEW;
 		ir->gpio_addr = MO_GP1_IO;
 		ir->mask_keycode = 0x3f;
 		ir->mask_keyup = 0x80;
 		ir->polling = 1; /* ms */
 		break;
 	case CX88_BOARD_KWORLD_LTV883:
-		ir_codes = &ir_codes_pixelview_table;
+		ir_codes = RC_MAP_PIXELVIEW;
 		ir->gpio_addr = MO_GP1_IO;
 		ir->mask_keycode = 0x1f;
 		ir->mask_keyup = 0x60;
 		ir->polling = 1; /* ms */
 		break;
 	case CX88_BOARD_ADSTECH_DVB_T_PCI:
-		ir_codes = &ir_codes_adstech_dvb_t_pci_table;
+		ir_codes = RC_MAP_ADSTECH_DVB_T_PCI;
 		ir->gpio_addr = MO_GP1_IO;
 		ir->mask_keycode = 0xbf;
 		ir->mask_keyup = 0x40;
 		ir->polling = 50; /* ms */
 		break;
 	case CX88_BOARD_MSI_TVANYWHERE_MASTER:
-		ir_codes = &ir_codes_msi_tvanywhere_table;
+		ir_codes = RC_MAP_MSI_TVANYWHERE;
 		ir->gpio_addr = MO_GP1_IO;
 		ir->mask_keycode = 0x1f;
 		ir->mask_keyup = 0x40;
@@ -298,7 +361,7 @@
 		break;
 	case CX88_BOARD_AVERTV_303:
 	case CX88_BOARD_AVERTV_STUDIO_303:
-		ir_codes         = &ir_codes_avertv_303_table;
+		ir_codes         = RC_MAP_AVERTV_303;
 		ir->gpio_addr    = MO_GP2_IO;
 		ir->mask_keycode = 0xfb;
 		ir->mask_keydown = 0x02;
@@ -311,41 +374,41 @@
 	case CX88_BOARD_PROF_7300:
 	case CX88_BOARD_PROF_7301:
 	case CX88_BOARD_PROF_6200:
-		ir_codes = &ir_codes_tbs_nec_table;
-		ir_type = IR_TYPE_PD;
+		ir_codes = RC_MAP_TBS_NEC;
+		ir_type = IR_TYPE_NEC;
 		ir->sampling = 0xff00; /* address */
 		break;
 	case CX88_BOARD_TEVII_S460:
 	case CX88_BOARD_TEVII_S420:
-		ir_codes = &ir_codes_tevii_nec_table;
-		ir_type = IR_TYPE_PD;
+		ir_codes = RC_MAP_TEVII_NEC;
+		ir_type = IR_TYPE_NEC;
 		ir->sampling = 0xff00; /* address */
 		break;
 	case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
-		ir_codes         = &ir_codes_dntv_live_dvbt_pro_table;
-		ir_type          = IR_TYPE_PD;
+		ir_codes         = RC_MAP_DNTV_LIVE_DVBT_PRO;
+		ir_type          = IR_TYPE_NEC;
 		ir->sampling     = 0xff00; /* address */
 		break;
 	case CX88_BOARD_NORWOOD_MICRO:
-		ir_codes         = &ir_codes_norwood_table;
+		ir_codes         = RC_MAP_NORWOOD;
 		ir->gpio_addr    = MO_GP1_IO;
 		ir->mask_keycode = 0x0e;
 		ir->mask_keyup   = 0x80;
 		ir->polling      = 50; /* ms */
 		break;
 	case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
-		ir_codes         = &ir_codes_npgtech_table;
+		ir_codes         = RC_MAP_NPGTECH;
 		ir->gpio_addr    = MO_GP0_IO;
 		ir->mask_keycode = 0xfa;
 		ir->polling      = 50; /* ms */
 		break;
 	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
-		ir_codes         = &ir_codes_pinnacle_pctv_hd_table;
+		ir_codes         = RC_MAP_PINNACLE_PCTV_HD;
 		ir_type          = IR_TYPE_RC5;
 		ir->sampling     = 1;
 		break;
 	case CX88_BOARD_POWERCOLOR_REAL_ANGEL:
-		ir_codes         = &ir_codes_powercolor_real_angel_table;
+		ir_codes         = RC_MAP_POWERCOLOR_REAL_ANGEL;
 		ir->gpio_addr    = MO_GP2_IO;
 		ir->mask_keycode = 0x7e;
 		ir->polling      = 100; /* ms */
@@ -357,6 +420,21 @@
 		goto err_out_free;
 	}
 
+	/*
+	 * The usage of mask_keycode were very convenient, due to several
+	 * reasons. Among others, the scancode tables were using the scancode
+	 * as the index elements. So, the less bits it was used, the smaller
+	 * the table were stored. After the input changes, the better is to use
+	 * the full scancodes, since it allows replacing the IR remote by
+	 * another one. Unfortunately, there are still some hardware, like
+	 * Pixelview Ultra Pro, where only part of the scancode is sent via
+	 * GPIO. So, there's no way to get the full scancode. Due to that,
+	 * hardware_mask were introduced here: it represents those hardware
+	 * that has such limits.
+	 */
+	if (hardware_mask && !ir->mask_keycode)
+		ir->mask_keycode = hardware_mask;
+
 	/* init input device */
 	snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name);
 	snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci));
@@ -381,19 +459,20 @@
 	ir->core = core;
 	core->ir = ir;
 
-	cx88_ir_start(core, ir);
+	ir->props.priv = core;
+	ir->props.open = cx88_ir_open;
+	ir->props.close = cx88_ir_close;
+	ir->props.scanmask = hardware_mask;
 
 	/* all done */
-	err = ir_input_register(ir->input, ir_codes, NULL);
+	err = ir_input_register(ir->input, ir_codes, &ir->props, MODULE_NAME);
 	if (err)
-		goto err_out_stop;
+		goto err_out_free;
 
 	return 0;
 
- err_out_stop:
-	cx88_ir_stop(core, ir);
-	core->ir = NULL;
  err_out_free:
+	core->ir = NULL;
 	kfree(ir);
 	return err;
 }
@@ -406,7 +485,7 @@
 	if (NULL == ir)
 		return 0;
 
-	cx88_ir_stop(core, ir);
+	cx88_ir_stop(core);
 	ir_input_unregister(ir->input);
 	kfree(ir);
 
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index 6aba7af..499f8d5 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -599,13 +599,22 @@
 static int cx8802_request_acquire(struct cx8802_driver *drv)
 {
 	struct cx88_core *core = drv->core;
+	unsigned int	i;
 
 	/* Fail a request for hardware if the device is busy. */
 	if (core->active_type_id != CX88_BOARD_NONE &&
 	    core->active_type_id != drv->type_id)
 		return -EBUSY;
 
-	core->input = CX88_VMUX_DVB;
+	core->input = 0;
+	for (i = 0;
+	     i < (sizeof(core->board.input) / sizeof(struct cx88_input));
+	     i++) {
+		if (core->board.input[i].type == CX88_VMUX_DVB) {
+			core->input = i;
+			break;
+		}
+	}
 
 	if (drv->advise_acquire)
 	{
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 48c450f..0fab65c 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -426,12 +426,13 @@
 		if (core->board.audio_chip &&
 		    core->board.audio_chip == V4L2_IDENT_WM8775) {
 			call_all(core, audio, s_routing,
-					INPUT(input).audioroute, 0, 0);
+				 INPUT(input).audioroute, 0, 0);
 		}
 		/* cx2388's C-ADC is connected to the tuner only.
 		   When used with S-Video, that ADC is busy dealing with
 		   chroma, so an external must be used for baseband audio */
-		if (INPUT(input).type != CX88_VMUX_TELEVISION ) {
+		if (INPUT(input).type != CX88_VMUX_TELEVISION &&
+		    INPUT(input).type != CX88_VMUX_CABLE) {
 			/* "I2S ADC mode" */
 			core->tvaudio = WW_I2SADC;
 			cx88_set_tvaudio(core);
@@ -561,8 +562,8 @@
 	*size = fh->fmt->depth*fh->width*fh->height >> 3;
 	if (0 == *count)
 		*count = 32;
-	while (*size * *count > vid_limit * 1024 * 1024)
-		(*count)--;
+	if (*size * *count > vid_limit * 1024 * 1024)
+		*count = (vid_limit * 1024 * 1024) / *size;
 	return 0;
 }
 
@@ -1537,9 +1538,12 @@
 		c->id >= V4L2_CID_LASTP1)
 		return -EINVAL;
 	if (c->id == V4L2_CID_AUDIO_MUTE) {
-		for (i = 0; i < CX8800_CTLS; i++)
+		for (i = 0; i < CX8800_CTLS; i++) {
 			if (cx8800_ctls[i].v.id == c->id)
 				break;
+		}
+		if (i == CX8800_CTLS)
+			return -EINVAL;
 		*c = cx8800_ctls[i].v;
 	} else
 		*c = no_ctl;
@@ -1977,7 +1981,7 @@
 	}
 
 	if (core->ir)
-		cx88_ir_stop(core, core->ir);
+		cx88_ir_stop(core);
 
 	cx88_shutdown(core); /* FIXME */
 	pci_disable_device(pci_dev);
@@ -2015,7 +2019,7 @@
 	spin_unlock(&dev->slock);
 
 	if (core->ir)
-		cx88_ir_stop(core, core->ir);
+		cx88_ir_stop(core);
 	/* FIXME -- shutdown device */
 	cx88_shutdown(core);
 
@@ -2056,7 +2060,7 @@
 	/* FIXME: re-initialize hardware */
 	cx88_reset(core);
 	if (core->ir)
-		cx88_ir_start(core, core->ir);
+		cx88_ir_start(core);
 
 	cx_set(MO_PCI_INTMSK, core->pci_irqmask);
 
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 48b6c04..bdb03d3 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -41,7 +41,7 @@
 
 #include <linux/version.h>
 #include <linux/mutex.h>
-#define CX88_VERSION_CODE KERNEL_VERSION(0,0,7)
+#define CX88_VERSION_CODE KERNEL_VERSION(0, 0, 8)
 
 #define UNSET (-1U)
 
@@ -290,7 +290,7 @@
 #define RESOURCE_VIDEO         2
 #define RESOURCE_VBI           4
 
-#define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
+#define BUFFER_TIMEOUT     msecs_to_jiffies(2000)
 
 /* buffer for one video frame */
 struct cx88_buffer {
@@ -683,8 +683,8 @@
 int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci);
 int cx88_ir_fini(struct cx88_core *core);
 void cx88_ir_irq(struct cx88_core *core);
-void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir);
-void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir);
+int cx88_ir_start(struct cx88_core *core);
+void cx88_ir_stop(struct cx88_core *core);
 
 /* ----------------------------------------------------------- */
 /* cx88-mpeg.c                                                 */
diff --git a/drivers/media/video/davinci/dm644x_ccdc.c b/drivers/media/video/davinci/dm644x_ccdc.c
index b4cc96d..490aafb3 100644
--- a/drivers/media/video/davinci/dm644x_ccdc.c
+++ b/drivers/media/video/davinci/dm644x_ccdc.c
@@ -101,6 +101,9 @@
 static u32 ccdc_raw_yuv_pix_formats[] =
 	{V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
 
+/* CCDC Save/Restore context */
+static u32 ccdc_ctx[CCDC_REG_END / sizeof(u32)];
+
 /* register access routines */
 static inline u32 regr(u32 offset)
 {
@@ -400,7 +403,11 @@
 		 * configure the FID, VD, HD pin polarity,
 		 * fld,hd pol positive, vd negative, 8-bit data
 		 */
-		syn_mode |= CCDC_SYN_MODE_VD_POL_NEGATIVE | CCDC_SYN_MODE_8BITS;
+		syn_mode |= CCDC_SYN_MODE_VD_POL_NEGATIVE;
+		if (ccdc_cfg.if_type == VPFE_BT656_10BIT)
+			syn_mode |= CCDC_SYN_MODE_10BITS;
+		else
+			syn_mode |= CCDC_SYN_MODE_8BITS;
 	} else {
 		/* y/c external sync mode */
 		syn_mode |= (((params->fid_pol & CCDC_FID_POL_MASK) <<
@@ -419,8 +426,13 @@
 	 * configure the order of y cb cr in SDRAM, and disable latch
 	 * internal register on vsync
 	 */
-	regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) |
-		 CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG);
+	if (ccdc_cfg.if_type == VPFE_BT656_10BIT)
+		regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) |
+			CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_BW656_10BIT,
+			CCDC_CCDCFG);
+	else
+		regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) |
+			CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG);
 
 	/*
 	 * configure the horizontal line offset. This should be a
@@ -435,7 +447,6 @@
 
 	ccdc_sbl_reset();
 	dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n");
-	ccdc_readregs();
 }
 
 static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
@@ -827,6 +838,7 @@
 	case VPFE_BT656:
 	case VPFE_YCBCR_SYNC_16:
 	case VPFE_YCBCR_SYNC_8:
+	case VPFE_BT656_10BIT:
 		ccdc_cfg.ycbcr.vd_pol = params->vdpol;
 		ccdc_cfg.ycbcr.hd_pol = params->hdpol;
 		break;
@@ -837,6 +849,87 @@
 	return 0;
 }
 
+static void ccdc_save_context(void)
+{
+	ccdc_ctx[CCDC_PCR >> 2] = regr(CCDC_PCR);
+	ccdc_ctx[CCDC_SYN_MODE >> 2] = regr(CCDC_SYN_MODE);
+	ccdc_ctx[CCDC_HD_VD_WID >> 2] = regr(CCDC_HD_VD_WID);
+	ccdc_ctx[CCDC_PIX_LINES >> 2] = regr(CCDC_PIX_LINES);
+	ccdc_ctx[CCDC_HORZ_INFO >> 2] = regr(CCDC_HORZ_INFO);
+	ccdc_ctx[CCDC_VERT_START >> 2] = regr(CCDC_VERT_START);
+	ccdc_ctx[CCDC_VERT_LINES >> 2] = regr(CCDC_VERT_LINES);
+	ccdc_ctx[CCDC_CULLING >> 2] = regr(CCDC_CULLING);
+	ccdc_ctx[CCDC_HSIZE_OFF >> 2] = regr(CCDC_HSIZE_OFF);
+	ccdc_ctx[CCDC_SDOFST >> 2] = regr(CCDC_SDOFST);
+	ccdc_ctx[CCDC_SDR_ADDR >> 2] = regr(CCDC_SDR_ADDR);
+	ccdc_ctx[CCDC_CLAMP >> 2] = regr(CCDC_CLAMP);
+	ccdc_ctx[CCDC_DCSUB >> 2] = regr(CCDC_DCSUB);
+	ccdc_ctx[CCDC_COLPTN >> 2] = regr(CCDC_COLPTN);
+	ccdc_ctx[CCDC_BLKCMP >> 2] = regr(CCDC_BLKCMP);
+	ccdc_ctx[CCDC_FPC >> 2] = regr(CCDC_FPC);
+	ccdc_ctx[CCDC_FPC_ADDR >> 2] = regr(CCDC_FPC_ADDR);
+	ccdc_ctx[CCDC_VDINT >> 2] = regr(CCDC_VDINT);
+	ccdc_ctx[CCDC_ALAW >> 2] = regr(CCDC_ALAW);
+	ccdc_ctx[CCDC_REC656IF >> 2] = regr(CCDC_REC656IF);
+	ccdc_ctx[CCDC_CCDCFG >> 2] = regr(CCDC_CCDCFG);
+	ccdc_ctx[CCDC_FMTCFG >> 2] = regr(CCDC_FMTCFG);
+	ccdc_ctx[CCDC_FMT_HORZ >> 2] = regr(CCDC_FMT_HORZ);
+	ccdc_ctx[CCDC_FMT_VERT >> 2] = regr(CCDC_FMT_VERT);
+	ccdc_ctx[CCDC_FMT_ADDR0 >> 2] = regr(CCDC_FMT_ADDR0);
+	ccdc_ctx[CCDC_FMT_ADDR1 >> 2] = regr(CCDC_FMT_ADDR1);
+	ccdc_ctx[CCDC_FMT_ADDR2 >> 2] = regr(CCDC_FMT_ADDR2);
+	ccdc_ctx[CCDC_FMT_ADDR3 >> 2] = regr(CCDC_FMT_ADDR3);
+	ccdc_ctx[CCDC_FMT_ADDR4 >> 2] = regr(CCDC_FMT_ADDR4);
+	ccdc_ctx[CCDC_FMT_ADDR5 >> 2] = regr(CCDC_FMT_ADDR5);
+	ccdc_ctx[CCDC_FMT_ADDR6 >> 2] = regr(CCDC_FMT_ADDR6);
+	ccdc_ctx[CCDC_FMT_ADDR7 >> 2] = regr(CCDC_FMT_ADDR7);
+	ccdc_ctx[CCDC_PRGEVEN_0 >> 2] = regr(CCDC_PRGEVEN_0);
+	ccdc_ctx[CCDC_PRGEVEN_1 >> 2] = regr(CCDC_PRGEVEN_1);
+	ccdc_ctx[CCDC_PRGODD_0 >> 2] = regr(CCDC_PRGODD_0);
+	ccdc_ctx[CCDC_PRGODD_1 >> 2] = regr(CCDC_PRGODD_1);
+	ccdc_ctx[CCDC_VP_OUT >> 2] = regr(CCDC_VP_OUT);
+}
+
+static void ccdc_restore_context(void)
+{
+	regw(ccdc_ctx[CCDC_SYN_MODE >> 2], CCDC_SYN_MODE);
+	regw(ccdc_ctx[CCDC_HD_VD_WID >> 2], CCDC_HD_VD_WID);
+	regw(ccdc_ctx[CCDC_PIX_LINES >> 2], CCDC_PIX_LINES);
+	regw(ccdc_ctx[CCDC_HORZ_INFO >> 2], CCDC_HORZ_INFO);
+	regw(ccdc_ctx[CCDC_VERT_START >> 2], CCDC_VERT_START);
+	regw(ccdc_ctx[CCDC_VERT_LINES >> 2], CCDC_VERT_LINES);
+	regw(ccdc_ctx[CCDC_CULLING >> 2], CCDC_CULLING);
+	regw(ccdc_ctx[CCDC_HSIZE_OFF >> 2], CCDC_HSIZE_OFF);
+	regw(ccdc_ctx[CCDC_SDOFST >> 2], CCDC_SDOFST);
+	regw(ccdc_ctx[CCDC_SDR_ADDR >> 2], CCDC_SDR_ADDR);
+	regw(ccdc_ctx[CCDC_CLAMP >> 2], CCDC_CLAMP);
+	regw(ccdc_ctx[CCDC_DCSUB >> 2], CCDC_DCSUB);
+	regw(ccdc_ctx[CCDC_COLPTN >> 2], CCDC_COLPTN);
+	regw(ccdc_ctx[CCDC_BLKCMP >> 2], CCDC_BLKCMP);
+	regw(ccdc_ctx[CCDC_FPC >> 2], CCDC_FPC);
+	regw(ccdc_ctx[CCDC_FPC_ADDR >> 2], CCDC_FPC_ADDR);
+	regw(ccdc_ctx[CCDC_VDINT >> 2], CCDC_VDINT);
+	regw(ccdc_ctx[CCDC_ALAW >> 2], CCDC_ALAW);
+	regw(ccdc_ctx[CCDC_REC656IF >> 2], CCDC_REC656IF);
+	regw(ccdc_ctx[CCDC_CCDCFG >> 2], CCDC_CCDCFG);
+	regw(ccdc_ctx[CCDC_FMTCFG >> 2], CCDC_FMTCFG);
+	regw(ccdc_ctx[CCDC_FMT_HORZ >> 2], CCDC_FMT_HORZ);
+	regw(ccdc_ctx[CCDC_FMT_VERT >> 2], CCDC_FMT_VERT);
+	regw(ccdc_ctx[CCDC_FMT_ADDR0 >> 2], CCDC_FMT_ADDR0);
+	regw(ccdc_ctx[CCDC_FMT_ADDR1 >> 2], CCDC_FMT_ADDR1);
+	regw(ccdc_ctx[CCDC_FMT_ADDR2 >> 2], CCDC_FMT_ADDR2);
+	regw(ccdc_ctx[CCDC_FMT_ADDR3 >> 2], CCDC_FMT_ADDR3);
+	regw(ccdc_ctx[CCDC_FMT_ADDR4 >> 2], CCDC_FMT_ADDR4);
+	regw(ccdc_ctx[CCDC_FMT_ADDR5 >> 2], CCDC_FMT_ADDR5);
+	regw(ccdc_ctx[CCDC_FMT_ADDR6 >> 2], CCDC_FMT_ADDR6);
+	regw(ccdc_ctx[CCDC_FMT_ADDR7 >> 2], CCDC_FMT_ADDR7);
+	regw(ccdc_ctx[CCDC_PRGEVEN_0 >> 2], CCDC_PRGEVEN_0);
+	regw(ccdc_ctx[CCDC_PRGEVEN_1 >> 2], CCDC_PRGEVEN_1);
+	regw(ccdc_ctx[CCDC_PRGODD_0 >> 2], CCDC_PRGODD_0);
+	regw(ccdc_ctx[CCDC_PRGODD_1 >> 2], CCDC_PRGODD_1);
+	regw(ccdc_ctx[CCDC_VP_OUT >> 2], CCDC_VP_OUT);
+	regw(ccdc_ctx[CCDC_PCR >> 2], CCDC_PCR);
+}
 static struct ccdc_hw_device ccdc_hw_dev = {
 	.name = "DM6446 CCDC",
 	.owner = THIS_MODULE,
@@ -945,10 +1038,40 @@
 	return 0;
 }
 
+static int dm644x_ccdc_suspend(struct device *dev)
+{
+	/* Save CCDC context */
+	ccdc_save_context();
+	/* Disable CCDC */
+	ccdc_enable(0);
+	/* Disable both master and slave clock */
+	clk_disable(ccdc_cfg.mclk);
+	clk_disable(ccdc_cfg.sclk);
+
+	return 0;
+}
+
+static int dm644x_ccdc_resume(struct device *dev)
+{
+	/* Enable both master and slave clock */
+	clk_enable(ccdc_cfg.mclk);
+	clk_enable(ccdc_cfg.sclk);
+	/* Restore CCDC context */
+	ccdc_restore_context();
+
+	return 0;
+}
+
+static const struct dev_pm_ops dm644x_ccdc_pm_ops = {
+	.suspend = dm644x_ccdc_suspend,
+	.resume = dm644x_ccdc_resume,
+};
+
 static struct platform_driver dm644x_ccdc_driver = {
 	.driver = {
 		.name	= "dm644x_ccdc",
 		.owner = THIS_MODULE,
+		.pm = &dm644x_ccdc_pm_ops,
 	},
 	.remove = __devexit_p(dm644x_ccdc_remove),
 	.probe = dm644x_ccdc_probe,
diff --git a/drivers/media/video/davinci/dm644x_ccdc_regs.h b/drivers/media/video/davinci/dm644x_ccdc_regs.h
index 6e5d053..90370e4 100644
--- a/drivers/media/video/davinci/dm644x_ccdc_regs.h
+++ b/drivers/media/video/davinci/dm644x_ccdc_regs.h
@@ -59,7 +59,7 @@
 #define CCDC_PRGODD_0				0x8c
 #define CCDC_PRGODD_1				0x90
 #define CCDC_VP_OUT				0x94
-
+#define CCDC_REG_END				0x98
 
 /***************************************************************
 *	Define for various register bit mask and shifts for CCDC
@@ -135,11 +135,19 @@
 #define CCDC_SYN_MODE_INPMOD_SHIFT		12
 #define CCDC_SYN_MODE_INPMOD_MASK		3
 #define CCDC_SYN_MODE_8BITS			(7 << 8)
+#define CCDC_SYN_MODE_10BITS			(6 << 8)
+#define CCDC_SYN_MODE_11BITS			(5 << 8)
+#define CCDC_SYN_MODE_12BITS			(4 << 8)
+#define CCDC_SYN_MODE_13BITS			(3 << 8)
+#define CCDC_SYN_MODE_14BITS			(2 << 8)
+#define CCDC_SYN_MODE_15BITS			(1 << 8)
+#define CCDC_SYN_MODE_16BITS			(0 << 8)
 #define CCDC_SYN_FLDMODE_MASK			1
 #define CCDC_SYN_FLDMODE_SHIFT			7
 #define CCDC_REC656IF_BT656_EN			3
 #define CCDC_SYN_MODE_VD_POL_NEGATIVE		(1 << 2)
 #define CCDC_CCDCFG_Y8POS_SHIFT			11
+#define CCDC_CCDCFG_BW656_10BIT 		(1 << 5)
 #define CCDC_SDOFST_FIELD_INTERLEAVED		0x249
 #define CCDC_NO_CULLING				0xffff00ff
 #endif
diff --git a/drivers/media/video/davinci/isif_regs.h b/drivers/media/video/davinci/isif_regs.h
index f7b8893..aa69a46 100644
--- a/drivers/media/video/davinci/isif_regs.h
+++ b/drivers/media/video/davinci/isif_regs.h
@@ -158,7 +158,7 @@
 
 /* gain - offset masks */
 #define GAIN_INTEGER_SHIFT			9
-#define OFFSET_MASK			  	0xFFF
+#define OFFSET_MASK				0xFFF
 #define GAIN_SDRAM_EN_SHIFT			12
 #define GAIN_IPIPE_EN_SHIFT			13
 #define GAIN_H3A_EN_SHIFT			14
diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c
index 398dbe7..1c25882 100644
--- a/drivers/media/video/davinci/vpfe_capture.c
+++ b/drivers/media/video/davinci/vpfe_capture.c
@@ -475,6 +475,11 @@
 	ret = ccdc_dev->hw_ops.open(vpfe_dev->pdev);
 	if (!ret)
 		vpfe_dev->initialized = 1;
+
+	/* Clear all VPFE/CCDC interrupts */
+	if (vpfe_dev->cfg->clr_intr)
+		vpfe_dev->cfg->clr_intr(-1);
+
 unlock:
 	mutex_unlock(&ccdc_lock);
 	return ret;
@@ -534,6 +539,16 @@
 	list_del(&vpfe_dev->next_frm->queue);
 	vpfe_dev->next_frm->state = VIDEOBUF_ACTIVE;
 	addr = videobuf_to_dma_contig(vpfe_dev->next_frm);
+
+	ccdc_dev->hw_ops.setfbaddr(addr);
+}
+
+static void vpfe_schedule_bottom_field(struct vpfe_device *vpfe_dev)
+{
+	unsigned long addr;
+
+	addr = videobuf_to_dma_contig(vpfe_dev->cur_frm);
+	addr += vpfe_dev->field_off;
 	ccdc_dev->hw_ops.setfbaddr(addr);
 }
 
@@ -554,7 +569,6 @@
 {
 	struct vpfe_device *vpfe_dev = dev_id;
 	enum v4l2_field field;
-	unsigned long addr;
 	int fid;
 
 	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nStarting vpfe_isr...\n");
@@ -562,7 +576,7 @@
 
 	/* if streaming not started, don't do anything */
 	if (!vpfe_dev->started)
-		return IRQ_HANDLED;
+		goto clear_intr;
 
 	/* only for 6446 this will be applicable */
 	if (NULL != ccdc_dev->hw_ops.reset)
@@ -574,7 +588,7 @@
 			"frame format is progressive...\n");
 		if (vpfe_dev->cur_frm != vpfe_dev->next_frm)
 			vpfe_process_buffer_complete(vpfe_dev);
-		return IRQ_HANDLED;
+		goto clear_intr;
 	}
 
 	/* interlaced or TB capture check which field we are in hardware */
@@ -599,12 +613,9 @@
 			 * the CCDC memory address
 			 */
 			if (field == V4L2_FIELD_SEQ_TB) {
-				addr =
-				  videobuf_to_dma_contig(vpfe_dev->cur_frm);
-				addr += vpfe_dev->field_off;
-				ccdc_dev->hw_ops.setfbaddr(addr);
+				vpfe_schedule_bottom_field(vpfe_dev);
 			}
-			return IRQ_HANDLED;
+			goto clear_intr;
 		}
 		/*
 		 * if one field is just being captured configure
@@ -624,6 +635,10 @@
 		 */
 		vpfe_dev->field_id = fid;
 	}
+clear_intr:
+	if (vpfe_dev->cfg->clr_intr)
+		vpfe_dev->cfg->clr_intr(irq);
+
 	return IRQ_HANDLED;
 }
 
@@ -635,8 +650,11 @@
 	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nInside vdint1_isr...\n");
 
 	/* if streaming not started, don't do anything */
-	if (!vpfe_dev->started)
+	if (!vpfe_dev->started) {
+		if (vpfe_dev->cfg->clr_intr)
+			vpfe_dev->cfg->clr_intr(irq);
 		return IRQ_HANDLED;
+	}
 
 	spin_lock(&vpfe_dev->dma_queue_lock);
 	if ((vpfe_dev->fmt.fmt.pix.field == V4L2_FIELD_NONE) &&
@@ -644,6 +662,10 @@
 	    vpfe_dev->cur_frm == vpfe_dev->next_frm)
 		vpfe_schedule_next_buffer(vpfe_dev);
 	spin_unlock(&vpfe_dev->dma_queue_lock);
+
+	if (vpfe_dev->cfg->clr_intr)
+		vpfe_dev->cfg->clr_intr(irq);
+
 	return IRQ_HANDLED;
 }
 
@@ -714,7 +736,7 @@
 	/* Decrement device usrs counter */
 	vpfe_dev->usrs--;
 	/* Close the priority */
-	v4l2_prio_close(&vpfe_dev->prio, &fh->prio);
+	v4l2_prio_close(&vpfe_dev->prio, fh->prio);
 	/* If this is the last file handle */
 	if (!vpfe_dev->usrs) {
 		vpfe_dev->initialized = 0;
@@ -1218,7 +1240,10 @@
 	struct vpfe_device *vpfe_dev = fh->vpfe_dev;
 
 	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_setup\n");
-	*size = config_params.device_bufsize;
+	*size = vpfe_dev->fmt.fmt.pix.sizeimage;
+	if (vpfe_dev->memory == V4L2_MEMORY_MMAP &&
+		vpfe_dev->fmt.fmt.pix.sizeimage > config_params.device_bufsize)
+		*size = config_params.device_bufsize;
 
 	if (*count < config_params.min_numbuffers)
 		*count = config_params.min_numbuffers;
@@ -1233,6 +1258,8 @@
 {
 	struct vpfe_fh *fh = vq->priv_data;
 	struct vpfe_device *vpfe_dev = fh->vpfe_dev;
+	unsigned long addr;
+	int ret;
 
 	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_prepare\n");
 
@@ -1242,8 +1269,18 @@
 		vb->height = vpfe_dev->fmt.fmt.pix.height;
 		vb->size = vpfe_dev->fmt.fmt.pix.sizeimage;
 		vb->field = field;
+
+		ret = videobuf_iolock(vq, vb, NULL);;
+		if (ret < 0)
+			return ret;
+
+		addr = videobuf_to_dma_contig(vb);
+		/* Make sure user addresses are aligned to 32 bytes */
+		if (!ALIGN(addr, 32))
+			return -EINVAL;
+
+		vb->state = VIDEOBUF_PREPARED;
 	}
-	vb->state = VIDEOBUF_PREPARED;
 	return 0;
 }
 
@@ -1311,13 +1348,6 @@
 		return -EINVAL;
 	}
 
-	if (V4L2_MEMORY_USERPTR == req_buf->memory) {
-		/* we don't support user ptr IO */
-		v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs:"
-			 " USERPTR IO not supported\n");
-		return  -EINVAL;
-	}
-
 	ret = mutex_lock_interruptible(&vpfe_dev->lock);
 	if (ret)
 		return ret;
@@ -1831,7 +1861,6 @@
 		goto probe_free_dev_mem;
 	}
 
-	mutex_lock(&ccdc_lock);
 	/* Allocate memory for ccdc configuration */
 	ccdc_cfg = kmalloc(sizeof(struct ccdc_config), GFP_KERNEL);
 	if (NULL == ccdc_cfg) {
@@ -1840,6 +1869,8 @@
 		goto probe_free_lock;
 	}
 
+	mutex_lock(&ccdc_lock);
+
 	strncpy(ccdc_cfg->name, vpfe_cfg->ccdc, 32);
 	/* Get VINT0 irq resource */
 	res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@@ -2015,18 +2046,14 @@
 	return 0;
 }
 
-static int
-vpfe_suspend(struct device *dev)
+static int vpfe_suspend(struct device *dev)
 {
-	/* add suspend code here later */
-	return -1;
+	return 0;
 }
 
-static int
-vpfe_resume(struct device *dev)
+static int vpfe_resume(struct device *dev)
 {
-	/* add resume code here later */
-	return -1;
+	return 0;
 }
 
 static const struct dev_pm_ops vpfe_dev_pm_ops = {
diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c
index 2e5a7fb..a7f48b5 100644
--- a/drivers/media/video/davinci/vpif_capture.c
+++ b/drivers/media/video/davinci/vpif_capture.c
@@ -869,7 +869,7 @@
 	mutex_unlock(&common->lock);
 
 	/* Close the priority */
-	v4l2_prio_close(&ch->prio, &fh->prio);
+	v4l2_prio_close(&ch->prio, fh->prio);
 
 	if (fh->initialized)
 		ch->initialized = 0;
@@ -1444,7 +1444,7 @@
 		}
 	}
 
-	ret = v4l2_prio_check(&ch->prio, &fh->prio);
+	ret = v4l2_prio_check(&ch->prio, fh->prio);
 	if (0 != ret)
 		return ret;
 
@@ -1554,7 +1554,7 @@
 		}
 	}
 
-	ret = v4l2_prio_check(&ch->prio, &fh->prio);
+	ret = v4l2_prio_check(&ch->prio, fh->prio);
 	if (0 != ret)
 		return ret;
 
@@ -1710,7 +1710,7 @@
 		}
 	}
 
-	ret = v4l2_prio_check(&ch->prio, &fh->prio);
+	ret = v4l2_prio_check(&ch->prio, fh->prio);
 	if (0 != ret)
 		return ret;
 
diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c
index 13c3a1b..da07607 100644
--- a/drivers/media/video/davinci/vpif_display.c
+++ b/drivers/media/video/davinci/vpif_display.c
@@ -384,7 +384,7 @@
 	int index;
 
 	std_info->stdid = vid_ch->stdid;
-	if (!std_info)
+	if (!std_info->stdid)
 		return -1;
 
 	for (index = 0; index < ARRAY_SIZE(ch_params); index++) {
@@ -671,7 +671,7 @@
 		ch->initialized = 0;
 
 	/* Close the priority */
-	v4l2_prio_close(&ch->prio, &fh->prio);
+	v4l2_prio_close(&ch->prio, fh->prio);
 	filep->private_data = NULL;
 	fh->initialized = 0;
 	kfree(fh);
@@ -753,7 +753,7 @@
 		}
 
 		/* Check for the priority */
-		ret = v4l2_prio_check(&ch->prio, &fh->prio);
+		ret = v4l2_prio_check(&ch->prio, fh->prio);
 		if (0 != ret)
 			return ret;
 		fh->initialized = 1;
diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c
index bd78338..e182abf 100644
--- a/drivers/media/video/em28xx/em28xx-audio.c
+++ b/drivers/media/video/em28xx/em28xx-audio.c
@@ -491,7 +491,7 @@
 	strcpy(pcm->name, "Empia 28xx Capture");
 
 	snd_card_set_dev(card, &dev->udev->dev);
-	strcpy(card->driver, "Empia Em28xx Audio");
+	strcpy(card->driver, "Em28xx-Audio");
 	strcpy(card->shortname, "Em28xx Audio");
 	strcpy(card->longname, "Empia Em28xx Audio");
 
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index b0fb0833..3a4fd85 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -602,7 +602,7 @@
 		.name         = "Gadmei UTV330+",
 		.tuner_type   = TUNER_TNF_5335MF,
 		.tda9887_conf = TDA9887_PRESENT,
-		.ir_codes     = &ir_codes_gadmei_rm008z_table,
+		.ir_codes     = RC_MAP_GADMEI_RM008Z,
 		.decoder      = EM28XX_SAA711X,
 		.xclk         = EM28XX_XCLK_FREQUENCY_12MHZ,
 		.input        = { {
@@ -681,6 +681,20 @@
 			.amux     = EM28XX_AMUX_LINE_IN,
 		} },
 	},
+	[EM2860_BOARD_TVP5150_REFERENCE_DESIGN] = {
+		.name          = "EM2860/TVP5150 Reference Design",
+		.tuner_type    = TUNER_ABSENT,	/* Capture only device */
+		.decoder       = EM28XX_TVP5150,
+		.input         = { {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
 	[EM2861_BOARD_PLEXTOR_PX_TV100U] = {
 		.name         = "Plextor ConvertX PX-TV100U",
 		.tuner_type   = TUNER_TNF_5335MF,
@@ -777,7 +791,7 @@
 		.mts_firmware = 1,
 		.has_dvb      = 1,
 		.dvb_gpio     = hauppauge_wintv_hvr_900_digital,
-		.ir_codes     = &ir_codes_hauppauge_new_table,
+		.ir_codes     = RC_MAP_HAUPPAUGE_NEW,
 		.decoder      = EM28XX_TVP5150,
 		.input        = { {
 			.type     = EM28XX_VMUX_TELEVISION,
@@ -802,7 +816,7 @@
 		.tuner_type   = TUNER_XC2028,
 		.tuner_gpio   = default_tuner_gpio,
 		.mts_firmware = 1,
-		.ir_codes     = &ir_codes_hauppauge_new_table,
+		.ir_codes     = RC_MAP_HAUPPAUGE_NEW,
 		.decoder      = EM28XX_TVP5150,
 		.input        = { {
 			.type     = EM28XX_VMUX_TELEVISION,
@@ -828,7 +842,7 @@
 		.mts_firmware   = 1,
 		.has_dvb        = 1,
 		.dvb_gpio       = hauppauge_wintv_hvr_900_digital,
-		.ir_codes       = &ir_codes_hauppauge_new_table,
+		.ir_codes       = RC_MAP_HAUPPAUGE_NEW,
 		.decoder        = EM28XX_TVP5150,
 		.input          = { {
 			.type     = EM28XX_VMUX_TELEVISION,
@@ -854,7 +868,7 @@
 		.mts_firmware   = 1,
 		.has_dvb        = 1,
 		.dvb_gpio       = hauppauge_wintv_hvr_900_digital,
-		.ir_codes       = &ir_codes_rc5_hauppauge_new_table,
+		.ir_codes       = RC_MAP_RC5_HAUPPAUGE_NEW,
 		.decoder        = EM28XX_TVP5150,
 		.input          = { {
 			.type     = EM28XX_VMUX_TELEVISION,
@@ -880,7 +894,7 @@
 		.mts_firmware   = 1,
 		.has_dvb        = 1,
 		.dvb_gpio       = hauppauge_wintv_hvr_900_digital,
-		.ir_codes       = &ir_codes_pinnacle_pctv_hd_table,
+		.ir_codes       = RC_MAP_PINNACLE_PCTV_HD,
 		.decoder        = EM28XX_TVP5150,
 		.input          = { {
 			.type     = EM28XX_VMUX_TELEVISION,
@@ -906,7 +920,7 @@
 		.mts_firmware   = 1,
 		.has_dvb        = 1,
 		.dvb_gpio       = hauppauge_wintv_hvr_900_digital,
-		.ir_codes       = &ir_codes_ati_tv_wonder_hd_600_table,
+		.ir_codes       = RC_MAP_ATI_TV_WONDER_HD_600,
 		.decoder        = EM28XX_TVP5150,
 		.input          = { {
 			.type     = EM28XX_VMUX_TELEVISION,
@@ -932,7 +946,7 @@
 		.decoder        = EM28XX_TVP5150,
 		.has_dvb        = 1,
 		.dvb_gpio       = default_digital,
-		.ir_codes       = &ir_codes_terratec_cinergy_xs_table,
+		.ir_codes       = RC_MAP_TERRATEC_CINERGY_XS,
 		.xclk           = EM28XX_XCLK_FREQUENCY_12MHZ, /* NEC IR */
 		.input          = { {
 			.type     = EM28XX_VMUX_TELEVISION,
@@ -1282,7 +1296,7 @@
 		.decoder	= EM28XX_SAA711X,
 		.has_dvb	= 1,
 		.dvb_gpio	= em2882_kworld_315u_digital,
-		.ir_codes	= &ir_codes_kworld_315u_table,
+		.ir_codes	= RC_MAP_KWORLD_315U,
 		.xclk		= EM28XX_XCLK_FREQUENCY_12MHZ,
 		.i2c_speed	= EM28XX_I2C_CLK_WAIT_ENABLE,
 		/* Analog mode - still not ready */
@@ -1404,10 +1418,14 @@
 	},
 	[EM2882_BOARD_KWORLD_VS_DVBT] = {
 		.name         = "Kworld VS-DVB-T 323UR",
-		.valid        = EM28XX_BOARD_NOT_VALIDATED,
 		.tuner_type   = TUNER_XC2028,
 		.tuner_gpio   = default_tuner_gpio,
 		.decoder      = EM28XX_TVP5150,
+		.mts_firmware = 1,
+		.has_dvb      = 1,
+		.dvb_gpio     = kworld_330u_digital,
+		.xclk         = EM28XX_XCLK_FREQUENCY_12MHZ, /* NEC IR */
+		.ir_codes     = RC_MAP_KWORLD_315U,
 		.input        = { {
 			.type     = EM28XX_VMUX_TELEVISION,
 			.vmux     = TVP5150_COMPOSITE0,
@@ -1430,7 +1448,7 @@
 		.decoder      = EM28XX_TVP5150,
 		.has_dvb      = 1,
 		.dvb_gpio     = hauppauge_wintv_hvr_900_digital,
-		.ir_codes     = &ir_codes_terratec_cinergy_xs_table,
+		.ir_codes     = RC_MAP_TERRATEC_CINERGY_XS,
 		.xclk         = EM28XX_XCLK_FREQUENCY_12MHZ,
 		.input        = { {
 			.type     = EM28XX_VMUX_TELEVISION,
@@ -1523,7 +1541,7 @@
 		.mts_firmware = 1,
 		.decoder      = EM28XX_TVP5150,
 		.tuner_gpio   = default_tuner_gpio,
-		.ir_codes     = &ir_codes_kaiomy_table,
+		.ir_codes     = RC_MAP_KAIOMY,
 		.input          = { {
 			.type     = EM28XX_VMUX_TELEVISION,
 			.vmux     = TVP5150_COMPOSITE0,
@@ -1623,7 +1641,7 @@
 		.mts_firmware = 1,
 		.has_dvb      = 1,
 		.dvb_gpio     = evga_indtube_digital,
-		.ir_codes     = &ir_codes_evga_indtube_table,
+		.ir_codes     = RC_MAP_EVGA_INDTUBE,
 		.input        = { {
 			.type     = EM28XX_VMUX_TELEVISION,
 			.vmux     = TVP5150_COMPOSITE0,
@@ -1672,6 +1690,8 @@
 			.driver_info = EM2820_BOARD_UNKNOWN },
 	{ USB_DEVICE(0xeb1a, 0x2862),
 			.driver_info = EM2820_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2863),
+			.driver_info = EM2820_BOARD_UNKNOWN },
 	{ USB_DEVICE(0xeb1a, 0x2870),
 			.driver_info = EM2820_BOARD_UNKNOWN },
 	{ USB_DEVICE(0xeb1a, 0x2881),
@@ -1792,6 +1812,7 @@
 	{0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC},
 	{0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
 	{0x1ba50080, EM2860_BOARD_SAA711X_REFERENCE_DESIGN, TUNER_ABSENT},
+	{0x77800080, EM2860_BOARD_TVP5150_REFERENCE_DESIGN, TUNER_ABSENT},
 	{0xc51200e3, EM2820_BOARD_GADMEI_TVR200, TUNER_LG_PAL_NEW_TAPC},
 	{0x4ba50080, EM2861_BOARD_GADMEI_UTV330PLUS, TUNER_TNF_5335MF},
 };
@@ -2138,6 +2159,7 @@
 		break;
 	case EM2883_BOARD_KWORLD_HYBRID_330U:
 	case EM2882_BOARD_DIKOM_DK300:
+	case EM2882_BOARD_KWORLD_VS_DVBT:
 		ctl->demod = XC3028_FE_CHINA;
 		ctl->fname = XC2028_DEFAULT_FIRMWARE;
 		break;
@@ -2313,21 +2335,21 @@
 	switch (dev->model) {
 	case EM2800_BOARD_TERRATEC_CINERGY_200:
 	case EM2820_BOARD_TERRATEC_CINERGY_250:
-		dev->init_data.ir_codes = &ir_codes_em_terratec_table;
+		dev->init_data.ir_codes = RC_MAP_EM_TERRATEC;
 		dev->init_data.get_key = em28xx_get_key_terratec;
 		dev->init_data.name = "i2c IR (EM28XX Terratec)";
 		break;
 	case EM2820_BOARD_PINNACLE_USB_2:
-		dev->init_data.ir_codes = &ir_codes_pinnacle_grey_table;
+		dev->init_data.ir_codes = RC_MAP_PINNACLE_GREY;
 		dev->init_data.get_key = em28xx_get_key_pinnacle_usb_grey;
 		dev->init_data.name = "i2c IR (EM28XX Pinnacle PCTV)";
 		break;
 	case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
-		dev->init_data.ir_codes = &ir_codes_rc5_hauppauge_new_table;
+		dev->init_data.ir_codes = RC_MAP_RC5_HAUPPAUGE_NEW;
 		dev->init_data.get_key = em28xx_get_key_em_haup;
 		dev->init_data.name = "i2c IR (EM2840 Hauppauge)";
 	case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
-		dev->init_data.ir_codes = &ir_codes_winfast_usbii_deluxe_table;;
+		dev->init_data.ir_codes = RC_MAP_WINFAST_USBII_DELUXE;;
 		dev->init_data.get_key = em28xx_get_key_winfast_usbii_deluxe;
 		dev->init_data.name = "i2c IR (EM2820 Winfast TV USBII Deluxe)";
 		break;
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index a41cc55..d3813ed 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -782,11 +782,15 @@
 
 	em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
 
-	/* If we don't set the start position to 4 in VBI mode, we end up
-	   with line 21 being YUYV encoded instead of being in 8-bit
-	   greyscale */
+	/* If we don't set the start position to 2 in VBI mode, we end up
+	   with line 20/21 being YUYV encoded instead of being in 8-bit
+	   greyscale.  The core of the issue is that line 21 (and line 23 for
+	   PAL WSS) are inside of active video region, and as a result they
+	   get the pixelformatting associated with that area.  So by cropping
+	   it out, we end up with the same format as the rest of the VBI
+	   region */
 	if (em28xx_vbi_supported(dev) == 1)
-		em28xx_capture_area_set(dev, 0, 4, width >> 2, height >> 2);
+		em28xx_capture_area_set(dev, 0, 2, width >> 2, height >> 2);
 	else
 		em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2);
 
@@ -1174,21 +1178,18 @@
  */
 
 static LIST_HEAD(em28xx_extension_devlist);
-static DEFINE_MUTEX(em28xx_extension_devlist_lock);
 
 int em28xx_register_extension(struct em28xx_ops *ops)
 {
 	struct em28xx *dev = NULL;
 
 	mutex_lock(&em28xx_devlist_mutex);
-	mutex_lock(&em28xx_extension_devlist_lock);
 	list_add_tail(&ops->next, &em28xx_extension_devlist);
 	list_for_each_entry(dev, &em28xx_devlist, devlist) {
 		if (dev)
 			ops->init(dev);
 	}
 	printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
-	mutex_unlock(&em28xx_extension_devlist_lock);
 	mutex_unlock(&em28xx_devlist_mutex);
 	return 0;
 }
@@ -1204,10 +1205,8 @@
 			ops->fini(dev);
 	}
 
-	mutex_lock(&em28xx_extension_devlist_lock);
 	printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
 	list_del(&ops->next);
-	mutex_unlock(&em28xx_extension_devlist_lock);
 	mutex_unlock(&em28xx_devlist_mutex);
 }
 EXPORT_SYMBOL(em28xx_unregister_extension);
@@ -1216,26 +1215,26 @@
 {
 	struct em28xx_ops *ops = NULL;
 
-	mutex_lock(&em28xx_extension_devlist_lock);
+	mutex_lock(&em28xx_devlist_mutex);
 	if (!list_empty(&em28xx_extension_devlist)) {
 		list_for_each_entry(ops, &em28xx_extension_devlist, next) {
 			if (ops->init)
 				ops->init(dev);
 		}
 	}
-	mutex_unlock(&em28xx_extension_devlist_lock);
+	mutex_unlock(&em28xx_devlist_mutex);
 }
 
 void em28xx_close_extension(struct em28xx *dev)
 {
 	struct em28xx_ops *ops = NULL;
 
-	mutex_lock(&em28xx_extension_devlist_lock);
+	mutex_lock(&em28xx_devlist_mutex);
 	if (!list_empty(&em28xx_extension_devlist)) {
 		list_for_each_entry(ops, &em28xx_extension_devlist, next) {
 			if (ops->fini)
 				ops->fini(dev);
 		}
 	}
-	mutex_unlock(&em28xx_extension_devlist_lock);
+	mutex_unlock(&em28xx_devlist_mutex);
 }
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
index bcd3c37..cf1d8c3 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -467,6 +467,7 @@
 	}
 	dev->dvb = dvb;
 
+	mutex_lock(&dev->lock);
 	em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
 	/* init frontend */
 	switch (dev->model) {
@@ -506,6 +507,7 @@
 	case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
 	case EM2881_BOARD_PINNACLE_HYBRID_PRO:
 	case EM2882_BOARD_DIKOM_DK300:
+	case EM2882_BOARD_KWORLD_VS_DVBT:
 		dvb->frontend = dvb_attach(zl10353_attach,
 					   &em28xx_zl10353_xc3028_no_i2c_gate,
 					   &dev->i2c_adap);
@@ -589,15 +591,16 @@
 	if (result < 0)
 		goto out_free;
 
-	em28xx_set_mode(dev, EM28XX_SUSPEND);
 	em28xx_info("Successfully loaded em28xx-dvb\n");
-	return 0;
+ret:
+	em28xx_set_mode(dev, EM28XX_SUSPEND);
+	mutex_unlock(&dev->lock);
+	return result;
 
 out_free:
-	em28xx_set_mode(dev, EM28XX_SUSPEND);
 	kfree(dvb);
 	dev->dvb = NULL;
-	return result;
+	goto ret;
 }
 
 static int dvb_fini(struct em28xx *dev)
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 20a0001..5c3fd94 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -39,6 +39,8 @@
 module_param(ir_debug, int, 0644);
 MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
 
+#define MODULE_NAME "em28xx"
+
 #define i2cdprintk(fmt, arg...) \
 	if (ir_debug) { \
 		printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
@@ -360,14 +362,20 @@
 	schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
 }
 
-static void em28xx_ir_start(struct em28xx_IR *ir)
+static int em28xx_ir_start(void *priv)
 {
+	struct em28xx_IR *ir = priv;
+
 	INIT_DELAYED_WORK(&ir->work, em28xx_ir_work);
 	schedule_delayed_work(&ir->work, 0);
+
+	return 0;
 }
 
-static void em28xx_ir_stop(struct em28xx_IR *ir)
+static void em28xx_ir_stop(void *priv)
 {
+	struct em28xx_IR *ir = priv;
+
 	cancel_delayed_work_sync(&ir->work);
 }
 
@@ -380,7 +388,6 @@
 
 	/* Adjust xclk based o IR table for RC5/NEC tables */
 
-	dev->board.ir_codes->ir_type = IR_TYPE_OTHER;
 	if (ir_type == IR_TYPE_RC5) {
 		dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE;
 		ir->full_code = 1;
@@ -388,11 +395,9 @@
 		dev->board.xclk &= ~EM28XX_XCLK_IR_RC5_MODE;
 		ir_config = EM2874_IR_NEC;
 		ir->full_code = 1;
-	} else
+	} else if (ir_type != IR_TYPE_UNKNOWN)
 		rc = -EINVAL;
 
-	dev->board.ir_codes->ir_type = ir_type;
-
 	em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, dev->board.xclk,
 			      EM28XX_XCLK_IR_RC5_MODE);
 
@@ -443,6 +448,13 @@
 	ir->props.allowed_protos = IR_TYPE_RC5 | IR_TYPE_NEC;
 	ir->props.priv = ir;
 	ir->props.change_protocol = em28xx_ir_change_protocol;
+	ir->props.open = em28xx_ir_start;
+	ir->props.close = em28xx_ir_stop;
+
+	/* By default, keep protocol field untouched */
+	err = em28xx_ir_change_protocol(ir, IR_TYPE_UNKNOWN);
+	if (err)
+		goto err_out_free;
 
 	/* This is how often we ask the chip for IR information */
 	ir->polling = 100; /* ms */
@@ -455,7 +467,6 @@
 	strlcat(ir->phys, "/input0", sizeof(ir->phys));
 
 	/* Set IR protocol */
-	em28xx_ir_change_protocol(ir, dev->board.ir_codes->ir_type);
 	err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER);
 	if (err < 0)
 		goto err_out_free;
@@ -470,17 +481,15 @@
 	input_dev->dev.parent = &dev->udev->dev;
 
 
-	em28xx_ir_start(ir);
 
 	/* all done */
 	err = ir_input_register(ir->input, dev->board.ir_codes,
-				&ir->props);
+				&ir->props, MODULE_NAME);
 	if (err)
 		goto err_out_stop;
 
 	return 0;
  err_out_stop:
-	em28xx_ir_stop(ir);
 	dev->ir = NULL;
  err_out_free:
 	kfree(ir);
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 0fe2011..20090e3 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -203,12 +203,6 @@
 	if (dma_q->pos + len > buf->vb.size)
 		len = buf->vb.size - dma_q->pos;
 
-	if (p[0] != 0x88 && p[0] != 0x22) {
-		em28xx_isocdbg("frame is not complete\n");
-		len += 4;
-	} else
-		p += 4;
-
 	startread = p;
 	remain = len;
 
@@ -309,14 +303,6 @@
 	if (dma_q->pos + len > buf->vb.size)
 		len = buf->vb.size - dma_q->pos;
 
-	if ((p[0] == 0x33 && p[1] == 0x95) ||
-	    (p[0] == 0x88 && p[1] == 0x88)) {
-		/* Header field, advance past it */
-		p += 4;
-	} else {
-		len += 4;
-	}
-
 	startread = p;
 
 	startwrite = outp + dma_q->pos;
@@ -507,8 +493,15 @@
 
 			dma_q->pos = 0;
 		}
-		if (buf != NULL)
+		if (buf != NULL) {
+			if (p[0] != 0x88 && p[0] != 0x22) {
+				em28xx_isocdbg("frame is not complete\n");
+				len += 4;
+			} else {
+				p += 4;
+			}
 			em28xx_copy_video(dev, dma_q, buf, p, outp, len);
+		}
 	}
 	return rc;
 }
@@ -555,8 +548,7 @@
 				continue;
 		}
 
-		len = urb->iso_frame_desc[i].actual_length - 4;
-
+		len = urb->iso_frame_desc[i].actual_length;
 		if (urb->iso_frame_desc[i].actual_length <= 0) {
 			/* em28xx_isocdbg("packet %d is empty",i); - spammy */
 			continue;
@@ -577,6 +569,17 @@
 			dev->vbi_read = 0;
 			em28xx_isocdbg("VBI START HEADER!!!\n");
 			dev->cur_field = p[2];
+			p += 4;
+			len -= 4;
+		} else if (p[0] == 0x88 && p[1] == 0x88 &&
+			   p[2] == 0x88 && p[3] == 0x88) {
+			/* continuation */
+			p += 4;
+			len -= 4;
+		} else if (p[0] == 0x22 && p[1] == 0x5a) {
+			/* start video */
+			p += 4;
+			len -= 4;
 		}
 
 		vbi_size = dev->vbi_width * dev->vbi_height;
@@ -631,9 +634,6 @@
 
 		if (dev->capture_type == 1) {
 			dev->capture_type = 2;
-			em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2],
-				       len, (p[2] & 1) ? "odd" : "even");
-
 			if (dev->progressive || !(dev->cur_field & 1)) {
 				if (buf != NULL)
 					buffer_filled(dev, dma_q, buf);
@@ -652,8 +652,25 @@
 
 			dma_q->pos = 0;
 		}
-		if (buf != NULL && dev->capture_type == 2)
-			em28xx_copy_video(dev, dma_q, buf, p, outp, len);
+
+		if (buf != NULL && dev->capture_type == 2) {
+			if (len > 4 && p[0] == 0x88 && p[1] == 0x88 &&
+			    p[2] == 0x88 && p[3] == 0x88) {
+				p += 4;
+				len -= 4;
+			}
+			if (len > 4 && p[0] == 0x22 && p[1] == 0x5a) {
+				em28xx_isocdbg("Video frame %d, len=%i, %s\n",
+					       p[2], len, (p[2] & 1) ?
+					       "odd" : "even");
+				p += 4;
+				len -= 4;
+			}
+
+			if (len > 0)
+				em28xx_copy_video(dev, dma_q, buf, p, outp,
+						  len);
+		}
 	}
 	return rc;
 }
@@ -1483,6 +1500,7 @@
 		return -EINVAL;
 
 	strcpy(t->name, "Tuner");
+	t->type = V4L2_TUNER_ANALOG_TV;
 
 	mutex_lock(&dev->lock);
 	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
@@ -1814,7 +1832,7 @@
 	mutex_lock(&dev->lock);
 
 	f->fmt.sliced.service_set = 0;
-	v4l2_device_call_all(&dev->v4l2_dev, 0, video, g_fmt, f);
+	v4l2_device_call_all(&dev->v4l2_dev, 0, vbi, g_sliced_fmt, &f->fmt.sliced);
 
 	if (f->fmt.sliced.service_set == 0)
 		rc = -EINVAL;
@@ -1836,7 +1854,7 @@
 		return rc;
 
 	mutex_lock(&dev->lock);
-	v4l2_device_call_all(&dev->v4l2_dev, 0, video, g_fmt, f);
+	v4l2_device_call_all(&dev->v4l2_dev, 0, vbi, g_sliced_fmt, &f->fmt.sliced);
 	mutex_unlock(&dev->lock);
 
 	if (f->fmt.sliced.service_set == 0)
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index ba6fe5d..b252d1b 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -68,6 +68,7 @@
 #define EM2820_BOARD_HERCULES_SMART_TV_USB2	  26
 #define EM2820_BOARD_PINNACLE_USB_2_FM1216ME	  27
 #define EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE 28
+#define EM2860_BOARD_TVP5150_REFERENCE_DESIGN	  29
 #define EM2820_BOARD_VIDEOLOGY_20K14XUSB	  30
 #define EM2821_BOARD_USBGEAR_VD204		  31
 #define EM2821_BOARD_SUPERCOMP_USB_2		  32
@@ -140,10 +141,10 @@
 #define EM28XX_NUM_BUFS 5
 
 /* number of packets for each buffer
-   windows requests only 40 packets .. so we better do the same
+   windows requests only 64 packets .. so we better do the same
    this is what I found out for all alternate numbers there!
  */
-#define EM28XX_NUM_PACKETS 40
+#define EM28XX_NUM_PACKETS 64
 
 #define EM28XX_INTERLACED_DEFAULT 1
 
@@ -411,7 +412,7 @@
 
 	struct em28xx_input       input[MAX_EM28XX_INPUT];
 	struct em28xx_input	  radio;
-	struct ir_scancode_table  *ir_codes;
+	char			  *ir_codes;
 };
 
 struct em28xx_eeprom {
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index e6c23d50..a5cfc76 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -1713,7 +1713,7 @@
 	if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
 		return -EFAULT;
 
-	for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+	for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) {
 		if (ctrl.id == s->qctrl[i].id) {
 			if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
 				return -EINVAL;
@@ -1723,7 +1723,9 @@
 			ctrl.value -= ctrl.value % s->qctrl[i].step;
 			break;
 		}
-
+	}
+	if (i == ARRAY_SIZE(s->qctrl))
+		return -EINVAL;
 	if ((err = s->set_ctrl(cam, &ctrl)))
 		return err;
 
diff --git a/drivers/media/video/font.h b/drivers/media/video/font.h
deleted file mode 100644
index 8b1fecc..0000000
--- a/drivers/media/video/font.h
+++ /dev/null
@@ -1,407 +0,0 @@
-static unsigned char rom8x16_bits[] = {
-/* Character 0 (0x30):
-   ht=16, width=8
-   +--------+
-   |        |
-   |        |
-   | *****  |
-   |**   ** |
-   |**   ** |
-   |**  *** |
-   |** **** |
-   |**** ** |
-   |***  ** |
-   |**   ** |
-   |**   ** |
-   | *****  |
-   |        |
-   |        |
-   |        |
-   |        |
-   +--------+ */
-0x00,
-0x00,
-0x7c,
-0xc6,
-0xc6,
-0xce,
-0xde,
-0xf6,
-0xe6,
-0xc6,
-0xc6,
-0x7c,
-0x00,
-0x00,
-0x00,
-0x00,
-
-/* Character 1 (0x31):
-   ht=16, width=8
-   +--------+
-   |        |
-   |        |
-   |   **   |
-   | ****   |
-   |   **   |
-   |   **   |
-   |   **   |
-   |   **   |
-   |   **   |
-   |   **   |
-   |   **   |
-   | ****** |
-   |        |
-   |        |
-   |        |
-   |        |
-   +--------+ */
-0x00,
-0x00,
-0x18,
-0x78,
-0x18,
-0x18,
-0x18,
-0x18,
-0x18,
-0x18,
-0x18,
-0x7e,
-0x00,
-0x00,
-0x00,
-0x00,
-
-/* Character 2 (0x32):
-   ht=16, width=8
-   +--------+
-   |        |
-   |        |
-   | *****  |
-   |**   ** |
-   |**   ** |
-   |     ** |
-   |    **  |
-   |   **   |
-   |  **    |
-   | **     |
-   |**   ** |
-   |******* |
-   |        |
-   |        |
-   |        |
-   |        |
-   +--------+ */
-0x00,
-0x00,
-0x7c,
-0xc6,
-0xc6,
-0x06,
-0x0c,
-0x18,
-0x30,
-0x60,
-0xc6,
-0xfe,
-0x00,
-0x00,
-0x00,
-0x00,
-
-/* Character 3 (0x33):
-   ht=16, width=8
-   +--------+
-   |        |
-   |        |
-   | *****  |
-   |**   ** |
-   |     ** |
-   |     ** |
-   |  ****  |
-   |     ** |
-   |     ** |
-   |     ** |
-   |**   ** |
-   | *****  |
-   |        |
-   |        |
-   |        |
-   |        |
-   +--------+ */
-0x00,
-0x00,
-0x7c,
-0xc6,
-0x06,
-0x06,
-0x3c,
-0x06,
-0x06,
-0x06,
-0xc6,
-0x7c,
-0x00,
-0x00,
-0x00,
-0x00,
-
-/* Character 4 (0x34):
-   ht=16, width=8
-   +--------+
-   |        |
-   |        |
-   |    **  |
-   |   ***  |
-   |  ****  |
-   | ** **  |
-   |**  **  |
-   |**  **  |
-   |******* |
-   |    **  |
-   |    **  |
-   |   **** |
-   |        |
-   |        |
-   |        |
-   |        |
-   +--------+ */
-0x00,
-0x00,
-0x0c,
-0x1c,
-0x3c,
-0x6c,
-0xcc,
-0xcc,
-0xfe,
-0x0c,
-0x0c,
-0x1e,
-0x00,
-0x00,
-0x00,
-0x00,
-
-/* Character 5 (0x35):
-   ht=16, width=8
-   +--------+
-   |        |
-   |        |
-   |******* |
-   |**      |
-   |**      |
-   |**      |
-   |******  |
-   |     ** |
-   |     ** |
-   |     ** |
-   |**   ** |
-   | *****  |
-   |        |
-   |        |
-   |        |
-   |        |
-   +--------+ */
-0x00,
-0x00,
-0xfe,
-0xc0,
-0xc0,
-0xc0,
-0xfc,
-0x06,
-0x06,
-0x06,
-0xc6,
-0x7c,
-0x00,
-0x00,
-0x00,
-0x00,
-
-/* Character 6 (0x36):
-   ht=16, width=8
-   +--------+
-   |        |
-   |        |
-   | *****  |
-   |**   ** |
-   |**      |
-   |**      |
-   |******  |
-   |**   ** |
-   |**   ** |
-   |**   ** |
-   |**   ** |
-   | *****  |
-   |        |
-   |        |
-   |        |
-   |        |
-   +--------+ */
-0x00,
-0x00,
-0x7c,
-0xc6,
-0xc0,
-0xc0,
-0xfc,
-0xc6,
-0xc6,
-0xc6,
-0xc6,
-0x7c,
-0x00,
-0x00,
-0x00,
-0x00,
-
-/* Character 7 (0x37):
-   ht=16, width=8
-   +--------+
-   |        |
-   |        |
-   |******* |
-   |**   ** |
-   |     ** |
-   |    **  |
-   |   **   |
-   |  **    |
-   |  **    |
-   |  **    |
-   |  **    |
-   |  **    |
-   |        |
-   |        |
-   |        |
-   |        |
-   +--------+ */
-0x00,
-0x00,
-0xfe,
-0xc6,
-0x06,
-0x0c,
-0x18,
-0x30,
-0x30,
-0x30,
-0x30,
-0x30,
-0x00,
-0x00,
-0x00,
-0x00,
-
-/* Character 8 (0x38):
-   ht=16, width=8
-   +--------+
-   |        |
-   |        |
-   | *****  |
-   |**   ** |
-   |**   ** |
-   |**   ** |
-   | *****  |
-   |**   ** |
-   |**   ** |
-   |**   ** |
-   |**   ** |
-   | *****  |
-   |        |
-   |        |
-   |        |
-   |        |
-   +--------+ */
-0x00,
-0x00,
-0x7c,
-0xc6,
-0xc6,
-0xc6,
-0x7c,
-0xc6,
-0xc6,
-0xc6,
-0xc6,
-0x7c,
-0x00,
-0x00,
-0x00,
-0x00,
-
-/* Character 9 (0x39):
-   ht=16, width=8
-   +--------+
-   |        |
-   |        |
-   | *****  |
-   |**   ** |
-   |**   ** |
-   |**   ** |
-   |**   ** |
-   | ****** |
-   |     ** |
-   |     ** |
-   |**   ** |
-   | *****  |
-   |        |
-   |        |
-   |        |
-   |        |
-   +--------+ */
-0x00,
-0x00,
-0x7c,
-0xc6,
-0xc6,
-0xc6,
-0xc6,
-0x7e,
-0x06,
-0x06,
-0xc6,
-0x7c,
-0x00,
-0x00,
-0x00,
-0x00,
-/* Character : (0x3a):
-   ht=16, width=8
-   +--------+
-   |        |
-   |        |
-   |        |
-   |        |
-   |        |
-   |    **  |
-   |    **  |
-   |        |
-   |        |
-   |    **  |
-   |    **  |
-   |        |
-   |        |
-   |        |
-   |        |
-   |        |
-   +--------+ */
-0x00,
-0x00,
-0x00,
-0x00,
-0x00,
-0x0c,
-0x0c,
-0x00,
-0x00,
-0x0c,
-0x0c,
-0x00,
-0x00,
-0x00,
-0x00,
-0x00,
-};
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig
index e0060c1..5d920e5 100644
--- a/drivers/media/video/gspca/Kconfig
+++ b/drivers/media/video/gspca/Kconfig
@@ -172,12 +172,6 @@
 	 To compile this driver as a module, choose M here: the
 	 module will be called gspca_sn9c20x.
 
-config USB_GSPCA_SN9C20X_EVDEV
-	bool "Enable evdev support"
-	depends on USB_GSPCA_SN9C20X && INPUT
-	---help---
-	  Say Y here in order to enable evdev support for sn9c20x webcam button.
-
 config USB_GSPCA_SONIXB
 	tristate "SONIX Bayer USB Camera Driver"
 	depends on VIDEO_V4L2 && USB_GSPCA
diff --git a/drivers/media/video/gspca/cpia1.c b/drivers/media/video/gspca/cpia1.c
index 82945ed..58b696f 100644
--- a/drivers/media/video/gspca/cpia1.c
+++ b/drivers/media/video/gspca/cpia1.c
@@ -374,7 +374,7 @@
 static int sd_setcomptarget(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getcomptarget(struct gspca_dev *gspca_dev, __s32 *val);
 
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
 	{
 	    {
 		.id      = V4L2_CID_BRIGHTNESS,
@@ -861,7 +861,7 @@
 	return do_command(gspca_dev, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
 }
 
-int command_setformat(struct gspca_dev *gspca_dev)
+static int command_setformat(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	int ret;
@@ -878,7 +878,7 @@
 			  sd->params.roi.rowStart, sd->params.roi.rowEnd);
 }
 
-int command_setcolourparams(struct gspca_dev *gspca_dev)
+static int command_setcolourparams(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	return do_command(gspca_dev, CPIA_COMMAND_SetColourParams,
@@ -887,7 +887,7 @@
 			  sd->params.colourParams.saturation, 0);
 }
 
-int command_setapcor(struct gspca_dev *gspca_dev)
+static int command_setapcor(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	return do_command(gspca_dev, CPIA_COMMAND_SetApcor,
@@ -897,7 +897,7 @@
 			  sd->params.apcor.gain8);
 }
 
-int command_setvloffset(struct gspca_dev *gspca_dev)
+static int command_setvloffset(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	return do_command(gspca_dev, CPIA_COMMAND_SetVLOffset,
@@ -907,7 +907,7 @@
 			  sd->params.vlOffset.gain8);
 }
 
-int command_setexposure(struct gspca_dev *gspca_dev)
+static int command_setexposure(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	int ret;
@@ -943,7 +943,7 @@
 	return ret;
 }
 
-int command_setcolourbalance(struct gspca_dev *gspca_dev)
+static int command_setcolourbalance(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
@@ -973,7 +973,7 @@
 	return -EINVAL;
 }
 
-int command_setcompressiontarget(struct gspca_dev *gspca_dev)
+static int command_setcompressiontarget(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
@@ -983,7 +983,7 @@
 			  sd->params.compressionTarget.targetQ, 0);
 }
 
-int command_setyuvtresh(struct gspca_dev *gspca_dev)
+static int command_setyuvtresh(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
@@ -992,7 +992,7 @@
 			  sd->params.yuvThreshold.uvThreshold, 0, 0);
 }
 
-int command_setcompressionparams(struct gspca_dev *gspca_dev)
+static int command_setcompressionparams(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
@@ -1009,7 +1009,7 @@
 			    sd->params.compressionParams.decimationThreshMod);
 }
 
-int command_setcompression(struct gspca_dev *gspca_dev)
+static int command_setcompression(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
@@ -1018,7 +1018,7 @@
 			  sd->params.compression.decimation, 0, 0);
 }
 
-int command_setsensorfps(struct gspca_dev *gspca_dev)
+static int command_setsensorfps(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
@@ -1027,7 +1027,7 @@
 			  sd->params.sensorFps.baserate, 0, 0);
 }
 
-int command_setflickerctrl(struct gspca_dev *gspca_dev)
+static int command_setflickerctrl(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
@@ -1038,7 +1038,7 @@
 			  0);
 }
 
-int command_setecptiming(struct gspca_dev *gspca_dev)
+static int command_setecptiming(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
@@ -1046,12 +1046,12 @@
 			  sd->params.ecpTiming, 0, 0, 0);
 }
 
-int command_pause(struct gspca_dev *gspca_dev)
+static int command_pause(struct gspca_dev *gspca_dev)
 {
 	return do_command(gspca_dev, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
 }
 
-int command_resume(struct gspca_dev *gspca_dev)
+static int command_resume(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
@@ -1059,7 +1059,8 @@
 			  0, sd->params.streamStartLine, 0, 0);
 }
 
-int command_setlights(struct gspca_dev *gspca_dev)
+#if 0 /* Currently unused */
+static int command_setlights(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	int ret, p1, p2;
@@ -1078,6 +1079,7 @@
 	return do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, 2, 0,
 			  p1 | p2 | 0xE0, 0);
 }
+#endif
 
 static int set_flicker(struct gspca_dev *gspca_dev, int on, int apply)
 {
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index 222af47..efe6159 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -1,7 +1,7 @@
 /*
  * Main USB camera driver
  *
- * Copyright (C) 2008-2009 Jean-Francois Moine (http://moinejf.free.fr)
+ * Copyright (C) 2008-2010 Jean-François Moine <http://moinejf.free.fr>
  *
  * Camera button input handling by Márton Németh
  * Copyright (C) 2009-2010 Márton Németh <nm127@freemail.hu>
@@ -35,12 +35,12 @@
 #include <linux/io.h>
 #include <asm/page.h>
 #include <linux/uaccess.h>
-#include <linux/jiffies.h>
+#include <linux/ktime.h>
 #include <media/v4l2-ioctl.h>
 
 #include "gspca.h"
 
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 #include <linux/input.h>
 #include <linux/usb/input.h>
 #endif
@@ -51,7 +51,7 @@
 #error "DEF_NURBS too big"
 #endif
 
-MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
+MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("GSPCA USB Camera Driver");
 MODULE_LICENSE("GPL");
 
@@ -115,7 +115,7 @@
 /*
  * Input and interrupt endpoint handling functions
  */
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 static void int_irq(struct urb *urb)
 {
 	struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
@@ -199,7 +199,7 @@
 	void *buffer = NULL;
 	int ret = -EINVAL;
 
-	buffer_len = ep->wMaxPacketSize;
+	buffer_len = le16_to_cpu(ep->wMaxPacketSize);
 	interval = ep->bInterval;
 	PDEBUG(D_PROBE, "found int in endpoint: 0x%x, "
 		"buffer_len=%u, interval=%u",
@@ -213,7 +213,7 @@
 		goto error;
 	}
 
-	buffer = usb_buffer_alloc(dev, ep->wMaxPacketSize,
+	buffer = usb_buffer_alloc(dev, buffer_len,
 				GFP_KERNEL, &urb->transfer_dma);
 	if (!buffer) {
 		ret = -ENOMEM;
@@ -280,9 +280,18 @@
 	}
 }
 #else
-#define gspca_input_connect(gspca_dev)		0
-#define gspca_input_create_urb(gspca_dev)
-#define gspca_input_destroy_urb(gspca_dev)
+static inline void gspca_input_destroy_urb(struct gspca_dev *gspca_dev)
+{
+}
+
+static inline void gspca_input_create_urb(struct gspca_dev *gspca_dev)
+{
+}
+
+static inline int gspca_input_connect(struct gspca_dev *dev)
+{
+	return 0;
+}
 #endif
 
 /* get the current input frame buffer */
@@ -442,8 +451,7 @@
 	 * is not queued, discard the whole frame */
 	if (packet_type == FIRST_PACKET) {
 		frame->data_end = frame->data;
-		jiffies_to_timeval(get_jiffies_64(),
-				   &frame->v4l2_buf.timestamp);
+		frame->v4l2_buf.timestamp = ktime_to_timeval(ktime_get());
 		frame->v4l2_buf.sequence = ++gspca_dev->sequence;
 	} else if (gspca_dev->last_packet_type == DISCARD_PACKET) {
 		if (packet_type == LAST_PACKET)
@@ -605,6 +613,37 @@
 	}
 }
 
+static int gspca_set_alt0(struct gspca_dev *gspca_dev)
+{
+	int ret;
+
+	if (gspca_dev->alt == 0)
+		return 0;
+	ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0);
+	if (ret < 0)
+		PDEBUG(D_ERR|D_STREAM, "set alt 0 err %d", ret);
+	return ret;
+}
+
+/* Note: both the queue and the usb locks should be held when calling this */
+static void gspca_stream_off(struct gspca_dev *gspca_dev)
+{
+	gspca_dev->streaming = 0;
+	if (gspca_dev->present) {
+		if (gspca_dev->sd_desc->stopN)
+			gspca_dev->sd_desc->stopN(gspca_dev);
+		destroy_urbs(gspca_dev);
+		gspca_input_destroy_urb(gspca_dev);
+		gspca_set_alt0(gspca_dev);
+		gspca_input_create_urb(gspca_dev);
+	}
+
+	/* always call stop0 to free the subdriver's resources */
+	if (gspca_dev->sd_desc->stop0)
+		gspca_dev->sd_desc->stop0(gspca_dev);
+	PDEBUG(D_STREAM, "stream off OK");
+}
+
 /*
  * look for an input transfer endpoint in an alternate setting
  */
@@ -830,8 +869,7 @@
 		}
 		if (ret >= 0)
 			break;
-		gspca_dev->streaming = 0;
-		destroy_urbs(gspca_dev);
+		gspca_stream_off(gspca_dev);
 		if (ret != -ENOSPC) {
 			PDEBUG(D_ERR|D_STREAM,
 				"usb_submit_urb alt %d err %d",
@@ -861,37 +899,6 @@
 	return ret;
 }
 
-static int gspca_set_alt0(struct gspca_dev *gspca_dev)
-{
-	int ret;
-
-	if (gspca_dev->alt == 0)
-		return 0;
-	ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0);
-	if (ret < 0)
-		PDEBUG(D_ERR|D_STREAM, "set alt 0 err %d", ret);
-	return ret;
-}
-
-/* Note: both the queue and the usb locks should be held when calling this */
-static void gspca_stream_off(struct gspca_dev *gspca_dev)
-{
-	gspca_dev->streaming = 0;
-	if (gspca_dev->present) {
-		if (gspca_dev->sd_desc->stopN)
-			gspca_dev->sd_desc->stopN(gspca_dev);
-		destroy_urbs(gspca_dev);
-		gspca_input_destroy_urb(gspca_dev);
-		gspca_set_alt0(gspca_dev);
-		gspca_input_create_urb(gspca_dev);
-	}
-
-	/* always call stop0 to free the subdriver's resources */
-	if (gspca_dev->sd_desc->stop0)
-		gspca_dev->sd_desc->stop0(gspca_dev);
-	PDEBUG(D_STREAM, "stream off OK");
-}
-
 static void gspca_set_default_mode(struct gspca_dev *gspca_dev)
 {
 	int i;
@@ -1495,7 +1502,7 @@
 			  struct v4l2_requestbuffers *rb)
 {
 	struct gspca_dev *gspca_dev = priv;
-	int i, ret = 0;
+	int i, ret = 0, streaming;
 
 	switch (rb->memory) {
 	case GSPCA_MEMORY_READ:			/* (internal call) */
@@ -1530,7 +1537,8 @@
 	}
 
 	/* stop streaming */
-	if (gspca_dev->streaming) {
+	streaming = gspca_dev->streaming;
+	if (streaming) {
 		mutex_lock(&gspca_dev->usb_lock);
 		gspca_dev->usb_err = 0;
 		gspca_stream_off(gspca_dev);
@@ -1549,6 +1557,8 @@
 	if (ret == 0) {
 		rb->count = gspca_dev->nframes;
 		gspca_dev->capt_file = file;
+		if (streaming)
+			ret = gspca_init_transfer(gspca_dev);
 	}
 out:
 	mutex_unlock(&gspca_dev->queue_lock);
@@ -1582,6 +1592,12 @@
 	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
 		return -ERESTARTSYS;
 
+	/* check the capture file */
+	if (gspca_dev->capt_file != file) {
+		ret = -EBUSY;
+		goto out;
+	}
+
 	if (gspca_dev->nframes == 0
 	    || !(gspca_dev->frame[0].v4l2_buf.flags & V4L2_BUF_FLAG_QUEUED)) {
 		ret = -EINVAL;
@@ -1619,6 +1635,12 @@
 	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
 		return -ERESTARTSYS;
 
+	/* check the capture file */
+	if (gspca_dev->capt_file != file) {
+		ret = -EBUSY;
+		goto out;
+	}
+
 	/* stop streaming */
 	if (mutex_lock_interruptible(&gspca_dev->usb_lock)) {
 		ret = -ERESTARTSYS;
@@ -2124,7 +2146,7 @@
 	}
 
 	/* get a frame */
-	jiffies_to_timeval(get_jiffies_64(), &timestamp);
+	timestamp = ktime_to_timeval(ktime_get());
 	timestamp.tv_sec--;
 	n = 2;
 	for (;;) {
@@ -2315,7 +2337,7 @@
 
 	return 0;
 out:
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 	if (gspca_dev->input_dev)
 		input_unregister_device(gspca_dev->input_dev);
 #endif
@@ -2334,7 +2356,7 @@
 void gspca_disconnect(struct usb_interface *intf)
 {
 	struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 	struct input_dev *input_dev;
 #endif
 
@@ -2348,7 +2370,7 @@
 		wake_up_interruptible(&gspca_dev->wq);
 	}
 
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 	gspca_input_destroy_urb(gspca_dev);
 	input_dev = gspca_dev->input_dev;
 	if (input_dev) {
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index 8bb242f..8b963df 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -130,7 +130,7 @@
 	cam_reg_op get_register;
 #endif
 	cam_ident_op get_chip_ident;
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 	cam_int_pkt_op int_pkt_scan;
 	/* other_input makes the gspca core create gspca_dev->input even when
 	   int_pkt_scan is NULL, for cams with non interrupt driven buttons */
@@ -158,7 +158,7 @@
 	struct module *module;		/* subdriver handling the device */
 	struct usb_device *dev;
 	struct file *capt_file;		/* file doing video capture */
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 	struct input_dev *input_dev;
 	char phys[64];			/* physical device path */
 #endif
@@ -171,7 +171,7 @@
 #define USB_BUF_SZ 64
 	__u8 *usb_buf;				/* buffer for USB exchanges */
 	struct urb *urb[MAX_NURBS];
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 	struct urb *int_urb;
 #endif
 
diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c
index 957e05e..dc1e4ef 100644
--- a/drivers/media/video/gspca/ov534.c
+++ b/drivers/media/video/gspca/ov534.c
@@ -10,8 +10,8 @@
  * https://jim.sh/svn/jim/devl/playstation/ps3/eye/test/
  *
  * PS3 Eye camera enhanced by Richard Kaswy http://kaswy.free.fr
- * PS3 Eye camera, brightness, contrast, hue, AWB control added
- *	by Max Thrun <bear24rw@gmail.com>
+ * PS3 Eye camera - brightness, contrast, awb, agc, aec controls
+ *                  added by Max Thrun <bear24rw@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -60,15 +60,13 @@
 	u8 contrast;
 	u8 gain;
 	u8 exposure;
-	u8 redblc;
-	u8 blueblc;
-	u8 hue;
-	u8 autogain;
+	u8 agc;
 	u8 awb;
+	u8 aec;
 	s8 sharpness;
 	u8 hflip;
 	u8 vflip;
-
+	u8 freqfltr;
 };
 
 /* V4L2 controls supported by the driver */
@@ -76,197 +74,183 @@
 static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setredblc(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getredblc(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setblueblc(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getblueblc(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setagc(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getagc(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setaec(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getaec(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreqfltr(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreqfltr(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+		struct v4l2_querymenu *menu);
 
 static const struct ctrl sd_ctrls[] = {
-    {							/* 0 */
-	{
-		.id      = V4L2_CID_BRIGHTNESS,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Brightness",
-		.minimum = 0,
-		.maximum = 255,
-		.step    = 1,
-#define BRIGHTNESS_DEF 20
-		.default_value = BRIGHTNESS_DEF,
+	{	/* 0 */
+		{
+			.id      = V4L2_CID_BRIGHTNESS,
+			.type    = V4L2_CTRL_TYPE_INTEGER,
+			.name    = "Brightness",
+			.minimum = 0,
+			.maximum = 255,
+			.step    = 1,
+#define BRIGHTNESS_DEF 0
+			.default_value = BRIGHTNESS_DEF,
+		},
+		.set = sd_setbrightness,
+		.get = sd_getbrightness,
 	},
-	.set = sd_setbrightness,
-	.get = sd_getbrightness,
-    },
-    {							/* 1 */
-	{
-		.id      = V4L2_CID_CONTRAST,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Contrast",
-		.minimum = 0,
-		.maximum = 255,
-		.step    = 1,
-#define CONTRAST_DEF 37
-		.default_value = CONTRAST_DEF,
+	{	/* 1 */
+		{
+			.id      = V4L2_CID_CONTRAST,
+			.type    = V4L2_CTRL_TYPE_INTEGER,
+			.name    = "Contrast",
+			.minimum = 0,
+			.maximum = 255,
+			.step    = 1,
+#define CONTRAST_DEF 32
+			.default_value = CONTRAST_DEF,
+		},
+		.set = sd_setcontrast,
+		.get = sd_getcontrast,
 	},
-	.set = sd_setcontrast,
-	.get = sd_getcontrast,
-    },
-    {							/* 2 */
-	{
-	    .id      = V4L2_CID_GAIN,
-	    .type    = V4L2_CTRL_TYPE_INTEGER,
-	    .name    = "Main Gain",
-	    .minimum = 0,
-	    .maximum = 63,
-	    .step    = 1,
+	{	/* 2 */
+		{
+			.id      = V4L2_CID_GAIN,
+			.type    = V4L2_CTRL_TYPE_INTEGER,
+			.name    = "Main Gain",
+			.minimum = 0,
+			.maximum = 63,
+			.step    = 1,
 #define GAIN_DEF 20
-	    .default_value = GAIN_DEF,
+			.default_value = GAIN_DEF,
+		},
+		.set = sd_setgain,
+		.get = sd_getgain,
 	},
-	.set = sd_setgain,
-	.get = sd_getgain,
-    },
-    {							/* 3 */
-	{
-	    .id      = V4L2_CID_EXPOSURE,
-	    .type    = V4L2_CTRL_TYPE_INTEGER,
-	    .name    = "Exposure",
-	    .minimum = 0,
-	    .maximum = 255,
-	    .step    = 1,
+	{	/* 3 */
+		{
+			.id      = V4L2_CID_EXPOSURE,
+			.type    = V4L2_CTRL_TYPE_INTEGER,
+			.name    = "Exposure",
+			.minimum = 0,
+			.maximum = 255,
+			.step    = 1,
 #define EXPO_DEF 120
-	    .default_value = EXPO_DEF,
+			.default_value = EXPO_DEF,
+		},
+		.set = sd_setexposure,
+		.get = sd_getexposure,
 	},
-	.set = sd_setexposure,
-	.get = sd_getexposure,
-    },
-    {							/* 4 */
-	{
-	    .id      = V4L2_CID_RED_BALANCE,
-	    .type    = V4L2_CTRL_TYPE_INTEGER,
-	    .name    = "Red Balance",
-	    .minimum = 0,
-	    .maximum = 255,
-	    .step    = 1,
-#define RED_BALANCE_DEF 128
-	    .default_value = RED_BALANCE_DEF,
+	{	/* 4 */
+		{
+			.id      = V4L2_CID_AUTOGAIN,
+			.type    = V4L2_CTRL_TYPE_BOOLEAN,
+			.name    = "Auto Gain",
+			.minimum = 0,
+			.maximum = 1,
+			.step    = 1,
+#define AGC_DEF 1
+			.default_value = AGC_DEF,
+		},
+		.set = sd_setagc,
+		.get = sd_getagc,
 	},
-	.set = sd_setredblc,
-	.get = sd_getredblc,
-    },
-    {							/* 5 */
-	{
-	    .id      = V4L2_CID_BLUE_BALANCE,
-	    .type    = V4L2_CTRL_TYPE_INTEGER,
-	    .name    = "Blue Balance",
-	    .minimum = 0,
-	    .maximum = 255,
-	    .step    = 1,
-#define BLUE_BALANCE_DEF 128
-	    .default_value = BLUE_BALANCE_DEF,
+#define AWB_IDX 5
+	{	/* 5 */
+		{
+			.id      = V4L2_CID_AUTO_WHITE_BALANCE,
+			.type    = V4L2_CTRL_TYPE_BOOLEAN,
+			.name    = "Auto White Balance",
+			.minimum = 0,
+			.maximum = 1,
+			.step    = 1,
+#define AWB_DEF 1
+			.default_value = AWB_DEF,
+		},
+		.set = sd_setawb,
+		.get = sd_getawb,
 	},
-	.set = sd_setblueblc,
-	.get = sd_getblueblc,
-    },
-    {							/* 6 */
-	{
-		.id      = V4L2_CID_HUE,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Hue",
-		.minimum = 0,
-		.maximum = 255,
-		.step    = 1,
-#define HUE_DEF 143
-		.default_value = HUE_DEF,
+	{	/* 6 */
+		{
+			.id      = V4L2_CID_EXPOSURE_AUTO,
+			.type    = V4L2_CTRL_TYPE_BOOLEAN,
+			.name    = "Auto Exposure",
+			.minimum = 0,
+			.maximum = 1,
+			.step    = 1,
+#define AEC_DEF 1
+			.default_value = AEC_DEF,
+		},
+		.set = sd_setaec,
+		.get = sd_getaec,
 	},
-	.set = sd_sethue,
-	.get = sd_gethue,
-    },
-    {							/* 7 */
-	{
-	    .id      = V4L2_CID_AUTOGAIN,
-	    .type    = V4L2_CTRL_TYPE_BOOLEAN,
-	    .name    = "Autogain",
-	    .minimum = 0,
-	    .maximum = 1,
-	    .step    = 1,
-#define AUTOGAIN_DEF 0
-	    .default_value = AUTOGAIN_DEF,
-	},
-	.set = sd_setautogain,
-	.get = sd_getautogain,
-    },
-#define AWB_IDX 8
-    {							/* 8 */
-	{
-		.id      = V4L2_CID_AUTO_WHITE_BALANCE,
-		.type    = V4L2_CTRL_TYPE_BOOLEAN,
-		.name    = "Auto White Balance",
-		.minimum = 0,
-		.maximum = 1,
-		.step    = 1,
-#define AWB_DEF 0
-		.default_value = AWB_DEF,
-	},
-	.set = sd_setawb,
-	.get = sd_getawb,
-    },
-    {							/* 9 */
-	{
-	    .id      = V4L2_CID_SHARPNESS,
-	    .type    = V4L2_CTRL_TYPE_INTEGER,
-	    .name    = "Sharpness",
-	    .minimum = 0,
-	    .maximum = 63,
-	    .step    = 1,
+	{	/* 7 */
+		{
+			.id      = V4L2_CID_SHARPNESS,
+			.type    = V4L2_CTRL_TYPE_INTEGER,
+			.name    = "Sharpness",
+			.minimum = 0,
+			.maximum = 63,
+			.step    = 1,
 #define SHARPNESS_DEF 0
-	    .default_value = SHARPNESS_DEF,
+			.default_value = SHARPNESS_DEF,
+		},
+		.set = sd_setsharpness,
+		.get = sd_getsharpness,
 	},
-	.set = sd_setsharpness,
-	.get = sd_getsharpness,
-    },
-    {							/* 10 */
-	{
-	    .id      = V4L2_CID_HFLIP,
-	    .type    = V4L2_CTRL_TYPE_BOOLEAN,
-	    .name    = "HFlip",
-	    .minimum = 0,
-	    .maximum = 1,
-	    .step    = 1,
+	{	/* 8 */
+		{
+			.id      = V4L2_CID_HFLIP,
+			.type    = V4L2_CTRL_TYPE_BOOLEAN,
+			.name    = "HFlip",
+			.minimum = 0,
+			.maximum = 1,
+			.step    = 1,
 #define HFLIP_DEF 0
-	    .default_value = HFLIP_DEF,
+			.default_value = HFLIP_DEF,
+		},
+		.set = sd_sethflip,
+		.get = sd_gethflip,
 	},
-	.set = sd_sethflip,
-	.get = sd_gethflip,
-    },
-    {							/* 11 */
-	{
-	    .id      = V4L2_CID_VFLIP,
-	    .type    = V4L2_CTRL_TYPE_BOOLEAN,
-	    .name    = "VFlip",
-	    .minimum = 0,
-	    .maximum = 1,
-	    .step    = 1,
+	{	/* 9 */
+		{
+			.id      = V4L2_CID_VFLIP,
+			.type    = V4L2_CTRL_TYPE_BOOLEAN,
+			.name    = "VFlip",
+			.minimum = 0,
+			.maximum = 1,
+			.step    = 1,
 #define VFLIP_DEF 0
-	    .default_value = VFLIP_DEF,
+			.default_value = VFLIP_DEF,
+		},
+		.set = sd_setvflip,
+		.get = sd_getvflip,
 	},
-	.set = sd_setvflip,
-	.get = sd_getvflip,
-    },
+	{	/* 10 */
+		{
+			.id      = V4L2_CID_POWER_LINE_FREQUENCY,
+			.type    = V4L2_CTRL_TYPE_MENU,
+			.name    = "Light Frequency Filter",
+			.minimum = 0,
+			.maximum = 1,
+			.step    = 1,
+#define FREQFLTR_DEF 0
+			.default_value = FREQFLTR_DEF,
+		},
+		.set = sd_setfreqfltr,
+		.get = sd_getfreqfltr,
+	},
 };
 
 static const struct v4l2_pix_format ov772x_mode[] = {
@@ -675,14 +659,14 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	sccb_reg_write(gspca_dev, 0x9B, sd->brightness);
+	sccb_reg_write(gspca_dev, 0x9b, sd->brightness);
 }
 
 static void setcontrast(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	sccb_reg_write(gspca_dev, 0x9C, sd->contrast);
+	sccb_reg_write(gspca_dev, 0x9c, sd->contrast);
 }
 
 static void setgain(struct gspca_dev *gspca_dev)
@@ -690,6 +674,9 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 	u8 val;
 
+	if (sd->agc)
+		return;
+
 	val = sd->gain;
 	switch (val & 0x30) {
 	case 0x00:
@@ -717,44 +704,36 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 	u8 val;
 
+	if (sd->aec)
+		return;
+
+	/* 'val' is one byte and represents half of the exposure value we are
+	 * going to set into registers, a two bytes value:
+	 *
+	 *    MSB: ((u16) val << 1) >> 8   == val >> 7
+	 *    LSB: ((u16) val << 1) & 0xff == val << 1
+	 */
 	val = sd->exposure;
 	sccb_reg_write(gspca_dev, 0x08, val >> 7);
 	sccb_reg_write(gspca_dev, 0x10, val << 1);
 }
 
-static void setredblc(struct gspca_dev *gspca_dev)
+static void setagc(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	sccb_reg_write(gspca_dev, 0x43, sd->redblc);
-}
-
-static void setblueblc(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sccb_reg_write(gspca_dev, 0x42, sd->blueblc);
-}
-
-static void sethue(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sccb_reg_write(gspca_dev, 0x01, sd->hue);
-}
-
-static void setautogain(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	if (sd->autogain) {
-		sccb_reg_write(gspca_dev, 0x13, 0xf7); /* AGC,AEC,AWB ON */
+	if (sd->agc) {
+		sccb_reg_write(gspca_dev, 0x13,
+				sccb_reg_read(gspca_dev, 0x13) | 0x04);
 		sccb_reg_write(gspca_dev, 0x64,
 				sccb_reg_read(gspca_dev, 0x64) | 0x03);
 	} else {
-		sccb_reg_write(gspca_dev, 0x13, 0xf0); /* AGC,AEC,AWB OFF */
+		sccb_reg_write(gspca_dev, 0x13,
+				sccb_reg_read(gspca_dev, 0x13) & ~0x04);
 		sccb_reg_write(gspca_dev, 0x64,
-				sccb_reg_read(gspca_dev, 0x64) & 0xfc);
+				sccb_reg_read(gspca_dev, 0x64) & ~0x03);
+
+		setgain(gspca_dev);
 	}
 }
 
@@ -762,10 +741,31 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	if (sd->awb)
-		sccb_reg_write(gspca_dev, 0x63, 0xe0);	/* AWB on */
-	else
-		sccb_reg_write(gspca_dev, 0x63, 0xaa);	/* AWB off */
+	if (sd->awb) {
+		sccb_reg_write(gspca_dev, 0x13,
+				sccb_reg_read(gspca_dev, 0x13) | 0x02);
+		sccb_reg_write(gspca_dev, 0x63,
+				sccb_reg_read(gspca_dev, 0x63) | 0xc0);
+	} else {
+		sccb_reg_write(gspca_dev, 0x13,
+				sccb_reg_read(gspca_dev, 0x13) & ~0x02);
+		sccb_reg_write(gspca_dev, 0x63,
+				sccb_reg_read(gspca_dev, 0x63) & ~0xc0);
+	}
+}
+
+static void setaec(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->aec)
+		sccb_reg_write(gspca_dev, 0x13,
+				sccb_reg_read(gspca_dev, 0x13) | 0x01);
+	else {
+		sccb_reg_write(gspca_dev, 0x13,
+				sccb_reg_read(gspca_dev, 0x13) & ~0x01);
+		setexposure(gspca_dev);
+	}
 }
 
 static void setsharpness(struct gspca_dev *gspca_dev)
@@ -774,8 +774,8 @@
 	u8 val;
 
 	val = sd->sharpness;
-	sccb_reg_write(gspca_dev, 0x91, val);	/* vga noise */
-	sccb_reg_write(gspca_dev, 0x8e, val);	/* qvga noise */
+	sccb_reg_write(gspca_dev, 0x91, val);	/* Auto de-noise threshold */
+	sccb_reg_write(gspca_dev, 0x8e, val);	/* De-noise threshold */
 }
 
 static void sethflip(struct gspca_dev *gspca_dev)
@@ -787,7 +787,7 @@
 				sccb_reg_read(gspca_dev, 0x0c) | 0x40);
 	else
 		sccb_reg_write(gspca_dev, 0x0c,
-				sccb_reg_read(gspca_dev, 0x0c) & 0xbf);
+				sccb_reg_read(gspca_dev, 0x0c) & ~0x40);
 }
 
 static void setvflip(struct gspca_dev *gspca_dev)
@@ -799,9 +799,20 @@
 				sccb_reg_read(gspca_dev, 0x0c) | 0x80);
 	else
 		sccb_reg_write(gspca_dev, 0x0c,
-				sccb_reg_read(gspca_dev, 0x0c) & 0x7f);
+				sccb_reg_read(gspca_dev, 0x0c) & ~0x80);
 }
 
+static void setfreqfltr(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->freqfltr == 0)
+		sccb_reg_write(gspca_dev, 0x2b, 0x00);
+	else
+		sccb_reg_write(gspca_dev, 0x2b, 0x9e);
+}
+
+
 /* this function is called at probe time */
 static int sd_config(struct gspca_dev *gspca_dev,
 		     const struct usb_device_id *id)
@@ -825,26 +836,17 @@
 	sd->contrast = CONTRAST_DEF;
 	sd->gain = GAIN_DEF;
 	sd->exposure = EXPO_DEF;
-	sd->redblc = RED_BALANCE_DEF;
-	sd->blueblc = BLUE_BALANCE_DEF;
-	sd->hue = HUE_DEF;
-#if AUTOGAIN_DEF != 0
-	sd->autogain = AUTOGAIN_DEF;
+#if AGC_DEF != 0
+	sd->agc = AGC_DEF;
 #else
 	gspca_dev->ctrl_inac |= (1 << AWB_IDX);
 #endif
-#if AWB_DEF != 0
-	sd->awb = AWB_DEF
-#endif
-#if SHARPNESS_DEF != 0
+	sd->awb = AWB_DEF;
+	sd->aec = AEC_DEF;
 	sd->sharpness = SHARPNESS_DEF;
-#endif
-#if HFLIP_DEF != 0
 	sd->hflip = HFLIP_DEF;
-#endif
-#if VFLIP_DEF != 0
 	sd->vflip = VFLIP_DEF;
-#endif
+	sd->freqfltr = FREQFLTR_DEF;
 
 	return 0;
 }
@@ -904,18 +906,17 @@
 	}
 	set_frame_rate(gspca_dev);
 
-	setautogain(gspca_dev);
+	setagc(gspca_dev);
 	setawb(gspca_dev);
+	setaec(gspca_dev);
 	setgain(gspca_dev);
-	setredblc(gspca_dev);
-	setblueblc(gspca_dev);
-	sethue(gspca_dev);
 	setexposure(gspca_dev);
 	setbrightness(gspca_dev);
 	setcontrast(gspca_dev);
 	setsharpness(gspca_dev);
 	setvflip(gspca_dev);
 	sethflip(gspca_dev);
+	setfreqfltr(gspca_dev);
 
 	ov534_set_led(gspca_dev, 1);
 	ov534_reg_write(gspca_dev, 0xe0, 0x00);
@@ -1092,65 +1093,11 @@
 	return 0;
 }
 
-static int sd_setredblc(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setagc(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	sd->redblc = val;
-	if (gspca_dev->streaming)
-		setredblc(gspca_dev);
-	return 0;
-}
-
-static int sd_getredblc(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->redblc;
-	return 0;
-}
-
-static int sd_setblueblc(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->blueblc = val;
-	if (gspca_dev->streaming)
-		setblueblc(gspca_dev);
-	return 0;
-}
-
-static int sd_getblueblc(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->blueblc;
-	return 0;
-}
-
-static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->hue = val;
-	if (gspca_dev->streaming)
-		sethue(gspca_dev);
-	return 0;
-}
-
-static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->hue;
-	return 0;
-}
-
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->autogain = val;
+	sd->agc = val;
 
 	if (gspca_dev->streaming) {
 
@@ -1160,16 +1107,16 @@
 			gspca_dev->ctrl_inac &= ~(1 << AWB_IDX);
 		else
 			gspca_dev->ctrl_inac |= (1 << AWB_IDX);
-		setautogain(gspca_dev);
+		setagc(gspca_dev);
 	}
 	return 0;
 }
 
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getagc(struct gspca_dev *gspca_dev, __s32 *val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	*val = sd->autogain;
+	*val = sd->agc;
 	return 0;
 }
 
@@ -1191,6 +1138,24 @@
 	return 0;
 }
 
+static int sd_setaec(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->aec = val;
+	if (gspca_dev->streaming)
+		setaec(gspca_dev);
+	return 0;
+}
+
+static int sd_getaec(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->aec;
+	return 0;
+}
+
 static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -1245,6 +1210,43 @@
 	return 0;
 }
 
+static int sd_setfreqfltr(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->freqfltr = val;
+	if (gspca_dev->streaming)
+		setfreqfltr(gspca_dev);
+	return 0;
+}
+
+static int sd_getfreqfltr(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->freqfltr;
+	return 0;
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+		struct v4l2_querymenu *menu)
+{
+	switch (menu->id) {
+	case V4L2_CID_POWER_LINE_FREQUENCY:
+		switch (menu->index) {
+		case 0:         /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
+			strcpy((char *) menu->name, "Disabled");
+			return 0;
+		case 1:         /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+			strcpy((char *) menu->name, "50 Hz");
+			return 0;
+		}
+		break;
+	}
+
+	return -EINVAL;
+}
+
 /* get stream parameters (framerate) */
 static int sd_get_streamparm(struct gspca_dev *gspca_dev,
 			     struct v4l2_streamparm *parm)
@@ -1296,6 +1298,7 @@
 	.start    = sd_start,
 	.stopN    = sd_stopN,
 	.pkt_scan = sd_pkt_scan,
+	.querymenu = sd_querymenu,
 	.get_streamparm = sd_get_streamparm,
 	.set_streamparm = sd_set_streamparm,
 };
diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c
index 0c87c34..a40f8893 100644
--- a/drivers/media/video/gspca/pac207.c
+++ b/drivers/media/video/gspca/pac207.c
@@ -99,7 +99,7 @@
 	    {
 		.id = V4L2_CID_EXPOSURE,
 		.type = V4L2_CTRL_TYPE_INTEGER,
-		.name = "exposure",
+		.name = "Exposure",
 		.minimum = PAC207_EXPOSURE_MIN,
 		.maximum = PAC207_EXPOSURE_MAX,
 		.step = 1,
@@ -130,7 +130,7 @@
 	    {
 		.id = V4L2_CID_GAIN,
 		.type = V4L2_CTRL_TYPE_INTEGER,
-		.name = "gain",
+		.name = "Gain",
 		.minimum = PAC207_GAIN_MIN,
 		.maximum = PAC207_GAIN_MAX,
 		.step = 1,
diff --git a/drivers/media/video/gspca/sn9c2028.c b/drivers/media/video/gspca/sn9c2028.c
index dda5fd4..71d9447 100644
--- a/drivers/media/video/gspca/sn9c2028.c
+++ b/drivers/media/video/gspca/sn9c2028.c
@@ -39,7 +39,7 @@
 };
 
 /* V4L2 controls supported by the driver */
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
 };
 
 /* How to change the resolution of any of the VGA cams is unknown */
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c
index 3dee3e5..644a7fd 100644
--- a/drivers/media/video/gspca/sn9c20x.c
+++ b/drivers/media/video/gspca/sn9c20x.c
@@ -18,10 +18,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
-#ifdef CONFIG_USB_GSPCA_SN9C20X_EVDEV
-#include <linux/kthread.h>
-#include <linux/freezer.h>
-#include <linux/usb/input.h>
+#ifdef CONFIG_INPUT
 #include <linux/input.h>
 #include <linux/slab.h>
 #endif
@@ -30,6 +27,7 @@
 #include "jpeg.h"
 
 #include <media/v4l2-chip-ident.h>
+#include <linux/dmi.h>
 
 MODULE_AUTHOR("Brian Johnson <brijohn@gmail.com>, "
 		"microdia project <microdia@googlegroups.com>");
@@ -52,9 +50,15 @@
 #define SENSOR_MT9V112	7
 #define SENSOR_MT9M001	8
 #define SENSOR_MT9M111	9
-#define SENSOR_HV7131R	10
+#define SENSOR_MT9M112  10
+#define SENSOR_HV7131R	11
 #define SENSOR_MT9VPRB	20
 
+/* camera flags */
+#define HAS_NO_BUTTON	0x1
+#define LED_REVERSE	0x2 /* some cameras unset gpio to turn on leds */
+#define FLIP_DETECT	0x4
+
 /* specific webcam descriptor */
 struct sd {
 	struct gspca_dev gspca_dev;
@@ -88,11 +92,7 @@
 	u8 *jpeg_hdr;
 	u8 quality;
 
-#ifdef CONFIG_USB_GSPCA_SN9C20X_EVDEV
-	struct input_dev *input_dev;
-	u8 input_gpio;
-	struct task_struct *input_task;
-#endif
+	u8 flags;
 };
 
 struct i2c_reg_u8 {
@@ -130,6 +130,39 @@
 static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val);
 static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val);
 
+static const struct dmi_system_id flip_dmi_table[] = {
+	{
+		.ident = "MSI MS-1034",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "MS-1034"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "0341")
+		}
+	},
+	{
+		.ident = "MSI MS-1632",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
+			DMI_MATCH(DMI_BOARD_NAME, "MS-1632")
+		}
+	},
+	{
+		.ident = "MSI MS-1635X",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
+			DMI_MATCH(DMI_BOARD_NAME, "MS-1635X")
+		}
+	},
+	{
+		.ident = "ASUSTeK W7J",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."),
+			DMI_MATCH(DMI_BOARD_NAME, "W7J       ")
+		}
+	},
+	{}
+};
+
 static const struct ctrl sd_ctrls[] = {
 	{
 #define BRIGHTNESS_IDX 0
@@ -713,6 +746,7 @@
 	V4L2_IDENT_MT9V112,
 	V4L2_IDENT_MT9M001C12ST,
 	V4L2_IDENT_MT9M111,
+	V4L2_IDENT_MT9M112,
 	V4L2_IDENT_HV7131R,
 };
 
@@ -735,7 +769,8 @@
 	{0x11be, 0xf0},	{0x11bf, 0x00},	{0x118c, 0x1f},
 	{0x118d, 0x1f},	{0x118e, 0x1f},	{0x118f, 0x1f},
 	{0x1180, 0x01},	{0x1181, 0x00},	{0x1182, 0x01},
-	{0x1183, 0x00},	{0x1184, 0x50},	{0x1185, 0x80}
+	{0x1183, 0x00},	{0x1184, 0x50},	{0x1185, 0x80},
+	{0x1007, 0x00}
 };
 
 /* Gain = (bit[3:0] / 16 + 1) * (bit[4] + 1) * (bit[5] + 1) * (bit[6] + 1) */
@@ -914,40 +949,30 @@
 };
 
 static struct i2c_reg_u8 ov9655_init[] = {
-	{0x12, 0x80}, {0x12, 0x01}, {0x0d, 0x00}, {0x0e, 0x61},
-	{0x11, 0x80}, {0x13, 0xba}, {0x14, 0x2e}, {0x16, 0x24},
-	{0x1e, 0x04}, {0x1e, 0x04}, {0x1e, 0x04}, {0x27, 0x08},
-	{0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x32, 0xbf},
-	{0x34, 0x3d}, {0x35, 0x00}, {0x36, 0xf8}, {0x38, 0x12},
-	{0x39, 0x57}, {0x3a, 0x00}, {0x3b, 0xcc}, {0x3c, 0x0c},
-	{0x3d, 0x19}, {0x3e, 0x0c}, {0x3f, 0x01}, {0x41, 0x40},
-	{0x42, 0x80}, {0x45, 0x46}, {0x46, 0x62}, {0x47, 0x2a},
-	{0x48, 0x3c}, {0x4a, 0xf0}, {0x4b, 0xdc}, {0x4c, 0xdc},
-	{0x4d, 0xdc}, {0x4e, 0xdc}, {0x69, 0x02}, {0x6c, 0x04},
-	{0x6f, 0x9e}, {0x70, 0x05}, {0x71, 0x78}, {0x77, 0x02},
-	{0x8a, 0x23}, {0x8c, 0x0d}, {0x90, 0x7e}, {0x91, 0x7c},
-	{0x9f, 0x6e}, {0xa0, 0x6e}, {0xa5, 0x68}, {0xa6, 0x60},
-	{0xa8, 0xc1}, {0xa9, 0xfa}, {0xaa, 0x92}, {0xab, 0x04},
-	{0xac, 0x80}, {0xad, 0x80}, {0xae, 0x80}, {0xaf, 0x80},
-	{0xb2, 0xf2}, {0xb3, 0x20}, {0xb5, 0x00}, {0xb6, 0xaf},
-	{0xbb, 0xae}, {0xbc, 0x44}, {0xbd, 0x44}, {0xbe, 0x3b},
-	{0xbf, 0x3a}, {0xc0, 0xe2}, {0xc1, 0xc8}, {0xc2, 0x01},
+	{0x12, 0x80}, {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba},
+	{0x14, 0x2e}, {0x16, 0x24}, {0x1e, 0x04}, {0x27, 0x08},
+	{0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x34, 0x3d},
+	{0x35, 0x00}, {0x38, 0x12}, {0x0f, 0x42}, {0x39, 0x57},
+	{0x3a, 0x00}, {0x3b, 0xcc}, {0x3c, 0x0c}, {0x3d, 0x19},
+	{0x3e, 0x0c}, {0x3f, 0x01}, {0x41, 0x40}, {0x42, 0x80},
+	{0x45, 0x46}, {0x46, 0x62}, {0x47, 0x2a}, {0x48, 0x3c},
+	{0x4a, 0xf0}, {0x4b, 0xdc}, {0x4c, 0xdc}, {0x4d, 0xdc},
+	{0x4e, 0xdc}, {0x6c, 0x04}, {0x6f, 0x9e}, {0x70, 0x05},
+	{0x71, 0x78}, {0x77, 0x02}, {0x8a, 0x23}, {0x90, 0x7e},
+	{0x91, 0x7c}, {0x9f, 0x6e}, {0xa0, 0x6e}, {0xa5, 0x68},
+	{0xa6, 0x60}, {0xa8, 0xc1}, {0xa9, 0xfa}, {0xaa, 0x92},
+	{0xab, 0x04}, {0xac, 0x80}, {0xad, 0x80}, {0xae, 0x80},
+	{0xaf, 0x80}, {0xb2, 0xf2}, {0xb3, 0x20}, {0xb5, 0x00},
+	{0xb6, 0xaf}, {0xbb, 0xae}, {0xbc, 0x44}, {0xbd, 0x44},
+	{0xbe, 0x3b}, {0xbf, 0x3a}, {0xc1, 0xc8}, {0xc2, 0x01},
 	{0xc4, 0x00}, {0xc6, 0x85}, {0xc7, 0x81}, {0xc9, 0xe0},
-	{0xca, 0xe8}, {0xcc, 0xd8}, {0xcd, 0x93}, {0x12, 0x61},
+	{0xca, 0xe8}, {0xcc, 0xd8}, {0xcd, 0x93}, {0x2d, 0x00},
+	{0x2e, 0x00}, {0x01, 0x80}, {0x02, 0x80}, {0x12, 0x61},
 	{0x36, 0xfa}, {0x8c, 0x8d}, {0xc0, 0xaa}, {0x69, 0x0a},
-	{0x03, 0x12}, {0x17, 0x14}, {0x18, 0x00}, {0x19, 0x01},
-	{0x1a, 0x3d}, {0x32, 0xbf}, {0x11, 0x80}, {0x2a, 0x10},
-	{0x2b, 0x0a}, {0x92, 0x00}, {0x93, 0x00}, {0x1e, 0x04},
-	{0x1e, 0x04}, {0x10, 0x7c}, {0x04, 0x03}, {0xa1, 0x00},
-	{0x2d, 0x00}, {0x2e, 0x00}, {0x00, 0x00}, {0x01, 0x80},
-	{0x02, 0x80}, {0x12, 0x61}, {0x36, 0xfa}, {0x8c, 0x8d},
-	{0xc0, 0xaa}, {0x69, 0x0a}, {0x03, 0x12}, {0x17, 0x14},
-	{0x18, 0x00}, {0x19, 0x01}, {0x1a, 0x3d}, {0x32, 0xbf},
-	{0x11, 0x80}, {0x2a, 0x10}, {0x2b, 0x0a}, {0x92, 0x00},
-	{0x93, 0x00}, {0x04, 0x01}, {0x10, 0x1f}, {0xa1, 0x00},
-	{0x00, 0x0a}, {0xa1, 0x00}, {0x10, 0x5d}, {0x04, 0x03},
-	{0x00, 0x01}, {0xa1, 0x00}, {0x10, 0x7c}, {0x04, 0x03},
-	{0x00, 0x03}, {0x00, 0x0a}, {0x00, 0x10}, {0x00, 0x13},
+	{0x03, 0x09}, {0x17, 0x16}, {0x18, 0x6e}, {0x19, 0x01},
+	{0x1a, 0x3e}, {0x32, 0x09}, {0x2a, 0x10}, {0x2b, 0x0a},
+	{0x92, 0x00}, {0x93, 0x00}, {0xa1, 0x00}, {0x10, 0x7c},
+	{0x04, 0x03}, {0x00, 0x13},
 };
 
 static struct i2c_reg_u16 mt9v112_init[] = {
@@ -971,29 +996,12 @@
 
 static struct i2c_reg_u16 mt9v111_init[] = {
 	{0x01, 0x0004}, {0x0d, 0x0001}, {0x0d, 0x0000},
-	{0x01, 0x0001}, {0x02, 0x0016}, {0x03, 0x01e1},
-	{0x04, 0x0281}, {0x05, 0x0004}, {0x07, 0x3002},
-	{0x21, 0x0000}, {0x25, 0x4024}, {0x26, 0xff03},
-	{0x27, 0xff10}, {0x2b, 0x7828}, {0x2c, 0xb43c},
-	{0x2d, 0xf0a0},	{0x2e, 0x0c64},	{0x2f, 0x0064},
-	{0x67, 0x4010},	{0x06, 0x301e},	{0x08, 0x0480},
-	{0x01, 0x0004},	{0x02, 0x0016}, {0x03, 0x01e6},
-	{0x04, 0x0286},	{0x05, 0x0004}, {0x06, 0x0000},
-	{0x07, 0x3002},	{0x08, 0x0008}, {0x0c, 0x0000},
-	{0x0d, 0x0000}, {0x0e, 0x0000}, {0x0f, 0x0000},
-	{0x10, 0x0000},	{0x11, 0x0000},	{0x12, 0x00b0},
-	{0x13, 0x007c},	{0x14, 0x0000}, {0x15, 0x0000},
-	{0x16, 0x0000}, {0x17, 0x0000},	{0x18, 0x0000},
-	{0x19, 0x0000},	{0x1a, 0x0000},	{0x1b, 0x0000},
-	{0x1c, 0x0000},	{0x1d, 0x0000},	{0x30, 0x0000},
-	{0x30, 0x0005},	{0x31, 0x0000},	{0x02, 0x0016},
-	{0x03, 0x01e1},	{0x04, 0x0281}, {0x05, 0x0004},
-	{0x06, 0x0000},	{0x07, 0x3002},	{0x06, 0x002d},
-	{0x05, 0x0004},	{0x09, 0x0064},	{0x2b, 0x00a0},
-	{0x2c, 0x00a0},	{0x2d, 0x00a0},	{0x2e, 0x00a0},
-	{0x02, 0x0016},	{0x03, 0x01e1},	{0x04, 0x0281},
-	{0x05, 0x0004},	{0x06, 0x002d},	{0x07, 0x3002},
-	{0x0e, 0x0008},	{0x06, 0x002d},	{0x05, 0x0004},
+	{0x01, 0x0001}, {0x05, 0x0004}, {0x2d, 0xe0a0},
+	{0x2e, 0x0c64},	{0x2f, 0x0064}, {0x06, 0x600e},
+	{0x08, 0x0480}, {0x01, 0x0004}, {0x02, 0x0016},
+	{0x03, 0x01e7}, {0x04, 0x0287}, {0x05, 0x0004},
+	{0x06, 0x002d},	{0x07, 0x3002}, {0x08, 0x0008},
+	{0x0e, 0x0008}, {0x20, 0x0000}
 };
 
 static struct i2c_reg_u16 mt9v011_init[] = {
@@ -1043,6 +1051,13 @@
 	{0xf0, 0x0000},
 };
 
+static struct i2c_reg_u16 mt9m112_init[] = {
+	{0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
+	{0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
+	{0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
+	{0xf0, 0x0000},
+};
+
 static struct i2c_reg_u8 hv7131r_init[] = {
 	{0x02, 0x08}, {0x02, 0x00}, {0x01, 0x08},
 	{0x02, 0x00}, {0x20, 0x00}, {0x21, 0xd0},
@@ -1240,8 +1255,8 @@
 	}
 	/* disable hflip and vflip */
 	gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
-	sd->hstart = 0;
-	sd->vstart = 7;
+	sd->hstart = 1;
+	sd->vstart = 2;
 	return 0;
 }
 
@@ -1337,6 +1352,7 @@
 				return -ENODEV;
 			}
 		}
+		gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) | (1 << GAIN_IDX);
 		sd->hstart = 2;
 		sd->vstart = 2;
 		sd->sensor = SENSOR_MT9V111;
@@ -1369,6 +1385,23 @@
 	return -ENODEV;
 }
 
+static int mt9m112_init_sensor(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i;
+	for (i = 0; i < ARRAY_SIZE(mt9m112_init); i++) {
+		if (i2c_w2(gspca_dev, mt9m112_init[i].reg,
+				mt9m112_init[i].val) < 0) {
+			err("MT9M112 sensor initialization failed");
+			return -ENODEV;
+		}
+	}
+	gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) | (1 << GAIN_IDX);
+	sd->hstart = 0;
+	sd->vstart = 2;
+	return 0;
+}
+
 static int mt9m111_init_sensor(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -1421,87 +1454,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_USB_GSPCA_SN9C20X_EVDEV
-static int input_kthread(void *data)
-{
-	struct gspca_dev *gspca_dev = (struct gspca_dev *)data;
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wait);
-	set_freezable();
-	for (;;) {
-		if (kthread_should_stop())
-			break;
-
-		if (reg_r(gspca_dev, 0x1005, 1) < 0)
-			continue;
-
-		input_report_key(sd->input_dev,
-				 KEY_CAMERA,
-				 gspca_dev->usb_buf[0] & sd->input_gpio);
-		input_sync(sd->input_dev);
-
-		wait_event_freezable_timeout(wait,
-					     kthread_should_stop(),
-					     msecs_to_jiffies(100));
-	}
-	return 0;
-}
-
-
-static int sn9c20x_input_init(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	if (sd->input_gpio == 0)
-		return 0;
-
-	sd->input_dev = input_allocate_device();
-	if (!sd->input_dev)
-		return -ENOMEM;
-
-	sd->input_dev->name = "SN9C20X Webcam";
-
-	sd->input_dev->phys = kasprintf(GFP_KERNEL, "usb-%s-%s",
-					 gspca_dev->dev->bus->bus_name,
-					 gspca_dev->dev->devpath);
-
-	if (!sd->input_dev->phys)
-		return -ENOMEM;
-
-	usb_to_input_id(gspca_dev->dev, &sd->input_dev->id);
-	sd->input_dev->dev.parent = &gspca_dev->dev->dev;
-
-	set_bit(EV_KEY, sd->input_dev->evbit);
-	set_bit(KEY_CAMERA, sd->input_dev->keybit);
-
-	if (input_register_device(sd->input_dev))
-		return -EINVAL;
-
-	sd->input_task = kthread_run(input_kthread, gspca_dev, "sn9c20x/%s-%s",
-				     gspca_dev->dev->bus->bus_name,
-				     gspca_dev->dev->devpath);
-
-	if (IS_ERR(sd->input_task))
-		return -EINVAL;
-
-	return 0;
-}
-
-static void sn9c20x_input_cleanup(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	if (sd->input_task != NULL && !IS_ERR(sd->input_task))
-		kthread_stop(sd->input_task);
-
-	if (sd->input_dev != NULL) {
-		input_unregister_device(sd->input_dev);
-		kfree(sd->input_dev->phys);
-		input_free_device(sd->input_dev);
-		sd->input_dev = NULL;
-	}
-}
-#endif
-
 static int set_cmatrix(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -1579,17 +1531,26 @@
 
 static int set_hvflip(struct gspca_dev *gspca_dev)
 {
-	u8 value, tslb;
+	u8 value, tslb, hflip, vflip;
 	u16 value2;
 	struct sd *sd = (struct sd *) gspca_dev;
+
+	if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) {
+		hflip = !sd->hflip;
+		vflip = !sd->vflip;
+	} else {
+		hflip = sd->hflip;
+		vflip = sd->vflip;
+	}
+
 	switch (sd->sensor) {
 	case SENSOR_OV9650:
 		i2c_r1(gspca_dev, 0x1e, &value);
 		value &= ~0x30;
 		tslb = 0x01;
-		if (sd->hflip)
+		if (hflip)
 			value |= 0x20;
-		if (sd->vflip) {
+		if (vflip) {
 			value |= 0x10;
 			tslb = 0x49;
 		}
@@ -1600,28 +1561,29 @@
 	case SENSOR_MT9V011:
 		i2c_r2(gspca_dev, 0x20, &value2);
 		value2 &= ~0xc0a0;
-		if (sd->hflip)
+		if (hflip)
 			value2 |= 0x8080;
-		if (sd->vflip)
+		if (vflip)
 			value2 |= 0x4020;
 		i2c_w2(gspca_dev, 0x20, value2);
 		break;
+	case SENSOR_MT9M112:
 	case SENSOR_MT9M111:
 	case SENSOR_MT9V112:
 		i2c_r2(gspca_dev, 0x20, &value2);
 		value2 &= ~0x0003;
-		if (sd->hflip)
+		if (hflip)
 			value2 |= 0x0002;
-		if (sd->vflip)
+		if (vflip)
 			value2 |= 0x0001;
 		i2c_w2(gspca_dev, 0x20, value2);
 		break;
 	case SENSOR_HV7131R:
 		i2c_r1(gspca_dev, 0x01, &value);
 		value &= ~0x03;
-		if (sd->vflip)
+		if (vflip)
 			value |= 0x01;
-		if (sd->hflip)
+		if (hflip)
 			value |= 0x02;
 		i2c_w1(gspca_dev, 0x01, value);
 		break;
@@ -1645,7 +1607,6 @@
 		break;
 	case SENSOR_MT9M001:
 	case SENSOR_MT9V112:
-	case SENSOR_MT9V111:
 	case SENSOR_MT9V011:
 		exp[0] |= (3 << 4);
 		exp[2] = 0x09;
@@ -1655,9 +1616,9 @@
 	case SENSOR_HV7131R:
 		exp[0] |= (4 << 4);
 		exp[2] = 0x25;
-		exp[3] = ((sd->exposure * 0xffffff) / 0xffff) >> 16;
-		exp[4] = ((sd->exposure * 0xffffff) / 0xffff) >> 8;
-		exp[5] = ((sd->exposure * 0xffffff) / 0xffff) & 0xff;
+		exp[3] = (sd->exposure >> 5) & 0xff;
+		exp[4] = (sd->exposure << 3) & 0xff;
+		exp[5] = 0;
 		break;
 	default:
 		return 0;
@@ -1680,7 +1641,6 @@
 		gain[3] = ov_gain[sd->gain];
 		break;
 	case SENSOR_MT9V011:
-	case SENSOR_MT9V111:
 		gain[0] |= (3 << 4);
 		gain[2] = 0x35;
 		gain[3] = micron1_gain[sd->gain] >> 8;
@@ -1931,7 +1891,7 @@
 		if (reg->match.addr != sd->i2c_addr)
 			return -EINVAL;
 		if (sd->sensor >= SENSOR_MT9V011 &&
-		    sd->sensor <= SENSOR_MT9M111) {
+		    sd->sensor <= SENSOR_MT9M112) {
 			if (i2c_r2(gspca_dev, reg->reg, (u16 *)&reg->val) < 0)
 				return -EINVAL;
 		} else {
@@ -1960,7 +1920,7 @@
 		if (reg->match.addr != sd->i2c_addr)
 			return -EINVAL;
 		if (sd->sensor >= SENSOR_MT9V011 &&
-		    sd->sensor <= SENSOR_MT9M111) {
+		    sd->sensor <= SENSOR_MT9M112) {
 			if (i2c_w2(gspca_dev, reg->reg, reg->val) < 0)
 				return -EINVAL;
 		} else {
@@ -2005,8 +1965,10 @@
 
 	sd->sensor = (id->driver_info >> 8) & 0xff;
 	sd->i2c_addr = id->driver_info & 0xff;
+	sd->flags = (id->driver_info >> 16) & 0xff;
 
 	switch (sd->sensor) {
+	case SENSOR_MT9M112:
 	case SENSOR_MT9M111:
 	case SENSOR_OV9650:
 	case SENSOR_SOI968:
@@ -2039,11 +2001,6 @@
 
 	sd->quality = 95;
 
-#ifdef CONFIG_USB_GSPCA_SN9C20X_EVDEV
-	sd->input_gpio = (id->driver_info >> 16) & 0xff;
-	if (sn9c20x_input_init(gspca_dev) < 0)
-		return -ENODEV;
-#endif
 	return 0;
 }
 
@@ -2063,6 +2020,11 @@
 		}
 	}
 
+	if (sd->flags & LED_REVERSE)
+		reg_w1(gspca_dev, 0x1006, 0x00);
+	else
+		reg_w1(gspca_dev, 0x1006, 0x20);
+
 	if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) {
 		err("Device initialization failed");
 		return -ENODEV;
@@ -2103,6 +2065,11 @@
 			return -ENODEV;
 		info("MT9M111 sensor detected");
 		break;
+	case SENSOR_MT9M112:
+		if (mt9m112_init_sensor(gspca_dev) < 0)
+			return -ENODEV;
+		info("MT9M112 sensor detected");
+		break;
 	case SENSOR_MT9M001:
 		if (mt9m001_init_sensor(gspca_dev) < 0)
 			return -ENODEV;
@@ -2162,6 +2129,7 @@
 			i2c_w1(gspca_dev, 0x12, (value & 0x7) | 0x40);
 		}
 		break;
+	case SENSOR_MT9M112:
 	case SENSOR_MT9M111:
 		if (mode & MODE_SXGA) {
 			i2c_w2(gspca_dev, 0xf0, 0x0002);
@@ -2243,6 +2211,8 @@
 	set_exposure(gspca_dev);
 	set_hvflip(gspca_dev);
 
+	reg_w1(gspca_dev, 0x1007, 0x20);
+
 	reg_r(gspca_dev, 0x1061, 1);
 	reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] | 0x02);
 	return 0;
@@ -2250,6 +2220,8 @@
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
+	reg_w1(gspca_dev, 0x1007, 0x00);
+
 	reg_r(gspca_dev, 0x1061, 1);
 	reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02);
 }
@@ -2343,6 +2315,24 @@
 		do_autoexposure(gspca_dev, avg_lum);
 }
 
+#ifdef CONFIG_INPUT
+static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
+			u8 *data,		/* interrupt packet */
+			int len)		/* interrupt packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret = -EINVAL;
+	if (!(sd->flags & HAS_NO_BUTTON) && len == 1) {
+			input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
+			input_sync(gspca_dev->input_dev);
+			input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+			input_sync(gspca_dev->input_dev);
+			ret = 0;
+	}
+	return ret;
+}
+#endif
+
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			u8 *data,			/* isoc packet */
 			int len)			/* iso packet length */
@@ -2409,6 +2399,9 @@
 	.stopN = sd_stopN,
 	.stop0 = sd_stop0,
 	.pkt_scan = sd_pkt_scan,
+#ifdef CONFIG_INPUT
+	.int_pkt_scan = sd_int_pkt_scan,
+#endif
 	.dq_callback = sd_dqcallback,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 	.set_register = sd_dbg_s_register,
@@ -2417,8 +2410,8 @@
 	.get_chip_ident = sd_chip_ident,
 };
 
-#define SN9C20X(sensor, i2c_addr, button_mask) \
-	.driver_info =  (button_mask << 16) \
+#define SN9C20X(sensor, i2c_addr, flags) \
+	.driver_info =  ((flags & 0xff) << 16) \
 			| (SENSOR_ ## sensor << 8) \
 			| (i2c_addr)
 
@@ -2426,8 +2419,10 @@
 	{USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)},
 	{USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)},
 	{USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)},
-	{USB_DEVICE(0x0c45, 0x624e), SN9C20X(SOI968, 0x30, 0x10)},
-	{USB_DEVICE(0x0c45, 0x624f), SN9C20X(OV9650, 0x30, 0)},
+	{USB_DEVICE(0x0c45, 0x624c), SN9C20X(MT9M112, 0x5d, 0)},
+	{USB_DEVICE(0x0c45, 0x624e), SN9C20X(SOI968, 0x30, LED_REVERSE)},
+	{USB_DEVICE(0x0c45, 0x624f), SN9C20X(OV9650, 0x30,
+					     (FLIP_DETECT | HAS_NO_BUTTON))},
 	{USB_DEVICE(0x0c45, 0x6251), SN9C20X(OV9650, 0x30, 0)},
 	{USB_DEVICE(0x0c45, 0x6253), SN9C20X(OV9650, 0x30, 0)},
 	{USB_DEVICE(0x0c45, 0x6260), SN9C20X(OV7670, 0x21, 0)},
@@ -2438,6 +2433,7 @@
 	{USB_DEVICE(0x0c45, 0x6280), SN9C20X(MT9M001, 0x5d, 0)},
 	{USB_DEVICE(0x0c45, 0x6282), SN9C20X(MT9M111, 0x5d, 0)},
 	{USB_DEVICE(0x0c45, 0x6288), SN9C20X(OV9655, 0x30, 0)},
+	{USB_DEVICE(0x0c45, 0x628c), SN9C20X(MT9M112, 0x5d, 0)},
 	{USB_DEVICE(0x0c45, 0x628e), SN9C20X(SOI968, 0x30, 0)},
 	{USB_DEVICE(0x0c45, 0x628f), SN9C20X(OV9650, 0x30, 0)},
 	{USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)},
@@ -2448,6 +2444,8 @@
 	{USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)},
 	{USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)},
 	{USB_DEVICE(0x0458, 0x7029), SN9C20X(HV7131R, 0x11, 0)},
+	{USB_DEVICE(0x0458, 0x704a), SN9C20X(MT9M112, 0x5d, 0)},
+	{USB_DEVICE(0x0458, 0x704c), SN9C20X(MT9M112, 0x5d, 0)},
 	{USB_DEVICE(0xa168, 0x0610), SN9C20X(HV7131R, 0x11, 0)},
 	{USB_DEVICE(0xa168, 0x0611), SN9C20X(HV7131R, 0x11, 0)},
 	{USB_DEVICE(0xa168, 0x0613), SN9C20X(HV7131R, 0x11, 0)},
@@ -2467,22 +2465,11 @@
 				THIS_MODULE);
 }
 
-static void sd_disconnect(struct usb_interface *intf)
-{
-#ifdef CONFIG_USB_GSPCA_SN9C20X_EVDEV
-	struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
-
-	sn9c20x_input_cleanup(gspca_dev);
-#endif
-
-	gspca_disconnect(intf);
-}
-
 static struct usb_driver sd_driver = {
 	.name = MODULE_NAME,
 	.id_table = device_table,
 	.probe = sd_probe,
-	.disconnect = sd_disconnect,
+	.disconnect = gspca_disconnect,
 #ifdef CONFIG_PM
 	.suspend = gspca_suspend,
 	.resume = gspca_resume,
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index 1d61b92..bb923ef 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -1,7 +1,7 @@
 /*
  * Sonix sn9c102p sn9c105 sn9c120 (jpeg) subdriver
  *
- * Copyright (C) 2009 Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2009-2010 Jean-François Moine <http://moinejf.free.fr>
  * Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
  *
  * This program is free software; you can redistribute it and/or modify
@@ -28,7 +28,7 @@
 
 #define V4L2_CID_INFRARED (V4L2_CID_PRIVATE_BASE + 0)
 
-MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver");
 MODULE_LICENSE("GPL");
 
@@ -67,20 +67,25 @@
 #define BRIDGE_SN9C110 2
 #define BRIDGE_SN9C120 3
 	u8 sensor;			/* Type of image sensor chip */
-#define SENSOR_ADCM1700 0
-#define SENSOR_HV7131R 1
-#define SENSOR_MI0360 2
-#define SENSOR_MO4000 3
-#define SENSOR_MT9V111 4
-#define SENSOR_OM6802 5
-#define SENSOR_OV7630 6
-#define SENSOR_OV7648 7
-#define SENSOR_OV7660 8
-#define SENSOR_PO1030 9
-#define SENSOR_SP80708 10
+enum {
+	SENSOR_ADCM1700,
+	SENSOR_GC0307,
+	SENSOR_HV7131R,
+	SENSOR_MI0360,
+	SENSOR_MO4000,
+	SENSOR_MT9V111,
+	SENSOR_OM6802,
+	SENSOR_OV7630,
+	SENSOR_OV7648,
+	SENSOR_OV7660,
+	SENSOR_PO1030,
+	SENSOR_PO2030N,
+	SENSOR_SOI768,
+	SENSOR_SP80708,
+} sensors;
 	u8 i2c_addr;
 
-	u8 *jpeg_hdr;
+	u8 jpeg_hdr[JPEG_HDR_SZ];
 };
 
 /* V4L2 controls supported by the driver */
@@ -281,29 +286,60 @@
 };
 
 /* table of the disabled controls */
-static __u32 ctrl_dis[] = {
-	(1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX) |
-			(1 << AUTOGAIN_IDX),	/* SENSOR_ADCM1700 0 */
-	(1 << INFRARED_IDX) | (1 << FREQ_IDX),
-						/* SENSOR_HV7131R 1 */
-	(1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX),
-						/* SENSOR_MI0360 2 */
-	(1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX),
-						/* SENSOR_MO4000 3 */
-	(1 << VFLIP_IDX) | (1 << FREQ_IDX),
-						/* SENSOR_MT9V111 4 */
-	(1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX),
-						/* SENSOR_OM6802 5 */
-	(1 << INFRARED_IDX),
-						/* SENSOR_OV7630 6 */
-	(1 << INFRARED_IDX),
-						/* SENSOR_OV7648 7 */
-	(1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
-						/* SENSOR_OV7660 8 */
-	(1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX) |
-			      (1 << FREQ_IDX),	/* SENSOR_PO1030 9 */
-	(1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX) |
-			      (1 << FREQ_IDX),	/* SENSOR_SP80708 10 */
+static const __u32 ctrl_dis[] = {
+[SENSOR_ADCM1700] =	(1 << AUTOGAIN_IDX) |
+			(1 << INFRARED_IDX) |
+			(1 << VFLIP_IDX) |
+			(1 << FREQ_IDX),
+
+[SENSOR_GC0307] =	(1 << INFRARED_IDX) |
+			(1 << VFLIP_IDX) |
+			(1 << FREQ_IDX),
+
+[SENSOR_HV7131R] =	(1 << INFRARED_IDX) |
+			(1 << FREQ_IDX),
+
+[SENSOR_MI0360] =	(1 << INFRARED_IDX) |
+			(1 << VFLIP_IDX) |
+			(1 << FREQ_IDX),
+
+[SENSOR_MO4000] =	(1 << INFRARED_IDX) |
+			(1 << VFLIP_IDX) |
+			(1 << FREQ_IDX),
+
+[SENSOR_MT9V111] =	(1 << VFLIP_IDX) |
+			(1 << FREQ_IDX),
+
+[SENSOR_OM6802] =	(1 << INFRARED_IDX) |
+			(1 << VFLIP_IDX) |
+			(1 << FREQ_IDX),
+
+[SENSOR_OV7630] =	(1 << INFRARED_IDX),
+
+[SENSOR_OV7648] =	(1 << INFRARED_IDX),
+
+[SENSOR_OV7660] =	(1 << AUTOGAIN_IDX) |
+			(1 << INFRARED_IDX) |
+			(1 << VFLIP_IDX),
+
+[SENSOR_PO1030] =	(1 << AUTOGAIN_IDX) |
+			(1 << INFRARED_IDX) |
+			(1 << VFLIP_IDX) |
+			(1 << FREQ_IDX),
+
+[SENSOR_PO2030N] =	(1 << AUTOGAIN_IDX) |
+			(1 << INFRARED_IDX) |
+			(1 << VFLIP_IDX) |
+			(1 << FREQ_IDX),
+[SENSOR_SOI768] =	(1 << AUTOGAIN_IDX) |
+			(1 << INFRARED_IDX) |
+			(1 << VFLIP_IDX) |
+			(1 << FREQ_IDX),
+
+[SENSOR_SP80708] =	(1 << AUTOGAIN_IDX) |
+			(1 << INFRARED_IDX) |
+			(1 << VFLIP_IDX) |
+			(1 << FREQ_IDX),
 };
 
 static const struct v4l2_pix_format cif_mode[] = {
@@ -343,7 +379,17 @@
 	0x06,	0x00,	0x00,	0x00
 };
 
-/*Data from sn9c102p+hv7131r */
+static const u8 sn_gc0307[0x1c] = {
+/*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7 */
+	0x00,	0x61,	0x62,	0x00,	0x1a,	0x00,	0x00,	0x00,
+/*	reg8	reg9	rega	regb	regc	regd	rege	regf */
+	0x80,	0x21,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
+/*	reg10	reg11	reg12	reg13	reg14	reg15	reg16	reg17 */
+	0x03,	0x00,	0x03,	0x01,	0x08,	0x28,	0x1e,	0x02,
+/*	reg18	reg19	reg1a	reg1b */
+	0x06,	0x00,	0x00,	0x00
+};
+
 static const u8 sn_hv7131[0x1c] = {
 /*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7 */
 	0x00,	0x03,	0x64,	0x00,	0x1a,	0x20,	0x20,	0x20,
@@ -401,7 +447,7 @@
 
 static const u8 sn_ov7630[0x1c] = {
 /*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7 */
-	0x00,	0x21,	0x40,	0x00,	0x1a,	0x20,	0x1f,	0x20,
+	0x00,	0x21,	0x40,	0x00,	0x1a,	0x00,	0x00,	0x00,
 /*	reg8	reg9	rega	regb	regc	regd	rege	regf */
 	0x81,	0x21,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
 /*	reg10	reg11	reg12	reg13	reg14	reg15	reg16	reg17 */
@@ -443,6 +489,28 @@
 	0x07,	0x00,	0x00,	0x00
 };
 
+static const u8 sn_po2030n[0x1c] = {
+/*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7 */
+	0x00,	0x63,	0x40,	0x00,	0x1a,	0x00,	0x00,	0x00,
+/*	reg8	reg9	rega	regb	regc	regd	rege	regf */
+	0x81,	0x6e,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
+/*	reg10	reg11	reg12	reg13	reg14	reg15	reg16	reg17 */
+	0x03,	0x00,	0x00,	0x01,	0x14,	0x28,	0x1e,	0x00,
+/*	reg18	reg19	reg1a	reg1b */
+	0x07,	0x00,	0x00,	0x00
+};
+
+static const u8 sn_soi768[0x1c] = {
+/*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7 */
+	0x00,	0x21,	0x40,	0x00,	0x1a,	0x00,	0x00,	0x00,
+/*	reg8	reg9	rega	regb	regc	regd	rege	regf */
+	0x81,	0x21,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
+/*	reg10	reg11	reg12	reg13	reg14	reg15	reg16	reg17 */
+	0x03,	0x00,	0x00,	0x01,	0x08,	0x28,	0x1e,	0x00,
+/*	reg18	reg19	reg1a	reg1b */
+	0x07,	0x00,	0x00,	0x00
+};
+
 static const u8 sn_sp80708[0x1c] = {
 /*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7 */
 	0x00,	0x63,	0x60,	0x00,	0x1a,	0x20,	0x20,	0x20,
@@ -456,17 +524,20 @@
 
 /* sequence specific to the sensors - !! index = SENSOR_xxx */
 static const u8 *sn_tb[] = {
-	sn_adcm1700,
-	sn_hv7131,
-	sn_mi0360,
-	sn_mo4000,
-	sn_mt9v111,
-	sn_om6802,
-	sn_ov7630,
-	sn_ov7648,
-	sn_ov7660,
-	sn_po1030,
-	sn_sp80708
+[SENSOR_ADCM1700] =	sn_adcm1700,
+[SENSOR_GC0307] =	sn_gc0307,
+[SENSOR_HV7131R] =	sn_hv7131,
+[SENSOR_MI0360] =	sn_mi0360,
+[SENSOR_MO4000] =	sn_mo4000,
+[SENSOR_MT9V111] =	sn_mt9v111,
+[SENSOR_OM6802] =	sn_om6802,
+[SENSOR_OV7630] =	sn_ov7630,
+[SENSOR_OV7648] =	sn_ov7648,
+[SENSOR_OV7660] =	sn_ov7660,
+[SENSOR_PO1030] =	sn_po1030,
+[SENSOR_PO2030N] =	sn_po2030n,
+[SENSOR_SOI768] =	sn_soi768,
+[SENSOR_SP80708] =	sn_sp80708,
 };
 
 /* default gamma table */
@@ -484,8 +555,13 @@
 	0x08, 0x3a, 0x52, 0x65, 0x75, 0x83, 0x91, 0x9d,
 	0xa9, 0xb4, 0xbe, 0xc8, 0xd2, 0xdb, 0xe4, 0xed, 0xf5
 };
-/* gamma for sensor SP80708 */
+/* gamma for sensor GC0307 */
 static const u8 gamma_spec_2[17] = {
+	0x14, 0x37, 0x50, 0x6a, 0x7c, 0x8d, 0x9d, 0xab,
+	0xb5, 0xbf, 0xc2, 0xcb, 0xd1, 0xd6, 0xdb, 0xe1, 0xeb
+};
+/* gamma for sensor SP80708 */
+static const u8 gamma_spec_3[17] = {
 	0x0a, 0x2d, 0x4e, 0x68, 0x7d, 0x8f, 0x9f, 0xab,
 	0xb7, 0xc2, 0xcc, 0xd3, 0xd8, 0xde, 0xe2, 0xe5, 0xe6
 };
@@ -533,6 +609,58 @@
 	{0xb0, 0x51, 0x32, 0x00, 0xa2, 0x00, 0x00, 0x10},
 	{}
 };
+static const u8 gc0307_sensor_init[][8] = {
+	{0xa0, 0x21, 0x43, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x44, 0xa2, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x01, 0x6a, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x02, 0x70, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x11, 0x05, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x08, 0x02, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x09, 0x01, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x0a, 0xe8, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x0b, 0x02, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x0c, 0x80, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x0d, 0x22, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x0e, 0x02, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x0f, 0xb2, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x12, 0x70, 0x00, 0x00, 0x00, 0x10},
+	{0xdd, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*delay 10ms*/
+	{0xa0, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x15, 0xb8, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x16, 0x13, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x17, 0x52, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x18, 0x50, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x1e, 0x0d, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x1f, 0x32, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x61, 0x90, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x63, 0x70, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x65, 0x98, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x67, 0x90, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x04, 0x96, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x45, 0x27, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x47, 0x2c, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x43, 0x47, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x44, 0xd8, 0x00, 0x00, 0x00, 0x10},
+	{}
+};
+static const u8 gc0307_sensor_param1[][8] = {
+	{0xa0, 0x21, 0x68, 0x13, 0x00, 0x00, 0x00, 0x10},
+	{0xd0, 0x21, 0x61, 0x80, 0x00, 0x80, 0x00, 0x10},
+	{0xc0, 0x21, 0x65, 0x80, 0x00, 0x80, 0x00, 0x10},
+	{0xc0, 0x21, 0x63, 0xa0, 0x00, 0xa6, 0x00, 0x10},
+/*param3*/
+	{0xa0, 0x21, 0x01, 0x6e, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x02, 0x88, 0x00, 0x00, 0x00, 0x10},
+	{}
+};
+
 static const u8 hv7131r_sensor_init[][8] = {
 	{0xc1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
 	{0xb1, 0x11, 0x34, 0x17, 0x7f, 0x00, 0x00, 0x10},
@@ -767,7 +895,9 @@
 	{0xc1, 0x21, 0x7b, 0x00, 0x4c, 0xf7, 0x00, 0x10},
 	{0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10},
 	{0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10},
-/* */
+	{}
+};
+static const u8 ov7630_sensor_param1[][8] = {
 	{0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
 	{0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
 /*fixme: + 0x12, 0x04*/
@@ -984,6 +1114,113 @@
 	{}
 };
 
+static const u8 po2030n_sensor_init[][8] = {
+	{0xa1, 0x6e, 0x1e, 0x1a, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x6e, 0x1f, 0x99, 0x00, 0x00, 0x00, 0x10},
+	{0xdd, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 10ms */
+	{0xa1, 0x6e, 0x1e, 0x0a, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x6e, 0x1f, 0x19, 0x00, 0x00, 0x00, 0x10},
+	{0xdd, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 10ms */
+	{0xa1, 0x6e, 0x20, 0x44, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x6e, 0x04, 0x03, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x6e, 0x05, 0x70, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x6e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x6e, 0x07, 0x25, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x08, 0x00, 0xd0, 0x00, 0x08, 0x10},
+	{0xd1, 0x6e, 0x0c, 0x03, 0x50, 0x01, 0xe8, 0x10},
+	{0xd1, 0x6e, 0x1d, 0x20, 0x0a, 0x19, 0x44, 0x10},
+	{0xd1, 0x6e, 0x21, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x25, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x29, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x35, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x39, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x41, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x45, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x49, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x4d, 0x00, 0x00, 0x00, 0xed, 0x10},
+	{0xd1, 0x6e, 0x51, 0x17, 0x4a, 0x2f, 0xc0, 0x10},
+	{0xd1, 0x6e, 0x55, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x59, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x61, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x65, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x69, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x71, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x75, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x79, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x81, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x85, 0x00, 0x00, 0x00, 0x08, 0x10},
+	{0xd1, 0x6e, 0x89, 0x01, 0xe8, 0x00, 0x01, 0x10},
+	{0xa1, 0x6e, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x21, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x25, 0x00, 0x00, 0x00, 0x01, 0x10},
+	{0xd1, 0x6e, 0x29, 0xe6, 0x00, 0xbd, 0x03, 0x10},
+	{0xd1, 0x6e, 0x2d, 0x41, 0x38, 0x68, 0x40, 0x10},
+	{0xd1, 0x6e, 0x31, 0x2b, 0x00, 0x36, 0x00, 0x10},
+	{0xd1, 0x6e, 0x35, 0x30, 0x30, 0x08, 0x00, 0x10},
+	{0xd1, 0x6e, 0x39, 0x00, 0x00, 0x33, 0x06, 0x10},
+	{0xb1, 0x6e, 0x3d, 0x06, 0x02, 0x00, 0x00, 0x10},
+	{}
+};
+static const u8 po2030n_sensor_param1[][8] = {
+	{0xa1, 0x6e, 0x1a, 0x01, 0x00, 0x00, 0x00, 0x10},
+	{0xdd, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 8ms */
+	{0xa1, 0x6e, 0x1b, 0xf4, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x16, 0x50, 0x40, 0x49, 0x40, 0x10},
+/*param2*/
+	{0xa1, 0x6e, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x6e, 0x04, 0x03, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x6e, 0x05, 0x6f, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x6e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x6e, 0x07, 0x25, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10},
+	{0xc1, 0x6e, 0x16, 0x52, 0x40, 0x48, 0x00, 0x10},
+/*after start*/
+	{0xa1, 0x6e, 0x15, 0x0f, 0x00, 0x00, 0x00, 0x10},
+	{0xdd, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */
+	{0xa1, 0x6e, 0x1a, 0x05, 0x00, 0x00, 0x00, 0x10},
+	{0xdd, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */
+	{0xa1, 0x6e, 0x1b, 0x53, 0x00, 0x00, 0x00, 0x10},
+	{}
+};
+
+static const u8 soi768_sensor_init[][8] = {
+	{0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset */
+	{0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 96ms */
+	{0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x13, 0x80, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x0f, 0x03, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x19, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{}
+};
+static const u8 soi768_sensor_param1[][8] = {
+	{0xa1, 0x21, 0x10, 0x10, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xb1, 0x21, 0x01, 0x7f, 0x7f, 0x00, 0x00, 0x10},
+/* */
+/*	{0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10}, */
+/*	{0xa1, 0x21, 0x2d, 0x25, 0x00, 0x00, 0x00, 0x10}, */
+	{0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10},
+/*	{0xb1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10}, */
+	{0xa1, 0x21, 0x02, 0x8d, 0x00, 0x00, 0x00, 0x10},
+/* the next sequence should be used for auto gain */
+	{0xa1, 0x21, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10},
+			/* global gain ? : 07 - change with 0x15 at the end */
+	{0xa1, 0x21, 0x10, 0x3f, 0x00, 0x00, 0x00, 0x10}, /* ???? : 063f */
+	{0xa1, 0x21, 0x04, 0x06, 0x00, 0x00, 0x00, 0x10},
+	{0xb1, 0x21, 0x2d, 0x00, 0x02, 0x00, 0x00, 0x10},
+			/* exposure ? : 0200 - change with 0x1e at the end */
+	{}
+};
+
 static const u8 sp80708_sensor_init[][8] = {
 	{0xa1, 0x18, 0x06, 0xf9, 0x00, 0x00, 0x00, 0x10},
 	{0xa1, 0x18, 0x09, 0x1f, 0x00, 0x00, 0x00, 0x10},
@@ -1069,18 +1306,21 @@
 	{}
 };
 
-static const u8 (*sensor_init[11])[8] = {
-	adcm1700_sensor_init,	/* ADCM1700 0 */
-	hv7131r_sensor_init,	/* HV7131R 1 */
-	mi0360_sensor_init,	/* MI0360 2 */
-	mo4000_sensor_init,	/* MO4000 3 */
-	mt9v111_sensor_init,	/* MT9V111 4 */
-	om6802_sensor_init,	/* OM6802 5 */
-	ov7630_sensor_init,	/* OV7630 6 */
-	ov7648_sensor_init,	/* OV7648 7 */
-	ov7660_sensor_init,	/* OV7660 8 */
-	po1030_sensor_init,	/* PO1030 9 */
-	sp80708_sensor_init,	/* SP80708 10 */
+static const u8 (*sensor_init[])[8] = {
+[SENSOR_ADCM1700] =	adcm1700_sensor_init,
+[SENSOR_GC0307] =	gc0307_sensor_init,
+[SENSOR_HV7131R] =	hv7131r_sensor_init,
+[SENSOR_MI0360] =	mi0360_sensor_init,
+[SENSOR_MO4000] =	mo4000_sensor_init,
+[SENSOR_MT9V111] =	mt9v111_sensor_init,
+[SENSOR_OM6802] =	om6802_sensor_init,
+[SENSOR_OV7630] =	ov7630_sensor_init,
+[SENSOR_OV7648] =	ov7648_sensor_init,
+[SENSOR_OV7660] =	ov7660_sensor_init,
+[SENSOR_PO1030] =	po1030_sensor_init,
+[SENSOR_PO2030N] =	po2030n_sensor_init,
+[SENSOR_SOI768] =	soi768_sensor_init,
+[SENSOR_SP80708] =	sp80708_sensor_init,
 };
 
 /* read <len> bytes to gspca_dev->usb_buf */
@@ -1146,10 +1386,11 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	PDEBUG(D_USBO, "i2c_w2 [%02x] = %02x", reg, val);
+	PDEBUG(D_USBO, "i2c_w1 [%02x] = %02x", reg, val);
 	switch (sd->sensor) {
 	case SENSOR_ADCM1700:
-	case SENSOR_OM6802:		/* i2c command = a0 (100 kHz) */
+	case SENSOR_OM6802:
+	case SENSOR_GC0307:		/* i2c command = a0 (100 kHz) */
 		gspca_dev->usb_buf[0] = 0x80 | (2 << 4);
 		break;
 	default:			/* i2c command = a1 (400 kHz) */
@@ -1177,6 +1418,8 @@
 static void i2c_w8(struct gspca_dev *gspca_dev,
 		   const u8 *buffer)
 {
+	PDEBUG(D_USBO, "i2c_w8 [%02x] = %02x ..",
+		buffer[2], buffer[3]);
 	memcpy(gspca_dev->usb_buf, buffer, 8);
 	usb_control_msg(gspca_dev->dev,
 			usb_sndctrlpipe(gspca_dev->dev, 0),
@@ -1196,7 +1439,8 @@
 
 	switch (sd->sensor) {
 	case SENSOR_ADCM1700:
-	case SENSOR_OM6802:		/* i2c command = 90 (100 kHz) */
+	case SENSOR_OM6802:
+	case SENSOR_GC0307:		/* i2c command = a0 (100 kHz) */
 		mode[0] = 0x80 | 0x10;
 		break;
 	default:			/* i2c command = 91 (400 kHz) */
@@ -1300,39 +1544,100 @@
 	}
 }
 
-static void ov7648_probe(struct gspca_dev *gspca_dev)
+static void ov7630_probe(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
+	u16 val;
 
 	/* check ov76xx */
 	reg_w1(gspca_dev, 0x17, 0x62);
 	reg_w1(gspca_dev, 0x01, 0x08);
 	sd->i2c_addr = 0x21;
 	i2c_r(gspca_dev, 0x0a, 2);
-	if (gspca_dev->usb_buf[3] == 0x76) {	/* ov76xx */
-		PDEBUG(D_PROBE, "Sensor ov%02x%02x",
-			gspca_dev->usb_buf[3], gspca_dev->usb_buf[4]);
-		return;
-	}
-
-	/* reset */
+	val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
 	reg_w1(gspca_dev, 0x01, 0x29);
 	reg_w1(gspca_dev, 0x17, 0x42);
+	if (val == 0x7628) {			/* soi768 */
+		sd->sensor = SENSOR_SOI768;
+/*fixme: only valid for 0c45:613e?*/
+		gspca_dev->cam.input_flags =
+				V4L2_IN_ST_VFLIP | V4L2_IN_ST_HFLIP;
+		PDEBUG(D_PROBE, "Sensor soi768");
+		return;
+	}
+	PDEBUG(D_PROBE, "Sensor ov%04x", val);
+}
+
+static void ov7648_probe(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u16 val;
+
+	/* check ov76xx */
+	reg_w1(gspca_dev, 0x17, 0x62);
+	reg_w1(gspca_dev, 0x01, 0x08);
+	sd->i2c_addr = 0x21;
+	i2c_r(gspca_dev, 0x0a, 2);
+	val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
+	reg_w1(gspca_dev, 0x01, 0x29);
+	reg_w1(gspca_dev, 0x17, 0x42);
+	if ((val & 0xff00) == 0x7600) {		/* ov76xx */
+		PDEBUG(D_PROBE, "Sensor ov%04x", val);
+		return;
+	}
 
 	/* check po1030 */
 	reg_w1(gspca_dev, 0x17, 0x62);
 	reg_w1(gspca_dev, 0x01, 0x08);
 	sd->i2c_addr = 0x6e;
 	i2c_r(gspca_dev, 0x00, 2);
-	if (gspca_dev->usb_buf[3] == 0x10	/* po1030 */
-	    && gspca_dev->usb_buf[4] == 0x30) {
+	val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
+	reg_w1(gspca_dev, 0x01, 0x29);
+	reg_w1(gspca_dev, 0x17, 0x42);
+	if (val == 0x1030) {			/* po1030 */
 		PDEBUG(D_PROBE, "Sensor po1030");
 		sd->sensor = SENSOR_PO1030;
 		return;
 	}
 
-	PDEBUG(D_PROBE, "Unknown sensor %02x%02x",
-		gspca_dev->usb_buf[3], gspca_dev->usb_buf[4]);
+	PDEBUG(D_PROBE, "Unknown sensor %04x", val);
+}
+
+/* 0c45:6142 sensor may be po2030n, gc0305 or gc0307 */
+static void po2030n_probe(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u16 val;
+
+	/* check gc0307 */
+	reg_w1(gspca_dev, 0x17, 0x62);
+	reg_w1(gspca_dev, 0x01, 0x08);
+	reg_w1(gspca_dev, 0x02, 0x22);
+	sd->i2c_addr = 0x21;
+	i2c_r(gspca_dev, 0x00, 1);
+	val = gspca_dev->usb_buf[4];
+	reg_w1(gspca_dev, 0x01, 0x29);		/* reset */
+	reg_w1(gspca_dev, 0x17, 0x42);
+	if (val == 0x99) {			/* gc0307 (?) */
+		PDEBUG(D_PROBE, "Sensor gc0307");
+		sd->sensor = SENSOR_GC0307;
+		return;
+	}
+
+	/* check po2030n */
+	reg_w1(gspca_dev, 0x17, 0x62);
+	reg_w1(gspca_dev, 0x01, 0x0a);
+	sd->i2c_addr = 0x6e;
+	i2c_r(gspca_dev, 0x00, 2);
+	val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
+	reg_w1(gspca_dev, 0x01, 0x29);
+	reg_w1(gspca_dev, 0x17, 0x42);
+	if (val == 0x2030) {
+		PDEBUG(D_PROBE, "Sensor po2030n");
+/*		sd->sensor = SENSOR_PO2030N; */
+	} else {
+		PDEBUG(D_PROBE, "Unknown sensor ID %04x", val);
+	}
 }
 
 static void bridge_init(struct gspca_dev *gspca_dev,
@@ -1355,8 +1660,11 @@
 	reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2);
 	reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5);
 	switch (sd->sensor) {
+	case SENSOR_GC0307:
 	case SENSOR_OV7660:
 	case SENSOR_PO1030:
+	case SENSOR_PO2030N:
+	case SENSOR_SOI768:
 	case SENSOR_SP80708:
 		reg9a = reg9a_spec;
 		break;
@@ -1377,6 +1685,14 @@
 		reg_w1(gspca_dev, 0x01, 0x42);
 		reg_w1(gspca_dev, 0x01, 0x42);
 		break;
+	case SENSOR_GC0307:
+		msleep(50);
+		reg_w1(gspca_dev, 0x01, 0x61);
+		reg_w1(gspca_dev, 0x17, 0x22);
+		reg_w1(gspca_dev, 0x01, 0x60);
+		reg_w1(gspca_dev, 0x01, 0x40);
+		msleep(50);
+		break;
 	case SENSOR_MT9V111:
 		reg_w1(gspca_dev, 0x01, 0x61);
 		reg_w1(gspca_dev, 0x17, 0x61);
@@ -1414,11 +1730,18 @@
 		reg_w1(gspca_dev, 0x01, 0x42);
 		break;
 	case SENSOR_PO1030:
+	case SENSOR_SOI768:
 		reg_w1(gspca_dev, 0x01, 0x61);
 		reg_w1(gspca_dev, 0x17, 0x20);
 		reg_w1(gspca_dev, 0x01, 0x60);
 		reg_w1(gspca_dev, 0x01, 0x40);
 		break;
+	case SENSOR_PO2030N:
+		reg_w1(gspca_dev, 0x01, 0x63);
+		reg_w1(gspca_dev, 0x17, 0x20);
+		reg_w1(gspca_dev, 0x01, 0x62);
+		reg_w1(gspca_dev, 0x01, 0x42);
+		break;
 	case SENSOR_OV7660:
 		/* fall thru */
 	case SENSOR_SP80708:
@@ -1523,9 +1846,15 @@
 		case SENSOR_MI0360:
 			mi0360_probe(gspca_dev);
 			break;
+		case SENSOR_OV7630:
+			ov7630_probe(gspca_dev);
+			break;
 		case SENSOR_OV7648:
 			ov7648_probe(gspca_dev);
 			break;
+		case SENSOR_PO2030N:
+			po2030n_probe(gspca_dev);
+			break;
 		}
 		regGpio[1] = 0x70;
 		reg_w(gspca_dev, 0x01, regGpio, 2);
@@ -1558,6 +1887,18 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	switch (sd->sensor) {
+	case SENSOR_GC0307: {
+		int a, b;
+
+		/* expo = 0..255 -> a = 19..43 */
+		a = 19 + expo * 25 / 256;
+		i2c_w1(gspca_dev, 0x68, a);
+		a -= 12;
+		b = a * a * 4;			/* heuristic */
+		i2c_w1(gspca_dev, 0x03, b >> 8);
+		i2c_w1(gspca_dev, 0x04, b);
+		break;
+	    }
 	case SENSOR_HV7131R: {
 		u8 Expodoit[] =
 			{ 0xc1, 0x11, 0x25, 0x00, 0x00, 0x00, 0x00, 0x16 };
@@ -1668,6 +2009,7 @@
 		expo = sd->brightness >> 4;
 		sd->exposure = setexposure(gspca_dev, expo);
 		break;
+	case SENSOR_GC0307:
 	case SENSOR_MT9V111:
 		expo = sd->brightness >> 8;
 		sd->exposure = setexposure(gspca_dev, expo);
@@ -1703,7 +2045,7 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 	int i, v;
 	u8 reg8a[12];			/* U & V gains */
-	static s16 uv[6] = {		/* same as reg84 in signed decimal */
+	static const s16 uv[6] = {	/* same as reg84 in signed decimal */
 		-24, -38, 64,		/* UR UG UB */
 		 62, -51, -9		/* VR VG VB */
 	};
@@ -1744,9 +2086,12 @@
 	case SENSOR_MT9V111:
 		gamma_base = gamma_spec_1;
 		break;
-	case SENSOR_SP80708:
+	case SENSOR_GC0307:
 		gamma_base = gamma_spec_2;
 		break;
+	case SENSOR_SP80708:
+		gamma_base = gamma_spec_3;
+		break;
 	default:
 		gamma_base = gamma_def;
 		break;
@@ -1937,14 +2282,17 @@
 	static const u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
 	static const u8 CA_adcm1700[] =
 				{ 0x14, 0xec, 0x0a, 0xf6 };
+	static const u8 CA_po2030n[] =
+				{ 0x1e, 0xe2, 0x14, 0xec };
 	static const u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd };	/* MI0360 */
+	static const u8 CE_gc0307[] =
+				{ 0x32, 0xce, 0x2d, 0xd3 };
 	static const u8 CE_ov76xx[] =
 				{ 0x32, 0xdd, 0x32, 0xdd };
+	static const u8 CE_po2030n[] =
+				{ 0x14, 0xe7, 0x1e, 0xdd };
 
 	/* create the JPEG header */
-	sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
-	if (!sd->jpeg_hdr)
-		return -ENOMEM;
 	jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
 			0x21);		/* JPEG 422 */
 	jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -1996,6 +2344,9 @@
 	}
 	reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]);
 	switch (sd->sensor) {
+	case SENSOR_GC0307:
+		reg17 = 0xa2;
+		break;
 	case SENSOR_MT9V111:
 		reg17 = 0xe0;
 		break;
@@ -2007,9 +2358,11 @@
 		reg17 = 0x20;
 		break;
 	case SENSOR_OV7660:
+	case SENSOR_SOI768:
 		reg17 = 0xa0;
 		break;
 	case SENSOR_PO1030:
+	case SENSOR_PO2030N:
 		reg17 = 0xa0;
 		break;
 	default:
@@ -2034,12 +2387,18 @@
 	case SENSOR_SP80708:
 		reg_w1(gspca_dev, 0x9a, 0x05);
 		break;
+	case SENSOR_GC0307:
 	case SENSOR_MT9V111:
 		reg_w1(gspca_dev, 0x9a, 0x07);
 		break;
+	case SENSOR_OV7630:
 	case SENSOR_OV7648:
 		reg_w1(gspca_dev, 0x9a, 0x0a);
 		break;
+	case SENSOR_PO2030N:
+	case SENSOR_SOI768:
+		reg_w1(gspca_dev, 0x9a, 0x06);
+		break;
 	default:
 		reg_w1(gspca_dev, 0x9a, 0x08);
 		break;
@@ -2064,6 +2423,11 @@
 		reg1 = 0x46;
 		reg17 = 0xe2;
 		break;
+	case SENSOR_GC0307:
+		init = gc0307_sensor_param1;
+		reg17 = 0xa2;
+		reg1 = 0x44;
+		break;
 	case SENSOR_MO4000:
 		if (mode) {
 /*			reg1 = 0x46;	 * 320 clk 48Mhz 60fp/s */
@@ -2087,6 +2451,7 @@
 		reg17 = 0x64;		/* 640 MCKSIZE */
 		break;
 	case SENSOR_OV7630:
+		init = ov7630_sensor_param1;
 		reg17 = 0xe2;
 		reg1 = 0x44;
 		break;
@@ -2113,6 +2478,16 @@
 		reg17 = 0xa2;
 		reg1 = 0x44;
 		break;
+	case SENSOR_PO2030N:
+		init = po2030n_sensor_param1;
+		reg1 = 0x46;
+		reg17 = 0xa2;
+		break;
+	case SENSOR_SOI768:
+		init = soi768_sensor_param1;
+		reg1 = 0x44;
+		reg17 = 0xa2;
+		break;
 	default:
 /*	case SENSOR_SP80708: */
 		init = sp80708_sensor_param1;
@@ -2132,17 +2507,33 @@
 	}
 
 	reg_w(gspca_dev, 0xc0, C0, 6);
-	if (sd->sensor == SENSOR_ADCM1700)
+	switch (sd->sensor) {
+	case SENSOR_ADCM1700:
+	case SENSOR_GC0307:
+	case SENSOR_SOI768:
 		reg_w(gspca_dev, 0xca, CA_adcm1700, 4);
-	else
+		break;
+	case SENSOR_PO2030N:
+		reg_w(gspca_dev, 0xca, CA_po2030n, 4);
+		break;
+	default:
 		reg_w(gspca_dev, 0xca, CA, 4);
+		break;
+	}
 	switch (sd->sensor) {
 	case SENSOR_ADCM1700:
 	case SENSOR_OV7630:
 	case SENSOR_OV7648:
 	case SENSOR_OV7660:
+	case SENSOR_SOI768:
 		reg_w(gspca_dev, 0xce, CE_ov76xx, 4);
 		break;
+	case SENSOR_GC0307:
+		reg_w(gspca_dev, 0xce, CE_gc0307, 4);
+		break;
+	case SENSOR_PO2030N:
+		reg_w(gspca_dev, 0xce, CE_po2030n, 4);
+		break;
 	default:
 		reg_w(gspca_dev, 0xce, CE, 4);
 					/* ?? {0x1e, 0xdd, 0x2d, 0xe7} */
@@ -2161,6 +2552,7 @@
 	setvflip(sd);
 	setbrightness(gspca_dev);
 	setcontrast(gspca_dev);
+	setcolors(gspca_dev);
 	setautogain(gspca_dev);
 	setfreq(gspca_dev);
 	return 0;
@@ -2175,11 +2567,16 @@
 		{ 0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10 };
 	static const u8 stopov7648[] =
 		{ 0xa1, 0x21, 0x76, 0x20, 0x00, 0x00, 0x00, 0x10 };
+	static const u8 stopsoi768[] =
+		{ 0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10 };
 	u8 data;
 	const u8 *sn9c1xx;
 
 	data = 0x0b;
 	switch (sd->sensor) {
+	case SENSOR_GC0307:
+		data = 0x29;
+		break;
 	case SENSOR_HV7131R:
 		i2c_w8(gspca_dev, stophv7131);
 		data = 0x2b;
@@ -2196,6 +2593,10 @@
 	case SENSOR_PO1030:
 		data = 0x29;
 		break;
+	case SENSOR_SOI768:
+		i2c_w8(gspca_dev, stopsoi768);
+		data = 0x29;
+		break;
 	}
 	sn9c1xx = sn_tb[sd->sensor];
 	reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
@@ -2206,13 +2607,6 @@
 	/* reg_w1(gspca_dev, 0xf1, 0x01); */
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	kfree(sd->jpeg_hdr);
-}
-
 static void do_autogain(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -2233,6 +2627,14 @@
 	if (delta < luma_mean - luma_delta ||
 	    delta > luma_mean + luma_delta) {
 		switch (sd->sensor) {
+		case SENSOR_GC0307:
+			expotimes = sd->exposure;
+			expotimes += (luma_mean - delta) >> 6;
+			if (expotimes < 0)
+				expotimes = 0;
+			sd->exposure = setexposure(gspca_dev,
+						   (unsigned int) expotimes);
+			break;
 		case SENSOR_HV7131R:
 			expotimes = sd->exposure >> 8;
 			expotimes += (luma_mean - delta) >> 4;
@@ -2584,7 +2986,6 @@
 	.init = sd_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
-	.stop0 = sd_stop0,
 	.pkt_scan = sd_pkt_scan,
 	.dq_callback = do_autogain,
 	.get_jcomp = sd_get_jcomp,
@@ -2656,7 +3057,7 @@
 #endif
 	{USB_DEVICE(0x0c45, 0x613c), BS(SN9C120, HV7131R)},
 	{USB_DEVICE(0x0c45, 0x613e), BS(SN9C120, OV7630)},
-/*	{USB_DEVICE(0x0c45, 0x6142), BS(SN9C120, PO2030N)},	 *sn9c120b*/
+	{USB_DEVICE(0x0c45, 0x6142), BS(SN9C120, PO2030N)},	/*sn9c120b*/
 	{USB_DEVICE(0x0c45, 0x6143), BS(SN9C120, SP80708)},	/*sn9c120b*/
 	{USB_DEVICE(0x0c45, 0x6148), BS(SN9C120, OM6802)},	/*sn9c120b*/
 	{USB_DEVICE(0x0c45, 0x614a), BS(SN9C120, ADCM1700)},	/*sn9c120b*/
diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c
index b9c80e2..7bb2355 100644
--- a/drivers/media/video/gspca/spca561.c
+++ b/drivers/media/video/gspca/spca561.c
@@ -22,6 +22,7 @@
 
 #define MODULE_NAME "spca561"
 
+#include <linux/input.h>
 #include "gspca.h"
 
 MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
@@ -249,9 +250,9 @@
 };
 
 static const __u16 spca561_161rev12A_data1[][2] = {
-	{0x29, 0x8118},		/* white balance - was 21 */
-	{0x08, 0x8114},		/* white balance - was 01 */
-	{0x0e, 0x8112},		/* white balance - was 00 */
+	{0x29, 0x8118},		/* Control register (various enable bits) */
+	{0x08, 0x8114},		/* GPIO: Led off */
+	{0x0e, 0x8112},		/* 0x0e stream off 0x3e stream on */
 	{0x00, 0x8102},		/* white balance - new */
 	{0x92, 0x8804},
 	{0x04, 0x8802},		/* windows uses 08 */
@@ -263,15 +264,11 @@
 	{0x07, 0x8601},
 	{0x07, 0x8602},
 	{0x04, 0x8501},
-	{0x21, 0x8118},
 
 	{0x07, 0x8201},		/* windows uses 02 */
 	{0x08, 0x8200},
 	{0x01, 0x8200},
 
-	{0x00, 0x8114},
-	{0x01, 0x8114},		/* windows uses 00 */
-
 	{0x90, 0x8604},
 	{0x00, 0x8605},
 	{0xb0, 0x8603},
@@ -302,6 +299,9 @@
 	{0xf0, 0x8505},
 	{0x32, 0x850a},
 /*	{0x99, 0x8700},		 * - white balance - new (removed) */
+	/* HDG we used to do this in stop0, making the init state and the state
+	   after a start / stop different, so do this here instead. */
+	{0x29, 0x8118},
 	{}
 };
 
@@ -645,6 +645,9 @@
 	setwhite(gspca_dev);
 	setgain(gspca_dev);
 	setexposure(gspca_dev);
+
+	/* Led ON (bit 3 -> 0 */
+	reg_w_val(gspca_dev->dev, 0x8114, 0x00);
 	return 0;
 }
 static int sd_start_72a(struct gspca_dev *gspca_dev)
@@ -691,26 +694,14 @@
 
 	if (sd->chip_revision == Rev012A) {
 		reg_w_val(gspca_dev->dev, 0x8112, 0x0e);
+		/* Led Off (bit 3 -> 1 */
+		reg_w_val(gspca_dev->dev, 0x8114, 0x08);
 	} else {
 		reg_w_val(gspca_dev->dev, 0x8112, 0x20);
 /*		reg_w_val(gspca_dev->dev, 0x8102, 0x00); ?? */
 	}
 }
 
-/* called on streamoff with alt 0 and on disconnect */
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	if (!gspca_dev->present)
-		return;
-	if (sd->chip_revision == Rev012A) {
-		reg_w_val(gspca_dev->dev, 0x8118, 0x29);
-		reg_w_val(gspca_dev->dev, 0x8114, 0x08);
-	}
-/*	reg_w_val(gspca_dev->dev, 0x8114, 0); */
-}
-
 static void do_autogain(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -788,6 +779,23 @@
 	switch (*data++) {			/* sequence number */
 	case 0:					/* start of frame */
 		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+
+		/* This should never happen */
+		if (len < 2) {
+			PDEBUG(D_ERR, "Short SOF packet, ignoring");
+			gspca_dev->last_packet_type = DISCARD_PACKET;
+			return;
+		}
+
+#ifdef CONFIG_INPUT
+		if (data[0] & 0x20) {
+			input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
+			input_sync(gspca_dev->input_dev);
+			input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+			input_sync(gspca_dev->input_dev);
+		}
+#endif
+
 		if (data[1] & 0x10) {
 			/* compressed bayer */
 			gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
@@ -1028,8 +1036,10 @@
 	.init = sd_init_12a,
 	.start = sd_start_12a,
 	.stopN = sd_stopN,
-	.stop0 = sd_stop0,
 	.pkt_scan = sd_pkt_scan,
+#ifdef CONFIG_INPUT
+	.other_input = 1,
+#endif
 };
 static const struct sd_desc sd_desc_72a = {
 	.name = MODULE_NAME,
@@ -1039,9 +1049,11 @@
 	.init = sd_init_72a,
 	.start = sd_start_72a,
 	.stopN = sd_stopN,
-	.stop0 = sd_stop0,
 	.pkt_scan = sd_pkt_scan,
 	.dq_callback = do_autogain,
+#ifdef CONFIG_INPUT
+	.other_input = 1,
+#endif
 };
 static const struct sd_desc *sd_desc[2] = {
 	&sd_desc_12a,
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
index 668a753..6301437 100644
--- a/drivers/media/video/gspca/t613.c
+++ b/drivers/media/video/gspca/t613.c
@@ -44,7 +44,10 @@
 	u8 gamma;
 	u8 sharpness;
 	u8 freq;
-	u8 whitebalance;
+	u8 red_balance; /* split balance */
+	u8 blue_balance;
+	u8 global_gain; /* aka gain */
+	u8 whitebalance; /* set default r/g/b and activate */
 	u8 mirror;
 	u8 effect;
 
@@ -70,8 +73,17 @@
 static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+
+
 static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setglobal_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getglobal_gain(struct gspca_dev *gspca_dev, __s32 *val);
+
 static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val);
@@ -79,6 +91,7 @@
 static int sd_querymenu(struct gspca_dev *gspca_dev,
 			struct v4l2_querymenu *menu);
 
+
 static const struct ctrl sd_ctrls[] = {
 	{
 	 {
@@ -139,7 +152,7 @@
 	 },
 	{
 	 {
-	  .id = V4L2_CID_GAIN,	/* here, i activate only the lowlight,
+	  .id = V4L2_CID_BACKLIGHT_COMPENSATION, /* Activa lowlight,
 				 * some apps dont bring up the
 				 * backligth_compensation control) */
 	  .type = V4L2_CTRL_TYPE_INTEGER,
@@ -183,7 +196,7 @@
 
 	{
 	 {
-	  .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
+	  .id =  V4L2_CID_AUTO_WHITE_BALANCE,
 	  .type = V4L2_CTRL_TYPE_INTEGER,
 	  .name = "White Balance",
 	  .minimum = 0,
@@ -223,6 +236,48 @@
 	 .set = sd_seteffect,
 	 .get = sd_geteffect
 	},
+	{
+	 {
+	    .id      = V4L2_CID_BLUE_BALANCE,
+	    .type    = V4L2_CTRL_TYPE_INTEGER,
+	    .name    = "Blue Balance",
+	    .minimum = 0x10,
+	    .maximum = 0x40,
+	    .step    = 1,
+#define BLUE_BALANCE_DEF 0x20
+	    .default_value = BLUE_BALANCE_DEF,
+	 },
+	.set = sd_setblue_balance,
+	.get = sd_getblue_balance,
+	},
+	{
+	 {
+	    .id      = V4L2_CID_RED_BALANCE,
+	    .type    = V4L2_CTRL_TYPE_INTEGER,
+	    .name    = "Red Balance",
+	    .minimum = 0x10,
+	    .maximum = 0x40,
+	    .step    = 1,
+#define RED_BALANCE_DEF 0x20
+	    .default_value = RED_BALANCE_DEF,
+	 },
+	.set = sd_setred_balance,
+	.get = sd_getred_balance,
+	},
+	{
+	 {
+	    .id      = V4L2_CID_GAIN,
+	    .type    = V4L2_CTRL_TYPE_INTEGER,
+	    .name    = "Gain",
+	    .minimum = 0x10,
+	    .maximum = 0x40,
+	    .step    = 1,
+#define global_gain_DEF  0x20
+	    .default_value = global_gain_DEF,
+	 },
+	.set = sd_setglobal_gain,
+	.get = sd_getglobal_gain,
+	},
 };
 
 static char *effects_control[] = {
@@ -523,6 +578,10 @@
 		u8 *tmpbuf;
 
 		tmpbuf = kmalloc(len, GFP_KERNEL);
+		if (!tmpbuf) {
+			err("Out of memory");
+			return;
+		}
 		memcpy(tmpbuf, buffer, len);
 		usb_control_msg(gspca_dev->dev,
 				usb_sndctrlpipe(gspca_dev->dev, 0),
@@ -542,10 +601,15 @@
 	int i;
 	u8 *p, *tmpbuf;
 
-	if (len * 2 <= USB_BUF_SZ)
+	if (len * 2 <= USB_BUF_SZ) {
 		p = tmpbuf = gspca_dev->usb_buf;
-	else
+	} else {
 		p = tmpbuf = kmalloc(len * 2, GFP_KERNEL);
+		if (!tmpbuf) {
+			err("Out of memory");
+			return;
+		}
+	}
 	i = len;
 	while (--i >= 0) {
 		*p++ = reg++;
@@ -642,6 +706,10 @@
 	sd->whitebalance = WHITE_BALANCE_DEF;
 	sd->sharpness = SHARPNESS_DEF;
 	sd->effect = EFFECTS_DEF;
+	sd->red_balance = RED_BALANCE_DEF;
+	sd->blue_balance = BLUE_BALANCE_DEF;
+	sd->global_gain = global_gain_DEF;
+
 	return 0;
 }
 
@@ -693,18 +761,40 @@
 	reg_w_ixbuf(gspca_dev, 0x90,
 		gamma_table[sd->gamma], sizeof gamma_table[0]);
 }
+static void setglobalgain(struct gspca_dev *gspca_dev)
+{
 
-static void setwhitebalance(struct gspca_dev *gspca_dev)
+	struct sd *sd = (struct sd *) gspca_dev;
+	reg_w(gspca_dev, (sd->red_balance  << 8) + 0x87);
+	reg_w(gspca_dev, (sd->blue_balance << 8) + 0x88);
+	reg_w(gspca_dev, (sd->global_gain  << 8) + 0x89);
+}
+
+/* Generic fnc for r/b balance, exposure and whitebalance */
+static void setbalance(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	u8 white_balance[8] =
-		{0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38};
+	/* on whitebalance leave defaults values */
+	if (sd->whitebalance) {
+		reg_w(gspca_dev, 0x3c80);
+	} else {
+		reg_w(gspca_dev, 0x3880);
+		/* shoud we wait here.. */
+		/* update and reset 'global gain' with webcam parameters */
+		sd->red_balance = reg_r(gspca_dev, 0x0087);
+		sd->blue_balance = reg_r(gspca_dev, 0x0088);
+		sd->global_gain = reg_r(gspca_dev, 0x0089);
+		setglobalgain(gspca_dev);
+	}
 
-	if (sd->whitebalance)
-		white_balance[7] = 0x3c;
+}
 
-	reg_w_buf(gspca_dev, white_balance, sizeof white_balance);
+
+
+static void setwhitebalance(struct gspca_dev *gspca_dev)
+{
+	setbalance(gspca_dev);
 }
 
 static void setsharpness(struct gspca_dev *gspca_dev)
@@ -1018,6 +1108,66 @@
 	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
+
+static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->blue_balance = val;
+	if (gspca_dev->streaming)
+		reg_w(gspca_dev, (val << 8) + 0x88);
+	return 0;
+}
+
+static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->blue_balance;
+	return 0;
+}
+
+static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->red_balance = val;
+	if (gspca_dev->streaming)
+		reg_w(gspca_dev, (val << 8) + 0x87);
+
+	return 0;
+}
+
+static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->red_balance;
+	return 0;
+}
+
+
+
+static int sd_setglobal_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->global_gain = val;
+	if (gspca_dev->streaming)
+		setglobalgain(gspca_dev);
+
+	return 0;
+}
+
+static int sd_getglobal_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->global_gain;
+	return 0;
+}
+
+
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
index 4989f9a..732c3df 100644
--- a/drivers/media/video/gspca/vc032x.c
+++ b/drivers/media/video/gspca/vc032x.c
@@ -1,9 +1,9 @@
 /*
- *		Z-star vc0321 library
- *		Copyright (C) 2006 Koninski Artur takeshi87@o2.pl
- *		Copyright (C) 2006 Michel Xhaard
+ * Z-star vc0321 library
  *
- * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2009-2010 Jean-François Moine <http://moinejf.free.fr>
+ * Copyright (C) 2006 Koninski Artur takeshi87@o2.pl
+ * Copyright (C) 2006 Michel Xhaard
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -24,7 +24,7 @@
 
 #include "gspca.h"
 
-MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("GSPCA/VC032X USB Camera Driver");
 MODULE_LICENSE("GPL");
 
@@ -1971,268 +1971,489 @@
 	{}
 };
 
-static const u8 ov7670_initVGA_JPG[][4] = {
+static const u8 ov7670_InitVGA[][4] = {
 	{0xb3, 0x01, 0x05, 0xcc},
-	{0x00, 0x00, 0x30, 0xdd},	{0xb0, 0x03, 0x19, 0xcc},
+	{0x00, 0x00, 0x30, 0xdd},
+	{0xb0, 0x03, 0x19, 0xcc},
 	{0x00, 0x00, 0x10, 0xdd},
-	{0xb0, 0x04, 0x02, 0xcc},	{0x00, 0x00, 0x10, 0xdd},
-	{0xb3, 0x00, 0x66, 0xcc},	{0xb3, 0x00, 0x67, 0xcc},
+	{0xb0, 0x04, 0x02, 0xcc},
+	{0x00, 0x00, 0x10, 0xdd},
+	{0xb3, 0x00, 0x66, 0xcc},
+	{0xb3, 0x00, 0x67, 0xcc},
+	{0xb0, 0x16, 0x01, 0xcc},
 	{0xb3, 0x35, 0xa1, 0xcc},	/* i2c add: 21 */
 	{0xb3, 0x34, 0x01, 0xcc},
-	{0xb3, 0x05, 0x01, 0xcc},	{0xb3, 0x06, 0x01, 0xcc},
-	{0xb3, 0x08, 0x01, 0xcc},	{0xb3, 0x09, 0x0c, 0xcc},
-	{0xb3, 0x02, 0x02, 0xcc},	{0xb3, 0x03, 0x1f, 0xcc},
-	{0xb3, 0x14, 0x00, 0xcc},	{0xb3, 0x15, 0x00, 0xcc},
-	{0xb3, 0x16, 0x02, 0xcc},	{0xb3, 0x17, 0x7f, 0xcc},
-	{0xb3, 0x04, 0x05, 0xcc},	{0xb3, 0x20, 0x00, 0xcc},
-	{0xb3, 0x21, 0x00, 0xcc},	{0xb3, 0x22, 0x01, 0xcc},
-	{0xb3, 0x23, 0xe0, 0xcc},	{0xbc, 0x00, 0x41, 0xcc},
-	{0xbc, 0x01, 0x01, 0xcc},	{0x00, 0x12, 0x80, 0xaa},
-	{0x00, 0x00, 0x20, 0xdd},	{0x00, 0x12, 0x00, 0xaa},
-	{0x00, 0x11, 0x40, 0xaa},	{0x00, 0x6b, 0x0a, 0xaa},
-	{0x00, 0x3a, 0x04, 0xaa},	{0x00, 0x40, 0xc0, 0xaa},
-	{0x00, 0x8c, 0x00, 0xaa},	{0x00, 0x7a, 0x29, 0xaa},
-	{0x00, 0x7b, 0x0e, 0xaa},	{0x00, 0x7c, 0x1a, 0xaa},
-	{0x00, 0x7d, 0x31, 0xaa},	{0x00, 0x7e, 0x53, 0xaa},
-	{0x00, 0x7f, 0x60, 0xaa},	{0x00, 0x80, 0x6b, 0xaa},
-	{0x00, 0x81, 0x73, 0xaa},	{0x00, 0x82, 0x7b, 0xaa},
-	{0x00, 0x83, 0x82, 0xaa},	{0x00, 0x84, 0x89, 0xaa},
-	{0x00, 0x85, 0x96, 0xaa},	{0x00, 0x86, 0xa1, 0xaa},
-	{0x00, 0x87, 0xb7, 0xaa},	{0x00, 0x88, 0xcc, 0xaa},
-	{0x00, 0x89, 0xe1, 0xaa},	{0x00, 0x13, 0xe0, 0xaa},
-	{0x00, 0x00, 0x00, 0xaa},	{0x00, 0x10, 0x00, 0xaa},
-	{0x00, 0x0d, 0x40, 0xaa},	{0x00, 0x14, 0x28, 0xaa},
-	{0x00, 0xa5, 0x05, 0xaa},	{0x00, 0xab, 0x07, 0xaa},
-	{0x00, 0x24, 0x95, 0xaa},	{0x00, 0x25, 0x33, 0xaa},
-	{0x00, 0x26, 0xe3, 0xaa},	{0x00, 0x9f, 0x88, 0xaa},
-	{0x00, 0xa0, 0x78, 0xaa},	{0x00, 0x55, 0x90, 0xaa},
-	{0x00, 0xa1, 0x03, 0xaa},	{0x00, 0xa6, 0xe0, 0xaa},
-	{0x00, 0xa7, 0xd8, 0xaa},	{0x00, 0xa8, 0xf0, 0xaa},
-	{0x00, 0xa9, 0x90, 0xaa},	{0x00, 0xaa, 0x14, 0xaa},
-	{0x00, 0x13, 0xe5, 0xaa},	{0x00, 0x0e, 0x61, 0xaa},
-	{0x00, 0x0f, 0x4b, 0xaa},	{0x00, 0x16, 0x02, 0xaa},
+	{0xb3, 0x05, 0x01, 0xcc},
+	{0xb3, 0x06, 0x01, 0xcc},
+	{0xb3, 0x08, 0x01, 0xcc},
+	{0xb3, 0x09, 0x0c, 0xcc},
+	{0xb3, 0x02, 0x02, 0xcc},
+	{0xb3, 0x03, 0x1f, 0xcc},
+	{0xb3, 0x14, 0x00, 0xcc},
+	{0xb3, 0x15, 0x00, 0xcc},
+	{0xb3, 0x16, 0x02, 0xcc},
+	{0xb3, 0x17, 0x7f, 0xcc},
+	{0xb3, 0x04, 0x05, 0xcc},
+	{0xb3, 0x20, 0x00, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},
+	{0xb3, 0x22, 0x01, 0xcc},
+	{0xb3, 0x23, 0xe0, 0xcc},
+	{0xbc, 0x00, 0x41, 0xcc},
+	{0xbc, 0x01, 0x01, 0xcc},
+	{0x00, 0x12, 0x80, 0xaa},
+	{0x00, 0x00, 0x20, 0xdd},
+	{0x00, 0x12, 0x00, 0xaa},
+	{0x00, 0x11, 0x40, 0xaa},
+	{0x00, 0x6b, 0x0a, 0xaa},
+	{0x00, 0x3a, 0x04, 0xaa},
+	{0x00, 0x40, 0xc0, 0xaa},
+	{0x00, 0x8c, 0x00, 0xaa},
+	{0x00, 0x7a, 0x29, 0xaa},
+	{0x00, 0x7b, 0x0e, 0xaa},
+	{0x00, 0x7c, 0x1a, 0xaa},
+	{0x00, 0x7d, 0x31, 0xaa},
+	{0x00, 0x7e, 0x53, 0xaa},
+	{0x00, 0x7f, 0x60, 0xaa},
+	{0x00, 0x80, 0x6b, 0xaa},
+	{0x00, 0x81, 0x73, 0xaa},
+	{0x00, 0x82, 0x7b, 0xaa},
+	{0x00, 0x83, 0x82, 0xaa},
+	{0x00, 0x84, 0x89, 0xaa},
+	{0x00, 0x85, 0x96, 0xaa},
+	{0x00, 0x86, 0xa1, 0xaa},
+	{0x00, 0x87, 0xb7, 0xaa},
+	{0x00, 0x88, 0xcc, 0xaa},
+	{0x00, 0x89, 0xe1, 0xaa},
+	{0x00, 0x13, 0xe0, 0xaa},
+	{0x00, 0x00, 0x00, 0xaa},
+	{0x00, 0x10, 0x00, 0xaa},
+	{0x00, 0x0d, 0x40, 0xaa},
+	{0x00, 0x14, 0x28, 0xaa},
+	{0x00, 0xa5, 0x05, 0xaa},
+	{0x00, 0xab, 0x07, 0xaa},
+	{0x00, 0x24, 0x95, 0xaa},
+	{0x00, 0x25, 0x33, 0xaa},
+	{0x00, 0x26, 0xe3, 0xaa},
+	{0x00, 0x9f, 0x88, 0xaa},
+	{0x00, 0xa0, 0x78, 0xaa},
+	{0x00, 0x55, 0x90, 0xaa},
+	{0x00, 0xa1, 0x03, 0xaa},
+	{0x00, 0xa6, 0xe0, 0xaa},
+	{0x00, 0xa7, 0xd8, 0xaa},
+	{0x00, 0xa8, 0xf0, 0xaa},
+	{0x00, 0xa9, 0x90, 0xaa},
+	{0x00, 0xaa, 0x14, 0xaa},
+	{0x00, 0x13, 0xe5, 0xaa},
+	{0x00, 0x0e, 0x61, 0xaa},
+	{0x00, 0x0f, 0x4b, 0xaa},
+	{0x00, 0x16, 0x02, 0xaa},
 	{0x00, 0x1e, 0x07, 0xaa},	/* MVFP */
 	{0x00, 0x21, 0x02, 0xaa},
-	{0x00, 0x22, 0x91, 0xaa},	{0x00, 0x29, 0x07, 0xaa},
-	{0x00, 0x33, 0x0b, 0xaa},	{0x00, 0x35, 0x0b, 0xaa},
-	{0x00, 0x37, 0x1d, 0xaa},	{0x00, 0x38, 0x71, 0xaa},
-	{0x00, 0x39, 0x2a, 0xaa},	{0x00, 0x3c, 0x78, 0xaa},
-	{0x00, 0x4d, 0x40, 0xaa},	{0x00, 0x4e, 0x20, 0xaa},
-	{0x00, 0x74, 0x19, 0xaa},	{0x00, 0x8d, 0x4f, 0xaa},
-	{0x00, 0x8e, 0x00, 0xaa},	{0x00, 0x8f, 0x00, 0xaa},
-	{0x00, 0x90, 0x00, 0xaa},	{0x00, 0x91, 0x00, 0xaa},
-	{0x00, 0x96, 0x00, 0xaa},	{0x00, 0x9a, 0x80, 0xaa},
-	{0x00, 0xb0, 0x84, 0xaa},	{0x00, 0xb1, 0x0c, 0xaa},
-	{0x00, 0xb2, 0x0e, 0xaa},	{0x00, 0xb3, 0x82, 0xaa},
-	{0x00, 0xb8, 0x0a, 0xaa},	{0x00, 0x43, 0x14, 0xaa},
-	{0x00, 0x44, 0xf0, 0xaa},	{0x00, 0x45, 0x45, 0xaa},
-	{0x00, 0x46, 0x63, 0xaa},	{0x00, 0x47, 0x2d, 0xaa},
-	{0x00, 0x48, 0x46, 0xaa},	{0x00, 0x59, 0x88, 0xaa},
-	{0x00, 0x5a, 0xa0, 0xaa},	{0x00, 0x5b, 0xc6, 0xaa},
-	{0x00, 0x5c, 0x7d, 0xaa},	{0x00, 0x5d, 0x5f, 0xaa},
-	{0x00, 0x5e, 0x19, 0xaa},	{0x00, 0x6c, 0x0a, 0xaa},
-	{0x00, 0x6d, 0x55, 0xaa},	{0x00, 0x6e, 0x11, 0xaa},
-	{0x00, 0x6f, 0x9e, 0xaa},	{0x00, 0x69, 0x00, 0xaa},
-	{0x00, 0x6a, 0x40, 0xaa},	{0x00, 0x01, 0x40, 0xaa},
-	{0x00, 0x02, 0x40, 0xaa},	{0x00, 0x13, 0xe7, 0xaa},
-	{0x00, 0x5f, 0xf0, 0xaa},	{0x00, 0x60, 0xf0, 0xaa},
-	{0x00, 0x61, 0xf0, 0xaa},	{0x00, 0x27, 0xa0, 0xaa},
-	{0x00, 0x28, 0x80, 0xaa},	{0x00, 0x2c, 0x90, 0xaa},
-	{0x00, 0x4f, 0x66, 0xaa},	{0x00, 0x50, 0x66, 0xaa},
-	{0x00, 0x51, 0x00, 0xaa},	{0x00, 0x52, 0x22, 0xaa},
-	{0x00, 0x53, 0x5e, 0xaa},	{0x00, 0x54, 0x80, 0xaa},
-	{0x00, 0x58, 0x9e, 0xaa},	{0x00, 0x41, 0x08, 0xaa},
-	{0x00, 0x3f, 0x00, 0xaa},	{0x00, 0x75, 0x85, 0xaa},
-	{0x00, 0x76, 0xe1, 0xaa},	{0x00, 0x4c, 0x00, 0xaa},
-	{0x00, 0x77, 0x0a, 0xaa},	{0x00, 0x3d, 0x88, 0xaa},
-	{0x00, 0x4b, 0x09, 0xaa},	{0x00, 0xc9, 0x60, 0xaa},
-	{0x00, 0x41, 0x38, 0xaa},	{0x00, 0x62, 0x30, 0xaa},
-	{0x00, 0x63, 0x30, 0xaa},	{0x00, 0x64, 0x08, 0xaa},
-	{0x00, 0x94, 0x07, 0xaa},	{0x00, 0x95, 0x0b, 0xaa},
-	{0x00, 0x65, 0x00, 0xaa},	{0x00, 0x66, 0x05, 0xaa},
-	{0x00, 0x56, 0x50, 0xaa},	{0x00, 0x34, 0x11, 0xaa},
-	{0x00, 0xa4, 0x88, 0xaa},	{0x00, 0x96, 0x00, 0xaa},
-	{0x00, 0x97, 0x30, 0xaa},	{0x00, 0x98, 0x20, 0xaa},
-	{0x00, 0x99, 0x30, 0xaa},	{0x00, 0x9a, 0x84, 0xaa},
-	{0x00, 0x9b, 0x29, 0xaa},	{0x00, 0x9c, 0x03, 0xaa},
-	{0x00, 0x78, 0x04, 0xaa},	{0x00, 0x79, 0x01, 0xaa},
-	{0x00, 0xc8, 0xf0, 0xaa},	{0x00, 0x79, 0x0f, 0xaa},
-	{0x00, 0xc8, 0x00, 0xaa},	{0x00, 0x79, 0x10, 0xaa},
-	{0x00, 0xc8, 0x7e, 0xaa},	{0x00, 0x79, 0x0a, 0xaa},
-	{0x00, 0xc8, 0x80, 0xaa},	{0x00, 0x79, 0x0b, 0xaa},
-	{0x00, 0xc8, 0x01, 0xaa},	{0x00, 0x79, 0x0c, 0xaa},
-	{0x00, 0xc8, 0x0f, 0xaa},	{0x00, 0x79, 0x0d, 0xaa},
-	{0x00, 0xc8, 0x20, 0xaa},	{0x00, 0x79, 0x09, 0xaa},
-	{0x00, 0xc8, 0x80, 0xaa},	{0x00, 0x79, 0x02, 0xaa},
-	{0x00, 0xc8, 0xc0, 0xaa},	{0x00, 0x79, 0x03, 0xaa},
-	{0x00, 0xc8, 0x40, 0xaa},	{0x00, 0x79, 0x05, 0xaa},
-	{0x00, 0xc8, 0x30, 0xaa},	{0x00, 0x79, 0x26, 0xaa},
-	{0x00, 0x11, 0x40, 0xaa},	{0x00, 0x3a, 0x04, 0xaa},
-	{0x00, 0x12, 0x00, 0xaa},	{0x00, 0x40, 0xc0, 0xaa},
-	{0x00, 0x8c, 0x00, 0xaa},	{0x00, 0x17, 0x14, 0xaa},
-	{0x00, 0x18, 0x02, 0xaa},	{0x00, 0x32, 0x92, 0xaa},
-	{0x00, 0x19, 0x02, 0xaa},	{0x00, 0x1a, 0x7a, 0xaa},
-	{0x00, 0x03, 0x0a, 0xaa},	{0x00, 0x0c, 0x00, 0xaa},
-	{0x00, 0x3e, 0x00, 0xaa},	{0x00, 0x70, 0x3a, 0xaa},
-	{0x00, 0x71, 0x35, 0xaa},	{0x00, 0x72, 0x11, 0xaa},
-	{0x00, 0x73, 0xf0, 0xaa},	{0x00, 0xa2, 0x02, 0xaa},
-	{0x00, 0xb1, 0x00, 0xaa},	{0x00, 0xb1, 0x0c, 0xaa},
+	{0x00, 0x22, 0x91, 0xaa},
+	{0x00, 0x29, 0x07, 0xaa},
+	{0x00, 0x33, 0x0b, 0xaa},
+	{0x00, 0x35, 0x0b, 0xaa},
+	{0x00, 0x37, 0x1d, 0xaa},
+	{0x00, 0x38, 0x71, 0xaa},
+	{0x00, 0x39, 0x2a, 0xaa},
+	{0x00, 0x3c, 0x78, 0xaa},
+	{0x00, 0x4d, 0x40, 0xaa},
+	{0x00, 0x4e, 0x20, 0xaa},
+	{0x00, 0x74, 0x19, 0xaa},
+	{0x00, 0x8d, 0x4f, 0xaa},
+	{0x00, 0x8e, 0x00, 0xaa},
+	{0x00, 0x8f, 0x00, 0xaa},
+	{0x00, 0x90, 0x00, 0xaa},
+	{0x00, 0x91, 0x00, 0xaa},
+	{0x00, 0x96, 0x00, 0xaa},
+	{0x00, 0x9a, 0x80, 0xaa},
+	{0x00, 0xb0, 0x84, 0xaa},
+	{0x00, 0xb1, 0x0c, 0xaa},
+	{0x00, 0xb2, 0x0e, 0xaa},
+	{0x00, 0xb3, 0x82, 0xaa},
+	{0x00, 0xb8, 0x0a, 0xaa},
+	{0x00, 0x43, 0x14, 0xaa},
+	{0x00, 0x44, 0xf0, 0xaa},
+	{0x00, 0x45, 0x45, 0xaa},
+	{0x00, 0x46, 0x63, 0xaa},
+	{0x00, 0x47, 0x2d, 0xaa},
+	{0x00, 0x48, 0x46, 0xaa},
+	{0x00, 0x59, 0x88, 0xaa},
+	{0x00, 0x5a, 0xa0, 0xaa},
+	{0x00, 0x5b, 0xc6, 0xaa},
+	{0x00, 0x5c, 0x7d, 0xaa},
+	{0x00, 0x5d, 0x5f, 0xaa},
+	{0x00, 0x5e, 0x19, 0xaa},
+	{0x00, 0x6c, 0x0a, 0xaa},
+	{0x00, 0x6d, 0x55, 0xaa},
+	{0x00, 0x6e, 0x11, 0xaa},
+	{0x00, 0x6f, 0x9e, 0xaa},
+	{0x00, 0x69, 0x00, 0xaa},
+	{0x00, 0x6a, 0x40, 0xaa},
+	{0x00, 0x01, 0x40, 0xaa},
+	{0x00, 0x02, 0x40, 0xaa},
+	{0x00, 0x13, 0xe7, 0xaa},
+	{0x00, 0x5f, 0xf0, 0xaa},
+	{0x00, 0x60, 0xf0, 0xaa},
+	{0x00, 0x61, 0xf0, 0xaa},
+	{0x00, 0x27, 0xa0, 0xaa},
+	{0x00, 0x28, 0x80, 0xaa},
+	{0x00, 0x2c, 0x90, 0xaa},
+	{0x00, 0x4f, 0x66, 0xaa},
+	{0x00, 0x50, 0x66, 0xaa},
+	{0x00, 0x51, 0x00, 0xaa},
+	{0x00, 0x52, 0x22, 0xaa},
+	{0x00, 0x53, 0x5e, 0xaa},
+	{0x00, 0x54, 0x80, 0xaa},
+	{0x00, 0x58, 0x9e, 0xaa},
+	{0x00, 0x41, 0x08, 0xaa},
+	{0x00, 0x3f, 0x00, 0xaa},
+	{0x00, 0x75, 0x85, 0xaa},
+	{0x00, 0x76, 0xe1, 0xaa},
+	{0x00, 0x4c, 0x00, 0xaa},
+	{0x00, 0x77, 0x0a, 0xaa},
+	{0x00, 0x3d, 0x88, 0xaa},
+	{0x00, 0x4b, 0x09, 0xaa},
+	{0x00, 0xc9, 0x60, 0xaa},
+	{0x00, 0x41, 0x38, 0xaa},
+	{0x00, 0x62, 0x30, 0xaa},
+	{0x00, 0x63, 0x30, 0xaa},
+	{0x00, 0x64, 0x08, 0xaa},
+	{0x00, 0x94, 0x07, 0xaa},
+	{0x00, 0x95, 0x0b, 0xaa},
+	{0x00, 0x65, 0x00, 0xaa},
+	{0x00, 0x66, 0x05, 0xaa},
+	{0x00, 0x56, 0x50, 0xaa},
+	{0x00, 0x34, 0x11, 0xaa},
+	{0x00, 0xa4, 0x88, 0xaa},
+	{0x00, 0x96, 0x00, 0xaa},
+	{0x00, 0x97, 0x30, 0xaa},
+	{0x00, 0x98, 0x20, 0xaa},
+	{0x00, 0x99, 0x30, 0xaa},
+	{0x00, 0x9a, 0x84, 0xaa},
+	{0x00, 0x9b, 0x29, 0xaa},
+	{0x00, 0x9c, 0x03, 0xaa},
+	{0x00, 0x78, 0x04, 0xaa},
+	{0x00, 0x79, 0x01, 0xaa},
+	{0x00, 0xc8, 0xf0, 0xaa},
+	{0x00, 0x79, 0x0f, 0xaa},
+	{0x00, 0xc8, 0x00, 0xaa},
+	{0x00, 0x79, 0x10, 0xaa},
+	{0x00, 0xc8, 0x7e, 0xaa},
+	{0x00, 0x79, 0x0a, 0xaa},
+	{0x00, 0xc8, 0x80, 0xaa},
+	{0x00, 0x79, 0x0b, 0xaa},
+	{0x00, 0xc8, 0x01, 0xaa},
+	{0x00, 0x79, 0x0c, 0xaa},
+	{0x00, 0xc8, 0x0f, 0xaa},
+	{0x00, 0x79, 0x0d, 0xaa},
+	{0x00, 0xc8, 0x20, 0xaa},
+	{0x00, 0x79, 0x09, 0xaa},
+	{0x00, 0xc8, 0x80, 0xaa},
+	{0x00, 0x79, 0x02, 0xaa},
+	{0x00, 0xc8, 0xc0, 0xaa},
+	{0x00, 0x79, 0x03, 0xaa},
+	{0x00, 0xc8, 0x40, 0xaa},
+	{0x00, 0x79, 0x05, 0xaa},
+	{0x00, 0xc8, 0x30, 0xaa},
+	{0x00, 0x79, 0x26, 0xaa},
+	{0x00, 0x11, 0x40, 0xaa},
+	{0x00, 0x3a, 0x04, 0xaa},
+	{0x00, 0x12, 0x00, 0xaa},
+	{0x00, 0x40, 0xc0, 0xaa},
+	{0x00, 0x8c, 0x00, 0xaa},
+	{0x00, 0x17, 0x14, 0xaa},
+	{0x00, 0x18, 0x02, 0xaa},
+	{0x00, 0x32, 0x92, 0xaa},
+	{0x00, 0x19, 0x02, 0xaa},
+	{0x00, 0x1a, 0x7a, 0xaa},
+	{0x00, 0x03, 0x0a, 0xaa},
+	{0x00, 0x0c, 0x00, 0xaa},
+	{0x00, 0x3e, 0x00, 0xaa},
+	{0x00, 0x70, 0x3a, 0xaa},
+	{0x00, 0x71, 0x35, 0xaa},
+	{0x00, 0x72, 0x11, 0xaa},
+	{0x00, 0x73, 0xf0, 0xaa},
+	{0x00, 0xa2, 0x02, 0xaa},
+	{0x00, 0xb1, 0x00, 0xaa},
+	{0x00, 0xb1, 0x0c, 0xaa},
 	{0x00, 0x1e, 0x37, 0xaa},	/* MVFP */
 	{0x00, 0xaa, 0x14, 0xaa},
-	{0x00, 0x24, 0x80, 0xaa},	{0x00, 0x25, 0x74, 0xaa},
-	{0x00, 0x26, 0xd3, 0xaa},	{0x00, 0x0d, 0x00, 0xaa},
-	{0x00, 0x14, 0x18, 0xaa},	{0x00, 0x9d, 0x99, 0xaa},
-	{0x00, 0x9e, 0x7f, 0xaa},	{0x00, 0x64, 0x08, 0xaa},
-	{0x00, 0x94, 0x07, 0xaa},	{0x00, 0x95, 0x06, 0xaa},
-	{0x00, 0x66, 0x05, 0xaa},	{0x00, 0x41, 0x08, 0xaa},
-	{0x00, 0x3f, 0x00, 0xaa},	{0x00, 0x75, 0x07, 0xaa},
-	{0x00, 0x76, 0xe1, 0xaa},	{0x00, 0x4c, 0x00, 0xaa},
-	{0x00, 0x77, 0x00, 0xaa},	{0x00, 0x3d, 0xc2, 0xaa},
-	{0x00, 0x4b, 0x09, 0xaa},	{0x00, 0xc9, 0x60, 0xaa},
-	{0x00, 0x41, 0x38, 0xaa},	{0xb6, 0x00, 0x00, 0xcc},
-	{0xb6, 0x03, 0x02, 0xcc},	{0xb6, 0x02, 0x80, 0xcc},
-	{0xb6, 0x05, 0x01, 0xcc},	{0xb6, 0x04, 0xe0, 0xcc},
-	{0xb6, 0x12, 0xf8, 0xcc},	{0xb6, 0x13, 0x13, 0xcc},
-	{0xb6, 0x18, 0x02, 0xcc},	{0xb6, 0x17, 0x58, 0xcc},
-	{0xb6, 0x16, 0x00, 0xcc},	{0xb6, 0x22, 0x12, 0xcc},
-	{0xb6, 0x23, 0x0b, 0xcc},	{0xbf, 0xc0, 0x39, 0xcc},
-	{0xbf, 0xc1, 0x04, 0xcc},	{0xbf, 0xcc, 0x00, 0xcc},
-	{0xb3, 0x5c, 0x01, 0xcc},	{0xb3, 0x01, 0x45, 0xcc},
+	{0x00, 0x24, 0x80, 0xaa},
+	{0x00, 0x25, 0x74, 0xaa},
+	{0x00, 0x26, 0xd3, 0xaa},
+	{0x00, 0x0d, 0x00, 0xaa},
+	{0x00, 0x14, 0x18, 0xaa},
+	{0x00, 0x9d, 0x99, 0xaa},
+	{0x00, 0x9e, 0x7f, 0xaa},
+	{0x00, 0x64, 0x08, 0xaa},
+	{0x00, 0x94, 0x07, 0xaa},
+	{0x00, 0x95, 0x06, 0xaa},
+	{0x00, 0x66, 0x05, 0xaa},
+	{0x00, 0x41, 0x08, 0xaa},
+	{0x00, 0x3f, 0x00, 0xaa},
+	{0x00, 0x75, 0x07, 0xaa},
+	{0x00, 0x76, 0xe1, 0xaa},
+	{0x00, 0x4c, 0x00, 0xaa},
+	{0x00, 0x77, 0x00, 0xaa},
+	{0x00, 0x3d, 0xc2, 0xaa},
+	{0x00, 0x4b, 0x09, 0xaa},
+	{0x00, 0xc9, 0x60, 0xaa},
+	{0x00, 0x41, 0x38, 0xaa},
+	{0xbf, 0xc0, 0x26, 0xcc},
+	{0xbf, 0xc1, 0x02, 0xcc},
+	{0xbf, 0xcc, 0x04, 0xcc},
+	{0xb3, 0x5c, 0x01, 0xcc},
+	{0xb3, 0x01, 0x45, 0xcc},
 	{0x00, 0x77, 0x05, 0xaa},
 	{},
 };
 
-static const u8 ov7670_initQVGA_JPG[][4] = {
-	{0xb3, 0x01, 0x05, 0xcc},	{0x00, 0x00, 0x30, 0xdd},
-	{0xb0, 0x03, 0x19, 0xcc},	{0x00, 0x00, 0x10, 0xdd},
-	{0xb0, 0x04, 0x02, 0xcc},	{0x00, 0x00, 0x10, 0xdd},
-	{0xb3, 0x00, 0x66, 0xcc},	{0xb3, 0x00, 0x67, 0xcc},
-	{0xb3, 0x35, 0xa1, 0xcc},	{0xb3, 0x34, 0x01, 0xcc},
-	{0xb3, 0x05, 0x01, 0xcc},	{0xb3, 0x06, 0x01, 0xcc},
-	{0xb3, 0x08, 0x01, 0xcc},	{0xb3, 0x09, 0x0c, 0xcc},
-	{0xb3, 0x02, 0x02, 0xcc},	{0xb3, 0x03, 0x1f, 0xcc},
-	{0xb3, 0x14, 0x00, 0xcc},	{0xb3, 0x15, 0x00, 0xcc},
-	{0xb3, 0x16, 0x02, 0xcc},	{0xb3, 0x17, 0x7f, 0xcc},
-	{0xb3, 0x04, 0x05, 0xcc},	{0xb3, 0x20, 0x00, 0xcc},
-	{0xb3, 0x21, 0x00, 0xcc},	{0xb3, 0x22, 0x01, 0xcc},
-	{0xb3, 0x23, 0xe0, 0xcc},	{0xbc, 0x00, 0xd1, 0xcc},
-	{0xbc, 0x01, 0x01, 0xcc},	{0x00, 0x12, 0x80, 0xaa},
-	{0x00, 0x00, 0x20, 0xdd},	{0x00, 0x12, 0x00, 0xaa},
-	{0x00, 0x11, 0x40, 0xaa},	{0x00, 0x6b, 0x0a, 0xaa},
-	{0x00, 0x3a, 0x04, 0xaa},	{0x00, 0x40, 0xc0, 0xaa},
-	{0x00, 0x8c, 0x00, 0xaa},	{0x00, 0x7a, 0x29, 0xaa},
-	{0x00, 0x7b, 0x0e, 0xaa},	{0x00, 0x7c, 0x1a, 0xaa},
-	{0x00, 0x7d, 0x31, 0xaa},	{0x00, 0x7e, 0x53, 0xaa},
-	{0x00, 0x7f, 0x60, 0xaa},	{0x00, 0x80, 0x6b, 0xaa},
-	{0x00, 0x81, 0x73, 0xaa},	{0x00, 0x82, 0x7b, 0xaa},
-	{0x00, 0x83, 0x82, 0xaa},	{0x00, 0x84, 0x89, 0xaa},
-	{0x00, 0x85, 0x96, 0xaa},	{0x00, 0x86, 0xa1, 0xaa},
-	{0x00, 0x87, 0xb7, 0xaa},	{0x00, 0x88, 0xcc, 0xaa},
-	{0x00, 0x89, 0xe1, 0xaa},	{0x00, 0x13, 0xe0, 0xaa},
-	{0x00, 0x00, 0x00, 0xaa},	{0x00, 0x10, 0x00, 0xaa},
-	{0x00, 0x0d, 0x40, 0xaa},	{0x00, 0x14, 0x28, 0xaa},
-	{0x00, 0xa5, 0x05, 0xaa},	{0x00, 0xab, 0x07, 0xaa},
-	{0x00, 0x24, 0x95, 0xaa},	{0x00, 0x25, 0x33, 0xaa},
-	{0x00, 0x26, 0xe3, 0xaa},	{0x00, 0x9f, 0x88, 0xaa},
-	{0x00, 0xa0, 0x78, 0xaa},	{0x00, 0x55, 0x90, 0xaa},
-	{0x00, 0xa1, 0x03, 0xaa},	{0x00, 0xa6, 0xe0, 0xaa},
-	{0x00, 0xa7, 0xd8, 0xaa},	{0x00, 0xa8, 0xf0, 0xaa},
-	{0x00, 0xa9, 0x90, 0xaa},	{0x00, 0xaa, 0x14, 0xaa},
-	{0x00, 0x13, 0xe5, 0xaa},	{0x00, 0x0e, 0x61, 0xaa},
-	{0x00, 0x0f, 0x4b, 0xaa},	{0x00, 0x16, 0x02, 0xaa},
+static const u8 ov7670_InitQVGA[][4] = {
+	{0xb3, 0x01, 0x05, 0xcc},
+	{0x00, 0x00, 0x30, 0xdd},
+	{0xb0, 0x03, 0x19, 0xcc},
+	{0x00, 0x00, 0x10, 0xdd},
+	{0xb0, 0x04, 0x02, 0xcc},
+	{0x00, 0x00, 0x10, 0xdd},
+	{0xb3, 0x00, 0x66, 0xcc},
+	{0xb3, 0x00, 0x67, 0xcc},
+	{0xb0, 0x16, 0x01, 0xcc},
+	{0xb3, 0x35, 0xa1, 0xcc},	/* i2c add: 21 */
+	{0xb3, 0x34, 0x01, 0xcc},
+	{0xb3, 0x05, 0x01, 0xcc},
+	{0xb3, 0x06, 0x01, 0xcc},
+	{0xb3, 0x08, 0x01, 0xcc},
+	{0xb3, 0x09, 0x0c, 0xcc},
+	{0xb3, 0x02, 0x02, 0xcc},
+	{0xb3, 0x03, 0x1f, 0xcc},
+	{0xb3, 0x14, 0x00, 0xcc},
+	{0xb3, 0x15, 0x00, 0xcc},
+	{0xb3, 0x16, 0x02, 0xcc},
+	{0xb3, 0x17, 0x7f, 0xcc},
+	{0xb3, 0x04, 0x05, 0xcc},
+	{0xb3, 0x20, 0x00, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},
+	{0xb3, 0x22, 0x01, 0xcc},
+	{0xb3, 0x23, 0xe0, 0xcc},
+	{0xbc, 0x00, 0xd1, 0xcc},
+	{0xbc, 0x01, 0x01, 0xcc},
+	{0x00, 0x12, 0x80, 0xaa},
+	{0x00, 0x00, 0x20, 0xdd},
+	{0x00, 0x12, 0x00, 0xaa},
+	{0x00, 0x11, 0x40, 0xaa},
+	{0x00, 0x6b, 0x0a, 0xaa},
+	{0x00, 0x3a, 0x04, 0xaa},
+	{0x00, 0x40, 0xc0, 0xaa},
+	{0x00, 0x8c, 0x00, 0xaa},
+	{0x00, 0x7a, 0x29, 0xaa},
+	{0x00, 0x7b, 0x0e, 0xaa},
+	{0x00, 0x7c, 0x1a, 0xaa},
+	{0x00, 0x7d, 0x31, 0xaa},
+	{0x00, 0x7e, 0x53, 0xaa},
+	{0x00, 0x7f, 0x60, 0xaa},
+	{0x00, 0x80, 0x6b, 0xaa},
+	{0x00, 0x81, 0x73, 0xaa},
+	{0x00, 0x82, 0x7b, 0xaa},
+	{0x00, 0x83, 0x82, 0xaa},
+	{0x00, 0x84, 0x89, 0xaa},
+	{0x00, 0x85, 0x96, 0xaa},
+	{0x00, 0x86, 0xa1, 0xaa},
+	{0x00, 0x87, 0xb7, 0xaa},
+	{0x00, 0x88, 0xcc, 0xaa},
+	{0x00, 0x89, 0xe1, 0xaa},
+	{0x00, 0x13, 0xe0, 0xaa},
+	{0x00, 0x00, 0x00, 0xaa},
+	{0x00, 0x10, 0x00, 0xaa},
+	{0x00, 0x0d, 0x40, 0xaa},
+	{0x00, 0x14, 0x28, 0xaa},
+	{0x00, 0xa5, 0x05, 0xaa},
+	{0x00, 0xab, 0x07, 0xaa},
+	{0x00, 0x24, 0x95, 0xaa},
+	{0x00, 0x25, 0x33, 0xaa},
+	{0x00, 0x26, 0xe3, 0xaa},
+	{0x00, 0x9f, 0x88, 0xaa},
+	{0x00, 0xa0, 0x78, 0xaa},
+	{0x00, 0x55, 0x90, 0xaa},
+	{0x00, 0xa1, 0x03, 0xaa},
+	{0x00, 0xa6, 0xe0, 0xaa},
+	{0x00, 0xa7, 0xd8, 0xaa},
+	{0x00, 0xa8, 0xf0, 0xaa},
+	{0x00, 0xa9, 0x90, 0xaa},
+	{0x00, 0xaa, 0x14, 0xaa},
+	{0x00, 0x13, 0xe5, 0xaa},
+	{0x00, 0x0e, 0x61, 0xaa},
+	{0x00, 0x0f, 0x4b, 0xaa},
+	{0x00, 0x16, 0x02, 0xaa},
 	{0x00, 0x1e, 0x07, 0xaa},	/* MVFP */
 	{0x00, 0x21, 0x02, 0xaa},
-	{0x00, 0x22, 0x91, 0xaa},	{0x00, 0x29, 0x07, 0xaa},
-	{0x00, 0x33, 0x0b, 0xaa},	{0x00, 0x35, 0x0b, 0xaa},
-	{0x00, 0x37, 0x1d, 0xaa},	{0x00, 0x38, 0x71, 0xaa},
-	{0x00, 0x39, 0x2a, 0xaa},	{0x00, 0x3c, 0x78, 0xaa},
-	{0x00, 0x4d, 0x40, 0xaa},	{0x00, 0x4e, 0x20, 0xaa},
-	{0x00, 0x74, 0x19, 0xaa},	{0x00, 0x8d, 0x4f, 0xaa},
-	{0x00, 0x8e, 0x00, 0xaa},	{0x00, 0x8f, 0x00, 0xaa},
-	{0x00, 0x90, 0x00, 0xaa},	{0x00, 0x91, 0x00, 0xaa},
-	{0x00, 0x96, 0x00, 0xaa},	{0x00, 0x9a, 0x80, 0xaa},
-	{0x00, 0xb0, 0x84, 0xaa},	{0x00, 0xb1, 0x0c, 0xaa},
-	{0x00, 0xb2, 0x0e, 0xaa},	{0x00, 0xb3, 0x82, 0xaa},
-	{0x00, 0xb8, 0x0a, 0xaa},	{0x00, 0x43, 0x14, 0xaa},
-	{0x00, 0x44, 0xf0, 0xaa},	{0x00, 0x45, 0x45, 0xaa},
-	{0x00, 0x46, 0x63, 0xaa},	{0x00, 0x47, 0x2d, 0xaa},
-	{0x00, 0x48, 0x46, 0xaa},	{0x00, 0x59, 0x88, 0xaa},
-	{0x00, 0x5a, 0xa0, 0xaa},	{0x00, 0x5b, 0xc6, 0xaa},
-	{0x00, 0x5c, 0x7d, 0xaa},	{0x00, 0x5d, 0x5f, 0xaa},
-	{0x00, 0x5e, 0x19, 0xaa},	{0x00, 0x6c, 0x0a, 0xaa},
-	{0x00, 0x6d, 0x55, 0xaa},	{0x00, 0x6e, 0x11, 0xaa},
-	{0x00, 0x6f, 0x9e, 0xaa},	{0x00, 0x69, 0x00, 0xaa},
-	{0x00, 0x6a, 0x40, 0xaa},	{0x00, 0x01, 0x40, 0xaa},
-	{0x00, 0x02, 0x40, 0xaa},	{0x00, 0x13, 0xe7, 0xaa},
-	{0x00, 0x5f, 0xf0, 0xaa},	{0x00, 0x60, 0xf0, 0xaa},
-	{0x00, 0x61, 0xf0, 0xaa},	{0x00, 0x27, 0xa0, 0xaa},
-	{0x00, 0x28, 0x80, 0xaa},	{0x00, 0x2c, 0x90, 0xaa},
-	{0x00, 0x4f, 0x66, 0xaa},	{0x00, 0x50, 0x66, 0xaa},
-	{0x00, 0x51, 0x00, 0xaa},	{0x00, 0x52, 0x22, 0xaa},
-	{0x00, 0x53, 0x5e, 0xaa},	{0x00, 0x54, 0x80, 0xaa},
-	{0x00, 0x58, 0x9e, 0xaa},	{0x00, 0x41, 0x08, 0xaa},
-	{0x00, 0x3f, 0x00, 0xaa},	{0x00, 0x75, 0x85, 0xaa},
-	{0x00, 0x76, 0xe1, 0xaa},	{0x00, 0x4c, 0x00, 0xaa},
-	{0x00, 0x77, 0x0a, 0xaa},	{0x00, 0x3d, 0x88, 0xaa},
-	{0x00, 0x4b, 0x09, 0xaa},	{0x00, 0xc9, 0x60, 0xaa},
-	{0x00, 0x41, 0x38, 0xaa},	{0x00, 0x62, 0x30, 0xaa},
-	{0x00, 0x63, 0x30, 0xaa},	{0x00, 0x64, 0x08, 0xaa},
-	{0x00, 0x94, 0x07, 0xaa},	{0x00, 0x95, 0x0b, 0xaa},
-	{0x00, 0x65, 0x00, 0xaa},	{0x00, 0x66, 0x05, 0xaa},
-	{0x00, 0x56, 0x50, 0xaa},	{0x00, 0x34, 0x11, 0xaa},
-	{0x00, 0xa4, 0x88, 0xaa},	{0x00, 0x96, 0x00, 0xaa},
-	{0x00, 0x97, 0x30, 0xaa},	{0x00, 0x98, 0x20, 0xaa},
-	{0x00, 0x99, 0x30, 0xaa},	{0x00, 0x9a, 0x84, 0xaa},
-	{0x00, 0x9b, 0x29, 0xaa},	{0x00, 0x9c, 0x03, 0xaa},
-	{0x00, 0x78, 0x04, 0xaa},	{0x00, 0x79, 0x01, 0xaa},
-	{0x00, 0xc8, 0xf0, 0xaa},	{0x00, 0x79, 0x0f, 0xaa},
-	{0x00, 0xc8, 0x00, 0xaa},	{0x00, 0x79, 0x10, 0xaa},
-	{0x00, 0xc8, 0x7e, 0xaa},	{0x00, 0x79, 0x0a, 0xaa},
-	{0x00, 0xc8, 0x80, 0xaa},	{0x00, 0x79, 0x0b, 0xaa},
-	{0x00, 0xc8, 0x01, 0xaa},	{0x00, 0x79, 0x0c, 0xaa},
-	{0x00, 0xc8, 0x0f, 0xaa},	{0x00, 0x79, 0x0d, 0xaa},
-	{0x00, 0xc8, 0x20, 0xaa},	{0x00, 0x79, 0x09, 0xaa},
-	{0x00, 0xc8, 0x80, 0xaa},	{0x00, 0x79, 0x02, 0xaa},
-	{0x00, 0xc8, 0xc0, 0xaa},	{0x00, 0x79, 0x03, 0xaa},
-	{0x00, 0xc8, 0x40, 0xaa},	{0x00, 0x79, 0x05, 0xaa},
-	{0x00, 0xc8, 0x30, 0xaa},	{0x00, 0x79, 0x26, 0xaa},
-	{0x00, 0x11, 0x40, 0xaa},	{0x00, 0x3a, 0x04, 0xaa},
-	{0x00, 0x12, 0x00, 0xaa},	{0x00, 0x40, 0xc0, 0xaa},
-	{0x00, 0x8c, 0x00, 0xaa},	{0x00, 0x17, 0x14, 0xaa},
-	{0x00, 0x18, 0x02, 0xaa},	{0x00, 0x32, 0x92, 0xaa},
-	{0x00, 0x19, 0x02, 0xaa},	{0x00, 0x1a, 0x7a, 0xaa},
-	{0x00, 0x03, 0x0a, 0xaa},	{0x00, 0x0c, 0x00, 0xaa},
-	{0x00, 0x3e, 0x00, 0xaa},	{0x00, 0x70, 0x3a, 0xaa},
-	{0x00, 0x71, 0x35, 0xaa},	{0x00, 0x72, 0x11, 0xaa},
-	{0x00, 0x73, 0xf0, 0xaa},	{0x00, 0xa2, 0x02, 0xaa},
-	{0x00, 0xb1, 0x00, 0xaa},	{0x00, 0xb1, 0x0c, 0xaa},
+	{0x00, 0x22, 0x91, 0xaa},
+	{0x00, 0x29, 0x07, 0xaa},
+	{0x00, 0x33, 0x0b, 0xaa},
+	{0x00, 0x35, 0x0b, 0xaa},
+	{0x00, 0x37, 0x1d, 0xaa},
+	{0x00, 0x38, 0x71, 0xaa},
+	{0x00, 0x39, 0x2a, 0xaa},
+	{0x00, 0x3c, 0x78, 0xaa},
+	{0x00, 0x4d, 0x40, 0xaa},
+	{0x00, 0x4e, 0x20, 0xaa},
+	{0x00, 0x74, 0x19, 0xaa},
+	{0x00, 0x8d, 0x4f, 0xaa},
+	{0x00, 0x8e, 0x00, 0xaa},
+	{0x00, 0x8f, 0x00, 0xaa},
+	{0x00, 0x90, 0x00, 0xaa},
+	{0x00, 0x91, 0x00, 0xaa},
+	{0x00, 0x96, 0x00, 0xaa},
+	{0x00, 0x9a, 0x80, 0xaa},
+	{0x00, 0xb0, 0x84, 0xaa},
+	{0x00, 0xb1, 0x0c, 0xaa},
+	{0x00, 0xb2, 0x0e, 0xaa},
+	{0x00, 0xb3, 0x82, 0xaa},
+	{0x00, 0xb8, 0x0a, 0xaa},
+	{0x00, 0x43, 0x14, 0xaa},
+	{0x00, 0x44, 0xf0, 0xaa},
+	{0x00, 0x45, 0x45, 0xaa},
+	{0x00, 0x46, 0x63, 0xaa},
+	{0x00, 0x47, 0x2d, 0xaa},
+	{0x00, 0x48, 0x46, 0xaa},
+	{0x00, 0x59, 0x88, 0xaa},
+	{0x00, 0x5a, 0xa0, 0xaa},
+	{0x00, 0x5b, 0xc6, 0xaa},
+	{0x00, 0x5c, 0x7d, 0xaa},
+	{0x00, 0x5d, 0x5f, 0xaa},
+	{0x00, 0x5e, 0x19, 0xaa},
+	{0x00, 0x6c, 0x0a, 0xaa},
+	{0x00, 0x6d, 0x55, 0xaa},
+	{0x00, 0x6e, 0x11, 0xaa},
+	{0x00, 0x6f, 0x9e, 0xaa},
+	{0x00, 0x69, 0x00, 0xaa},
+	{0x00, 0x6a, 0x40, 0xaa},
+	{0x00, 0x01, 0x40, 0xaa},
+	{0x00, 0x02, 0x40, 0xaa},
+	{0x00, 0x13, 0xe7, 0xaa},
+	{0x00, 0x5f, 0xf0, 0xaa},
+	{0x00, 0x60, 0xf0, 0xaa},
+	{0x00, 0x61, 0xf0, 0xaa},
+	{0x00, 0x27, 0xa0, 0xaa},
+	{0x00, 0x28, 0x80, 0xaa},
+	{0x00, 0x2c, 0x90, 0xaa},
+	{0x00, 0x4f, 0x66, 0xaa},
+	{0x00, 0x50, 0x66, 0xaa},
+	{0x00, 0x51, 0x00, 0xaa},
+	{0x00, 0x52, 0x22, 0xaa},
+	{0x00, 0x53, 0x5e, 0xaa},
+	{0x00, 0x54, 0x80, 0xaa},
+	{0x00, 0x58, 0x9e, 0xaa},
+	{0x00, 0x41, 0x08, 0xaa},
+	{0x00, 0x3f, 0x00, 0xaa},
+	{0x00, 0x75, 0x85, 0xaa},
+	{0x00, 0x76, 0xe1, 0xaa},
+	{0x00, 0x4c, 0x00, 0xaa},
+	{0x00, 0x77, 0x0a, 0xaa},
+	{0x00, 0x3d, 0x88, 0xaa},
+	{0x00, 0x4b, 0x09, 0xaa},
+	{0x00, 0xc9, 0x60, 0xaa},
+	{0x00, 0x41, 0x38, 0xaa},
+	{0x00, 0x62, 0x30, 0xaa},
+	{0x00, 0x63, 0x30, 0xaa},
+	{0x00, 0x64, 0x08, 0xaa},
+	{0x00, 0x94, 0x07, 0xaa},
+	{0x00, 0x95, 0x0b, 0xaa},
+	{0x00, 0x65, 0x00, 0xaa},
+	{0x00, 0x66, 0x05, 0xaa},
+	{0x00, 0x56, 0x50, 0xaa},
+	{0x00, 0x34, 0x11, 0xaa},
+	{0x00, 0xa4, 0x88, 0xaa},
+	{0x00, 0x96, 0x00, 0xaa},
+	{0x00, 0x97, 0x30, 0xaa},
+	{0x00, 0x98, 0x20, 0xaa},
+	{0x00, 0x99, 0x30, 0xaa},
+	{0x00, 0x9a, 0x84, 0xaa},
+	{0x00, 0x9b, 0x29, 0xaa},
+	{0x00, 0x9c, 0x03, 0xaa},
+	{0x00, 0x78, 0x04, 0xaa},
+	{0x00, 0x79, 0x01, 0xaa},
+	{0x00, 0xc8, 0xf0, 0xaa},
+	{0x00, 0x79, 0x0f, 0xaa},
+	{0x00, 0xc8, 0x00, 0xaa},
+	{0x00, 0x79, 0x10, 0xaa},
+	{0x00, 0xc8, 0x7e, 0xaa},
+	{0x00, 0x79, 0x0a, 0xaa},
+	{0x00, 0xc8, 0x80, 0xaa},
+	{0x00, 0x79, 0x0b, 0xaa},
+	{0x00, 0xc8, 0x01, 0xaa},
+	{0x00, 0x79, 0x0c, 0xaa},
+	{0x00, 0xc8, 0x0f, 0xaa},
+	{0x00, 0x79, 0x0d, 0xaa},
+	{0x00, 0xc8, 0x20, 0xaa},
+	{0x00, 0x79, 0x09, 0xaa},
+	{0x00, 0xc8, 0x80, 0xaa},
+	{0x00, 0x79, 0x02, 0xaa},
+	{0x00, 0xc8, 0xc0, 0xaa},
+	{0x00, 0x79, 0x03, 0xaa},
+	{0x00, 0xc8, 0x40, 0xaa},
+	{0x00, 0x79, 0x05, 0xaa},
+	{0x00, 0xc8, 0x30, 0xaa},
+	{0x00, 0x79, 0x26, 0xaa},
+	{0x00, 0x11, 0x40, 0xaa},
+	{0x00, 0x3a, 0x04, 0xaa},
+	{0x00, 0x12, 0x00, 0xaa},
+	{0x00, 0x40, 0xc0, 0xaa},
+	{0x00, 0x8c, 0x00, 0xaa},
+	{0x00, 0x17, 0x14, 0xaa},
+	{0x00, 0x18, 0x02, 0xaa},
+	{0x00, 0x32, 0x92, 0xaa},
+	{0x00, 0x19, 0x02, 0xaa},
+	{0x00, 0x1a, 0x7a, 0xaa},
+	{0x00, 0x03, 0x0a, 0xaa},
+	{0x00, 0x0c, 0x00, 0xaa},
+	{0x00, 0x3e, 0x00, 0xaa},
+	{0x00, 0x70, 0x3a, 0xaa},
+	{0x00, 0x71, 0x35, 0xaa},
+	{0x00, 0x72, 0x11, 0xaa},
+	{0x00, 0x73, 0xf0, 0xaa},
+	{0x00, 0xa2, 0x02, 0xaa},
+	{0x00, 0xb1, 0x00, 0xaa},
+	{0x00, 0xb1, 0x0c, 0xaa},
 	{0x00, 0x1e, 0x37, 0xaa},	/* MVFP */
 	{0x00, 0xaa, 0x14, 0xaa},
-	{0x00, 0x24, 0x80, 0xaa},	{0x00, 0x25, 0x74, 0xaa},
-	{0x00, 0x26, 0xd3, 0xaa},	{0x00, 0x0d, 0x00, 0xaa},
-	{0x00, 0x14, 0x18, 0xaa},	{0x00, 0x9d, 0x99, 0xaa},
-	{0x00, 0x9e, 0x7f, 0xaa},	{0x00, 0x64, 0x08, 0xaa},
-	{0x00, 0x94, 0x07, 0xaa},	{0x00, 0x95, 0x06, 0xaa},
-	{0x00, 0x66, 0x05, 0xaa},	{0x00, 0x41, 0x08, 0xaa},
-	{0x00, 0x3f, 0x00, 0xaa},	{0x00, 0x75, 0x07, 0xaa},
-	{0x00, 0x76, 0xe1, 0xaa},	{0x00, 0x4c, 0x00, 0xaa},
-	{0x00, 0x77, 0x00, 0xaa},	{0x00, 0x3d, 0xc2, 0xaa},
-	{0x00, 0x4b, 0x09, 0xaa},	{0x00, 0xc9, 0x60, 0xaa},
-	{0x00, 0x41, 0x38, 0xaa},	{0xb6, 0x00, 0x00, 0xcc},
-	{0xb6, 0x03, 0x01, 0xcc},	{0xb6, 0x02, 0x40, 0xcc},
-	{0xb6, 0x05, 0x00, 0xcc},	{0xb6, 0x04, 0xf0, 0xcc},
-	{0xb6, 0x12, 0xf8, 0xcc},	{0xb6, 0x13, 0x21, 0xcc},
-	{0xb6, 0x18, 0x00, 0xcc},	{0xb6, 0x17, 0x96, 0xcc},
-	{0xb6, 0x16, 0x00, 0xcc},	{0xb6, 0x22, 0x12, 0xcc},
-	{0xb6, 0x23, 0x0b, 0xcc},	{0xbf, 0xc0, 0x39, 0xcc},
-	{0xbf, 0xc1, 0x04, 0xcc},	{0xbf, 0xcc, 0x00, 0xcc},
-	{0xbc, 0x02, 0x18, 0xcc},	{0xbc, 0x03, 0x50, 0xcc},
-	{0xbc, 0x04, 0x18, 0xcc},	{0xbc, 0x05, 0x00, 0xcc},
-	{0xbc, 0x06, 0x00, 0xcc},	{0xbc, 0x08, 0x30, 0xcc},
-	{0xbc, 0x09, 0x40, 0xcc},	{0xbc, 0x0a, 0x10, 0xcc},
-	{0xbc, 0x0b, 0x00, 0xcc},	{0xbc, 0x0c, 0x00, 0xcc},
-	{0xb3, 0x5c, 0x01, 0xcc},	{0xb3, 0x01, 0x45, 0xcc},
-	{0x00, 0x77, 0x05, 0xaa },
+	{0x00, 0x24, 0x80, 0xaa},
+	{0x00, 0x25, 0x74, 0xaa},
+	{0x00, 0x26, 0xd3, 0xaa},
+	{0x00, 0x0d, 0x00, 0xaa},
+	{0x00, 0x14, 0x18, 0xaa},
+	{0x00, 0x9d, 0x99, 0xaa},
+	{0x00, 0x9e, 0x7f, 0xaa},
+	{0x00, 0x64, 0x08, 0xaa},
+	{0x00, 0x94, 0x07, 0xaa},
+	{0x00, 0x95, 0x06, 0xaa},
+	{0x00, 0x66, 0x05, 0xaa},
+	{0x00, 0x41, 0x08, 0xaa},
+	{0x00, 0x3f, 0x00, 0xaa},
+	{0x00, 0x75, 0x07, 0xaa},
+	{0x00, 0x76, 0xe1, 0xaa},
+	{0x00, 0x4c, 0x00, 0xaa},
+	{0x00, 0x77, 0x00, 0xaa},
+	{0x00, 0x3d, 0xc2, 0xaa},
+	{0x00, 0x4b, 0x09, 0xaa},
+	{0x00, 0xc9, 0x60, 0xaa},
+	{0x00, 0x41, 0x38, 0xaa},
+	{0xbc, 0x02, 0x18, 0xcc},
+	{0xbc, 0x03, 0x50, 0xcc},
+	{0xbc, 0x04, 0x18, 0xcc},
+	{0xbc, 0x05, 0x00, 0xcc},
+	{0xbc, 0x06, 0x00, 0xcc},
+	{0xbc, 0x08, 0x30, 0xcc},
+	{0xbc, 0x09, 0x40, 0xcc},
+	{0xbc, 0x0a, 0x10, 0xcc},
+	{0xbc, 0x0b, 0x00, 0xcc},
+	{0xbc, 0x0c, 0x00, 0xcc},
+	{0xbf, 0xc0, 0x26, 0xcc},
+	{0xbf, 0xc1, 0x02, 0xcc},
+	{0xbf, 0xcc, 0x04, 0xcc},
+	{0xb3, 0x5c, 0x01, 0xcc},
+	{0xb3, 0x01, 0x45, 0xcc},
+	{0x00, 0x77, 0x05, 0xaa},
 	{},
 };
 
@@ -3117,6 +3338,10 @@
 			cam->cam_mode = bi_mode;
 			cam->nmodes = ARRAY_SIZE(bi_mode);
 			break;
+		case SENSOR_OV7670:
+			cam->cam_mode = bi_mode;
+			cam->nmodes = ARRAY_SIZE(bi_mode) - 1;
+			break;
 		default:
 			cam->cam_mode = vc0323_mode;
 			cam->nmodes = ARRAY_SIZE(vc0323_mode) - 1;
@@ -3329,14 +3554,6 @@
 		else
 			init = ov7660_initVGA_data;	/* 640x480 */
 		break;
-	case SENSOR_OV7670:
-		/*GammaT = ov7660_gamma; */
-		/*MatrixT = ov7660_matrix; */
-		if (mode)
-			init = ov7670_initQVGA_JPG;	/* 320x240 */
-		else
-			init = ov7670_initVGA_JPG;	/* 640x480 */
-		break;
 	case SENSOR_MI0360:
 		GammaT = mi1320_gamma;
 		MatrixT = mi0360_matrix;
@@ -3373,6 +3590,9 @@
 		MatrixT = mi1320_matrix;
 		init = mi1320_soc_init[mode];
 		break;
+	case SENSOR_OV7670:
+		init = mode == 1 ? ov7670_InitVGA : ov7670_InitQVGA;
+		break;
 	case SENSOR_PO3130NC:
 		GammaT = po3130_gamma;
 		MatrixT = po3130_matrix;
@@ -3426,7 +3646,13 @@
 		sethvflip(gspca_dev);
 		setlightfreq(gspca_dev);
 	}
-	if (sd->sensor == SENSOR_POxxxx) {
+	switch (sd->sensor) {
+	case SENSOR_OV7670:
+		reg_w(gspca_dev->dev, 0x87, 0xffff, 0xffff);
+		reg_w(gspca_dev->dev, 0x88, 0xff00, 0xf0f1);
+		reg_w(gspca_dev->dev, 0xa0, 0x0000, 0xbfff);
+		break;
+	case SENSOR_POxxxx:
 		setcolors(gspca_dev);
 		setbrightness(gspca_dev);
 		setcontrast(gspca_dev);
@@ -3435,6 +3661,7 @@
 		msleep(80);
 		reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
 		usb_exchange(gspca_dev, poxxxx_init_end_2);
+		break;
 	}
 	return 0;
 }
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index 7d7814c..d02aa5c 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -40,7 +40,6 @@
 struct sd {
 	struct gspca_dev gspca_dev;	/* !! must be the first item */
 
-	u8 brightness;
 	u8 contrast;
 	u8 gamma;
 	u8 autogain;
@@ -80,8 +79,6 @@
 };
 
 /* V4L2 controls supported by the driver */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
@@ -94,21 +91,6 @@
 static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
 
 static const struct ctrl sd_ctrls[] = {
-#define BRIGHTNESS_IDX 0
-	{
-	    {
-		.id      = V4L2_CID_BRIGHTNESS,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Brightness",
-		.minimum = 0,
-		.maximum = 255,
-		.step    = 1,
-#define BRIGHTNESS_DEF 128
-		.default_value = BRIGHTNESS_DEF,
-	    },
-	    .set = sd_setbrightness,
-	    .get = sd_getbrightness,
-	},
 	{
 	    {
 		.id      = V4L2_CID_CONTRAST,
@@ -150,7 +132,7 @@
 	    .set = sd_setautogain,
 	    .get = sd_getautogain,
 	},
-#define LIGHTFREQ_IDX 4
+#define LIGHTFREQ_IDX 3
 	{
 	    {
 		.id	 = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -6004,33 +5986,6 @@
 		reg_w(gspca_dev->dev, matrix[i], 0x010a + i);
 }
 
-static void setbrightness(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	u8 brightness;
-
-	switch (sd->sensor) {
-	case SENSOR_GC0305:
-	case SENSOR_OV7620:
-	case SENSOR_PAS202B:
-	case SENSOR_PO2030:
-		return;
-	}
-/*fixme: is it really write to 011d and 018d for all other sensors? */
-	brightness = sd->brightness;
-	reg_w(gspca_dev->dev, brightness, 0x011d);
-	switch (sd->sensor) {
-	case SENSOR_ADCM2700:
-	case SENSOR_HV7131B:
-		return;
-	}
-	if (brightness < 0x70)
-		brightness += 0x10;
-	else
-		brightness = 0x80;
-	reg_w(gspca_dev->dev, brightness, 0x018d);
-}
-
 static void setsharpness(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -6059,8 +6014,8 @@
 	int g, i, k, adj, gp;
 	u8 gr[16];
 	static const u8 delta_tb[16] =		/* delta for contrast */
-		{0x15, 0x0d, 0x0a, 0x09, 0x08, 0x08, 0x08, 0x08,
-		 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
+		{0x2c, 0x1a, 0x12, 0x0c, 0x0a, 0x06, 0x06, 0x06,
+		 0x04, 0x06, 0x04, 0x04, 0x03, 0x03, 0x02, 0x02};
 	static const u8 gamma_tb[6][16] = {
 		{0x00, 0x00, 0x03, 0x0d, 0x1b, 0x2e, 0x45, 0x5f,
 		 0x79, 0x93, 0xab, 0xc1, 0xd4, 0xe5, 0xf3, 0xff},
@@ -6082,11 +6037,11 @@
 	adj = 0;
 	gp = 0;
 	for (i = 0; i < 16; i++) {
-		g = Tgamma[i] - delta_tb[i] * k / 128 - adj / 2;
+		g = Tgamma[i] - delta_tb[i] * k / 256 - adj / 2;
 		if (g > 0xff)
 			g = 0xff;
-		else if (g <= 0)
-			g = 1;
+		else if (g < 0)
+			g = 0;
 		reg_w(dev, g, 0x0120 + i);	/* gamma */
 		if (k > 0)
 			adj--;
@@ -6203,13 +6158,13 @@
 		 pas106b_50HZ, pas106b_50HZ,
 		 pas106b_60HZ, pas106b_60HZ},
 /* SENSOR_PAS202B 13 */
-		{pas202b_NoFlikerScale, pas202b_NoFliker,
-		 pas202b_50HZScale, pas202b_50HZ,
-		 pas202b_60HZScale, pas202b_60HZ},
+		{pas202b_NoFliker, pas202b_NoFlikerScale,
+		 pas202b_50HZ, pas202b_50HZScale,
+		 pas202b_60HZ, pas202b_60HZScale},
 /* SENSOR_PB0330 14 */
-		{pb0330_NoFlikerScale, pb0330_NoFliker,
-		 pb0330_50HZScale, pb0330_50HZ,
-		 pb0330_60HZScale, pb0330_60HZ},
+		{pb0330_NoFliker, pb0330_NoFlikerScale,
+		 pb0330_50HZ, pb0330_50HZScale,
+		 pb0330_60HZ, pb0330_60HZScale},
 /* SENSOR_PO2030 15 */
 		{po2030_NoFliker, po2030_NoFliker,
 		 po2030_50HZ, po2030_50HZ,
@@ -6789,7 +6744,6 @@
 		cam->nmodes = ARRAY_SIZE(broken_vga_mode);
 		break;
 	}
-	sd->brightness = BRIGHTNESS_DEF;
 	sd->contrast = CONTRAST_DEF;
 	sd->gamma = gamma[sd->sensor];
 	sd->autogain = AUTOGAIN_DEF;
@@ -6797,12 +6751,6 @@
 	sd->quality = QUALITY_DEF;
 
 	switch (sd->sensor) {
-	case SENSOR_GC0305:
-	case SENSOR_OV7620:
-	case SENSOR_PAS202B:
-	case SENSOR_PO2030:
-		gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX);
-		break;
 	case SENSOR_HV7131B:
 	case SENSOR_HV7131C:
 	case SENSOR_OV7630C:
@@ -6893,7 +6841,6 @@
 	}
 
 	setmatrix(gspca_dev);
-	setbrightness(gspca_dev);
 	switch (sd->sensor) {
 	case SENSOR_ADCM2700:
 	case SENSOR_OV7620:
@@ -7015,24 +6962,6 @@
 	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->brightness = val;
-	if (gspca_dev->streaming)
-		setbrightness(gspca_dev);
-	return 0;
-}
-
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->brightness;
-	return 0;
-}
-
 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c
index 2fc9865..830d47b 100644
--- a/drivers/media/video/hdpvr/hdpvr-core.c
+++ b/drivers/media/video/hdpvr/hdpvr-core.c
@@ -373,9 +373,6 @@
 	}
 #endif /* CONFIG_I2C */
 
-	/* save our data pointer in this interface device */
-	usb_set_intfdata(interface, dev);
-
 	/* let the user know what node this device is now attached to */
 	v4l2_info(&dev->v4l2_dev, "device now attached to %s\n",
 		  video_device_node_name(dev->video_dev));
@@ -391,44 +388,24 @@
 
 static void hdpvr_disconnect(struct usb_interface *interface)
 {
-	struct hdpvr_device *dev;
+	struct hdpvr_device *dev = to_hdpvr_dev(usb_get_intfdata(interface));
 
-	dev = usb_get_intfdata(interface);
-	usb_set_intfdata(interface, NULL);
-
+	v4l2_info(&dev->v4l2_dev, "device %s disconnected\n",
+		  video_device_node_name(dev->video_dev));
 	/* prevent more I/O from starting and stop any ongoing */
 	mutex_lock(&dev->io_mutex);
 	dev->status = STATUS_DISCONNECTED;
-	v4l2_device_disconnect(&dev->v4l2_dev);
-	video_unregister_device(dev->video_dev);
 	wake_up_interruptible(&dev->wait_data);
 	wake_up_interruptible(&dev->wait_buffer);
 	mutex_unlock(&dev->io_mutex);
+	v4l2_device_disconnect(&dev->v4l2_dev);
 	msleep(100);
 	flush_workqueue(dev->workqueue);
 	mutex_lock(&dev->io_mutex);
 	hdpvr_cancel_queue(dev);
-	destroy_workqueue(dev->workqueue);
 	mutex_unlock(&dev->io_mutex);
-
-	/* deregister I2C adapter */
-#ifdef CONFIG_I2C
-	mutex_lock(&dev->i2c_mutex);
-	if (dev->i2c_adapter)
-		i2c_del_adapter(dev->i2c_adapter);
-	kfree(dev->i2c_adapter);
-	dev->i2c_adapter = NULL;
-	mutex_unlock(&dev->i2c_mutex);
-#endif /* CONFIG_I2C */
-
+	video_unregister_device(dev->video_dev);
 	atomic_dec(&dev_nr);
-
-	v4l2_info(&dev->v4l2_dev, "device %s disconnected\n",
-		  video_device_node_name(dev->video_dev));
-
-	v4l2_device_unregister(&dev->v4l2_dev);
-	kfree(dev->usbc_buf);
-	kfree(dev);
 }
 
 
diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c
index 196f82d..d2f0ee2 100644
--- a/drivers/media/video/hdpvr/hdpvr-video.c
+++ b/drivers/media/video/hdpvr/hdpvr-video.c
@@ -1214,6 +1214,24 @@
 	struct hdpvr_device *dev = video_get_drvdata(vdev);
 
 	hdpvr_delete(dev);
+	mutex_lock(&dev->io_mutex);
+	destroy_workqueue(dev->workqueue);
+	mutex_unlock(&dev->io_mutex);
+
+	v4l2_device_unregister(&dev->v4l2_dev);
+
+	/* deregister I2C adapter */
+#ifdef CONFIG_I2C
+	mutex_lock(&dev->i2c_mutex);
+	if (dev->i2c_adapter)
+		i2c_del_adapter(dev->i2c_adapter);
+	kfree(dev->i2c_adapter);
+	dev->i2c_adapter = NULL;
+	mutex_unlock(&dev->i2c_mutex);
+#endif /* CONFIG_I2C */
+
+	kfree(dev->usbc_buf);
+	kfree(dev);
 }
 
 static const struct video_device hdpvr_video_template = {
diff --git a/drivers/media/video/hdpvr/hdpvr.h b/drivers/media/video/hdpvr/hdpvr.h
index 49ae25d..b0f046d 100644
--- a/drivers/media/video/hdpvr/hdpvr.h
+++ b/drivers/media/video/hdpvr/hdpvr.h
@@ -111,6 +111,11 @@
 	u8			*usbc_buf;
 };
 
+static inline struct hdpvr_device *to_hdpvr_dev(struct v4l2_device *v4l2_dev)
+{
+	return container_of(v4l2_dev, struct hdpvr_device, v4l2_dev);
+}
+
 
 /* buffer one bulk urb of data */
 struct hdpvr_buffer {
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index da18d69..29d4397 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -61,9 +61,9 @@
 MODULE_PARM_DESC(hauppauge, "Specify Hauppauge remote: 0=black, 1=grey (defaults to 0)");
 
 
-#define DEVNAME "ir-kbd-i2c"
+#define MODULE_NAME "ir-kbd-i2c"
 #define dprintk(level, fmt, arg...)	if (debug >= level) \
-	printk(KERN_DEBUG DEVNAME ": " fmt , ## arg)
+	printk(KERN_DEBUG MODULE_NAME ": " fmt , ## arg)
 
 /* ----------------------------------------------------------------------- */
 
@@ -297,7 +297,7 @@
 
 static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
-	struct ir_scancode_table *ir_codes = NULL;
+	char *ir_codes = NULL;
 	const char *name = NULL;
 	u64 ir_type = 0;
 	struct IR_i2c *ir;
@@ -322,13 +322,13 @@
 		name        = "Pixelview";
 		ir->get_key = get_key_pixelview;
 		ir_type     = IR_TYPE_OTHER;
-		ir_codes    = &ir_codes_empty_table;
+		ir_codes    = RC_MAP_EMPTY;
 		break;
 	case 0x4b:
 		name        = "PV951";
 		ir->get_key = get_key_pv951;
 		ir_type     = IR_TYPE_OTHER;
-		ir_codes    = &ir_codes_pv951_table;
+		ir_codes    = RC_MAP_PV951;
 		break;
 	case 0x18:
 	case 0x1f:
@@ -337,22 +337,22 @@
 		ir->get_key = get_key_haup;
 		ir_type     = IR_TYPE_RC5;
 		if (hauppauge == 1) {
-			ir_codes    = &ir_codes_hauppauge_new_table;
+			ir_codes    = RC_MAP_HAUPPAUGE_NEW;
 		} else {
-			ir_codes    = &ir_codes_rc5_tv_table;
+			ir_codes    = RC_MAP_RC5_TV;
 		}
 		break;
 	case 0x30:
 		name        = "KNC One";
 		ir->get_key = get_key_knc1;
 		ir_type     = IR_TYPE_OTHER;
-		ir_codes    = &ir_codes_empty_table;
+		ir_codes    = RC_MAP_EMPTY;
 		break;
 	case 0x6b:
 		name        = "FusionHDTV";
 		ir->get_key = get_key_fusionhdtv;
 		ir_type     = IR_TYPE_RC5;
-		ir_codes    = &ir_codes_fusionhdtv_mce_table;
+		ir_codes    = RC_MAP_FUSIONHDTV_MCE;
 		break;
 	case 0x0b:
 	case 0x47:
@@ -365,9 +365,9 @@
 			ir_type     = IR_TYPE_RC5;
 			ir->get_key = get_key_haup_xvr;
 			if (hauppauge == 1) {
-				ir_codes    = &ir_codes_hauppauge_new_table;
+				ir_codes    = RC_MAP_HAUPPAUGE_NEW;
 			} else {
-				ir_codes    = &ir_codes_rc5_tv_table;
+				ir_codes    = RC_MAP_RC5_TV;
 			}
 		} else {
 			/* Handled by saa7134-input */
@@ -379,7 +379,7 @@
 		name        = "AVerMedia Cardbus remote";
 		ir->get_key = get_key_avermedia_cardbus;
 		ir_type     = IR_TYPE_OTHER;
-		ir_codes    = &ir_codes_avermedia_cardbus_table;
+		ir_codes    = RC_MAP_AVERMEDIA_CARDBUS;
 		break;
 	}
 
@@ -447,11 +447,11 @@
 	input_dev->name       = ir->name;
 	input_dev->phys       = ir->phys;
 
-	err = ir_input_register(ir->input, ir->ir_codes, NULL);
+	err = ir_input_register(ir->input, ir->ir_codes, NULL, MODULE_NAME);
 	if (err)
 		goto err_out_free;
 
-	printk(DEVNAME ": %s detected at %s [%s]\n",
+	printk(MODULE_NAME ": %s detected at %s [%s]\n",
 	       ir->input->name, ir->input->phys, adap->name);
 
 	/* start polling via eventd */
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 9a25054..1b79475 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -1293,7 +1293,6 @@
 		ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
 		ivtv_init_mpeg_decoder(itv);
 	}
-	ivtv_s_std(NULL, &fh, &itv->tuner_std);
 
 	/* On a cx23416 this seems to be able to enable DMA to the chip? */
 	if (!itv->has_cx23415)
@@ -1310,6 +1309,10 @@
 	}
 	else
 		ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT);
+
+	/* For cards with video out, this call needs interrupts enabled */
+	ivtv_s_std(NULL, &fh, &itv->tuner_std);
+
 	return 0;
 }
 
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 5028e31..5b45fd2 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -63,6 +63,7 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
 #include <media/tuner.h>
 #include <media/cx2341x.h>
 #include <media/ir-kbd-i2c.h>
@@ -116,6 +117,9 @@
 #define IVTV_REG_VPU 			(0x9058)
 #define IVTV_REG_APU 			(0xA064)
 
+/* Other registers */
+#define IVTV_REG_DEC_LINE_FIELD		(0x28C0)
+
 /* debugging */
 extern int ivtv_debug;
 
@@ -372,6 +376,7 @@
 };
 
 struct ivtv_open_id {
+	struct v4l2_fh fh;
 	u32 open_id;                    /* unique ID for this file descriptor */
 	int type;                       /* stream type */
 	int yuv_frames;                 /* 1: started OUT_UDMA_YUV output mode */
@@ -379,6 +384,11 @@
 	struct ivtv *itv;
 };
 
+static inline struct ivtv_open_id *fh2id(struct v4l2_fh *fh)
+{
+	return container_of(fh, struct ivtv_open_id, fh);
+}
+
 struct yuv_frame_info
 {
 	u32 update;
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index babcabd..abf4109 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -32,6 +32,7 @@
 #include "ivtv-yuv.h"
 #include "ivtv-ioctl.h"
 #include "ivtv-cards.h"
+#include <media/v4l2-event.h>
 #include <media/saa7115.h>
 
 /* This function tries to claim the stream for a specific file descriptor.
@@ -506,7 +507,7 @@
 
 ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_t * pos)
 {
-	struct ivtv_open_id *id = filp->private_data;
+	struct ivtv_open_id *id = fh2id(filp->private_data);
 	struct ivtv *itv = id->itv;
 	struct ivtv_stream *s = &itv->streams[id->type];
 	int rc;
@@ -541,7 +542,7 @@
 
 ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos)
 {
-	struct ivtv_open_id *id = filp->private_data;
+	struct ivtv_open_id *id = fh2id(filp->private_data);
 	struct ivtv *itv = id->itv;
 	struct ivtv_stream *s = &itv->streams[id->type];
 	struct yuv_playback_info *yi = &itv->yuv_info;
@@ -711,19 +712,31 @@
 
 unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait)
 {
-	struct ivtv_open_id *id = filp->private_data;
+	struct ivtv_open_id *id = fh2id(filp->private_data);
 	struct ivtv *itv = id->itv;
 	struct ivtv_stream *s = &itv->streams[id->type];
 	int res = 0;
 
 	/* add stream's waitq to the poll list */
 	IVTV_DEBUG_HI_FILE("Decoder poll\n");
-	poll_wait(filp, &s->waitq, wait);
 
-	set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags);
-	if (test_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags) ||
-	    test_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags))
-		res = POLLPRI;
+	/* If there are subscribed events, then only use the new event
+	   API instead of the old video.h based API. */
+	if (!list_empty(&id->fh.events->subscribed)) {
+		poll_wait(filp, &id->fh.events->wait, wait);
+		/* Turn off the old-style vsync events */
+		clear_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags);
+		if (v4l2_event_pending(&id->fh))
+			res = POLLPRI;
+	} else {
+		/* This is the old-style API which is here only for backwards
+		   compatibility. */
+		poll_wait(filp, &s->waitq, wait);
+		set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags);
+		if (test_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags) ||
+		    test_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags))
+			res = POLLPRI;
+	}
 
 	/* Allow write if buffers are available for writing */
 	if (s->q_free.buffers)
@@ -733,7 +746,7 @@
 
 unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait)
 {
-	struct ivtv_open_id *id = filp->private_data;
+	struct ivtv_open_id *id = fh2id(filp->private_data);
 	struct ivtv *itv = id->itv;
 	struct ivtv_stream *s = &itv->streams[id->type];
 	int eof = test_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
@@ -833,13 +846,16 @@
 
 int ivtv_v4l2_close(struct file *filp)
 {
-	struct ivtv_open_id *id = filp->private_data;
+	struct v4l2_fh *fh = filp->private_data;
+	struct ivtv_open_id *id = fh2id(fh);
 	struct ivtv *itv = id->itv;
 	struct ivtv_stream *s = &itv->streams[id->type];
 
 	IVTV_DEBUG_FILE("close %s\n", s->name);
 
-	v4l2_prio_close(&itv->prio, &id->prio);
+	v4l2_prio_close(&itv->prio, id->prio);
+	v4l2_fh_del(fh);
+	v4l2_fh_exit(fh);
 
 	/* Easy case first: this stream was never claimed by us */
 	if (s->id != id->open_id) {
@@ -895,6 +911,7 @@
 {
 	struct ivtv *itv = s->itv;
 	struct ivtv_open_id *item;
+	int res = 0;
 
 	IVTV_DEBUG_FILE("open %s\n", s->name);
 
@@ -915,17 +932,27 @@
 	}
 
 	/* Allocate memory */
-	item = kmalloc(sizeof(struct ivtv_open_id), GFP_KERNEL);
+	item = kzalloc(sizeof(struct ivtv_open_id), GFP_KERNEL);
 	if (NULL == item) {
 		IVTV_DEBUG_WARN("nomem on v4l2 open\n");
 		return -ENOMEM;
 	}
+	v4l2_fh_init(&item->fh, s->vdev);
+	if (s->type == IVTV_DEC_STREAM_TYPE_YUV ||
+	    s->type == IVTV_DEC_STREAM_TYPE_MPG) {
+		res = v4l2_event_alloc(&item->fh, 60);
+	}
+	if (res < 0) {
+		v4l2_fh_exit(&item->fh);
+		kfree(item);
+		return res;
+	}
 	item->itv = itv;
 	item->type = s->type;
 	v4l2_prio_open(&itv->prio, &item->prio);
 
 	item->open_id = itv->open_id++;
-	filp->private_data = item;
+	filp->private_data = &item->fh;
 
 	if (item->type == IVTV_ENC_STREAM_TYPE_RAD) {
 		/* Try to claim this stream */
@@ -940,6 +967,7 @@
 				/* switching to radio while capture is
 				   in progress is not polite */
 				ivtv_release_stream(s);
+				v4l2_fh_exit(&item->fh);
 				kfree(item);
 				return -EBUSY;
 			}
@@ -970,6 +998,7 @@
 				1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31);
 		itv->yuv_info.stream_size = 0;
 	}
+	v4l2_fh_add(&item->fh);
 	return 0;
 }
 
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index 2ee03c2..a5b92d1 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -193,7 +193,7 @@
 	/* Our default information for ir-kbd-i2c.c to use */
 	switch (hw) {
 	case IVTV_HW_I2C_IR_RX_AVER:
-		init_data->ir_codes = &ir_codes_avermedia_cardbus_table;
+		init_data->ir_codes = RC_MAP_AVERMEDIA_CARDBUS;
 		init_data->internal_get_key_func =
 					IR_KBD_GET_KEY_AVERMEDIA_CARDBUS;
 		init_data->type = IR_TYPE_OTHER;
@@ -202,14 +202,14 @@
 	case IVTV_HW_I2C_IR_RX_HAUP_EXT:
 	case IVTV_HW_I2C_IR_RX_HAUP_INT:
 		/* Default to old black remote */
-		init_data->ir_codes = &ir_codes_rc5_tv_table;
+		init_data->ir_codes = RC_MAP_RC5_TV;
 		init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP;
 		init_data->type = IR_TYPE_RC5;
 		init_data->name = itv->card_name;
 		break;
 	case IVTV_HW_Z8F0811_IR_RX_HAUP:
 		/* Default to grey remote */
-		init_data->ir_codes = &ir_codes_hauppauge_new_table;
+		init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW;
 		init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
 		init_data->type = IR_TYPE_RC5;
 		init_data->name = itv->card_name;
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index 99f3c39..fa9f0d9 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -35,6 +35,7 @@
 #include <media/saa7127.h>
 #include <media/tveeprom.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-event.h>
 #include <linux/dvb/audio.h>
 #include <linux/i2c-id.h>
 
@@ -391,7 +392,7 @@
 		return 0;
 	}
 
-	v4l2_subdev_call(itv->sd_video, video, g_fmt, fmt);
+	v4l2_subdev_call(itv->sd_video, vbi, g_sliced_fmt, vbifmt);
 	vbifmt->service_set = ivtv_get_service_set(vbifmt);
 	return 0;
 }
@@ -597,7 +598,7 @@
 		return -EBUSY;
 	itv->vbi.sliced_in->service_set = 0;
 	itv->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
-	v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt);
+	v4l2_subdev_call(itv->sd_video, vbi, s_raw_fmt, &fmt->fmt.vbi);
 	return ivtv_g_fmt_vbi_cap(file, fh, fmt);
 }
 
@@ -615,7 +616,7 @@
 	if (ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0)
 		return -EBUSY;
 	itv->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
-	v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt);
+	v4l2_subdev_call(itv->sd_video, vbi, s_sliced_fmt, vbifmt);
 	memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in));
 	return 0;
 }
@@ -1087,8 +1088,10 @@
 
 int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
 {
+	DEFINE_WAIT(wait);
 	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 	struct yuv_playback_info *yi = &itv->yuv_info;
+	int f;
 
 	if ((*std & V4L2_STD_ALL) == 0)
 		return -EINVAL;
@@ -1128,6 +1131,25 @@
 		itv->is_out_60hz = itv->is_60hz;
 		itv->is_out_50hz = itv->is_50hz;
 		ivtv_call_all(itv, video, s_std_output, itv->std_out);
+
+		/*
+		 * The next firmware call is time sensitive. Time it to
+		 * avoid risk of a hard lock, by trying to ensure the call
+		 * happens within the first 100 lines of the top field.
+		 * Make 4 attempts to sync to the decoder before giving up.
+		 */
+		for (f = 0; f < 4; f++) {
+			prepare_to_wait(&itv->vsync_waitq, &wait,
+					TASK_UNINTERRUPTIBLE);
+			if ((read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16) < 100)
+				break;
+			schedule_timeout(msecs_to_jiffies(25));
+		}
+		finish_wait(&itv->vsync_waitq, &wait);
+
+		if (f == 4)
+			IVTV_WARN("Mode change failed to sync to decoder\n");
+
 		ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz);
 		itv->main_rect.left = itv->main_rect.top = 0;
 		itv->main_rect.width = 720;
@@ -1431,6 +1453,18 @@
 	return 0;
 }
 
+static int ivtv_subscribe_event(struct v4l2_fh *fh, struct v4l2_event_subscription *sub)
+{
+	switch (sub->type) {
+	case V4L2_EVENT_VSYNC:
+	case V4L2_EVENT_EOS:
+		break;
+	default:
+		return -EINVAL;
+	}
+	return v4l2_event_subscribe(fh, sub);
+}
+
 static int ivtv_log_status(struct file *file, void *fh)
 {
 	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
@@ -1539,10 +1573,11 @@
 
 static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
 {
-	struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
+	struct ivtv_open_id *id = fh2id(filp->private_data);
 	struct ivtv *itv = id->itv;
 	int nonblocking = filp->f_flags & O_NONBLOCK;
 	struct ivtv_stream *s = &itv->streams[id->type];
+	unsigned long iarg = (unsigned long)arg;
 
 	switch (cmd) {
 	case IVTV_IOC_DMA_FRAME: {
@@ -1724,6 +1759,33 @@
 		break;
 	}
 
+	case VIDEO_SELECT_SOURCE:
+		IVTV_DEBUG_IOCTL("VIDEO_SELECT_SOURCE\n");
+		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+			return -EINVAL;
+		return ivtv_passthrough_mode(itv, iarg == VIDEO_SOURCE_DEMUX);
+
+	case AUDIO_SET_MUTE:
+		IVTV_DEBUG_IOCTL("AUDIO_SET_MUTE\n");
+		itv->speed_mute_audio = iarg;
+		return 0;
+
+	case AUDIO_CHANNEL_SELECT:
+		IVTV_DEBUG_IOCTL("AUDIO_CHANNEL_SELECT\n");
+		if (iarg > AUDIO_STEREO_SWAPPED)
+			return -EINVAL;
+		itv->audio_stereo_mode = iarg;
+		ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
+		return 0;
+
+	case AUDIO_BILINGUAL_CHANNEL_SELECT:
+		IVTV_DEBUG_IOCTL("AUDIO_BILINGUAL_CHANNEL_SELECT\n");
+		if (iarg > AUDIO_STEREO_SWAPPED)
+			return -EINVAL;
+		itv->audio_bilingual_mode = iarg;
+		ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
+		return 0;
+
 	default:
 		return -EINVAL;
 	}
@@ -1755,6 +1817,10 @@
 	case VIDEO_CONTINUE:
 	case VIDEO_COMMAND:
 	case VIDEO_TRY_COMMAND:
+	case VIDEO_SELECT_SOURCE:
+	case AUDIO_SET_MUTE:
+	case AUDIO_CHANNEL_SELECT:
+	case AUDIO_BILINGUAL_CHANNEL_SELECT:
 		return ivtv_decoder_ioctls(file, cmd, (void *)arg);
 
 	default:
@@ -1767,42 +1833,9 @@
 		unsigned int cmd, unsigned long arg)
 {
 	struct video_device *vfd = video_devdata(filp);
-	struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
+	struct ivtv_open_id *id = fh2id(filp->private_data);
 	long ret;
 
-	/* Filter dvb ioctls that cannot be handled by the v4l ioctl framework */
-	switch (cmd) {
-	case VIDEO_SELECT_SOURCE:
-		IVTV_DEBUG_IOCTL("VIDEO_SELECT_SOURCE\n");
-		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
-			return -EINVAL;
-		return ivtv_passthrough_mode(itv, arg == VIDEO_SOURCE_DEMUX);
-
-	case AUDIO_SET_MUTE:
-		IVTV_DEBUG_IOCTL("AUDIO_SET_MUTE\n");
-		itv->speed_mute_audio = arg;
-		return 0;
-
-	case AUDIO_CHANNEL_SELECT:
-		IVTV_DEBUG_IOCTL("AUDIO_CHANNEL_SELECT\n");
-		if (arg > AUDIO_STEREO_SWAPPED)
-			return -EINVAL;
-		itv->audio_stereo_mode = arg;
-		ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
-		return 0;
-
-	case AUDIO_BILINGUAL_CHANNEL_SELECT:
-		IVTV_DEBUG_IOCTL("AUDIO_BILINGUAL_CHANNEL_SELECT\n");
-		if (arg > AUDIO_STEREO_SWAPPED)
-			return -EINVAL;
-		itv->audio_bilingual_mode = arg;
-		ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
-		return 0;
-
-	default:
-		break;
-	}
-
 	/* check priority */
 	switch (cmd) {
 	case VIDIOC_S_CTRL:
@@ -1817,8 +1850,9 @@
 	case VIDIOC_S_AUDOUT:
 	case VIDIOC_S_EXT_CTRLS:
 	case VIDIOC_S_FBUF:
+	case VIDIOC_S_PRIORITY:
 	case VIDIOC_OVERLAY:
-		ret = v4l2_prio_check(&itv->prio, &id->prio);
+		ret = v4l2_prio_check(&itv->prio, id->prio);
 		if (ret)
 			return ret;
 	}
@@ -1832,10 +1866,13 @@
 
 long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
-	struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
+	struct ivtv_open_id *id = fh2id(filp->private_data);
 	struct ivtv *itv = id->itv;
 	long res;
 
+	/* DQEVENT can block, so this should not run with the serialize lock */
+	if (cmd == VIDIOC_DQEVENT)
+		return ivtv_serialized_ioctl(itv, filp, cmd, arg);
 	mutex_lock(&itv->serialize_lock);
 	res = ivtv_serialized_ioctl(itv, filp, cmd, arg);
 	mutex_unlock(&itv->serialize_lock);
@@ -1906,6 +1943,8 @@
 	.vidioc_g_ext_ctrls 		    = ivtv_g_ext_ctrls,
 	.vidioc_s_ext_ctrls 		    = ivtv_s_ext_ctrls,
 	.vidioc_try_ext_ctrls    	    = ivtv_try_ext_ctrls,
+	.vidioc_subscribe_event 	    = ivtv_subscribe_event,
+	.vidioc_unsubscribe_event 	    = v4l2_event_unsubscribe,
 };
 
 void ivtv_set_funcs(struct video_device *vdev)
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index 12d36ca..fea1ec3 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -25,6 +25,7 @@
 #include "ivtv-mailbox.h"
 #include "ivtv-vbi.h"
 #include "ivtv-yuv.h"
+#include <media/v4l2-event.h>
 
 #define DMA_MAGIC_COOKIE 0x000001fe
 
@@ -752,7 +753,7 @@
 	 * to determine the line being displayed and ensure we handle
 	 * one vsync per frame.
 	 */
-	unsigned int frame = read_reg(0x28c0) & 1;
+	unsigned int frame = read_reg(IVTV_REG_DEC_LINE_FIELD) & 1;
 	struct yuv_playback_info *yi = &itv->yuv_info;
 	int last_dma_frame = atomic_read(&yi->next_dma_frame);
 	struct yuv_frame_info *f = &yi->new_frame_info[last_dma_frame];
@@ -778,6 +779,14 @@
 		}
 	}
 	if (frame != (itv->last_vsync_field & 1)) {
+		static const struct v4l2_event evtop = {
+			.type = V4L2_EVENT_VSYNC,
+			.u.vsync.field = V4L2_FIELD_TOP,
+		};
+		static const struct v4l2_event evbottom = {
+			.type = V4L2_EVENT_VSYNC,
+			.u.vsync.field = V4L2_FIELD_BOTTOM,
+		};
 		struct ivtv_stream *s = ivtv_get_output_stream(itv);
 
 		itv->last_vsync_field += 1;
@@ -791,10 +800,12 @@
 		if (test_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags)) {
 			set_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags);
 			wake_up(&itv->event_waitq);
+			if (s)
+				wake_up(&s->waitq);
 		}
+		if (s && s->vdev)
+			v4l2_event_queue(s->vdev, frame ? &evtop : &evbottom);
 		wake_up(&itv->vsync_waitq);
-		if (s)
-			wake_up(&s->waitq);
 
 		/* Send VBI to saa7127 */
 		if (frame && (itv->output_mode == OUT_PASSTHROUGH ||
@@ -852,9 +863,11 @@
 		 */
 		if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) {
 			/* vsync is enabled, see if we're in a new field */
-			if ((itv->last_vsync_field & 1) != (read_reg(0x28c0) & 1)) {
+			if ((itv->last_vsync_field & 1) !=
+			    (read_reg(IVTV_REG_DEC_LINE_FIELD) & 1)) {
 				/* New field, looks like we missed it */
-				IVTV_DEBUG_YUV("VSync interrupt missed %d\n",read_reg(0x28c0)>>16);
+				IVTV_DEBUG_YUV("VSync interrupt missed %d\n",
+				       read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16);
 				vsync_force = 1;
 			}
 		}
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index 1f9387f..de4288c 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -42,6 +42,7 @@
 #include "ivtv-yuv.h"
 #include "ivtv-cards.h"
 #include "ivtv-streams.h"
+#include <media/v4l2-event.h>
 
 static const struct v4l2_file_operations ivtv_v4l2_enc_fops = {
 	.owner = THIS_MODULE,
@@ -343,7 +344,10 @@
 	ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0);
 
 	/* setup VBI registers */
-	v4l2_subdev_call(itv->sd_video, video, s_fmt, &itv->vbi.in);
+	if (raw)
+		v4l2_subdev_call(itv->sd_video, vbi, s_raw_fmt, &itv->vbi.in.fmt.vbi);
+	else
+		v4l2_subdev_call(itv->sd_video, vbi, s_sliced_fmt, &itv->vbi.in.fmt.sliced);
 
 	/* determine number of lines and total number of VBI bytes.
 	   A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1
@@ -581,10 +585,9 @@
 		v4l2_subdev_call(itv->sd_audio, audio, s_stream, 1);
 		/* Avoid unpredictable PCI bus hang - disable video clocks */
 		v4l2_subdev_call(itv->sd_video, video, s_stream, 0);
-		ivtv_msleep_timeout(150, 1);
+		ivtv_msleep_timeout(300, 1);
 		ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
 		v4l2_subdev_call(itv->sd_video, video, s_stream, 1);
-		ivtv_msleep_timeout(150, 1);
 	}
 
 	/* begin_capture */
@@ -830,6 +833,10 @@
 		ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
 	}
 
+	/* Raw-passthrough is implied on start. Make sure it's stopped so
+	   the encoder will re-initialize when next started */
+	ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, 1, 2, 7);
+
 	wake_up(&s->waitq);
 
 	return 0;
@@ -837,6 +844,9 @@
 
 int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
 {
+	static const struct v4l2_event ev = {
+		.type = V4L2_EVENT_EOS,
+	};
 	struct ivtv *itv = s->itv;
 
 	if (s->vdev == NULL)
@@ -888,6 +898,7 @@
 
 	set_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags);
 	wake_up(&itv->event_waitq);
+	v4l2_event_queue(s->vdev, &ev);
 
 	/* wake up wait queues */
 	wake_up(&s->waitq);
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c
index f420d31..e1c347e 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/drivers/media/video/ivtv/ivtv-vbi.c
@@ -38,7 +38,7 @@
 	data.data[9] = itv->vbi.vps_payload.data[2];
 	data.data[10] = itv->vbi.vps_payload.data[3];
 	data.data[11] = itv->vbi.vps_payload.data[4];
-	ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_vbi_data, &data);
+	ivtv_call_hw(itv, IVTV_HW_SAA7127, vbi, s_vbi_data, &data);
 }
 
 static void ivtv_set_cc(struct ivtv *itv, int mode, const struct vbi_cc *cc)
@@ -52,12 +52,12 @@
 	data.line = (mode & 1) ? 21 : 0;
 	data.data[0] = cc->odd[0];
 	data.data[1] = cc->odd[1];
-	ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_vbi_data, &data);
+	ivtv_call_hw(itv, IVTV_HW_SAA7127, vbi, s_vbi_data, &data);
 	data.field = 1;
 	data.line = (mode & 2) ? 21 : 0;
 	data.data[0] = cc->even[0];
 	data.data[1] = cc->even[1];
-	ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_vbi_data, &data);
+	ivtv_call_hw(itv, IVTV_HW_SAA7127, vbi, s_vbi_data, &data);
 }
 
 static void ivtv_set_wss(struct ivtv *itv, int enabled, int mode)
@@ -80,7 +80,7 @@
 	data.line = enabled ? 23 : 0;
 	data.data[0] = mode & 0xff;
 	data.data[1] = (mode >> 8) & 0xff;
-	ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_vbi_data, &data);
+	ivtv_call_hw(itv, IVTV_HW_SAA7127, vbi, s_vbi_data, &data);
 }
 
 static int odd_parity(u8 c)
@@ -134,7 +134,7 @@
 			}
 		}
 	}
-	if (found_cc && vi->cc_payload_idx < sizeof(vi->cc_payload)) {
+	if (found_cc && vi->cc_payload_idx < ARRAY_SIZE(vi->cc_payload)) {
 		vi->cc_payload[vi->cc_payload_idx++] = cc;
 		set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
 	}
@@ -316,7 +316,7 @@
 			continue;
 		}
 		vbi.p = p + 4;
-		v4l2_subdev_call(itv->sd_video, video, decode_vbi_line, &vbi);
+		v4l2_subdev_call(itv->sd_video, vbi, decode_vbi_line, &vbi);
 		if (vbi.type && !(lines & (1 << vbi.line))) {
 			lines |= 1 << vbi.line;
 			itv->vbi.sliced_data[line].id = vbi.type;
@@ -440,7 +440,7 @@
 			data.id = V4L2_SLICED_WSS_625;
 			data.field = 0;
 
-			if (v4l2_subdev_call(itv->sd_video, video, g_vbi_data, &data) == 0) {
+			if (v4l2_subdev_call(itv->sd_video, vbi, g_vbi_data, &data) == 0) {
 				ivtv_set_wss(itv, 1, data.data[0] & 0xf);
 				vi->wss_missing_cnt = 0;
 			} else if (vi->wss_missing_cnt == 4) {
@@ -454,13 +454,13 @@
 
 			data.id = V4L2_SLICED_CAPTION_525;
 			data.field = 0;
-			if (v4l2_subdev_call(itv->sd_video, video, g_vbi_data, &data) == 0) {
+			if (v4l2_subdev_call(itv->sd_video, vbi, g_vbi_data, &data) == 0) {
 				mode |= 1;
 				cc.odd[0] = data.data[0];
 				cc.odd[1] = data.data[1];
 			}
 			data.field = 1;
-			if (v4l2_subdev_call(itv->sd_video, video, g_vbi_data, &data) == 0) {
+			if (v4l2_subdev_call(itv->sd_video, vbi, g_vbi_data, &data) == 0) {
 				mode |= 2;
 				cc.even[0] = data.data[0];
 				cc.even[1] = data.data[1];
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index de2ff1c..49e1a28 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -460,7 +460,7 @@
 
 			vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
 					FB_VBLANK_HAVE_VSYNC;
-			trace = read_reg(0x028c0) >> 16;
+			trace = read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16;
 			if (itv->is_50hz && trace > 312)
 				trace -= 312;
 			else if (itv->is_60hz && trace > 262)
diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c
new file mode 100644
index 0000000..554eaf1
--- /dev/null
+++ b/drivers/media/video/mem2mem_testdev.c
@@ -0,0 +1,1052 @@
+/*
+ * A virtual v4l2-mem2mem example device.
+ *
+ * This is a virtual device driver for testing mem-to-mem videobuf framework.
+ * It simulates a device that uses memory buffers for both source and
+ * destination, processes the data and issues an "irq" (simulated by a timer).
+ * The device is capable of multi-instance, multi-buffer-per-transaction
+ * operation (via the mem2mem framework).
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <p.osciak@samsung.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/version.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <linux/platform_device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf-vmalloc.h>
+
+#define MEM2MEM_TEST_MODULE_NAME "mem2mem-testdev"
+
+MODULE_DESCRIPTION("Virtual device for mem2mem framework testing");
+MODULE_AUTHOR("Pawel Osciak, <p.osciak@samsung.com>");
+MODULE_LICENSE("GPL");
+
+
+#define MIN_W 32
+#define MIN_H 32
+#define MAX_W 640
+#define MAX_H 480
+#define DIM_ALIGN_MASK 0x08 /* 8-alignment for dimensions */
+
+/* Flags that indicate a format can be used for capture/output */
+#define MEM2MEM_CAPTURE	(1 << 0)
+#define MEM2MEM_OUTPUT	(1 << 1)
+
+#define MEM2MEM_NAME		"m2m-testdev"
+
+/* Per queue */
+#define MEM2MEM_DEF_NUM_BUFS	VIDEO_MAX_FRAME
+/* In bytes, per queue */
+#define MEM2MEM_VID_MEM_LIMIT	(16 * 1024 * 1024)
+
+/* Default transaction time in msec */
+#define MEM2MEM_DEF_TRANSTIME	1000
+/* Default number of buffers per transaction */
+#define MEM2MEM_DEF_TRANSLEN	1
+#define MEM2MEM_COLOR_STEP	(0xff >> 4)
+#define MEM2MEM_NUM_TILES	8
+
+#define dprintk(dev, fmt, arg...) \
+	v4l2_dbg(1, 1, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
+
+
+void m2mtest_dev_release(struct device *dev)
+{}
+
+static struct platform_device m2mtest_pdev = {
+	.name		= MEM2MEM_NAME,
+	.dev.release	= m2mtest_dev_release,
+};
+
+struct m2mtest_fmt {
+	char	*name;
+	u32	fourcc;
+	int	depth;
+	/* Types the format can be used for */
+	u32	types;
+};
+
+static struct m2mtest_fmt formats[] = {
+	{
+		.name	= "RGB565 (BE)",
+		.fourcc	= V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
+		.depth	= 16,
+		/* Both capture and output format */
+		.types	= MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+	},
+	{
+		.name	= "4:2:2, packed, YUYV",
+		.fourcc	= V4L2_PIX_FMT_YUYV,
+		.depth	= 16,
+		/* Output-only format */
+		.types	= MEM2MEM_OUTPUT,
+	},
+};
+
+/* Per-queue, driver-specific private data */
+struct m2mtest_q_data {
+	unsigned int		width;
+	unsigned int		height;
+	unsigned int		sizeimage;
+	struct m2mtest_fmt	*fmt;
+};
+
+enum {
+	V4L2_M2M_SRC = 0,
+	V4L2_M2M_DST = 1,
+};
+
+/* Source and destination queue data */
+static struct m2mtest_q_data q_data[2];
+
+static struct m2mtest_q_data *get_q_data(enum v4l2_buf_type type)
+{
+	switch (type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		return &q_data[V4L2_M2M_SRC];
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return &q_data[V4L2_M2M_DST];
+	default:
+		BUG();
+	}
+	return NULL;
+}
+
+#define V4L2_CID_TRANS_TIME_MSEC	V4L2_CID_PRIVATE_BASE
+#define V4L2_CID_TRANS_NUM_BUFS		(V4L2_CID_PRIVATE_BASE + 1)
+
+static struct v4l2_queryctrl m2mtest_ctrls[] = {
+	{
+		.id		= V4L2_CID_TRANS_TIME_MSEC,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "Transaction time (msec)",
+		.minimum	= 1,
+		.maximum	= 10000,
+		.step		= 100,
+		.default_value	= 1000,
+		.flags		= 0,
+	}, {
+		.id		= V4L2_CID_TRANS_NUM_BUFS,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "Buffers per transaction",
+		.minimum	= 1,
+		.maximum	= MEM2MEM_DEF_NUM_BUFS,
+		.step		= 1,
+		.default_value	= 1,
+		.flags		= 0,
+	},
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+static struct m2mtest_fmt *find_format(struct v4l2_format *f)
+{
+	struct m2mtest_fmt *fmt;
+	unsigned int k;
+
+	for (k = 0; k < NUM_FORMATS; k++) {
+		fmt = &formats[k];
+		if (fmt->fourcc == f->fmt.pix.pixelformat)
+			break;
+	}
+
+	if (k == NUM_FORMATS)
+		return NULL;
+
+	return &formats[k];
+}
+
+struct m2mtest_dev {
+	struct v4l2_device	v4l2_dev;
+	struct video_device	*vfd;
+
+	atomic_t		num_inst;
+	struct mutex		dev_mutex;
+	spinlock_t		irqlock;
+
+	struct timer_list	timer;
+
+	struct v4l2_m2m_dev	*m2m_dev;
+};
+
+struct m2mtest_ctx {
+	struct m2mtest_dev	*dev;
+
+	/* Processed buffers in this transaction */
+	u8			num_processed;
+
+	/* Transaction length (i.e. how many buffers per transaction) */
+	u32			translen;
+	/* Transaction time (i.e. simulated processing time) in milliseconds */
+	u32			transtime;
+
+	/* Abort requested by m2m */
+	int			aborting;
+
+	struct v4l2_m2m_ctx	*m2m_ctx;
+};
+
+struct m2mtest_buffer {
+	/* vb must be first! */
+	struct videobuf_buffer	vb;
+};
+
+static struct v4l2_queryctrl *get_ctrl(int id)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(m2mtest_ctrls); ++i) {
+		if (id == m2mtest_ctrls[i].id)
+			return &m2mtest_ctrls[i];
+	}
+
+	return NULL;
+}
+
+static int device_process(struct m2mtest_ctx *ctx,
+			  struct m2mtest_buffer *in_buf,
+			  struct m2mtest_buffer *out_buf)
+{
+	struct m2mtest_dev *dev = ctx->dev;
+	u8 *p_in, *p_out;
+	int x, y, t, w;
+	int tile_w, bytes_left;
+	struct videobuf_queue *src_q;
+	struct videobuf_queue *dst_q;
+
+	src_q = v4l2_m2m_get_src_vq(ctx->m2m_ctx);
+	dst_q = v4l2_m2m_get_dst_vq(ctx->m2m_ctx);
+	p_in = videobuf_queue_to_vaddr(src_q, &in_buf->vb);
+	p_out = videobuf_queue_to_vaddr(dst_q, &out_buf->vb);
+	if (!p_in || !p_out) {
+		v4l2_err(&dev->v4l2_dev,
+			 "Acquiring kernel pointers to buffers failed\n");
+		return -EFAULT;
+	}
+
+	if (in_buf->vb.size < out_buf->vb.size) {
+		v4l2_err(&dev->v4l2_dev, "Output buffer is too small\n");
+		return -EINVAL;
+	}
+
+	tile_w = (in_buf->vb.width * (q_data[V4L2_M2M_DST].fmt->depth >> 3))
+		/ MEM2MEM_NUM_TILES;
+	bytes_left = in_buf->vb.bytesperline - tile_w * MEM2MEM_NUM_TILES;
+	w = 0;
+
+	for (y = 0; y < in_buf->vb.height; ++y) {
+		for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
+			if (w & 0x1) {
+				for (x = 0; x < tile_w; ++x)
+					*p_out++ = *p_in++ + MEM2MEM_COLOR_STEP;
+			} else {
+				for (x = 0; x < tile_w; ++x)
+					*p_out++ = *p_in++ - MEM2MEM_COLOR_STEP;
+			}
+			++w;
+		}
+		p_in += bytes_left;
+		p_out += bytes_left;
+	}
+
+	return 0;
+}
+
+static void schedule_irq(struct m2mtest_dev *dev, int msec_timeout)
+{
+	dprintk(dev, "Scheduling a simulated irq\n");
+	mod_timer(&dev->timer, jiffies + msecs_to_jiffies(msec_timeout));
+}
+
+/*
+ * mem2mem callbacks
+ */
+
+/**
+ * job_ready() - check whether an instance is ready to be scheduled to run
+ */
+static int job_ready(void *priv)
+{
+	struct m2mtest_ctx *ctx = priv;
+
+	if (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) < ctx->translen
+	    || v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < ctx->translen) {
+		dprintk(ctx->dev, "Not enough buffers available\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+static void job_abort(void *priv)
+{
+	struct m2mtest_ctx *ctx = priv;
+
+	/* Will cancel the transaction in the next interrupt handler */
+	ctx->aborting = 1;
+}
+
+/* device_run() - prepares and starts the device
+ *
+ * This simulates all the immediate preparations required before starting
+ * a device. This will be called by the framework when it decides to schedule
+ * a particular instance.
+ */
+static void device_run(void *priv)
+{
+	struct m2mtest_ctx *ctx = priv;
+	struct m2mtest_dev *dev = ctx->dev;
+	struct m2mtest_buffer *src_buf, *dst_buf;
+
+	src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+	dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+
+	device_process(ctx, src_buf, dst_buf);
+
+	/* Run a timer, which simulates a hardware irq  */
+	schedule_irq(dev, ctx->transtime);
+}
+
+
+static void device_isr(unsigned long priv)
+{
+	struct m2mtest_dev *m2mtest_dev = (struct m2mtest_dev *)priv;
+	struct m2mtest_ctx *curr_ctx;
+	struct m2mtest_buffer *src_buf, *dst_buf;
+	unsigned long flags;
+
+	curr_ctx = v4l2_m2m_get_curr_priv(m2mtest_dev->m2m_dev);
+
+	if (NULL == curr_ctx) {
+		printk(KERN_ERR
+			"Instance released before the end of transaction\n");
+		return;
+	}
+
+	src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
+	dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+	curr_ctx->num_processed++;
+
+	if (curr_ctx->num_processed == curr_ctx->translen
+	    || curr_ctx->aborting) {
+		dprintk(curr_ctx->dev, "Finishing transaction\n");
+		curr_ctx->num_processed = 0;
+		spin_lock_irqsave(&m2mtest_dev->irqlock, flags);
+		src_buf->vb.state = dst_buf->vb.state = VIDEOBUF_DONE;
+		wake_up(&src_buf->vb.done);
+		wake_up(&dst_buf->vb.done);
+		spin_unlock_irqrestore(&m2mtest_dev->irqlock, flags);
+		v4l2_m2m_job_finish(m2mtest_dev->m2m_dev, curr_ctx->m2m_ctx);
+	} else {
+		spin_lock_irqsave(&m2mtest_dev->irqlock, flags);
+		src_buf->vb.state = dst_buf->vb.state = VIDEOBUF_DONE;
+		wake_up(&src_buf->vb.done);
+		wake_up(&dst_buf->vb.done);
+		spin_unlock_irqrestore(&m2mtest_dev->irqlock, flags);
+		device_run(curr_ctx);
+	}
+}
+
+
+/*
+ * video ioctls
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *cap)
+{
+	strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
+	strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
+	cap->bus_info[0] = 0;
+	cap->version = KERNEL_VERSION(0, 1, 0);
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
+			  | V4L2_CAP_STREAMING;
+
+	return 0;
+}
+
+static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
+{
+	int i, num;
+	struct m2mtest_fmt *fmt;
+
+	num = 0;
+
+	for (i = 0; i < NUM_FORMATS; ++i) {
+		if (formats[i].types & type) {
+			/* index-th format of type type found ? */
+			if (num == f->index)
+				break;
+			/* Correct type but haven't reached our index yet,
+			 * just increment per-type index */
+			++num;
+		}
+	}
+
+	if (i < NUM_FORMATS) {
+		/* Format found */
+		fmt = &formats[i];
+		strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+		f->pixelformat = fmt->fourcc;
+		return 0;
+	}
+
+	/* Format not found */
+	return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	return enum_fmt(f, MEM2MEM_CAPTURE);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	return enum_fmt(f, MEM2MEM_OUTPUT);
+}
+
+static int vidioc_g_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
+{
+	struct videobuf_queue *vq;
+	struct m2mtest_q_data *q_data;
+
+	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+	if (!vq)
+		return -EINVAL;
+
+	q_data = get_q_data(f->type);
+
+	f->fmt.pix.width	= q_data->width;
+	f->fmt.pix.height	= q_data->height;
+	f->fmt.pix.field	= vq->field;
+	f->fmt.pix.pixelformat	= q_data->fmt->fourcc;
+	f->fmt.pix.bytesperline	= (q_data->width * q_data->fmt->depth) >> 3;
+	f->fmt.pix.sizeimage	= q_data->sizeimage;
+
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	return vidioc_g_fmt(priv, f);
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	return vidioc_g_fmt(priv, f);
+}
+
+static int vidioc_try_fmt(struct v4l2_format *f, struct m2mtest_fmt *fmt)
+{
+	enum v4l2_field field;
+
+	field = f->fmt.pix.field;
+
+	if (field == V4L2_FIELD_ANY)
+		field = V4L2_FIELD_NONE;
+	else if (V4L2_FIELD_NONE != field)
+		return -EINVAL;
+
+	/* V4L2 specification suggests the driver corrects the format struct
+	 * if any of the dimensions is unsupported */
+	f->fmt.pix.field = field;
+
+	if (f->fmt.pix.height < MIN_H)
+		f->fmt.pix.height = MIN_H;
+	else if (f->fmt.pix.height > MAX_H)
+		f->fmt.pix.height = MAX_H;
+
+	if (f->fmt.pix.width < MIN_W)
+		f->fmt.pix.width = MIN_W;
+	else if (f->fmt.pix.width > MAX_W)
+		f->fmt.pix.width = MAX_W;
+
+	f->fmt.pix.width &= ~DIM_ALIGN_MASK;
+	f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
+	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct m2mtest_fmt *fmt;
+	struct m2mtest_ctx *ctx = priv;
+
+	fmt = find_format(f);
+	if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) {
+		v4l2_err(&ctx->dev->v4l2_dev,
+			 "Fourcc format (0x%08x) invalid.\n",
+			 f->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+
+	return vidioc_try_fmt(f, fmt);
+}
+
+static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct m2mtest_fmt *fmt;
+	struct m2mtest_ctx *ctx = priv;
+
+	fmt = find_format(f);
+	if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) {
+		v4l2_err(&ctx->dev->v4l2_dev,
+			 "Fourcc format (0x%08x) invalid.\n",
+			 f->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+
+	return vidioc_try_fmt(f, fmt);
+}
+
+static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
+{
+	struct m2mtest_q_data *q_data;
+	struct videobuf_queue *vq;
+	int ret = 0;
+
+	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+	if (!vq)
+		return -EINVAL;
+
+	q_data = get_q_data(f->type);
+	if (!q_data)
+		return -EINVAL;
+
+	mutex_lock(&vq->vb_lock);
+
+	if (videobuf_queue_is_busy(vq)) {
+		v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
+		ret = -EBUSY;
+		goto out;
+	}
+
+	q_data->fmt		= find_format(f);
+	q_data->width		= f->fmt.pix.width;
+	q_data->height		= f->fmt.pix.height;
+	q_data->sizeimage	= q_data->width * q_data->height
+				* q_data->fmt->depth >> 3;
+	vq->field		= f->fmt.pix.field;
+
+	dprintk(ctx->dev,
+		"Setting format for type %d, wxh: %dx%d, fmt: %d\n",
+		f->type, q_data->width, q_data->height, q_data->fmt->fourcc);
+
+out:
+	mutex_unlock(&vq->vb_lock);
+	return ret;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	int ret;
+
+	ret = vidioc_try_fmt_vid_cap(file, priv, f);
+	if (ret)
+		return ret;
+
+	return vidioc_s_fmt(priv, f);
+}
+
+static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	int ret;
+
+	ret = vidioc_try_fmt_vid_out(file, priv, f);
+	if (ret)
+		return ret;
+
+	return vidioc_s_fmt(priv, f);
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *reqbufs)
+{
+	struct m2mtest_ctx *ctx = priv;
+
+	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+			   struct v4l2_buffer *buf)
+{
+	struct m2mtest_ctx *ctx = priv;
+
+	return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct m2mtest_ctx *ctx = priv;
+
+	return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct m2mtest_ctx *ctx = priv;
+
+	return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+			   enum v4l2_buf_type type)
+{
+	struct m2mtest_ctx *ctx = priv;
+
+	return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+			    enum v4l2_buf_type type)
+{
+	struct m2mtest_ctx *ctx = priv;
+
+	return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+			    struct v4l2_queryctrl *qc)
+{
+	struct v4l2_queryctrl *c;
+
+	c = get_ctrl(qc->id);
+	if (!c)
+		return -EINVAL;
+
+	*qc = *c;
+	return 0;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+			 struct v4l2_control *ctrl)
+{
+	struct m2mtest_ctx *ctx = priv;
+
+	switch (ctrl->id) {
+	case V4L2_CID_TRANS_TIME_MSEC:
+		ctrl->value = ctx->transtime;
+		break;
+
+	case V4L2_CID_TRANS_NUM_BUFS:
+		ctrl->value = ctx->translen;
+		break;
+
+	default:
+		v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int check_ctrl_val(struct m2mtest_ctx *ctx, struct v4l2_control *ctrl)
+{
+	struct v4l2_queryctrl *c;
+
+	c = get_ctrl(ctrl->id);
+	if (!c)
+		return -EINVAL;
+
+	if (ctrl->value < c->minimum || ctrl->value > c->maximum) {
+		v4l2_err(&ctx->dev->v4l2_dev, "Value out of range\n");
+		return -ERANGE;
+	}
+
+	return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+			 struct v4l2_control *ctrl)
+{
+	struct m2mtest_ctx *ctx = priv;
+	int ret = 0;
+
+	ret = check_ctrl_val(ctx, ctrl);
+	if (ret != 0)
+		return ret;
+
+	switch (ctrl->id) {
+	case V4L2_CID_TRANS_TIME_MSEC:
+		ctx->transtime = ctrl->value;
+		break;
+
+	case V4L2_CID_TRANS_NUM_BUFS:
+		ctx->translen = ctrl->value;
+		break;
+
+	default:
+		v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = {
+	.vidioc_querycap	= vidioc_querycap,
+
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap	= vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	= vidioc_s_fmt_vid_cap,
+
+	.vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+	.vidioc_g_fmt_vid_out	= vidioc_g_fmt_vid_out,
+	.vidioc_try_fmt_vid_out	= vidioc_try_fmt_vid_out,
+	.vidioc_s_fmt_vid_out	= vidioc_s_fmt_vid_out,
+
+	.vidioc_reqbufs		= vidioc_reqbufs,
+	.vidioc_querybuf	= vidioc_querybuf,
+
+	.vidioc_qbuf		= vidioc_qbuf,
+	.vidioc_dqbuf		= vidioc_dqbuf,
+
+	.vidioc_streamon	= vidioc_streamon,
+	.vidioc_streamoff	= vidioc_streamoff,
+
+	.vidioc_queryctrl	= vidioc_queryctrl,
+	.vidioc_g_ctrl		= vidioc_g_ctrl,
+	.vidioc_s_ctrl		= vidioc_s_ctrl,
+};
+
+
+/*
+ * Queue operations
+ */
+
+static void m2mtest_buf_release(struct videobuf_queue *vq,
+				struct videobuf_buffer *vb)
+{
+	struct m2mtest_ctx *ctx = vq->priv_data;
+
+	dprintk(ctx->dev, "type: %d, index: %d, state: %d\n",
+		vq->type, vb->i, vb->state);
+
+	videobuf_vmalloc_free(vb);
+	vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int m2mtest_buf_setup(struct videobuf_queue *vq, unsigned int *count,
+			  unsigned int *size)
+{
+	struct m2mtest_ctx *ctx = vq->priv_data;
+	struct m2mtest_q_data *q_data;
+
+	q_data = get_q_data(vq->type);
+
+	*size = q_data->width * q_data->height * q_data->fmt->depth >> 3;
+	dprintk(ctx->dev, "size:%d, w/h %d/%d, depth: %d\n",
+		*size, q_data->width, q_data->height, q_data->fmt->depth);
+
+	if (0 == *count)
+		*count = MEM2MEM_DEF_NUM_BUFS;
+
+	while (*size * *count > MEM2MEM_VID_MEM_LIMIT)
+		(*count)--;
+
+	v4l2_info(&ctx->dev->v4l2_dev,
+		  "%d buffers of size %d set up.\n", *count, *size);
+
+	return 0;
+}
+
+static int m2mtest_buf_prepare(struct videobuf_queue *vq,
+			       struct videobuf_buffer *vb,
+			       enum v4l2_field field)
+{
+	struct m2mtest_ctx *ctx = vq->priv_data;
+	struct m2mtest_q_data *q_data;
+	int ret;
+
+	dprintk(ctx->dev, "type: %d, index: %d, state: %d\n",
+		vq->type, vb->i, vb->state);
+
+	q_data = get_q_data(vq->type);
+
+	if (vb->baddr) {
+		/* User-provided buffer */
+		if (vb->bsize < q_data->sizeimage) {
+			/* Buffer too small to fit a frame */
+			v4l2_err(&ctx->dev->v4l2_dev,
+				 "User-provided buffer too small\n");
+			return -EINVAL;
+		}
+	} else if (vb->state != VIDEOBUF_NEEDS_INIT
+			&& vb->bsize < q_data->sizeimage) {
+		/* We provide the buffer, but it's already been initialized
+		 * and is too small */
+		return -EINVAL;
+	}
+
+	vb->width	= q_data->width;
+	vb->height	= q_data->height;
+	vb->bytesperline = (q_data->width * q_data->fmt->depth) >> 3;
+	vb->size	= q_data->sizeimage;
+	vb->field	= field;
+
+	if (VIDEOBUF_NEEDS_INIT == vb->state) {
+		ret = videobuf_iolock(vq, vb, NULL);
+		if (ret) {
+			v4l2_err(&ctx->dev->v4l2_dev,
+				 "Iolock failed\n");
+			goto fail;
+		}
+	}
+
+	vb->state = VIDEOBUF_PREPARED;
+
+	return 0;
+fail:
+	m2mtest_buf_release(vq, vb);
+	return ret;
+}
+
+static void m2mtest_buf_queue(struct videobuf_queue *vq,
+			   struct videobuf_buffer *vb)
+{
+	struct m2mtest_ctx *ctx = vq->priv_data;
+
+	v4l2_m2m_buf_queue(ctx->m2m_ctx, vq, vb);
+}
+
+static struct videobuf_queue_ops m2mtest_qops = {
+	.buf_setup	= m2mtest_buf_setup,
+	.buf_prepare	= m2mtest_buf_prepare,
+	.buf_queue	= m2mtest_buf_queue,
+	.buf_release	= m2mtest_buf_release,
+};
+
+static void queue_init(void *priv, struct videobuf_queue *vq,
+		       enum v4l2_buf_type type)
+{
+	struct m2mtest_ctx *ctx = priv;
+
+	videobuf_queue_vmalloc_init(vq, &m2mtest_qops, ctx->dev->v4l2_dev.dev,
+				    &ctx->dev->irqlock, type, V4L2_FIELD_NONE,
+				    sizeof(struct m2mtest_buffer), priv);
+}
+
+
+/*
+ * File operations
+ */
+static int m2mtest_open(struct file *file)
+{
+	struct m2mtest_dev *dev = video_drvdata(file);
+	struct m2mtest_ctx *ctx = NULL;
+
+	ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	file->private_data = ctx;
+	ctx->dev = dev;
+	ctx->translen = MEM2MEM_DEF_TRANSLEN;
+	ctx->transtime = MEM2MEM_DEF_TRANSTIME;
+	ctx->num_processed = 0;
+
+	ctx->m2m_ctx = v4l2_m2m_ctx_init(ctx, dev->m2m_dev, queue_init);
+	if (IS_ERR(ctx->m2m_ctx)) {
+		int ret = PTR_ERR(ctx->m2m_ctx);
+
+		kfree(ctx);
+		return ret;
+	}
+
+	atomic_inc(&dev->num_inst);
+
+	dprintk(dev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx);
+
+	return 0;
+}
+
+static int m2mtest_release(struct file *file)
+{
+	struct m2mtest_dev *dev = video_drvdata(file);
+	struct m2mtest_ctx *ctx = file->private_data;
+
+	dprintk(dev, "Releasing instance %p\n", ctx);
+
+	v4l2_m2m_ctx_release(ctx->m2m_ctx);
+	kfree(ctx);
+
+	atomic_dec(&dev->num_inst);
+
+	return 0;
+}
+
+static unsigned int m2mtest_poll(struct file *file,
+				 struct poll_table_struct *wait)
+{
+	struct m2mtest_ctx *ctx = (struct m2mtest_ctx *)file->private_data;
+
+	return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+}
+
+static int m2mtest_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct m2mtest_ctx *ctx = (struct m2mtest_ctx *)file->private_data;
+
+	return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+}
+
+static const struct v4l2_file_operations m2mtest_fops = {
+	.owner		= THIS_MODULE,
+	.open		= m2mtest_open,
+	.release	= m2mtest_release,
+	.poll		= m2mtest_poll,
+	.ioctl		= video_ioctl2,
+	.mmap		= m2mtest_mmap,
+};
+
+static struct video_device m2mtest_videodev = {
+	.name		= MEM2MEM_NAME,
+	.fops		= &m2mtest_fops,
+	.ioctl_ops	= &m2mtest_ioctl_ops,
+	.minor		= -1,
+	.release	= video_device_release,
+};
+
+static struct v4l2_m2m_ops m2m_ops = {
+	.device_run	= device_run,
+	.job_ready	= job_ready,
+	.job_abort	= job_abort,
+};
+
+static int m2mtest_probe(struct platform_device *pdev)
+{
+	struct m2mtest_dev *dev;
+	struct video_device *vfd;
+	int ret;
+
+	dev = kzalloc(sizeof *dev, GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	spin_lock_init(&dev->irqlock);
+
+	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+	if (ret)
+		goto free_dev;
+
+	atomic_set(&dev->num_inst, 0);
+	mutex_init(&dev->dev_mutex);
+
+	vfd = video_device_alloc();
+	if (!vfd) {
+		v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
+		ret = -ENOMEM;
+		goto unreg_dev;
+	}
+
+	*vfd = m2mtest_videodev;
+
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+		goto rel_vdev;
+	}
+
+	video_set_drvdata(vfd, dev);
+	snprintf(vfd->name, sizeof(vfd->name), "%s", m2mtest_videodev.name);
+	dev->vfd = vfd;
+	v4l2_info(&dev->v4l2_dev, MEM2MEM_TEST_MODULE_NAME
+			"Device registered as /dev/video%d\n", vfd->num);
+
+	setup_timer(&dev->timer, device_isr, (long)dev);
+	platform_set_drvdata(pdev, dev);
+
+	dev->m2m_dev = v4l2_m2m_init(&m2m_ops);
+	if (IS_ERR(dev->m2m_dev)) {
+		v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
+		ret = PTR_ERR(dev->m2m_dev);
+		goto err_m2m;
+	}
+
+	return 0;
+
+err_m2m:
+	video_unregister_device(dev->vfd);
+rel_vdev:
+	video_device_release(vfd);
+unreg_dev:
+	v4l2_device_unregister(&dev->v4l2_dev);
+free_dev:
+	kfree(dev);
+
+	return ret;
+}
+
+static int m2mtest_remove(struct platform_device *pdev)
+{
+	struct m2mtest_dev *dev =
+		(struct m2mtest_dev *)platform_get_drvdata(pdev);
+
+	v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_TEST_MODULE_NAME);
+	v4l2_m2m_release(dev->m2m_dev);
+	del_timer_sync(&dev->timer);
+	video_unregister_device(dev->vfd);
+	v4l2_device_unregister(&dev->v4l2_dev);
+	kfree(dev);
+
+	return 0;
+}
+
+static struct platform_driver m2mtest_pdrv = {
+	.probe		= m2mtest_probe,
+	.remove		= m2mtest_remove,
+	.driver		= {
+		.name	= MEM2MEM_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static void __exit m2mtest_exit(void)
+{
+	platform_driver_unregister(&m2mtest_pdrv);
+	platform_device_unregister(&m2mtest_pdev);
+}
+
+static int __init m2mtest_init(void)
+{
+	int ret;
+
+	ret = platform_device_register(&m2mtest_pdev);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&m2mtest_pdrv);
+	if (ret)
+		platform_device_unregister(&m2mtest_pdev);
+
+	return 0;
+}
+
+module_init(m2mtest_init);
+module_exit(m2mtest_exit);
+
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 4404e5e..2be23bc 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -30,9 +30,10 @@
 #include <linux/pci.h>
 #include <linux/sched.h>
 #include <linux/init.h>
-#include <linux/videodev.h>
 #include <linux/gfp.h>
+#include <linux/videodev2.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -1168,22 +1169,22 @@
 	case V4L2_CID_BRIGHTNESS:
 		sony_pic_camera_command(
 			SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, c->value);
-		meye.picture.brightness = c->value << 10;
+		meye.brightness = c->value << 10;
 		break;
 	case V4L2_CID_HUE:
 		sony_pic_camera_command(
 			SONY_PIC_COMMAND_SETCAMERAHUE, c->value);
-		meye.picture.hue = c->value << 10;
+		meye.hue = c->value << 10;
 		break;
 	case V4L2_CID_CONTRAST:
 		sony_pic_camera_command(
 			SONY_PIC_COMMAND_SETCAMERACONTRAST, c->value);
-		meye.picture.contrast = c->value << 10;
+		meye.contrast = c->value << 10;
 		break;
 	case V4L2_CID_SATURATION:
 		sony_pic_camera_command(
 			SONY_PIC_COMMAND_SETCAMERACOLOR, c->value);
-		meye.picture.colour = c->value << 10;
+		meye.colour = c->value << 10;
 		break;
 	case V4L2_CID_AGC:
 		sony_pic_camera_command(
@@ -1221,16 +1222,16 @@
 	mutex_lock(&meye.lock);
 	switch (c->id) {
 	case V4L2_CID_BRIGHTNESS:
-		c->value = meye.picture.brightness >> 10;
+		c->value = meye.brightness >> 10;
 		break;
 	case V4L2_CID_HUE:
-		c->value = meye.picture.hue >> 10;
+		c->value = meye.hue >> 10;
 		break;
 	case V4L2_CID_CONTRAST:
-		c->value = meye.picture.contrast >> 10;
+		c->value = meye.contrast >> 10;
 		break;
 	case V4L2_CID_SATURATION:
-		c->value = meye.picture.colour >> 10;
+		c->value = meye.colour >> 10;
 		break;
 	case V4L2_CID_AGC:
 		c->value = meye.params.agc;
@@ -1729,6 +1730,7 @@
 static int __devinit meye_probe(struct pci_dev *pcidev,
 				const struct pci_device_id *ent)
 {
+	struct v4l2_device *v4l2_dev = &meye.v4l2_dev;
 	int ret = -EBUSY;
 	unsigned long mchip_adr;
 
@@ -1737,70 +1739,75 @@
 		goto outnotdev;
 	}
 
+	ret = v4l2_device_register(&pcidev->dev, v4l2_dev);
+	if (ret < 0) {
+		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+		return ret;
+	}
 	ret = -ENOMEM;
 	meye.mchip_dev = pcidev;
-	meye.video_dev = video_device_alloc();
-	if (!meye.video_dev) {
-		printk(KERN_ERR "meye: video_device_alloc() failed!\n");
+	meye.vdev = video_device_alloc();
+	if (!meye.vdev) {
+		v4l2_err(v4l2_dev, "video_device_alloc() failed!\n");
 		goto outnotdev;
 	}
 
 	meye.grab_temp = vmalloc(MCHIP_NB_PAGES_MJPEG * PAGE_SIZE);
 	if (!meye.grab_temp) {
-		printk(KERN_ERR "meye: grab buffer allocation failed\n");
+		v4l2_err(v4l2_dev, "grab buffer allocation failed\n");
 		goto outvmalloc;
 	}
 
 	spin_lock_init(&meye.grabq_lock);
 	if (kfifo_alloc(&meye.grabq, sizeof(int) * MEYE_MAX_BUFNBRS,
 				GFP_KERNEL)) {
-		printk(KERN_ERR "meye: fifo allocation failed\n");
+		v4l2_err(v4l2_dev, "fifo allocation failed\n");
 		goto outkfifoalloc1;
 	}
 	spin_lock_init(&meye.doneq_lock);
 	if (kfifo_alloc(&meye.doneq, sizeof(int) * MEYE_MAX_BUFNBRS,
 				GFP_KERNEL)) {
-		printk(KERN_ERR "meye: fifo allocation failed\n");
+		v4l2_err(v4l2_dev, "fifo allocation failed\n");
 		goto outkfifoalloc2;
 	}
 
-	memcpy(meye.video_dev, &meye_template, sizeof(meye_template));
-	meye.video_dev->parent = &meye.mchip_dev->dev;
+	memcpy(meye.vdev, &meye_template, sizeof(meye_template));
+	meye.vdev->v4l2_dev = &meye.v4l2_dev;
 
 	ret = -EIO;
 	if ((ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1))) {
-		printk(KERN_ERR "meye: unable to power on the camera\n");
-		printk(KERN_ERR "meye: did you enable the camera in "
+		v4l2_err(v4l2_dev, "meye: unable to power on the camera\n");
+		v4l2_err(v4l2_dev, "meye: did you enable the camera in "
 				"sonypi using the module options ?\n");
 		goto outsonypienable;
 	}
 
 	if ((ret = pci_enable_device(meye.mchip_dev))) {
-		printk(KERN_ERR "meye: pci_enable_device failed\n");
+		v4l2_err(v4l2_dev, "meye: pci_enable_device failed\n");
 		goto outenabledev;
 	}
 
 	mchip_adr = pci_resource_start(meye.mchip_dev,0);
 	if (!mchip_adr) {
-		printk(KERN_ERR "meye: mchip has no device base address\n");
+		v4l2_err(v4l2_dev, "meye: mchip has no device base address\n");
 		goto outregions;
 	}
 	if (!request_mem_region(pci_resource_start(meye.mchip_dev, 0),
 				pci_resource_len(meye.mchip_dev, 0),
 				"meye")) {
-		printk(KERN_ERR "meye: request_mem_region failed\n");
+		v4l2_err(v4l2_dev, "meye: request_mem_region failed\n");
 		goto outregions;
 	}
 	meye.mchip_mmregs = ioremap(mchip_adr, MCHIP_MM_REGS);
 	if (!meye.mchip_mmregs) {
-		printk(KERN_ERR "meye: ioremap failed\n");
+		v4l2_err(v4l2_dev, "meye: ioremap failed\n");
 		goto outremap;
 	}
 
 	meye.mchip_irq = pcidev->irq;
 	if (request_irq(meye.mchip_irq, meye_irq,
 			IRQF_DISABLED | IRQF_SHARED, "meye", meye_irq)) {
-		printk(KERN_ERR "meye: request_irq failed\n");
+		v4l2_err(v4l2_dev, "request_irq failed\n");
 		goto outreqirq;
 	}
 
@@ -1824,21 +1831,18 @@
 	msleep(1);
 	mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK);
 
-	if (video_register_device(meye.video_dev, VFL_TYPE_GRABBER,
+	if (video_register_device(meye.vdev, VFL_TYPE_GRABBER,
 				  video_nr) < 0) {
-		printk(KERN_ERR "meye: video_register_device failed\n");
+		v4l2_err(v4l2_dev, "video_register_device failed\n");
 		goto outvideoreg;
 	}
 
 	mutex_init(&meye.lock);
 	init_waitqueue_head(&meye.proc_list);
-	meye.picture.depth = 16;
-	meye.picture.palette = VIDEO_PALETTE_YUV422;
-	meye.picture.brightness = 32 << 10;
-	meye.picture.hue = 32 << 10;
-	meye.picture.colour = 32 << 10;
-	meye.picture.contrast = 32 << 10;
-	meye.picture.whiteness = 0;
+	meye.brightness = 32 << 10;
+	meye.hue = 32 << 10;
+	meye.colour = 32 << 10;
+	meye.contrast = 32 << 10;
 	meye.params.subsample = 0;
 	meye.params.quality = 8;
 	meye.params.sharpness = 32;
@@ -1854,9 +1858,9 @@
 	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, 0);
 	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, 48);
 
-	printk(KERN_INFO "meye: Motion Eye Camera Driver v%s.\n",
+	v4l2_info(v4l2_dev, "Motion Eye Camera Driver v%s.\n",
 	       MEYE_DRIVER_VERSION);
-	printk(KERN_INFO "meye: mchip KL5A72002 rev. %d, base %lx, irq %d\n",
+	v4l2_info(v4l2_dev, "mchip KL5A72002 rev. %d, base %lx, irq %d\n",
 	       meye.mchip_dev->revision, mchip_adr, meye.mchip_irq);
 
 	return 0;
@@ -1879,14 +1883,14 @@
 outkfifoalloc1:
 	vfree(meye.grab_temp);
 outvmalloc:
-	video_device_release(meye.video_dev);
+	video_device_release(meye.vdev);
 outnotdev:
 	return ret;
 }
 
 static void __devexit meye_remove(struct pci_dev *pcidev)
 {
-	video_unregister_device(meye.video_dev);
+	video_unregister_device(meye.vdev);
 
 	mchip_hic_stop();
 
diff --git a/drivers/media/video/meye.h b/drivers/media/video/meye.h
index 1321ad5..4bdeb03 100644
--- a/drivers/media/video/meye.h
+++ b/drivers/media/video/meye.h
@@ -31,7 +31,7 @@
 #define _MEYE_PRIV_H_
 
 #define MEYE_DRIVER_MAJORVERSION	 1
-#define MEYE_DRIVER_MINORVERSION	13
+#define MEYE_DRIVER_MINORVERSION	14
 
 #define MEYE_DRIVER_VERSION __stringify(MEYE_DRIVER_MAJORVERSION) "." \
 			    __stringify(MEYE_DRIVER_MINORVERSION)
@@ -289,6 +289,7 @@
 
 /* Motion Eye device structure */
 struct meye {
+	struct v4l2_device v4l2_dev;	/* Main v4l2_device struct */
 	struct pci_dev *mchip_dev;	/* pci device */
 	u8 mchip_irq;			/* irq */
 	u8 mchip_mode;			/* actual mchip mode: HIC_MODE... */
@@ -308,8 +309,11 @@
 	struct kfifo doneq;		/* queue for grabbed buffers */
 	spinlock_t doneq_lock;		/* lock protecting the queue */
 	wait_queue_head_t proc_list;	/* wait queue */
-	struct video_device *video_dev;	/* video device parameters */
-	struct video_picture picture;	/* video picture parameters */
+	struct video_device *vdev;	/* video device parameters */
+	u16 brightness;
+	u16 hue;
+	u16 contrast;
+	u16 colour;
 	struct meye_params params;	/* additional parameters */
 	unsigned long in_use;		/* set to 1 if the device is in use */
 #ifdef CONFIG_PM
diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c
index a9061bf..78b4e09 100644
--- a/drivers/media/video/mt9t031.c
+++ b/drivers/media/video/mt9t031.c
@@ -8,14 +8,16 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/videodev2.h>
-#include <linux/slab.h>
+#include <linux/device.h>
 #include <linux/i2c.h>
 #include <linux/log2.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
 
-#include <media/v4l2-subdev.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/soc_camera.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-subdev.h>
 
 /*
  * mt9t031 i2c address 0x5d
@@ -681,12 +683,66 @@
 }
 
 /*
+ * Power Management:
+ * This function does nothing for now but must be present for pm to work
+ */
+static int mt9t031_runtime_suspend(struct device *dev)
+{
+	return 0;
+}
+
+/*
+ * Power Management:
+ * COLUMN_ADDRESS_MODE and ROW_ADDRESS_MODE are not rewritten if unchanged
+ * they are however changed at reset if the platform hook is present
+ * thus we rewrite them with the values stored by the driver
+ */
+static int mt9t031_runtime_resume(struct device *dev)
+{
+	struct video_device *vdev = to_video_device(dev);
+	struct soc_camera_device *icd = container_of(vdev->parent,
+		struct soc_camera_device, dev);
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct i2c_client *client = sd->priv;
+	struct mt9t031 *mt9t031 = to_mt9t031(client);
+
+	int ret;
+	u16 xbin, ybin;
+
+	xbin = min(mt9t031->xskip, (u16)3);
+	ybin = min(mt9t031->yskip, (u16)3);
+
+	ret = reg_write(client, MT9T031_COLUMN_ADDRESS_MODE,
+		((xbin - 1) << 4) | (mt9t031->xskip - 1));
+	if (ret < 0)
+		return ret;
+
+	ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE,
+		((ybin - 1) << 4) | (mt9t031->yskip - 1));
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct dev_pm_ops mt9t031_dev_pm_ops = {
+	.runtime_suspend	= mt9t031_runtime_suspend,
+	.runtime_resume		= mt9t031_runtime_resume,
+};
+
+static struct device_type mt9t031_dev_type = {
+	.name	= "MT9T031",
+	.pm	= &mt9t031_dev_pm_ops,
+};
+
+/*
  * Interface active, can use i2c. If it fails, it can indeed mean, that
  * this wasn't our capture interface, so, we wait for the right one
  */
 static int mt9t031_video_probe(struct i2c_client *client)
 {
 	struct mt9t031 *mt9t031 = to_mt9t031(client);
+	struct video_device *vdev = soc_camera_i2c_to_vdev(client);
 	s32 data;
 	int ret;
 
@@ -712,6 +768,8 @@
 	ret = mt9t031_idle(client);
 	if (ret < 0)
 		dev_err(&client->dev, "Failed to initialise the camera\n");
+	else
+		vdev->dev.type = &mt9t031_dev_type;
 
 	/* mt9t031_idle() has reset the chip to default. */
 	mt9t031->exposure = 255;
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index 1a34d29..e5bae4c 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -325,7 +325,7 @@
 	if (ret < 0)
 		return ret;
 
-	dev_dbg(&client->dev, "Frame %ux%u pixel\n", rect.width, rect.height);
+	dev_dbg(&client->dev, "Frame %dx%d pixel\n", rect.width, rect.height);
 
 	mt9v022->rect = rect;
 
diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c
index 34a6601..5c17f9e 100644
--- a/drivers/media/video/mx1_camera.c
+++ b/drivers/media/video/mx1_camera.c
@@ -139,8 +139,8 @@
 	if (!*count)
 		*count = 32;
 
-	while (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
-		(*count)--;
+	if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
+		*count = (MAX_VIDEO_MEM * 1024 * 1024) / *size;
 
 	dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size);
 
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c
index bd297f5..d477e30 100644
--- a/drivers/media/video/mx3_camera.c
+++ b/drivers/media/video/mx3_camera.c
@@ -796,7 +796,7 @@
  * FIXME: learn to use stride != width, then we can keep stride properly aligned
  * and support arbitrary (even) widths.
  */
-static inline void stride_align(__s32 *width)
+static inline void stride_align(__u32 *width)
 {
 	if (((*width + 7) &  ~7) < 4096)
 		*width = (*width + 7) &  ~7;
@@ -844,7 +844,7 @@
 		 * So far only direct camera-to-memory is supported
 		 */
 		if (channel_change_requested(icd, rect)) {
-			int ret = acquire_dma_channel(mx3_cam);
+			ret = acquire_dma_channel(mx3_cam);
 			if (ret < 0)
 				return ret;
 		}
diff --git a/drivers/media/video/omap/Kconfig b/drivers/media/video/omap/Kconfig
new file mode 100644
index 0000000..97c53949
--- /dev/null
+++ b/drivers/media/video/omap/Kconfig
@@ -0,0 +1,11 @@
+config VIDEO_OMAP2_VOUT
+	tristate "OMAP2/OMAP3 V4L2-Display driver"
+	depends on ARCH_OMAP24XX || ARCH_OMAP34XX
+	select VIDEOBUF_GEN
+	select VIDEOBUF_DMA_SG
+	select OMAP2_DSS
+	select OMAP2_VRAM
+	select OMAP2_VRFB
+	default n
+	---help---
+	  V4L2 Display driver support for OMAP2/3 based boards.
diff --git a/drivers/media/video/omap/Makefile b/drivers/media/video/omap/Makefile
new file mode 100644
index 0000000..b8bab00
--- /dev/null
+++ b/drivers/media/video/omap/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the omap video device drivers.
+#
+
+# OMAP2/3 Display driver
+omap-vout-mod-objs := omap_vout.o omap_voutlib.o
+obj-$(CONFIG_VIDEO_OMAP2_VOUT) += omap-vout-mod.o
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c
new file mode 100644
index 0000000..4c0ab49
--- /dev/null
+++ b/drivers/media/video/omap/omap_vout.c
@@ -0,0 +1,2643 @@
+/*
+ * omap_vout.c
+ *
+ * Copyright (C) 2005-2010 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * Leveraged code from the OMAP2 camera driver
+ * Video-for-Linux (Version 2) camera capture driver for
+ * the OMAP24xx camera controller.
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * History:
+ * 20-APR-2006 Khasim		Modified VRFB based Rotation,
+ *				The image data is always read from 0 degree
+ *				view and written
+ *				to the virtual space of desired rotation angle
+ * 4-DEC-2006  Jian		Changed to support better memory management
+ *
+ * 17-Nov-2008 Hardik		Changed driver to use video_ioctl2
+ *
+ * 23-Feb-2010 Vaibhav H	Modified to use new DSS2 interface
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/irq.h>
+#include <linux/videodev2.h>
+
+#include <media/videobuf-dma-sg.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+
+#include <plat/dma.h>
+#include <plat/vram.h>
+#include <plat/vrfb.h>
+#include <plat/display.h>
+
+#include "omap_voutlib.h"
+#include "omap_voutdef.h"
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("OMAP Video for Linux Video out driver");
+MODULE_LICENSE("GPL");
+
+
+/* Driver Configuration macros */
+#define VOUT_NAME		"omap_vout"
+
+enum omap_vout_channels {
+	OMAP_VIDEO1,
+	OMAP_VIDEO2,
+};
+
+enum dma_channel_state {
+	DMA_CHAN_NOT_ALLOTED,
+	DMA_CHAN_ALLOTED,
+};
+
+#define QQVGA_WIDTH		160
+#define QQVGA_HEIGHT		120
+
+/* Max Resolution supported by the driver */
+#define VID_MAX_WIDTH		1280	/* Largest width */
+#define VID_MAX_HEIGHT		720	/* Largest height */
+
+/* Mimimum requirement is 2x2 for DSS */
+#define VID_MIN_WIDTH		2
+#define VID_MIN_HEIGHT		2
+
+/* 2048 x 2048 is max res supported by OMAP display controller */
+#define MAX_PIXELS_PER_LINE     2048
+
+#define VRFB_TX_TIMEOUT         1000
+#define VRFB_NUM_BUFS		4
+
+/* Max buffer size tobe allocated during init */
+#define OMAP_VOUT_MAX_BUF_SIZE (VID_MAX_WIDTH*VID_MAX_HEIGHT*4)
+
+static struct videobuf_queue_ops video_vbq_ops;
+/* Variables configurable through module params*/
+static u32 video1_numbuffers = 3;
+static u32 video2_numbuffers = 3;
+static u32 video1_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
+static u32 video2_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
+static u32 vid1_static_vrfb_alloc;
+static u32 vid2_static_vrfb_alloc;
+static int debug;
+
+/* Module parameters */
+module_param(video1_numbuffers, uint, S_IRUGO);
+MODULE_PARM_DESC(video1_numbuffers,
+	"Number of buffers to be allocated at init time for Video1 device.");
+
+module_param(video2_numbuffers, uint, S_IRUGO);
+MODULE_PARM_DESC(video2_numbuffers,
+	"Number of buffers to be allocated at init time for Video2 device.");
+
+module_param(video1_bufsize, uint, S_IRUGO);
+MODULE_PARM_DESC(video1_bufsize,
+	"Size of the buffer to be allocated for video1 device");
+
+module_param(video2_bufsize, uint, S_IRUGO);
+MODULE_PARM_DESC(video2_bufsize,
+	"Size of the buffer to be allocated for video2 device");
+
+module_param(vid1_static_vrfb_alloc, bool, S_IRUGO);
+MODULE_PARM_DESC(vid1_static_vrfb_alloc,
+	"Static allocation of the VRFB buffer for video1 device");
+
+module_param(vid2_static_vrfb_alloc, bool, S_IRUGO);
+MODULE_PARM_DESC(vid2_static_vrfb_alloc,
+	"Static allocation of the VRFB buffer for video2 device");
+
+module_param(debug, bool, S_IRUGO);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+/* list of image formats supported by OMAP2 video pipelines */
+const static struct v4l2_fmtdesc omap_formats[] = {
+	{
+		/* Note:  V4L2 defines RGB565 as:
+		 *
+		 *      Byte 0                    Byte 1
+		 *      g2 g1 g0 r4 r3 r2 r1 r0   b4 b3 b2 b1 b0 g5 g4 g3
+		 *
+		 * We interpret RGB565 as:
+		 *
+		 *      Byte 0                    Byte 1
+		 *      g2 g1 g0 b4 b3 b2 b1 b0   r4 r3 r2 r1 r0 g5 g4 g3
+		 */
+		.description = "RGB565, le",
+		.pixelformat = V4L2_PIX_FMT_RGB565,
+	},
+	{
+		/* Note:  V4L2 defines RGB32 as: RGB-8-8-8-8  we use
+		 *  this for RGB24 unpack mode, the last 8 bits are ignored
+		 * */
+		.description = "RGB32, le",
+		.pixelformat = V4L2_PIX_FMT_RGB32,
+	},
+	{
+		/* Note:  V4L2 defines RGB24 as: RGB-8-8-8  we use
+		 *        this for RGB24 packed mode
+		 *
+		 */
+		.description = "RGB24, le",
+		.pixelformat = V4L2_PIX_FMT_RGB24,
+	},
+	{
+		.description = "YUYV (YUV 4:2:2), packed",
+		.pixelformat = V4L2_PIX_FMT_YUYV,
+	},
+	{
+		.description = "UYVY, packed",
+		.pixelformat = V4L2_PIX_FMT_UYVY,
+	},
+};
+
+#define NUM_OUTPUT_FORMATS (ARRAY_SIZE(omap_formats))
+
+/*
+ * Allocate buffers
+ */
+static unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr)
+{
+	u32 order, size;
+	unsigned long virt_addr, addr;
+
+	size = PAGE_ALIGN(buf_size);
+	order = get_order(size);
+	virt_addr = __get_free_pages(GFP_KERNEL | GFP_DMA, order);
+	addr = virt_addr;
+
+	if (virt_addr) {
+		while (size > 0) {
+			SetPageReserved(virt_to_page(addr));
+			addr += PAGE_SIZE;
+			size -= PAGE_SIZE;
+		}
+	}
+	*phys_addr = (u32) virt_to_phys((void *) virt_addr);
+	return virt_addr;
+}
+
+/*
+ * Free buffers
+ */
+static void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size)
+{
+	u32 order, size;
+	unsigned long addr = virtaddr;
+
+	size = PAGE_ALIGN(buf_size);
+	order = get_order(size);
+
+	while (size > 0) {
+		ClearPageReserved(virt_to_page(addr));
+		addr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+	free_pages((unsigned long) virtaddr, order);
+}
+
+/*
+ * Function for allocating video buffers
+ */
+static int omap_vout_allocate_vrfb_buffers(struct omap_vout_device *vout,
+		unsigned int *count, int startindex)
+{
+	int i, j;
+
+	for (i = 0; i < *count; i++) {
+		if (!vout->smsshado_virt_addr[i]) {
+			vout->smsshado_virt_addr[i] =
+				omap_vout_alloc_buffer(vout->smsshado_size,
+						&vout->smsshado_phy_addr[i]);
+		}
+		if (!vout->smsshado_virt_addr[i] && startindex != -1) {
+			if (V4L2_MEMORY_MMAP == vout->memory && i >= startindex)
+				break;
+		}
+		if (!vout->smsshado_virt_addr[i]) {
+			for (j = 0; j < i; j++) {
+				omap_vout_free_buffer(
+						vout->smsshado_virt_addr[j],
+						vout->smsshado_size);
+				vout->smsshado_virt_addr[j] = 0;
+				vout->smsshado_phy_addr[j] = 0;
+			}
+			*count = 0;
+			return -ENOMEM;
+		}
+		memset((void *) vout->smsshado_virt_addr[i], 0,
+				vout->smsshado_size);
+	}
+	return 0;
+}
+
+/*
+ * Try format
+ */
+static int omap_vout_try_format(struct v4l2_pix_format *pix)
+{
+	int ifmt, bpp = 0;
+
+	pix->height = clamp(pix->height, (u32)VID_MIN_HEIGHT,
+						(u32)VID_MAX_HEIGHT);
+	pix->width = clamp(pix->width, (u32)VID_MIN_WIDTH, (u32)VID_MAX_WIDTH);
+
+	for (ifmt = 0; ifmt < NUM_OUTPUT_FORMATS; ifmt++) {
+		if (pix->pixelformat == omap_formats[ifmt].pixelformat)
+			break;
+	}
+
+	if (ifmt == NUM_OUTPUT_FORMATS)
+		ifmt = 0;
+
+	pix->pixelformat = omap_formats[ifmt].pixelformat;
+	pix->field = V4L2_FIELD_ANY;
+	pix->priv = 0;
+
+	switch (pix->pixelformat) {
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_UYVY:
+	default:
+		pix->colorspace = V4L2_COLORSPACE_JPEG;
+		bpp = YUYV_BPP;
+		break;
+	case V4L2_PIX_FMT_RGB565:
+	case V4L2_PIX_FMT_RGB565X:
+		pix->colorspace = V4L2_COLORSPACE_SRGB;
+		bpp = RGB565_BPP;
+		break;
+	case V4L2_PIX_FMT_RGB24:
+		pix->colorspace = V4L2_COLORSPACE_SRGB;
+		bpp = RGB24_BPP;
+		break;
+	case V4L2_PIX_FMT_RGB32:
+	case V4L2_PIX_FMT_BGR32:
+		pix->colorspace = V4L2_COLORSPACE_SRGB;
+		bpp = RGB32_BPP;
+		break;
+	}
+	pix->bytesperline = pix->width * bpp;
+	pix->sizeimage = pix->bytesperline * pix->height;
+
+	return bpp;
+}
+
+/*
+ * omap_vout_uservirt_to_phys: This inline function is used to convert user
+ * space virtual address to physical address.
+ */
+static u32 omap_vout_uservirt_to_phys(u32 virtp)
+{
+	unsigned long physp = 0;
+	struct vm_area_struct *vma;
+	struct mm_struct *mm = current->mm;
+
+	vma = find_vma(mm, virtp);
+	/* For kernel direct-mapped memory, take the easy way */
+	if (virtp >= PAGE_OFFSET) {
+		physp = virt_to_phys((void *) virtp);
+	} else if (vma && (vma->vm_flags & VM_IO) && vma->vm_pgoff) {
+		/* this will catch, kernel-allocated, mmaped-to-usermode
+		   addresses */
+		physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start);
+	} else {
+		/* otherwise, use get_user_pages() for general userland pages */
+		int res, nr_pages = 1;
+		struct page *pages;
+		down_read(&current->mm->mmap_sem);
+
+		res = get_user_pages(current, current->mm, virtp, nr_pages, 1,
+				0, &pages, NULL);
+		up_read(&current->mm->mmap_sem);
+
+		if (res == nr_pages) {
+			physp =  __pa(page_address(&pages[0]) +
+					(virtp & ~PAGE_MASK));
+		} else {
+			printk(KERN_WARNING VOUT_NAME
+					"get_user_pages failed\n");
+			return 0;
+		}
+	}
+
+	return physp;
+}
+
+/*
+ * Wakes up the application once the DMA transfer to VRFB space is completed.
+ */
+static void omap_vout_vrfb_dma_tx_callback(int lch, u16 ch_status, void *data)
+{
+	struct vid_vrfb_dma *t = (struct vid_vrfb_dma *) data;
+
+	t->tx_status = 1;
+	wake_up_interruptible(&t->wait);
+}
+
+/*
+ * Release the VRFB context once the module exits
+ */
+static void omap_vout_release_vrfb(struct omap_vout_device *vout)
+{
+	int i;
+
+	for (i = 0; i < VRFB_NUM_BUFS; i++)
+		omap_vrfb_release_ctx(&vout->vrfb_context[i]);
+
+	if (vout->vrfb_dma_tx.req_status == DMA_CHAN_ALLOTED) {
+		vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
+		omap_free_dma(vout->vrfb_dma_tx.dma_ch);
+	}
+}
+
+/*
+ * Return true if rotation is 90 or 270
+ */
+static inline int rotate_90_or_270(const struct omap_vout_device *vout)
+{
+	return (vout->rotation == dss_rotation_90_degree ||
+			vout->rotation == dss_rotation_270_degree);
+}
+
+/*
+ * Return true if rotation is enabled
+ */
+static inline int rotation_enabled(const struct omap_vout_device *vout)
+{
+	return vout->rotation || vout->mirror;
+}
+
+/*
+ * Reverse the rotation degree if mirroring is enabled
+ */
+static inline int calc_rotation(const struct omap_vout_device *vout)
+{
+	if (!vout->mirror)
+		return vout->rotation;
+
+	switch (vout->rotation) {
+	case dss_rotation_90_degree:
+		return dss_rotation_270_degree;
+	case dss_rotation_270_degree:
+		return dss_rotation_90_degree;
+	case dss_rotation_180_degree:
+		return dss_rotation_0_degree;
+	default:
+		return dss_rotation_180_degree;
+	}
+}
+
+/*
+ * Free the V4L2 buffers
+ */
+static void omap_vout_free_buffers(struct omap_vout_device *vout)
+{
+	int i, numbuffers;
+
+	/* Allocate memory for the buffers */
+	numbuffers = (vout->vid) ?  video2_numbuffers : video1_numbuffers;
+	vout->buffer_size = (vout->vid) ? video2_bufsize : video1_bufsize;
+
+	for (i = 0; i < numbuffers; i++) {
+		omap_vout_free_buffer(vout->buf_virt_addr[i],
+				vout->buffer_size);
+		vout->buf_phy_addr[i] = 0;
+		vout->buf_virt_addr[i] = 0;
+	}
+}
+
+/*
+ * Free VRFB buffers
+ */
+static void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout)
+{
+	int j;
+
+	for (j = 0; j < VRFB_NUM_BUFS; j++) {
+		omap_vout_free_buffer(vout->smsshado_virt_addr[j],
+				vout->smsshado_size);
+		vout->smsshado_virt_addr[j] = 0;
+		vout->smsshado_phy_addr[j] = 0;
+	}
+}
+
+/*
+ * Allocate the buffers for the VRFB space.  Data is copied from V4L2
+ * buffers to the VRFB buffers using the DMA engine.
+ */
+static int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
+			  unsigned int *count, unsigned int startindex)
+{
+	int i;
+	bool yuv_mode;
+
+	/* Allocate the VRFB buffers only if the buffers are not
+	 * allocated during init time.
+	 */
+	if ((rotation_enabled(vout)) && !vout->vrfb_static_allocation)
+		if (omap_vout_allocate_vrfb_buffers(vout, count, startindex))
+			return -ENOMEM;
+
+	if (vout->dss_mode == OMAP_DSS_COLOR_YUV2 ||
+			vout->dss_mode == OMAP_DSS_COLOR_UYVY)
+		yuv_mode = true;
+	else
+		yuv_mode = false;
+
+	for (i = 0; i < *count; i++)
+		omap_vrfb_setup(&vout->vrfb_context[i],
+				vout->smsshado_phy_addr[i], vout->pix.width,
+				vout->pix.height, vout->bpp, yuv_mode);
+
+	return 0;
+}
+
+/*
+ * Convert V4L2 rotation to DSS rotation
+ *	V4L2 understand 0, 90, 180, 270.
+ *	Convert to 0, 1, 2 and 3 repsectively for DSS
+ */
+static int v4l2_rot_to_dss_rot(int v4l2_rotation,
+			enum dss_rotation *rotation, bool mirror)
+{
+	int ret = 0;
+
+	switch (v4l2_rotation) {
+	case 90:
+		*rotation = dss_rotation_90_degree;
+		break;
+	case 180:
+		*rotation = dss_rotation_180_degree;
+		break;
+	case 270:
+		*rotation = dss_rotation_270_degree;
+		break;
+	case 0:
+		*rotation = dss_rotation_0_degree;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+/*
+ * Calculate the buffer offsets from which the streaming should
+ * start. This offset calculation is mainly required because of
+ * the VRFB 32 pixels alignment with rotation.
+ */
+static int omap_vout_calculate_offset(struct omap_vout_device *vout)
+{
+	struct omap_overlay *ovl;
+	enum dss_rotation rotation;
+	struct omapvideo_info *ovid;
+	bool mirroring = vout->mirror;
+	struct omap_dss_device *cur_display;
+	struct v4l2_rect *crop = &vout->crop;
+	struct v4l2_pix_format *pix = &vout->pix;
+	int *cropped_offset = &vout->cropped_offset;
+	int vr_ps = 1, ps = 2, temp_ps = 2;
+	int offset = 0, ctop = 0, cleft = 0, line_length = 0;
+
+	ovid = &vout->vid_info;
+	ovl = ovid->overlays[0];
+	/* get the display device attached to the overlay */
+	if (!ovl->manager || !ovl->manager->device)
+		return -1;
+
+	cur_display = ovl->manager->device;
+	rotation = calc_rotation(vout);
+
+	if (V4L2_PIX_FMT_YUYV == pix->pixelformat ||
+			V4L2_PIX_FMT_UYVY == pix->pixelformat) {
+		if (rotation_enabled(vout)) {
+			/*
+			 * ps    - Actual pixel size for YUYV/UYVY for
+			 *         VRFB/Mirroring is 4 bytes
+			 * vr_ps - Virtually pixel size for YUYV/UYVY is
+			 *         2 bytes
+			 */
+			ps = 4;
+			vr_ps = 2;
+		} else {
+			ps = 2;	/* otherwise the pixel size is 2 byte */
+		}
+	} else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat) {
+		ps = 4;
+	} else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat) {
+		ps = 3;
+	}
+	vout->ps = ps;
+	vout->vr_ps = vr_ps;
+
+	if (rotation_enabled(vout)) {
+		line_length = MAX_PIXELS_PER_LINE;
+		ctop = (pix->height - crop->height) - crop->top;
+		cleft = (pix->width - crop->width) - crop->left;
+	} else {
+		line_length = pix->width;
+	}
+	vout->line_length = line_length;
+	switch (rotation) {
+	case dss_rotation_90_degree:
+		offset = vout->vrfb_context[0].yoffset *
+			vout->vrfb_context[0].bytespp;
+		temp_ps = ps / vr_ps;
+		if (mirroring == 0) {
+			*cropped_offset = offset + line_length *
+				temp_ps * cleft + crop->top * temp_ps;
+		} else {
+			*cropped_offset = offset + line_length * temp_ps *
+				cleft + crop->top * temp_ps + (line_length *
+				((crop->width / (vr_ps)) - 1) * ps);
+		}
+		break;
+	case dss_rotation_180_degree:
+		offset = ((MAX_PIXELS_PER_LINE * vout->vrfb_context[0].yoffset *
+			vout->vrfb_context[0].bytespp) +
+			(vout->vrfb_context[0].xoffset *
+			vout->vrfb_context[0].bytespp));
+		if (mirroring == 0) {
+			*cropped_offset = offset + (line_length * ps * ctop) +
+				(cleft / vr_ps) * ps;
+
+		} else {
+			*cropped_offset = offset + (line_length * ps * ctop) +
+				(cleft / vr_ps) * ps + (line_length *
+				(crop->height - 1) * ps);
+		}
+		break;
+	case dss_rotation_270_degree:
+		offset = MAX_PIXELS_PER_LINE * vout->vrfb_context[0].xoffset *
+			vout->vrfb_context[0].bytespp;
+		temp_ps = ps / vr_ps;
+		if (mirroring == 0) {
+			*cropped_offset = offset + line_length *
+			    temp_ps * crop->left + ctop * ps;
+		} else {
+			*cropped_offset = offset + line_length *
+				temp_ps * crop->left + ctop * ps +
+				(line_length * ((crop->width / vr_ps) - 1) *
+				 ps);
+		}
+		break;
+	case dss_rotation_0_degree:
+		if (mirroring == 0) {
+			*cropped_offset = (line_length * ps) *
+				crop->top + (crop->left / vr_ps) * ps;
+		} else {
+			*cropped_offset = (line_length * ps) *
+				crop->top + (crop->left / vr_ps) * ps +
+				(line_length * (crop->height - 1) * ps);
+		}
+		break;
+	default:
+		*cropped_offset = (line_length * ps * crop->top) /
+			vr_ps + (crop->left * ps) / vr_ps +
+			((crop->width / vr_ps) - 1) * ps;
+		break;
+	}
+	v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "%s Offset:%x\n",
+			__func__, *cropped_offset);
+	return 0;
+}
+
+/*
+ * Convert V4L2 pixel format to DSS pixel format
+ */
+static int video_mode_to_dss_mode(struct omap_vout_device *vout)
+{
+	struct omap_overlay *ovl;
+	struct omapvideo_info *ovid;
+	struct v4l2_pix_format *pix = &vout->pix;
+	enum omap_color_mode mode;
+
+	ovid = &vout->vid_info;
+	ovl = ovid->overlays[0];
+
+	switch (pix->pixelformat) {
+	case 0:
+		break;
+	case V4L2_PIX_FMT_YUYV:
+		mode = OMAP_DSS_COLOR_YUV2;
+		break;
+	case V4L2_PIX_FMT_UYVY:
+		mode = OMAP_DSS_COLOR_UYVY;
+		break;
+	case V4L2_PIX_FMT_RGB565:
+		mode = OMAP_DSS_COLOR_RGB16;
+		break;
+	case V4L2_PIX_FMT_RGB24:
+		mode = OMAP_DSS_COLOR_RGB24P;
+		break;
+	case V4L2_PIX_FMT_RGB32:
+		mode = (ovl->id == OMAP_DSS_VIDEO1) ?
+			OMAP_DSS_COLOR_RGB24U : OMAP_DSS_COLOR_ARGB32;
+		break;
+	case V4L2_PIX_FMT_BGR32:
+		mode = OMAP_DSS_COLOR_RGBX32;
+		break;
+	default:
+		mode = -EINVAL;
+	}
+	return mode;
+}
+
+/*
+ * Setup the overlay
+ */
+int omapvid_setup_overlay(struct omap_vout_device *vout,
+		struct omap_overlay *ovl, int posx, int posy, int outw,
+		int outh, u32 addr)
+{
+	int ret = 0;
+	struct omap_overlay_info info;
+	int cropheight, cropwidth, pixheight, pixwidth;
+
+	if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0 &&
+			(outw != vout->pix.width || outh != vout->pix.height)) {
+		ret = -EINVAL;
+		goto setup_ovl_err;
+	}
+
+	vout->dss_mode = video_mode_to_dss_mode(vout);
+	if (vout->dss_mode == -EINVAL) {
+		ret = -EINVAL;
+		goto setup_ovl_err;
+	}
+
+	/* Setup the input plane parameters according to
+	 * rotation value selected.
+	 */
+	if (rotate_90_or_270(vout)) {
+		cropheight = vout->crop.width;
+		cropwidth = vout->crop.height;
+		pixheight = vout->pix.width;
+		pixwidth = vout->pix.height;
+	} else {
+		cropheight = vout->crop.height;
+		cropwidth = vout->crop.width;
+		pixheight = vout->pix.height;
+		pixwidth = vout->pix.width;
+	}
+
+	ovl->get_overlay_info(ovl, &info);
+	info.paddr = addr;
+	info.vaddr = NULL;
+	info.width = cropwidth;
+	info.height = cropheight;
+	info.color_mode = vout->dss_mode;
+	info.mirror = vout->mirror;
+	info.pos_x = posx;
+	info.pos_y = posy;
+	info.out_width = outw;
+	info.out_height = outh;
+	info.global_alpha = vout->win.global_alpha;
+	if (!rotation_enabled(vout)) {
+		info.rotation = 0;
+		info.rotation_type = OMAP_DSS_ROT_DMA;
+		info.screen_width = pixwidth;
+	} else {
+		info.rotation = vout->rotation;
+		info.rotation_type = OMAP_DSS_ROT_VRFB;
+		info.screen_width = 2048;
+	}
+
+	v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
+		"%s enable=%d addr=%x width=%d\n height=%d color_mode=%d\n"
+		"rotation=%d mirror=%d posx=%d posy=%d out_width = %d \n"
+		"out_height=%d rotation_type=%d screen_width=%d\n",
+		__func__, info.enabled, info.paddr, info.width, info.height,
+		info.color_mode, info.rotation, info.mirror, info.pos_x,
+		info.pos_y, info.out_width, info.out_height, info.rotation_type,
+		info.screen_width);
+
+	ret = ovl->set_overlay_info(ovl, &info);
+	if (ret)
+		goto setup_ovl_err;
+
+	return 0;
+
+setup_ovl_err:
+	v4l2_warn(&vout->vid_dev->v4l2_dev, "setup_overlay failed\n");
+	return ret;
+}
+
+/*
+ * Initialize the overlay structure
+ */
+int omapvid_init(struct omap_vout_device *vout, u32 addr)
+{
+	int ret = 0, i;
+	struct v4l2_window *win;
+	struct omap_overlay *ovl;
+	int posx, posy, outw, outh, temp;
+	struct omap_video_timings *timing;
+	struct omapvideo_info *ovid = &vout->vid_info;
+
+	win = &vout->win;
+	for (i = 0; i < ovid->num_overlays; i++) {
+		ovl = ovid->overlays[i];
+		if (!ovl->manager || !ovl->manager->device)
+			return -EINVAL;
+
+		timing = &ovl->manager->device->panel.timings;
+
+		outw = win->w.width;
+		outh = win->w.height;
+		switch (vout->rotation) {
+		case dss_rotation_90_degree:
+			/* Invert the height and width for 90
+			 * and 270 degree rotation
+			 */
+			temp = outw;
+			outw = outh;
+			outh = temp;
+			posy = (timing->y_res - win->w.width) - win->w.left;
+			posx = win->w.top;
+			break;
+
+		case dss_rotation_180_degree:
+			posx = (timing->x_res - win->w.width) - win->w.left;
+			posy = (timing->y_res - win->w.height) - win->w.top;
+			break;
+
+		case dss_rotation_270_degree:
+			temp = outw;
+			outw = outh;
+			outh = temp;
+			posy = win->w.left;
+			posx = (timing->x_res - win->w.height) - win->w.top;
+			break;
+
+		default:
+			posx = win->w.left;
+			posy = win->w.top;
+			break;
+		}
+
+		ret = omapvid_setup_overlay(vout, ovl, posx, posy,
+				outw, outh, addr);
+		if (ret)
+			goto omapvid_init_err;
+	}
+	return 0;
+
+omapvid_init_err:
+	v4l2_warn(&vout->vid_dev->v4l2_dev, "apply_changes failed\n");
+	return ret;
+}
+
+/*
+ * Apply the changes set the go bit of DSS
+ */
+int omapvid_apply_changes(struct omap_vout_device *vout)
+{
+	int i;
+	struct omap_overlay *ovl;
+	struct omapvideo_info *ovid = &vout->vid_info;
+
+	for (i = 0; i < ovid->num_overlays; i++) {
+		ovl = ovid->overlays[i];
+		if (!ovl->manager || !ovl->manager->device)
+			return -EINVAL;
+		ovl->manager->apply(ovl->manager);
+	}
+
+	return 0;
+}
+
+void omap_vout_isr(void *arg, unsigned int irqstatus)
+{
+	int ret;
+	u32 addr, fid;
+	struct omap_overlay *ovl;
+	struct timeval timevalue;
+	struct omapvideo_info *ovid;
+	struct omap_dss_device *cur_display;
+	struct omap_vout_device *vout = (struct omap_vout_device *)arg;
+
+	if (!vout->streaming)
+		return;
+
+	ovid = &vout->vid_info;
+	ovl = ovid->overlays[0];
+	/* get the display device attached to the overlay */
+	if (!ovl->manager || !ovl->manager->device)
+		return;
+
+	cur_display = ovl->manager->device;
+
+	spin_lock(&vout->vbq_lock);
+	do_gettimeofday(&timevalue);
+	if (cur_display->type == OMAP_DISPLAY_TYPE_DPI) {
+		if (!(irqstatus & DISPC_IRQ_VSYNC))
+			goto vout_isr_err;
+
+		if (!vout->first_int && (vout->cur_frm != vout->next_frm)) {
+			vout->cur_frm->ts = timevalue;
+			vout->cur_frm->state = VIDEOBUF_DONE;
+			wake_up_interruptible(&vout->cur_frm->done);
+			vout->cur_frm = vout->next_frm;
+		}
+		vout->first_int = 0;
+		if (list_empty(&vout->dma_queue))
+			goto vout_isr_err;
+
+		vout->next_frm = list_entry(vout->dma_queue.next,
+				struct videobuf_buffer, queue);
+		list_del(&vout->next_frm->queue);
+
+		vout->next_frm->state = VIDEOBUF_ACTIVE;
+
+		addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i]
+			+ vout->cropped_offset;
+
+		/* First save the configuration in ovelray structure */
+		ret = omapvid_init(vout, addr);
+		if (ret)
+			printk(KERN_ERR VOUT_NAME
+					"failed to set overlay info\n");
+		/* Enable the pipeline and set the Go bit */
+		ret = omapvid_apply_changes(vout);
+		if (ret)
+			printk(KERN_ERR VOUT_NAME "failed to change mode\n");
+	} else {
+
+		if (vout->first_int) {
+			vout->first_int = 0;
+			goto vout_isr_err;
+		}
+		if (irqstatus & DISPC_IRQ_EVSYNC_ODD)
+			fid = 1;
+		else if (irqstatus & DISPC_IRQ_EVSYNC_EVEN)
+			fid = 0;
+		else
+			goto vout_isr_err;
+
+		vout->field_id ^= 1;
+		if (fid != vout->field_id) {
+			if (0 == fid)
+				vout->field_id = fid;
+
+			goto vout_isr_err;
+		}
+		if (0 == fid) {
+			if (vout->cur_frm == vout->next_frm)
+				goto vout_isr_err;
+
+			vout->cur_frm->ts = timevalue;
+			vout->cur_frm->state = VIDEOBUF_DONE;
+			wake_up_interruptible(&vout->cur_frm->done);
+			vout->cur_frm = vout->next_frm;
+		} else if (1 == fid) {
+			if (list_empty(&vout->dma_queue) ||
+					(vout->cur_frm != vout->next_frm))
+				goto vout_isr_err;
+
+			vout->next_frm = list_entry(vout->dma_queue.next,
+					struct videobuf_buffer, queue);
+			list_del(&vout->next_frm->queue);
+
+			vout->next_frm->state = VIDEOBUF_ACTIVE;
+			addr = (unsigned long)
+				vout->queued_buf_addr[vout->next_frm->i] +
+				vout->cropped_offset;
+			/* First save the configuration in ovelray structure */
+			ret = omapvid_init(vout, addr);
+			if (ret)
+				printk(KERN_ERR VOUT_NAME
+						"failed to set overlay info\n");
+			/* Enable the pipeline and set the Go bit */
+			ret = omapvid_apply_changes(vout);
+			if (ret)
+				printk(KERN_ERR VOUT_NAME
+						"failed to change mode\n");
+		}
+
+	}
+
+vout_isr_err:
+	spin_unlock(&vout->vbq_lock);
+}
+
+
+/* Video buffer call backs */
+
+/*
+ * Buffer setup function is called by videobuf layer when REQBUF ioctl is
+ * called. This is used to setup buffers and return size and count of
+ * buffers allocated. After the call to this buffer, videobuf layer will
+ * setup buffer queue depending on the size and count of buffers
+ */
+static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
+			  unsigned int *size)
+{
+	int startindex = 0, i, j;
+	u32 phy_addr = 0, virt_addr = 0;
+	struct omap_vout_device *vout = q->priv_data;
+
+	if (!vout)
+		return -EINVAL;
+
+	if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type)
+		return -EINVAL;
+
+	startindex = (vout->vid == OMAP_VIDEO1) ?
+		video1_numbuffers : video2_numbuffers;
+	if (V4L2_MEMORY_MMAP == vout->memory && *count < startindex)
+		*count = startindex;
+
+	if ((rotation_enabled(vout)) && *count > VRFB_NUM_BUFS)
+		*count = VRFB_NUM_BUFS;
+
+	/* If rotation is enabled, allocate memory for VRFB space also */
+	if (rotation_enabled(vout))
+		if (omap_vout_vrfb_buffer_setup(vout, count, startindex))
+			return -ENOMEM;
+
+	if (V4L2_MEMORY_MMAP != vout->memory)
+		return 0;
+
+	/* Now allocated the V4L2 buffers */
+	*size = PAGE_ALIGN(vout->pix.width * vout->pix.height * vout->bpp);
+	startindex = (vout->vid == OMAP_VIDEO1) ?
+		video1_numbuffers : video2_numbuffers;
+
+	for (i = startindex; i < *count; i++) {
+		vout->buffer_size = *size;
+
+		virt_addr = omap_vout_alloc_buffer(vout->buffer_size,
+				&phy_addr);
+		if (!virt_addr) {
+			if (!rotation_enabled(vout))
+				break;
+			/* Free the VRFB buffers if no space for V4L2 buffers */
+			for (j = i; j < *count; j++) {
+				omap_vout_free_buffer(
+						vout->smsshado_virt_addr[j],
+						vout->smsshado_size);
+				vout->smsshado_virt_addr[j] = 0;
+				vout->smsshado_phy_addr[j] = 0;
+			}
+		}
+		vout->buf_virt_addr[i] = virt_addr;
+		vout->buf_phy_addr[i] = phy_addr;
+	}
+	*count = vout->buffer_allocated = i;
+
+	return 0;
+}
+
+/*
+ * Free the V4L2 buffers additionally allocated than default
+ * number of buffers and free all the VRFB buffers
+ */
+static void omap_vout_free_allbuffers(struct omap_vout_device *vout)
+{
+	int num_buffers = 0, i;
+
+	num_buffers = (vout->vid == OMAP_VIDEO1) ?
+		video1_numbuffers : video2_numbuffers;
+
+	for (i = num_buffers; i < vout->buffer_allocated; i++) {
+		if (vout->buf_virt_addr[i])
+			omap_vout_free_buffer(vout->buf_virt_addr[i],
+					vout->buffer_size);
+
+		vout->buf_virt_addr[i] = 0;
+		vout->buf_phy_addr[i] = 0;
+	}
+	/* Free the VRFB buffers only if they are allocated
+	 * during reqbufs.  Don't free if init time allocated
+	 */
+	if (!vout->vrfb_static_allocation) {
+		for (i = 0; i < VRFB_NUM_BUFS; i++) {
+			if (vout->smsshado_virt_addr[i]) {
+				omap_vout_free_buffer(
+						vout->smsshado_virt_addr[i],
+						vout->smsshado_size);
+				vout->smsshado_virt_addr[i] = 0;
+				vout->smsshado_phy_addr[i] = 0;
+			}
+		}
+	}
+	vout->buffer_allocated = num_buffers;
+}
+
+/*
+ * This function will be called when VIDIOC_QBUF ioctl is called.
+ * It prepare buffers before give out for the display. This function
+ * converts user space virtual address into physical address if userptr memory
+ * exchange mechanism is used. If rotation is enabled, it copies entire
+ * buffer into VRFB memory space before giving it to the DSS.
+ */
+static int omap_vout_buffer_prepare(struct videobuf_queue *q,
+			    struct videobuf_buffer *vb,
+			    enum v4l2_field field)
+{
+	struct vid_vrfb_dma *tx;
+	enum dss_rotation rotation;
+	struct videobuf_dmabuf *dmabuf = NULL;
+	struct omap_vout_device *vout = q->priv_data;
+	u32 dest_frame_index = 0, src_element_index = 0;
+	u32 dest_element_index = 0, src_frame_index = 0;
+	u32 elem_count = 0, frame_count = 0, pixsize = 2;
+
+	if (VIDEOBUF_NEEDS_INIT == vb->state) {
+		vb->width = vout->pix.width;
+		vb->height = vout->pix.height;
+		vb->size = vb->width * vb->height * vout->bpp;
+		vb->field = field;
+	}
+	vb->state = VIDEOBUF_PREPARED;
+	/* if user pointer memory mechanism is used, get the physical
+	 * address of the buffer
+	 */
+	if (V4L2_MEMORY_USERPTR == vb->memory) {
+		if (0 == vb->baddr)
+			return -EINVAL;
+		/* Virtual address */
+		/* priv points to struct videobuf_pci_sg_memory. But we went
+		 * pointer to videobuf_dmabuf, which is member of
+		 * videobuf_pci_sg_memory */
+		dmabuf = videobuf_to_dma(q->bufs[vb->i]);
+		dmabuf->vmalloc = (void *) vb->baddr;
+
+		/* Physical address */
+		dmabuf->bus_addr =
+			(dma_addr_t) omap_vout_uservirt_to_phys(vb->baddr);
+	}
+
+	if (!rotation_enabled(vout)) {
+		dmabuf = videobuf_to_dma(q->bufs[vb->i]);
+		vout->queued_buf_addr[vb->i] = (u8 *) dmabuf->bus_addr;
+		return 0;
+	}
+	dmabuf = videobuf_to_dma(q->bufs[vb->i]);
+	/* If rotation is enabled, copy input buffer into VRFB
+	 * memory space using DMA. We are copying input buffer
+	 * into VRFB memory space of desired angle and DSS will
+	 * read image VRFB memory for 0 degree angle
+	 */
+	pixsize = vout->bpp * vout->vrfb_bpp;
+	/*
+	 * DMA transfer in double index mode
+	 */
+
+	/* Frame index */
+	dest_frame_index = ((MAX_PIXELS_PER_LINE * pixsize) -
+			(vout->pix.width * vout->bpp)) + 1;
+
+	/* Source and destination parameters */
+	src_element_index = 0;
+	src_frame_index = 0;
+	dest_element_index = 1;
+	/* Number of elements per frame */
+	elem_count = vout->pix.width * vout->bpp;
+	frame_count = vout->pix.height;
+	tx = &vout->vrfb_dma_tx;
+	tx->tx_status = 0;
+	omap_set_dma_transfer_params(tx->dma_ch, OMAP_DMA_DATA_TYPE_S32,
+			(elem_count / 4), frame_count, OMAP_DMA_SYNC_ELEMENT,
+			tx->dev_id, 0x0);
+	/* src_port required only for OMAP1 */
+	omap_set_dma_src_params(tx->dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
+			dmabuf->bus_addr, src_element_index, src_frame_index);
+	/*set dma source burst mode for VRFB */
+	omap_set_dma_src_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16);
+	rotation = calc_rotation(vout);
+
+	/* dest_port required only for OMAP1 */
+	omap_set_dma_dest_params(tx->dma_ch, 0, OMAP_DMA_AMODE_DOUBLE_IDX,
+			vout->vrfb_context[vb->i].paddr[0], dest_element_index,
+			dest_frame_index);
+	/*set dma dest burst mode for VRFB */
+	omap_set_dma_dest_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16);
+	omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE, 0x20, 0);
+
+	omap_start_dma(tx->dma_ch);
+	interruptible_sleep_on_timeout(&tx->wait, VRFB_TX_TIMEOUT);
+
+	if (tx->tx_status == 0) {
+		omap_stop_dma(tx->dma_ch);
+		return -EINVAL;
+	}
+	/* Store buffers physical address into an array. Addresses
+	 * from this array will be used to configure DSS */
+	vout->queued_buf_addr[vb->i] = (u8 *)
+		vout->vrfb_context[vb->i].paddr[rotation];
+	return 0;
+}
+
+/*
+ * Buffer queue funtion will be called from the videobuf layer when _QBUF
+ * ioctl is called. It is used to enqueue buffer, which is ready to be
+ * displayed.
+ */
+static void omap_vout_buffer_queue(struct videobuf_queue *q,
+			  struct videobuf_buffer *vb)
+{
+	struct omap_vout_device *vout = q->priv_data;
+
+	/* Driver is also maintainig a queue. So enqueue buffer in the driver
+	 * queue */
+	list_add_tail(&vb->queue, &vout->dma_queue);
+
+	vb->state = VIDEOBUF_QUEUED;
+}
+
+/*
+ * Buffer release function is called from videobuf layer to release buffer
+ * which are already allocated
+ */
+static void omap_vout_buffer_release(struct videobuf_queue *q,
+			    struct videobuf_buffer *vb)
+{
+	struct omap_vout_device *vout = q->priv_data;
+
+	vb->state = VIDEOBUF_NEEDS_INIT;
+
+	if (V4L2_MEMORY_MMAP != vout->memory)
+		return;
+}
+
+/*
+ *  File operations
+ */
+static void omap_vout_vm_open(struct vm_area_struct *vma)
+{
+	struct omap_vout_device *vout = vma->vm_private_data;
+
+	v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
+		"vm_open [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
+	vout->mmap_count++;
+}
+
+static void omap_vout_vm_close(struct vm_area_struct *vma)
+{
+	struct omap_vout_device *vout = vma->vm_private_data;
+
+	v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
+		"vm_close [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
+	vout->mmap_count--;
+}
+
+static struct vm_operations_struct omap_vout_vm_ops = {
+	.open	= omap_vout_vm_open,
+	.close	= omap_vout_vm_close,
+};
+
+static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	int i;
+	void *pos;
+	unsigned long start = vma->vm_start;
+	unsigned long size = (vma->vm_end - vma->vm_start);
+	struct videobuf_dmabuf *dmabuf = NULL;
+	struct omap_vout_device *vout = file->private_data;
+	struct videobuf_queue *q = &vout->vbq;
+
+	v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
+			" %s pgoff=0x%lx, start=0x%lx, end=0x%lx\n", __func__,
+			vma->vm_pgoff, vma->vm_start, vma->vm_end);
+
+	/* look for the buffer to map */
+	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+		if (NULL == q->bufs[i])
+			continue;
+		if (V4L2_MEMORY_MMAP != q->bufs[i]->memory)
+			continue;
+		if (q->bufs[i]->boff == (vma->vm_pgoff << PAGE_SHIFT))
+			break;
+	}
+
+	if (VIDEO_MAX_FRAME == i) {
+		v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
+				"offset invalid [offset=0x%lx]\n",
+				(vma->vm_pgoff << PAGE_SHIFT));
+		return -EINVAL;
+	}
+	q->bufs[i]->baddr = vma->vm_start;
+
+	vma->vm_flags |= VM_RESERVED;
+	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+	vma->vm_ops = &omap_vout_vm_ops;
+	vma->vm_private_data = (void *) vout;
+	dmabuf = videobuf_to_dma(q->bufs[i]);
+	pos = dmabuf->vmalloc;
+	vma->vm_pgoff = virt_to_phys((void *)pos) >> PAGE_SHIFT;
+	while (size > 0) {
+		unsigned long pfn;
+		pfn = virt_to_phys((void *) pos) >> PAGE_SHIFT;
+		if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED))
+			return -EAGAIN;
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+	vout->mmap_count++;
+	v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
+
+	return 0;
+}
+
+static int omap_vout_release(struct file *file)
+{
+	unsigned int ret, i;
+	struct videobuf_queue *q;
+	struct omapvideo_info *ovid;
+	struct omap_vout_device *vout = file->private_data;
+
+	v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__);
+	ovid = &vout->vid_info;
+
+	if (!vout)
+		return 0;
+
+	q = &vout->vbq;
+	/* Disable all the overlay managers connected with this interface */
+	for (i = 0; i < ovid->num_overlays; i++) {
+		struct omap_overlay *ovl = ovid->overlays[i];
+		if (ovl->manager && ovl->manager->device) {
+			struct omap_overlay_info info;
+			ovl->get_overlay_info(ovl, &info);
+			info.enabled = 0;
+			ovl->set_overlay_info(ovl, &info);
+		}
+	}
+	/* Turn off the pipeline */
+	ret = omapvid_apply_changes(vout);
+	if (ret)
+		v4l2_warn(&vout->vid_dev->v4l2_dev,
+				"Unable to apply changes\n");
+
+	/* Free all buffers */
+	omap_vout_free_allbuffers(vout);
+	videobuf_mmap_free(q);
+
+	/* Even if apply changes fails we should continue
+	   freeing allocated memeory */
+	if (vout->streaming) {
+		u32 mask = 0;
+
+		mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN |
+			DISPC_IRQ_EVSYNC_ODD;
+		omap_dispc_unregister_isr(omap_vout_isr, vout, mask);
+		vout->streaming = 0;
+
+		videobuf_streamoff(q);
+		videobuf_queue_cancel(q);
+	}
+
+	if (vout->mmap_count != 0)
+		vout->mmap_count = 0;
+
+	vout->opened -= 1;
+	file->private_data = NULL;
+
+	if (vout->buffer_allocated)
+		videobuf_mmap_free(q);
+
+	v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
+	return ret;
+}
+
+static int omap_vout_open(struct file *file)
+{
+	struct videobuf_queue *q;
+	struct omap_vout_device *vout = NULL;
+
+	vout = video_drvdata(file);
+	v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__);
+
+	if (vout == NULL)
+		return -ENODEV;
+
+	/* for now, we only support single open */
+	if (vout->opened)
+		return -EBUSY;
+
+	vout->opened += 1;
+
+	file->private_data = vout;
+	vout->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
+	q = &vout->vbq;
+	video_vbq_ops.buf_setup = omap_vout_buffer_setup;
+	video_vbq_ops.buf_prepare = omap_vout_buffer_prepare;
+	video_vbq_ops.buf_release = omap_vout_buffer_release;
+	video_vbq_ops.buf_queue = omap_vout_buffer_queue;
+	spin_lock_init(&vout->vbq_lock);
+
+	videobuf_queue_sg_init(q, &video_vbq_ops, NULL, &vout->vbq_lock,
+			vout->type, V4L2_FIELD_NONE,
+			sizeof(struct videobuf_buffer), vout);
+
+	v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
+	return 0;
+}
+
+/*
+ * V4L2 ioctls
+ */
+static int vidioc_querycap(struct file *file, void *fh,
+		struct v4l2_capability *cap)
+{
+	struct omap_vout_device *vout = fh;
+
+	strlcpy(cap->driver, VOUT_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, vout->vfd->name, sizeof(cap->card));
+	cap->bus_info[0] = '\0';
+	cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT;
+
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *fh,
+			struct v4l2_fmtdesc *fmt)
+{
+	int index = fmt->index;
+	enum v4l2_buf_type type = fmt->type;
+
+	fmt->index = index;
+	fmt->type = type;
+	if (index >= NUM_OUTPUT_FORMATS)
+		return -EINVAL;
+
+	fmt->flags = omap_formats[index].flags;
+	strlcpy(fmt->description, omap_formats[index].description,
+			sizeof(fmt->description));
+	fmt->pixelformat = omap_formats[index].pixelformat;
+
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_out(struct file *file, void *fh,
+			struct v4l2_format *f)
+{
+	struct omap_vout_device *vout = fh;
+
+	f->fmt.pix = vout->pix;
+	return 0;
+
+}
+
+static int vidioc_try_fmt_vid_out(struct file *file, void *fh,
+			struct v4l2_format *f)
+{
+	struct omap_overlay *ovl;
+	struct omapvideo_info *ovid;
+	struct omap_video_timings *timing;
+	struct omap_vout_device *vout = fh;
+
+	ovid = &vout->vid_info;
+	ovl = ovid->overlays[0];
+
+	if (!ovl->manager || !ovl->manager->device)
+		return -EINVAL;
+	/* get the display device attached to the overlay */
+	timing = &ovl->manager->device->panel.timings;
+
+	vout->fbuf.fmt.height = timing->y_res;
+	vout->fbuf.fmt.width = timing->x_res;
+
+	omap_vout_try_format(&f->fmt.pix);
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_out(struct file *file, void *fh,
+			struct v4l2_format *f)
+{
+	int ret, bpp;
+	struct omap_overlay *ovl;
+	struct omapvideo_info *ovid;
+	struct omap_video_timings *timing;
+	struct omap_vout_device *vout = fh;
+
+	if (vout->streaming)
+		return -EBUSY;
+
+	mutex_lock(&vout->lock);
+
+	ovid = &vout->vid_info;
+	ovl = ovid->overlays[0];
+
+	/* get the display device attached to the overlay */
+	if (!ovl->manager || !ovl->manager->device) {
+		ret = -EINVAL;
+		goto s_fmt_vid_out_exit;
+	}
+	timing = &ovl->manager->device->panel.timings;
+
+	/* We dont support RGB24-packed mode if vrfb rotation
+	 * is enabled*/
+	if ((rotation_enabled(vout)) &&
+			f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) {
+		ret = -EINVAL;
+		goto s_fmt_vid_out_exit;
+	}
+
+	/* get the framebuffer parameters */
+
+	if (rotate_90_or_270(vout)) {
+		vout->fbuf.fmt.height = timing->x_res;
+		vout->fbuf.fmt.width = timing->y_res;
+	} else {
+		vout->fbuf.fmt.height = timing->y_res;
+		vout->fbuf.fmt.width = timing->x_res;
+	}
+
+	/* change to samller size is OK */
+
+	bpp = omap_vout_try_format(&f->fmt.pix);
+	f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height * bpp;
+
+	/* try & set the new output format */
+	vout->bpp = bpp;
+	vout->pix = f->fmt.pix;
+	vout->vrfb_bpp = 1;
+
+	/* If YUYV then vrfb bpp is 2, for  others its 1 */
+	if (V4L2_PIX_FMT_YUYV == vout->pix.pixelformat ||
+			V4L2_PIX_FMT_UYVY == vout->pix.pixelformat)
+		vout->vrfb_bpp = 2;
+
+	/* set default crop and win */
+	omap_vout_new_format(&vout->pix, &vout->fbuf, &vout->crop, &vout->win);
+
+	/* Save the changes in the overlay strcuture */
+	ret = omapvid_init(vout, 0);
+	if (ret) {
+		v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode\n");
+		goto s_fmt_vid_out_exit;
+	}
+
+	ret = 0;
+
+s_fmt_vid_out_exit:
+	mutex_unlock(&vout->lock);
+	return ret;
+}
+
+static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh,
+			struct v4l2_format *f)
+{
+	int ret = 0;
+	struct omap_vout_device *vout = fh;
+	struct v4l2_window *win = &f->fmt.win;
+
+	ret = omap_vout_try_window(&vout->fbuf, win);
+
+	if (!ret) {
+		if (vout->vid == OMAP_VIDEO1)
+			win->global_alpha = 255;
+		else
+			win->global_alpha = f->fmt.win.global_alpha;
+	}
+
+	return ret;
+}
+
+static int vidioc_s_fmt_vid_overlay(struct file *file, void *fh,
+			struct v4l2_format *f)
+{
+	int ret = 0;
+	struct omap_overlay *ovl;
+	struct omapvideo_info *ovid;
+	struct omap_vout_device *vout = fh;
+	struct v4l2_window *win = &f->fmt.win;
+
+	mutex_lock(&vout->lock);
+	ovid = &vout->vid_info;
+	ovl = ovid->overlays[0];
+
+	ret = omap_vout_new_window(&vout->crop, &vout->win, &vout->fbuf, win);
+	if (!ret) {
+		/* Video1 plane does not support global alpha */
+		if (ovl->id == OMAP_DSS_VIDEO1)
+			vout->win.global_alpha = 255;
+		else
+			vout->win.global_alpha = f->fmt.win.global_alpha;
+
+		vout->win.chromakey = f->fmt.win.chromakey;
+	}
+	mutex_unlock(&vout->lock);
+	return ret;
+}
+
+static int vidioc_enum_fmt_vid_overlay(struct file *file, void *fh,
+			struct v4l2_fmtdesc *fmt)
+{
+	int index = fmt->index;
+	enum v4l2_buf_type type = fmt->type;
+
+	fmt->index = index;
+	fmt->type = type;
+	if (index >= NUM_OUTPUT_FORMATS)
+		return -EINVAL;
+
+	fmt->flags = omap_formats[index].flags;
+	strlcpy(fmt->description, omap_formats[index].description,
+			sizeof(fmt->description));
+	fmt->pixelformat = omap_formats[index].pixelformat;
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh,
+			struct v4l2_format *f)
+{
+	u32 key_value =  0;
+	struct omap_overlay *ovl;
+	struct omapvideo_info *ovid;
+	struct omap_vout_device *vout = fh;
+	struct omap_overlay_manager_info info;
+	struct v4l2_window *win = &f->fmt.win;
+
+	ovid = &vout->vid_info;
+	ovl = ovid->overlays[0];
+
+	win->w = vout->win.w;
+	win->field = vout->win.field;
+	win->global_alpha = vout->win.global_alpha;
+
+	if (ovl->manager && ovl->manager->get_manager_info) {
+		ovl->manager->get_manager_info(ovl->manager, &info);
+		key_value = info.trans_key;
+	}
+	win->chromakey = key_value;
+	return 0;
+}
+
+static int vidioc_cropcap(struct file *file, void *fh,
+		struct v4l2_cropcap *cropcap)
+{
+	struct omap_vout_device *vout = fh;
+	struct v4l2_pix_format *pix = &vout->pix;
+
+	if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+
+	/* Width and height are always even */
+	cropcap->bounds.width = pix->width & ~1;
+	cropcap->bounds.height = pix->height & ~1;
+
+	omap_vout_default_crop(&vout->pix, &vout->fbuf, &cropcap->defrect);
+	cropcap->pixelaspect.numerator = 1;
+	cropcap->pixelaspect.denominator = 1;
+	return 0;
+}
+
+static int vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+	struct omap_vout_device *vout = fh;
+
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+	crop->c = vout->crop;
+	return 0;
+}
+
+static int vidioc_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+	int ret = -EINVAL;
+	struct omap_vout_device *vout = fh;
+	struct omapvideo_info *ovid;
+	struct omap_overlay *ovl;
+	struct omap_video_timings *timing;
+
+	if (vout->streaming)
+		return -EBUSY;
+
+	mutex_lock(&vout->lock);
+	ovid = &vout->vid_info;
+	ovl = ovid->overlays[0];
+
+	if (!ovl->manager || !ovl->manager->device) {
+		ret = -EINVAL;
+		goto s_crop_err;
+	}
+	/* get the display device attached to the overlay */
+	timing = &ovl->manager->device->panel.timings;
+
+	if (rotate_90_or_270(vout)) {
+		vout->fbuf.fmt.height = timing->x_res;
+		vout->fbuf.fmt.width = timing->y_res;
+	} else {
+		vout->fbuf.fmt.height = timing->y_res;
+		vout->fbuf.fmt.width = timing->x_res;
+	}
+
+	if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		ret = omap_vout_new_crop(&vout->pix, &vout->crop, &vout->win,
+				&vout->fbuf, &crop->c);
+
+s_crop_err:
+	mutex_unlock(&vout->lock);
+	return ret;
+}
+
+static int vidioc_queryctrl(struct file *file, void *fh,
+		struct v4l2_queryctrl *ctrl)
+{
+	int ret = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_ROTATE:
+		ret = v4l2_ctrl_query_fill(ctrl, 0, 270, 90, 0);
+		break;
+	case V4L2_CID_BG_COLOR:
+		ret = v4l2_ctrl_query_fill(ctrl, 0, 0xFFFFFF, 1, 0);
+		break;
+	case V4L2_CID_VFLIP:
+		ret = v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0);
+		break;
+	default:
+		ctrl->name[0] = '\0';
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl)
+{
+	int ret = 0;
+	struct omap_vout_device *vout = fh;
+
+	switch (ctrl->id) {
+	case V4L2_CID_ROTATE:
+		ctrl->value = vout->control[0].value;
+		break;
+	case V4L2_CID_BG_COLOR:
+	{
+		struct omap_overlay_manager_info info;
+		struct omap_overlay *ovl;
+
+		ovl = vout->vid_info.overlays[0];
+		if (!ovl->manager || !ovl->manager->get_manager_info) {
+			ret = -EINVAL;
+			break;
+		}
+
+		ovl->manager->get_manager_info(ovl->manager, &info);
+		ctrl->value = info.default_color;
+		break;
+	}
+	case V4L2_CID_VFLIP:
+		ctrl->value = vout->control[2].value;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
+{
+	int ret = 0;
+	struct omap_vout_device *vout = fh;
+
+	switch (a->id) {
+	case V4L2_CID_ROTATE:
+	{
+		int rotation = a->value;
+
+		mutex_lock(&vout->lock);
+
+		if (rotation && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) {
+			mutex_unlock(&vout->lock);
+			ret = -EINVAL;
+			break;
+		}
+
+		if (v4l2_rot_to_dss_rot(rotation, &vout->rotation,
+							vout->mirror)) {
+			mutex_unlock(&vout->lock);
+			ret = -EINVAL;
+			break;
+		}
+
+		vout->control[0].value = rotation;
+		mutex_unlock(&vout->lock);
+		break;
+	}
+	case V4L2_CID_BG_COLOR:
+	{
+		struct omap_overlay *ovl;
+		unsigned int  color = a->value;
+		struct omap_overlay_manager_info info;
+
+		ovl = vout->vid_info.overlays[0];
+
+		mutex_lock(&vout->lock);
+		if (!ovl->manager || !ovl->manager->get_manager_info) {
+			mutex_unlock(&vout->lock);
+			ret = -EINVAL;
+			break;
+		}
+
+		ovl->manager->get_manager_info(ovl->manager, &info);
+		info.default_color = color;
+		if (ovl->manager->set_manager_info(ovl->manager, &info)) {
+			mutex_unlock(&vout->lock);
+			ret = -EINVAL;
+			break;
+		}
+
+		vout->control[1].value = color;
+		mutex_unlock(&vout->lock);
+		break;
+	}
+	case V4L2_CID_VFLIP:
+	{
+		struct omap_overlay *ovl;
+		struct omapvideo_info *ovid;
+		unsigned int  mirror = a->value;
+
+		ovid = &vout->vid_info;
+		ovl = ovid->overlays[0];
+
+		mutex_lock(&vout->lock);
+
+		if (mirror  && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) {
+			mutex_unlock(&vout->lock);
+			ret = -EINVAL;
+			break;
+		}
+		vout->mirror = mirror;
+		vout->control[2].value = mirror;
+		mutex_unlock(&vout->lock);
+		break;
+	}
+	default:
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static int vidioc_reqbufs(struct file *file, void *fh,
+			struct v4l2_requestbuffers *req)
+{
+	int ret = 0;
+	unsigned int i, num_buffers = 0;
+	struct omap_vout_device *vout = fh;
+	struct videobuf_queue *q = &vout->vbq;
+	struct videobuf_dmabuf *dmabuf = NULL;
+
+	if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) || (req->count < 0))
+		return -EINVAL;
+	/* if memory is not mmp or userptr
+	   return error */
+	if ((V4L2_MEMORY_MMAP != req->memory) &&
+			(V4L2_MEMORY_USERPTR != req->memory))
+		return -EINVAL;
+
+	mutex_lock(&vout->lock);
+	/* Cannot be requested when streaming is on */
+	if (vout->streaming) {
+		ret = -EBUSY;
+		goto reqbuf_err;
+	}
+
+	/* If buffers are already allocated free them */
+	if (q->bufs[0] && (V4L2_MEMORY_MMAP == q->bufs[0]->memory)) {
+		if (vout->mmap_count) {
+			ret = -EBUSY;
+			goto reqbuf_err;
+		}
+		num_buffers = (vout->vid == OMAP_VIDEO1) ?
+			video1_numbuffers : video2_numbuffers;
+		for (i = num_buffers; i < vout->buffer_allocated; i++) {
+			dmabuf = videobuf_to_dma(q->bufs[i]);
+			omap_vout_free_buffer((u32)dmabuf->vmalloc,
+					vout->buffer_size);
+			vout->buf_virt_addr[i] = 0;
+			vout->buf_phy_addr[i] = 0;
+		}
+		vout->buffer_allocated = num_buffers;
+		videobuf_mmap_free(q);
+	} else if (q->bufs[0] && (V4L2_MEMORY_USERPTR == q->bufs[0]->memory)) {
+		if (vout->buffer_allocated) {
+			videobuf_mmap_free(q);
+			for (i = 0; i < vout->buffer_allocated; i++) {
+				kfree(q->bufs[i]);
+				q->bufs[i] = NULL;
+			}
+			vout->buffer_allocated = 0;
+		}
+	}
+
+	/*store the memory type in data structure */
+	vout->memory = req->memory;
+
+	INIT_LIST_HEAD(&vout->dma_queue);
+
+	/* call videobuf_reqbufs api */
+	ret = videobuf_reqbufs(q, req);
+	if (ret < 0)
+		goto reqbuf_err;
+
+	vout->buffer_allocated = req->count;
+	for (i = 0; i < req->count; i++) {
+		dmabuf = videobuf_to_dma(q->bufs[i]);
+		dmabuf->vmalloc = (void *) vout->buf_virt_addr[i];
+		dmabuf->bus_addr = (dma_addr_t) vout->buf_phy_addr[i];
+		dmabuf->sglen = 1;
+	}
+reqbuf_err:
+	mutex_unlock(&vout->lock);
+	return ret;
+}
+
+static int vidioc_querybuf(struct file *file, void *fh,
+			struct v4l2_buffer *b)
+{
+	struct omap_vout_device *vout = fh;
+
+	return videobuf_querybuf(&vout->vbq, b);
+}
+
+static int vidioc_qbuf(struct file *file, void *fh,
+			struct v4l2_buffer *buffer)
+{
+	struct omap_vout_device *vout = fh;
+	struct videobuf_queue *q = &vout->vbq;
+
+	if ((V4L2_BUF_TYPE_VIDEO_OUTPUT != buffer->type) ||
+			(buffer->index >= vout->buffer_allocated) ||
+			(q->bufs[buffer->index]->memory != buffer->memory)) {
+		return -EINVAL;
+	}
+	if (V4L2_MEMORY_USERPTR == buffer->memory) {
+		if ((buffer->length < vout->pix.sizeimage) ||
+				(0 == buffer->m.userptr)) {
+			return -EINVAL;
+		}
+	}
+
+	if ((rotation_enabled(vout)) &&
+			vout->vrfb_dma_tx.req_status == DMA_CHAN_NOT_ALLOTED) {
+		v4l2_warn(&vout->vid_dev->v4l2_dev,
+				"DMA Channel not allocated for Rotation\n");
+		return -EINVAL;
+	}
+
+	return videobuf_qbuf(q, buffer);
+}
+
+static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+	struct omap_vout_device *vout = fh;
+	struct videobuf_queue *q = &vout->vbq;
+
+	if (!vout->streaming)
+		return -EINVAL;
+
+	if (file->f_flags & O_NONBLOCK)
+		/* Call videobuf_dqbuf for non blocking mode */
+		return videobuf_dqbuf(q, (struct v4l2_buffer *)b, 1);
+	else
+		/* Call videobuf_dqbuf for  blocking mode */
+		return videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0);
+}
+
+static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+	int ret = 0, j;
+	u32 addr = 0, mask = 0;
+	struct omap_vout_device *vout = fh;
+	struct videobuf_queue *q = &vout->vbq;
+	struct omapvideo_info *ovid = &vout->vid_info;
+
+	mutex_lock(&vout->lock);
+
+	if (vout->streaming) {
+		ret = -EBUSY;
+		goto streamon_err;
+	}
+
+	ret = videobuf_streamon(q);
+	if (ret)
+		goto streamon_err;
+
+	if (list_empty(&vout->dma_queue)) {
+		ret = -EIO;
+		goto streamon_err1;
+	}
+
+	/* Get the next frame from the buffer queue */
+	vout->next_frm = vout->cur_frm = list_entry(vout->dma_queue.next,
+			struct videobuf_buffer, queue);
+	/* Remove buffer from the buffer queue */
+	list_del(&vout->cur_frm->queue);
+	/* Mark state of the current frame to active */
+	vout->cur_frm->state = VIDEOBUF_ACTIVE;
+	/* Initialize field_id and started member */
+	vout->field_id = 0;
+
+	/* set flag here. Next QBUF will start DMA */
+	vout->streaming = 1;
+
+	vout->first_int = 1;
+
+	if (omap_vout_calculate_offset(vout)) {
+		ret = -EINVAL;
+		goto streamon_err1;
+	}
+	addr = (unsigned long) vout->queued_buf_addr[vout->cur_frm->i]
+		+ vout->cropped_offset;
+
+	mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD;
+
+	omap_dispc_register_isr(omap_vout_isr, vout, mask);
+
+	for (j = 0; j < ovid->num_overlays; j++) {
+		struct omap_overlay *ovl = ovid->overlays[j];
+
+		if (ovl->manager && ovl->manager->device) {
+			struct omap_overlay_info info;
+			ovl->get_overlay_info(ovl, &info);
+			info.enabled = 1;
+			info.paddr = addr;
+			if (ovl->set_overlay_info(ovl, &info)) {
+				ret = -EINVAL;
+				goto streamon_err1;
+			}
+		}
+	}
+
+	/* First save the configuration in ovelray structure */
+	ret = omapvid_init(vout, addr);
+	if (ret)
+		v4l2_err(&vout->vid_dev->v4l2_dev,
+				"failed to set overlay info\n");
+	/* Enable the pipeline and set the Go bit */
+	ret = omapvid_apply_changes(vout);
+	if (ret)
+		v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode\n");
+
+	ret = 0;
+
+streamon_err1:
+	if (ret)
+		ret = videobuf_streamoff(q);
+streamon_err:
+	mutex_unlock(&vout->lock);
+	return ret;
+}
+
+static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+	u32 mask = 0;
+	int ret = 0, j;
+	struct omap_vout_device *vout = fh;
+	struct omapvideo_info *ovid = &vout->vid_info;
+
+	if (!vout->streaming)
+		return -EINVAL;
+
+	vout->streaming = 0;
+	mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD;
+
+	omap_dispc_unregister_isr(omap_vout_isr, vout, mask);
+
+	for (j = 0; j < ovid->num_overlays; j++) {
+		struct omap_overlay *ovl = ovid->overlays[j];
+
+		if (ovl->manager && ovl->manager->device) {
+			struct omap_overlay_info info;
+
+			ovl->get_overlay_info(ovl, &info);
+			info.enabled = 0;
+			ret = ovl->set_overlay_info(ovl, &info);
+			if (ret)
+				v4l2_err(&vout->vid_dev->v4l2_dev,
+				"failed to update overlay info in streamoff\n");
+		}
+	}
+
+	/* Turn of the pipeline */
+	ret = omapvid_apply_changes(vout);
+	if (ret)
+		v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode in"
+				" streamoff\n");
+
+	INIT_LIST_HEAD(&vout->dma_queue);
+	ret = videobuf_streamoff(&vout->vbq);
+
+	return ret;
+}
+
+static int vidioc_s_fbuf(struct file *file, void *fh,
+				struct v4l2_framebuffer *a)
+{
+	int enable = 0;
+	struct omap_overlay *ovl;
+	struct omapvideo_info *ovid;
+	struct omap_vout_device *vout = fh;
+	struct omap_overlay_manager_info info;
+	enum omap_dss_trans_key_type key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
+
+	ovid = &vout->vid_info;
+	ovl = ovid->overlays[0];
+
+	/* OMAP DSS doesn't support Source and Destination color
+	   key together */
+	if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) &&
+			(a->flags & V4L2_FBUF_FLAG_CHROMAKEY))
+		return -EINVAL;
+	/* OMAP DSS Doesn't support the Destination color key
+	   and alpha blending together */
+	if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY) &&
+			(a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA))
+		return -EINVAL;
+
+	if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY)) {
+		vout->fbuf.flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY;
+		key_type =  OMAP_DSS_COLOR_KEY_VID_SRC;
+	} else
+		vout->fbuf.flags &= ~V4L2_FBUF_FLAG_SRC_CHROMAKEY;
+
+	if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY)) {
+		vout->fbuf.flags |= V4L2_FBUF_FLAG_CHROMAKEY;
+		key_type =  OMAP_DSS_COLOR_KEY_GFX_DST;
+	} else
+		vout->fbuf.flags &=  ~V4L2_FBUF_FLAG_CHROMAKEY;
+
+	if (a->flags & (V4L2_FBUF_FLAG_CHROMAKEY |
+				V4L2_FBUF_FLAG_SRC_CHROMAKEY))
+		enable = 1;
+	else
+		enable = 0;
+	if (ovl->manager && ovl->manager->get_manager_info &&
+			ovl->manager->set_manager_info) {
+
+		ovl->manager->get_manager_info(ovl->manager, &info);
+		info.trans_enabled = enable;
+		info.trans_key_type = key_type;
+		info.trans_key = vout->win.chromakey;
+
+		if (ovl->manager->set_manager_info(ovl->manager, &info))
+			return -EINVAL;
+	}
+	if (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) {
+		vout->fbuf.flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
+		enable = 1;
+	} else {
+		vout->fbuf.flags &= ~V4L2_FBUF_FLAG_LOCAL_ALPHA;
+		enable = 0;
+	}
+	if (ovl->manager && ovl->manager->get_manager_info &&
+			ovl->manager->set_manager_info) {
+		ovl->manager->get_manager_info(ovl->manager, &info);
+		info.alpha_enabled = enable;
+		if (ovl->manager->set_manager_info(ovl->manager, &info))
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int vidioc_g_fbuf(struct file *file, void *fh,
+		struct v4l2_framebuffer *a)
+{
+	struct omap_overlay *ovl;
+	struct omapvideo_info *ovid;
+	struct omap_vout_device *vout = fh;
+	struct omap_overlay_manager_info info;
+
+	ovid = &vout->vid_info;
+	ovl = ovid->overlays[0];
+
+	a->flags = 0x0;
+	a->capability = V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_CHROMAKEY
+		| V4L2_FBUF_CAP_SRC_CHROMAKEY;
+
+	if (ovl->manager && ovl->manager->get_manager_info) {
+		ovl->manager->get_manager_info(ovl->manager, &info);
+		if (info.trans_key_type == OMAP_DSS_COLOR_KEY_VID_SRC)
+			a->flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY;
+		if (info.trans_key_type == OMAP_DSS_COLOR_KEY_GFX_DST)
+			a->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
+	}
+	if (ovl->manager && ovl->manager->get_manager_info) {
+		ovl->manager->get_manager_info(ovl->manager, &info);
+		if (info.alpha_enabled)
+			a->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
+	}
+
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops vout_ioctl_ops = {
+	.vidioc_querycap      			= vidioc_querycap,
+	.vidioc_enum_fmt_vid_out 		= vidioc_enum_fmt_vid_out,
+	.vidioc_g_fmt_vid_out			= vidioc_g_fmt_vid_out,
+	.vidioc_try_fmt_vid_out			= vidioc_try_fmt_vid_out,
+	.vidioc_s_fmt_vid_out			= vidioc_s_fmt_vid_out,
+	.vidioc_queryctrl    			= vidioc_queryctrl,
+	.vidioc_g_ctrl       			= vidioc_g_ctrl,
+	.vidioc_s_fbuf				= vidioc_s_fbuf,
+	.vidioc_g_fbuf				= vidioc_g_fbuf,
+	.vidioc_s_ctrl       			= vidioc_s_ctrl,
+	.vidioc_try_fmt_vid_overlay 		= vidioc_try_fmt_vid_overlay,
+	.vidioc_s_fmt_vid_overlay		= vidioc_s_fmt_vid_overlay,
+	.vidioc_enum_fmt_vid_overlay		= vidioc_enum_fmt_vid_overlay,
+	.vidioc_g_fmt_vid_overlay		= vidioc_g_fmt_vid_overlay,
+	.vidioc_cropcap				= vidioc_cropcap,
+	.vidioc_g_crop				= vidioc_g_crop,
+	.vidioc_s_crop				= vidioc_s_crop,
+	.vidioc_reqbufs				= vidioc_reqbufs,
+	.vidioc_querybuf			= vidioc_querybuf,
+	.vidioc_qbuf				= vidioc_qbuf,
+	.vidioc_dqbuf				= vidioc_dqbuf,
+	.vidioc_streamon			= vidioc_streamon,
+	.vidioc_streamoff			= vidioc_streamoff,
+};
+
+static const struct v4l2_file_operations omap_vout_fops = {
+	.owner 		= THIS_MODULE,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap 		= omap_vout_mmap,
+	.open 		= omap_vout_open,
+	.release 	= omap_vout_release,
+};
+
+/* Init functions used during driver initialization */
+/* Initial setup of video_data */
+static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
+{
+	struct video_device *vfd;
+	struct v4l2_pix_format *pix;
+	struct v4l2_control *control;
+	struct omap_dss_device *display =
+		vout->vid_info.overlays[0]->manager->device;
+
+	/* set the default pix */
+	pix = &vout->pix;
+
+	/* Set the default picture of QVGA  */
+	pix->width = QQVGA_WIDTH;
+	pix->height = QQVGA_HEIGHT;
+
+	/* Default pixel format is RGB 5-6-5 */
+	pix->pixelformat = V4L2_PIX_FMT_RGB565;
+	pix->field = V4L2_FIELD_ANY;
+	pix->bytesperline = pix->width * 2;
+	pix->sizeimage = pix->bytesperline * pix->height;
+	pix->priv = 0;
+	pix->colorspace = V4L2_COLORSPACE_JPEG;
+
+	vout->bpp = RGB565_BPP;
+	vout->fbuf.fmt.width  =  display->panel.timings.x_res;
+	vout->fbuf.fmt.height =  display->panel.timings.y_res;
+
+	/* Set the data structures for the overlay parameters*/
+	vout->win.global_alpha = 255;
+	vout->fbuf.flags = 0;
+	vout->fbuf.capability = V4L2_FBUF_CAP_LOCAL_ALPHA |
+		V4L2_FBUF_CAP_SRC_CHROMAKEY | V4L2_FBUF_CAP_CHROMAKEY;
+	vout->win.chromakey = 0;
+
+	omap_vout_new_format(pix, &vout->fbuf, &vout->crop, &vout->win);
+
+	/*Initialize the control variables for
+	  rotation, flipping and background color. */
+	control = vout->control;
+	control[0].id = V4L2_CID_ROTATE;
+	control[0].value = 0;
+	vout->rotation = 0;
+	vout->mirror = 0;
+	vout->control[2].id = V4L2_CID_HFLIP;
+	vout->control[2].value = 0;
+	vout->vrfb_bpp = 2;
+
+	control[1].id = V4L2_CID_BG_COLOR;
+	control[1].value = 0;
+
+	/* initialize the video_device struct */
+	vfd = vout->vfd = video_device_alloc();
+
+	if (!vfd) {
+		printk(KERN_ERR VOUT_NAME ": could not allocate"
+				" video device struct\n");
+		return -ENOMEM;
+	}
+	vfd->release = video_device_release;
+	vfd->ioctl_ops = &vout_ioctl_ops;
+
+	strlcpy(vfd->name, VOUT_NAME, sizeof(vfd->name));
+
+	/* need to register for a VID_HARDWARE_* ID in videodev.h */
+	vfd->fops = &omap_vout_fops;
+	vfd->v4l2_dev = &vout->vid_dev->v4l2_dev;
+	mutex_init(&vout->lock);
+
+	vfd->minor = -1;
+	return 0;
+
+}
+
+/* Setup video buffers */
+static int __init omap_vout_setup_video_bufs(struct platform_device *pdev,
+		int vid_num)
+{
+	u32 numbuffers;
+	int ret = 0, i, j;
+	int image_width, image_height;
+	struct video_device *vfd;
+	struct omap_vout_device *vout;
+	int static_vrfb_allocation = 0, vrfb_num_bufs = VRFB_NUM_BUFS;
+	struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
+	struct omap2video_device *vid_dev =
+		container_of(v4l2_dev, struct omap2video_device, v4l2_dev);
+
+	vout = vid_dev->vouts[vid_num];
+	vfd = vout->vfd;
+
+	numbuffers = (vid_num == 0) ? video1_numbuffers : video2_numbuffers;
+	vout->buffer_size = (vid_num == 0) ? video1_bufsize : video2_bufsize;
+	dev_info(&pdev->dev, "Buffer Size = %d\n", vout->buffer_size);
+
+	for (i = 0; i < numbuffers; i++) {
+		vout->buf_virt_addr[i] =
+			omap_vout_alloc_buffer(vout->buffer_size,
+					(u32 *) &vout->buf_phy_addr[i]);
+		if (!vout->buf_virt_addr[i]) {
+			numbuffers = i;
+			ret = -ENOMEM;
+			goto free_buffers;
+		}
+	}
+
+	for (i = 0; i < VRFB_NUM_BUFS; i++) {
+		if (omap_vrfb_request_ctx(&vout->vrfb_context[i])) {
+			dev_info(&pdev->dev, ": VRFB allocation failed\n");
+			for (j = 0; j < i; j++)
+				omap_vrfb_release_ctx(&vout->vrfb_context[j]);
+			ret = -ENOMEM;
+			goto free_buffers;
+		}
+	}
+	vout->cropped_offset = 0;
+
+	/* Calculate VRFB memory size */
+	/* allocate for worst case size */
+	image_width = VID_MAX_WIDTH / TILE_SIZE;
+	if (VID_MAX_WIDTH % TILE_SIZE)
+		image_width++;
+
+	image_width = image_width * TILE_SIZE;
+	image_height = VID_MAX_HEIGHT / TILE_SIZE;
+
+	if (VID_MAX_HEIGHT % TILE_SIZE)
+		image_height++;
+
+	image_height = image_height * TILE_SIZE;
+	vout->smsshado_size = PAGE_ALIGN(image_width * image_height * 2 * 2);
+
+	/*
+	 * Request and Initialize DMA, for DMA based VRFB transfer
+	 */
+	vout->vrfb_dma_tx.dev_id = OMAP_DMA_NO_DEVICE;
+	vout->vrfb_dma_tx.dma_ch = -1;
+	vout->vrfb_dma_tx.req_status = DMA_CHAN_ALLOTED;
+	ret = omap_request_dma(vout->vrfb_dma_tx.dev_id, "VRFB DMA TX",
+			omap_vout_vrfb_dma_tx_callback,
+			(void *) &vout->vrfb_dma_tx, &vout->vrfb_dma_tx.dma_ch);
+	if (ret < 0) {
+		vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
+		dev_info(&pdev->dev, ": failed to allocate DMA Channel for"
+				" video%d\n", vfd->minor);
+	}
+	init_waitqueue_head(&vout->vrfb_dma_tx.wait);
+
+	/* Allocate VRFB buffers if selected through bootargs */
+	static_vrfb_allocation = (vid_num == 0) ?
+		vid1_static_vrfb_alloc : vid2_static_vrfb_alloc;
+
+	/* statically allocated the VRFB buffer is done through
+	   commands line aruments */
+	if (static_vrfb_allocation) {
+		if (omap_vout_allocate_vrfb_buffers(vout, &vrfb_num_bufs, -1)) {
+			ret =  -ENOMEM;
+			goto release_vrfb_ctx;
+		}
+		vout->vrfb_static_allocation = 1;
+	}
+	return 0;
+
+release_vrfb_ctx:
+	for (j = 0; j < VRFB_NUM_BUFS; j++)
+		omap_vrfb_release_ctx(&vout->vrfb_context[j]);
+
+free_buffers:
+	for (i = 0; i < numbuffers; i++) {
+		omap_vout_free_buffer(vout->buf_virt_addr[i],
+						vout->buffer_size);
+		vout->buf_virt_addr[i] = 0;
+		vout->buf_phy_addr[i] = 0;
+	}
+	return ret;
+
+}
+
+/* Create video out devices */
+static int __init omap_vout_create_video_devices(struct platform_device *pdev)
+{
+	int ret = 0, k;
+	struct omap_vout_device *vout;
+	struct video_device *vfd = NULL;
+	struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
+	struct omap2video_device *vid_dev = container_of(v4l2_dev,
+			struct omap2video_device, v4l2_dev);
+
+	for (k = 0; k < pdev->num_resources; k++) {
+
+		vout = kmalloc(sizeof(struct omap_vout_device), GFP_KERNEL);
+		if (!vout) {
+			dev_err(&pdev->dev, ": could not allocate memory\n");
+			return -ENOMEM;
+		}
+		memset(vout, 0, sizeof(struct omap_vout_device));
+
+		vout->vid = k;
+		vid_dev->vouts[k] = vout;
+		vout->vid_dev = vid_dev;
+		/* Select video2 if only 1 overlay is controlled by V4L2 */
+		if (pdev->num_resources == 1)
+			vout->vid_info.overlays[0] = vid_dev->overlays[k + 2];
+		else
+			/* Else select video1 and video2 one by one. */
+			vout->vid_info.overlays[0] = vid_dev->overlays[k + 1];
+		vout->vid_info.num_overlays = 1;
+		vout->vid_info.id = k + 1;
+
+		/* Setup the default configuration for the video devices
+		 */
+		if (omap_vout_setup_video_data(vout) != 0) {
+			ret = -ENOMEM;
+			goto error;
+		}
+
+		/* Allocate default number of buffers for the video streaming
+		 * and reserve the VRFB space for rotation
+		 */
+		if (omap_vout_setup_video_bufs(pdev, k) != 0) {
+			ret = -ENOMEM;
+			goto error1;
+		}
+
+		/* Register the Video device with V4L2
+		 */
+		vfd = vout->vfd;
+		if (video_register_device(vfd, VFL_TYPE_GRABBER, k + 1) < 0) {
+			dev_err(&pdev->dev, ": Could not register "
+					"Video for Linux device\n");
+			vfd->minor = -1;
+			ret = -ENODEV;
+			goto error2;
+		}
+		video_set_drvdata(vfd, vout);
+
+		/* Configure the overlay structure */
+		ret = omapvid_init(vid_dev->vouts[k], 0);
+		if (!ret)
+			goto success;
+
+error2:
+		omap_vout_release_vrfb(vout);
+		omap_vout_free_buffers(vout);
+error1:
+		video_device_release(vfd);
+error:
+		kfree(vout);
+		return ret;
+
+success:
+		dev_info(&pdev->dev, ": registered and initialized"
+				" video device %d\n", vfd->minor);
+		if (k == (pdev->num_resources - 1))
+			return 0;
+	}
+
+	return -ENODEV;
+}
+/* Driver functions */
+static void omap_vout_cleanup_device(struct omap_vout_device *vout)
+{
+	struct video_device *vfd;
+
+	if (!vout)
+		return;
+
+	vfd = vout->vfd;
+	if (vfd) {
+		if (!video_is_registered(vfd)) {
+			/*
+			 * The device was never registered, so release the
+			 * video_device struct directly.
+			 */
+			video_device_release(vfd);
+		} else {
+			/*
+			 * The unregister function will release the video_device
+			 * struct as well as unregistering it.
+			 */
+			video_unregister_device(vfd);
+		}
+	}
+
+	omap_vout_release_vrfb(vout);
+	omap_vout_free_buffers(vout);
+	/* Free the VRFB buffer if allocated
+	 * init time
+	 */
+	if (vout->vrfb_static_allocation)
+		omap_vout_free_vrfb_buffers(vout);
+
+	kfree(vout);
+}
+
+static int omap_vout_remove(struct platform_device *pdev)
+{
+	int k;
+	struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
+	struct omap2video_device *vid_dev = container_of(v4l2_dev, struct
+			omap2video_device, v4l2_dev);
+
+	v4l2_device_unregister(v4l2_dev);
+	for (k = 0; k < pdev->num_resources; k++)
+		omap_vout_cleanup_device(vid_dev->vouts[k]);
+
+	for (k = 0; k < vid_dev->num_displays; k++) {
+		if (vid_dev->displays[k]->state != OMAP_DSS_DISPLAY_DISABLED)
+			vid_dev->displays[k]->disable(vid_dev->displays[k]);
+
+		omap_dss_put_device(vid_dev->displays[k]);
+	}
+	kfree(vid_dev);
+	return 0;
+}
+
+static int __init omap_vout_probe(struct platform_device *pdev)
+{
+	int ret = 0, i;
+	struct omap_overlay *ovl;
+	struct omap_dss_device *dssdev = NULL;
+	struct omap_dss_device *def_display;
+	struct omap2video_device *vid_dev = NULL;
+
+	if (pdev->num_resources == 0) {
+		dev_err(&pdev->dev, "probed for an unknown device\n");
+		return -ENODEV;
+	}
+
+	vid_dev = kzalloc(sizeof(struct omap2video_device), GFP_KERNEL);
+	if (vid_dev == NULL)
+		return -ENOMEM;
+
+	vid_dev->num_displays = 0;
+	for_each_dss_dev(dssdev) {
+		omap_dss_get_device(dssdev);
+		vid_dev->displays[vid_dev->num_displays++] = dssdev;
+	}
+
+	if (vid_dev->num_displays == 0) {
+		dev_err(&pdev->dev, "no displays\n");
+		ret = -EINVAL;
+		goto probe_err0;
+	}
+
+	vid_dev->num_overlays = omap_dss_get_num_overlays();
+	for (i = 0; i < vid_dev->num_overlays; i++)
+		vid_dev->overlays[i] = omap_dss_get_overlay(i);
+
+	vid_dev->num_managers = omap_dss_get_num_overlay_managers();
+	for (i = 0; i < vid_dev->num_managers; i++)
+		vid_dev->managers[i] = omap_dss_get_overlay_manager(i);
+
+	/* Get the Video1 overlay and video2 overlay.
+	 * Setup the Display attached to that overlays
+	 */
+	for (i = 1; i < vid_dev->num_overlays; i++) {
+		ovl = omap_dss_get_overlay(i);
+		if (ovl->manager && ovl->manager->device) {
+			def_display = ovl->manager->device;
+		} else {
+			dev_warn(&pdev->dev, "cannot find display\n");
+			def_display = NULL;
+		}
+		if (def_display) {
+			ret = def_display->enable(def_display);
+			if (ret) {
+				/* Here we are not considering a error
+				 *  as display may be enabled by frame
+				 *  buffer driver
+				 */
+				dev_warn(&pdev->dev,
+					"'%s' Display already enabled\n",
+					def_display->name);
+			}
+			/* set the update mode */
+			if (def_display->caps &
+					OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
+#ifdef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
+				if (def_display->enable_te)
+					def_display->enable_te(def_display, 1);
+				if (def_display->set_update_mode)
+					def_display->set_update_mode(def_display,
+							OMAP_DSS_UPDATE_AUTO);
+#else	/* MANUAL_UPDATE */
+				if (def_display->enable_te)
+					def_display->enable_te(def_display, 0);
+				if (def_display->set_update_mode)
+					def_display->set_update_mode(def_display,
+							OMAP_DSS_UPDATE_MANUAL);
+#endif
+			} else {
+				if (def_display->set_update_mode)
+					def_display->set_update_mode(def_display,
+							OMAP_DSS_UPDATE_AUTO);
+			}
+		}
+	}
+
+	if (v4l2_device_register(&pdev->dev, &vid_dev->v4l2_dev) < 0) {
+		dev_err(&pdev->dev, "v4l2_device_register failed\n");
+		ret = -ENODEV;
+		goto probe_err1;
+	}
+
+	ret = omap_vout_create_video_devices(pdev);
+	if (ret)
+		goto probe_err2;
+
+	for (i = 0; i < vid_dev->num_displays; i++) {
+		struct omap_dss_device *display = vid_dev->displays[i];
+
+		if (display->update)
+			display->update(display, 0, 0,
+					display->panel.timings.x_res,
+					display->panel.timings.y_res);
+	}
+	return 0;
+
+probe_err2:
+	v4l2_device_unregister(&vid_dev->v4l2_dev);
+probe_err1:
+	for (i = 1; i < vid_dev->num_overlays; i++) {
+		def_display = NULL;
+		ovl = omap_dss_get_overlay(i);
+		if (ovl->manager && ovl->manager->device)
+			def_display = ovl->manager->device;
+
+		if (def_display)
+			def_display->disable(def_display);
+	}
+probe_err0:
+	kfree(vid_dev);
+	return ret;
+}
+
+static struct platform_driver omap_vout_driver = {
+	.driver = {
+		.name = VOUT_NAME,
+	},
+	.probe = omap_vout_probe,
+	.remove = omap_vout_remove,
+};
+
+static int __init omap_vout_init(void)
+{
+	if (platform_driver_register(&omap_vout_driver) != 0) {
+		printk(KERN_ERR VOUT_NAME ":Could not register Video driver\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void omap_vout_cleanup(void)
+{
+	platform_driver_unregister(&omap_vout_driver);
+}
+
+late_initcall(omap_vout_init);
+module_exit(omap_vout_cleanup);
diff --git a/drivers/media/video/omap/omap_voutdef.h b/drivers/media/video/omap/omap_voutdef.h
new file mode 100644
index 0000000..ea3a047
--- /dev/null
+++ b/drivers/media/video/omap/omap_voutdef.h
@@ -0,0 +1,147 @@
+/*
+ * omap_voutdef.h
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef OMAP_VOUTDEF_H
+#define OMAP_VOUTDEF_H
+
+#include <plat/display.h>
+
+#define YUYV_BPP        2
+#define RGB565_BPP      2
+#define RGB24_BPP       3
+#define RGB32_BPP       4
+#define TILE_SIZE       32
+#define YUYV_VRFB_BPP   2
+#define RGB_VRFB_BPP    1
+#define MAX_CID		3
+#define MAC_VRFB_CTXS	4
+#define MAX_VOUT_DEV	2
+#define MAX_OVLS	3
+#define MAX_DISPLAYS	3
+#define MAX_MANAGERS	3
+
+/* Enum for Rotation
+ * DSS understands rotation in 0, 1, 2, 3 context
+ * while V4L2 driver understands it as 0, 90, 180, 270
+ */
+enum dss_rotation {
+	dss_rotation_0_degree	= 0,
+	dss_rotation_90_degree	= 1,
+	dss_rotation_180_degree	= 2,
+	dss_rotation_270_degree = 3,
+};
+/*
+ * This structure is used to store the DMA transfer parameters
+ * for VRFB hidden buffer
+ */
+struct vid_vrfb_dma {
+	int dev_id;
+	int dma_ch;
+	int req_status;
+	int tx_status;
+	wait_queue_head_t wait;
+};
+
+struct omapvideo_info {
+	int id;
+	int num_overlays;
+	struct omap_overlay *overlays[MAX_OVLS];
+};
+
+struct omap2video_device {
+	struct mutex  mtx;
+
+	int state;
+
+	struct v4l2_device v4l2_dev;
+	struct omap_vout_device *vouts[MAX_VOUT_DEV];
+
+	int num_displays;
+	struct omap_dss_device *displays[MAX_DISPLAYS];
+	int num_overlays;
+	struct omap_overlay *overlays[MAX_OVLS];
+	int num_managers;
+	struct omap_overlay_manager *managers[MAX_MANAGERS];
+};
+
+/* per-device data structure */
+struct omap_vout_device {
+
+	struct omapvideo_info vid_info;
+	struct video_device *vfd;
+	struct omap2video_device *vid_dev;
+	int vid;
+	int opened;
+
+	/* we don't allow to change image fmt/size once buffer has
+	 * been allocated
+	 */
+	int buffer_allocated;
+	/* allow to reuse previously allocated buffer which is big enough */
+	int buffer_size;
+	/* keep buffer info across opens */
+	unsigned long buf_virt_addr[VIDEO_MAX_FRAME];
+	unsigned long buf_phy_addr[VIDEO_MAX_FRAME];
+	enum omap_color_mode dss_mode;
+
+	/* we don't allow to request new buffer when old buffers are
+	 * still mmaped
+	 */
+	int mmap_count;
+
+	spinlock_t vbq_lock;		/* spinlock for videobuf queues */
+	unsigned long field_count;	/* field counter for videobuf_buffer */
+
+	/* non-NULL means streaming is in progress. */
+	bool streaming;
+
+	struct v4l2_pix_format pix;
+	struct v4l2_rect crop;
+	struct v4l2_window win;
+	struct v4l2_framebuffer fbuf;
+
+	/* Lock to protect the shared data structures in ioctl */
+	struct mutex lock;
+
+	/* V4L2 control structure for different control id */
+	struct v4l2_control control[MAX_CID];
+	enum dss_rotation rotation;
+	bool mirror;
+	int flicker_filter;
+	/* V4L2 control structure for different control id */
+
+	int bpp; /* bytes per pixel */
+	int vrfb_bpp; /* bytes per pixel with respect to VRFB */
+
+	struct vid_vrfb_dma vrfb_dma_tx;
+	unsigned int smsshado_phy_addr[MAC_VRFB_CTXS];
+	unsigned int smsshado_virt_addr[MAC_VRFB_CTXS];
+	struct vrfb vrfb_context[MAC_VRFB_CTXS];
+	bool vrfb_static_allocation;
+	unsigned int smsshado_size;
+	unsigned char pos;
+
+	int ps, vr_ps, line_length, first_int, field_id;
+	enum v4l2_memory memory;
+	struct videobuf_buffer *cur_frm, *next_frm;
+	struct list_head dma_queue;
+	u8 *queued_buf_addr[VIDEO_MAX_FRAME];
+	u32 cropped_offset;
+	s32 tv_field1_offset;
+	void *isr_handle;
+
+	/* Buffer queue variables */
+	struct omap_vout_device *vout;
+	enum v4l2_buf_type type;
+	struct videobuf_queue vbq;
+	int io_allowed;
+
+};
+#endif	/* ifndef OMAP_VOUTDEF_H */
diff --git a/drivers/media/video/omap/omap_voutlib.c b/drivers/media/video/omap/omap_voutlib.c
new file mode 100644
index 0000000..b941c76
--- /dev/null
+++ b/drivers/media/video/omap/omap_voutlib.c
@@ -0,0 +1,293 @@
+/*
+ * omap_voutlib.c
+ *
+ * Copyright (C) 2005-2010 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * Based on the OMAP2 camera driver
+ * Video-for-Linux (Version 2) camera capture driver for
+ * the OMAP24xx camera controller.
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <plat/cpu.h>
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("OMAP Video library");
+MODULE_LICENSE("GPL");
+
+/* Return the default overlay cropping rectangle in crop given the image
+ * size in pix and the video display size in fbuf.  The default
+ * cropping rectangle is the largest rectangle no larger than the capture size
+ * that will fit on the display.  The default cropping rectangle is centered in
+ * the image.  All dimensions and offsets are rounded down to even numbers.
+ */
+void omap_vout_default_crop(struct v4l2_pix_format *pix,
+		  struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop)
+{
+	crop->width = (pix->width < fbuf->fmt.width) ?
+		pix->width : fbuf->fmt.width;
+	crop->height = (pix->height < fbuf->fmt.height) ?
+		pix->height : fbuf->fmt.height;
+	crop->width &= ~1;
+	crop->height &= ~1;
+	crop->left = ((pix->width - crop->width) >> 1) & ~1;
+	crop->top = ((pix->height - crop->height) >> 1) & ~1;
+}
+EXPORT_SYMBOL_GPL(omap_vout_default_crop);
+
+/* Given a new render window in new_win, adjust the window to the
+ * nearest supported configuration.  The adjusted window parameters are
+ * returned in new_win.
+ * Returns zero if succesful, or -EINVAL if the requested window is
+ * impossible and cannot reasonably be adjusted.
+ */
+int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
+			struct v4l2_window *new_win)
+{
+	struct v4l2_rect try_win;
+
+	/* make a working copy of the new_win rectangle */
+	try_win = new_win->w;
+
+	/* adjust the preview window so it fits on the display by clipping any
+	 * offscreen areas
+	 */
+	if (try_win.left < 0) {
+		try_win.width += try_win.left;
+		try_win.left = 0;
+	}
+	if (try_win.top < 0) {
+		try_win.height += try_win.top;
+		try_win.top = 0;
+	}
+	try_win.width = (try_win.width < fbuf->fmt.width) ?
+		try_win.width : fbuf->fmt.width;
+	try_win.height = (try_win.height < fbuf->fmt.height) ?
+		try_win.height : fbuf->fmt.height;
+	if (try_win.left + try_win.width > fbuf->fmt.width)
+		try_win.width = fbuf->fmt.width - try_win.left;
+	if (try_win.top + try_win.height > fbuf->fmt.height)
+		try_win.height = fbuf->fmt.height - try_win.top;
+	try_win.width &= ~1;
+	try_win.height &= ~1;
+
+	if (try_win.width <= 0 || try_win.height <= 0)
+		return -EINVAL;
+
+	/* We now have a valid preview window, so go with it */
+	new_win->w = try_win;
+	new_win->field = V4L2_FIELD_ANY;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(omap_vout_try_window);
+
+/* Given a new render window in new_win, adjust the window to the
+ * nearest supported configuration.  The image cropping window in crop
+ * will also be adjusted if necessary.  Preference is given to keeping the
+ * the window as close to the requested configuration as possible.  If
+ * successful, new_win, vout->win, and crop are updated.
+ * Returns zero if succesful, or -EINVAL if the requested preview window is
+ * impossible and cannot reasonably be adjusted.
+ */
+int omap_vout_new_window(struct v4l2_rect *crop,
+		struct v4l2_window *win, struct v4l2_framebuffer *fbuf,
+		struct v4l2_window *new_win)
+{
+	int err;
+
+	err = omap_vout_try_window(fbuf, new_win);
+	if (err)
+		return err;
+
+	/* update our preview window */
+	win->w = new_win->w;
+	win->field = new_win->field;
+	win->chromakey = new_win->chromakey;
+
+	/* Adjust the cropping window to allow for resizing limitation */
+	if (cpu_is_omap24xx()) {
+		/* For 24xx limit is 8x to 1/2x scaling. */
+		if ((crop->height/win->w.height) >= 2)
+			crop->height = win->w.height * 2;
+
+		if ((crop->width/win->w.width) >= 2)
+			crop->width = win->w.width * 2;
+
+		if (crop->width > 768) {
+			/* The OMAP2420 vertical resizing line buffer is 768
+			 * pixels wide. If the cropped image is wider than
+			 * 768 pixels then it cannot be vertically resized.
+			 */
+			if (crop->height != win->w.height)
+				crop->width = 768;
+		}
+	} else if (cpu_is_omap34xx()) {
+		/* For 34xx limit is 8x to 1/4x scaling. */
+		if ((crop->height/win->w.height) >= 4)
+			crop->height = win->w.height * 4;
+
+		if ((crop->width/win->w.width) >= 4)
+			crop->width = win->w.width * 4;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(omap_vout_new_window);
+
+/* Given a new cropping rectangle in new_crop, adjust the cropping rectangle to
+ * the nearest supported configuration.  The image render window in win will
+ * also be adjusted if necessary.  The preview window is adjusted such that the
+ * horizontal and vertical rescaling ratios stay constant.  If the render
+ * window would fall outside the display boundaries, the cropping rectangle
+ * will also be adjusted to maintain the rescaling ratios.  If successful, crop
+ * and win are updated.
+ * Returns zero if succesful, or -EINVAL if the requested cropping rectangle is
+ * impossible and cannot reasonably be adjusted.
+ */
+int omap_vout_new_crop(struct v4l2_pix_format *pix,
+	      struct v4l2_rect *crop, struct v4l2_window *win,
+	      struct v4l2_framebuffer *fbuf, const struct v4l2_rect *new_crop)
+{
+	struct v4l2_rect try_crop;
+	unsigned long vresize, hresize;
+
+	/* make a working copy of the new_crop rectangle */
+	try_crop = *new_crop;
+
+	/* adjust the cropping rectangle so it fits in the image */
+	if (try_crop.left < 0) {
+		try_crop.width += try_crop.left;
+		try_crop.left = 0;
+	}
+	if (try_crop.top < 0) {
+		try_crop.height += try_crop.top;
+		try_crop.top = 0;
+	}
+	try_crop.width = (try_crop.width < pix->width) ?
+		try_crop.width : pix->width;
+	try_crop.height = (try_crop.height < pix->height) ?
+		try_crop.height : pix->height;
+	if (try_crop.left + try_crop.width > pix->width)
+		try_crop.width = pix->width - try_crop.left;
+	if (try_crop.top + try_crop.height > pix->height)
+		try_crop.height = pix->height - try_crop.top;
+
+	try_crop.width &= ~1;
+	try_crop.height &= ~1;
+
+	if (try_crop.width <= 0 || try_crop.height <= 0)
+		return -EINVAL;
+
+	if (cpu_is_omap24xx()) {
+		if (crop->height != win->w.height) {
+			/* If we're resizing vertically, we can't support a
+			 * crop width wider than 768 pixels.
+			 */
+			if (try_crop.width > 768)
+				try_crop.width = 768;
+		}
+	}
+	/* vertical resizing */
+	vresize = (1024 * crop->height) / win->w.height;
+	if (cpu_is_omap24xx() && (vresize > 2048))
+		vresize = 2048;
+	else if (cpu_is_omap34xx() && (vresize > 4096))
+		vresize = 4096;
+
+	win->w.height = ((1024 * try_crop.height) / vresize) & ~1;
+	if (win->w.height == 0)
+		win->w.height = 2;
+	if (win->w.height + win->w.top > fbuf->fmt.height) {
+		/* We made the preview window extend below the bottom of the
+		 * display, so clip it to the display boundary and resize the
+		 * cropping height to maintain the vertical resizing ratio.
+		 */
+		win->w.height = (fbuf->fmt.height - win->w.top) & ~1;
+		if (try_crop.height == 0)
+			try_crop.height = 2;
+	}
+	/* horizontal resizing */
+	hresize = (1024 * crop->width) / win->w.width;
+	if (cpu_is_omap24xx() && (hresize > 2048))
+		hresize = 2048;
+	else if (cpu_is_omap34xx() && (hresize > 4096))
+		hresize = 4096;
+
+	win->w.width = ((1024 * try_crop.width) / hresize) & ~1;
+	if (win->w.width == 0)
+		win->w.width = 2;
+	if (win->w.width + win->w.left > fbuf->fmt.width) {
+		/* We made the preview window extend past the right side of the
+		 * display, so clip it to the display boundary and resize the
+		 * cropping width to maintain the horizontal resizing ratio.
+		 */
+		win->w.width = (fbuf->fmt.width - win->w.left) & ~1;
+		if (try_crop.width == 0)
+			try_crop.width = 2;
+	}
+	if (cpu_is_omap24xx()) {
+		if ((try_crop.height/win->w.height) >= 2)
+			try_crop.height = win->w.height * 2;
+
+		if ((try_crop.width/win->w.width) >= 2)
+			try_crop.width = win->w.width * 2;
+
+		if (try_crop.width > 768) {
+			/* The OMAP2420 vertical resizing line buffer is
+			 * 768 pixels wide.  If the cropped image is wider
+			 * than 768 pixels then it cannot be vertically resized.
+			 */
+			if (try_crop.height != win->w.height)
+				try_crop.width = 768;
+		}
+	} else if (cpu_is_omap34xx()) {
+		if ((try_crop.height/win->w.height) >= 4)
+			try_crop.height = win->w.height * 4;
+
+		if ((try_crop.width/win->w.width) >= 4)
+			try_crop.width = win->w.width * 4;
+	}
+	/* update our cropping rectangle and we're done */
+	*crop = try_crop;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(omap_vout_new_crop);
+
+/* Given a new format in pix and fbuf,  crop and win
+ * structures are initialized to default values. crop
+ * is initialized to the largest window size that will fit on the display.  The
+ * crop window is centered in the image. win is initialized to
+ * the same size as crop and is centered on the display.
+ * All sizes and offsets are constrained to be even numbers.
+ */
+void omap_vout_new_format(struct v4l2_pix_format *pix,
+		struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop,
+		struct v4l2_window *win)
+{
+	/* crop defines the preview source window in the image capture
+	 * buffer
+	 */
+	omap_vout_default_crop(pix, fbuf, crop);
+
+	/* win defines the preview target window on the display */
+	win->w.width = crop->width;
+	win->w.height = crop->height;
+	win->w.left = ((fbuf->fmt.width - win->w.width) >> 1) & ~1;
+	win->w.top = ((fbuf->fmt.height - win->w.height) >> 1) & ~1;
+}
+EXPORT_SYMBOL_GPL(omap_vout_new_format);
+
diff --git a/drivers/media/video/omap/omap_voutlib.h b/drivers/media/video/omap/omap_voutlib.h
new file mode 100644
index 0000000..a60b16e
--- /dev/null
+++ b/drivers/media/video/omap/omap_voutlib.h
@@ -0,0 +1,34 @@
+/*
+ * omap_voutlib.h
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#ifndef OMAP_VOUTLIB_H
+#define OMAP_VOUTLIB_H
+
+extern void omap_vout_default_crop(struct v4l2_pix_format *pix,
+		struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop);
+
+extern int omap_vout_new_crop(struct v4l2_pix_format *pix,
+		struct v4l2_rect *crop, struct v4l2_window *win,
+		struct v4l2_framebuffer *fbuf,
+		const struct v4l2_rect *new_crop);
+
+extern int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
+		struct v4l2_window *new_win);
+
+extern int omap_vout_new_window(struct v4l2_rect *crop,
+		struct v4l2_window *win, struct v4l2_framebuffer *fbuf,
+		struct v4l2_window *new_win);
+
+extern void omap_vout_new_format(struct v4l2_pix_format *pix,
+		struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop,
+		struct v4l2_window *win);
+#endif	/* #ifndef OMAP_VOUTLIB_H */
+
diff --git a/drivers/media/video/omap24xxcam.c b/drivers/media/video/omap24xxcam.c
index ce76d95..f85b2ed8 100644
--- a/drivers/media/video/omap24xxcam.c
+++ b/drivers/media/video/omap24xxcam.c
@@ -452,8 +452,8 @@
 	*size = fh->pix.sizeimage;
 
 	/* accessing fh->cam->capture_mem is ok, it's constant */
-	while (*size * *cnt > fh->cam->capture_mem)
-		(*cnt)--;
+	if (*size * *cnt > fh->cam->capture_mem)
+		*cnt = fh->cam->capture_mem / *size;
 
 	return 0;
 }
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
index e0bce8d..a109120 100644
--- a/drivers/media/video/ov511.c
+++ b/drivers/media/video/ov511.c
@@ -57,8 +57,8 @@
 #define DRIVER_VERSION "v1.64 for Linux 2.5"
 #define EMAIL "mark@alpha.dyndns.org"
 #define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org> & Bret Wallach \
-	& Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
-	<cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>"
+& Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
+<cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>"
 #define DRIVER_DESC "ov511 USB Camera Driver"
 
 #define OV511_I2C_RETRIES 3
@@ -5916,11 +5916,6 @@
 	mutex_lock(&ov->lock);
 	usb_set_intfdata (intf, NULL);
 
-	if (!ov) {
-		mutex_unlock(&ov->lock);
-		return;
-	}
-
 	/* Free device number */
 	ov511_devused &= ~(1 << ov->nr);
 
@@ -5945,7 +5940,7 @@
 	ov->dev = NULL;
 
 	/* Free the memory */
-	if (ov && !ov->user) {
+	if (!ov->user) {
 		mutex_lock(&ov->cbuf_lock);
 		kfree(ov->cbuf);
 		ov->cbuf = NULL;
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c
index aaa50f9..91c886a 100644
--- a/drivers/media/video/ov7670.c
+++ b/drivers/media/video/ov7670.c
@@ -198,6 +198,7 @@
 	struct ov7670_format_struct *fmt;  /* Current format */
 	unsigned char sat;		/* Saturation value */
 	int hue;			/* Hue value */
+	u8 clkrc;			/* Clock divider value */
 };
 
 static inline struct ov7670_info *to_state(struct v4l2_subdev *sd)
@@ -351,7 +352,7 @@
 static struct regval_list ov7670_fmt_yuv422[] = {
 	{ REG_COM7, 0x0 },  /* Selects YUV mode */
 	{ REG_RGB444, 0 },	/* No RGB444 please */
-	{ REG_COM1, 0 },
+	{ REG_COM1, 0 },	/* CCIR601 */
 	{ REG_COM15, COM15_R00FF },
 	{ REG_COM9, 0x18 }, /* 4x gain ceiling; 0x8 is reserved bit */
 	{ 0x4f, 0x80 }, 	/* "matrix coefficient 1" */
@@ -367,7 +368,7 @@
 static struct regval_list ov7670_fmt_rgb565[] = {
 	{ REG_COM7, COM7_RGB },	/* Selects RGB mode */
 	{ REG_RGB444, 0 },	/* No RGB444 please */
-	{ REG_COM1, 0x0 },
+	{ REG_COM1, 0x0 },	/* CCIR601 */
 	{ REG_COM15, COM15_RGB565 },
 	{ REG_COM9, 0x38 }, 	/* 16x gain ceiling; 0x8 is reserved bit */
 	{ 0x4f, 0xb3 }, 	/* "matrix coefficient 1" */
@@ -383,7 +384,7 @@
 static struct regval_list ov7670_fmt_rgb444[] = {
 	{ REG_COM7, COM7_RGB },	/* Selects RGB mode */
 	{ REG_RGB444, R444_ENABLE },	/* Enable xxxxrrrr ggggbbbb */
-	{ REG_COM1, 0x40 },	/* Magic reserved bit */
+	{ REG_COM1, 0x0 },	/* CCIR601 */
 	{ REG_COM15, COM15_R01FE|COM15_RGB565 }, /* Data range needed? */
 	{ REG_COM9, 0x38 }, 	/* 16x gain ceiling; 0x8 is reserved bit */
 	{ 0x4f, 0xb3 }, 	/* "matrix coefficient 1" */
@@ -408,8 +409,13 @@
 
 /*
  * Low-level register I/O.
+ *
+ * Note that there are two versions of these.  On the XO 1, the
+ * i2c controller only does SMBUS, so that's what we use.  The
+ * ov7670 is not really an SMBUS device, though, so the communication
+ * is not always entirely reliable.
  */
-
+#ifdef CONFIG_OLPC_XO_1
 static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg,
 		unsigned char *value)
 {
@@ -432,10 +438,68 @@
 	int ret = i2c_smbus_write_byte_data(client, reg, value);
 
 	if (reg == REG_COM7 && (value & COM7_RESET))
-		msleep(2);  /* Wait for reset to run */
+		msleep(5);  /* Wait for reset to run */
 	return ret;
 }
 
+#else /* ! CONFIG_OLPC_XO_1 */
+/*
+ * On most platforms, we'd rather do straight i2c I/O.
+ */
+static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg,
+		unsigned char *value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u8 data = reg;
+	struct i2c_msg msg;
+	int ret;
+
+	/*
+	 * Send out the register address...
+	 */
+	msg.addr = client->addr;
+	msg.flags = 0;
+	msg.len = 1;
+	msg.buf = &data;
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret < 0) {
+		printk(KERN_ERR "Error %d on register write\n", ret);
+		return ret;
+	}
+	/*
+	 * ...then read back the result.
+	 */
+	msg.flags = I2C_M_RD;
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret >= 0) {
+		*value = data;
+		ret = 0;
+	}
+	return ret;
+}
+
+
+static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg,
+		unsigned char value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct i2c_msg msg;
+	unsigned char data[2] = { reg, value };
+	int ret;
+
+	msg.addr = client->addr;
+	msg.flags = 0;
+	msg.len = 2;
+	msg.buf = data;
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret > 0)
+		ret = 0;
+	if (reg == REG_COM7 && (value & COM7_RESET))
+		msleep(5);  /* Wait for reset to run */
+	return ret;
+}
+#endif /* CONFIG_OLPC_XO_1 */
+
 
 /*
  * Write a list of register settings; ff/ff stops the process.
@@ -744,22 +808,12 @@
 	struct ov7670_format_struct *ovfmt;
 	struct ov7670_win_size *wsize;
 	struct ov7670_info *info = to_state(sd);
-	unsigned char com7, clkrc = 0;
+	unsigned char com7;
 
 	ret = ov7670_try_fmt_internal(sd, fmt, &ovfmt, &wsize);
 	if (ret)
 		return ret;
 	/*
-	 * HACK: if we're running rgb565 we need to grab then rewrite
-	 * CLKRC.  If we're *not*, however, then rewriting clkrc hoses
-	 * the colors.
-	 */
-	if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) {
-		ret = ov7670_read(sd, REG_CLKRC, &clkrc);
-		if (ret)
-			return ret;
-	}
-	/*
 	 * COM7 is a pain in the ass, it doesn't like to be read then
 	 * quickly written afterward.  But we have everything we need
 	 * to set it absolutely here, as long as the format-specific
@@ -779,8 +833,18 @@
 		ret = ov7670_write_array(sd, wsize->regs);
 	info->fmt = ovfmt;
 
-	if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565 && ret == 0)
-		ret = ov7670_write(sd, REG_CLKRC, clkrc);
+	/*
+	 * If we're running RGB565, we must rewrite clkrc after setting
+	 * the other parameters or the image looks poor.  If we're *not*
+	 * doing RGB565, we must not rewrite clkrc or the image looks
+	 * *really* poor.
+	 *
+	 * (Update) Now that we retain clkrc state, we should be able
+	 * to write it unconditionally, and that will make the frame
+	 * rate persistent too.
+	 */
+	if (ret == 0)
+		ret = ov7670_write(sd, REG_CLKRC, info->clkrc);
 	return ret;
 }
 
@@ -791,20 +855,17 @@
 static int ov7670_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
 {
 	struct v4l2_captureparm *cp = &parms->parm.capture;
-	unsigned char clkrc;
-	int ret;
+	struct ov7670_info *info = to_state(sd);
 
 	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
-	ret = ov7670_read(sd, REG_CLKRC, &clkrc);
-	if (ret < 0)
-		return ret;
+
 	memset(cp, 0, sizeof(struct v4l2_captureparm));
 	cp->capability = V4L2_CAP_TIMEPERFRAME;
 	cp->timeperframe.numerator = 1;
 	cp->timeperframe.denominator = OV7670_FRAME_RATE;
-	if ((clkrc & CLK_EXT) == 0 && (clkrc & CLK_SCALE) > 1)
-		cp->timeperframe.denominator /= (clkrc & CLK_SCALE);
+	if ((info->clkrc & CLK_EXT) == 0 && (info->clkrc & CLK_SCALE) > 1)
+		cp->timeperframe.denominator /= (info->clkrc & CLK_SCALE);
 	return 0;
 }
 
@@ -812,19 +873,14 @@
 {
 	struct v4l2_captureparm *cp = &parms->parm.capture;
 	struct v4l2_fract *tpf = &cp->timeperframe;
-	unsigned char clkrc;
-	int ret, div;
+	struct ov7670_info *info = to_state(sd);
+	int div;
 
 	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 	if (cp->extendedmode != 0)
 		return -EINVAL;
-	/*
-	 * CLKRC has a reserved bit, so let's preserve it.
-	 */
-	ret = ov7670_read(sd, REG_CLKRC, &clkrc);
-	if (ret < 0)
-		return ret;
+
 	if (tpf->numerator == 0 || tpf->denominator == 0)
 		div = 1;  /* Reset to full rate */
 	else
@@ -833,10 +889,10 @@
 		div = 1;
 	else if (div > CLK_SCALE)
 		div = CLK_SCALE;
-	clkrc = (clkrc & 0x80) | div;
+	info->clkrc = (info->clkrc & 0x80) | div;
 	tpf->numerator = 1;
 	tpf->denominator = OV7670_FRAME_RATE/div;
-	return ov7670_write(sd, REG_CLKRC, clkrc);
+	return ov7670_write(sd, REG_CLKRC, info->clkrc);
 }
 
 
@@ -1115,6 +1171,140 @@
 	return ret;
 }
 
+/*
+ * GAIN is split between REG_GAIN and REG_VREF[7:6].  If one believes
+ * the data sheet, the VREF parts should be the most significant, but
+ * experience shows otherwise.  There seems to be little value in
+ * messing with the VREF bits, so we leave them alone.
+ */
+static int ov7670_g_gain(struct v4l2_subdev *sd, __s32 *value)
+{
+	int ret;
+	unsigned char gain;
+
+	ret = ov7670_read(sd, REG_GAIN, &gain);
+	*value = gain;
+	return ret;
+}
+
+static int ov7670_s_gain(struct v4l2_subdev *sd, int value)
+{
+	int ret;
+	unsigned char com8;
+
+	ret = ov7670_write(sd, REG_GAIN, value & 0xff);
+	/* Have to turn off AGC as well */
+	if (ret == 0) {
+		ret = ov7670_read(sd, REG_COM8, &com8);
+		ret = ov7670_write(sd, REG_COM8, com8 & ~COM8_AGC);
+	}
+	return ret;
+}
+
+/*
+ * Tweak autogain.
+ */
+static int ov7670_g_autogain(struct v4l2_subdev *sd, __s32 *value)
+{
+	int ret;
+	unsigned char com8;
+
+	ret = ov7670_read(sd, REG_COM8, &com8);
+	*value = (com8 & COM8_AGC) != 0;
+	return ret;
+}
+
+static int ov7670_s_autogain(struct v4l2_subdev *sd, int value)
+{
+	int ret;
+	unsigned char com8;
+
+	ret = ov7670_read(sd, REG_COM8, &com8);
+	if (ret == 0) {
+		if (value)
+			com8 |= COM8_AGC;
+		else
+			com8 &= ~COM8_AGC;
+		ret = ov7670_write(sd, REG_COM8, com8);
+	}
+	return ret;
+}
+
+/*
+ * Exposure is spread all over the place: top 6 bits in AECHH, middle
+ * 8 in AECH, and two stashed in COM1 just for the hell of it.
+ */
+static int ov7670_g_exp(struct v4l2_subdev *sd, __s32 *value)
+{
+	int ret;
+	unsigned char com1, aech, aechh;
+
+	ret = ov7670_read(sd, REG_COM1, &com1) +
+		ov7670_read(sd, REG_AECH, &aech) +
+		ov7670_read(sd, REG_AECHH, &aechh);
+	*value = ((aechh & 0x3f) << 10) | (aech << 2) | (com1 & 0x03);
+	return ret;
+}
+
+static int ov7670_s_exp(struct v4l2_subdev *sd, int value)
+{
+	int ret;
+	unsigned char com1, com8, aech, aechh;
+
+	ret = ov7670_read(sd, REG_COM1, &com1) +
+		ov7670_read(sd, REG_COM8, &com8);
+		ov7670_read(sd, REG_AECHH, &aechh);
+	if (ret)
+		return ret;
+
+	com1 = (com1 & 0xfc) | (value & 0x03);
+	aech = (value >> 2) & 0xff;
+	aechh = (aechh & 0xc0) | ((value >> 10) & 0x3f);
+	ret = ov7670_write(sd, REG_COM1, com1) +
+		ov7670_write(sd, REG_AECH, aech) +
+		ov7670_write(sd, REG_AECHH, aechh);
+	/* Have to turn off AEC as well */
+	if (ret == 0)
+		ret = ov7670_write(sd, REG_COM8, com8 & ~COM8_AEC);
+	return ret;
+}
+
+/*
+ * Tweak autoexposure.
+ */
+static int ov7670_g_autoexp(struct v4l2_subdev *sd, __s32 *value)
+{
+	int ret;
+	unsigned char com8;
+	enum v4l2_exposure_auto_type *atype = (enum v4l2_exposure_auto_type *) value;
+
+	ret = ov7670_read(sd, REG_COM8, &com8);
+	if (com8 & COM8_AEC)
+		*atype = V4L2_EXPOSURE_AUTO;
+	else
+		*atype = V4L2_EXPOSURE_MANUAL;
+	return ret;
+}
+
+static int ov7670_s_autoexp(struct v4l2_subdev *sd,
+		enum v4l2_exposure_auto_type value)
+{
+	int ret;
+	unsigned char com8;
+
+	ret = ov7670_read(sd, REG_COM8, &com8);
+	if (ret == 0) {
+		if (value == V4L2_EXPOSURE_AUTO)
+			com8 |= COM8_AEC;
+		else
+			com8 &= ~COM8_AEC;
+		ret = ov7670_write(sd, REG_COM8, com8);
+	}
+	return ret;
+}
+
+
+
 static int ov7670_queryctrl(struct v4l2_subdev *sd,
 		struct v4l2_queryctrl *qc)
 {
@@ -1131,6 +1321,14 @@
 		return v4l2_ctrl_query_fill(qc, 0, 256, 1, 128);
 	case V4L2_CID_HUE:
 		return v4l2_ctrl_query_fill(qc, -180, 180, 5, 0);
+	case V4L2_CID_GAIN:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
+	case V4L2_CID_AUTOGAIN:
+		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
+	case V4L2_CID_EXPOSURE:
+		return v4l2_ctrl_query_fill(qc, 0, 65535, 1, 500);
+	case V4L2_CID_EXPOSURE_AUTO:
+		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
 	}
 	return -EINVAL;
 }
@@ -1150,6 +1348,14 @@
 		return ov7670_g_vflip(sd, &ctrl->value);
 	case V4L2_CID_HFLIP:
 		return ov7670_g_hflip(sd, &ctrl->value);
+	case V4L2_CID_GAIN:
+		return ov7670_g_gain(sd, &ctrl->value);
+	case V4L2_CID_AUTOGAIN:
+		return ov7670_g_autogain(sd, &ctrl->value);
+	case V4L2_CID_EXPOSURE:
+		return ov7670_g_exp(sd, &ctrl->value);
+	case V4L2_CID_EXPOSURE_AUTO:
+		return ov7670_g_autoexp(sd, &ctrl->value);
 	}
 	return -EINVAL;
 }
@@ -1169,6 +1375,15 @@
 		return ov7670_s_vflip(sd, ctrl->value);
 	case V4L2_CID_HFLIP:
 		return ov7670_s_hflip(sd, ctrl->value);
+	case V4L2_CID_GAIN:
+		return ov7670_s_gain(sd, ctrl->value);
+	case V4L2_CID_AUTOGAIN:
+		return ov7670_s_autogain(sd, ctrl->value);
+	case V4L2_CID_EXPOSURE:
+		return ov7670_s_exp(sd, ctrl->value);
+	case V4L2_CID_EXPOSURE_AUTO:
+		return ov7670_s_autoexp(sd,
+				(enum v4l2_exposure_auto_type) ctrl->value);
 	}
 	return -EINVAL;
 }
@@ -1268,6 +1483,7 @@
 
 	info->fmt = &ov7670_formats[0];
 	info->sat = 128;	/* Review this */
+	info->clkrc = 1;	/* 30fps */
 
 	return 0;
 }
diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c
index 47bf60c..36599a6 100644
--- a/drivers/media/video/ov9640.c
+++ b/drivers/media/video/ov9640.c
@@ -59,9 +59,9 @@
  * 		COM12 |= OV9640_COM12_YUV_AVG
  *
  *	 for RGB, alter the following registers:
- *	 	COM7  |= OV9640_COM7_RGB
- *	 	COM13 |= OV9640_COM13_RGB_AVG
- *	 	COM15 |= proper RGB color encoding mode
+ *		COM7  |= OV9640_COM7_RGB
+ *		COM13 |= OV9640_COM13_RGB_AVG
+ *		COM15 |= proper RGB color encoding mode
  */
 static const struct ov9640_reg ov9640_regs_qqcif[] = {
 	{ OV9640_CLKRC,	OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x0f) },
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index 0598bbd..7129b50 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -61,7 +61,6 @@
 	int depth;
 	int input;
 	s32 brightness, saturation, hue, contrast;
-	unsigned long in_use;
 	struct mutex lock;
 	int i2c_count;
 	struct i2c_info i2cinfo[64];
@@ -931,25 +930,8 @@
 	return len;
 }
 
-static int pms_exclusive_open(struct file *file)
-{
-	struct pms *dev = video_drvdata(file);
-
-	return test_and_set_bit(0, &dev->in_use) ? -EBUSY : 0;
-}
-
-static int pms_exclusive_release(struct file *file)
-{
-	struct pms *dev = video_drvdata(file);
-
-	clear_bit(0, &dev->in_use);
-	return 0;
-}
-
 static const struct v4l2_file_operations pms_fops = {
 	.owner		= THIS_MODULE,
-	.open           = pms_exclusive_open,
-	.release        = pms_exclusive_release,
 	.ioctl		= video_ioctl2,
 	.read           = pms_read,
 };
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 712b300..301ef19 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -2028,7 +2028,7 @@
 	memset(&fmt, 0, sizeof(fmt));
 	fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
 	v4l2_device_call_all(&hdw->v4l2_dev, hdw->decoder_client_id,
-			     video, s_fmt, &fmt);
+			     vbi, s_sliced_fmt, &fmt.fmt.sliced);
 }
 
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index bf1e0fe..5ffa0d2 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -49,7 +49,7 @@
 
 struct pvr2_v4l2_fh {
 	struct pvr2_channel channel;
-	struct pvr2_v4l2_dev *dev_info;
+	struct pvr2_v4l2_dev *pdi;
 	enum v4l2_priority prio;
 	struct pvr2_ioread *rhp;
 	struct file *file;
@@ -162,7 +162,7 @@
 {
 	struct pvr2_v4l2_fh *fh = file->private_data;
 	struct pvr2_v4l2 *vp = fh->vhead;
-	struct pvr2_v4l2_dev *dev_info = fh->dev_info;
+	struct pvr2_v4l2_dev *pdi = fh->pdi;
 	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
 	long ret = -EINVAL;
 
@@ -183,7 +183,7 @@
 	case VIDIOC_S_INPUT:
 	case VIDIOC_S_TUNER:
 	case VIDIOC_S_FREQUENCY:
-		ret = v4l2_prio_check(&vp->prio, &fh->prio);
+		ret = v4l2_prio_check(&vp->prio, fh->prio);
 		if (ret)
 			return ret;
 	}
@@ -564,14 +564,14 @@
 
 	case VIDIOC_STREAMON:
 	{
-		if (!fh->dev_info->stream) {
+		if (!fh->pdi->stream) {
 			/* No stream defined for this node.  This means
 			   that we're not currently allowed to stream from
 			   this node. */
 			ret = -EPERM;
 			break;
 		}
-		ret = pvr2_hdw_set_stream_type(hdw,dev_info->config);
+		ret = pvr2_hdw_set_stream_type(hdw,pdi->config);
 		if (ret < 0) return ret;
 		ret = pvr2_hdw_set_streaming(hdw,!0);
 		break;
@@ -579,7 +579,7 @@
 
 	case VIDIOC_STREAMOFF:
 	{
-		if (!fh->dev_info->stream) {
+		if (!fh->pdi->stream) {
 			/* No stream defined for this node.  This means
 			   that we're not currently allowed to stream from
 			   this node. */
@@ -972,7 +972,7 @@
 		fhp->rhp = NULL;
 	}
 
-	v4l2_prio_close(&vp->prio, &fhp->prio);
+	v4l2_prio_close(&vp->prio, fhp->prio);
 	file->private_data = NULL;
 
 	if (fhp->vnext) {
@@ -1032,7 +1032,7 @@
 	}
 
 	init_waitqueue_head(&fhp->wait_data);
-	fhp->dev_info = dip;
+	fhp->pdi = dip;
 
 	pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
 	pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
@@ -1093,7 +1093,7 @@
 
 	fhp->file = file;
 	file->private_data = fhp;
-	v4l2_prio_open(&vp->prio,&fhp->prio);
+	v4l2_prio_open(&vp->prio, &fhp->prio);
 
 	fhp->fw_mode_flag = pvr2_hdw_cpufw_get_enabled(hdw);
 
@@ -1113,7 +1113,7 @@
 	struct pvr2_hdw *hdw;
 	if (fh->rhp) return 0;
 
-	if (!fh->dev_info->stream) {
+	if (!fh->pdi->stream) {
 		/* No stream defined for this node.  This means that we're
 		   not currently allowed to stream from this node. */
 		return -EPERM;
@@ -1122,21 +1122,21 @@
 	/* First read() attempt.  Try to claim the stream and start
 	   it... */
 	if ((ret = pvr2_channel_claim_stream(&fh->channel,
-					     fh->dev_info->stream)) != 0) {
+					     fh->pdi->stream)) != 0) {
 		/* Someone else must already have it */
 		return ret;
 	}
 
-	fh->rhp = pvr2_channel_create_mpeg_stream(fh->dev_info->stream);
+	fh->rhp = pvr2_channel_create_mpeg_stream(fh->pdi->stream);
 	if (!fh->rhp) {
 		pvr2_channel_claim_stream(&fh->channel,NULL);
 		return -ENOMEM;
 	}
 
 	hdw = fh->channel.mc_head->hdw;
-	sp = fh->dev_info->stream->stream;
+	sp = fh->pdi->stream->stream;
 	pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh);
-	pvr2_hdw_set_stream_type(hdw,fh->dev_info->config);
+	pvr2_hdw_set_stream_type(hdw,fh->pdi->config);
 	if ((ret = pvr2_hdw_set_streaming(hdw,!0)) < 0) return ret;
 	return pvr2_ioread_set_enabled(fh->rhp,!0);
 }
diff --git a/drivers/media/video/pwc/Kconfig b/drivers/media/video/pwc/Kconfig
index 340f954..11980db 100644
--- a/drivers/media/video/pwc/Kconfig
+++ b/drivers/media/video/pwc/Kconfig
@@ -39,7 +39,7 @@
 config USB_PWC_INPUT_EVDEV
 	bool "USB Philips Cameras input events device support"
 	default y
-	depends on USB_PWC=INPUT || INPUT=y
+	depends on USB_PWC && (USB_PWC=INPUT || INPUT=y)
 	---help---
 	  This option makes USB Philips cameras register the snapshot button as
 	  an input device to report button events.
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index 04bf5c1..7fe70e7 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -253,8 +253,8 @@
 
 	if (0 == *count)
 		*count = 32;
-	while (*size * *count > vid_limit * 1024 * 1024)
-		(*count)--;
+	if (*size * *count > vid_limit * 1024 * 1024)
+		*count = (vid_limit * 1024 * 1024) / *size;
 
 	return 0;
 }
diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c
index 9277194..bbd9c11 100644
--- a/drivers/media/video/rj54n1cb0c.c
+++ b/drivers/media/video/rj54n1cb0c.c
@@ -555,15 +555,15 @@
 	return ret;
 }
 
-static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h,
-			       u32 *out_w, u32 *out_h);
+static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h,
+			       s32 *out_w, s32 *out_h);
 
 static int rj54n1_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
 	struct i2c_client *client = sd->priv;
 	struct rj54n1 *rj54n1 = to_rj54n1(client);
 	struct v4l2_rect *rect = &a->c;
-	unsigned int dummy = 0, output_w, output_h,
+	int dummy = 0, output_w, output_h,
 		input_w = rect->width, input_h = rect->height;
 	int ret;
 
@@ -577,7 +577,7 @@
 	output_w = (input_w * 1024 + rj54n1->resize / 2) / rj54n1->resize;
 	output_h = (input_h * 1024 + rj54n1->resize / 2) / rj54n1->resize;
 
-	dev_dbg(&client->dev, "Scaling for %ux%u : %u = %ux%u\n",
+	dev_dbg(&client->dev, "Scaling for %dx%d : %u = %dx%d\n",
 		input_w, input_h, rj54n1->resize, output_w, output_h);
 
 	ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h);
@@ -638,8 +638,8 @@
  * the output one, updates the window sizes and returns an error or the resize
  * coefficient on success. Note: we only use the "Fixed Scaling" on this camera.
  */
-static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h,
-			       u32 *out_w, u32 *out_h)
+static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h,
+			       s32 *out_w, s32 *out_h)
 {
 	struct i2c_client *client = sd->priv;
 	struct rj54n1 *rj54n1 = to_rj54n1(client);
@@ -749,7 +749,7 @@
 	 * improve the image quality or stability for larger frames (see comment
 	 * above), but I didn't check the framerate.
 	 */
-	skip = min(resize / 1024, (unsigned)15);
+	skip = min(resize / 1024, 15U);
 
 	inc_sel = 1 << skip;
 
@@ -819,7 +819,7 @@
 	*out_w = output_w;
 	*out_h = output_h;
 
-	dev_dbg(&client->dev, "Scaled for %ux%u : %u = %ux%u, skip %u\n",
+	dev_dbg(&client->dev, "Scaled for %dx%d : %u = %ux%u, skip %u\n",
 		*in_w, *in_h, resize, output_w, output_h, skip);
 
 	return resize;
@@ -1017,7 +1017,7 @@
 	struct i2c_client *client = sd->priv;
 	struct rj54n1 *rj54n1 = to_rj54n1(client);
 	const struct rj54n1_datafmt *fmt;
-	unsigned int output_w, output_h, max_w, max_h,
+	int output_w, output_h, max_w, max_h,
 		input_w = rj54n1->rect.width, input_h = rj54n1->rect.height;
 	int ret;
 
diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c
index 3de914d..3c7a79f 100644
--- a/drivers/media/video/s2255drv.c
+++ b/drivers/media/video/s2255drv.c
@@ -1,7 +1,7 @@
 /*
  *  s2255drv.c - a driver for the Sensoray 2255 USB video capture device
  *
- *   Copyright (C) 2007-2008 by Sensoray Company Inc.
+ *   Copyright (C) 2007-2010 by Sensoray Company Inc.
  *                              Dean Anderson
  *
  * Some video buffer code based on vivi driver:
@@ -52,14 +52,19 @@
 #include <linux/smp_lock.h>
 #include <media/videobuf-vmalloc.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <linux/vmalloc.h>
 #include <linux/usb.h>
 
+#define S2255_MAJOR_VERSION	1
+#define S2255_MINOR_VERSION	20
+#define S2255_RELEASE		0
+#define S2255_VERSION		KERNEL_VERSION(S2255_MAJOR_VERSION, \
+					       S2255_MINOR_VERSION, \
+					       S2255_RELEASE)
 #define FIRMWARE_FILE_NAME "f2255usb.bin"
 
-
-
 /* default JPEG quality */
 #define S2255_DEF_JPEG_QUAL     50
 /* vendor request in */
@@ -76,14 +81,14 @@
 #define S2255_LOAD_TIMEOUT      (5000 + S2255_DSP_BOOTTIME)
 #define S2255_DEF_BUFS          16
 #define S2255_SETMODE_TIMEOUT   500
-#define MAX_CHANNELS		4
-#define S2255_MARKER_FRAME	0x2255DA4AL
-#define S2255_MARKER_RESPONSE	0x2255ACACL
-#define S2255_RESPONSE_SETMODE  0x01
-#define S2255_RESPONSE_FW       0x10
+#define S2255_VIDSTATUS_TIMEOUT 350
+#define S2255_MARKER_FRAME	cpu_to_le32(0x2255DA4AL)
+#define S2255_MARKER_RESPONSE	cpu_to_le32(0x2255ACACL)
+#define S2255_RESPONSE_SETMODE  cpu_to_le32(0x01)
+#define S2255_RESPONSE_FW       cpu_to_le32(0x10)
+#define S2255_RESPONSE_STATUS   cpu_to_le32(0x20)
 #define S2255_USB_XFER_SIZE	(16 * 1024)
 #define MAX_CHANNELS		4
-#define MAX_PIPE_BUFFERS	1
 #define SYS_FRAMES		4
 /* maximum size is PAL full size plus room for the marker header(s) */
 #define SYS_FRAMES_MAXSIZE	(720*288*2*2 + 4096)
@@ -118,9 +123,10 @@
 #define COLOR_YUVPK	2	/* YUV packed */
 #define COLOR_Y8	4	/* monochrome */
 #define COLOR_JPG       5       /* JPEG */
-#define MASK_COLOR      0xff
-#define MASK_JPG_QUALITY 0xff00
 
+#define MASK_COLOR       0x000000ff
+#define MASK_JPG_QUALITY 0x0000ff00
+#define MASK_INPUT_TYPE  0x000f0000
 /* frame decimation. Not implemented by V4L yet(experimental in V4L) */
 #define FDEC_1		1	/* capture every frame. default */
 #define FDEC_2		2	/* capture every 2nd frame */
@@ -139,12 +145,12 @@
 #define DEF_HUE		0
 
 /* usb config commands */
-#define IN_DATA_TOKEN	0x2255c0de
-#define CMD_2255	0xc2255000
-#define CMD_SET_MODE	(CMD_2255 | 0x10)
-#define CMD_START	(CMD_2255 | 0x20)
-#define CMD_STOP	(CMD_2255 | 0x30)
-#define CMD_STATUS	(CMD_2255 | 0x40)
+#define IN_DATA_TOKEN	cpu_to_le32(0x2255c0de)
+#define CMD_2255	cpu_to_le32(0xc2255000)
+#define CMD_SET_MODE	cpu_to_le32((CMD_2255 | 0x10))
+#define CMD_START	cpu_to_le32((CMD_2255 | 0x20))
+#define CMD_STOP	cpu_to_le32((CMD_2255 | 0x30))
+#define CMD_STATUS	cpu_to_le32((CMD_2255 | 0x40))
 
 struct s2255_mode {
 	u32 format;	/* input video format (NTSC, PAL) */
@@ -194,7 +200,6 @@
 #define S2255_FW_SUCCESS	2
 #define S2255_FW_FAILED		3
 #define S2255_FW_DISCONNECTING  4
-
 #define S2255_FW_MARKER		cpu_to_le32(0x22552f2f)
 /* 2255 read states */
 #define S2255_READ_IDLE         0
@@ -223,8 +228,10 @@
 struct s2255_fmt; /*forward declaration */
 
 struct s2255_dev {
+	struct video_device	vdev[MAX_CHANNELS];
+	struct v4l2_device 	v4l2_dev;
+	atomic_t                channels; /* number of channels registered */
 	int			frames;
-	int			users[MAX_CHANNELS];
 	struct mutex		lock;
 	struct mutex		open_lock;
 	int			resources[MAX_CHANNELS];
@@ -233,11 +240,10 @@
 	u8			read_endpoint;
 
 	struct s2255_dmaqueue	vidq[MAX_CHANNELS];
-	struct video_device	*vdev[MAX_CHANNELS];
 	struct timer_list	timer;
 	struct s2255_fw	*fw_data;
-	struct s2255_pipeinfo	pipes[MAX_PIPE_BUFFERS];
-	struct s2255_bufferi		buffer[MAX_CHANNELS];
+	struct s2255_pipeinfo	pipe;
+	struct s2255_bufferi	buffer[MAX_CHANNELS];
 	struct s2255_mode	mode[MAX_CHANNELS];
 	/* jpeg compression */
 	struct v4l2_jpegcompression jc[MAX_CHANNELS];
@@ -261,11 +267,21 @@
 	int                     chn_configured[MAX_CHANNELS];
 	wait_queue_head_t       wait_setmode[MAX_CHANNELS];
 	int                     setmode_ready[MAX_CHANNELS];
+	/* video status items */
+	int                     vidstatus[MAX_CHANNELS];
+	wait_queue_head_t       wait_vidstatus[MAX_CHANNELS];
+	int                     vidstatus_ready[MAX_CHANNELS];
 	int                     chn_ready;
-	struct kref		kref;
 	spinlock_t              slock;
+	/* dsp firmware version (f2255usb.bin) */
+	int                     dsp_fw_ver;
+	u16                     pid; /* product id */
 };
-#define to_s2255_dev(d) container_of(d, struct s2255_dev, kref)
+
+static inline struct s2255_dev *to_s2255_dev(struct v4l2_device *v4l2_dev)
+{
+	return container_of(v4l2_dev, struct s2255_dev, v4l2_dev);
+}
 
 struct s2255_fmt {
 	char *name;
@@ -296,17 +312,43 @@
 
 /* current cypress EEPROM firmware version */
 #define S2255_CUR_USB_FWVER	((3 << 8) | 6)
-#define S2255_MAJOR_VERSION	1
-#define S2255_MINOR_VERSION	14
-#define S2255_RELEASE		0
-#define S2255_VERSION		KERNEL_VERSION(S2255_MAJOR_VERSION, \
-					       S2255_MINOR_VERSION, \
-					       S2255_RELEASE)
-
-/* vendor ids */
-#define USB_S2255_VENDOR_ID	0x1943
-#define USB_S2255_PRODUCT_ID	0x2255
+/* current DSP FW version */
+#define S2255_CUR_DSP_FWVER     8
+/* Need DSP version 5+ for video status feature */
+#define S2255_MIN_DSP_STATUS      5
+#define S2255_MIN_DSP_COLORFILTER 8
 #define S2255_NORMS		(V4L2_STD_PAL | V4L2_STD_NTSC)
+
+/* private V4L2 controls */
+
+/*
+ * The following chart displays how COLORFILTER should be set
+ *  =========================================================
+ *  =     fourcc              =     COLORFILTER             =
+ *  =                         ===============================
+ *  =                         =   0             =    1      =
+ *  =========================================================
+ *  =  V4L2_PIX_FMT_GREY(Y8)  = monochrome from = monochrome=
+ *  =                         = s-video or      = composite =
+ *  =                         = B/W camera      = input     =
+ *  =========================================================
+ *  =    other                = color, svideo   = color,    =
+ *  =                         =                 = composite =
+ *  =========================================================
+ *
+ * Notes:
+ *   channels 0-3 on 2255 are composite
+ *   channels 0-1 on 2257 are composite, 2-3 are s-video
+ * If COLORFILTER is 0 with a composite color camera connected,
+ * the output will appear monochrome but hatching
+ * will occur.
+ * COLORFILTER is different from "color killer" and "color effects"
+ * for reasons above.
+ */
+#define S2255_V4L2_YC_ON  1
+#define S2255_V4L2_YC_OFF 0
+#define V4L2_CID_PRIVATE_COLORFILTER (V4L2_CID_PRIVATE_BASE + 0)
+
 /* frame prefix size (sent once every frame) */
 #define PREFIX_SIZE		512
 
@@ -325,9 +367,8 @@
 static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
 			  struct s2255_mode *mode);
 static int s2255_board_shutdown(struct s2255_dev *dev);
-static void s2255_exit_v4l(struct s2255_dev *dev);
 static void s2255_fwload_start(struct s2255_dev *dev, int reset);
-static void s2255_destroy(struct kref *kref);
+static void s2255_destroy(struct s2255_dev *dev);
 static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req,
 			     u16 index, u16 value, void *buf,
 			     s32 buf_len, int bOut);
@@ -347,7 +388,6 @@
 
 static struct usb_driver s2255_driver;
 
-
 /* Declare static vars that will be used as parameters */
 static unsigned int vid_limit = 16;	/* Video memory limit, in Mb */
 
@@ -362,58 +402,16 @@
 MODULE_PARM_DESC(video_nr, "start video minor(-1 default autodetect)");
 
 /* USB device table */
+#define USB_SENSORAY_VID	0x1943
 static struct usb_device_id s2255_table[] = {
-	{USB_DEVICE(USB_S2255_VENDOR_ID, USB_S2255_PRODUCT_ID)},
+	{USB_DEVICE(USB_SENSORAY_VID, 0x2255)},
+	{USB_DEVICE(USB_SENSORAY_VID, 0x2257)}, /*same family as 2255*/
 	{ }			/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, s2255_table);
 
-
 #define BUFFER_TIMEOUT msecs_to_jiffies(400)
 
-/* supported controls */
-static struct v4l2_queryctrl s2255_qctrl[] = {
-	{
-	.id = V4L2_CID_BRIGHTNESS,
-	.type = V4L2_CTRL_TYPE_INTEGER,
-	.name = "Brightness",
-	.minimum = -127,
-	.maximum = 128,
-	.step = 1,
-	.default_value = 0,
-	.flags = 0,
-	}, {
-	.id = V4L2_CID_CONTRAST,
-	.type = V4L2_CTRL_TYPE_INTEGER,
-	.name = "Contrast",
-	.minimum = 0,
-	.maximum = 255,
-	.step = 0x1,
-	.default_value = DEF_CONTRAST,
-	.flags = 0,
-	}, {
-	.id = V4L2_CID_SATURATION,
-	.type = V4L2_CTRL_TYPE_INTEGER,
-	.name = "Saturation",
-	.minimum = 0,
-	.maximum = 255,
-	.step = 0x1,
-	.default_value = DEF_SATURATION,
-	.flags = 0,
-	}, {
-	.id = V4L2_CID_HUE,
-	.type = V4L2_CTRL_TYPE_INTEGER,
-	.name = "Hue",
-	.minimum = 0,
-	.maximum = 255,
-	.step = 0x1,
-	.default_value = DEF_HUE,
-	.flags = 0,
-	}
-};
-
-static int qctl_regs[ARRAY_SIZE(s2255_qctrl)];
-
 /* image formats.  */
 static const struct s2255_fmt formats[] = {
 	{
@@ -505,7 +503,7 @@
 static void s2255_timer(unsigned long user_data)
 {
 	struct s2255_fw *data = (struct s2255_fw *)user_data;
-	dprintk(100, "s2255 timer\n");
+	dprintk(100, "%s\n", __func__);
 	if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) {
 		printk(KERN_ERR "s2255: can't submit urb\n");
 		atomic_set(&data->fw_state, S2255_FW_FAILED);
@@ -527,7 +525,7 @@
 	struct s2255_fw *data = urb->context;
 	struct usb_device *udev = urb->dev;
 	int len;
-	dprintk(100, "udev %p urb %p", udev, urb);
+	dprintk(100, "%s: udev %p urb %p", __func__, udev, urb);
 	if (urb->status) {
 		dev_err(&udev->dev, "URB failed with status %d\n", urb->status);
 		atomic_set(&data->fw_state, S2255_FW_FAILED);
@@ -573,8 +571,8 @@
 		data->fw_loaded += len;
 	} else {
 		atomic_set(&data->fw_state, S2255_FW_LOADED_DSPWAIT);
+		dprintk(100, "%s: firmware upload complete\n", __func__);
 	}
-	dprintk(100, "2255 complete done\n");
 	return;
 
 }
@@ -585,9 +583,7 @@
 	struct s2255_buffer *buf;
 	unsigned long flags = 0;
 	int rc = 0;
-	dprintk(2, "wakeup: %p channel: %d\n", &dma_q, chn);
 	spin_lock_irqsave(&dev->slock, flags);
-
 	if (list_empty(&dma_q->active)) {
 		dprintk(1, "No active queue to serve\n");
 		rc = -1;
@@ -595,23 +591,19 @@
 	}
 	buf = list_entry(dma_q->active.next,
 			 struct s2255_buffer, vb.queue);
-
 	list_del(&buf->vb.queue);
 	do_gettimeofday(&buf->vb.ts);
-	dprintk(100, "[%p/%d] wakeup\n", buf, buf->vb.i);
 	s2255_fillbuff(dev, buf, dma_q->channel, jpgsize);
 	wake_up(&buf->vb.done);
-	dprintk(2, "wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i);
+	dprintk(2, "%s: [buf/i] [%p/%d]\n", __func__, buf, buf->vb.i);
 unlock:
 	spin_unlock_irqrestore(&dev->slock, flags);
 	return 0;
 }
 
-
 static const struct s2255_fmt *format_by_fourcc(int fourcc)
 {
 	unsigned int i;
-
 	for (i = 0; i < ARRAY_SIZE(formats); i++) {
 		if (-1 == formats[i].fourcc)
 			continue;
@@ -621,9 +613,6 @@
 	return NULL;
 }
 
-
-
-
 /* video buffer vmalloc implementation based partly on VIVI driver which is
  *          Copyright (c) 2006 by
  *                  Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
@@ -703,8 +692,8 @@
 	if (0 == *count)
 		*count = S2255_DEF_BUFS;
 
-	while (*size * (*count) > vid_limit * 1024 * 1024)
-		(*count)--;
+	if (*size * *count > vid_limit * 1024 * 1024)
+		*count = (vid_limit * 1024 * 1024) / *size;
 
 	return 0;
 }
@@ -727,10 +716,10 @@
 	if (fh->fmt == NULL)
 		return -EINVAL;
 
-	if ((fh->width < norm_minw(fh->dev->vdev[fh->channel])) ||
-	    (fh->width > norm_maxw(fh->dev->vdev[fh->channel])) ||
-	    (fh->height < norm_minh(fh->dev->vdev[fh->channel])) ||
-	    (fh->height > norm_maxh(fh->dev->vdev[fh->channel]))) {
+	if ((fh->width < norm_minw(&fh->dev->vdev[fh->channel])) ||
+	    (fh->width > norm_maxw(&fh->dev->vdev[fh->channel])) ||
+	    (fh->height < norm_minh(&fh->dev->vdev[fh->channel])) ||
+	    (fh->height > norm_maxh(&fh->dev->vdev[fh->channel]))) {
 		dprintk(4, "invalid buffer prepare\n");
 		return -EINVAL;
 	}
@@ -747,7 +736,6 @@
 	buf->vb.height = fh->height;
 	buf->vb.field = field;
 
-
 	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
 		rc = videobuf_iolock(vq, &buf->vb, NULL);
 		if (rc < 0)
@@ -767,9 +755,7 @@
 	struct s2255_fh *fh = vq->priv_data;
 	struct s2255_dev *dev = fh->dev;
 	struct s2255_dmaqueue *vidq = &dev->vidq[fh->channel];
-
 	dprintk(1, "%s\n", __func__);
-
 	buf->vb.state = VIDEOBUF_QUEUED;
 	list_add_tail(&buf->vb.queue, &vidq->active);
 }
@@ -828,6 +814,27 @@
 	dprintk(1, "res: put\n");
 }
 
+static int vidioc_querymenu(struct file *file, void *priv,
+			    struct v4l2_querymenu *qmenu)
+{
+	static const char *colorfilter[] = {
+		"Off",
+		"On",
+		NULL
+	};
+	if (qmenu->id == V4L2_CID_PRIVATE_COLORFILTER) {
+		int i;
+		const char **menu_items = colorfilter;
+		for (i = 0; i < qmenu->index && menu_items[i]; i++)
+			; /* do nothing (from v4l2-common.c) */
+		if (menu_items[i] == NULL || menu_items[i][0] == '\0')
+			return -EINVAL;
+		strlcpy(qmenu->name, menu_items[qmenu->index],
+			sizeof(qmenu->name));
+		return 0;
+	}
+	return v4l2_ctrl_query_menu(qmenu, NULL, NULL);
+}
 
 static int vidioc_querycap(struct file *file, void *priv,
 			   struct v4l2_capability *cap)
@@ -883,7 +890,7 @@
 	int is_ntsc;
 
 	is_ntsc =
-	    (dev->vdev[fh->channel]->current_norm & V4L2_STD_NTSC) ? 1 : 0;
+	    (dev->vdev[fh->channel].current_norm & V4L2_STD_NTSC) ? 1 : 0;
 
 	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
 
@@ -894,10 +901,8 @@
 	if (field == V4L2_FIELD_ANY)
 		b_any_field = 1;
 
-	dprintk(4, "try format %d \n", is_ntsc);
-	/* supports 3 sizes. see s2255drv.h */
-	dprintk(50, "width test %d, height %d\n",
-		f->fmt.pix.width, f->fmt.pix.height);
+	dprintk(50, "%s NTSC: %d suggested width: %d, height: %d\n",
+		__func__, is_ntsc, f->fmt.pix.width, f->fmt.pix.height);
 	if (is_ntsc) {
 		/* NTSC */
 		if (f->fmt.pix.height >= NUM_LINES_1CIFS_NTSC * 2) {
@@ -952,29 +957,24 @@
 			}
 		}
 		if (f->fmt.pix.width >= LINE_SZ_4CIFS_PAL) {
-			dprintk(50, "pal 704\n");
 			f->fmt.pix.width = LINE_SZ_4CIFS_PAL;
 			field = V4L2_FIELD_SEQ_TB;
 		} else if (f->fmt.pix.width >= LINE_SZ_2CIFS_PAL) {
-			dprintk(50, "pal 352A\n");
 			f->fmt.pix.width = LINE_SZ_2CIFS_PAL;
 			field = V4L2_FIELD_TOP;
 		} else if (f->fmt.pix.width >= LINE_SZ_1CIFS_PAL) {
-			dprintk(50, "pal 352B\n");
 			f->fmt.pix.width = LINE_SZ_1CIFS_PAL;
 			field = V4L2_FIELD_TOP;
 		} else {
-			dprintk(50, "pal 352C\n");
 			f->fmt.pix.width = LINE_SZ_1CIFS_PAL;
 			field = V4L2_FIELD_TOP;
 		}
 	}
-
-	dprintk(50, "width %d height %d field %d \n", f->fmt.pix.width,
-		f->fmt.pix.height, f->fmt.pix.field);
 	f->fmt.pix.field = field;
 	f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
 	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+	dprintk(50, "%s: set width %d height %d field %d\n", __func__,
+		f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
 	return 0;
 }
 
@@ -1006,7 +1006,7 @@
 	}
 
 	if (res_locked(fh->dev, fh)) {
-		dprintk(1, "can't change format after started\n");
+		dprintk(1, "%s: channel busy\n", __func__);
 		ret = -EBUSY;
 		goto out_s_fmt;
 	}
@@ -1016,17 +1016,14 @@
 	fh->height = f->fmt.pix.height;
 	fh->vb_vidq.field = f->fmt.pix.field;
 	fh->type = f->type;
-	norm = norm_minw(fh->dev->vdev[fh->channel]);
-	if (fh->width > norm_minw(fh->dev->vdev[fh->channel])) {
-		if (fh->height > norm_minh(fh->dev->vdev[fh->channel])) {
+	norm = norm_minw(&fh->dev->vdev[fh->channel]);
+	if (fh->width > norm_minw(&fh->dev->vdev[fh->channel])) {
+		if (fh->height > norm_minh(&fh->dev->vdev[fh->channel])) {
 			if (fh->dev->cap_parm[fh->channel].capturemode &
-			    V4L2_MODE_HIGHQUALITY) {
+			    V4L2_MODE_HIGHQUALITY)
 				fh->mode.scale = SCALE_4CIFSI;
-				dprintk(2, "scale 4CIFSI\n");
-			} else {
+			else
 				fh->mode.scale = SCALE_4CIFS;
-				dprintk(2, "scale 4CIFS\n");
-			}
 		} else
 			fh->mode.scale = SCALE_2CIFS;
 
@@ -1037,19 +1034,23 @@
 	/* color mode */
 	switch (fh->fmt->fourcc) {
 	case V4L2_PIX_FMT_GREY:
-		fh->mode.color = COLOR_Y8;
+		fh->mode.color &= ~MASK_COLOR;
+		fh->mode.color |= COLOR_Y8;
 		break;
 	case V4L2_PIX_FMT_JPEG:
-		fh->mode.color = COLOR_JPG |
-			(fh->dev->jc[fh->channel].quality << 8);
+		fh->mode.color &= ~MASK_COLOR;
+		fh->mode.color |= COLOR_JPG;
+		fh->mode.color |= (fh->dev->jc[fh->channel].quality << 8);
 		break;
 	case V4L2_PIX_FMT_YUV422P:
-		fh->mode.color = COLOR_YUVPL;
+		fh->mode.color &= ~MASK_COLOR;
+		fh->mode.color |= COLOR_YUVPL;
 		break;
 	case V4L2_PIX_FMT_YUYV:
 	case V4L2_PIX_FMT_UYVY:
 	default:
-		fh->mode.color = COLOR_YUVPK;
+		fh->mode.color &= ~MASK_COLOR;
+		fh->mode.color |= COLOR_YUVPK;
 		break;
 	}
 	ret = 0;
@@ -1178,19 +1179,13 @@
 	return usbInSize;
 }
 
-static void dump_verify_mode(struct s2255_dev *sdev, struct s2255_mode *mode)
+static void s2255_print_cfg(struct s2255_dev *sdev, struct s2255_mode *mode)
 {
 	struct device *dev = &sdev->udev->dev;
 	dev_info(dev, "------------------------------------------------\n");
-	dev_info(dev, "verify mode\n");
-	dev_info(dev, "format: %d\n", mode->format);
-	dev_info(dev, "scale: %d\n", mode->scale);
-	dev_info(dev, "fdec: %d\n", mode->fdec);
-	dev_info(dev, "color: %d\n", mode->color);
+	dev_info(dev, "format: %d\nscale %d\n", mode->format, mode->scale);
+	dev_info(dev, "fdec: %d\ncolor %d\n", mode->fdec, mode->color);
 	dev_info(dev, "bright: 0x%x\n", mode->bright);
-	dev_info(dev, "restart: 0x%x\n", mode->restart);
-	dev_info(dev, "usb_block: 0x%x\n", mode->usb_block);
-	dev_info(dev, "single: 0x%x\n", mode->single);
 	dev_info(dev, "------------------------------------------------\n");
 }
 
@@ -1206,44 +1201,38 @@
 			  struct s2255_mode *mode)
 {
 	int res;
-	u32 *buffer;
+	__le32 *buffer;
 	unsigned long chn_rev;
-
 	mutex_lock(&dev->lock);
 	chn_rev = G_chnmap[chn];
-	dprintk(3, "mode scale [%ld] %p %d\n", chn, mode, mode->scale);
-	dprintk(3, "mode scale [%ld] %p %d\n", chn, &dev->mode[chn],
-		dev->mode[chn].scale);
-	dprintk(2, "mode contrast %x\n", mode->contrast);
-
+	dprintk(3, "%s channel %lu\n", __func__, chn);
 	/* if JPEG, set the quality */
-	if ((mode->color & MASK_COLOR) == COLOR_JPG)
-		mode->color = (dev->jc[chn].quality << 8) | COLOR_JPG;
-
+	if ((mode->color & MASK_COLOR) == COLOR_JPG) {
+		mode->color &= ~MASK_COLOR;
+		mode->color |= COLOR_JPG;
+		mode->color &= ~MASK_JPG_QUALITY;
+		mode->color |= (dev->jc[chn].quality << 8);
+	}
 	/* save the mode */
 	dev->mode[chn] = *mode;
 	dev->req_image_size[chn] = get_transfer_size(mode);
-	dprintk(1, "transfer size %ld\n", dev->req_image_size[chn]);
-
+	dprintk(1, "%s: reqsize %ld\n", __func__, dev->req_image_size[chn]);
 	buffer = kzalloc(512, GFP_KERNEL);
 	if (buffer == NULL) {
 		dev_err(&dev->udev->dev, "out of mem\n");
 		mutex_unlock(&dev->lock);
 		return -ENOMEM;
 	}
-
 	/* set the mode */
 	buffer[0] = IN_DATA_TOKEN;
-	buffer[1] = (u32) chn_rev;
+	buffer[1] = (__le32) cpu_to_le32(chn_rev);
 	buffer[2] = CMD_SET_MODE;
 	memcpy(&buffer[3], &dev->mode[chn], sizeof(struct s2255_mode));
 	dev->setmode_ready[chn] = 0;
 	res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
 	if (debug)
-		dump_verify_mode(dev, mode);
+		s2255_print_cfg(dev, mode);
 	kfree(buffer);
-	dprintk(1, "set mode done chn %lu, %d\n", chn, res);
-
 	/* wait at least 3 frames before continuing */
 	if (mode->restart) {
 		wait_event_timeout(dev->wait_setmode[chn],
@@ -1254,10 +1243,46 @@
 			res = -EFAULT;
 		}
 	}
-
 	/* clear the restart flag */
 	dev->mode[chn].restart = 0;
 	mutex_unlock(&dev->lock);
+	dprintk(1, "%s chn %lu, result: %d\n", __func__, chn, res);
+	return res;
+}
+
+static int s2255_cmd_status(struct s2255_dev *dev, unsigned long chn,
+			    u32 *pstatus)
+{
+	int res;
+	__le32 *buffer;
+	u32 chn_rev;
+	mutex_lock(&dev->lock);
+	chn_rev = G_chnmap[chn];
+	dprintk(4, "%s chan %lu\n", __func__, chn);
+	buffer = kzalloc(512, GFP_KERNEL);
+	if (buffer == NULL) {
+		dev_err(&dev->udev->dev, "out of mem\n");
+		mutex_unlock(&dev->lock);
+		return -ENOMEM;
+	}
+	/* form the get vid status command */
+	buffer[0] = IN_DATA_TOKEN;
+	buffer[1] = (__le32) cpu_to_le32(chn_rev);
+	buffer[2] = CMD_STATUS;
+	*pstatus = 0;
+	dev->vidstatus_ready[chn] = 0;
+	res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
+	kfree(buffer);
+	wait_event_timeout(dev->wait_vidstatus[chn],
+			   (dev->vidstatus_ready[chn] != 0),
+			   msecs_to_jiffies(S2255_VIDSTATUS_TIMEOUT));
+	if (dev->vidstatus_ready[chn] != 1) {
+		printk(KERN_DEBUG "s2255: no vidstatus response\n");
+		res = -EFAULT;
+	}
+	*pstatus = dev->vidstatus[chn];
+	dprintk(4, "%s, vid status %d\n", __func__, *pstatus);
+	mutex_unlock(&dev->lock);
 	return res;
 }
 
@@ -1291,7 +1316,7 @@
 	new_mode = &fh->mode;
 	old_mode = &fh->dev->mode[chn];
 
-	if (new_mode->color != old_mode->color)
+	if ((new_mode->color & MASK_COLOR) != (old_mode->color & MASK_COLOR))
 		new_mode->restart = 1;
 	else if (new_mode->scale != old_mode->scale)
 		new_mode->restart = 1;
@@ -1302,7 +1327,6 @@
 	new_mode->restart = 0;
 	*old_mode = *new_mode;
 	dev->cur_fmt[chn] = fh->fmt;
-	dprintk(1, "%s[%d]\n", __func__, chn);
 	dev->last_frame[chn] = -1;
 	dev->bad_payload[chn] = 0;
 	dev->cur_frame[chn] = 0;
@@ -1325,7 +1349,6 @@
 {
 	struct s2255_fh *fh = priv;
 	struct s2255_dev *dev = fh->dev;
-
 	dprintk(4, "%s\n, channel: %d", __func__, fh->channel);
 	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
 		printk(KERN_ERR "invalid fh type0\n");
@@ -1347,27 +1370,32 @@
 	struct s2255_mode *mode;
 	struct videobuf_queue *q = &fh->vb_vidq;
 	int ret = 0;
-
 	mutex_lock(&q->vb_lock);
 	if (videobuf_queue_is_busy(q)) {
 		dprintk(1, "queue busy\n");
 		ret = -EBUSY;
 		goto out_s_std;
 	}
-
 	if (res_locked(fh->dev, fh)) {
 		dprintk(1, "can't change standard after started\n");
 		ret = -EBUSY;
 		goto out_s_std;
 	}
 	mode = &fh->mode;
-
 	if (*i & V4L2_STD_NTSC) {
-		dprintk(4, "vidioc_s_std NTSC\n");
-		mode->format = FORMAT_NTSC;
+		dprintk(4, "%s NTSC\n", __func__);
+		/* if changing format, reset frame decimation/intervals */
+		if (mode->format != FORMAT_NTSC) {
+			mode->format = FORMAT_NTSC;
+			mode->fdec = FDEC_1;
+		}
 	} else if (*i & V4L2_STD_PAL) {
-		dprintk(4, "vidioc_s_std PAL\n");
+		dprintk(4, "%s PAL\n", __func__);
 		mode->format = FORMAT_PAL;
+		if (mode->format != FORMAT_PAL) {
+			mode->format = FORMAT_PAL;
+			mode->fdec = FDEC_1;
+		}
 	} else {
 		ret = -EINVAL;
 	}
@@ -1386,12 +1414,32 @@
 static int vidioc_enum_input(struct file *file, void *priv,
 			     struct v4l2_input *inp)
 {
+	struct s2255_fh *fh = priv;
+	struct s2255_dev *dev = fh->dev;
+	u32 status = 0;
 	if (inp->index != 0)
 		return -EINVAL;
-
 	inp->type = V4L2_INPUT_TYPE_CAMERA;
 	inp->std = S2255_NORMS;
-	strlcpy(inp->name, "Camera", sizeof(inp->name));
+	inp->status = 0;
+	if (dev->dsp_fw_ver >= S2255_MIN_DSP_STATUS) {
+		int rc;
+		rc = s2255_cmd_status(dev, fh->channel, &status);
+		dprintk(4, "s2255_cmd_status rc: %d status %x\n", rc, status);
+		if (rc == 0)
+			inp->status =  (status & 0x01) ? 0
+				: V4L2_IN_ST_NO_SIGNAL;
+	}
+	switch (dev->pid) {
+	case 0x2255:
+	default:
+		strlcpy(inp->name, "Composite", sizeof(inp->name));
+		break;
+	case 0x2257:
+		strlcpy(inp->name, (fh->channel < 2) ? "Composite" : "S-Video",
+			sizeof(inp->name));
+		break;
+	}
 	return 0;
 }
 
@@ -1411,74 +1459,113 @@
 static int vidioc_queryctrl(struct file *file, void *priv,
 			    struct v4l2_queryctrl *qc)
 {
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++)
-		if (qc->id && qc->id == s2255_qctrl[i].id) {
-			memcpy(qc, &(s2255_qctrl[i]), sizeof(*qc));
-			return 0;
-		}
-
-	dprintk(4, "query_ctrl -EINVAL %d\n", qc->id);
-	return -EINVAL;
+	struct s2255_fh *fh = priv;
+	struct s2255_dev *dev = fh->dev;
+	switch (qc->id) {
+	case V4L2_CID_BRIGHTNESS:
+		v4l2_ctrl_query_fill(qc, -127, 127, 1, DEF_BRIGHT);
+		break;
+	case V4L2_CID_CONTRAST:
+		v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_CONTRAST);
+		break;
+	case V4L2_CID_SATURATION:
+		v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_SATURATION);
+		break;
+	case V4L2_CID_HUE:
+		v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_HUE);
+		break;
+	case V4L2_CID_PRIVATE_COLORFILTER:
+		if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
+			return -EINVAL;
+		if ((dev->pid == 0x2257) && (fh->channel > 1))
+			return -EINVAL;
+		strlcpy(qc->name, "Color Filter", sizeof(qc->name));
+		qc->type = V4L2_CTRL_TYPE_MENU;
+		qc->minimum = 0;
+		qc->maximum = 1;
+		qc->step = 1;
+		qc->default_value = 1;
+		qc->flags = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+	dprintk(4, "%s, id %d\n", __func__, qc->id);
+	return 0;
 }
 
 static int vidioc_g_ctrl(struct file *file, void *priv,
 			 struct v4l2_control *ctrl)
 {
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++)
-		if (ctrl->id == s2255_qctrl[i].id) {
-			ctrl->value = qctl_regs[i];
-			return 0;
-		}
-	dprintk(4, "g_ctrl -EINVAL\n");
-
-	return -EINVAL;
+	struct s2255_fh *fh = priv;
+	struct s2255_dev *dev = fh->dev;
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		ctrl->value = fh->mode.bright;
+		break;
+	case V4L2_CID_CONTRAST:
+		ctrl->value = fh->mode.contrast;
+		break;
+	case V4L2_CID_SATURATION:
+		ctrl->value = fh->mode.saturation;
+		break;
+	case V4L2_CID_HUE:
+		ctrl->value = fh->mode.hue;
+		break;
+	case V4L2_CID_PRIVATE_COLORFILTER:
+		if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
+			return -EINVAL;
+		if ((dev->pid == 0x2257) && (fh->channel > 1))
+			return -EINVAL;
+		ctrl->value = !((fh->mode.color & MASK_INPUT_TYPE) >> 16);
+		break;
+	default:
+		return -EINVAL;
+	}
+	dprintk(4, "%s, id %d val %d\n", __func__, ctrl->id, ctrl->value);
+	return 0;
 }
 
 static int vidioc_s_ctrl(struct file *file, void *priv,
 			 struct v4l2_control *ctrl)
 {
-	int i;
 	struct s2255_fh *fh = priv;
 	struct s2255_dev *dev = fh->dev;
 	struct s2255_mode *mode;
 	mode = &fh->mode;
-	dprintk(4, "vidioc_s_ctrl\n");
-	for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++) {
-		if (ctrl->id == s2255_qctrl[i].id) {
-			if (ctrl->value < s2255_qctrl[i].minimum ||
-			    ctrl->value > s2255_qctrl[i].maximum)
-				return -ERANGE;
-
-			qctl_regs[i] = ctrl->value;
-			/* update the mode to the corresponding value */
-			switch (ctrl->id) {
-			case V4L2_CID_BRIGHTNESS:
-				mode->bright = ctrl->value;
-				break;
-			case V4L2_CID_CONTRAST:
-				mode->contrast = ctrl->value;
-				break;
-			case V4L2_CID_HUE:
-				mode->hue = ctrl->value;
-				break;
-			case V4L2_CID_SATURATION:
-				mode->saturation = ctrl->value;
-				break;
-			}
-			mode->restart = 0;
-			/* set mode here.  Note: stream does not need restarted.
-			   some V4L programs restart stream unnecessarily
-			   after a s_crtl.
-			 */
-			s2255_set_mode(dev, fh->channel, mode);
-			return 0;
-		}
+	dprintk(4, "%s\n", __func__);
+	/* update the mode to the corresponding value */
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		mode->bright = ctrl->value;
+		break;
+	case V4L2_CID_CONTRAST:
+		mode->contrast = ctrl->value;
+		break;
+	case V4L2_CID_HUE:
+		mode->hue = ctrl->value;
+		break;
+	case V4L2_CID_SATURATION:
+		mode->saturation = ctrl->value;
+		break;
+	case V4L2_CID_PRIVATE_COLORFILTER:
+		if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
+			return -EINVAL;
+		if ((dev->pid == 0x2257) && (fh->channel > 1))
+			return -EINVAL;
+		mode->color &= ~MASK_INPUT_TYPE;
+		mode->color |= ((ctrl->value ? 0 : 1) << 16);
+		break;
+	default:
+		return -EINVAL;
 	}
-	return -EINVAL;
+	mode->restart = 0;
+	/* set mode here.  Note: stream does not need restarted.
+	   some V4L programs restart stream unnecessarily
+	   after a s_crtl.
+	*/
+	s2255_set_mode(dev, fh->channel, mode);
+	return 0;
 }
 
 static int vidioc_g_jpegcomp(struct file *file, void *priv,
@@ -1487,7 +1574,7 @@
 	struct s2255_fh *fh = priv;
 	struct s2255_dev *dev = fh->dev;
 	*jc = dev->jc[fh->channel];
-	dprintk(2, "getting jpegcompression, quality %d\n", jc->quality);
+	dprintk(2, "%s: quality %d\n", __func__, jc->quality);
 	return 0;
 }
 
@@ -1499,7 +1586,7 @@
 	if (jc->quality < 0 || jc->quality > 100)
 		return -EINVAL;
 	dev->jc[fh->channel].quality = jc->quality;
-	dprintk(2, "setting jpeg quality %d\n", jc->quality);
+	dprintk(2, "%s: quality %d\n", __func__, jc->quality);
 	return 0;
 }
 
@@ -1508,10 +1595,34 @@
 {
 	struct s2255_fh *fh = priv;
 	struct s2255_dev *dev = fh->dev;
+	__u32 def_num, def_dem;
 	if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
+	memset(sp, 0, sizeof(struct v4l2_streamparm));
+	sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
 	sp->parm.capture.capturemode = dev->cap_parm[fh->channel].capturemode;
-	dprintk(2, "getting parm %d\n", sp->parm.capture.capturemode);
+	def_num = (fh->mode.format == FORMAT_NTSC) ? 1001 : 1000;
+	def_dem = (fh->mode.format == FORMAT_NTSC) ? 30000 : 25000;
+	sp->parm.capture.timeperframe.denominator = def_dem;
+	switch (fh->mode.fdec) {
+	default:
+	case FDEC_1:
+		sp->parm.capture.timeperframe.numerator = def_num;
+		break;
+	case FDEC_2:
+		sp->parm.capture.timeperframe.numerator = def_num * 2;
+		break;
+	case FDEC_3:
+		sp->parm.capture.timeperframe.numerator = def_num * 3;
+		break;
+	case FDEC_5:
+		sp->parm.capture.timeperframe.numerator = def_num * 5;
+		break;
+	}
+	dprintk(4, "%s capture mode, %d timeperframe %d/%d\n", __func__,
+		sp->parm.capture.capturemode,
+		sp->parm.capture.timeperframe.numerator,
+		sp->parm.capture.timeperframe.denominator);
 	return 0;
 }
 
@@ -1520,15 +1631,79 @@
 {
 	struct s2255_fh *fh = priv;
 	struct s2255_dev *dev = fh->dev;
-
+	int fdec = FDEC_1;
+	__u32 def_num, def_dem;
 	if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
-
-	dev->cap_parm[fh->channel].capturemode = sp->parm.capture.capturemode;
-	dprintk(2, "setting param capture mode %d\n",
-		sp->parm.capture.capturemode);
+	/* high quality capture mode requires a stream restart */
+	if (dev->cap_parm[fh->channel].capturemode
+	    != sp->parm.capture.capturemode && res_locked(fh->dev, fh))
+		return -EBUSY;
+	def_num = (fh->mode.format == FORMAT_NTSC) ? 1001 : 1000;
+	def_dem = (fh->mode.format == FORMAT_NTSC) ? 30000 : 25000;
+	if (def_dem != sp->parm.capture.timeperframe.denominator)
+		sp->parm.capture.timeperframe.numerator = def_num;
+	else if (sp->parm.capture.timeperframe.numerator <= def_num)
+		sp->parm.capture.timeperframe.numerator = def_num;
+	else if (sp->parm.capture.timeperframe.numerator <= (def_num * 2)) {
+		sp->parm.capture.timeperframe.numerator = def_num * 2;
+		fdec = FDEC_2;
+	} else if (sp->parm.capture.timeperframe.numerator <= (def_num * 3)) {
+		sp->parm.capture.timeperframe.numerator = def_num * 3;
+		fdec = FDEC_3;
+	} else {
+		sp->parm.capture.timeperframe.numerator = def_num * 5;
+		fdec = FDEC_5;
+	}
+	fh->mode.fdec = fdec;
+	sp->parm.capture.timeperframe.denominator = def_dem;
+	s2255_set_mode(dev, fh->channel, &fh->mode);
+	dprintk(4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n",
+		__func__,
+		sp->parm.capture.capturemode,
+		sp->parm.capture.timeperframe.numerator,
+		sp->parm.capture.timeperframe.denominator, fdec);
 	return 0;
 }
+
+static int vidioc_enum_frameintervals(struct file *file, void *priv,
+			    struct v4l2_frmivalenum *fe)
+{
+	int is_ntsc = 0;
+#define NUM_FRAME_ENUMS 4
+	int frm_dec[NUM_FRAME_ENUMS] = {1, 2, 3, 5};
+	if (fe->index < 0 || fe->index >= NUM_FRAME_ENUMS)
+		return -EINVAL;
+	switch (fe->width) {
+	case 640:
+		if (fe->height != 240 && fe->height != 480)
+			return -EINVAL;
+		is_ntsc = 1;
+		break;
+	case 320:
+		if (fe->height != 240)
+			return -EINVAL;
+		is_ntsc = 1;
+		break;
+	case 704:
+		if (fe->height != 288 && fe->height != 576)
+			return -EINVAL;
+		break;
+	case 352:
+		if (fe->height != 288)
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+	fe->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+	fe->discrete.denominator = is_ntsc ? 30000 : 25000;
+	fe->discrete.numerator = (is_ntsc ? 1001 : 1000) * frm_dec[fe->index];
+	dprintk(4, "%s discrete %d/%d\n", __func__, fe->discrete.numerator,
+		fe->discrete.denominator);
+	return 0;
+}
+
 static int s2255_open(struct file *file)
 {
 	struct video_device *vdev = video_devdata(file);
@@ -1538,31 +1713,29 @@
 	int i = 0;
 	int cur_channel = -1;
 	int state;
-
 	dprintk(1, "s2255: open called (dev=%s)\n",
 		video_device_node_name(vdev));
 
-	lock_kernel();
-
 	for (i = 0; i < MAX_CHANNELS; i++) {
-		if (dev->vdev[i] == vdev) {
+		if (&dev->vdev[i] == vdev) {
 			cur_channel = i;
 			break;
 		}
 	}
-
-	if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_DISCONNECTING) {
-		unlock_kernel();
-		printk(KERN_INFO "disconnecting\n");
+	if (i == MAX_CHANNELS)
 		return -ENODEV;
-	}
-	kref_get(&dev->kref);
+
+	/*
+	 * open lock necessary to prevent multiple instances
+	 * of v4l-conf (or other programs) from simultaneously
+	 * reloading firmware.
+	 */
 	mutex_lock(&dev->open_lock);
-
-	dev->users[cur_channel]++;
-	dprintk(4, "s2255: open_handles %d\n", dev->users[cur_channel]);
-
-	switch (atomic_read(&dev->fw_data->fw_state)) {
+	state = atomic_read(&dev->fw_data->fw_state);
+	switch (state) {
+	case S2255_FW_DISCONNECTING:
+		mutex_unlock(&dev->open_lock);
+		return -ENODEV;
 	case S2255_FW_FAILED:
 		s2255_dev_err(&dev->udev->dev,
 			"firmware load failed. retrying.\n");
@@ -1573,6 +1746,8 @@
 				    (atomic_read(&dev->fw_data->fw_state)
 				     == S2255_FW_DISCONNECTING)),
 				   msecs_to_jiffies(S2255_LOAD_TIMEOUT));
+		/* state may have changed, re-read */
+		state = atomic_read(&dev->fw_data->fw_state);
 		break;
 	case S2255_FW_NOTLOADED:
 	case S2255_FW_LOADED_DSPWAIT:
@@ -1584,53 +1759,50 @@
 				     == S2255_FW_SUCCESS) ||
 				    (atomic_read(&dev->fw_data->fw_state)
 				     == S2255_FW_DISCONNECTING)),
-			msecs_to_jiffies(S2255_LOAD_TIMEOUT));
+				   msecs_to_jiffies(S2255_LOAD_TIMEOUT));
+		/* state may have changed, re-read */
+		state = atomic_read(&dev->fw_data->fw_state);
 		break;
 	case S2255_FW_SUCCESS:
 	default:
 		break;
 	}
-	state = atomic_read(&dev->fw_data->fw_state);
-	if (state != S2255_FW_SUCCESS) {
-		int rc;
-		switch (state) {
-		case S2255_FW_FAILED:
-			printk(KERN_INFO "2255 FW load failed. %d\n", state);
-			rc = -ENODEV;
-			break;
-		case S2255_FW_DISCONNECTING:
-			printk(KERN_INFO "%s: disconnecting\n", __func__);
-			rc = -ENODEV;
-			break;
-		case S2255_FW_LOADED_DSPWAIT:
-		case S2255_FW_NOTLOADED:
-			printk(KERN_INFO "%s: firmware not loaded yet"
-			       "please try again later\n",
-			       __func__);
-			rc = -EAGAIN;
-			break;
-		default:
-			printk(KERN_INFO "%s: unknown state\n", __func__);
-			rc = -EFAULT;
-			break;
-		}
-		dev->users[cur_channel]--;
+	/* state may have changed in above switch statement */
+	switch (state) {
+	case S2255_FW_SUCCESS:
+		break;
+	case S2255_FW_FAILED:
+		printk(KERN_INFO "2255 firmware load failed.\n");
 		mutex_unlock(&dev->open_lock);
-		kref_put(&dev->kref, s2255_destroy);
-		unlock_kernel();
-		return rc;
+		return -ENODEV;
+	case S2255_FW_DISCONNECTING:
+		printk(KERN_INFO "%s: disconnecting\n", __func__);
+		mutex_unlock(&dev->open_lock);
+		return -ENODEV;
+	case S2255_FW_LOADED_DSPWAIT:
+	case S2255_FW_NOTLOADED:
+		printk(KERN_INFO "%s: firmware not loaded yet"
+		       "please try again later\n",
+		       __func__);
+		/*
+		 * Timeout on firmware load means device unusable.
+		 * Set firmware failure state.
+		 * On next s2255_open the firmware will be reloaded.
+		 */
+		atomic_set(&dev->fw_data->fw_state,
+			   S2255_FW_FAILED);
+		mutex_unlock(&dev->open_lock);
+		return -EAGAIN;
+	default:
+		printk(KERN_INFO "%s: unknown state\n", __func__);
+		mutex_unlock(&dev->open_lock);
+		return -EFAULT;
 	}
-
+	mutex_unlock(&dev->open_lock);
 	/* allocate + initialize per filehandle data */
 	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-	if (NULL == fh) {
-		dev->users[cur_channel]--;
-		mutex_unlock(&dev->open_lock);
-		kref_put(&dev->kref, s2255_destroy);
-		unlock_kernel();
+	if (NULL == fh)
 		return -ENOMEM;
-	}
-
 	file->private_data = fh;
 	fh->dev = dev;
 	fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -1640,35 +1812,23 @@
 	fh->width = LINE_SZ_4CIFS_NTSC;
 	fh->height = NUM_LINES_4CIFS_NTSC * 2;
 	fh->channel = cur_channel;
-
 	/* configure channel to default state */
 	if (!dev->chn_configured[cur_channel]) {
 		s2255_set_mode(dev, cur_channel, &fh->mode);
 		dev->chn_configured[cur_channel] = 1;
 	}
-
-
-	/* Put all controls at a sane state */
-	for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++)
-		qctl_regs[i] = s2255_qctrl[i].default_value;
-
-	dprintk(1, "s2255drv: open dev=%s type=%s users=%d\n",
-		video_device_node_name(vdev), v4l2_type_names[type],
-		dev->users[cur_channel]);
-	dprintk(2, "s2255drv: open: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n",
+	dprintk(1, "%s: dev=%s type=%s\n", __func__,
+		video_device_node_name(vdev), v4l2_type_names[type]);
+	dprintk(2, "%s: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", __func__,
 		(unsigned long)fh, (unsigned long)dev,
 		(unsigned long)&dev->vidq[cur_channel]);
-	dprintk(4, "s2255drv: open: list_empty active=%d\n",
+	dprintk(4, "%s: list_empty active=%d\n", __func__,
 		list_empty(&dev->vidq[cur_channel].active));
-
 	videobuf_queue_vmalloc_init(&fh->vb_vidq, &s2255_video_qops,
 				    NULL, &dev->slock,
 				    fh->type,
 				    V4L2_FIELD_INTERLACED,
 				    sizeof(struct s2255_buffer), fh);
-
-	mutex_unlock(&dev->open_lock);
-	unlock_kernel();
 	return 0;
 }
 
@@ -1679,39 +1839,19 @@
 	struct s2255_fh *fh = file->private_data;
 	int rc;
 	dprintk(100, "%s\n", __func__);
-
 	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
 		return POLLERR;
-
 	rc = videobuf_poll_stream(file, &fh->vb_vidq, wait);
 	return rc;
 }
 
-static void s2255_destroy(struct kref *kref)
+static void s2255_destroy(struct s2255_dev *dev)
 {
-	struct s2255_dev *dev = to_s2255_dev(kref);
-	int i;
-	if (!dev) {
-		printk(KERN_ERR "s2255drv: kref problem\n");
-		return;
-	}
-	atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
-	wake_up(&dev->fw_data->wait_fw);
-	for (i = 0; i < MAX_CHANNELS; i++) {
-		dev->setmode_ready[i] = 1;
-		wake_up(&dev->wait_setmode[i]);
-	}
-	mutex_lock(&dev->open_lock);
-	/* reset the DSP so firmware can be reload next time */
-	s2255_reset_dsppower(dev);
-	s2255_exit_v4l(dev);
 	/* board shutdown stops the read pipe if it is running */
 	s2255_board_shutdown(dev);
 	/* make sure firmware still not trying to load */
 	del_timer(&dev->timer);  /* only started in .probe and .open */
-
 	if (dev->fw_data->fw_urb) {
-		dprintk(2, "kill fw_urb\n");
 		usb_kill_urb(dev->fw_data->fw_urb);
 		usb_free_urb(dev->fw_data->fw_urb);
 		dev->fw_data->fw_urb = NULL;
@@ -1720,24 +1860,22 @@
 		release_firmware(dev->fw_data->fw);
 	kfree(dev->fw_data->pfw_data);
 	kfree(dev->fw_data);
+	/* reset the DSP so firmware can be reloaded next time */
+	s2255_reset_dsppower(dev);
+	mutex_destroy(&dev->open_lock);
+	mutex_destroy(&dev->lock);
 	usb_put_dev(dev->udev);
 	dprintk(1, "%s", __func__);
-
-	mutex_unlock(&dev->open_lock);
 	kfree(dev);
 }
 
-static int s2255_close(struct file *file)
+static int s2255_release(struct file *file)
 {
 	struct s2255_fh *fh = file->private_data;
 	struct s2255_dev *dev = fh->dev;
 	struct video_device *vdev = video_devdata(file);
-
 	if (!dev)
 		return -ENODEV;
-
-	mutex_lock(&dev->open_lock);
-
 	/* turn off stream */
 	if (res_check(fh)) {
 		if (dev->b_acquire[fh->channel])
@@ -1745,15 +1883,8 @@
 		videobuf_streamoff(&fh->vb_vidq);
 		res_free(dev, fh);
 	}
-
 	videobuf_mmap_free(&fh->vb_vidq);
-	dev->users[fh->channel]--;
-
-	mutex_unlock(&dev->open_lock);
-
-	kref_put(&dev->kref, s2255_destroy);
-	dprintk(1, "s2255: close called (dev=%s, users=%d)\n",
-		video_device_node_name(vdev), dev->users[fh->channel]);
+	dprintk(1, "%s (dev=%s)\n", __func__, video_device_node_name(vdev));
 	kfree(fh);
 	return 0;
 }
@@ -1765,27 +1896,25 @@
 
 	if (!fh)
 		return -ENODEV;
-	dprintk(4, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
-
+	dprintk(4, "%s, vma=0x%08lx\n", __func__, (unsigned long)vma);
 	ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
-
-	dprintk(4, "vma start=0x%08lx, size=%ld, ret=%d\n",
+	dprintk(4, "%s vma start=0x%08lx, size=%ld, ret=%d\n", __func__,
 		(unsigned long)vma->vm_start,
 		(unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);
-
 	return ret;
 }
 
 static const struct v4l2_file_operations s2255_fops_v4l = {
 	.owner = THIS_MODULE,
 	.open = s2255_open,
-	.release = s2255_close,
+	.release = s2255_release,
 	.poll = s2255_poll,
 	.ioctl = video_ioctl2,	/* V4L2 ioctl handler */
 	.mmap = s2255_mmap_v4l,
 };
 
 static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
+	.vidioc_querymenu = vidioc_querymenu,
 	.vidioc_querycap = vidioc_querycap,
 	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
 	.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
@@ -1811,13 +1940,23 @@
 	.vidioc_g_jpegcomp = vidioc_g_jpegcomp,
 	.vidioc_s_parm = vidioc_s_parm,
 	.vidioc_g_parm = vidioc_g_parm,
+	.vidioc_enum_frameintervals = vidioc_enum_frameintervals,
 };
 
+static void s2255_video_device_release(struct video_device *vdev)
+{
+	struct s2255_dev *dev = video_get_drvdata(vdev);
+	dprintk(4, "%s, chnls: %d \n", __func__, atomic_read(&dev->channels));
+	if (atomic_dec_and_test(&dev->channels))
+		s2255_destroy(dev);
+	return;
+}
+
 static struct video_device template = {
 	.name = "s2255v",
 	.fops = &s2255_fops_v4l,
 	.ioctl_ops = &s2255_ioctl_ops,
-	.release = video_device_release,
+	.release = s2255_video_device_release,
 	.tvnorms = S2255_NORMS,
 	.current_norm = V4L2_STD_NTSC_M,
 };
@@ -1827,7 +1966,9 @@
 	int ret;
 	int i;
 	int cur_nr = video_nr;
-
+	ret = v4l2_device_register(&dev->interface->dev, &dev->v4l2_dev);
+	if (ret)
+		return ret;
 	/* initialize all video 4 linux */
 	/* register 4 video devices */
 	for (i = 0; i < MAX_CHANNELS; i++) {
@@ -1835,45 +1976,39 @@
 		dev->vidq[i].dev = dev;
 		dev->vidq[i].channel = i;
 		/* register 4 video devices */
-		dev->vdev[i] = video_device_alloc();
-		memcpy(dev->vdev[i], &template, sizeof(struct video_device));
-		dev->vdev[i]->parent = &dev->interface->dev;
-		video_set_drvdata(dev->vdev[i], dev);
+		memcpy(&dev->vdev[i], &template, sizeof(struct video_device));
+		dev->vdev[i].v4l2_dev = &dev->v4l2_dev;
+		video_set_drvdata(&dev->vdev[i], dev);
 		if (video_nr == -1)
-			ret = video_register_device(dev->vdev[i],
+			ret = video_register_device(&dev->vdev[i],
 						    VFL_TYPE_GRABBER,
 						    video_nr);
 		else
-			ret = video_register_device(dev->vdev[i],
+			ret = video_register_device(&dev->vdev[i],
 						    VFL_TYPE_GRABBER,
 						    cur_nr + i);
-		video_set_drvdata(dev->vdev[i], dev);
-
-		if (ret != 0) {
+		if (ret) {
 			dev_err(&dev->udev->dev,
 				"failed to register video device!\n");
-			return ret;
+			break;
 		}
+		atomic_inc(&dev->channels);
+		v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
+			  video_device_node_name(&dev->vdev[i]));
+
 	}
+
 	printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %d.%d\n",
 	       S2255_MAJOR_VERSION,
 	       S2255_MINOR_VERSION);
-	return ret;
-}
-
-static void s2255_exit_v4l(struct s2255_dev *dev)
-{
-
-	int i;
-	for (i = 0; i < MAX_CHANNELS; i++) {
-		if (video_is_registered(dev->vdev[i])) {
-			video_unregister_device(dev->vdev[i]);
-			printk(KERN_INFO "s2255 unregistered\n");
-		} else {
-			video_device_release(dev->vdev[i]);
-			printk(KERN_INFO "s2255 released\n");
-		}
+	/* if no channels registered, return error and probe will fail*/
+	if (atomic_read(&dev->channels) == 0) {
+		v4l2_device_unregister(&dev->v4l2_dev);
+		return ret;
 	}
+	if (atomic_read(&dev->channels) != MAX_CHANNELS)
+		printk(KERN_WARNING "s2255: Not all channels available.\n");
+	return 0;
 }
 
 /* this function moves the usb stream read pipe data
@@ -1907,14 +2042,14 @@
 	if (frm->ulState == S2255_READ_IDLE) {
 		int jj;
 		unsigned int cc;
-		s32 *pdword;
+		__le32 *pdword; /*data from dsp is little endian */
 		int payload;
 		/* search for marker codes */
 		pdata = (unsigned char *)pipe_info->transfer_buffer;
+		pdword = (__le32 *)pdata;
 		for (jj = 0; jj < (pipe_info->cur_transfer_size - 12); jj++) {
-			switch (*(s32 *) pdata) {
+			switch (*pdword) {
 			case S2255_MARKER_FRAME:
-				pdword = (s32 *)pdata;
 				dprintk(4, "found frame marker at offset:"
 					" %d [%x %x]\n", jj, pdata[0],
 					pdata[1]);
@@ -1938,7 +2073,6 @@
 				dev->jpg_size[dev->cc] = pdword[4];
 				break;
 			case S2255_MARKER_RESPONSE:
-				pdword = (s32 *)pdata;
 				pdata += DEF_USB_BLOCK;
 				jj += DEF_USB_BLOCK;
 				if (pdword[1] >= MAX_CHANNELS)
@@ -1955,7 +2089,6 @@
 					dprintk(5, "setmode ready %d\n", cc);
 					break;
 				case S2255_RESPONSE_FW:
-
 					dev->chn_ready |= (1 << cc);
 					if ((dev->chn_ready & 0x0f) != 0x0f)
 						break;
@@ -1965,6 +2098,13 @@
 						   S2255_FW_SUCCESS);
 					wake_up(&dev->fw_data->wait_fw);
 					break;
+				case S2255_RESPONSE_STATUS:
+					dev->vidstatus[cc] = pdword[3];
+					dev->vidstatus_ready[cc] = 1;
+					wake_up(&dev->wait_vidstatus[cc]);
+					dprintk(5, "got vidstatus %x chan %d\n",
+						pdword[3], cc);
+					break;
 				default:
 					printk(KERN_INFO "s2255 unknown resp\n");
 				}
@@ -2165,28 +2305,22 @@
 
 static int s2255_board_init(struct s2255_dev *dev)
 {
-	int j;
 	struct s2255_mode mode_def = DEF_MODEI_NTSC_CONT;
 	int fw_ver;
+	int j;
+	struct s2255_pipeinfo *pipe = &dev->pipe;
 	dprintk(4, "board init: %p", dev);
+	memset(pipe, 0, sizeof(*pipe));
+	pipe->dev = dev;
+	pipe->cur_transfer_size = S2255_USB_XFER_SIZE;
+	pipe->max_transfer_size = S2255_USB_XFER_SIZE;
 
-	for (j = 0; j < MAX_PIPE_BUFFERS; j++) {
-		struct s2255_pipeinfo *pipe = &dev->pipes[j];
-
-		memset(pipe, 0, sizeof(*pipe));
-		pipe->dev = dev;
-		pipe->cur_transfer_size = S2255_USB_XFER_SIZE;
-		pipe->max_transfer_size = S2255_USB_XFER_SIZE;
-
-		pipe->transfer_buffer = kzalloc(pipe->max_transfer_size,
-						GFP_KERNEL);
-		if (pipe->transfer_buffer == NULL) {
-			dprintk(1, "out of memory!\n");
-			return -ENOMEM;
-		}
-
+	pipe->transfer_buffer = kzalloc(pipe->max_transfer_size,
+					GFP_KERNEL);
+	if (pipe->transfer_buffer == NULL) {
+		dprintk(1, "out of memory!\n");
+		return -ENOMEM;
 	}
-
 	/* query the firmware */
 	fw_ver = s2255_get_fx2fw(dev);
 
@@ -2203,6 +2337,8 @@
 	for (j = 0; j < MAX_CHANNELS; j++) {
 		dev->b_acquire[j] = 0;
 		dev->mode[j] = mode_def;
+		if (dev->pid == 0x2257 && j > 1)
+			dev->mode[j].color |= (1 << 16);
 		dev->jc[j].quality = S2255_DEF_JPEG_QUAL;
 		dev->cur_fmt[j] = &formats[0];
 		dev->mode[j].restart = 1;
@@ -2213,16 +2349,14 @@
 	}
 	/* start read pipe */
 	s2255_start_readpipe(dev);
-
-	dprintk(1, "S2255: board initialized\n");
+	dprintk(1, "%s: success\n", __func__);
 	return 0;
 }
 
 static int s2255_board_shutdown(struct s2255_dev *dev)
 {
 	u32 i;
-
-	dprintk(1, "S2255: board shutdown: %p", dev);
+	dprintk(1, "%s: dev: %p", __func__,  dev);
 
 	for (i = 0; i < MAX_CHANNELS; i++) {
 		if (dev->b_acquire[i])
@@ -2233,12 +2367,8 @@
 
 	for (i = 0; i < MAX_CHANNELS; i++)
 		s2255_release_sys_buffers(dev, i);
-
-	/* release transfer buffers */
-	for (i = 0; i < MAX_PIPE_BUFFERS; i++) {
-		struct s2255_pipeinfo *pipe = &dev->pipes[i];
-		kfree(pipe->transfer_buffer);
-	}
+	/* release transfer buffer */
+	kfree(dev->pipe.transfer_buffer);
 	return 0;
 }
 
@@ -2248,9 +2378,8 @@
 	struct s2255_dev *dev;
 	int status;
 	int pipe;
-
 	pipe_info = purb->context;
-	dprintk(100, "read pipe completion %p, status %d\n", purb,
+	dprintk(100, "%s: urb:%p, status %d\n", __func__, purb,
 		purb->status);
 	if (pipe_info == NULL) {
 		dev_err(&purb->dev->dev, "no context!\n");
@@ -2265,13 +2394,13 @@
 	status = purb->status;
 	/* if shutting down, do not resubmit, exit immediately */
 	if (status == -ESHUTDOWN) {
-		dprintk(2, "read_pipe_completion: err shutdown\n");
+		dprintk(2, "%s: err shutdown\n", __func__);
 		pipe_info->err_count++;
 		return;
 	}
 
 	if (pipe_info->state == 0) {
-		dprintk(2, "exiting USB pipe");
+		dprintk(2, "%s: exiting USB pipe", __func__);
 		return;
 	}
 
@@ -2279,7 +2408,7 @@
 		s2255_read_video_callback(dev, pipe_info);
 	else {
 		pipe_info->err_count++;
-		dprintk(1, "s2255drv: failed URB %d\n", status);
+		dprintk(1, "%s: failed URB %d\n", __func__, status);
 	}
 
 	pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint);
@@ -2295,7 +2424,7 @@
 			dev_err(&dev->udev->dev, "error submitting urb\n");
 		}
 	} else {
-		dprintk(2, "read pipe complete state 0\n");
+		dprintk(2, "%s :complete state 0\n", __func__);
 	}
 	return;
 }
@@ -2304,35 +2433,28 @@
 {
 	int pipe;
 	int retval;
-	int i;
-	struct s2255_pipeinfo *pipe_info = dev->pipes;
+	struct s2255_pipeinfo *pipe_info = &dev->pipe;
 	pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint);
-	dprintk(2, "start pipe IN %d\n", dev->read_endpoint);
-
-	for (i = 0; i < MAX_PIPE_BUFFERS; i++) {
-		pipe_info->state = 1;
-		pipe_info->err_count = 0;
-		pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL);
-		if (!pipe_info->stream_urb) {
-			dev_err(&dev->udev->dev,
-				"ReadStream: Unable to alloc URB\n");
-			return -ENOMEM;
-		}
-		/* transfer buffer allocated in board_init */
-		usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev,
-				  pipe,
-				  pipe_info->transfer_buffer,
-				  pipe_info->cur_transfer_size,
-				  read_pipe_completion, pipe_info);
-
-		dprintk(4, "submitting URB %p\n", pipe_info->stream_urb);
-		retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
-		if (retval) {
-			printk(KERN_ERR "s2255: start read pipe failed\n");
-			return retval;
-		}
+	dprintk(2, "%s: IN %d\n", __func__, dev->read_endpoint);
+	pipe_info->state = 1;
+	pipe_info->err_count = 0;
+	pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!pipe_info->stream_urb) {
+		dev_err(&dev->udev->dev,
+			"ReadStream: Unable to alloc URB\n");
+		return -ENOMEM;
 	}
-
+	/* transfer buffer allocated in board_init */
+	usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev,
+			  pipe,
+			  pipe_info->transfer_buffer,
+			  pipe_info->cur_transfer_size,
+			  read_pipe_completion, pipe_info);
+	retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
+	if (retval) {
+		printk(KERN_ERR "s2255: start read pipe failed\n");
+		return retval;
+	}
 	return 0;
 }
 
@@ -2347,10 +2469,7 @@
 		dprintk(2, "start acquire failed, bad channel %lu\n", chn);
 		return -1;
 	}
-
 	chn_rev = G_chnmap[chn];
-	dprintk(1, "S2255: start acquire %lu \n", chn);
-
 	buffer = kzalloc(512, GFP_KERNEL);
 	if (buffer == NULL) {
 		dev_err(&dev->udev->dev, "out of mem\n");
@@ -2366,9 +2485,9 @@
 	}
 
 	/* send the start command */
-	*(u32 *) buffer = IN_DATA_TOKEN;
-	*((u32 *) buffer + 1) = (u32) chn_rev;
-	*((u32 *) buffer + 2) = (u32) CMD_START;
+	*(__le32 *) buffer = IN_DATA_TOKEN;
+	*((__le32 *) buffer + 1) = (__le32) cpu_to_le32(chn_rev);
+	*((__le32 *) buffer + 2) = CMD_START;
 	res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
 	if (res != 0)
 		dev_err(&dev->udev->dev, "CMD_START error\n");
@@ -2383,65 +2502,41 @@
 	unsigned char *buffer;
 	int res;
 	unsigned long chn_rev;
-
 	if (chn >= MAX_CHANNELS) {
 		dprintk(2, "stop acquire failed, bad channel %lu\n", chn);
 		return -1;
 	}
 	chn_rev = G_chnmap[chn];
-
 	buffer = kzalloc(512, GFP_KERNEL);
 	if (buffer == NULL) {
 		dev_err(&dev->udev->dev, "out of mem\n");
 		return -ENOMEM;
 	}
-
 	/* send the stop command */
-	dprintk(4, "stop acquire %lu\n", chn);
-	*(u32 *) buffer = IN_DATA_TOKEN;
-	*((u32 *) buffer + 1) = (u32) chn_rev;
-	*((u32 *) buffer + 2) = CMD_STOP;
+	*(__le32 *) buffer = IN_DATA_TOKEN;
+	*((__le32 *) buffer + 1) = (__le32) cpu_to_le32(chn_rev);
+	*((__le32 *) buffer + 2) = CMD_STOP;
 	res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
-
 	if (res != 0)
 		dev_err(&dev->udev->dev, "CMD_STOP error\n");
-
-	dprintk(4, "stop acquire: releasing states \n");
-
 	kfree(buffer);
 	dev->b_acquire[chn] = 0;
-
+	dprintk(4, "%s: chn %lu, res %d\n", __func__, chn, res);
 	return res;
 }
 
 static void s2255_stop_readpipe(struct s2255_dev *dev)
 {
-	int j;
+	struct s2255_pipeinfo *pipe = &dev->pipe;
 
-	if (dev == NULL) {
-		s2255_dev_err(&dev->udev->dev, "invalid device\n");
-		return;
+	pipe->state = 0;
+	if (pipe->stream_urb) {
+		/* cancel urb */
+		usb_kill_urb(pipe->stream_urb);
+		usb_free_urb(pipe->stream_urb);
+		pipe->stream_urb = NULL;
 	}
-	dprintk(4, "stop read pipe\n");
-	for (j = 0; j < MAX_PIPE_BUFFERS; j++) {
-		struct s2255_pipeinfo *pipe_info = &dev->pipes[j];
-		if (pipe_info) {
-			if (pipe_info->state == 0)
-				continue;
-			pipe_info->state = 0;
-		}
-	}
-
-	for (j = 0; j < MAX_PIPE_BUFFERS; j++) {
-		struct s2255_pipeinfo *pipe_info = &dev->pipes[j];
-		if (pipe_info->stream_urb) {
-			/* cancel urb */
-			usb_kill_urb(pipe_info->stream_urb);
-			usb_free_urb(pipe_info->stream_urb);
-			pipe_info->stream_urb = NULL;
-		}
-	}
-	dprintk(2, "s2255 stop read pipe: %d\n", j);
+	dprintk(4, "%s", __func__);
 	return;
 }
 
@@ -2473,32 +2568,28 @@
 	int retval = -ENOMEM;
 	__le32 *pdata;
 	int fw_size;
-
-	dprintk(2, "s2255: probe\n");
-
+	dprintk(2, "%s\n", __func__);
 	/* allocate memory for our device state and initialize it to zero */
 	dev = kzalloc(sizeof(struct s2255_dev), GFP_KERNEL);
 	if (dev == NULL) {
 		s2255_dev_err(&interface->dev, "out of memory\n");
-		goto error;
+		return -ENOMEM;
 	}
-
+	atomic_set(&dev->channels, 0);
+	dev->pid = id->idProduct;
 	dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL);
 	if (!dev->fw_data)
-		goto error;
-
+		goto errorFWDATA1;
 	mutex_init(&dev->lock);
 	mutex_init(&dev->open_lock);
-
 	/* grab usb_device and save it */
 	dev->udev = usb_get_dev(interface_to_usbdev(interface));
 	if (dev->udev == NULL) {
 		dev_err(&interface->dev, "null usb device\n");
 		retval = -ENODEV;
-		goto error;
+		goto errorUDEV;
 	}
-	kref_init(&dev->kref);
-	dprintk(1, "dev: %p, kref: %p udev %p interface %p\n", dev, &dev->kref,
+	dprintk(1, "dev: %p, udev %p interface %p\n", dev,
 		dev->udev, interface);
 	dev->interface = interface;
 	/* set up the endpoint information  */
@@ -2514,39 +2605,33 @@
 
 	if (!dev->read_endpoint) {
 		dev_err(&interface->dev, "Could not find bulk-in endpoint\n");
-		goto error;
+		goto errorEP;
 	}
-
-	/* set intfdata */
-	usb_set_intfdata(interface, dev);
-
-	dprintk(100, "after intfdata %p\n", dev);
-
 	init_timer(&dev->timer);
 	dev->timer.function = s2255_timer;
 	dev->timer.data = (unsigned long)dev->fw_data;
-
 	init_waitqueue_head(&dev->fw_data->wait_fw);
-	for (i = 0; i < MAX_CHANNELS; i++)
+	for (i = 0; i < MAX_CHANNELS; i++) {
 		init_waitqueue_head(&dev->wait_setmode[i]);
-
+		init_waitqueue_head(&dev->wait_vidstatus[i]);
+	}
 
 	dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL);
-
 	if (!dev->fw_data->fw_urb) {
 		dev_err(&interface->dev, "out of memory!\n");
-		goto error;
+		goto errorFWURB;
 	}
+
 	dev->fw_data->pfw_data = kzalloc(CHUNK_SIZE, GFP_KERNEL);
 	if (!dev->fw_data->pfw_data) {
 		dev_err(&interface->dev, "out of memory!\n");
-		goto error;
+		goto errorFWDATA2;
 	}
 	/* load the first chunk */
 	if (request_firmware(&dev->fw_data->fw,
 			     FIRMWARE_FILE_NAME, &dev->udev->dev)) {
 		printk(KERN_ERR "sensoray 2255 failed to get firmware\n");
-		goto error;
+		goto errorREQFW;
 	}
 	/* check the firmware is valid */
 	fw_size = dev->fw_data->fw->size;
@@ -2555,59 +2640,80 @@
 	if (*pdata != S2255_FW_MARKER) {
 		printk(KERN_INFO "Firmware invalid.\n");
 		retval = -ENODEV;
-		goto error;
+		goto errorFWMARKER;
 	} else {
 		/* make sure firmware is the latest */
 		__le32 *pRel;
 		pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4];
 		printk(KERN_INFO "s2255 dsp fw version %x\n", *pRel);
+		dev->dsp_fw_ver = *pRel;
+		if (*pRel < S2255_CUR_DSP_FWVER)
+			printk(KERN_INFO "s2255: f2255usb.bin out of date.\n");
+		if (dev->pid == 0x2257 && *pRel < S2255_MIN_DSP_COLORFILTER)
+			printk(KERN_WARNING "s2255: 2257 requires firmware %d"
+			       "or above.\n", S2255_MIN_DSP_COLORFILTER);
 	}
-	/* loads v4l specific */
-	s2255_probe_v4l(dev);
 	usb_reset_device(dev->udev);
 	/* load 2255 board specific */
 	retval = s2255_board_init(dev);
 	if (retval)
-		goto error;
-
-	dprintk(4, "before probe done %p\n", dev);
+		goto errorBOARDINIT;
 	spin_lock_init(&dev->slock);
-
 	s2255_fwload_start(dev, 0);
+	/* loads v4l specific */
+	retval = s2255_probe_v4l(dev);
+	if (retval)
+		goto errorBOARDINIT;
 	dev_info(&interface->dev, "Sensoray 2255 detected\n");
 	return 0;
-error:
+errorBOARDINIT:
+	s2255_board_shutdown(dev);
+errorFWMARKER:
+	release_firmware(dev->fw_data->fw);
+errorREQFW:
+	kfree(dev->fw_data->pfw_data);
+errorFWDATA2:
+	usb_free_urb(dev->fw_data->fw_urb);
+errorFWURB:
+	del_timer(&dev->timer);
+errorEP:
+	usb_put_dev(dev->udev);
+errorUDEV:
+	kfree(dev->fw_data);
+	mutex_destroy(&dev->open_lock);
+	mutex_destroy(&dev->lock);
+errorFWDATA1:
+	kfree(dev);
+	printk(KERN_WARNING "Sensoray 2255 driver load failed: 0x%x\n", retval);
 	return retval;
 }
 
 /* disconnect routine. when board is removed physically or with rmmod */
 static void s2255_disconnect(struct usb_interface *interface)
 {
-	struct s2255_dev *dev = NULL;
+	struct s2255_dev *dev = to_s2255_dev(usb_get_intfdata(interface));
 	int i;
-	dprintk(1, "s2255: disconnect interface %p\n", interface);
-	dev = usb_get_intfdata(interface);
-
-	/*
-	 * wake up any of the timers to allow open_lock to be
-	 * acquired sooner
-	 */
+	int channels = atomic_read(&dev->channels);
+	v4l2_device_unregister(&dev->v4l2_dev);
+	/*see comments in the uvc_driver.c usb disconnect function */
+	atomic_inc(&dev->channels);
+	/* unregister each video device. */
+	for (i = 0; i < channels; i++) {
+		if (video_is_registered(&dev->vdev[i]))
+			video_unregister_device(&dev->vdev[i]);
+	}
+	/* wake up any of our timers */
 	atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
 	wake_up(&dev->fw_data->wait_fw);
 	for (i = 0; i < MAX_CHANNELS; i++) {
 		dev->setmode_ready[i] = 1;
 		wake_up(&dev->wait_setmode[i]);
+		dev->vidstatus_ready[i] = 1;
+		wake_up(&dev->wait_vidstatus[i]);
 	}
-
-	mutex_lock(&dev->open_lock);
-	usb_set_intfdata(interface, NULL);
-	mutex_unlock(&dev->open_lock);
-
-	if (dev) {
-		kref_put(&dev->kref, s2255_destroy);
-		dprintk(1, "s2255drv: disconnect\n");
-		dev_info(&interface->dev, "s2255usb now disconnected\n");
-	}
+	if (atomic_dec_and_test(&dev->channels))
+		s2255_destroy(dev);
+	dev_info(&interface->dev, "%s\n", __func__);
 }
 
 static struct usb_driver s2255_driver = {
@@ -2620,15 +2726,12 @@
 static int __init usb_s2255_init(void)
 {
 	int result;
-
 	/* register this driver with the USB subsystem */
 	result = usb_register(&s2255_driver);
-
 	if (result)
 		pr_err(KBUILD_MODNAME
-			": usb_register failed. Error number %d\n", result);
-
-	dprintk(2, "s2255_init: done\n");
+		       ": usb_register failed. Error number %d\n", result);
+	dprintk(2, "%s\n", __func__);
 	return result;
 }
 
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index c0a7f8a..53b6fcd 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -74,6 +74,7 @@
 	int contrast;
 	int hue;
 	int sat;
+	int chroma_agc;
 	int width;
 	int height;
 	u32 ident;
@@ -592,7 +593,7 @@
 	R_5D_DID, 0xbd,
 	R_5E_SDID, 0x35,
 
-	R_02_INPUT_CNTL_1, 0x84,		/* input tuner -> input 4, amplifier active */
+	R_02_INPUT_CNTL_1, 0xc4, /* input tuner -> input 4, amplifier active */
 
 	R_80_GLOBAL_CNTL_1, 0x20,		/* enable task B */
 	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,
@@ -743,6 +744,7 @@
 static int saa711x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
 	struct saa711x_state *state = to_state(sd);
+	u8 val;
 
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
@@ -784,7 +786,21 @@
 		state->hue = ctrl->value;
 		saa711x_write(sd, R_0D_CHROMA_HUE_CNTL, state->hue);
 		break;
-
+	case V4L2_CID_CHROMA_AGC:
+		val = saa711x_read(sd, R_0F_CHROMA_GAIN_CNTL);
+		state->chroma_agc = ctrl->value;
+		if (ctrl->value)
+			val &= 0x7f;
+		else
+			val |= 0x80;
+		saa711x_write(sd, R_0F_CHROMA_GAIN_CNTL, val);
+		break;
+	case V4L2_CID_CHROMA_GAIN:
+		/* Chroma gain cannot be set when AGC is enabled */
+		if (state->chroma_agc == 1)
+			return -EINVAL;
+		saa711x_write(sd, R_0F_CHROMA_GAIN_CNTL, ctrl->value | 0x80);
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -809,6 +825,12 @@
 	case V4L2_CID_HUE:
 		ctrl->value = state->hue;
 		break;
+	case V4L2_CID_CHROMA_AGC:
+		ctrl->value = state->chroma_agc;
+		break;
+	case V4L2_CID_CHROMA_GAIN:
+		ctrl->value = saa711x_read(sd, R_0F_CHROMA_GAIN_CNTL) & 0x7f;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -1069,7 +1091,7 @@
 				saa7115_cfg_vbi_off);
 }
 
-static int saa711x_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+static int saa711x_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *sliced)
 {
 	static u16 lcr2vbi[] = {
 		0, V4L2_SLICED_TELETEXT_B, 0,	/* 1 */
@@ -1078,11 +1100,8 @@
 		V4L2_SLICED_VPS, 0, 0, 0, 0,	/* 7 */
 		0, 0, 0, 0
 	};
-	struct v4l2_sliced_vbi_format *sliced = &fmt->fmt.sliced;
 	int i;
 
-	if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
-		return -EINVAL;
 	memset(sliced, 0, sizeof(*sliced));
 	/* done if using raw VBI */
 	if (saa711x_read(sd, R_80_GLOBAL_CNTL_1) & 0x10)
@@ -1098,16 +1117,27 @@
 	return 0;
 }
 
+static int saa711x_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+	if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+		return -EINVAL;
+	return saa711x_g_sliced_fmt(sd, &fmt->fmt.sliced);
+}
+
+static int saa711x_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt)
+{
+	saa711x_set_lcr(sd, NULL);
+	return 0;
+}
+
+static int saa711x_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt)
+{
+	saa711x_set_lcr(sd, fmt);
+	return 0;
+}
+
 static int saa711x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
 {
-	if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
-		saa711x_set_lcr(sd, &fmt->fmt.sliced);
-		return 0;
-	}
-	if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-		saa711x_set_lcr(sd, NULL);
-		return 0;
-	}
 	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 
@@ -1209,6 +1239,10 @@
 		return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
 	case V4L2_CID_HUE:
 		return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
+	case V4L2_CID_CHROMA_AGC:
+		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
+	case V4L2_CID_CHROMA_GAIN:
+		return v4l2_ctrl_query_fill(qc, 0, 127, 1, 48);
 	default:
 		return -EINVAL;
 	}
@@ -1524,18 +1558,25 @@
 	.s_crystal_freq = saa711x_s_crystal_freq,
 	.g_fmt = saa711x_g_fmt,
 	.s_fmt = saa711x_s_fmt,
-	.g_vbi_data = saa711x_g_vbi_data,
-	.decode_vbi_line = saa711x_decode_vbi_line,
 	.s_stream = saa711x_s_stream,
 	.querystd = saa711x_querystd,
 	.g_input_status = saa711x_g_input_status,
 };
 
+static const struct v4l2_subdev_vbi_ops saa711x_vbi_ops = {
+	.g_vbi_data = saa711x_g_vbi_data,
+	.decode_vbi_line = saa711x_decode_vbi_line,
+	.g_sliced_fmt = saa711x_g_sliced_fmt,
+	.s_sliced_fmt = saa711x_s_sliced_fmt,
+	.s_raw_fmt = saa711x_s_raw_fmt,
+};
+
 static const struct v4l2_subdev_ops saa711x_ops = {
 	.core = &saa711x_core_ops,
 	.tuner = &saa711x_tuner_ops,
 	.audio = &saa711x_audio_ops,
 	.video = &saa711x_video_ops,
+	.vbi = &saa711x_vbi_ops,
 };
 
 /* ----------------------------------------------------------------------- */
@@ -1593,6 +1634,7 @@
 	state->contrast = 64;
 	state->hue = 0;
 	state->sat = 64;
+	state->chroma_agc = 1;
 	switch (chip_id) {
 	case '1':
 		state->ident = V4L2_IDENT_SAA7111;
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index 250ef84..87986ad 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -625,29 +625,33 @@
 	return saa7127_set_video_enable(sd, enable);
 }
 
-static int saa7127_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+static int saa7127_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt)
 {
 	struct saa7127_state *state = to_state(sd);
 
-	if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
-		return -EINVAL;
-
-	memset(&fmt->fmt.sliced, 0, sizeof(fmt->fmt.sliced));
+	memset(fmt, 0, sizeof(*fmt));
 	if (state->vps_enable)
-		fmt->fmt.sliced.service_lines[0][16] = V4L2_SLICED_VPS;
+		fmt->service_lines[0][16] = V4L2_SLICED_VPS;
 	if (state->wss_enable)
-		fmt->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
+		fmt->service_lines[0][23] = V4L2_SLICED_WSS_625;
 	if (state->cc_enable) {
-		fmt->fmt.sliced.service_lines[0][21] = V4L2_SLICED_CAPTION_525;
-		fmt->fmt.sliced.service_lines[1][21] = V4L2_SLICED_CAPTION_525;
+		fmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+		fmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
 	}
-	fmt->fmt.sliced.service_set =
+	fmt->service_set =
 		(state->vps_enable ? V4L2_SLICED_VPS : 0) |
 		(state->wss_enable ? V4L2_SLICED_WSS_625 : 0) |
 		(state->cc_enable ? V4L2_SLICED_CAPTION_525 : 0);
 	return 0;
 }
 
+static int saa7127_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+	if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+		return -EINVAL;
+	return saa7127_g_sliced_fmt(sd, &fmt->fmt.sliced);
+}
+
 static int saa7127_s_vbi_data(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
 {
 	switch (data->id) {
@@ -727,16 +731,21 @@
 };
 
 static const struct v4l2_subdev_video_ops saa7127_video_ops = {
-	.s_vbi_data = saa7127_s_vbi_data,
 	.g_fmt = saa7127_g_fmt,
 	.s_std_output = saa7127_s_std_output,
 	.s_routing = saa7127_s_routing,
 	.s_stream = saa7127_s_stream,
 };
 
+static const struct v4l2_subdev_vbi_ops saa7127_vbi_ops = {
+	.s_vbi_data = saa7127_s_vbi_data,
+	.g_sliced_fmt = saa7127_g_sliced_fmt,
+};
+
 static const struct v4l2_subdev_ops saa7127_ops = {
 	.core = &saa7127_core_ops,
 	.video = &saa7127_video_ops,
+	.vbi = &saa7127_vbi_ops,
 };
 
 /* ----------------------------------------------------------------------- */
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index d48c450..d3bd82a 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -1011,8 +1011,6 @@
 	unsigned int idx;
 	int err, addr;
 
-	if (snd_BUG_ON(!chip))
-		return -EINVAL;
 	strcpy(card->mixername, "SAA7134 Mixer");
 
 	for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_volume_controls); idx++) {
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 297833f..72700d4e 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -5355,6 +5355,79 @@
 			.amux = LINE2,
 		},
 	},
+	[SAA7134_BOARD_HAWELL_HW_404M7] = {
+		/* Hawell HW-404M7 & Hawell HW-808M7  */
+		/* Bogoslovskiy Viktor <bogovic@bk.ru> */
+		.name         = "Hawell HW-404M7",
+		.audio_clock   = 0x00200000,
+		.tuner_type    = UNSET,
+		.radio_type    = UNSET,
+		.tuner_addr   = ADDR_UNSET,
+		.radio_addr   = ADDR_UNSET,
+		.gpiomask      = 0x389c00,
+		.inputs       = {{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+			.gpio = 0x01fc00,
+		} },
+	},
+	[SAA7134_BOARD_BEHOLD_H7] = {
+		/* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV H7",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_XC5000,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.ts_type	= SAA7134_MPEG_TS_PARALLEL,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 2,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 9,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_A7] = {
+		/* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV A7",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_XC5000,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 2,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 9,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+		},
+	},
 
 };
 
@@ -6549,6 +6622,18 @@
 		.subvendor    = PCI_ANY_ID,
 		.subdevice    = PCI_ANY_ID,
 		.driver_data  = SAA7134_BOARD_UNKNOWN,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5ace, /* Beholder Intl. Ltd. */
+		.subdevice    = 0x7190,
+		.driver_data  = SAA7134_BOARD_BEHOLD_H7,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5ace, /* Beholder Intl. Ltd. */
+		.subdevice    = 0x7090,
+		.driver_data  = SAA7134_BOARD_BEHOLD_A7,
 	},{
 		/* --- end of list --- */
 	}
@@ -6602,6 +6687,8 @@
 {
 	switch (dev->board) {
 	case SAA7134_BOARD_BEHOLD_X7:
+	case SAA7134_BOARD_BEHOLD_H7:
+	case SAA7134_BOARD_BEHOLD_A7:
 		if (command == XC5000_TUNER_RESET) {
 		/* Down and UP pheripherial RESET pin for reset all chips */
 			saa_writeb(SAA7134_SPECIAL_MODE, 0x00);
@@ -6973,6 +7060,8 @@
 	case SAA7134_BOARD_BEHOLD_M6_EXTRA:
 	case SAA7134_BOARD_BEHOLD_H6:
 	case SAA7134_BOARD_BEHOLD_X7:
+	case SAA7134_BOARD_BEHOLD_H7:
+	case SAA7134_BOARD_BEHOLD_A7:
 		dev->has_remote = SAA7134_REMOTE_I2C;
 		break;
 	case SAA7134_BOARD_AVERMEDIA_A169_B:
@@ -7215,6 +7304,11 @@
 		       printk(KERN_INFO "%s: P7131 analog only, using "
 						       "entry of %s\n",
 		       dev->name, saa7134_boards[dev->board].name);
+
+			/* IR init has already happened for other cards, so
+			 * we have to catch up. */
+			dev->has_remote = SAA7134_REMOTE_GPIO;
+			saa7134_input_init1(dev);
 	       }
 	       break;
 	case SAA7134_BOARD_HAUPPAUGE_HVR1150:
@@ -7344,6 +7438,23 @@
 		}
 		break;
 	}
+	case SAA7134_BOARD_BEHOLD_H6:
+	{
+		u8 data[] = { 0x09, 0x9f, 0x86, 0x11};
+		struct i2c_msg msg = {.addr = 0x61, .flags = 0, .buf = data,
+							.len = sizeof(data)};
+
+		/* The tuner TUNER_PHILIPS_FMD1216MEX_MK3 after hardware    */
+		/* start has disabled IF and enabled DVB-T. When saa7134    */
+		/* scan I2C devices it not detect IF tda9887 and can`t      */
+		/* watch TV without software reboot. For solve this problem */
+		/* switch the tuner to analog TV mode manually.             */
+		if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
+				printk(KERN_WARNING
+				      "%s: Unable to enable IF of the tuner.\n",
+				       dev->name);
+		break;
+	}
 	} /* switch() */
 
 	/* initialize tuner */
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index a7ad781..90f2318 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -471,7 +471,7 @@
 	"DONE_RA0", "DONE_RA1", "DONE_RA2", "DONE_RA3",
 	"AR", "PE", "PWR_ON", "RDCAP", "INTL", "FIDT", "MMC",
 	"TRIG_ERR", "CONF_ERR", "LOAD_ERR",
-	"GPIO16?", "GPIO18", "GPIO22", "GPIO23"
+	"GPIO16", "GPIO18", "GPIO22", "GPIO23"
 };
 #define IRQBITS ARRAY_SIZE(irqbits)
 
@@ -601,12 +601,14 @@
 			/* disable gpio16 IRQ */
 			printk(KERN_WARNING "%s/irq: looping -- "
 			       "clearing GPIO16 enable bit\n",dev->name);
-			saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO16);
+			saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO16_P);
+			saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO16_N);
 		} else if (report & SAA7134_IRQ_REPORT_GPIO18) {
 			/* disable gpio18 IRQs */
 			printk(KERN_WARNING "%s/irq: looping -- "
 			       "clearing GPIO18 enable bit\n",dev->name);
-			saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18);
+			saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18_P);
+			saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18_N);
 		} else {
 			/* disable all irqs */
 			printk(KERN_WARNING "%s/irq: looping -- "
@@ -698,11 +700,13 @@
 
 	if (dev->has_remote == SAA7134_REMOTE_GPIO && dev->remote) {
 		if (dev->remote->mask_keydown & 0x10000)
-			irq2_mask |= SAA7134_IRQ2_INTE_GPIO16;
-		else if (dev->remote->mask_keydown & 0x40000)
-			irq2_mask |= SAA7134_IRQ2_INTE_GPIO18;
-		else if (dev->remote->mask_keyup & 0x40000)
-			irq2_mask |= SAA7134_IRQ2_INTE_GPIO18A;
+			irq2_mask |= SAA7134_IRQ2_INTE_GPIO16_N;
+		else {		/* Allow enabling both IRQ edge triggers */
+			if (dev->remote->mask_keydown & 0x40000)
+				irq2_mask |= SAA7134_IRQ2_INTE_GPIO18_P;
+			if (dev->remote->mask_keyup & 0x40000)
+				irq2_mask |= SAA7134_IRQ2_INTE_GPIO18_N;
+		}
 	}
 
 	if (dev->has_remote == SAA7134_REMOTE_I2C) {
@@ -1227,7 +1231,7 @@
 	if (card_has_mpeg(dev))
 		saa7134_ts_init_hw(dev);
 	if (dev->remote)
-		saa7134_ir_start(dev, dev->remote);
+		saa7134_ir_start(dev);
 	saa7134_hw_enable1(dev);
 
 	msleep(100);
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 4ab4a98..31e82be 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -1532,6 +1532,15 @@
 				   &dev->i2c_adap, &behold_x7_tunerconfig);
 		}
 		break;
+	case SAA7134_BOARD_BEHOLD_H7:
+		fe0->dvb.frontend = dvb_attach(zl10353_attach,
+						&behold_x7_config,
+						&dev->i2c_adap);
+		if (fe0->dvb.frontend) {
+			dvb_attach(xc5000_attach, fe0->dvb.frontend,
+				   &dev->i2c_adap, &behold_x7_tunerconfig);
+		}
+		break;
 	case SAA7134_BOARD_AVERMEDIA_A700_PRO:
 	case SAA7134_BOARD_AVERMEDIA_A700_HYBRID:
 		/* Zarlink ZL10313 */
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 58a0cdc..e5565e2 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -28,6 +28,8 @@
 #include "saa7134-reg.h"
 #include "saa7134.h"
 
+#define MODULE_NAME "saa7134"
+
 static unsigned int disable_ir;
 module_param(disable_ir, int, 0444);
 MODULE_PARM_DESC(disable_ir,"disable infrared remote support");
@@ -66,6 +68,7 @@
 /* Helper functions for RC5 and NEC decoding at GPIO16 or GPIO18 */
 static int saa7134_rc5_irq(struct saa7134_dev *dev);
 static int saa7134_nec_irq(struct saa7134_dev *dev);
+static int saa7134_raw_decode_irq(struct saa7134_dev *dev);
 static void nec_task(unsigned long data);
 static void saa7134_nec_timer(unsigned long data);
 
@@ -397,14 +400,23 @@
 
 void saa7134_input_irq(struct saa7134_dev *dev)
 {
-	struct card_ir *ir = dev->remote;
+	struct card_ir *ir;
+
+	if (!dev || !dev->remote)
+		return;
+
+	ir = dev->remote;
+	if (!ir->running)
+		return;
 
 	if (ir->nec_gpio) {
 		saa7134_nec_irq(dev);
-	} else if (!ir->polling && !ir->rc5_gpio) {
+	} else if (!ir->polling && !ir->rc5_gpio && !ir->raw_decode) {
 		build_key(dev);
 	} else if (ir->rc5_gpio) {
 		saa7134_rc5_irq(dev);
+	} else if (ir->raw_decode) {
+		saa7134_raw_decode_irq(dev);
 	}
 }
 
@@ -417,8 +429,32 @@
 	mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
 }
 
-void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir)
+void ir_raw_decode_timer_end(unsigned long data)
 {
+	struct saa7134_dev *dev = (struct saa7134_dev *)data;
+	struct card_ir *ir = dev->remote;
+
+	ir_raw_event_handle(dev->remote->dev);
+
+	ir->active = 0;
+}
+
+static int __saa7134_ir_start(void *priv)
+{
+	struct saa7134_dev *dev = priv;
+	struct card_ir *ir;
+
+	if (!dev)
+		return -EINVAL;
+
+	ir  = dev->remote;
+	if (!ir)
+		return -EINVAL;
+
+	if (ir->running)
+		return 0;
+
+	ir->running = 1;
 	if (ir->polling) {
 		setup_timer(&ir->timer, saa7134_input_timer,
 			    (unsigned long)dev);
@@ -441,26 +477,125 @@
 		setup_timer(&ir->timer_keyup, saa7134_nec_timer,
 			    (unsigned long)dev);
 		tasklet_init(&ir->tlet, nec_task, (unsigned long)dev);
+	} else if (ir->raw_decode) {
+		/* set timer_end for code completion */
+		init_timer(&ir->timer_end);
+		ir->timer_end.function = ir_raw_decode_timer_end;
+		ir->timer_end.data = (unsigned long)dev;
+		ir->active = 0;
 	}
+
+	return 0;
+}
+
+static void __saa7134_ir_stop(void *priv)
+{
+	struct saa7134_dev *dev = priv;
+	struct card_ir *ir;
+
+	if (!dev)
+		return;
+
+	ir  = dev->remote;
+	if (!ir)
+		return;
+
+	if (!ir->running)
+		return;
+	if (dev->remote->polling)
+		del_timer_sync(&dev->remote->timer);
+	else if (ir->rc5_gpio)
+		del_timer_sync(&ir->timer_end);
+	else if (ir->nec_gpio)
+		tasklet_kill(&ir->tlet);
+	else if (ir->raw_decode) {
+		del_timer_sync(&ir->timer_end);
+		ir->active = 0;
+	}
+
+	ir->running = 0;
+
+	return;
+}
+
+int saa7134_ir_start(struct saa7134_dev *dev)
+{
+	if (dev->remote->users)
+		return __saa7134_ir_start(dev);
+
+	return 0;
 }
 
 void saa7134_ir_stop(struct saa7134_dev *dev)
 {
-	if (dev->remote->polling)
-		del_timer_sync(&dev->remote->timer);
+	if (dev->remote->users)
+		__saa7134_ir_stop(dev);
+}
+
+static int saa7134_ir_open(void *priv)
+{
+	struct saa7134_dev *dev = priv;
+
+	dev->remote->users++;
+	return __saa7134_ir_start(dev);
+}
+
+static void saa7134_ir_close(void *priv)
+{
+	struct saa7134_dev *dev = priv;
+
+	dev->remote->users--;
+	if (!dev->remote->users)
+		__saa7134_ir_stop(dev);
+}
+
+
+int saa7134_ir_change_protocol(void *priv, u64 ir_type)
+{
+	struct saa7134_dev *dev = priv;
+	struct card_ir *ir = dev->remote;
+	u32 nec_gpio, rc5_gpio;
+
+	if (ir_type == IR_TYPE_RC5) {
+		dprintk("Changing protocol to RC5\n");
+		nec_gpio = 0;
+		rc5_gpio = 1;
+	} else if (ir_type == IR_TYPE_NEC) {
+		dprintk("Changing protocol to NEC\n");
+		nec_gpio = 1;
+		rc5_gpio = 0;
+	} else {
+		dprintk("IR protocol type %ud is not supported\n",
+			(unsigned)ir_type);
+		return -EINVAL;
+	}
+
+	if (ir->running) {
+		saa7134_ir_stop(dev);
+		ir->nec_gpio = nec_gpio;
+		ir->rc5_gpio = rc5_gpio;
+		saa7134_ir_start(dev);
+	} else {
+		ir->nec_gpio = nec_gpio;
+		ir->rc5_gpio = rc5_gpio;
+	}
+
+	return 0;
 }
 
 int saa7134_input_init1(struct saa7134_dev *dev)
 {
 	struct card_ir *ir;
 	struct input_dev *input_dev;
-	struct ir_scancode_table *ir_codes = NULL;
+	char *ir_codes = NULL;
 	u32 mask_keycode = 0;
 	u32 mask_keydown = 0;
 	u32 mask_keyup   = 0;
 	int polling      = 0;
 	int rc5_gpio	 = 0;
 	int nec_gpio	 = 0;
+	int raw_decode   = 0;
+	int allow_protocol_change = 0;
 	u64 ir_type = IR_TYPE_OTHER;
 	int err;
 
@@ -476,27 +611,27 @@
 	case SAA7134_BOARD_FLYTVPLATINUM_FM:
 	case SAA7134_BOARD_FLYTVPLATINUM_MINI2:
 	case SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM:
-		ir_codes     = &ir_codes_flyvideo_table;
+		ir_codes     = RC_MAP_FLYVIDEO;
 		mask_keycode = 0xEC00000;
 		mask_keydown = 0x0040000;
 		break;
 	case SAA7134_BOARD_CINERGY400:
 	case SAA7134_BOARD_CINERGY600:
 	case SAA7134_BOARD_CINERGY600_MK3:
-		ir_codes     = &ir_codes_cinergy_table;
+		ir_codes     = RC_MAP_CINERGY;
 		mask_keycode = 0x00003f;
 		mask_keyup   = 0x040000;
 		break;
 	case SAA7134_BOARD_ECS_TVP3XP:
 	case SAA7134_BOARD_ECS_TVP3XP_4CB5:
-		ir_codes     = &ir_codes_eztv_table;
+		ir_codes     = RC_MAP_EZTV;
 		mask_keycode = 0x00017c;
 		mask_keyup   = 0x000002;
 		polling      = 50; // ms
 		break;
 	case SAA7134_BOARD_KWORLD_XPERT:
 	case SAA7134_BOARD_AVACSSMARTTV:
-		ir_codes     = &ir_codes_pixelview_table;
+		ir_codes     = RC_MAP_PIXELVIEW;
 		mask_keycode = 0x00001F;
 		mask_keyup   = 0x000020;
 		polling      = 50; // ms
@@ -513,7 +648,7 @@
 	case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
 	case SAA7134_BOARD_AVERMEDIA_M102:
 	case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS:
-		ir_codes     = &ir_codes_avermedia_table;
+		ir_codes     = RC_MAP_AVERMEDIA;
 		mask_keycode = 0x0007C8;
 		mask_keydown = 0x000010;
 		polling      = 50; // ms
@@ -522,14 +657,15 @@
 		saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
 		break;
 	case SAA7134_BOARD_AVERMEDIA_M135A:
-		ir_codes     = &ir_codes_avermedia_m135a_table;
-		mask_keydown = 0x0040000;
-		mask_keycode = 0x00013f;
-		nec_gpio     = 1;
+		ir_codes     = RC_MAP_AVERMEDIA_M135A_RM_JX;
+		mask_keydown = 0x0040000;	/* Enable GPIO18 line on both edges */
+		mask_keyup   = 0x0040000;
+		mask_keycode = 0xffff;
+		raw_decode   = 1;
 		break;
 	case SAA7134_BOARD_AVERMEDIA_777:
 	case SAA7134_BOARD_AVERMEDIA_A16AR:
-		ir_codes     = &ir_codes_avermedia_table;
+		ir_codes     = RC_MAP_AVERMEDIA;
 		mask_keycode = 0x02F200;
 		mask_keydown = 0x000400;
 		polling      = 50; // ms
@@ -538,7 +674,7 @@
 		saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
 		break;
 	case SAA7134_BOARD_AVERMEDIA_A16D:
-		ir_codes     = &ir_codes_avermedia_a16d_table;
+		ir_codes     = RC_MAP_AVERMEDIA_A16D;
 		mask_keycode = 0x02F200;
 		mask_keydown = 0x000400;
 		polling      = 50; /* ms */
@@ -547,14 +683,14 @@
 		saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
 		break;
 	case SAA7134_BOARD_KWORLD_TERMINATOR:
-		ir_codes     = &ir_codes_pixelview_table;
+		ir_codes     = RC_MAP_PIXELVIEW;
 		mask_keycode = 0x00001f;
 		mask_keyup   = 0x000060;
 		polling      = 50; // ms
 		break;
 	case SAA7134_BOARD_MANLI_MTV001:
 	case SAA7134_BOARD_MANLI_MTV002:
-		ir_codes     = &ir_codes_manli_table;
+		ir_codes     = RC_MAP_MANLI;
 		mask_keycode = 0x001f00;
 		mask_keyup   = 0x004000;
 		polling      = 50; /* ms */
@@ -574,25 +710,25 @@
 	case SAA7134_BOARD_BEHOLD_507_9FM:
 	case SAA7134_BOARD_BEHOLD_507RDS_MK3:
 	case SAA7134_BOARD_BEHOLD_507RDS_MK5:
-		ir_codes     = &ir_codes_manli_table;
+		ir_codes     = RC_MAP_MANLI;
 		mask_keycode = 0x003f00;
 		mask_keyup   = 0x004000;
 		polling      = 50; /* ms */
 		break;
 	case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
-		ir_codes     = &ir_codes_behold_columbus_table;
+		ir_codes     = RC_MAP_BEHOLD_COLUMBUS;
 		mask_keycode = 0x003f00;
 		mask_keyup   = 0x004000;
 		polling      = 50; // ms
 		break;
 	case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
-		ir_codes     = &ir_codes_pctv_sedna_table;
+		ir_codes     = RC_MAP_PCTV_SEDNA;
 		mask_keycode = 0x001f00;
 		mask_keyup   = 0x004000;
 		polling      = 50; // ms
 		break;
 	case SAA7134_BOARD_GOTVIEW_7135:
-		ir_codes     = &ir_codes_gotview7135_table;
+		ir_codes     = RC_MAP_GOTVIEW7135;
 		mask_keycode = 0x0003CC;
 		mask_keydown = 0x000010;
 		polling	     = 5; /* ms */
@@ -601,80 +737,80 @@
 	case SAA7134_BOARD_VIDEOMATE_TV_PVR:
 	case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
 	case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
-		ir_codes     = &ir_codes_videomate_tv_pvr_table;
+		ir_codes     = RC_MAP_VIDEOMATE_TV_PVR;
 		mask_keycode = 0x00003F;
 		mask_keyup   = 0x400000;
 		polling      = 50; // ms
 		break;
 	case SAA7134_BOARD_PROTEUS_2309:
-		ir_codes     = &ir_codes_proteus_2309_table;
+		ir_codes     = RC_MAP_PROTEUS_2309;
 		mask_keycode = 0x00007F;
 		mask_keyup   = 0x000080;
 		polling      = 50; // ms
 		break;
 	case SAA7134_BOARD_VIDEOMATE_DVBT_300:
 	case SAA7134_BOARD_VIDEOMATE_DVBT_200:
-		ir_codes     = &ir_codes_videomate_tv_pvr_table;
+		ir_codes     = RC_MAP_VIDEOMATE_TV_PVR;
 		mask_keycode = 0x003F00;
 		mask_keyup   = 0x040000;
 		break;
 	case SAA7134_BOARD_FLYDVBS_LR300:
 	case SAA7134_BOARD_FLYDVBT_LR301:
 	case SAA7134_BOARD_FLYDVBTDUO:
-		ir_codes     = &ir_codes_flydvb_table;
+		ir_codes     = RC_MAP_FLYDVB;
 		mask_keycode = 0x0001F00;
 		mask_keydown = 0x0040000;
 		break;
 	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
 	case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
 	case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
-		ir_codes     = &ir_codes_asus_pc39_table;
+		ir_codes     = RC_MAP_ASUS_PC39;
 		mask_keydown = 0x0040000;
 		rc5_gpio = 1;
 		break;
 	case SAA7134_BOARD_ENCORE_ENLTV:
 	case SAA7134_BOARD_ENCORE_ENLTV_FM:
-		ir_codes     = &ir_codes_encore_enltv_table;
+		ir_codes     = RC_MAP_ENCORE_ENLTV;
 		mask_keycode = 0x00007f;
 		mask_keyup   = 0x040000;
 		polling      = 50; // ms
 		break;
 	case SAA7134_BOARD_ENCORE_ENLTV_FM53:
-		ir_codes     = &ir_codes_encore_enltv_fm53_table;
+		ir_codes     = RC_MAP_ENCORE_ENLTV_FM53;
 		mask_keydown = 0x0040000;
 		mask_keycode = 0x00007f;
 		nec_gpio = 1;
 		break;
 	case SAA7134_BOARD_10MOONSTVMASTER3:
-		ir_codes     = &ir_codes_encore_enltv_table;
+		ir_codes     = RC_MAP_ENCORE_ENLTV;
 		mask_keycode = 0x5f80000;
 		mask_keyup   = 0x8000000;
 		polling      = 50; //ms
 		break;
 	case SAA7134_BOARD_GENIUS_TVGO_A11MCE:
-		ir_codes     = &ir_codes_genius_tvgo_a11mce_table;
+		ir_codes     = RC_MAP_GENIUS_TVGO_A11MCE;
 		mask_keycode = 0xff;
 		mask_keydown = 0xf00000;
 		polling = 50; /* ms */
 		break;
 	case SAA7134_BOARD_REAL_ANGEL_220:
-		ir_codes     = &ir_codes_real_audio_220_32_keys_table;
+		ir_codes     = RC_MAP_REAL_AUDIO_220_32_KEYS;
 		mask_keycode = 0x3f00;
 		mask_keyup   = 0x4000;
 		polling = 50; /* ms */
 		break;
 	case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
-		ir_codes     = &ir_codes_kworld_plus_tv_analog_table;
+		ir_codes     = RC_MAP_KWORLD_PLUS_TV_ANALOG;
 		mask_keycode = 0x7f;
 		polling = 40; /* ms */
 		break;
 	case SAA7134_BOARD_VIDEOMATE_S350:
-		ir_codes     = &ir_codes_videomate_s350_table;
+		ir_codes     = RC_MAP_VIDEOMATE_S350;
 		mask_keycode = 0x003f00;
 		mask_keydown = 0x040000;
 		break;
 	case SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S:
-		ir_codes     = &ir_codes_winfast_table;
+		ir_codes     = RC_MAP_WINFAST;
 		mask_keycode = 0x5f00;
 		mask_keyup   = 0x020000;
 		polling      = 50; /* ms */
@@ -695,6 +831,9 @@
 	}
 
 	ir->dev = input_dev;
+	dev->remote = ir;
+
+	ir->running = 0;
 
 	/* init hardware-specific stuff */
 	ir->mask_keycode = mask_keycode;
@@ -703,6 +842,7 @@
 	ir->polling      = polling;
 	ir->rc5_gpio	 = rc5_gpio;
 	ir->nec_gpio	 = nec_gpio;
+	ir->raw_decode	 = raw_decode;
 
 	/* init input device */
 	snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)",
@@ -710,6 +850,19 @@
 	snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
 		 pci_name(dev->pci));
 
+
+	ir->props.priv = dev;
+	ir->props.open = saa7134_ir_open;
+	ir->props.close = saa7134_ir_close;
+
+	if (raw_decode)
+		ir->props.driver_type = RC_DRIVER_IR_RAW;
+
+	if (!raw_decode && allow_protocol_change) {
+		ir->props.allowed_protos = IR_TYPE_RC5 | IR_TYPE_NEC;
+		ir->props.change_protocol = saa7134_ir_change_protocol;
+	}
+
 	err = ir_input_init(input_dev, &ir->ir, ir_type);
 	if (err < 0)
 		goto err_out_free;
@@ -727,12 +880,9 @@
 	}
 	input_dev->dev.parent = &dev->pci->dev;
 
-	dev->remote = ir;
-	saa7134_ir_start(dev, ir);
-
-	err = ir_input_register(ir->dev, ir_codes, NULL);
+	err = ir_input_register(ir->dev, ir_codes, &ir->props, MODULE_NAME);
 	if (err)
-		goto err_out_stop;
+		goto err_out_free;
 
 	/* the remote isn't as bouncy as a keyboard */
 	ir->dev->rep[REP_DELAY] = repeat_delay;
@@ -740,10 +890,8 @@
 
 	return 0;
 
- err_out_stop:
-	saa7134_ir_stop(dev);
+err_out_free:
 	dev->remote = NULL;
- err_out_free:
 	kfree(ir);
 	return err;
 }
@@ -787,24 +935,24 @@
 		dev->init_data.name = "Pinnacle PCTV";
 		if (pinnacle_remote == 0) {
 			dev->init_data.get_key = get_key_pinnacle_color;
-			dev->init_data.ir_codes = &ir_codes_pinnacle_color_table;
+			dev->init_data.ir_codes = RC_MAP_PINNACLE_COLOR;
 			info.addr = 0x47;
 		} else {
 			dev->init_data.get_key = get_key_pinnacle_grey;
-			dev->init_data.ir_codes = &ir_codes_pinnacle_grey_table;
+			dev->init_data.ir_codes = RC_MAP_PINNACLE_GREY;
 			info.addr = 0x47;
 		}
 		break;
 	case SAA7134_BOARD_UPMOST_PURPLE_TV:
 		dev->init_data.name = "Purple TV";
 		dev->init_data.get_key = get_key_purpletv;
-		dev->init_data.ir_codes = &ir_codes_purpletv_table;
+		dev->init_data.ir_codes = RC_MAP_PURPLETV;
 		info.addr = 0x7a;
 		break;
 	case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS:
 		dev->init_data.name = "MSI TV@nywhere Plus";
 		dev->init_data.get_key = get_key_msi_tvanywhere_plus;
-		dev->init_data.ir_codes = &ir_codes_msi_tvanywhere_plus_table;
+		dev->init_data.ir_codes = RC_MAP_MSI_TVANYWHERE_PLUS;
 		info.addr = 0x30;
 		/* MSI TV@nywhere Plus controller doesn't seem to
 		   respond to probes unless we read something from
@@ -818,7 +966,7 @@
 	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
 		dev->init_data.name = "HVR 1110";
 		dev->init_data.get_key = get_key_hvr1110;
-		dev->init_data.ir_codes = &ir_codes_hauppauge_new_table;
+		dev->init_data.ir_codes = RC_MAP_HAUPPAUGE_NEW;
 		info.addr = 0x71;
 		break;
 	case SAA7134_BOARD_BEHOLD_607FM_MK3:
@@ -834,9 +982,12 @@
 	case SAA7134_BOARD_BEHOLD_M6_EXTRA:
 	case SAA7134_BOARD_BEHOLD_H6:
 	case SAA7134_BOARD_BEHOLD_X7:
+	case SAA7134_BOARD_BEHOLD_H7:
+	case SAA7134_BOARD_BEHOLD_A7:
 		dev->init_data.name = "BeholdTV";
 		dev->init_data.get_key = get_key_beholdm6xx;
-		dev->init_data.ir_codes = &ir_codes_behold_table;
+		dev->init_data.ir_codes = RC_MAP_BEHOLD;
+		dev->init_data.type = IR_TYPE_NEC;
 		info.addr = 0x2d;
 		break;
 	case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
@@ -846,7 +997,7 @@
 	case SAA7134_BOARD_FLYDVB_TRIO:
 		dev->init_data.name = "FlyDVB Trio";
 		dev->init_data.get_key = get_key_flydvb_trio;
-		dev->init_data.ir_codes = &ir_codes_flydvb_table;
+		dev->init_data.ir_codes = RC_MAP_FLYDVB;
 		info.addr = 0x0b;
 		break;
 	default:
@@ -859,6 +1010,33 @@
 	i2c_new_device(&dev->i2c_adap, &info);
 }
 
+static int saa7134_raw_decode_irq(struct saa7134_dev *dev)
+{
+	struct card_ir	*ir = dev->remote;
+	unsigned long 	timeout;
+	int space;
+
+	/* Generate initial event */
+	saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+	saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+	space = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & ir->mask_keydown;
+	ir_raw_event_store_edge(dev->remote->dev, space ? IR_SPACE : IR_PULSE);
+
+
+	/*
+	 * Wait 15 ms from the start of the first IR event before processing
+	 * the event. This time is enough for NEC protocol. May need adjustments
+	 * to work with other protocols.
+	 */
+	if (!ir->active) {
+		timeout = jiffies + jiffies_to_msecs(15);
+		mod_timer(&ir->timer_end, timeout);
+		ir->active = 1;
+	}
+
+	return 1;
+}
+
 static int saa7134_rc5_irq(struct saa7134_dev *dev)
 {
 	struct card_ir *ir = dev->remote;
@@ -901,7 +1079,6 @@
 	return 1;
 }
 
-
 /* On NEC protocol, One has 2.25 ms, and zero has 1.125 ms
    The first pulse (start) has 9 + 4.5 ms
  */
@@ -1011,14 +1188,14 @@
 	/* Keep repeating the last key */
 	mod_timer(&ir->timer_keyup, jiffies + msecs_to_jiffies(150));
 
-	saa_setl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18);
+	saa_setl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18_P);
 }
 
 static int saa7134_nec_irq(struct saa7134_dev *dev)
 {
 	struct card_ir *ir = dev->remote;
 
-	saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18);
+	saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18_P);
 	tasklet_schedule(&ir->tlet);
 
 	return 1;
diff --git a/drivers/media/video/saa7134/saa7134-reg.h b/drivers/media/video/saa7134/saa7134-reg.h
index cf89d96..e7e0af1 100644
--- a/drivers/media/video/saa7134/saa7134-reg.h
+++ b/drivers/media/video/saa7134/saa7134-reg.h
@@ -112,17 +112,17 @@
 #define   SAA7134_IRQ1_INTE_RA0_0               (1 <<  0)
 
 #define SAA7134_IRQ2                            (0x2c8 >> 2)
-#define   SAA7134_IRQ2_INTE_GPIO23A             (1 << 17)
-#define   SAA7134_IRQ2_INTE_GPIO23              (1 << 16)
-#define   SAA7134_IRQ2_INTE_GPIO22A             (1 << 15)
-#define   SAA7134_IRQ2_INTE_GPIO22              (1 << 14)
-#define   SAA7134_IRQ2_INTE_GPIO18A             (1 << 13)
-#define   SAA7134_IRQ2_INTE_GPIO18              (1 << 12)
-#define   SAA7134_IRQ2_INTE_GPIO16              (1 << 11) /* not certain */
-#define   SAA7134_IRQ2_INTE_SC2                 (1 << 10)
-#define   SAA7134_IRQ2_INTE_SC1                 (1 <<  9)
-#define   SAA7134_IRQ2_INTE_SC0                 (1 <<  8)
-#define   SAA7134_IRQ2_INTE_DEC5                (1 <<  7)
+#define   SAA7134_IRQ2_INTE_GPIO23_N             (1 << 17)	/* negative edge */
+#define   SAA7134_IRQ2_INTE_GPIO23_P             (1 << 16)	/* positive edge */
+#define   SAA7134_IRQ2_INTE_GPIO22_N             (1 << 15)	/* negative edge */
+#define   SAA7134_IRQ2_INTE_GPIO22_P             (1 << 14)	/* positive edge */
+#define   SAA7134_IRQ2_INTE_GPIO18_N             (1 << 13)	/* negative edge */
+#define   SAA7134_IRQ2_INTE_GPIO18_P             (1 << 12)	/* positive edge */
+#define   SAA7134_IRQ2_INTE_GPIO16_N             (1 << 11)	/* negative edge */
+#define   SAA7134_IRQ2_INTE_GPIO16_P             (1 << 10)	/* positive edge */
+#define   SAA7134_IRQ2_INTE_SC2                 (1 <<  9)
+#define   SAA7134_IRQ2_INTE_SC1                 (1 <<  8)
+#define   SAA7134_IRQ2_INTE_SC0                 (1 <<  7)
 #define   SAA7134_IRQ2_INTE_DEC4                (1 <<  6)
 #define   SAA7134_IRQ2_INTE_DEC3                (1 <<  5)
 #define   SAA7134_IRQ2_INTE_DEC2                (1 <<  4)
@@ -135,7 +135,7 @@
 #define   SAA7134_IRQ_REPORT_GPIO23             (1 << 17)
 #define   SAA7134_IRQ_REPORT_GPIO22             (1 << 16)
 #define   SAA7134_IRQ_REPORT_GPIO18             (1 << 15)
-#define   SAA7134_IRQ_REPORT_GPIO16             (1 << 14) /* not certain */
+#define   SAA7134_IRQ_REPORT_GPIO16             (1 << 14)
 #define   SAA7134_IRQ_REPORT_LOAD_ERR           (1 << 13)
 #define   SAA7134_IRQ_REPORT_CONF_ERR           (1 << 12)
 #define   SAA7134_IRQ_REPORT_TRIG_ERR           (1 << 11)
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index 31138d3..45f0ac8 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -1180,7 +1180,7 @@
 	   That needs to be fixed somehow, but for now this is
 	   good enough. */
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
@@ -1359,7 +1359,7 @@
 	fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_BGR24);
 	fh->width    = 720;
 	fh->height   = 576;
-	v4l2_prio_open(&dev->prio,&fh->prio);
+	v4l2_prio_open(&dev->prio, &fh->prio);
 
 	videobuf_queue_sg_init(&fh->cap, &video_qops,
 			    &dev->pci->dev, &dev->slock,
@@ -1502,7 +1502,7 @@
 	saa7134_pgtable_free(dev->pci,&fh->pt_cap);
 	saa7134_pgtable_free(dev->pci,&fh->pt_vbi);
 
-	v4l2_prio_close(&dev->prio,&fh->prio);
+	v4l2_prio_close(&dev->prio, fh->prio);
 	file->private_data = NULL;
 	kfree(fh);
 	return 0;
@@ -1632,8 +1632,15 @@
 	}
 
 	f->fmt.pix.field = field;
-	v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2,
-			      &f->fmt.pix.height, 32, maxh, 0, 0);
+	if (f->fmt.pix.width  < 48)
+		f->fmt.pix.width  = 48;
+	if (f->fmt.pix.height < 32)
+		f->fmt.pix.height = 32;
+	if (f->fmt.pix.width > maxw)
+		f->fmt.pix.width = maxw;
+	if (f->fmt.pix.height > maxh)
+		f->fmt.pix.height = maxh;
+	f->fmt.pix.width &= ~0x03;
 	f->fmt.pix.bytesperline =
 		(f->fmt.pix.width * fmt->depth) >> 3;
 	f->fmt.pix.sizeimage =
@@ -1778,7 +1785,7 @@
 	struct saa7134_dev *dev = fh->dev;
 	int err;
 
-	err = v4l2_prio_check(&dev->prio, &fh->prio);
+	err = v4l2_prio_check(&dev->prio, fh->prio);
 	if (0 != err)
 		return err;
 
@@ -1832,7 +1839,7 @@
 	   That needs to be fixed somehow, but for now this is
 	   good enough. */
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	} else if (res_locked(dev, RESOURCE_OVERLAY)) {
@@ -2016,7 +2023,7 @@
 	struct saa7134_dev *dev = fh->dev;
 	int rx, mode, err;
 
-	err = v4l2_prio_check(&dev->prio, &fh->prio);
+	err = v4l2_prio_check(&dev->prio, fh->prio);
 	if (0 != err)
 		return err;
 
@@ -2050,7 +2057,7 @@
 	struct saa7134_dev *dev = fh->dev;
 	int err;
 
-	err = v4l2_prio_check(&dev->prio, &fh->prio);
+	err = v4l2_prio_check(&dev->prio, fh->prio);
 	if (0 != err)
 		return err;
 
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index bf13096..3962534 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -20,7 +20,7 @@
  */
 
 #include <linux/version.h>
-#define SAA7134_VERSION_CODE KERNEL_VERSION(0,2,15)
+#define SAA7134_VERSION_CODE KERNEL_VERSION(0, 2, 16)
 
 #include <linux/pci.h>
 #include <linux/i2c.h>
@@ -300,6 +300,9 @@
 #define SAA7134_BOARD_ASUS_EUROPA_HYBRID	174
 #define SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S 175
 #define SAA7134_BOARD_BEHOLD_505RDS_MK3     176
+#define SAA7134_BOARD_HAWELL_HW_404M7		177
+#define SAA7134_BOARD_BEHOLD_H7             178
+#define SAA7134_BOARD_BEHOLD_A7             179
 
 #define SAA7134_MAXBOARDS 32
 #define SAA7134_INPUT_MAX 8
@@ -809,7 +812,7 @@
 void saa7134_input_fini(struct saa7134_dev *dev);
 void saa7134_input_irq(struct saa7134_dev *dev);
 void saa7134_probe_i2c_ir(struct saa7134_dev *dev);
-void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir);
+int saa7134_ir_start(struct saa7134_dev *dev);
 void saa7134_ir_stop(struct saa7134_dev *dev);
 
 
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 1ad980f..4ac3b48 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -115,9 +115,20 @@
 };
 
 struct sh_mobile_ceu_cam {
-	struct v4l2_rect ceu_rect;
-	unsigned int cam_width;
-	unsigned int cam_height;
+	/* CEU offsets within scaled by the CEU camera output */
+	unsigned int ceu_left;
+	unsigned int ceu_top;
+	/* Client output, as seen by the CEU */
+	unsigned int width;
+	unsigned int height;
+	/*
+	 * User window from S_CROP / G_CROP, produced by client cropping and
+	 * scaling, CEU scaling and CEU cropping, mapped back onto the client
+	 * input window
+	 */
+	struct v4l2_rect subrect;
+	/* Camera cropping rectangle */
+	struct v4l2_rect rect;
 	const struct soc_mbus_pixelfmt *extra_fmt;
 	enum v4l2_mbus_pixelcode code;
 };
@@ -213,8 +224,8 @@
 		*count = 2;
 
 	if (pcdev->video_limit) {
-		while (PAGE_ALIGN(*size) * *count > pcdev->video_limit)
-			(*count)--;
+		if (PAGE_ALIGN(*size) * *count > pcdev->video_limit)
+			*count = pcdev->video_limit / PAGE_ALIGN(*size);
 	}
 
 	dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size);
@@ -565,38 +576,36 @@
 }
 
 /* rect is guaranteed to not exceed the scaled camera rectangle */
-static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd,
-				   unsigned int out_width,
-				   unsigned int out_height)
+static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd)
 {
 	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 	struct sh_mobile_ceu_cam *cam = icd->host_priv;
-	struct v4l2_rect *rect = &cam->ceu_rect;
 	struct sh_mobile_ceu_dev *pcdev = ici->priv;
 	unsigned int height, width, cdwdr_width, in_width, in_height;
 	unsigned int left_offset, top_offset;
 	u32 camor;
 
-	dev_dbg(icd->dev.parent, "Crop %ux%u@%u:%u\n",
-		rect->width, rect->height, rect->left, rect->top);
+	dev_geo(icd->dev.parent, "Crop %ux%u@%u:%u\n",
+		icd->user_width, icd->user_height, cam->ceu_left, cam->ceu_top);
 
-	left_offset	= rect->left;
-	top_offset	= rect->top;
+	left_offset	= cam->ceu_left;
+	top_offset	= cam->ceu_top;
 
+	/* CEU cropping (CFSZR) is applied _after_ the scaling filter (CFLCR) */
 	if (pcdev->image_mode) {
-		in_width = rect->width;
+		in_width = cam->width;
 		if (!pcdev->is_16bit) {
 			in_width *= 2;
 			left_offset *= 2;
 		}
-		width = out_width;
-		cdwdr_width = out_width;
+		width = icd->user_width;
+		cdwdr_width = icd->user_width;
 	} else {
-		int bytes_per_line = soc_mbus_bytes_per_line(out_width,
+		int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
 						icd->current_fmt->host_fmt);
 		unsigned int w_factor;
 
-		width = out_width;
+		width = icd->user_width;
 
 		switch (icd->current_fmt->host_fmt->packing) {
 		case SOC_MBUS_PACKING_2X8_PADHI:
@@ -606,17 +615,17 @@
 			w_factor = 1;
 		}
 
-		in_width = rect->width * w_factor;
+		in_width = cam->width * w_factor;
 		left_offset = left_offset * w_factor;
 
 		if (bytes_per_line < 0)
-			cdwdr_width = out_width;
+			cdwdr_width = icd->user_width;
 		else
 			cdwdr_width = bytes_per_line;
 	}
 
-	height = out_height;
-	in_height = rect->height;
+	height = icd->user_height;
+	in_height = cam->height;
 	if (V4L2_FIELD_NONE != pcdev->field) {
 		height /= 2;
 		in_height /= 2;
@@ -775,9 +784,10 @@
 	}
 	ceu_write(pcdev, CAIFR, value);
 
-	sh_mobile_ceu_set_rect(icd, icd->user_width, icd->user_height);
+	sh_mobile_ceu_set_rect(icd);
 	mdelay(1);
 
+	dev_geo(icd->dev.parent, "CFLCR 0x%x\n", pcdev->cflcr);
 	ceu_write(pcdev, CFLCR, pcdev->cflcr);
 
 	/*
@@ -866,6 +876,8 @@
 		 fmt->packing == SOC_MBUS_PACKING_EXTEND16);
 }
 
+static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect);
+
 static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
 				     struct soc_camera_format_xlate *xlate)
 {
@@ -894,10 +906,55 @@
 		return 0;
 
 	if (!icd->host_priv) {
+		struct v4l2_mbus_framefmt mf;
+		struct v4l2_rect rect;
+		struct device *dev = icd->dev.parent;
+		int shift = 0;
+
+		/* FIXME: subwindow is lost between close / open */
+
+		/* Cache current client geometry */
+		ret = client_g_rect(sd, &rect);
+		if (ret < 0)
+			return ret;
+
+		/* First time */
+		ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
+		if (ret < 0)
+			return ret;
+
+		while ((mf.width > 2560 || mf.height > 1920) && shift < 4) {
+			/* Try 2560x1920, 1280x960, 640x480, 320x240 */
+			mf.width	= 2560 >> shift;
+			mf.height	= 1920 >> shift;
+			ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+			if (ret < 0)
+				return ret;
+			shift++;
+		}
+
+		if (shift == 4) {
+			dev_err(dev, "Failed to configure the client below %ux%x\n",
+				mf.width, mf.height);
+			return -EIO;
+		}
+
+		dev_geo(dev, "camera fmt %ux%u\n", mf.width, mf.height);
+
 		cam = kzalloc(sizeof(*cam), GFP_KERNEL);
 		if (!cam)
 			return -ENOMEM;
 
+		/* We are called with current camera crop, initialise subrect with it */
+		cam->rect	= rect;
+		cam->subrect	= rect;
+
+		cam->width	= mf.width;
+		cam->height	= mf.height;
+
+		cam->width	= mf.width;
+		cam->height	= mf.height;
+
 		icd->host_priv = cam;
 	} else {
 		cam = icd->host_priv;
@@ -979,16 +1036,12 @@
 	return (size * 4096 + scale / 2) / scale;
 }
 
-static unsigned int scale_up(unsigned int size, unsigned int scale)
-{
-	return (size * scale + 2048) / 4096;
-}
-
 static unsigned int calc_generic_scale(unsigned int input, unsigned int output)
 {
 	return (input * 4096 + output / 2) / output;
 }
 
+/* Get and store current client crop */
 static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect)
 {
 	struct v4l2_crop crop;
@@ -1007,25 +1060,51 @@
 	cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
 	ret = v4l2_subdev_call(sd, video, cropcap, &cap);
-	if (ret < 0)
-		return ret;
-
-	*rect = cap.defrect;
+	if (!ret)
+		*rect = cap.defrect;
 
 	return ret;
 }
 
+/* Client crop has changed, update our sub-rectangle to remain within the area */
+static void update_subrect(struct sh_mobile_ceu_cam *cam)
+{
+	struct v4l2_rect *rect = &cam->rect, *subrect = &cam->subrect;
+
+	if (rect->width < subrect->width)
+		subrect->width = rect->width;
+
+	if (rect->height < subrect->height)
+		subrect->height = rect->height;
+
+	if (rect->left > subrect->left)
+		subrect->left = rect->left;
+	else if (rect->left + rect->width >
+		 subrect->left + subrect->width)
+		subrect->left = rect->left + rect->width -
+			subrect->width;
+
+	if (rect->top > subrect->top)
+		subrect->top = rect->top;
+	else if (rect->top + rect->height >
+		 subrect->top + subrect->height)
+		subrect->top = rect->top + rect->height -
+			subrect->height;
+}
+
 /*
  * The common for both scaling and cropping iterative approach is:
  * 1. try if the client can produce exactly what requested by the user
  * 2. if (1) failed, try to double the client image until we get one big enough
  * 3. if (2) failed, try to request the maximum image
  */
-static int client_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *crop,
+static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop,
 			 struct v4l2_crop *cam_crop)
 {
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
 	struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c;
 	struct device *dev = sd->v4l2_dev->dev;
+	struct sh_mobile_ceu_cam *cam = icd->host_priv;
 	struct v4l2_cropcap cap;
 	int ret;
 	unsigned int width, height;
@@ -1041,13 +1120,14 @@
 	 */
 	if (!memcmp(rect, cam_rect, sizeof(*rect))) {
 		/* Even if camera S_CROP failed, but camera rectangle matches */
-		dev_dbg(dev, "Camera S_CROP successful for %ux%u@%u:%u\n",
+		dev_dbg(dev, "Camera S_CROP successful for %dx%d@%d:%d\n",
 			rect->width, rect->height, rect->left, rect->top);
+		cam->rect = *cam_rect;
 		return 0;
 	}
 
 	/* Try to fix cropping, that camera hasn't managed to set */
-	dev_geo(dev, "Fix camera S_CROP for %ux%u@%u:%u to %ux%u@%u:%u\n",
+	dev_geo(dev, "Fix camera S_CROP for %dx%d@%d:%d to %dx%d@%d:%d\n",
 		cam_rect->width, cam_rect->height,
 		cam_rect->left, cam_rect->top,
 		rect->width, rect->height, rect->left, rect->top);
@@ -1057,6 +1137,7 @@
 	if (ret < 0)
 		return ret;
 
+	/* Put user requested rectangle within sensor bounds */
 	soc_camera_limit_side(&rect->left, &rect->width, cap.bounds.left, 2,
 			      cap.bounds.width);
 	soc_camera_limit_side(&rect->top, &rect->height, cap.bounds.top, 4,
@@ -1069,6 +1150,10 @@
 	width = max(cam_rect->width, 2);
 	height = max(cam_rect->height, 2);
 
+	/*
+	 * Loop as long as sensor is not covering the requested rectangle and
+	 * is still within its bounds
+	 */
 	while (!ret && (is_smaller(cam_rect, rect) ||
 			is_inside(cam_rect, rect)) &&
 	       (cap.bounds.width > width || cap.bounds.height > height)) {
@@ -1086,6 +1171,7 @@
 		 * target left, set it to the middle point between the current
 		 * left and minimum left. But that would add too much
 		 * complexity: we would have to iterate each border separately.
+		 * Instead we just drop to the left and top bounds.
 		 */
 		if (cam_rect->left > rect->left)
 			cam_rect->left = cap.bounds.left;
@@ -1103,7 +1189,7 @@
 
 		v4l2_subdev_call(sd, video, s_crop, cam_crop);
 		ret = client_g_rect(sd, cam_rect);
-		dev_geo(dev, "Camera S_CROP %d for %ux%u@%u:%u\n", ret,
+		dev_geo(dev, "Camera S_CROP %d for %dx%d@%d:%d\n", ret,
 			cam_rect->width, cam_rect->height,
 			cam_rect->left, cam_rect->top);
 	}
@@ -1117,82 +1203,24 @@
 		*cam_rect = cap.bounds;
 		v4l2_subdev_call(sd, video, s_crop, cam_crop);
 		ret = client_g_rect(sd, cam_rect);
-		dev_geo(dev, "Camera S_CROP %d for max %ux%u@%u:%u\n", ret,
+		dev_geo(dev, "Camera S_CROP %d for max %dx%d@%d:%d\n", ret,
 			cam_rect->width, cam_rect->height,
 			cam_rect->left, cam_rect->top);
 	}
 
+	if (!ret) {
+		cam->rect = *cam_rect;
+		update_subrect(cam);
+	}
+
 	return ret;
 }
 
-static int get_camera_scales(struct v4l2_subdev *sd, struct v4l2_rect *rect,
-			     unsigned int *scale_h, unsigned int *scale_v)
-{
-	struct v4l2_mbus_framefmt mf;
-	int ret;
-
-	ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
-	if (ret < 0)
-		return ret;
-
-	*scale_h = calc_generic_scale(rect->width, mf.width);
-	*scale_v = calc_generic_scale(rect->height, mf.height);
-
-	return 0;
-}
-
-static int get_camera_subwin(struct soc_camera_device *icd,
-			     struct v4l2_rect *cam_subrect,
-			     unsigned int cam_hscale, unsigned int cam_vscale)
-{
-	struct sh_mobile_ceu_cam *cam = icd->host_priv;
-	struct v4l2_rect *ceu_rect = &cam->ceu_rect;
-
-	if (!ceu_rect->width) {
-		struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-		struct device *dev = icd->dev.parent;
-		struct v4l2_mbus_framefmt mf;
-		int ret;
-		/* First time */
-
-		ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
-		if (ret < 0)
-			return ret;
-
-		dev_geo(dev, "camera fmt %ux%u\n", mf.width, mf.height);
-
-		if (mf.width > 2560) {
-			ceu_rect->width	 = 2560;
-			ceu_rect->left	 = (mf.width - 2560) / 2;
-		} else {
-			ceu_rect->width	 = mf.width;
-			ceu_rect->left	 = 0;
-		}
-
-		if (mf.height > 1920) {
-			ceu_rect->height = 1920;
-			ceu_rect->top	 = (mf.height - 1920) / 2;
-		} else {
-			ceu_rect->height = mf.height;
-			ceu_rect->top	 = 0;
-		}
-
-		dev_geo(dev, "initialised CEU rect %ux%u@%u:%u\n",
-			ceu_rect->width, ceu_rect->height,
-			ceu_rect->left, ceu_rect->top);
-	}
-
-	cam_subrect->width	= scale_up(ceu_rect->width, cam_hscale);
-	cam_subrect->left	= scale_up(ceu_rect->left, cam_hscale);
-	cam_subrect->height	= scale_up(ceu_rect->height, cam_vscale);
-	cam_subrect->top	= scale_up(ceu_rect->top, cam_vscale);
-
-	return 0;
-}
-
+/* Iterative s_mbus_fmt, also updates cached client crop on success */
 static int client_s_fmt(struct soc_camera_device *icd,
 			struct v4l2_mbus_framefmt *mf, bool ceu_can_scale)
 {
+	struct sh_mobile_ceu_cam *cam = icd->host_priv;
 	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
 	struct device *dev = icd->dev.parent;
 	unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h;
@@ -1200,6 +1228,15 @@
 	struct v4l2_cropcap cap;
 	int ret;
 
+	ret = v4l2_subdev_call(sd, video, s_mbus_fmt, mf);
+	if (ret < 0)
+		return ret;
+
+	dev_geo(dev, "camera scaled to %ux%u\n", mf->width, mf->height);
+
+	if ((width == mf->width && height == mf->height) || !ceu_can_scale)
+		goto update_cache;
+
 	cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
 	ret = v4l2_subdev_call(sd, video, cropcap, &cap);
@@ -1209,15 +1246,6 @@
 	max_width = min(cap.bounds.width, 2560);
 	max_height = min(cap.bounds.height, 1920);
 
-	ret = v4l2_subdev_call(sd, video, s_mbus_fmt, mf);
-	if (ret < 0)
-		return ret;
-
-	dev_geo(dev, "camera scaled to %ux%u\n", mf->width, mf->height);
-
-	if ((width == mf->width && height == mf->height) || !ceu_can_scale)
-		return 0;
-
 	/* Camera set a format, but geometry is not precise, try to improve */
 	tmp_w = mf->width;
 	tmp_h = mf->height;
@@ -1239,26 +1267,37 @@
 		}
 	}
 
+update_cache:
+	/* Update cache */
+	ret = client_g_rect(sd, &cam->rect);
+	if (ret < 0)
+		return ret;
+
+	update_subrect(cam);
+
 	return 0;
 }
 
 /**
- * @rect	- camera cropped rectangle
- * @sub_rect	- CEU cropped rectangle, mapped back to camera input area
- * @ceu_rect	- on output calculated CEU crop rectangle
+ * @width	- on output: user width, mapped back to input
+ * @height	- on output: user height, mapped back to input
+ * @mf		- in- / output camera output window
  */
-static int client_scale(struct soc_camera_device *icd, struct v4l2_rect *rect,
-			struct v4l2_rect *sub_rect, struct v4l2_rect *ceu_rect,
-			struct v4l2_mbus_framefmt *mf, bool ceu_can_scale)
+static int client_scale(struct soc_camera_device *icd,
+			struct v4l2_mbus_framefmt *mf,
+			unsigned int *width, unsigned int *height,
+			bool ceu_can_scale)
 {
-	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
 	struct sh_mobile_ceu_cam *cam = icd->host_priv;
 	struct device *dev = icd->dev.parent;
 	struct v4l2_mbus_framefmt mf_tmp = *mf;
 	unsigned int scale_h, scale_v;
 	int ret;
 
-	/* 5. Apply iterative camera S_FMT for camera user window. */
+	/*
+	 * 5. Apply iterative camera S_FMT for camera user window (also updates
+	 *    client crop cache and the imaginary sub-rectangle).
+	 */
 	ret = client_s_fmt(icd, &mf_tmp, ceu_can_scale);
 	if (ret < 0)
 		return ret;
@@ -1270,60 +1309,22 @@
 
 	/* unneeded - it is already in "mf_tmp" */
 
-	/* 7. Calculate new camera scales. */
-	ret = get_camera_scales(sd, rect, &scale_h, &scale_v);
-	if (ret < 0)
-		return ret;
+	/* 7. Calculate new client scales. */
+	scale_h = calc_generic_scale(cam->rect.width, mf_tmp.width);
+	scale_v = calc_generic_scale(cam->rect.height, mf_tmp.height);
 
-	dev_geo(dev, "7: camera scales %u:%u\n", scale_h, scale_v);
-
-	cam->cam_width	= mf_tmp.width;
-	cam->cam_height	= mf_tmp.height;
 	mf->width	= mf_tmp.width;
 	mf->height	= mf_tmp.height;
 	mf->colorspace	= mf_tmp.colorspace;
 
 	/*
 	 * 8. Calculate new CEU crop - apply camera scales to previously
-	 *    calculated "effective" crop.
+	 *    updated "effective" crop.
 	 */
-	ceu_rect->left = scale_down(sub_rect->left, scale_h);
-	ceu_rect->width = scale_down(sub_rect->width, scale_h);
-	ceu_rect->top = scale_down(sub_rect->top, scale_v);
-	ceu_rect->height = scale_down(sub_rect->height, scale_v);
+	*width = scale_down(cam->subrect.width, scale_h);
+	*height = scale_down(cam->subrect.height, scale_v);
 
-	dev_geo(dev, "8: new CEU rect %ux%u@%u:%u\n",
-		ceu_rect->width, ceu_rect->height,
-		ceu_rect->left, ceu_rect->top);
-
-	return 0;
-}
-
-/* Get combined scales */
-static int get_scales(struct soc_camera_device *icd,
-		      unsigned int *scale_h, unsigned int *scale_v)
-{
-	struct sh_mobile_ceu_cam *cam = icd->host_priv;
-	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-	struct v4l2_crop cam_crop;
-	unsigned int width_in, height_in;
-	int ret;
-
-	cam_crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-	ret = client_g_rect(sd, &cam_crop.c);
-	if (ret < 0)
-		return ret;
-
-	ret = get_camera_scales(sd, &cam_crop.c, scale_h, scale_v);
-	if (ret < 0)
-		return ret;
-
-	width_in = scale_up(cam->ceu_rect.width, *scale_h);
-	height_in = scale_up(cam->ceu_rect.height, *scale_v);
-
-	*scale_h = calc_generic_scale(width_in, icd->user_width);
-	*scale_v = calc_generic_scale(height_in, icd->user_height);
+	dev_geo(dev, "8: new client sub-window %ux%u\n", *width, *height);
 
 	return 0;
 }
@@ -1342,115 +1343,165 @@
 	struct sh_mobile_ceu_dev *pcdev = ici->priv;
 	struct v4l2_crop cam_crop;
 	struct sh_mobile_ceu_cam *cam = icd->host_priv;
-	struct v4l2_rect *cam_rect = &cam_crop.c, *ceu_rect = &cam->ceu_rect;
+	struct v4l2_rect *cam_rect = &cam_crop.c;
 	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
 	struct device *dev = icd->dev.parent;
 	struct v4l2_mbus_framefmt mf;
-	unsigned int scale_comb_h, scale_comb_v, scale_ceu_h, scale_ceu_v,
-		out_width, out_height;
+	unsigned int scale_cam_h, scale_cam_v, scale_ceu_h, scale_ceu_v,
+		out_width, out_height, scale_h, scale_v;
+	int interm_width, interm_height;
 	u32 capsr, cflcr;
 	int ret;
 
-	/* 1. Calculate current combined scales. */
-	ret = get_scales(icd, &scale_comb_h, &scale_comb_v);
+	dev_geo(dev, "S_CROP(%ux%u@%u:%u)\n", rect->width, rect->height,
+		rect->left, rect->top);
+
+	/* During camera cropping its output window can change too, stop CEU */
+	capsr = capture_save_reset(pcdev);
+	dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr);
+
+	/* 1. - 2. Apply iterative camera S_CROP for new input window. */
+	ret = client_s_crop(icd, a, &cam_crop);
 	if (ret < 0)
 		return ret;
 
-	dev_geo(dev, "1: combined scales %u:%u\n", scale_comb_h, scale_comb_v);
-
-	/* 2. Apply iterative camera S_CROP for new input window. */
-	ret = client_s_crop(sd, a, &cam_crop);
-	if (ret < 0)
-		return ret;
-
-	dev_geo(dev, "2: camera cropped to %ux%u@%u:%u\n",
+	dev_geo(dev, "1-2: camera cropped to %ux%u@%u:%u\n",
 		cam_rect->width, cam_rect->height,
 		cam_rect->left, cam_rect->top);
 
 	/* On success cam_crop contains current camera crop */
 
-	/*
-	 * 3. If old combined scales applied to new crop produce an impossible
-	 *    user window, adjust scales to produce nearest possible window.
-	 */
-	out_width	= scale_down(rect->width, scale_comb_h);
-	out_height	= scale_down(rect->height, scale_comb_v);
+	/* 3. Retrieve camera output window */
+	ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
+	if (ret < 0)
+		return ret;
 
-	if (out_width > 2560)
-		out_width = 2560;
-	else if (out_width < 2)
-		out_width = 2;
+	if (mf.width > 2560 || mf.height > 1920)
+		return -EINVAL;
 
-	if (out_height > 1920)
-		out_height = 1920;
-	else if (out_height < 4)
-		out_height = 4;
+	/* Cache camera output window */
+	cam->width	= mf.width;
+	cam->height	= mf.height;
 
-	dev_geo(dev, "3: Adjusted output %ux%u\n", out_width, out_height);
+	/* 4. Calculate camera scales */
+	scale_cam_h	= calc_generic_scale(cam_rect->width, mf.width);
+	scale_cam_v	= calc_generic_scale(cam_rect->height, mf.height);
 
-	/* 4. Use G_CROP to retrieve actual input window: already in cam_crop */
+	/* Calculate intermediate window */
+	interm_width	= scale_down(rect->width, scale_cam_h);
+	interm_height	= scale_down(rect->height, scale_cam_v);
+
+	if (pcdev->image_mode) {
+		out_width	= min(interm_width, icd->user_width);
+		out_height	= min(interm_height, icd->user_height);
+	} else {
+		out_width	= interm_width;
+		out_height	= interm_height;
+	}
 
 	/*
-	 * 5. Using actual input window and calculated combined scales calculate
-	 *    camera target output window.
+	 * 5. Calculate CEU scales from camera scales from results of (5) and
+	 *    the user window
 	 */
-	mf.width	= scale_down(cam_rect->width, scale_comb_h);
-	mf.height	= scale_down(cam_rect->height, scale_comb_v);
+	scale_ceu_h	= calc_scale(interm_width, &out_width);
+	scale_ceu_v	= calc_scale(interm_height, &out_height);
 
-	dev_geo(dev, "5: camera target %ux%u\n", mf.width, mf.height);
+	/* Calculate camera scales */
+	scale_h		= calc_generic_scale(cam_rect->width, out_width);
+	scale_v		= calc_generic_scale(cam_rect->height, out_height);
 
-	/* 6. - 9. */
-	mf.code		= cam->code;
-	mf.field	= pcdev->field;
+	dev_geo(dev, "5: CEU scales %u:%u\n", scale_ceu_h, scale_ceu_v);
 
-	capsr = capture_save_reset(pcdev);
-	dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr);
-
-	/* Make relative to camera rectangle */
-	rect->left	-= cam_rect->left;
-	rect->top	-= cam_rect->top;
-
-	ret = client_scale(icd, cam_rect, rect, ceu_rect, &mf,
-			   pcdev->image_mode &&
-			   V4L2_FIELD_NONE == pcdev->field);
-
-	dev_geo(dev, "6-9: %d\n", ret);
-
-	/* 10. Use CEU cropping to crop to the new window. */
-	sh_mobile_ceu_set_rect(icd, out_width, out_height);
-
-	dev_geo(dev, "10: CEU cropped to %ux%u@%u:%u\n",
-		ceu_rect->width, ceu_rect->height,
-		ceu_rect->left, ceu_rect->top);
-
-	/*
-	 * 11. Calculate CEU scales from camera scales from results of (10) and
-	 *     user window from (3)
-	 */
-	scale_ceu_h = calc_scale(ceu_rect->width, &out_width);
-	scale_ceu_v = calc_scale(ceu_rect->height, &out_height);
-
-	dev_geo(dev, "11: CEU scales %u:%u\n", scale_ceu_h, scale_ceu_v);
-
-	/* 12. Apply CEU scales. */
+	/* Apply CEU scales. */
 	cflcr = scale_ceu_h | (scale_ceu_v << 16);
 	if (cflcr != pcdev->cflcr) {
 		pcdev->cflcr = cflcr;
 		ceu_write(pcdev, CFLCR, cflcr);
 	}
 
+	icd->user_width	 = out_width;
+	icd->user_height = out_height;
+	cam->ceu_left	 = scale_down(rect->left - cam_rect->left, scale_h) & ~1;
+	cam->ceu_top	 = scale_down(rect->top - cam_rect->top, scale_v) & ~1;
+
+	/* 6. Use CEU cropping to crop to the new window. */
+	sh_mobile_ceu_set_rect(icd);
+
+	cam->subrect = *rect;
+
+	dev_geo(dev, "6: CEU cropped to %ux%u@%u:%u\n",
+		icd->user_width, icd->user_height,
+		cam->ceu_left, cam->ceu_top);
+
 	/* Restore capture */
 	if (pcdev->active)
 		capsr |= 1;
 	capture_restore(pcdev, capsr);
 
-	icd->user_width = out_width;
-	icd->user_height = out_height;
-
 	/* Even if only camera cropping succeeded */
 	return ret;
 }
 
+static int sh_mobile_ceu_get_crop(struct soc_camera_device *icd,
+				  struct v4l2_crop *a)
+{
+	struct sh_mobile_ceu_cam *cam = icd->host_priv;
+
+	a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->c = cam->subrect;
+
+	return 0;
+}
+
+/*
+ * Calculate real client output window by applying new scales to the current
+ * client crop. New scales are calculated from the requested output format and
+ * CEU crop, mapped backed onto the client input (subrect).
+ */
+static void calculate_client_output(struct soc_camera_device *icd,
+		struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf)
+{
+	struct sh_mobile_ceu_cam *cam = icd->host_priv;
+	struct device *dev = icd->dev.parent;
+	struct v4l2_rect *cam_subrect = &cam->subrect;
+	unsigned int scale_v, scale_h;
+
+	if (cam_subrect->width == cam->rect.width &&
+	    cam_subrect->height == cam->rect.height) {
+		/* No sub-cropping */
+		mf->width	= pix->width;
+		mf->height	= pix->height;
+		return;
+	}
+
+	/* 1.-2. Current camera scales and subwin - cached. */
+
+	dev_geo(dev, "2: subwin %ux%u@%u:%u\n",
+		cam_subrect->width, cam_subrect->height,
+		cam_subrect->left, cam_subrect->top);
+
+	/*
+	 * 3. Calculate new combined scales from input sub-window to requested
+	 *    user window.
+	 */
+
+	/*
+	 * TODO: CEU cannot scale images larger than VGA to smaller than SubQCIF
+	 * (128x96) or larger than VGA
+	 */
+	scale_h = calc_generic_scale(cam_subrect->width, pix->width);
+	scale_v = calc_generic_scale(cam_subrect->height, pix->height);
+
+	dev_geo(dev, "3: scales %u:%u\n", scale_h, scale_v);
+
+	/*
+	 * 4. Calculate client output window by applying combined scales to real
+	 *    input window.
+	 */
+	mf->width	= scale_down(cam->rect.width, scale_h);
+	mf->height	= scale_down(cam->rect.height, scale_v);
+}
+
 /* Similar to set_crop multistage iterative algorithm */
 static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
 				 struct v4l2_format *f)
@@ -1460,18 +1511,17 @@
 	struct sh_mobile_ceu_cam *cam = icd->host_priv;
 	struct v4l2_pix_format *pix = &f->fmt.pix;
 	struct v4l2_mbus_framefmt mf;
-	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
 	struct device *dev = icd->dev.parent;
 	__u32 pixfmt = pix->pixelformat;
 	const struct soc_camera_format_xlate *xlate;
-	struct v4l2_crop cam_crop;
-	struct v4l2_rect *cam_rect = &cam_crop.c, cam_subrect, ceu_rect;
-	unsigned int scale_cam_h, scale_cam_v;
+	unsigned int ceu_sub_width, ceu_sub_height;
 	u16 scale_v, scale_h;
 	int ret;
 	bool image_mode;
 	enum v4l2_field field;
 
+	dev_geo(dev, "S_FMT(pix=0x%x, %ux%u)\n", pixfmt, pix->width, pix->height);
+
 	switch (pix->field) {
 	default:
 		pix->field = V4L2_FIELD_NONE;
@@ -1492,46 +1542,8 @@
 		return -EINVAL;
 	}
 
-	/* 1. Calculate current camera scales. */
-	cam_crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-	ret = client_g_rect(sd, cam_rect);
-	if (ret < 0)
-		return ret;
-
-	ret = get_camera_scales(sd, cam_rect, &scale_cam_h, &scale_cam_v);
-	if (ret < 0)
-		return ret;
-
-	dev_geo(dev, "1: camera scales %u:%u\n", scale_cam_h, scale_cam_v);
-
-	/*
-	 * 2. Calculate "effective" input crop (sensor subwindow) - CEU crop
-	 *    scaled back at current camera scales onto input window.
-	 */
-	ret = get_camera_subwin(icd, &cam_subrect, scale_cam_h, scale_cam_v);
-	if (ret < 0)
-		return ret;
-
-	dev_geo(dev, "2: subwin %ux%u@%u:%u\n",
-		cam_subrect.width, cam_subrect.height,
-		cam_subrect.left, cam_subrect.top);
-
-	/*
-	 * 3. Calculate new combined scales from "effective" input window to
-	 *    requested user window.
-	 */
-	scale_h = calc_generic_scale(cam_subrect.width, pix->width);
-	scale_v = calc_generic_scale(cam_subrect.height, pix->height);
-
-	dev_geo(dev, "3: scales %u:%u\n", scale_h, scale_v);
-
-	/*
-	 * 4. Calculate camera output window by applying combined scales to real
-	 *    input window.
-	 */
-	mf.width	= scale_down(cam_rect->width, scale_h);
-	mf.height	= scale_down(cam_rect->height, scale_v);
+	/* 1.-4. Calculate client output geometry */
+	calculate_client_output(icd, &f->fmt.pix, &mf);
 	mf.field	= pix->field;
 	mf.colorspace	= pix->colorspace;
 	mf.code		= xlate->code;
@@ -1547,17 +1559,17 @@
 		image_mode = false;
 	}
 
-	dev_geo(dev, "4: camera output %ux%u\n", mf.width, mf.height);
+	dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height);
 
 	/* 5. - 9. */
-	ret = client_scale(icd, cam_rect, &cam_subrect, &ceu_rect, &mf,
+	ret = client_scale(icd, &mf, &ceu_sub_width, &ceu_sub_height,
 			   image_mode && V4L2_FIELD_NONE == field);
 
-	dev_geo(dev, "5-9: client scale %d\n", ret);
+	dev_geo(dev, "5-9: client scale return %d\n", ret);
 
 	/* Done with the camera. Now see if we can improve the result */
 
-	dev_dbg(dev, "Camera %d fmt %ux%u, requested %ux%u\n",
+	dev_geo(dev, "Camera %d fmt %ux%u, requested %ux%u\n",
 		ret, mf.width, mf.height, pix->width, pix->height);
 	if (ret < 0)
 		return ret;
@@ -1565,40 +1577,44 @@
 	if (mf.code != xlate->code)
 		return -EINVAL;
 
+	/* 9. Prepare CEU crop */
+	cam->width = mf.width;
+	cam->height = mf.height;
+
 	/* 10. Use CEU scaling to scale to the requested user window. */
 
 	/* We cannot scale up */
-	if (pix->width > mf.width)
-		pix->width = mf.width;
-	if (pix->width > ceu_rect.width)
-		pix->width = ceu_rect.width;
+	if (pix->width > ceu_sub_width)
+		ceu_sub_width = pix->width;
 
-	if (pix->height > mf.height)
-		pix->height = mf.height;
-	if (pix->height > ceu_rect.height)
-		pix->height = ceu_rect.height;
+	if (pix->height > ceu_sub_height)
+		ceu_sub_height = pix->height;
 
 	pix->colorspace = mf.colorspace;
 
 	if (image_mode) {
 		/* Scale pix->{width x height} down to width x height */
-		scale_h = calc_scale(ceu_rect.width, &pix->width);
-		scale_v = calc_scale(ceu_rect.height, &pix->height);
-
-		pcdev->cflcr = scale_h | (scale_v << 16);
+		scale_h		= calc_scale(ceu_sub_width, &pix->width);
+		scale_v		= calc_scale(ceu_sub_height, &pix->height);
 	} else {
-		pix->width = ceu_rect.width;
-		pix->height = ceu_rect.height;
-		scale_h = scale_v = 0;
-		pcdev->cflcr = 0;
+		pix->width	= ceu_sub_width;
+		pix->height	= ceu_sub_height;
+		scale_h		= 0;
+		scale_v		= 0;
 	}
 
+	pcdev->cflcr = scale_h | (scale_v << 16);
+
+	/*
+	 * We have calculated CFLCR, the actual configuration will be performed
+	 * in sh_mobile_ceu_set_bus_param()
+	 */
+
 	dev_geo(dev, "10: W: %u : 0x%x = %u, H: %u : 0x%x = %u\n",
-		ceu_rect.width, scale_h, pix->width,
-		ceu_rect.height, scale_v, pix->height);
+		ceu_sub_width, scale_h, pix->width,
+		ceu_sub_height, scale_v, pix->height);
 
 	cam->code		= xlate->code;
-	cam->ceu_rect		= ceu_rect;
 	icd->current_fmt	= xlate;
 
 	pcdev->field = field;
@@ -1820,6 +1836,7 @@
 	.remove		= sh_mobile_ceu_remove_device,
 	.get_formats	= sh_mobile_ceu_get_formats,
 	.put_formats	= sh_mobile_ceu_put_formats,
+	.get_crop	= sh_mobile_ceu_get_crop,
 	.set_crop	= sh_mobile_ceu_set_crop,
 	.set_fmt	= sh_mobile_ceu_set_fmt,
 	.try_fmt	= sh_mobile_ceu_try_fmt,
diff --git a/drivers/media/video/sh_vou.c b/drivers/media/video/sh_vou.c
new file mode 100644
index 0000000..f5b892a
--- /dev/null
+++ b/drivers/media/video/sh_vou.c
@@ -0,0 +1,1476 @@
+/*
+ * SuperH Video Output Unit (VOU) driver
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+
+#include <media/sh_vou.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mediabus.h>
+#include <media/videobuf-dma-contig.h>
+
+/* Mirror addresses are not available for all registers */
+#define VOUER	0
+#define VOUCR	4
+#define VOUSTR	8
+#define VOUVCR	0xc
+#define VOUISR	0x10
+#define VOUBCR	0x14
+#define VOUDPR	0x18
+#define VOUDSR	0x1c
+#define VOUVPR	0x20
+#define VOUIR	0x24
+#define VOUSRR	0x28
+#define VOUMSR	0x2c
+#define VOUHIR	0x30
+#define VOUDFR	0x34
+#define VOUAD1R	0x38
+#define VOUAD2R	0x3c
+#define VOUAIR	0x40
+#define VOUSWR	0x44
+#define VOURCR	0x48
+#define VOURPR	0x50
+
+enum sh_vou_status {
+	SH_VOU_IDLE,
+	SH_VOU_INITIALISING,
+	SH_VOU_RUNNING,
+};
+
+#define VOU_MAX_IMAGE_WIDTH	720
+#define VOU_MAX_IMAGE_HEIGHT	480
+
+struct sh_vou_device {
+	struct v4l2_device v4l2_dev;
+	struct video_device *vdev;
+	atomic_t use_count;
+	struct sh_vou_pdata *pdata;
+	spinlock_t lock;
+	void __iomem *base;
+	/* State information */
+	struct v4l2_pix_format pix;
+	struct v4l2_rect rect;
+	struct list_head queue;
+	v4l2_std_id std;
+	int pix_idx;
+	struct videobuf_buffer *active;
+	enum sh_vou_status status;
+};
+
+struct sh_vou_file {
+	struct videobuf_queue vbq;
+};
+
+/* Register access routines for sides A, B and mirror addresses */
+static void sh_vou_reg_a_write(struct sh_vou_device *vou_dev, unsigned int reg,
+			       u32 value)
+{
+	__raw_writel(value, vou_dev->base + reg);
+}
+
+static void sh_vou_reg_ab_write(struct sh_vou_device *vou_dev, unsigned int reg,
+				u32 value)
+{
+	__raw_writel(value, vou_dev->base + reg);
+	__raw_writel(value, vou_dev->base + reg + 0x1000);
+}
+
+static void sh_vou_reg_m_write(struct sh_vou_device *vou_dev, unsigned int reg,
+			       u32 value)
+{
+	__raw_writel(value, vou_dev->base + reg + 0x2000);
+}
+
+static u32 sh_vou_reg_a_read(struct sh_vou_device *vou_dev, unsigned int reg)
+{
+	return __raw_readl(vou_dev->base + reg);
+}
+
+static void sh_vou_reg_a_set(struct sh_vou_device *vou_dev, unsigned int reg,
+			     u32 value, u32 mask)
+{
+	u32 old = __raw_readl(vou_dev->base + reg);
+
+	value = (value & mask) | (old & ~mask);
+	__raw_writel(value, vou_dev->base + reg);
+}
+
+static void sh_vou_reg_b_set(struct sh_vou_device *vou_dev, unsigned int reg,
+			     u32 value, u32 mask)
+{
+	sh_vou_reg_a_set(vou_dev, reg + 0x1000, value, mask);
+}
+
+static void sh_vou_reg_ab_set(struct sh_vou_device *vou_dev, unsigned int reg,
+			      u32 value, u32 mask)
+{
+	sh_vou_reg_a_set(vou_dev, reg, value, mask);
+	sh_vou_reg_b_set(vou_dev, reg, value, mask);
+}
+
+struct sh_vou_fmt {
+	u32		pfmt;
+	char		*desc;
+	unsigned char	bpp;
+	unsigned char	rgb;
+	unsigned char	yf;
+	unsigned char	pkf;
+};
+
+/* Further pixel formats can be added */
+static struct sh_vou_fmt vou_fmt[] = {
+	{
+		.pfmt	= V4L2_PIX_FMT_NV12,
+		.bpp	= 12,
+		.desc	= "YVU420 planar",
+		.yf	= 0,
+		.rgb	= 0,
+	},
+	{
+		.pfmt	= V4L2_PIX_FMT_NV16,
+		.bpp	= 16,
+		.desc	= "YVYU planar",
+		.yf	= 1,
+		.rgb	= 0,
+	},
+	{
+		.pfmt	= V4L2_PIX_FMT_RGB24,
+		.bpp	= 24,
+		.desc	= "RGB24",
+		.pkf	= 2,
+		.rgb	= 1,
+	},
+	{
+		.pfmt	= V4L2_PIX_FMT_RGB565,
+		.bpp	= 16,
+		.desc	= "RGB565",
+		.pkf	= 3,
+		.rgb	= 1,
+	},
+	{
+		.pfmt	= V4L2_PIX_FMT_RGB565X,
+		.bpp	= 16,
+		.desc	= "RGB565 byteswapped",
+		.pkf	= 3,
+		.rgb	= 1,
+	},
+};
+
+static void sh_vou_schedule_next(struct sh_vou_device *vou_dev,
+				 struct videobuf_buffer *vb)
+{
+	dma_addr_t addr1, addr2;
+
+	addr1 = videobuf_to_dma_contig(vb);
+	switch (vou_dev->pix.pixelformat) {
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV16:
+		addr2 = addr1 + vou_dev->pix.width * vou_dev->pix.height;
+		break;
+	default:
+		addr2 = 0;
+	}
+
+	sh_vou_reg_m_write(vou_dev, VOUAD1R, addr1);
+	sh_vou_reg_m_write(vou_dev, VOUAD2R, addr2);
+}
+
+static void sh_vou_stream_start(struct sh_vou_device *vou_dev,
+				struct videobuf_buffer *vb)
+{
+	unsigned int row_coeff;
+#ifdef __LITTLE_ENDIAN
+	u32 dataswap = 7;
+#else
+	u32 dataswap = 0;
+#endif
+
+	switch (vou_dev->pix.pixelformat) {
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV16:
+		row_coeff = 1;
+		break;
+	case V4L2_PIX_FMT_RGB565:
+		dataswap ^= 1;
+	case V4L2_PIX_FMT_RGB565X:
+		row_coeff = 2;
+		break;
+	case V4L2_PIX_FMT_RGB24:
+		row_coeff = 3;
+		break;
+	}
+
+	sh_vou_reg_a_write(vou_dev, VOUSWR, dataswap);
+	sh_vou_reg_ab_write(vou_dev, VOUAIR, vou_dev->pix.width * row_coeff);
+	sh_vou_schedule_next(vou_dev, vb);
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	BUG_ON(in_interrupt());
+
+	/* Wait until this buffer is no longer in STATE_QUEUED or STATE_ACTIVE */
+	videobuf_waiton(vb, 0, 0);
+	videobuf_dma_contig_free(vq, vb);
+	vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+/* Locking: caller holds vq->vb_lock mutex */
+static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count,
+			    unsigned int *size)
+{
+	struct video_device *vdev = vq->priv_data;
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+	*size = vou_fmt[vou_dev->pix_idx].bpp * vou_dev->pix.width *
+		vou_dev->pix.height / 8;
+
+	if (*count < 2)
+		*count = 2;
+
+	/* Taking into account maximum frame size, *count will stay >= 2 */
+	if (PAGE_ALIGN(*size) * *count > 4 * 1024 * 1024)
+		*count = 4 * 1024 * 1024 / PAGE_ALIGN(*size);
+
+	dev_dbg(vq->dev, "%s(): count=%d, size=%d\n", __func__, *count, *size);
+
+	return 0;
+}
+
+/* Locking: caller holds vq->vb_lock mutex */
+static int sh_vou_buf_prepare(struct videobuf_queue *vq,
+			      struct videobuf_buffer *vb,
+			      enum v4l2_field field)
+{
+	struct video_device *vdev = vq->priv_data;
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+	struct v4l2_pix_format *pix = &vou_dev->pix;
+	int bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8;
+	int ret;
+
+	dev_dbg(vq->dev, "%s()\n", __func__);
+
+	if (vb->width	!= pix->width ||
+	    vb->height	!= pix->height ||
+	    vb->field	!= pix->field) {
+		vb->width	= pix->width;
+		vb->height	= pix->height;
+		vb->field	= field;
+		if (vb->state != VIDEOBUF_NEEDS_INIT)
+			free_buffer(vq, vb);
+	}
+
+	vb->size = vb->height * bytes_per_line;
+	if (vb->baddr && vb->bsize < vb->size) {
+		/* User buffer too small */
+		dev_warn(vq->dev, "User buffer too small: [%u] @ %lx\n",
+			 vb->bsize, vb->baddr);
+		return -EINVAL;
+	}
+
+	if (vb->state == VIDEOBUF_NEEDS_INIT) {
+		ret = videobuf_iolock(vq, vb, NULL);
+		if (ret < 0) {
+			dev_warn(vq->dev, "IOLOCK buf-type %d: %d\n",
+				 vb->memory, ret);
+			return ret;
+		}
+		vb->state = VIDEOBUF_PREPARED;
+	}
+
+	dev_dbg(vq->dev,
+		"%s(): fmt #%d, %u bytes per line, phys 0x%x, type %d, state %d\n",
+		__func__, vou_dev->pix_idx, bytes_per_line,
+		videobuf_to_dma_contig(vb), vb->memory, vb->state);
+
+	return 0;
+}
+
+/* Locking: caller holds vq->vb_lock mutex and vq->irqlock spinlock */
+static void sh_vou_buf_queue(struct videobuf_queue *vq,
+			     struct videobuf_buffer *vb)
+{
+	struct video_device *vdev = vq->priv_data;
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+	dev_dbg(vq->dev, "%s()\n", __func__);
+
+	vb->state = VIDEOBUF_QUEUED;
+	list_add_tail(&vb->queue, &vou_dev->queue);
+
+	if (vou_dev->status == SH_VOU_RUNNING) {
+		return;
+	} else if (!vou_dev->active) {
+		vou_dev->active = vb;
+		/* Start from side A: we use mirror addresses, so, set B */
+		sh_vou_reg_a_write(vou_dev, VOURPR, 1);
+		dev_dbg(vq->dev, "%s: first buffer status 0x%x\n", __func__,
+			sh_vou_reg_a_read(vou_dev, VOUSTR));
+		sh_vou_schedule_next(vou_dev, vb);
+		/* Only activate VOU after the second buffer */
+	} else if (vou_dev->active->queue.next == &vb->queue) {
+		/* Second buffer - initialise register side B */
+		sh_vou_reg_a_write(vou_dev, VOURPR, 0);
+		sh_vou_stream_start(vou_dev, vb);
+
+		/* Register side switching with frame VSYNC */
+		sh_vou_reg_a_write(vou_dev, VOURCR, 5);
+		dev_dbg(vq->dev, "%s: second buffer status 0x%x\n", __func__,
+			sh_vou_reg_a_read(vou_dev, VOUSTR));
+
+		/* Enable End-of-Frame (VSYNC) interrupts */
+		sh_vou_reg_a_write(vou_dev, VOUIR, 0x10004);
+		/* Two buffers on the queue - activate the hardware */
+
+		vou_dev->status = SH_VOU_RUNNING;
+		sh_vou_reg_a_write(vou_dev, VOUER, 0x107);
+	}
+}
+
+static void sh_vou_buf_release(struct videobuf_queue *vq,
+			       struct videobuf_buffer *vb)
+{
+	struct video_device *vdev = vq->priv_data;
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+	unsigned long flags;
+
+	dev_dbg(vq->dev, "%s()\n", __func__);
+
+	spin_lock_irqsave(&vou_dev->lock, flags);
+
+	if (vou_dev->active == vb) {
+		/* disable output */
+		sh_vou_reg_a_set(vou_dev, VOUER, 0, 1);
+		/* ...but the current frame will complete */
+		sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000);
+		vou_dev->active = NULL;
+	}
+
+	if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED)) {
+		vb->state = VIDEOBUF_ERROR;
+		list_del(&vb->queue);
+	}
+
+	spin_unlock_irqrestore(&vou_dev->lock, flags);
+
+	free_buffer(vq, vb);
+}
+
+static struct videobuf_queue_ops sh_vou_video_qops = {
+	.buf_setup	= sh_vou_buf_setup,
+	.buf_prepare	= sh_vou_buf_prepare,
+	.buf_queue	= sh_vou_buf_queue,
+	.buf_release	= sh_vou_buf_release,
+};
+
+/* Video IOCTLs */
+static int sh_vou_querycap(struct file *file, void  *priv,
+			   struct v4l2_capability *cap)
+{
+	struct sh_vou_file *vou_file = priv;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	strlcpy(cap->card, "SuperH VOU", sizeof(cap->card));
+	cap->version = KERNEL_VERSION(0, 1, 0);
+	cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+	return 0;
+}
+
+/* Enumerate formats, that the device can accept from the user */
+static int sh_vou_enum_fmt_vid_out(struct file *file, void  *priv,
+				   struct v4l2_fmtdesc *fmt)
+{
+	struct sh_vou_file *vou_file = priv;
+
+	if (fmt->index >= ARRAY_SIZE(vou_fmt))
+		return -EINVAL;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	strlcpy(fmt->description, vou_fmt[fmt->index].desc,
+		sizeof(fmt->description));
+	fmt->pixelformat = vou_fmt[fmt->index].pfmt;
+
+	return 0;
+}
+
+static int sh_vou_g_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *fmt)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+	dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
+
+	fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	fmt->fmt.pix = vou_dev->pix;
+
+	return 0;
+}
+
+static const unsigned char vou_scale_h_num[] = {1, 9, 2, 9, 4};
+static const unsigned char vou_scale_h_den[] = {1, 8, 1, 4, 1};
+static const unsigned char vou_scale_h_fld[] = {0, 2, 1, 3};
+static const unsigned char vou_scale_v_num[] = {1, 2, 4};
+static const unsigned char vou_scale_v_den[] = {1, 1, 1};
+static const unsigned char vou_scale_v_fld[] = {0, 1};
+
+static void sh_vou_configure_geometry(struct sh_vou_device *vou_dev,
+				      int pix_idx, int w_idx, int h_idx)
+{
+	struct sh_vou_fmt *fmt = vou_fmt + pix_idx;
+	unsigned int black_left, black_top, width_max, height_max,
+		frame_in_height, frame_out_height, frame_out_top;
+	struct v4l2_rect *rect = &vou_dev->rect;
+	struct v4l2_pix_format *pix = &vou_dev->pix;
+	u32 vouvcr = 0, dsr_h, dsr_v;
+
+	if (vou_dev->std & V4L2_STD_525_60) {
+		width_max = 858;
+		height_max = 262;
+	} else {
+		width_max = 864;
+		height_max = 312;
+	}
+
+	frame_in_height = pix->height / 2;
+	frame_out_height = rect->height / 2;
+	frame_out_top = rect->top / 2;
+
+	/*
+	 * Cropping scheme: max useful image is 720x480, and the total video
+	 * area is 858x525 (NTSC) or 864x625 (PAL). AK8813 / 8814 starts
+	 * sampling data beginning with fixed 276th (NTSC) / 288th (PAL) clock,
+	 * of which the first 33 / 25 clocks HSYNC must be held active. This
+	 * has to be configured in CR[HW]. 1 pixel equals 2 clock periods.
+	 * This gives CR[HW] = 16 / 12, VPR[HVP] = 138 / 144, which gives
+	 * exactly 858 - 138 = 864 - 144 = 720! We call the out-of-display area,
+	 * beyond DSR, specified on the left and top by the VPR register "black
+	 * pixels" and out-of-image area (DPR) "background pixels." We fix VPR
+	 * at 138 / 144 : 20, because that's the HSYNC timing, that our first
+	 * client requires, and that's exactly what leaves us 720 pixels for the
+	 * image; we leave VPR[VVP] at default 20 for now, because the client
+	 * doesn't seem to have any special requirements for it. Otherwise we
+	 * could also set it to max - 240 = 22 / 72. Thus VPR depends only on
+	 * the selected standard, and DPR and DSR are selected according to
+	 * cropping. Q: how does the client detect the first valid line? Does
+	 * HSYNC stay inactive during invalid (black) lines?
+	 */
+	black_left = width_max - VOU_MAX_IMAGE_WIDTH;
+	black_top = 20;
+
+	dsr_h = rect->width + rect->left;
+	dsr_v = frame_out_height + frame_out_top;
+
+	dev_dbg(vou_dev->v4l2_dev.dev,
+		"image %ux%u, black %u:%u, offset %u:%u, display %ux%u\n",
+		pix->width, frame_in_height, black_left, black_top,
+		rect->left, frame_out_top, dsr_h, dsr_v);
+
+	/* VOUISR height - half of a frame height in frame mode */
+	sh_vou_reg_ab_write(vou_dev, VOUISR, (pix->width << 16) | frame_in_height);
+	sh_vou_reg_ab_write(vou_dev, VOUVPR, (black_left << 16) | black_top);
+	sh_vou_reg_ab_write(vou_dev, VOUDPR, (rect->left << 16) | frame_out_top);
+	sh_vou_reg_ab_write(vou_dev, VOUDSR, (dsr_h << 16) | dsr_v);
+
+	/*
+	 * if necessary, we could set VOUHIR to
+	 * max(black_left + dsr_h, width_max) here
+	 */
+
+	if (w_idx)
+		vouvcr |= (1 << 15) | (vou_scale_h_fld[w_idx - 1] << 4);
+	if (h_idx)
+		vouvcr |= (1 << 14) | vou_scale_v_fld[h_idx - 1];
+
+	dev_dbg(vou_dev->v4l2_dev.dev, "%s: scaling 0x%x\n", fmt->desc, vouvcr);
+
+	/* To produce a colour bar for testing set bit 23 of VOUVCR */
+	sh_vou_reg_ab_write(vou_dev, VOUVCR, vouvcr);
+	sh_vou_reg_ab_write(vou_dev, VOUDFR,
+			    fmt->pkf | (fmt->yf << 8) | (fmt->rgb << 16));
+}
+
+struct sh_vou_geometry {
+	struct v4l2_rect output;
+	unsigned int in_width;
+	unsigned int in_height;
+	int scale_idx_h;
+	int scale_idx_v;
+};
+
+/*
+ * Find input geometry, that we can use to produce output, closest to the
+ * requested rectangle, using VOU scaling
+ */
+static void vou_adjust_input(struct sh_vou_geometry *geo, v4l2_std_id std)
+{
+	/* The compiler cannot know, that best and idx will indeed be set */
+	unsigned int best_err = UINT_MAX, best = 0, width_max, height_max;
+	int i, idx = 0;
+
+	if (std & V4L2_STD_525_60) {
+		width_max = 858;
+		height_max = 262;
+	} else {
+		width_max = 864;
+		height_max = 312;
+	}
+
+	/* Image width must be a multiple of 4 */
+	v4l_bound_align_image(&geo->in_width, 0, VOU_MAX_IMAGE_WIDTH, 2,
+			      &geo->in_height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0);
+
+	/* Select scales to come as close as possible to the output image */
+	for (i = ARRAY_SIZE(vou_scale_h_num) - 1; i >= 0; i--) {
+		unsigned int err;
+		unsigned int found = geo->output.width * vou_scale_h_den[i] /
+			vou_scale_h_num[i];
+
+		if (found > VOU_MAX_IMAGE_WIDTH)
+			/* scales increase */
+			break;
+
+		err = abs(found - geo->in_width);
+		if (err < best_err) {
+			best_err = err;
+			idx = i;
+			best = found;
+		}
+		if (!err)
+			break;
+	}
+
+	geo->in_width = best;
+	geo->scale_idx_h = idx;
+
+	best_err = UINT_MAX;
+
+	/* This loop can be replaced with one division */
+	for (i = ARRAY_SIZE(vou_scale_v_num) - 1; i >= 0; i--) {
+		unsigned int err;
+		unsigned int found = geo->output.height * vou_scale_v_den[i] /
+			vou_scale_v_num[i];
+
+		if (found > VOU_MAX_IMAGE_HEIGHT)
+			/* scales increase */
+			break;
+
+		err = abs(found - geo->in_height);
+		if (err < best_err) {
+			best_err = err;
+			idx = i;
+			best = found;
+		}
+		if (!err)
+			break;
+	}
+
+	geo->in_height = best;
+	geo->scale_idx_v = idx;
+}
+
+/*
+ * Find output geometry, that we can produce, using VOU scaling, closest to
+ * the requested rectangle
+ */
+static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std)
+{
+	unsigned int best_err = UINT_MAX, best, width_max, height_max;
+	int i, idx;
+
+	if (std & V4L2_STD_525_60) {
+		width_max = 858;
+		height_max = 262 * 2;
+	} else {
+		width_max = 864;
+		height_max = 312 * 2;
+	}
+
+	/* Select scales to come as close as possible to the output image */
+	for (i = 0; i < ARRAY_SIZE(vou_scale_h_num); i++) {
+		unsigned int err;
+		unsigned int found = geo->in_width * vou_scale_h_num[i] /
+			vou_scale_h_den[i];
+
+		if (found > VOU_MAX_IMAGE_WIDTH)
+			/* scales increase */
+			break;
+
+		err = abs(found - geo->output.width);
+		if (err < best_err) {
+			best_err = err;
+			idx = i;
+			best = found;
+		}
+		if (!err)
+			break;
+	}
+
+	geo->output.width = best;
+	geo->scale_idx_h = idx;
+	if (geo->output.left + best > width_max)
+		geo->output.left = width_max - best;
+
+	pr_debug("%s(): W %u * %u/%u = %u\n", __func__, geo->in_width,
+		 vou_scale_h_num[idx], vou_scale_h_den[idx], best);
+
+	best_err = UINT_MAX;
+
+	/* This loop can be replaced with one division */
+	for (i = 0; i < ARRAY_SIZE(vou_scale_v_num); i++) {
+		unsigned int err;
+		unsigned int found = geo->in_height * vou_scale_v_num[i] /
+			vou_scale_v_den[i];
+
+		if (found > VOU_MAX_IMAGE_HEIGHT)
+			/* scales increase */
+			break;
+
+		err = abs(found - geo->output.height);
+		if (err < best_err) {
+			best_err = err;
+			idx = i;
+			best = found;
+		}
+		if (!err)
+			break;
+	}
+
+	geo->output.height = best;
+	geo->scale_idx_v = idx;
+	if (geo->output.top + best > height_max)
+		geo->output.top = height_max - best;
+
+	pr_debug("%s(): H %u * %u/%u = %u\n", __func__, geo->in_height,
+		 vou_scale_v_num[idx], vou_scale_v_den[idx], best);
+}
+
+static int sh_vou_s_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *fmt)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+	int pix_idx;
+	struct sh_vou_geometry geo;
+	struct v4l2_mbus_framefmt mbfmt = {
+		/* Revisit: is this the correct code? */
+		.code = V4L2_MBUS_FMT_YUYV8_2X8_LE,
+		.field = V4L2_FIELD_INTERLACED,
+		.colorspace = V4L2_COLORSPACE_SMPTE170M,
+	};
+	int ret;
+
+	dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__,
+		vou_dev->rect.width, vou_dev->rect.height,
+		pix->width, pix->height);
+
+	if (pix->field == V4L2_FIELD_ANY)
+		pix->field = V4L2_FIELD_NONE;
+
+	if (fmt->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
+	    pix->field != V4L2_FIELD_NONE)
+		return -EINVAL;
+
+	for (pix_idx = 0; pix_idx < ARRAY_SIZE(vou_fmt); pix_idx++)
+		if (vou_fmt[pix_idx].pfmt == pix->pixelformat)
+			break;
+
+	if (pix_idx == ARRAY_SIZE(vou_fmt))
+		return -EINVAL;
+
+	/* Image width must be a multiple of 4 */
+	v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 2,
+			      &pix->height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0);
+
+	geo.in_width = pix->width;
+	geo.in_height = pix->height;
+	geo.output = vou_dev->rect;
+
+	vou_adjust_output(&geo, vou_dev->std);
+
+	mbfmt.width = geo.output.width;
+	mbfmt.height = geo.output.height;
+	ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
+					 s_mbus_fmt, &mbfmt);
+	/* Must be implemented, so, don't check for -ENOIOCTLCMD */
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__,
+		geo.output.width, geo.output.height, mbfmt.width, mbfmt.height);
+
+	/* Sanity checks */
+	if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH ||
+	    (unsigned)mbfmt.height > VOU_MAX_IMAGE_HEIGHT ||
+	    mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8_LE)
+		return -EIO;
+
+	if (mbfmt.width != geo.output.width ||
+	    mbfmt.height != geo.output.height) {
+		geo.output.width = mbfmt.width;
+		geo.output.height = mbfmt.height;
+
+		vou_adjust_input(&geo, vou_dev->std);
+	}
+
+	/* We tried to preserve output rectangle, but it could have changed */
+	vou_dev->rect = geo.output;
+	pix->width = geo.in_width;
+	pix->height = geo.in_height;
+
+	dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u\n", __func__,
+		pix->width, pix->height);
+
+	vou_dev->pix_idx = pix_idx;
+
+	vou_dev->pix = *pix;
+
+	sh_vou_configure_geometry(vou_dev, pix_idx,
+				  geo.scale_idx_h, geo.scale_idx_v);
+
+	return 0;
+}
+
+static int sh_vou_try_fmt_vid_out(struct file *file, void *priv,
+				  struct v4l2_format *fmt)
+{
+	struct sh_vou_file *vou_file = priv;
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+	int i;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	pix->field = V4L2_FIELD_NONE;
+
+	v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 1,
+			      &pix->height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0);
+
+	for (i = 0; ARRAY_SIZE(vou_fmt); i++)
+		if (vou_fmt[i].pfmt == pix->pixelformat)
+			return 0;
+
+	pix->pixelformat = vou_fmt[0].pfmt;
+
+	return 0;
+}
+
+static int sh_vou_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *req)
+{
+	struct sh_vou_file *vou_file = priv;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+
+	return videobuf_reqbufs(&vou_file->vbq, req);
+}
+
+static int sh_vou_querybuf(struct file *file, void *priv,
+			   struct v4l2_buffer *b)
+{
+	struct sh_vou_file *vou_file = priv;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	return videobuf_querybuf(&vou_file->vbq, b);
+}
+
+static int sh_vou_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct sh_vou_file *vou_file = priv;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	return videobuf_qbuf(&vou_file->vbq, b);
+}
+
+static int sh_vou_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct sh_vou_file *vou_file = priv;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	return videobuf_dqbuf(&vou_file->vbq, b, file->f_flags & O_NONBLOCK);
+}
+
+static int sh_vou_streamon(struct file *file, void *priv,
+			   enum v4l2_buf_type buftype)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+	struct sh_vou_file *vou_file = priv;
+	int ret;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0,
+					 video, s_stream, 1);
+	if (ret < 0 && ret != -ENOIOCTLCMD)
+		return ret;
+
+	/* This calls our .buf_queue() (== sh_vou_buf_queue) */
+	return videobuf_streamon(&vou_file->vbq);
+}
+
+static int sh_vou_streamoff(struct file *file, void *priv,
+			    enum v4l2_buf_type buftype)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+	struct sh_vou_file *vou_file = priv;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	/*
+	 * This calls buf_release from host driver's videobuf_queue_ops for all
+	 * remaining buffers. When the last buffer is freed, stop streaming
+	 */
+	videobuf_streamoff(&vou_file->vbq);
+	v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, s_stream, 0);
+
+	return 0;
+}
+
+static u32 sh_vou_ntsc_mode(enum sh_vou_bus_fmt bus_fmt)
+{
+	switch (bus_fmt) {
+	default:
+		pr_warning("%s(): Invalid bus-format code %d, using default 8-bit\n",
+			   __func__, bus_fmt);
+	case SH_VOU_BUS_8BIT:
+		return 1;
+	case SH_VOU_BUS_16BIT:
+		return 0;
+	case SH_VOU_BUS_BT656:
+		return 3;
+	}
+}
+
+static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+	int ret;
+
+	dev_dbg(vou_dev->v4l2_dev.dev, "%s(): 0x%llx\n", __func__, *std_id);
+
+	if (*std_id & ~vdev->tvnorms)
+		return -EINVAL;
+
+	ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
+					 s_std_output, *std_id);
+	/* Shall we continue, if the subdev doesn't support .s_std_output()? */
+	if (ret < 0 && ret != -ENOIOCTLCMD)
+		return ret;
+
+	if (*std_id & V4L2_STD_525_60)
+		sh_vou_reg_ab_set(vou_dev, VOUCR,
+			sh_vou_ntsc_mode(vou_dev->pdata->bus_fmt) << 29, 7 << 29);
+	else
+		sh_vou_reg_ab_set(vou_dev, VOUCR, 5 << 29, 7 << 29);
+
+	vou_dev->std = *std_id;
+
+	return 0;
+}
+
+static int sh_vou_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+	dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
+
+	*std = vou_dev->std;
+
+	return 0;
+}
+
+static int sh_vou_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+	dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
+
+	a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	a->c = vou_dev->rect;
+
+	return 0;
+}
+
+/* Assume a dull encoder, do all the work ourselves. */
+static int sh_vou_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+	struct v4l2_rect *rect = &a->c;
+	struct v4l2_crop sd_crop = {.type = V4L2_BUF_TYPE_VIDEO_OUTPUT};
+	struct v4l2_pix_format *pix = &vou_dev->pix;
+	struct sh_vou_geometry geo;
+	struct v4l2_mbus_framefmt mbfmt = {
+		/* Revisit: is this the correct code? */
+		.code = V4L2_MBUS_FMT_YUYV8_2X8_LE,
+		.field = V4L2_FIELD_INTERLACED,
+		.colorspace = V4L2_COLORSPACE_SMPTE170M,
+	};
+	int ret;
+
+	dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u@%u:%u\n", __func__,
+		rect->width, rect->height, rect->left, rect->top);
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+
+	v4l_bound_align_image(&rect->width, 0, VOU_MAX_IMAGE_WIDTH, 1,
+			      &rect->height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0);
+
+	if (rect->width + rect->left > VOU_MAX_IMAGE_WIDTH)
+		rect->left = VOU_MAX_IMAGE_WIDTH - rect->width;
+
+	if (rect->height + rect->top > VOU_MAX_IMAGE_HEIGHT)
+		rect->top = VOU_MAX_IMAGE_HEIGHT - rect->height;
+
+	geo.output = *rect;
+	geo.in_width = pix->width;
+	geo.in_height = pix->height;
+
+	/* Configure the encoder one-to-one, position at 0, ignore errors */
+	sd_crop.c.width = geo.output.width;
+	sd_crop.c.height = geo.output.height;
+	/*
+	 * We first issue a S_CROP, so that the subsequent S_FMT delivers the
+	 * final encoder configuration.
+	 */
+	v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
+				   s_crop, &sd_crop);
+	mbfmt.width = geo.output.width;
+	mbfmt.height = geo.output.height;
+	ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
+					 s_mbus_fmt, &mbfmt);
+	/* Must be implemented, so, don't check for -ENOIOCTLCMD */
+	if (ret < 0)
+		return ret;
+
+	/* Sanity checks */
+	if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH ||
+	    (unsigned)mbfmt.height > VOU_MAX_IMAGE_HEIGHT ||
+	    mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8_LE)
+		return -EIO;
+
+	geo.output.width = mbfmt.width;
+	geo.output.height = mbfmt.height;
+
+	/*
+	 * No down-scaling. According to the API, current call has precedence:
+	 * http://v4l2spec.bytesex.org/spec/x1904.htm#AEN1954 paragraph two.
+	 */
+	vou_adjust_input(&geo, vou_dev->std);
+
+	/* We tried to preserve output rectangle, but it could have changed */
+	vou_dev->rect = geo.output;
+	pix->width = geo.in_width;
+	pix->height = geo.in_height;
+
+	sh_vou_configure_geometry(vou_dev, vou_dev->pix_idx,
+				  geo.scale_idx_h, geo.scale_idx_v);
+
+	return 0;
+}
+
+/*
+ * Total field: NTSC 858 x 2 * 262/263, PAL 864 x 2 * 312/313, default rectangle
+ * is the initial register values, height takes the interlaced format into
+ * account. The actual image can only go up to 720 x 2 * 240, So, VOUVPR can
+ * actually only meaningfully contain values <= 720 and <= 240 respectively, and
+ * not <= 864 and <= 312.
+ */
+static int sh_vou_cropcap(struct file *file, void *priv,
+			  struct v4l2_cropcap *a)
+{
+	struct sh_vou_file *vou_file = priv;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	a->type				= V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	a->bounds.left			= 0;
+	a->bounds.top			= 0;
+	a->bounds.width			= VOU_MAX_IMAGE_WIDTH;
+	a->bounds.height		= VOU_MAX_IMAGE_HEIGHT;
+	/* Default = max, set VOUDPR = 0, which is not hardware default */
+	a->defrect.left			= 0;
+	a->defrect.top			= 0;
+	a->defrect.width		= VOU_MAX_IMAGE_WIDTH;
+	a->defrect.height		= VOU_MAX_IMAGE_HEIGHT;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+static irqreturn_t sh_vou_isr(int irq, void *dev_id)
+{
+	struct sh_vou_device *vou_dev = dev_id;
+	static unsigned long j;
+	struct videobuf_buffer *vb;
+	static int cnt;
+	static int side;
+	u32 irq_status = sh_vou_reg_a_read(vou_dev, VOUIR), masked;
+	u32 vou_status = sh_vou_reg_a_read(vou_dev, VOUSTR);
+
+	if (!(irq_status & 0x300)) {
+		if (printk_timed_ratelimit(&j, 500))
+			dev_warn(vou_dev->v4l2_dev.dev, "IRQ status 0x%x!\n",
+				 irq_status);
+		return IRQ_NONE;
+	}
+
+	spin_lock(&vou_dev->lock);
+	if (!vou_dev->active || list_empty(&vou_dev->queue)) {
+		if (printk_timed_ratelimit(&j, 500))
+			dev_warn(vou_dev->v4l2_dev.dev,
+				 "IRQ without active buffer: %x!\n", irq_status);
+		/* Just ack: buf_release will disable further interrupts */
+		sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x300);
+		spin_unlock(&vou_dev->lock);
+		return IRQ_HANDLED;
+	}
+
+	masked = ~(0x300 & irq_status) & irq_status & 0x30304;
+	dev_dbg(vou_dev->v4l2_dev.dev,
+		"IRQ status 0x%x -> 0x%x, VOU status 0x%x, cnt %d\n",
+		irq_status, masked, vou_status, cnt);
+
+	cnt++;
+	side = vou_status & 0x10000;
+
+	/* Clear only set interrupts */
+	sh_vou_reg_a_write(vou_dev, VOUIR, masked);
+
+	vb = vou_dev->active;
+	list_del(&vb->queue);
+
+	vb->state = VIDEOBUF_DONE;
+	do_gettimeofday(&vb->ts);
+	vb->field_count++;
+	wake_up(&vb->done);
+
+	if (list_empty(&vou_dev->queue)) {
+		/* Stop VOU */
+		dev_dbg(vou_dev->v4l2_dev.dev, "%s: queue empty after %d\n",
+			__func__, cnt);
+		sh_vou_reg_a_set(vou_dev, VOUER, 0, 1);
+		vou_dev->active = NULL;
+		vou_dev->status = SH_VOU_INITIALISING;
+		/* Disable End-of-Frame (VSYNC) interrupts */
+		sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000);
+		spin_unlock(&vou_dev->lock);
+		return IRQ_HANDLED;
+	}
+
+	vou_dev->active = list_entry(vou_dev->queue.next,
+				     struct videobuf_buffer, queue);
+
+	if (vou_dev->active->queue.next != &vou_dev->queue) {
+		struct videobuf_buffer *new = list_entry(vou_dev->active->queue.next,
+						struct videobuf_buffer, queue);
+		sh_vou_schedule_next(vou_dev, new);
+	}
+
+	spin_unlock(&vou_dev->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int sh_vou_hw_init(struct sh_vou_device *vou_dev)
+{
+	struct sh_vou_pdata *pdata = vou_dev->pdata;
+	u32 voucr = sh_vou_ntsc_mode(pdata->bus_fmt) << 29;
+	int i = 100;
+
+	/* Disable all IRQs */
+	sh_vou_reg_a_write(vou_dev, VOUIR, 0);
+
+	/* Reset VOU interfaces - registers unaffected */
+	sh_vou_reg_a_write(vou_dev, VOUSRR, 0x101);
+	while (--i && (sh_vou_reg_a_read(vou_dev, VOUSRR) & 0x101))
+		udelay(1);
+
+	if (!i)
+		return -ETIMEDOUT;
+
+	dev_dbg(vou_dev->v4l2_dev.dev, "Reset took %dus\n", 100 - i);
+
+	if (pdata->flags & SH_VOU_PCLK_FALLING)
+		voucr |= 1 << 28;
+	if (pdata->flags & SH_VOU_HSYNC_LOW)
+		voucr |= 1 << 27;
+	if (pdata->flags & SH_VOU_VSYNC_LOW)
+		voucr |= 1 << 26;
+	sh_vou_reg_ab_set(vou_dev, VOUCR, voucr, 0xfc000000);
+
+	/* Manual register side switching at first */
+	sh_vou_reg_a_write(vou_dev, VOURCR, 4);
+	/* Default - fixed HSYNC length, can be made configurable is required */
+	sh_vou_reg_ab_write(vou_dev, VOUMSR, 0x800000);
+
+	return 0;
+}
+
+/* File operations */
+static int sh_vou_open(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+	struct sh_vou_file *vou_file = kzalloc(sizeof(struct sh_vou_file),
+					       GFP_KERNEL);
+
+	if (!vou_file)
+		return -ENOMEM;
+
+	dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
+
+	file->private_data = vou_file;
+
+	if (atomic_inc_return(&vou_dev->use_count) == 1) {
+		int ret;
+		/* First open */
+		vou_dev->status = SH_VOU_INITIALISING;
+		pm_runtime_get_sync(vdev->v4l2_dev->dev);
+		ret = sh_vou_hw_init(vou_dev);
+		if (ret < 0) {
+			atomic_dec(&vou_dev->use_count);
+			pm_runtime_put(vdev->v4l2_dev->dev);
+			vou_dev->status = SH_VOU_IDLE;
+			return ret;
+		}
+	}
+
+	videobuf_queue_dma_contig_init(&vou_file->vbq, &sh_vou_video_qops,
+				       vou_dev->v4l2_dev.dev, &vou_dev->lock,
+				       V4L2_BUF_TYPE_VIDEO_OUTPUT,
+				       V4L2_FIELD_NONE,
+				       sizeof(struct videobuf_buffer), vdev);
+
+	return 0;
+}
+
+static int sh_vou_release(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+	struct sh_vou_file *vou_file = file->private_data;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	if (!atomic_dec_return(&vou_dev->use_count)) {
+		/* Last close */
+		vou_dev->status = SH_VOU_IDLE;
+		sh_vou_reg_a_set(vou_dev, VOUER, 0, 0x101);
+		pm_runtime_put(vdev->v4l2_dev->dev);
+	}
+
+	file->private_data = NULL;
+	kfree(vou_file);
+
+	return 0;
+}
+
+static int sh_vou_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct sh_vou_file *vou_file = file->private_data;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	return videobuf_mmap_mapper(&vou_file->vbq, vma);
+}
+
+static unsigned int sh_vou_poll(struct file *file, poll_table *wait)
+{
+	struct sh_vou_file *vou_file = file->private_data;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	return videobuf_poll_stream(file, &vou_file->vbq, wait);
+}
+
+static int sh_vou_g_chip_ident(struct file *file, void *fh,
+				   struct v4l2_dbg_chip_ident *id)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+	return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, g_chip_ident, id);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int sh_vou_g_register(struct file *file, void *fh,
+				 struct v4l2_dbg_register *reg)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+	return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, g_register, reg);
+}
+
+static int sh_vou_s_register(struct file *file, void *fh,
+				 struct v4l2_dbg_register *reg)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+	return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, s_register, reg);
+}
+#endif
+
+/* sh_vou display ioctl operations */
+static const struct v4l2_ioctl_ops sh_vou_ioctl_ops = {
+	.vidioc_querycap        	= sh_vou_querycap,
+	.vidioc_enum_fmt_vid_out	= sh_vou_enum_fmt_vid_out,
+	.vidioc_g_fmt_vid_out		= sh_vou_g_fmt_vid_out,
+	.vidioc_s_fmt_vid_out		= sh_vou_s_fmt_vid_out,
+	.vidioc_try_fmt_vid_out		= sh_vou_try_fmt_vid_out,
+	.vidioc_reqbufs			= sh_vou_reqbufs,
+	.vidioc_querybuf		= sh_vou_querybuf,
+	.vidioc_qbuf			= sh_vou_qbuf,
+	.vidioc_dqbuf			= sh_vou_dqbuf,
+	.vidioc_streamon		= sh_vou_streamon,
+	.vidioc_streamoff		= sh_vou_streamoff,
+	.vidioc_s_std			= sh_vou_s_std,
+	.vidioc_g_std			= sh_vou_g_std,
+	.vidioc_cropcap			= sh_vou_cropcap,
+	.vidioc_g_crop			= sh_vou_g_crop,
+	.vidioc_s_crop			= sh_vou_s_crop,
+	.vidioc_g_chip_ident		= sh_vou_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register		= sh_vou_g_register,
+	.vidioc_s_register		= sh_vou_s_register,
+#endif
+};
+
+static const struct v4l2_file_operations sh_vou_fops = {
+	.owner		= THIS_MODULE,
+	.open		= sh_vou_open,
+	.release	= sh_vou_release,
+	.ioctl		= video_ioctl2,
+	.mmap		= sh_vou_mmap,
+	.poll		= sh_vou_poll,
+};
+
+static const struct video_device sh_vou_video_template = {
+	.name		= "sh_vou",
+	.fops		= &sh_vou_fops,
+	.ioctl_ops	= &sh_vou_ioctl_ops,
+	.tvnorms	= V4L2_STD_525_60, /* PAL only supported in 8-bit non-bt656 mode */
+	.current_norm	= V4L2_STD_NTSC_M,
+};
+
+static int __devinit sh_vou_probe(struct platform_device *pdev)
+{
+	struct sh_vou_pdata *vou_pdata = pdev->dev.platform_data;
+	struct v4l2_rect *rect;
+	struct v4l2_pix_format *pix;
+	struct i2c_adapter *i2c_adap;
+	struct video_device *vdev;
+	struct sh_vou_device *vou_dev;
+	struct resource *reg_res, *region;
+	struct v4l2_subdev *subdev;
+	int irq, ret;
+
+	reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	irq = platform_get_irq(pdev, 0);
+
+	if (!vou_pdata || !reg_res || irq <= 0) {
+		dev_err(&pdev->dev, "Insufficient VOU platform information.\n");
+		return -ENODEV;
+	}
+
+	vou_dev = kzalloc(sizeof(*vou_dev), GFP_KERNEL);
+	if (!vou_dev)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&vou_dev->queue);
+	spin_lock_init(&vou_dev->lock);
+	atomic_set(&vou_dev->use_count, 0);
+	vou_dev->pdata = vou_pdata;
+	vou_dev->status = SH_VOU_IDLE;
+
+	rect = &vou_dev->rect;
+	pix = &vou_dev->pix;
+
+	/* Fill in defaults */
+	vou_dev->std		= sh_vou_video_template.current_norm;
+	rect->left		= 0;
+	rect->top		= 0;
+	rect->width		= VOU_MAX_IMAGE_WIDTH;
+	rect->height		= VOU_MAX_IMAGE_HEIGHT;
+	pix->width		= VOU_MAX_IMAGE_WIDTH;
+	pix->height		= VOU_MAX_IMAGE_HEIGHT;
+	pix->pixelformat	= V4L2_PIX_FMT_YVYU;
+	pix->field		= V4L2_FIELD_NONE;
+	pix->bytesperline	= VOU_MAX_IMAGE_WIDTH * 2;
+	pix->sizeimage		= VOU_MAX_IMAGE_WIDTH * 2 * VOU_MAX_IMAGE_HEIGHT;
+	pix->colorspace		= V4L2_COLORSPACE_SMPTE170M;
+
+	region = request_mem_region(reg_res->start, resource_size(reg_res),
+				    pdev->name);
+	if (!region) {
+		dev_err(&pdev->dev, "VOU region already claimed\n");
+		ret = -EBUSY;
+		goto ereqmemreg;
+	}
+
+	vou_dev->base = ioremap(reg_res->start, resource_size(reg_res));
+	if (!vou_dev->base) {
+		ret = -ENOMEM;
+		goto emap;
+	}
+
+	ret = request_irq(irq, sh_vou_isr, 0, "vou", vou_dev);
+	if (ret < 0)
+		goto ereqirq;
+
+	ret = v4l2_device_register(&pdev->dev, &vou_dev->v4l2_dev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Error registering v4l2 device\n");
+		goto ev4l2devreg;
+	}
+
+	/* Allocate memory for video device */
+	vdev = video_device_alloc();
+	if (vdev == NULL) {
+		ret = -ENOMEM;
+		goto evdevalloc;
+	}
+
+	*vdev = sh_vou_video_template;
+	if (vou_pdata->bus_fmt == SH_VOU_BUS_8BIT)
+		vdev->tvnorms |= V4L2_STD_PAL;
+	vdev->v4l2_dev = &vou_dev->v4l2_dev;
+	vdev->release = video_device_release;
+
+	vou_dev->vdev = vdev;
+	video_set_drvdata(vdev, vou_dev);
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_resume(&pdev->dev);
+
+	i2c_adap = i2c_get_adapter(vou_pdata->i2c_adap);
+	if (!i2c_adap) {
+		ret = -ENODEV;
+		goto ei2cgadap;
+	}
+
+	ret = sh_vou_hw_init(vou_dev);
+	if (ret < 0)
+		goto ereset;
+
+	subdev = v4l2_i2c_new_subdev_board(&vou_dev->v4l2_dev, i2c_adap,
+			vou_pdata->module_name, vou_pdata->board_info, NULL);
+	if (!subdev) {
+		ret = -ENOMEM;
+		goto ei2cnd;
+	}
+
+	ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+	if (ret < 0)
+		goto evregdev;
+
+	return 0;
+
+evregdev:
+ei2cnd:
+ereset:
+	i2c_put_adapter(i2c_adap);
+ei2cgadap:
+	video_device_release(vdev);
+	pm_runtime_disable(&pdev->dev);
+evdevalloc:
+	v4l2_device_unregister(&vou_dev->v4l2_dev);
+ev4l2devreg:
+	free_irq(irq, vou_dev);
+ereqirq:
+	iounmap(vou_dev->base);
+emap:
+	release_mem_region(reg_res->start, resource_size(reg_res));
+ereqmemreg:
+	kfree(vou_dev);
+	return ret;
+}
+
+static int __devexit sh_vou_remove(struct platform_device *pdev)
+{
+	int irq = platform_get_irq(pdev, 0);
+	struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
+	struct sh_vou_device *vou_dev = container_of(v4l2_dev,
+						struct sh_vou_device, v4l2_dev);
+	struct v4l2_subdev *sd = list_entry(v4l2_dev->subdevs.next,
+					    struct v4l2_subdev, list);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct resource *reg_res;
+
+	if (irq > 0)
+		free_irq(irq, vou_dev);
+	pm_runtime_disable(&pdev->dev);
+	video_unregister_device(vou_dev->vdev);
+	i2c_put_adapter(client->adapter);
+	v4l2_device_unregister(&vou_dev->v4l2_dev);
+	iounmap(vou_dev->base);
+	reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (reg_res)
+		release_mem_region(reg_res->start, resource_size(reg_res));
+	kfree(vou_dev);
+	return 0;
+}
+
+static struct platform_driver __refdata sh_vou = {
+	.remove  = __devexit_p(sh_vou_remove),
+	.driver  = {
+		.name	= "sh-vou",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init sh_vou_init(void)
+{
+	return platform_driver_probe(&sh_vou, sh_vou_probe);
+}
+
+static void __exit sh_vou_exit(void)
+{
+	platform_driver_unregister(&sh_vou);
+}
+
+module_init(sh_vou_init);
+module_exit(sh_vou_exit);
+
+MODULE_DESCRIPTION("SuperH VOU driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sh-vou");
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index cbf8087..28e19da 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -2295,7 +2295,7 @@
 	if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
 		return -EFAULT;
 
-	for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+	for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) {
 		if (ctrl.id == s->qctrl[i].id) {
 			if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
 				return -EINVAL;
@@ -2305,7 +2305,9 @@
 			ctrl.value -= ctrl.value % s->qctrl[i].step;
 			break;
 		}
-
+	}
+	if (i == ARRAY_SIZE(s->qctrl))
+		return -EINVAL;
 	if ((err = s->set_ctrl(cam, &ctrl)))
 		return err;
 
diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h
index cc40d6b..522ba3f 100644
--- a/drivers/media/video/sn9c102/sn9c102_devtable.h
+++ b/drivers/media/video/sn9c102/sn9c102_devtable.h
@@ -40,12 +40,12 @@
 
 static const struct usb_device_id sn9c102_id_table[] = {
 	/* SN9C101 and SN9C102 */
-#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
+#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6001, BRIDGE_SN9C102), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6005, BRIDGE_SN9C102), },
 #endif
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6007, BRIDGE_SN9C102), },
-#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
+#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), },
 /*	{ SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), }, OV6650 */
@@ -53,13 +53,13 @@
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), },
-#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
+#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6028, BRIDGE_SN9C102), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6029, BRIDGE_SN9C102), },
 #endif
 	{ SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), },
-#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
+#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
 	{ SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), },
 /*	{ SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, HV7131R */
 #endif
@@ -74,7 +74,7 @@
 	{ SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x608c, BRIDGE_SN9C103), },
 /*	{ SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), }, CISVF10 */
-#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
+#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
 	{ SN9C102_USB_DEVICE(0x0c45, 0x608f, BRIDGE_SN9C103), },
 #endif
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), },
@@ -86,7 +86,7 @@
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60af, BRIDGE_SN9C103), },
-#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
+#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60b0, BRIDGE_SN9C103), },
 #endif
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), },
@@ -97,7 +97,7 @@
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), },
 	/* SN9C105 */
-#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
+#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE
 	{ SN9C102_USB_DEVICE(0x045e, 0x00f5, BRIDGE_SN9C105), },
 	{ SN9C102_USB_DEVICE(0x045e, 0x00f7, BRIDGE_SN9C105), },
 	{ SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), },
@@ -121,11 +121,11 @@
 	{ SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), },
 /*	{ SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, MO8000 */
-#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
+#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE
 	{ SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), },
 #endif
 	{ SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), },
-#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
+#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE
 	{ SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), },
 #endif
diff --git a/drivers/media/video/sn9c102/sn9c102_hv7131d.c b/drivers/media/video/sn9c102/sn9c102_hv7131d.c
index db24349..2dce5c9 100644
--- a/drivers/media/video/sn9c102/sn9c102_hv7131d.c
+++ b/drivers/media/video/sn9c102/sn9c102_hv7131d.c
@@ -255,7 +255,7 @@
 	if (err || r0 < 0 || r1 < 0)
 		return -EIO;
 
-	if (r0 != 0x00 || r1 != 0x04)
+	if ((r0 != 0x00 && r0 != 0x01) || r1 != 0x04)
 		return -ENODEV;
 
 	sn9c102_attach_sensor(cam, &hv7131d);
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index a24174d..db1ca0e 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/pm_runtime.h>
 #include <linux/vmalloc.h>
 
 #include <media/soc_camera.h>
@@ -388,6 +389,11 @@
 			goto eiciadd;
 		}
 
+		pm_runtime_enable(&icd->vdev->dev);
+		ret = pm_runtime_resume(&icd->vdev->dev);
+		if (ret < 0 && ret != -ENOSYS)
+			goto eresume;
+
 		/*
 		 * Try to configure with default parameters. Notice: this is the
 		 * very first open, so, we cannot race against other calls,
@@ -409,10 +415,12 @@
 	return 0;
 
 	/*
-	 * First five errors are entered with the .video_lock held
+	 * First four errors are entered with the .video_lock held
 	 * and use_count == 1
 	 */
 esfmt:
+	pm_runtime_disable(&icd->vdev->dev);
+eresume:
 	ici->ops->remove(icd);
 eiciadd:
 	if (icl->power)
@@ -437,7 +445,11 @@
 	if (!icd->use_count) {
 		struct soc_camera_link *icl = to_soc_camera_link(icd);
 
+		pm_runtime_suspend(&icd->vdev->dev);
+		pm_runtime_disable(&icd->vdev->dev);
+
 		ici->ops->remove(icd);
+
 		if (icl->power)
 			icl->power(icd->pdev, 0);
 	}
@@ -741,8 +753,7 @@
 /*
  * According to the V4L2 API, drivers shall not update the struct v4l2_crop
  * argument with the actual geometry, instead, the user shall use G_CROP to
- * retrieve it. However, we expect camera host and client drivers to update
- * the argument, which we then use internally, but do not return to the user.
+ * retrieve it.
  */
 static int soc_camera_s_crop(struct file *file, void *fh,
 			     struct v4l2_crop *a)
@@ -1319,6 +1330,7 @@
  */
 static int soc_camera_video_start(struct soc_camera_device *icd)
 {
+	struct device_type *type = icd->vdev->dev.type;
 	int ret;
 
 	if (!icd->dev.parent)
@@ -1335,6 +1347,9 @@
 		return ret;
 	}
 
+	/* Restore device type, possibly set by the subdevice driver */
+	icd->vdev->dev.type = type;
+
 	return 0;
 }
 
diff --git a/drivers/media/video/tlg2300/pd-dvb.c b/drivers/media/video/tlg2300/pd-dvb.c
index ebd9cb5..edd78f8 100644
--- a/drivers/media/video/tlg2300/pd-dvb.c
+++ b/drivers/media/video/tlg2300/pd-dvb.c
@@ -97,15 +97,17 @@
 	return ret;
 }
 
+#ifdef CONFIG_PM
 static void poseidon_fe_release(struct dvb_frontend *fe)
 {
 	struct poseidon *pd = fe->demodulator_priv;
 
-#ifdef CONFIG_PM
 	pd->pm_suspend = NULL;
 	pd->pm_resume  = NULL;
-#endif
 }
+#else
+#define poseidon_fe_release NULL
+#endif
 
 static s32 poseidon_fe_sleep(struct dvb_frontend *fe)
 {
diff --git a/drivers/media/video/tlg2300/pd-main.c b/drivers/media/video/tlg2300/pd-main.c
index 2cf0ebf..c267e0c 100644
--- a/drivers/media/video/tlg2300/pd-main.c
+++ b/drivers/media/video/tlg2300/pd-main.c
@@ -24,7 +24,6 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/init.h>
@@ -55,8 +54,8 @@
 module_param(debug_mode, int, 0644);
 MODULE_PARM_DESC(debug_mode, "0 = disable, 1 = enable, 2 = verbose");
 
-const char *firmware_name = "tlg2300_firmware.bin";
-struct usb_driver poseidon_driver;
+static const char *firmware_name = "tlg2300_firmware.bin";
+static struct usb_driver poseidon_driver;
 static LIST_HEAD(pd_device_list);
 
 /*
@@ -501,7 +500,7 @@
 	kref_put(&pd->kref, poseidon_delete);
 }
 
-struct usb_driver poseidon_driver = {
+static struct usb_driver poseidon_driver = {
 	.name		= "poseidon",
 	.probe		= poseidon_probe,
 	.disconnect	= poseidon_disconnect,
diff --git a/drivers/media/video/tlg2300/pd-radio.c b/drivers/media/video/tlg2300/pd-radio.c
index 755766b1..fae84c2 100644
--- a/drivers/media/video/tlg2300/pd-radio.c
+++ b/drivers/media/video/tlg2300/pd-radio.c
@@ -161,7 +161,8 @@
 	.ioctl	       = video_ioctl2,
 };
 
-int tlg_fm_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt)
+static int tlg_fm_vidioc_g_tuner(struct file *file, void *priv,
+				 struct v4l2_tuner *vt)
 {
 	struct tuner_fm_sig_stat_s fm_stat = {};
 	int ret, status, count = 5;
@@ -203,7 +204,8 @@
 	return 0;
 }
 
-int fm_get_freq(struct file *file, void *priv, struct v4l2_frequency *argp)
+static int fm_get_freq(struct file *file, void *priv,
+		       struct v4l2_frequency *argp)
 {
 	struct poseidon *p = file->private_data;
 
@@ -246,7 +248,8 @@
 	return ret;
 }
 
-int fm_set_freq(struct file *file, void *priv, struct v4l2_frequency *argp)
+static int fm_set_freq(struct file *file, void *priv,
+		       struct v4l2_frequency *argp)
 {
 	struct poseidon *p = file->private_data;
 
@@ -258,13 +261,13 @@
 	return set_frequency(p, argp->frequency);
 }
 
-int tlg_fm_vidioc_g_ctrl(struct file *file, void *priv,
+static int tlg_fm_vidioc_g_ctrl(struct file *file, void *priv,
 		struct v4l2_control *arg)
 {
 	return 0;
 }
 
-int tlg_fm_vidioc_g_exts_ctrl(struct file *file, void *fh,
+static int tlg_fm_vidioc_g_exts_ctrl(struct file *file, void *fh,
 				struct v4l2_ext_controls *ctrls)
 {
 	struct poseidon *p = file->private_data;
@@ -285,7 +288,7 @@
 	return 0;
 }
 
-int tlg_fm_vidioc_s_exts_ctrl(struct file *file, void *fh,
+static int tlg_fm_vidioc_s_exts_ctrl(struct file *file, void *fh,
 			struct v4l2_ext_controls *ctrls)
 {
 	int i;
@@ -312,13 +315,13 @@
 	return 0;
 }
 
-int tlg_fm_vidioc_s_ctrl(struct file *file, void *priv,
+static int tlg_fm_vidioc_s_ctrl(struct file *file, void *priv,
 		struct v4l2_control *ctrl)
 {
 	return 0;
 }
 
-int tlg_fm_vidioc_queryctrl(struct file *file, void *priv,
+static int tlg_fm_vidioc_queryctrl(struct file *file, void *priv,
 		struct v4l2_queryctrl *ctrl)
 {
 	if (!(ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL))
@@ -337,7 +340,7 @@
 	return -EINVAL;
 }
 
-int tlg_fm_vidioc_querymenu(struct file *file, void *fh,
+static int tlg_fm_vidioc_querymenu(struct file *file, void *fh,
 				struct v4l2_querymenu *qmenu)
 {
 	return v4l2_ctrl_query_menu(qmenu, NULL, NULL);
diff --git a/drivers/media/video/tlg2300/pd-video.c b/drivers/media/video/tlg2300/pd-video.c
index cf8f18c..c750fd1 100644
--- a/drivers/media/video/tlg2300/pd-video.c
+++ b/drivers/media/video/tlg2300/pd-video.c
@@ -12,11 +12,13 @@
 #include "pd-common.h"
 #include "vendorcmds.h"
 
+#ifdef CONFIG_PM
 static int pm_video_suspend(struct poseidon *pd);
 static int pm_video_resume(struct poseidon *pd);
+#endif
 static void iso_bubble_handler(struct work_struct *w);
 
-int usb_transfer_mode;
+static int usb_transfer_mode;
 module_param(usb_transfer_mode, int, 0644);
 MODULE_PARM_DESC(usb_transfer_mode, "0 = Bulk, 1 = Isochronous");
 
@@ -617,7 +619,7 @@
 	return 0;
 }
 
-int fire_all_urb(struct video_data *video)
+static int fire_all_urb(struct video_data *video)
 {
 	int i, ret;
 
@@ -877,7 +879,7 @@
 	return ret;
 }
 
-int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *norm)
 {
 	struct front_face *front = fh;
 	logs(front);
@@ -1020,7 +1022,7 @@
 	return 0;
 }
 
-int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
+static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
 {
 	a->index = 0;
 	a->capability = V4L2_AUDCAP_STEREO;
@@ -1029,7 +1031,7 @@
 	return 0;
 }
 
-int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
+static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
 {
 	return (0 == a->index) ? 0 : -EINVAL;
 }
@@ -1189,7 +1191,7 @@
 }
 
 /* Just stop the URBs, do not free the URBs */
-int usb_transfer_stop(struct video_data *video)
+static int usb_transfer_stop(struct video_data *video)
 {
 	if (video->is_streaming) {
 		int i;
@@ -1518,13 +1520,13 @@
 	return  videobuf_mmap_mapper(&front->q, vma);
 }
 
-unsigned int pd_video_poll(struct file *file, poll_table *table)
+static unsigned int pd_video_poll(struct file *file, poll_table *table)
 {
 	struct front_face *front = file->private_data;
 	return videobuf_poll_stream(file, &front->q, table);
 }
 
-ssize_t pd_video_read(struct file *file, char __user *buffer,
+static ssize_t pd_video_read(struct file *file, char __user *buffer,
 			size_t count, loff_t *ppos)
 {
 	struct front_face *front = file->private_data;
diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c
index e4815a1..e826114 100644
--- a/drivers/media/video/tvp514x.c
+++ b/drivers/media/video/tvp514x.c
@@ -79,6 +79,8 @@
 };
 
 static struct tvp514x_reg tvp514x_reg_list_default[0x40];
+
+static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable);
 /**
  * struct tvp514x_decoder - TVP5146/47 decoder object
  * @sd: Subdevice Slave handle
@@ -644,6 +646,17 @@
 		/* Index out of bound */
 		return -EINVAL;
 
+	/*
+	 * For the sequence streamon -> streamoff and again s_input
+	 * it fails to lock the signal, since streamoff puts TVP514x
+	 * into power off state which leads to failure in sub-sequent s_input.
+	 *
+	 * So power up the TVP514x device here, since it is important to lock
+	 * the signal at this stage.
+	 */
+	if (!decoder->streaming)
+		tvp514x_s_stream(sd, 1);
+
 	input_sel = input;
 	output_sel = output;
 
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index 908ffb6..47f0582 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -891,29 +891,26 @@
 	return 0;
 }
 
-static int tvp5150_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+static int tvp5150_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt)
 {
-	struct v4l2_sliced_vbi_format *svbi;
+	/* this is for capturing 36 raw vbi lines
+	   if there's a way to cut off the beginning 2 vbi lines
+	   with the tvp5150 then the vbi line count could be lowered
+	   to 17 lines/field again, although I couldn't find a register
+	   which could do that cropping */
+	if (fmt->sample_format == V4L2_PIX_FMT_GREY)
+		tvp5150_write(sd, TVP5150_LUMA_PROC_CTL_1, 0x70);
+	if (fmt->count[0] == 18 && fmt->count[1] == 18) {
+		tvp5150_write(sd, TVP5150_VERT_BLANKING_START, 0x00);
+		tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP, 0x01);
+	}
+	return 0;
+}
+
+static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
+{
 	int i;
 
-	/* raw vbi */
-	if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-		/* this is for capturing 36 raw vbi lines
-		   if there's a way to cut off the beginning 2 vbi lines
-		   with the tvp5150 then the vbi line count could be lowered
-		   to 17 lines/field again, although I couldn't find a register
-		   which could do that cropping */
-		if (fmt->fmt.vbi.sample_format == V4L2_PIX_FMT_GREY)
-			tvp5150_write(sd, TVP5150_LUMA_PROC_CTL_1, 0x70);
-		if (fmt->fmt.vbi.count[0] == 18 && fmt->fmt.vbi.count[1] == 18) {
-			tvp5150_write(sd, TVP5150_VERT_BLANKING_START, 0x00);
-			tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP, 0x01);
-		}
-		return 0;
-	}
-	if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
-		return -EINVAL;
-	svbi = &fmt->fmt.sliced;
 	if (svbi->service_set != 0) {
 		for (i = 0; i <= 23; i++) {
 			svbi->service_lines[1][i] = 0;
@@ -937,14 +934,21 @@
 	return 0;
 }
 
-static int tvp5150_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+static int tvp5150_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
 {
-	struct v4l2_sliced_vbi_format *svbi;
+	switch (fmt->type) {
+	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+		return tvp5150_s_sliced_fmt(sd, &fmt->fmt.sliced);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
+{
 	int i, mask = 0;
 
-	if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
-		return -EINVAL;
-	svbi = &fmt->fmt.sliced;
 	memset(svbi, 0, sizeof(*svbi));
 
 	for (i = 0; i <= 23; i++) {
@@ -956,6 +960,12 @@
 	return 0;
 }
 
+static int tvp5150_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+	if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+		return -EINVAL;
+	return tvp5150_g_sliced_fmt(sd, &fmt->fmt.sliced);
+}
 
 static int tvp5150_g_chip_ident(struct v4l2_subdev *sd,
 				struct v4l2_dbg_chip_ident *chip)
@@ -1046,13 +1056,20 @@
 	.s_routing = tvp5150_s_routing,
 	.g_fmt = tvp5150_g_fmt,
 	.s_fmt = tvp5150_s_fmt,
+};
+
+static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = {
 	.g_sliced_vbi_cap = tvp5150_g_sliced_vbi_cap,
+	.g_sliced_fmt = tvp5150_g_sliced_fmt,
+	.s_sliced_fmt = tvp5150_s_sliced_fmt,
+	.s_raw_fmt = tvp5150_s_raw_fmt,
 };
 
 static const struct v4l2_subdev_ops tvp5150_ops = {
 	.core = &tvp5150_core_ops,
 	.tuner = &tvp5150_tuner_ops,
 	.video = &tvp5150_video_ops,
+	.vbi = &tvp5150_vbi_ops,
 };
 
 
diff --git a/drivers/media/video/tvp7002.c b/drivers/media/video/tvp7002.c
index 4a69bcc..8085ac3 100644
--- a/drivers/media/video/tvp7002.c
+++ b/drivers/media/video/tvp7002.c
@@ -458,7 +458,7 @@
 /*
  * tvp7002_read - Read a value from a register in an TVP7002
  * @sd: ptr to v4l2_subdev struct
- * @reg: TVP7002 register address
+ * @addr: TVP7002 register address
  * @dst: pointer to 8-bit destination
  *
  * Returns value read if successful, or non-zero (-1) otherwise.
@@ -488,7 +488,7 @@
  * @sd: pointer to standard V4L2 sub-device structure
  * @reg: destination register
  * @val: value to be read
- * @error: pointer to error value
+ * @err: pointer to error value
  *
  * Read a value in a register and save error value in pointer.
  * Also update the register table if successful
@@ -535,7 +535,7 @@
  * @sd: pointer to standard V4L2 sub-device structure
  * @reg: destination register
  * @val: value to be written
- * @error: pointer to error value
+ * @err: pointer to error value
  *
  * Write a value in a register and save error value in pointer.
  * Also update the register table if successful
@@ -596,7 +596,7 @@
 /*
  * tvp7002_s_dv_preset() - Set digital video preset
  * @sd: ptr to v4l2_subdev struct
- * @std: ptr to v4l2_dv_preset struct
+ * @dv_preset: ptr to v4l2_dv_preset struct
  *
  * Set the digital video preset for a TVP7002 decoder device.
  * Returns zero when successful or -EINVAL if register access fails.
@@ -676,7 +676,7 @@
 /*
  * tvp7002_queryctrl() - Query a control
  * @sd: ptr to v4l2_subdev struct
- * @ctrl: ptr to v4l2_queryctrl struct
+ * @qc: ptr to v4l2_queryctrl struct
  *
  * Query a control of a TVP7002 decoder device.
  * Returns zero when successful or -EINVAL if register read fails.
@@ -776,7 +776,7 @@
 /*
  * tvp7002_query_dv_preset() - query DV preset
  * @sd: pointer to standard V4L2 sub-device structure
- * @std_id: standard V4L2 v4l2_dv_preset
+ * @qpreset: standard V4L2 v4l2_dv_preset structure
  *
  * Returns the current DV preset by TVP7002. If no active input is
  * detected, returns -EINVAL
@@ -785,7 +785,6 @@
 						struct v4l2_dv_preset *qpreset)
 {
 	const struct tvp7002_preset_definition *presets = tvp7002_presets;
-	struct v4l2_dv_enum_preset e_preset;
 	struct tvp7002 *device;
 	u8 progressive;
 	u32 lpfr;
@@ -828,20 +827,18 @@
 		}
 
 	if (index == NUM_PRESETS) {
-		v4l2_err(sd, "querystd error, lpf = %x, cpl = %x\n",
+		v4l2_dbg(1, debug, sd, "detection failed: lpf = %x, cpl = %x\n",
 								lpfr, cpln);
-		return -EINVAL;
+		/* Could not detect a signal, so return the 'invalid' preset */
+		qpreset->preset = V4L2_DV_INVALID;
+		return 0;
 	}
 
-	if (v4l_fill_dv_preset_info(presets->preset, &e_preset))
-		return -EINVAL;
-
 	/* Set values in found preset */
 	qpreset->preset = presets->preset;
 
 	/* Update lines per frame and clocks per line info */
-	v4l2_dbg(1, debug, sd, "Current preset: %d %d",
-					e_preset.width, e_preset.height);
+	v4l2_dbg(1, debug, sd, "detected preset: %d\n", presets->preset);
 	return 0;
 }
 
@@ -849,7 +846,7 @@
 /*
  * tvp7002_g_register() - Get the value of a register
  * @sd: ptr to v4l2_subdev struct
- * @vreg: ptr to v4l2_dbg_register struct
+ * @reg: ptr to v4l2_dbg_register struct
  *
  * Get the value of a TVP7002 decoder device register.
  * Returns zero when successful, -EINVAL if register read fails or
@@ -876,7 +873,7 @@
 /*
  * tvp7002_s_register() - set a control
  * @sd: ptr to v4l2_subdev struct
- * @ctrl: ptr to v4l2_control struct
+ * @reg: ptr to v4l2_dbg_register struct
  *
  * Get the value of a TVP7002 decoder device register.
  * Returns zero when successful, -EINVAL if register read fails or
@@ -899,7 +896,7 @@
 /*
  * tvp7002_enum_fmt() - Enum supported formats
  * @sd: pointer to standard V4L2 sub-device structure
- * @enable: pointer to format struct
+ * @fmtdesc: pointer to format struct
  *
  * Enumerate supported formats.
  */
@@ -994,6 +991,23 @@
 	return 0;
 }
 
+/*
+ * tvp7002_enum_dv_presets() - Enum supported digital video formats
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @preset: pointer to format struct
+ *
+ * Enumerate supported digital video formats.
+ */
+static int tvp7002_enum_dv_presets(struct v4l2_subdev *sd,
+		struct v4l2_dv_enum_preset *preset)
+{
+	/* Check requested format index is within range */
+	if (preset->index >= NUM_PRESETS)
+		return -EINVAL;
+
+	return v4l_fill_dv_preset_info(tvp7002_presets[preset->index].preset, preset);
+}
+
 /* V4L2 core operation handlers */
 static const struct v4l2_subdev_core_ops tvp7002_core_ops = {
 	.g_chip_ident = tvp7002_g_chip_ident,
@@ -1009,6 +1023,7 @@
 
 /* Specific video subsystem operation handlers */
 static const struct v4l2_subdev_video_ops tvp7002_video_ops = {
+	.enum_dv_presets = tvp7002_enum_dv_presets,
 	.s_dv_preset = tvp7002_s_dv_preset,
 	.query_dv_preset = tvp7002_query_dv_preset,
 	.s_stream = tvp7002_s_stream,
@@ -1042,8 +1057,8 @@
 
 /*
  * tvp7002_probe - Probe a TVP7002 device
- * @sd: ptr to v4l2_subdev struct
- * @ctrl: ptr to i2c_device_id struct
+ * @c: ptr to i2c_client struct
+ * @id: ptr to i2c_device_id struct
  *
  * Initialize the TVP7002 device
  * Returns zero when successful, -EINVAL if register read fails or
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
index fab48ec..fbd665f 100644
--- a/drivers/media/video/usbvideo/quickcam_messenger.c
+++ b/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -693,12 +693,13 @@
 
 static void qcm_stop_data(struct uvd *uvd)
 {
-	struct qcm *cam = (struct qcm *) uvd->user_data;
+	struct qcm *cam;
 	int i, j;
 	int ret;
 
 	if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
 		return;
+	cam = (struct qcm *) uvd->user_data;
 
 	ret = qcm_camera_off(uvd);
 	if (ret)
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c
index 08376523..42ba287 100644
--- a/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/drivers/media/video/usbvision/usbvision-i2c.c
@@ -244,6 +244,9 @@
 	switch (usbvision_device_data[usbvision->DevModel].Codec) {
 	case CODEC_SAA7113:
 	case CODEC_SAA7111:
+		/* Without this delay the detection of the saa711x is
+		   hit-and-miss. */
+		mdelay(10);
 		v4l2_i2c_new_subdev(&usbvision->v4l2_dev,
 				&usbvision->i2c_adap, "saa7115",
 				"saa7115_auto", 0, saa711x_addrs);
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index 7c17ec6..6248a63 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -137,8 +137,6 @@
 static int video_nr = -1;
 /* Sequential Number of Radio Device */
 static int radio_nr = -1;
-/* Sequential Number of VBI Device */
-static int vbi_nr = -1;
 
 /* Grab parameters for the device driver */
 
@@ -148,14 +146,12 @@
 module_param(PowerOnAtOpen, int, 0444);
 module_param(video_nr, int, 0444);
 module_param(radio_nr, int, 0444);
-module_param(vbi_nr, int, 0444);
 
 MODULE_PARM_DESC(isocMode, " Set the default format for ISOC endpoint.  Default: 0x60 (Compression On)");
 MODULE_PARM_DESC(video_debug, " Set the default Debug Mode of the device driver.  Default: 0 (Off)");
 MODULE_PARM_DESC(PowerOnAtOpen, " Set the default device to power on when device is opened.  Default: 1 (On)");
 MODULE_PARM_DESC(video_nr, "Set video device number (/dev/videoX).  Default: -1 (autodetect)");
 MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX).  Default: -1 (autodetect)");
-MODULE_PARM_DESC(vbi_nr, "Set vbi device number (/dev/vbiX).  Default: -1 (autodetect)");
 
 
 // Misc stuff
@@ -1244,36 +1240,6 @@
 	return errCode;
 }
 
-/*
- * Here comes the stuff for vbi on usbvision based devices
- *
- */
-static int usbvision_vbi_open(struct file *file)
-{
-	/* TODO */
-	return -ENODEV;
-}
-
-static int usbvision_vbi_close(struct file *file)
-{
-	/* TODO */
-	return -ENODEV;
-}
-
-static long usbvision_do_vbi_ioctl(struct file *file,
-				 unsigned int cmd, void *arg)
-{
-	/* TODO */
-	return -ENOIOCTLCMD;
-}
-
-static long usbvision_vbi_ioctl(struct file *file,
-		       unsigned int cmd, unsigned long arg)
-{
-	return video_usercopy(file, cmd, arg, usbvision_do_vbi_ioctl);
-}
-
-
 //
 // Video registration stuff
 //
@@ -1367,21 +1333,6 @@
 	.current_norm         = V4L2_STD_PAL
 };
 
-// vbi template
-static const struct v4l2_file_operations usbvision_vbi_fops = {
-	.owner             = THIS_MODULE,
-	.open		= usbvision_vbi_open,
-	.release	= usbvision_vbi_close,
-	.ioctl		= usbvision_vbi_ioctl,
-};
-
-static struct video_device usbvision_vbi_template=
-{
-	.fops		= &usbvision_vbi_fops,
-	.release	= video_device_release,
-	.name           = "usbvision-vbi",
-};
-
 
 static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision,
 					struct video_device *vdev_template,
@@ -1410,18 +1361,6 @@
 // unregister video4linux devices
 static void usbvision_unregister_video(struct usb_usbvision *usbvision)
 {
-	// vbi Device:
-	if (usbvision->vbi) {
-		PDEBUG(DBG_PROBE, "unregister %s [v4l2]",
-		       video_device_node_name(usbvision->vbi));
-		if (video_is_registered(usbvision->vbi)) {
-			video_unregister_device(usbvision->vbi);
-		} else {
-			video_device_release(usbvision->vbi);
-		}
-		usbvision->vbi = NULL;
-	}
-
 	// Radio Device:
 	if (usbvision->rdev) {
 		PDEBUG(DBG_PROBE, "unregister %s [v4l2]",
@@ -1482,22 +1421,6 @@
 		printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device %s [v4l2]\n",
 		       usbvision->nr, video_device_node_name(usbvision->rdev));
 	}
-	// vbi Device:
-	if (usbvision_device_data[usbvision->DevModel].vbi) {
-		usbvision->vbi = usbvision_vdev_init(usbvision,
-						     &usbvision_vbi_template,
-						     "USBVision VBI");
-		if (usbvision->vbi == NULL) {
-			goto err_exit;
-		}
-		if (video_register_device(usbvision->vbi,
-					  VFL_TYPE_VBI,
-					  vbi_nr)<0) {
-			goto err_exit;
-		}
-		printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device %s [v4l2] (Not Working Yet!)\n",
-		       usbvision->nr, video_device_node_name(usbvision->vbi));
-	}
 	// all done
 	return 0;
 
@@ -1726,8 +1649,6 @@
 	usbvision_configure_video(usbvision);
 	mutex_unlock(&usbvision->lock);
 
-
-	usb_set_intfdata (intf, usbvision);
 	usbvision_create_sysfs(usbvision->vdev);
 
 	PDEBUG(DBG_PROBE, "success");
@@ -1745,7 +1666,7 @@
  */
 static void __devexit usbvision_disconnect(struct usb_interface *intf)
 {
-	struct usb_usbvision *usbvision = usb_get_intfdata(intf);
+	struct usb_usbvision *usbvision = to_usbvision(usb_get_intfdata(intf));
 
 	PDEBUG(DBG_PROBE, "");
 
@@ -1754,7 +1675,6 @@
 			"%s: usb_get_intfdata() failed\n", __func__);
 		return;
 	}
-	usb_set_intfdata (intf, NULL);
 
 	mutex_lock(&usbvision->lock);
 
diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h
index f8d7458..d1b3cc0 100644
--- a/drivers/media/video/usbvision/usbvision.h
+++ b/drivers/media/video/usbvision/usbvision.h
@@ -360,7 +360,6 @@
 	struct v4l2_device v4l2_dev;
 	struct video_device *vdev;         				/* Video Device */
 	struct video_device *rdev;               			/* Radio Device */
-	struct video_device *vbi; 					/* VBI Device   */
 
 	/* i2c Declaration Section*/
 	struct i2c_adapter i2c_adap;
@@ -463,6 +462,11 @@
 	int ComprBlockTypes[4];
 };
 
+static inline struct usb_usbvision *to_usbvision(struct v4l2_device *v4l2_dev)
+{
+	return container_of(v4l2_dev, struct usb_usbvision, v4l2_dev);
+}
+
 #define call_all(usbvision, o, f, args...) \
 	v4l2_device_call_all(&usbvision->v4l2_dev, 0, o, f, ##args)
 
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index 6d3850b..aa0720a 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -217,8 +217,7 @@
 		.selector	= UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL,
 		.index		= 4,
 		.size		= 1,
-		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
-				| UVC_CONTROL_RESTORE,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_RESTORE,
 	},
 	{
 		.entity		= UVC_GUID_UVC_CAMERA,
@@ -233,8 +232,9 @@
 		.selector	= UVC_CT_FOCUS_RELATIVE_CONTROL,
 		.index		= 6,
 		.size		= 2,
-		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-				| UVC_CONTROL_AUTO_UPDATE,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN
+				| UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES
+				| UVC_CONTROL_GET_DEF | UVC_CONTROL_AUTO_UPDATE,
 	},
 	{
 		.entity		= UVC_GUID_UVC_CAMERA,
@@ -249,8 +249,7 @@
 		.selector	= UVC_CT_IRIS_RELATIVE_CONTROL,
 		.index		= 8,
 		.size		= 1,
-		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
-				| UVC_CONTROL_AUTO_UPDATE,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_AUTO_UPDATE,
 	},
 	{
 		.entity		= UVC_GUID_UVC_CAMERA,
@@ -265,8 +264,9 @@
 		.selector	= UVC_CT_ZOOM_RELATIVE_CONTROL,
 		.index		= 10,
 		.size		= 3,
-		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-				| UVC_CONTROL_AUTO_UPDATE,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN
+				| UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES
+				| UVC_CONTROL_GET_DEF | UVC_CONTROL_AUTO_UPDATE,
 	},
 	{
 		.entity		= UVC_GUID_UVC_CAMERA,
@@ -281,8 +281,9 @@
 		.selector	= UVC_CT_PANTILT_RELATIVE_CONTROL,
 		.index		= 12,
 		.size		= 4,
-		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-				| UVC_CONTROL_AUTO_UPDATE,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN
+				| UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES
+				| UVC_CONTROL_GET_DEF | UVC_CONTROL_AUTO_UPDATE,
 	},
 	{
 		.entity		= UVC_GUID_UVC_CAMERA,
@@ -297,8 +298,9 @@
 		.selector	= UVC_CT_ROLL_RELATIVE_CONTROL,
 		.index		= 14,
 		.size		= 2,
-		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-				| UVC_CONTROL_AUTO_UPDATE,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN
+				| UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES
+				| UVC_CONTROL_GET_DEF | UVC_CONTROL_AUTO_UPDATE,
 	},
 	{
 		.entity		= UVC_GUID_UVC_CAMERA,
@@ -562,6 +564,26 @@
 		.data_type	= UVC_CTRL_DATA_TYPE_BOOLEAN,
 	},
 	{
+		.id		= V4L2_CID_IRIS_ABSOLUTE,
+		.name		= "Iris, Absolute",
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= UVC_CT_IRIS_ABSOLUTE_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+	},
+	{
+		.id		= V4L2_CID_IRIS_RELATIVE,
+		.name		= "Iris, Relative",
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= UVC_CT_IRIS_RELATIVE_CONTROL,
+		.size		= 8,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_SIGNED,
+	},
+	{
 		.id		= V4L2_CID_ZOOM_ABSOLUTE,
 		.name		= "Zoom, Absolute",
 		.entity		= UVC_GUID_UVC_CAMERA,
@@ -822,6 +844,8 @@
 	strlcpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name);
 	v4l2_ctrl->flags = 0;
 
+	if (!(ctrl->info->flags & UVC_CONTROL_GET_CUR))
+		v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
 	if (!(ctrl->info->flags & UVC_CONTROL_SET_CUR))
 		v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 
@@ -1047,6 +1071,8 @@
 				   uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
 		step = mapping->get(mapping, UVC_GET_RES,
 				    uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+		if (step == 0)
+			step = 1;
 
 		xctrl->value = min + (xctrl->value - min + step/2) / step * step;
 		xctrl->value = clamp(xctrl->value, min, max);
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index 86ff8c1..838b56f 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -91,11 +91,16 @@
 		.fcc		= V4L2_PIX_FMT_UYVY,
 	},
 	{
-		.name		= "Greyscale",
+		.name		= "Greyscale (8-bit)",
 		.guid		= UVC_GUID_FORMAT_Y800,
 		.fcc		= V4L2_PIX_FMT_GREY,
 	},
 	{
+		.name		= "Greyscale (16-bit)",
+		.guid		= UVC_GUID_FORMAT_Y16,
+		.fcc		= V4L2_PIX_FMT_Y16,
+	},
+	{
 		.name		= "RGB Bayer",
 		.guid		= UVC_GUID_FORMAT_BY8,
 		.fcc		= V4L2_PIX_FMT_SBGGR8,
@@ -2105,6 +2110,15 @@
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_QUIRK_STREAM_NO_FID },
+	/* Syntek (Packard Bell EasyNote MX52 */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x174f,
+	  .idProduct		= 0x8a12,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_STREAM_NO_FID },
 	/* Syntek (Asus F9SG) */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2169,6 +2183,15 @@
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Arkmicro unbranded */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x18ec,
+	  .idProduct		= 0x3290,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_DEF },
 	/* Bodelin ProScopeHR */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_DEV_HI
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c
index 4a925a3..133c78d1 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -388,8 +388,12 @@
 
 	poll_wait(file, &buf->wait, wait);
 	if (buf->state == UVC_BUF_STATE_DONE ||
-	    buf->state == UVC_BUF_STATE_ERROR)
-		mask |= POLLIN | POLLRDNORM;
+	    buf->state == UVC_BUF_STATE_ERROR) {
+		if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			mask |= POLLIN | POLLRDNORM;
+		else
+			mask |= POLLOUT | POLLWRNORM;
+	}
 
 done:
 	mutex_unlock(&queue->mutex);
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index 2bba059..d1f8840 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -131,11 +131,13 @@
 #define UVC_GUID_FORMAT_Y800 \
 	{ 'Y',  '8',  '0',  '0', 0x00, 0x00, 0x10, 0x00, \
 	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y16 \
+	{ 'Y',  '1',  '6',  ' ', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
 #define UVC_GUID_FORMAT_BY8 \
 	{ 'B',  'Y',  '8',  ' ', 0x00, 0x00, 0x10, 0x00, \
 	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
 
-
 /* ------------------------------------------------------------------------
  * Driver specific constants.
  */
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 36b5cb8..4e53b0b 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -51,6 +51,9 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/i2c.h>
+#if defined(CONFIG_SPI)
+#include <linux/spi/spi.h>
+#endif
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -85,10 +88,9 @@
 			      val == V4L2_PRIORITY_INTERACTIVE  || \
 			      val == V4L2_PRIORITY_RECORD)
 
-int v4l2_prio_init(struct v4l2_prio_state *global)
+void v4l2_prio_init(struct v4l2_prio_state *global)
 {
-	memset(global,0,sizeof(*global));
-	return 0;
+	memset(global, 0, sizeof(*global));
 }
 EXPORT_SYMBOL(v4l2_prio_init);
 
@@ -108,17 +110,16 @@
 }
 EXPORT_SYMBOL(v4l2_prio_change);
 
-int v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local)
+void v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local)
 {
-	return v4l2_prio_change(global,local,V4L2_PRIORITY_DEFAULT);
+	v4l2_prio_change(global, local, V4L2_PRIORITY_DEFAULT);
 }
 EXPORT_SYMBOL(v4l2_prio_open);
 
-int v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority *local)
+void v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority local)
 {
-	if (V4L2_PRIO_VALID(*local))
-		atomic_dec(&global->prios[*local]);
-	return 0;
+	if (V4L2_PRIO_VALID(local))
+		atomic_dec(&global->prios[local]);
 }
 EXPORT_SYMBOL(v4l2_prio_close);
 
@@ -134,11 +135,9 @@
 }
 EXPORT_SYMBOL(v4l2_prio_max);
 
-int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local)
+int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority local)
 {
-	if (*local < v4l2_prio_max(global))
-		return -EBUSY;
-	return 0;
+	return (local < v4l2_prio_max(global)) ? -EBUSY : 0;
 }
 EXPORT_SYMBOL(v4l2_prio_check);
 
@@ -340,6 +339,13 @@
 		"None",
 		"Black & White",
 		"Sepia",
+		"Negative",
+		"Emboss",
+		"Sketch",
+		"Sky blue",
+		"Grass green",
+		"Skin whiten",
+		"Vivid",
 		NULL
 	};
 	static const char *tune_preemphasis[] = {
@@ -429,10 +435,13 @@
 	case V4L2_CID_SHARPNESS:		return "Sharpness";
 	case V4L2_CID_BACKLIGHT_COMPENSATION:	return "Backlight Compensation";
 	case V4L2_CID_CHROMA_AGC:		return "Chroma AGC";
+	case V4L2_CID_CHROMA_GAIN:		return "Chroma Gain";
 	case V4L2_CID_COLOR_KILLER:		return "Color Killer";
 	case V4L2_CID_COLORFX:			return "Color Effects";
+	case V4L2_CID_AUTOBRIGHTNESS:		return "Brightness, Automatic";
+	case V4L2_CID_BAND_STOP_FILTER:		return "Band-Stop Filter";
 	case V4L2_CID_ROTATE:			return "Rotate";
-	case V4L2_CID_BG_COLOR:			return "Background color";
+	case V4L2_CID_BG_COLOR:			return "Background Color";
 
 	/* MPEG controls */
 	case V4L2_CID_MPEG_CLASS: 		return "MPEG Encoder Controls";
@@ -483,6 +492,8 @@
 	case V4L2_CID_FOCUS_ABSOLUTE:		return "Focus, Absolute";
 	case V4L2_CID_FOCUS_RELATIVE:		return "Focus, Relative";
 	case V4L2_CID_FOCUS_AUTO:		return "Focus, Automatic";
+	case V4L2_CID_IRIS_ABSOLUTE:		return "Iris, Absolute";
+	case V4L2_CID_IRIS_RELATIVE:		return "Iris, Relative";
 	case V4L2_CID_ZOOM_ABSOLUTE:		return "Zoom, Absolute";
 	case V4L2_CID_ZOOM_RELATIVE:		return "Zoom, Relative";
 	case V4L2_CID_ZOOM_CONTINUOUS:		return "Zoom, Continuous";
@@ -620,6 +631,7 @@
 	case V4L2_CID_BLUE_BALANCE:
 	case V4L2_CID_GAMMA:
 	case V4L2_CID_SHARPNESS:
+	case V4L2_CID_CHROMA_GAIN:
 	case V4L2_CID_RDS_TX_DEVIATION:
 	case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME:
 	case V4L2_CID_AUDIO_LIMITER_DEVIATION:
@@ -636,6 +648,7 @@
 	case V4L2_CID_PAN_RELATIVE:
 	case V4L2_CID_TILT_RELATIVE:
 	case V4L2_CID_FOCUS_RELATIVE:
+	case V4L2_CID_IRIS_RELATIVE:
 	case V4L2_CID_ZOOM_RELATIVE:
 		qctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
 		break;
@@ -951,6 +964,66 @@
 
 #endif /* defined(CONFIG_I2C) */
 
+#if defined(CONFIG_SPI)
+
+/* Load a spi sub-device. */
+
+void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi,
+		const struct v4l2_subdev_ops *ops)
+{
+	v4l2_subdev_init(sd, ops);
+	sd->flags |= V4L2_SUBDEV_FL_IS_SPI;
+	/* the owner is the same as the spi_device's driver owner */
+	sd->owner = spi->dev.driver->owner;
+	/* spi_device and v4l2_subdev point to one another */
+	v4l2_set_subdevdata(sd, spi);
+	spi_set_drvdata(spi, sd);
+	/* initialize name */
+	strlcpy(sd->name, spi->dev.driver->name, sizeof(sd->name));
+}
+EXPORT_SYMBOL_GPL(v4l2_spi_subdev_init);
+
+struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev,
+		struct spi_master *master, struct spi_board_info *info)
+{
+	struct v4l2_subdev *sd = NULL;
+	struct spi_device *spi = NULL;
+
+	BUG_ON(!v4l2_dev);
+
+	if (info->modalias)
+		request_module(info->modalias);
+
+	spi = spi_new_device(master, info);
+
+	if (spi == NULL || spi->dev.driver == NULL)
+		goto error;
+
+	if (!try_module_get(spi->dev.driver->owner))
+		goto error;
+
+	sd = spi_get_drvdata(spi);
+
+	/* Register with the v4l2_device which increases the module's
+	   use count as well. */
+	if (v4l2_device_register_subdev(v4l2_dev, sd))
+		sd = NULL;
+
+	/* Decrease the module use count to match the first try_module_get. */
+	module_put(spi->dev.driver->owner);
+
+error:
+	/* If we have a client but no subdev, then something went wrong and
+	   we must unregister the client. */
+	if (spi && sd == NULL)
+		spi_unregister_device(spi);
+
+	return sd;
+}
+EXPORT_SYMBOL_GPL(v4l2_spi_new_subdev);
+
+#endif /* defined(CONFIG_SPI) */
+
 /* Clamp x to be between min and max, aligned to a multiple of 2^align.  min
  * and max don't have to be aligned, but there must be at least one valid
  * value.  E.g., min=17,max=31,align=4 is not allowed as there are no multiples
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index f77f84b..9004a5f 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -1086,6 +1086,9 @@
 	case VIDIOC_QUERY_DV_PRESET:
 	case VIDIOC_S_DV_TIMINGS:
 	case VIDIOC_G_DV_TIMINGS:
+	case VIDIOC_DQEVENT:
+	case VIDIOC_SUBSCRIBE_EVENT:
+	case VIDIOC_UNSUBSCRIBE_EVENT:
 		ret = do_video_ioctl(file, cmd, arg);
 		break;
 
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 7090699..0ca7ec9 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -421,6 +421,10 @@
 	if (!vdev->release)
 		return -EINVAL;
 
+	/* v4l2_fh support */
+	spin_lock_init(&vdev->fh_lock);
+	INIT_LIST_HEAD(&vdev->fh_list);
+
 	/* Part 1: check device type */
 	switch (type) {
 	case VFL_TYPE_GRABBER:
@@ -596,9 +600,7 @@
 	if (!vdev || !video_is_registered(vdev))
 		return;
 
-	mutex_lock(&videodev_lock);
 	clear_bit(V4L2_FL_REGISTERED, &vdev->flags);
-	mutex_unlock(&videodev_lock);
 	device_unregister(&vdev->dev);
 }
 EXPORT_SYMBOL(video_unregister_device);
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
index 0d06e7c..5a7dc4a 100644
--- a/drivers/media/video/v4l2-device.c
+++ b/drivers/media/video/v4l2-device.c
@@ -21,6 +21,9 @@
 #include <linux/types.h>
 #include <linux/ioctl.h>
 #include <linux/i2c.h>
+#if defined(CONFIG_SPI)
+#include <linux/spi/spi.h>
+#endif
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 
@@ -97,6 +100,14 @@
 				i2c_unregister_device(client);
 		}
 #endif
+#if defined(CONFIG_SPI)
+		if (sd->flags & V4L2_SUBDEV_FL_IS_SPI) {
+			struct spi_device *spi = v4l2_get_subdevdata(sd);
+
+			if (spi)
+				spi_unregister_device(spi);
+		}
+#endif
 	}
 }
 EXPORT_SYMBOL_GPL(v4l2_device_unregister);
diff --git a/drivers/media/video/v4l2-event.c b/drivers/media/video/v4l2-event.c
new file mode 100644
index 0000000..de74ce0
--- /dev/null
+++ b/drivers/media/video/v4l2-event.c
@@ -0,0 +1,292 @@
+/*
+ * v4l2-event.c
+ *
+ * V4L2 events.
+ *
+ * Copyright (C) 2009--2010 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+int v4l2_event_init(struct v4l2_fh *fh)
+{
+	fh->events = kzalloc(sizeof(*fh->events), GFP_KERNEL);
+	if (fh->events == NULL)
+		return -ENOMEM;
+
+	init_waitqueue_head(&fh->events->wait);
+
+	INIT_LIST_HEAD(&fh->events->free);
+	INIT_LIST_HEAD(&fh->events->available);
+	INIT_LIST_HEAD(&fh->events->subscribed);
+
+	fh->events->sequence = -1;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_init);
+
+int v4l2_event_alloc(struct v4l2_fh *fh, unsigned int n)
+{
+	struct v4l2_events *events = fh->events;
+	unsigned long flags;
+
+	if (!events) {
+		WARN_ON(1);
+		return -ENOMEM;
+	}
+
+	while (events->nallocated < n) {
+		struct v4l2_kevent *kev;
+
+		kev = kzalloc(sizeof(*kev), GFP_KERNEL);
+		if (kev == NULL)
+			return -ENOMEM;
+
+		spin_lock_irqsave(&fh->vdev->fh_lock, flags);
+		list_add_tail(&kev->list, &events->free);
+		events->nallocated++;
+		spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_alloc);
+
+#define list_kfree(list, type, member)				\
+	while (!list_empty(list)) {				\
+		type *hi;					\
+		hi = list_first_entry(list, type, member);	\
+		list_del(&hi->member);				\
+		kfree(hi);					\
+	}
+
+void v4l2_event_free(struct v4l2_fh *fh)
+{
+	struct v4l2_events *events = fh->events;
+
+	if (!events)
+		return;
+
+	list_kfree(&events->free, struct v4l2_kevent, list);
+	list_kfree(&events->available, struct v4l2_kevent, list);
+	list_kfree(&events->subscribed, struct v4l2_subscribed_event, list);
+
+	kfree(events);
+	fh->events = NULL;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_free);
+
+static int __v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event)
+{
+	struct v4l2_events *events = fh->events;
+	struct v4l2_kevent *kev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&fh->vdev->fh_lock, flags);
+
+	if (list_empty(&events->available)) {
+		spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
+		return -ENOENT;
+	}
+
+	WARN_ON(events->navailable == 0);
+
+	kev = list_first_entry(&events->available, struct v4l2_kevent, list);
+	list_move(&kev->list, &events->free);
+	events->navailable--;
+
+	kev->event.pending = events->navailable;
+	*event = kev->event;
+
+	spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
+
+	return 0;
+}
+
+int v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event,
+		       int nonblocking)
+{
+	struct v4l2_events *events = fh->events;
+	int ret;
+
+	if (nonblocking)
+		return __v4l2_event_dequeue(fh, event);
+
+	do {
+		ret = wait_event_interruptible(events->wait,
+					       events->navailable != 0);
+		if (ret < 0)
+			return ret;
+
+		ret = __v4l2_event_dequeue(fh, event);
+	} while (ret == -ENOENT);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_dequeue);
+
+/* Caller must hold fh->event->lock! */
+static struct v4l2_subscribed_event *v4l2_event_subscribed(
+	struct v4l2_fh *fh, u32 type)
+{
+	struct v4l2_events *events = fh->events;
+	struct v4l2_subscribed_event *sev;
+
+	assert_spin_locked(&fh->vdev->fh_lock);
+
+	list_for_each_entry(sev, &events->subscribed, list) {
+		if (sev->type == type)
+			return sev;
+	}
+
+	return NULL;
+}
+
+void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev)
+{
+	struct v4l2_fh *fh;
+	unsigned long flags;
+	struct timespec timestamp;
+
+	ktime_get_ts(&timestamp);
+
+	spin_lock_irqsave(&vdev->fh_lock, flags);
+
+	list_for_each_entry(fh, &vdev->fh_list, list) {
+		struct v4l2_events *events = fh->events;
+		struct v4l2_kevent *kev;
+
+		/* Are we subscribed? */
+		if (!v4l2_event_subscribed(fh, ev->type))
+			continue;
+
+		/* Increase event sequence number on fh. */
+		events->sequence++;
+
+		/* Do we have any free events? */
+		if (list_empty(&events->free))
+			continue;
+
+		/* Take one and fill it. */
+		kev = list_first_entry(&events->free, struct v4l2_kevent, list);
+		kev->event.type = ev->type;
+		kev->event.u = ev->u;
+		kev->event.timestamp = timestamp;
+		kev->event.sequence = events->sequence;
+		list_move_tail(&kev->list, &events->available);
+
+		events->navailable++;
+
+		wake_up_all(&events->wait);
+	}
+
+	spin_unlock_irqrestore(&vdev->fh_lock, flags);
+}
+EXPORT_SYMBOL_GPL(v4l2_event_queue);
+
+int v4l2_event_pending(struct v4l2_fh *fh)
+{
+	return fh->events->navailable;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_pending);
+
+int v4l2_event_subscribe(struct v4l2_fh *fh,
+			 struct v4l2_event_subscription *sub)
+{
+	struct v4l2_events *events = fh->events;
+	struct v4l2_subscribed_event *sev;
+	unsigned long flags;
+
+	if (fh->events == NULL) {
+		WARN_ON(1);
+		return -ENOMEM;
+	}
+
+	sev = kmalloc(sizeof(*sev), GFP_KERNEL);
+	if (!sev)
+		return -ENOMEM;
+
+	spin_lock_irqsave(&fh->vdev->fh_lock, flags);
+
+	if (v4l2_event_subscribed(fh, sub->type) == NULL) {
+		INIT_LIST_HEAD(&sev->list);
+		sev->type = sub->type;
+
+		list_add(&sev->list, &events->subscribed);
+		sev = NULL;
+	}
+
+	spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
+
+	kfree(sev);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_subscribe);
+
+static void v4l2_event_unsubscribe_all(struct v4l2_fh *fh)
+{
+	struct v4l2_events *events = fh->events;
+	struct v4l2_subscribed_event *sev;
+	unsigned long flags;
+
+	do {
+		sev = NULL;
+
+		spin_lock_irqsave(&fh->vdev->fh_lock, flags);
+		if (!list_empty(&events->subscribed)) {
+			sev = list_first_entry(&events->subscribed,
+				       struct v4l2_subscribed_event, list);
+			list_del(&sev->list);
+		}
+		spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
+		kfree(sev);
+	} while (sev);
+}
+
+int v4l2_event_unsubscribe(struct v4l2_fh *fh,
+			   struct v4l2_event_subscription *sub)
+{
+	struct v4l2_subscribed_event *sev;
+	unsigned long flags;
+
+	if (sub->type == V4L2_EVENT_ALL) {
+		v4l2_event_unsubscribe_all(fh);
+		return 0;
+	}
+
+	spin_lock_irqsave(&fh->vdev->fh_lock, flags);
+
+	sev = v4l2_event_subscribed(fh, sub->type);
+	if (sev != NULL)
+		list_del(&sev->list);
+
+	spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
+
+	kfree(sev);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_unsubscribe);
diff --git a/drivers/media/video/v4l2-fh.c b/drivers/media/video/v4l2-fh.c
new file mode 100644
index 0000000..d78f184
--- /dev/null
+++ b/drivers/media/video/v4l2-fh.c
@@ -0,0 +1,79 @@
+/*
+ * v4l2-fh.c
+ *
+ * V4L2 file handles.
+ *
+ * Copyright (C) 2009--2010 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/bitops.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+
+int v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev)
+{
+	fh->vdev = vdev;
+	INIT_LIST_HEAD(&fh->list);
+	set_bit(V4L2_FL_USES_V4L2_FH, &fh->vdev->flags);
+
+	/*
+	 * fh->events only needs to be initialized if the driver
+	 * supports the VIDIOC_SUBSCRIBE_EVENT ioctl.
+	 */
+	if (vdev->ioctl_ops && vdev->ioctl_ops->vidioc_subscribe_event)
+		return v4l2_event_init(fh);
+
+	fh->events = NULL;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_fh_init);
+
+void v4l2_fh_add(struct v4l2_fh *fh)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&fh->vdev->fh_lock, flags);
+	list_add(&fh->list, &fh->vdev->fh_list);
+	spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
+}
+EXPORT_SYMBOL_GPL(v4l2_fh_add);
+
+void v4l2_fh_del(struct v4l2_fh *fh)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&fh->vdev->fh_lock, flags);
+	list_del_init(&fh->list);
+	spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
+}
+EXPORT_SYMBOL_GPL(v4l2_fh_del);
+
+void v4l2_fh_exit(struct v4l2_fh *fh)
+{
+	if (fh->vdev == NULL)
+		return;
+
+	fh->vdev = NULL;
+
+	v4l2_event_free(fh);
+}
+EXPORT_SYMBOL_GPL(v4l2_fh_exit);
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 7d59c10..0eeceae 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -26,6 +26,8 @@
 #endif
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
 #include <media/v4l2-chip-ident.h>
 
 #define dbgarg(cmd, fmt, arg...) \
@@ -291,6 +293,9 @@
 	[_IOC_NR(VIDIOC_QUERY_DV_PRESET)]  = "VIDIOC_QUERY_DV_PRESET",
 	[_IOC_NR(VIDIOC_S_DV_TIMINGS)]     = "VIDIOC_S_DV_TIMINGS",
 	[_IOC_NR(VIDIOC_G_DV_TIMINGS)]     = "VIDIOC_G_DV_TIMINGS",
+	[_IOC_NR(VIDIOC_DQEVENT)]	   = "VIDIOC_DQEVENT",
+	[_IOC_NR(VIDIOC_SUBSCRIBE_EVENT)]  = "VIDIOC_SUBSCRIBE_EVENT",
+	[_IOC_NR(VIDIOC_UNSUBSCRIBE_EVENT)] = "VIDIOC_UNSUBSCRIBE_EVENT",
 };
 #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
 
@@ -610,17 +615,33 @@
 	void *fh = file->private_data;
 	long ret = -EINVAL;
 
+	if (ops == NULL) {
+		printk(KERN_WARNING "videodev: \"%s\" has no ioctl_ops.\n",
+				vfd->name);
+		return -EINVAL;
+	}
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+	/********************************************************
+	 All other V4L1 calls are handled by v4l1_compat module.
+	 Those calls will be translated into V4L2 calls, and
+	 __video_do_ioctl will be called again, with one or more
+	 V4L2 ioctls.
+	 ********************************************************/
+	if (_IOC_TYPE(cmd) == 'v' && cmd != VIDIOCGMBUF &&
+				_IOC_NR(cmd) < BASE_VIDIOCPRIVATE) {
+		return v4l_compat_translate_ioctl(file, cmd, arg,
+						__video_do_ioctl);
+	}
+#endif
+
 	if ((vfd->debug & V4L2_DEBUG_IOCTL) &&
 				!(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) {
 		v4l_print_ioctl(vfd->name, cmd);
 		printk(KERN_CONT "\n");
 	}
 
-	if (ops == NULL) {
-		printk(KERN_WARNING "videodev: \"%s\" has no ioctl_ops.\n",
-				vfd->name);
-		return -EINVAL;
-	}
+	switch (cmd) {
 
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
 	/***********************************************************
@@ -630,31 +651,21 @@
 	 ***********************************************************/
 
 	/* --- streaming capture ------------------------------------- */
-	if (cmd == VIDIOCGMBUF) {
+	case VIDIOCGMBUF:
+	{
 		struct video_mbuf *p = arg;
 
 		if (!ops->vidiocgmbuf)
-			return ret;
+			break;
 		ret = ops->vidiocgmbuf(file, fh, p);
 		if (!ret)
 			dbgarg(cmd, "size=%d, frames=%d, offsets=0x%08lx\n",
 						p->size, p->frames,
 						(unsigned long)p->offsets);
-		return ret;
+		break;
 	}
-
-	/********************************************************
-	 All other V4L1 calls are handled by v4l1_compat module.
-	 Those calls will be translated into V4L2 calls, and
-	 __video_do_ioctl will be called again, with one or more
-	 V4L2 ioctls.
-	 ********************************************************/
-	if (_IOC_TYPE(cmd) == 'v' && _IOC_NR(cmd) < BASE_VIDIOCPRIVATE)
-		return v4l_compat_translate_ioctl(file, cmd, arg,
-						__video_do_ioctl);
 #endif
 
-	switch (cmd) {
 	/* --- capabilities ------------------------------------------ */
 	case VIDIOC_QUERYCAP:
 	{
@@ -1072,7 +1083,7 @@
 				id &= ~curr_id;
 		}
 		if (i <= index)
-			return -EINVAL;
+			break;
 
 		v4l2_video_std_construct(p, curr_id, descr);
 
@@ -1597,7 +1608,7 @@
 			v4l2_std_id std = vfd->current_norm;
 
 			if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-				return -EINVAL;
+				break;
 
 			ret = 0;
 			if (ops->vidioc_g_std)
@@ -1942,7 +1953,55 @@
 		}
 		break;
 	}
+	case VIDIOC_DQEVENT:
+	{
+		struct v4l2_event *ev = arg;
 
+		if (!ops->vidioc_subscribe_event)
+			break;
+
+		ret = v4l2_event_dequeue(fh, ev, file->f_flags & O_NONBLOCK);
+		if (ret < 0) {
+			dbgarg(cmd, "no pending events?");
+			break;
+		}
+		dbgarg(cmd,
+		       "pending=%d, type=0x%8.8x, sequence=%d, "
+		       "timestamp=%lu.%9.9lu ",
+		       ev->pending, ev->type, ev->sequence,
+		       ev->timestamp.tv_sec, ev->timestamp.tv_nsec);
+		break;
+	}
+	case VIDIOC_SUBSCRIBE_EVENT:
+	{
+		struct v4l2_event_subscription *sub = arg;
+
+		if (!ops->vidioc_subscribe_event)
+			break;
+
+		ret = ops->vidioc_subscribe_event(fh, sub);
+		if (ret < 0) {
+			dbgarg(cmd, "failed, ret=%ld", ret);
+			break;
+		}
+		dbgarg(cmd, "type=0x%8.8x", sub->type);
+		break;
+	}
+	case VIDIOC_UNSUBSCRIBE_EVENT:
+	{
+		struct v4l2_event_subscription *sub = arg;
+
+		if (!ops->vidioc_unsubscribe_event)
+			break;
+
+		ret = ops->vidioc_unsubscribe_event(fh, sub);
+		if (ret < 0) {
+			dbgarg(cmd, "failed, ret=%ld", ret);
+			break;
+		}
+		dbgarg(cmd, "type=0x%8.8x", sub->type);
+		break;
+	}
 	default:
 	{
 		if (!ops->vidioc_default)
@@ -2006,7 +2065,7 @@
 {
 	char	sbuf[128];
 	void    *mbuf = NULL;
-	void	*parg = NULL;
+	void	*parg = (void *)arg;
 	long	err  = -EINVAL;
 	int     is_ext_ctrl;
 	size_t  ctrls_size = 0;
diff --git a/drivers/media/video/v4l2-mem2mem.c b/drivers/media/video/v4l2-mem2mem.c
new file mode 100644
index 0000000..f45f940
--- /dev/null
+++ b/drivers/media/video/v4l2-mem2mem.c
@@ -0,0 +1,633 @@
+/*
+ * Memory-to-memory device framework for Video for Linux 2 and videobuf.
+ *
+ * Helper functions for devices that use videobuf buffers for both their
+ * source and destination.
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <p.osciak@samsung.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <media/videobuf-core.h>
+#include <media/v4l2-mem2mem.h>
+
+MODULE_DESCRIPTION("Mem to mem device framework for videobuf");
+MODULE_AUTHOR("Pawel Osciak, <p.osciak@samsung.com>");
+MODULE_LICENSE("GPL");
+
+static bool debug;
+module_param(debug, bool, 0644);
+
+#define dprintk(fmt, arg...)						\
+	do {								\
+		if (debug)						\
+			printk(KERN_DEBUG "%s: " fmt, __func__, ## arg);\
+	} while (0)
+
+
+/* Instance is already queued on the job_queue */
+#define TRANS_QUEUED		(1 << 0)
+/* Instance is currently running in hardware */
+#define TRANS_RUNNING		(1 << 1)
+
+
+/* Offset base for buffers on the destination queue - used to distinguish
+ * between source and destination buffers when mmapping - they receive the same
+ * offsets but for different queues */
+#define DST_QUEUE_OFF_BASE	(1 << 30)
+
+
+/**
+ * struct v4l2_m2m_dev - per-device context
+ * @curr_ctx:		currently running instance
+ * @job_queue:		instances queued to run
+ * @job_spinlock:	protects job_queue
+ * @m2m_ops:		driver callbacks
+ */
+struct v4l2_m2m_dev {
+	struct v4l2_m2m_ctx	*curr_ctx;
+
+	struct list_head	job_queue;
+	spinlock_t		job_spinlock;
+
+	struct v4l2_m2m_ops	*m2m_ops;
+};
+
+static struct v4l2_m2m_queue_ctx *get_queue_ctx(struct v4l2_m2m_ctx *m2m_ctx,
+						enum v4l2_buf_type type)
+{
+	switch (type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return &m2m_ctx->cap_q_ctx;
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		return &m2m_ctx->out_q_ctx;
+	default:
+		printk(KERN_ERR "Invalid buffer type\n");
+		return NULL;
+	}
+}
+
+/**
+ * v4l2_m2m_get_vq() - return videobuf_queue for the given type
+ */
+struct videobuf_queue *v4l2_m2m_get_vq(struct v4l2_m2m_ctx *m2m_ctx,
+				       enum v4l2_buf_type type)
+{
+	struct v4l2_m2m_queue_ctx *q_ctx;
+
+	q_ctx = get_queue_ctx(m2m_ctx, type);
+	if (!q_ctx)
+		return NULL;
+
+	return &q_ctx->q;
+}
+EXPORT_SYMBOL(v4l2_m2m_get_vq);
+
+/**
+ * v4l2_m2m_next_buf() - return next buffer from the list of ready buffers
+ */
+void *v4l2_m2m_next_buf(struct v4l2_m2m_ctx *m2m_ctx, enum v4l2_buf_type type)
+{
+	struct v4l2_m2m_queue_ctx *q_ctx;
+	struct videobuf_buffer *vb = NULL;
+	unsigned long flags;
+
+	q_ctx = get_queue_ctx(m2m_ctx, type);
+	if (!q_ctx)
+		return NULL;
+
+	spin_lock_irqsave(q_ctx->q.irqlock, flags);
+
+	if (list_empty(&q_ctx->rdy_queue))
+		goto end;
+
+	vb = list_entry(q_ctx->rdy_queue.next, struct videobuf_buffer, queue);
+	vb->state = VIDEOBUF_ACTIVE;
+
+end:
+	spin_unlock_irqrestore(q_ctx->q.irqlock, flags);
+	return vb;
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_next_buf);
+
+/**
+ * v4l2_m2m_buf_remove() - take off a buffer from the list of ready buffers and
+ * return it
+ */
+void *v4l2_m2m_buf_remove(struct v4l2_m2m_ctx *m2m_ctx, enum v4l2_buf_type type)
+{
+	struct v4l2_m2m_queue_ctx *q_ctx;
+	struct videobuf_buffer *vb = NULL;
+	unsigned long flags;
+
+	q_ctx = get_queue_ctx(m2m_ctx, type);
+	if (!q_ctx)
+		return NULL;
+
+	spin_lock_irqsave(q_ctx->q.irqlock, flags);
+	if (!list_empty(&q_ctx->rdy_queue)) {
+		vb = list_entry(q_ctx->rdy_queue.next, struct videobuf_buffer,
+				queue);
+		list_del(&vb->queue);
+		q_ctx->num_rdy--;
+	}
+	spin_unlock_irqrestore(q_ctx->q.irqlock, flags);
+
+	return vb;
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_buf_remove);
+
+/*
+ * Scheduling handlers
+ */
+
+/**
+ * v4l2_m2m_get_curr_priv() - return driver private data for the currently
+ * running instance or NULL if no instance is running
+ */
+void *v4l2_m2m_get_curr_priv(struct v4l2_m2m_dev *m2m_dev)
+{
+	unsigned long flags;
+	void *ret = NULL;
+
+	spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
+	if (m2m_dev->curr_ctx)
+		ret = m2m_dev->curr_ctx->priv;
+	spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(v4l2_m2m_get_curr_priv);
+
+/**
+ * v4l2_m2m_try_run() - select next job to perform and run it if possible
+ *
+ * Get next transaction (if present) from the waiting jobs list and run it.
+ */
+static void v4l2_m2m_try_run(struct v4l2_m2m_dev *m2m_dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
+	if (NULL != m2m_dev->curr_ctx) {
+		spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
+		dprintk("Another instance is running, won't run now\n");
+		return;
+	}
+
+	if (list_empty(&m2m_dev->job_queue)) {
+		spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
+		dprintk("No job pending\n");
+		return;
+	}
+
+	m2m_dev->curr_ctx = list_entry(m2m_dev->job_queue.next,
+				   struct v4l2_m2m_ctx, queue);
+	m2m_dev->curr_ctx->job_flags |= TRANS_RUNNING;
+	spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
+
+	m2m_dev->m2m_ops->device_run(m2m_dev->curr_ctx->priv);
+}
+
+/**
+ * v4l2_m2m_try_schedule() - check whether an instance is ready to be added to
+ * the pending job queue and add it if so.
+ * @m2m_ctx:	m2m context assigned to the instance to be checked
+ *
+ * There are three basic requirements an instance has to meet to be able to run:
+ * 1) at least one source buffer has to be queued,
+ * 2) at least one destination buffer has to be queued,
+ * 3) streaming has to be on.
+ *
+ * There may also be additional, custom requirements. In such case the driver
+ * should supply a custom callback (job_ready in v4l2_m2m_ops) that should
+ * return 1 if the instance is ready.
+ * An example of the above could be an instance that requires more than one
+ * src/dst buffer per transaction.
+ */
+static void v4l2_m2m_try_schedule(struct v4l2_m2m_ctx *m2m_ctx)
+{
+	struct v4l2_m2m_dev *m2m_dev;
+	unsigned long flags_job, flags;
+
+	m2m_dev = m2m_ctx->m2m_dev;
+	dprintk("Trying to schedule a job for m2m_ctx: %p\n", m2m_ctx);
+
+	if (!m2m_ctx->out_q_ctx.q.streaming
+	    || !m2m_ctx->cap_q_ctx.q.streaming) {
+		dprintk("Streaming needs to be on for both queues\n");
+		return;
+	}
+
+	spin_lock_irqsave(&m2m_dev->job_spinlock, flags_job);
+	if (m2m_ctx->job_flags & TRANS_QUEUED) {
+		spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
+		dprintk("On job queue already\n");
+		return;
+	}
+
+	spin_lock_irqsave(m2m_ctx->out_q_ctx.q.irqlock, flags);
+	if (list_empty(&m2m_ctx->out_q_ctx.rdy_queue)) {
+		spin_unlock_irqrestore(m2m_ctx->out_q_ctx.q.irqlock, flags);
+		spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
+		dprintk("No input buffers available\n");
+		return;
+	}
+	if (list_empty(&m2m_ctx->cap_q_ctx.rdy_queue)) {
+		spin_unlock_irqrestore(m2m_ctx->out_q_ctx.q.irqlock, flags);
+		spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
+		dprintk("No output buffers available\n");
+		return;
+	}
+	spin_unlock_irqrestore(m2m_ctx->out_q_ctx.q.irqlock, flags);
+
+	if (m2m_dev->m2m_ops->job_ready
+		&& (!m2m_dev->m2m_ops->job_ready(m2m_ctx->priv))) {
+		spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
+		dprintk("Driver not ready\n");
+		return;
+	}
+
+	list_add_tail(&m2m_ctx->queue, &m2m_dev->job_queue);
+	m2m_ctx->job_flags |= TRANS_QUEUED;
+
+	spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
+
+	v4l2_m2m_try_run(m2m_dev);
+}
+
+/**
+ * v4l2_m2m_job_finish() - inform the framework that a job has been finished
+ * and have it clean up
+ *
+ * Called by a driver to yield back the device after it has finished with it.
+ * Should be called as soon as possible after reaching a state which allows
+ * other instances to take control of the device.
+ *
+ * This function has to be called only after device_run() callback has been
+ * called on the driver. To prevent recursion, it should not be called directly
+ * from the device_run() callback though.
+ */
+void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev,
+			 struct v4l2_m2m_ctx *m2m_ctx)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
+	if (!m2m_dev->curr_ctx || m2m_dev->curr_ctx != m2m_ctx) {
+		spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
+		dprintk("Called by an instance not currently running\n");
+		return;
+	}
+
+	list_del(&m2m_dev->curr_ctx->queue);
+	m2m_dev->curr_ctx->job_flags &= ~(TRANS_QUEUED | TRANS_RUNNING);
+	m2m_dev->curr_ctx = NULL;
+
+	spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
+
+	/* This instance might have more buffers ready, but since we do not
+	 * allow more than one job on the job_queue per instance, each has
+	 * to be scheduled separately after the previous one finishes. */
+	v4l2_m2m_try_schedule(m2m_ctx);
+	v4l2_m2m_try_run(m2m_dev);
+}
+EXPORT_SYMBOL(v4l2_m2m_job_finish);
+
+/**
+ * v4l2_m2m_reqbufs() - multi-queue-aware REQBUFS multiplexer
+ */
+int v4l2_m2m_reqbufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+		     struct v4l2_requestbuffers *reqbufs)
+{
+	struct videobuf_queue *vq;
+
+	vq = v4l2_m2m_get_vq(m2m_ctx, reqbufs->type);
+	return videobuf_reqbufs(vq, reqbufs);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_reqbufs);
+
+/**
+ * v4l2_m2m_querybuf() - multi-queue-aware QUERYBUF multiplexer
+ *
+ * See v4l2_m2m_mmap() documentation for details.
+ */
+int v4l2_m2m_querybuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+		      struct v4l2_buffer *buf)
+{
+	struct videobuf_queue *vq;
+	int ret;
+
+	vq = v4l2_m2m_get_vq(m2m_ctx, buf->type);
+	ret = videobuf_querybuf(vq, buf);
+
+	if (buf->memory == V4L2_MEMORY_MMAP
+	    && vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		buf->m.offset += DST_QUEUE_OFF_BASE;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_querybuf);
+
+/**
+ * v4l2_m2m_qbuf() - enqueue a source or destination buffer, depending on
+ * the type
+ */
+int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+		  struct v4l2_buffer *buf)
+{
+	struct videobuf_queue *vq;
+	int ret;
+
+	vq = v4l2_m2m_get_vq(m2m_ctx, buf->type);
+	ret = videobuf_qbuf(vq, buf);
+	if (!ret)
+		v4l2_m2m_try_schedule(m2m_ctx);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_qbuf);
+
+/**
+ * v4l2_m2m_dqbuf() - dequeue a source or destination buffer, depending on
+ * the type
+ */
+int v4l2_m2m_dqbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+		   struct v4l2_buffer *buf)
+{
+	struct videobuf_queue *vq;
+
+	vq = v4l2_m2m_get_vq(m2m_ctx, buf->type);
+	return videobuf_dqbuf(vq, buf, file->f_flags & O_NONBLOCK);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_dqbuf);
+
+/**
+ * v4l2_m2m_streamon() - turn on streaming for a video queue
+ */
+int v4l2_m2m_streamon(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+		      enum v4l2_buf_type type)
+{
+	struct videobuf_queue *vq;
+	int ret;
+
+	vq = v4l2_m2m_get_vq(m2m_ctx, type);
+	ret = videobuf_streamon(vq);
+	if (!ret)
+		v4l2_m2m_try_schedule(m2m_ctx);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_streamon);
+
+/**
+ * v4l2_m2m_streamoff() - turn off streaming for a video queue
+ */
+int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+		       enum v4l2_buf_type type)
+{
+	struct videobuf_queue *vq;
+
+	vq = v4l2_m2m_get_vq(m2m_ctx, type);
+	return videobuf_streamoff(vq);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_streamoff);
+
+/**
+ * v4l2_m2m_poll() - poll replacement, for destination buffers only
+ *
+ * Call from the driver's poll() function. Will poll both queues. If a buffer
+ * is available to dequeue (with dqbuf) from the source queue, this will
+ * indicate that a non-blocking write can be performed, while read will be
+ * returned in case of the destination queue.
+ */
+unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+			   struct poll_table_struct *wait)
+{
+	struct videobuf_queue *src_q, *dst_q;
+	struct videobuf_buffer *src_vb = NULL, *dst_vb = NULL;
+	unsigned int rc = 0;
+
+	src_q = v4l2_m2m_get_src_vq(m2m_ctx);
+	dst_q = v4l2_m2m_get_dst_vq(m2m_ctx);
+
+	mutex_lock(&src_q->vb_lock);
+	mutex_lock(&dst_q->vb_lock);
+
+	if (src_q->streaming && !list_empty(&src_q->stream))
+		src_vb = list_first_entry(&src_q->stream,
+					  struct videobuf_buffer, stream);
+	if (dst_q->streaming && !list_empty(&dst_q->stream))
+		dst_vb = list_first_entry(&dst_q->stream,
+					  struct videobuf_buffer, stream);
+
+	if (!src_vb && !dst_vb) {
+		rc = POLLERR;
+		goto end;
+	}
+
+	if (src_vb) {
+		poll_wait(file, &src_vb->done, wait);
+		if (src_vb->state == VIDEOBUF_DONE
+		    || src_vb->state == VIDEOBUF_ERROR)
+			rc |= POLLOUT | POLLWRNORM;
+	}
+	if (dst_vb) {
+		poll_wait(file, &dst_vb->done, wait);
+		if (dst_vb->state == VIDEOBUF_DONE
+		    || dst_vb->state == VIDEOBUF_ERROR)
+			rc |= POLLIN | POLLRDNORM;
+	}
+
+end:
+	mutex_unlock(&dst_q->vb_lock);
+	mutex_unlock(&src_q->vb_lock);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_poll);
+
+/**
+ * v4l2_m2m_mmap() - source and destination queues-aware mmap multiplexer
+ *
+ * Call from driver's mmap() function. Will handle mmap() for both queues
+ * seamlessly for videobuffer, which will receive normal per-queue offsets and
+ * proper videobuf queue pointers. The differentiation is made outside videobuf
+ * by adding a predefined offset to buffers from one of the queues and
+ * subtracting it before passing it back to videobuf. Only drivers (and
+ * thus applications) receive modified offsets.
+ */
+int v4l2_m2m_mmap(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+			 struct vm_area_struct *vma)
+{
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	struct videobuf_queue *vq;
+
+	if (offset < DST_QUEUE_OFF_BASE) {
+		vq = v4l2_m2m_get_src_vq(m2m_ctx);
+	} else {
+		vq = v4l2_m2m_get_dst_vq(m2m_ctx);
+		vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT);
+	}
+
+	return videobuf_mmap_mapper(vq, vma);
+}
+EXPORT_SYMBOL(v4l2_m2m_mmap);
+
+/**
+ * v4l2_m2m_init() - initialize per-driver m2m data
+ *
+ * Usually called from driver's probe() function.
+ */
+struct v4l2_m2m_dev *v4l2_m2m_init(struct v4l2_m2m_ops *m2m_ops)
+{
+	struct v4l2_m2m_dev *m2m_dev;
+
+	if (!m2m_ops)
+		return ERR_PTR(-EINVAL);
+
+	BUG_ON(!m2m_ops->device_run);
+	BUG_ON(!m2m_ops->job_abort);
+
+	m2m_dev = kzalloc(sizeof *m2m_dev, GFP_KERNEL);
+	if (!m2m_dev)
+		return ERR_PTR(-ENOMEM);
+
+	m2m_dev->curr_ctx = NULL;
+	m2m_dev->m2m_ops = m2m_ops;
+	INIT_LIST_HEAD(&m2m_dev->job_queue);
+	spin_lock_init(&m2m_dev->job_spinlock);
+
+	return m2m_dev;
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_init);
+
+/**
+ * v4l2_m2m_release() - cleans up and frees a m2m_dev structure
+ *
+ * Usually called from driver's remove() function.
+ */
+void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev)
+{
+	kfree(m2m_dev);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_release);
+
+/**
+ * v4l2_m2m_ctx_init() - allocate and initialize a m2m context
+ * @priv - driver's instance private data
+ * @m2m_dev - a previously initialized m2m_dev struct
+ * @vq_init - a callback for queue type-specific initialization function to be
+ * used for initializing videobuf_queues
+ *
+ * Usually called from driver's open() function.
+ */
+struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(void *priv, struct v4l2_m2m_dev *m2m_dev,
+			void (*vq_init)(void *priv, struct videobuf_queue *,
+					enum v4l2_buf_type))
+{
+	struct v4l2_m2m_ctx *m2m_ctx;
+	struct v4l2_m2m_queue_ctx *out_q_ctx, *cap_q_ctx;
+
+	if (!vq_init)
+		return ERR_PTR(-EINVAL);
+
+	m2m_ctx = kzalloc(sizeof *m2m_ctx, GFP_KERNEL);
+	if (!m2m_ctx)
+		return ERR_PTR(-ENOMEM);
+
+	m2m_ctx->priv = priv;
+	m2m_ctx->m2m_dev = m2m_dev;
+
+	out_q_ctx = get_queue_ctx(m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	cap_q_ctx = get_queue_ctx(m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+	INIT_LIST_HEAD(&out_q_ctx->rdy_queue);
+	INIT_LIST_HEAD(&cap_q_ctx->rdy_queue);
+
+	INIT_LIST_HEAD(&m2m_ctx->queue);
+
+	vq_init(priv, &out_q_ctx->q, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	vq_init(priv, &cap_q_ctx->q, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+	out_q_ctx->q.priv_data = cap_q_ctx->q.priv_data = priv;
+
+	return m2m_ctx;
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ctx_init);
+
+/**
+ * v4l2_m2m_ctx_release() - release m2m context
+ *
+ * Usually called from driver's release() function.
+ */
+void v4l2_m2m_ctx_release(struct v4l2_m2m_ctx *m2m_ctx)
+{
+	struct v4l2_m2m_dev *m2m_dev;
+	struct videobuf_buffer *vb;
+	unsigned long flags;
+
+	m2m_dev = m2m_ctx->m2m_dev;
+
+	spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
+	if (m2m_ctx->job_flags & TRANS_RUNNING) {
+		spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
+		m2m_dev->m2m_ops->job_abort(m2m_ctx->priv);
+		dprintk("m2m_ctx %p running, will wait to complete", m2m_ctx);
+		vb = v4l2_m2m_next_dst_buf(m2m_ctx);
+		BUG_ON(NULL == vb);
+		wait_event(vb->done, vb->state != VIDEOBUF_ACTIVE
+				     && vb->state != VIDEOBUF_QUEUED);
+	} else if (m2m_ctx->job_flags & TRANS_QUEUED) {
+		list_del(&m2m_ctx->queue);
+		m2m_ctx->job_flags &= ~(TRANS_QUEUED | TRANS_RUNNING);
+		spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
+		dprintk("m2m_ctx: %p had been on queue and was removed\n",
+			m2m_ctx);
+	} else {
+		/* Do nothing, was not on queue/running */
+		spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
+	}
+
+	videobuf_stop(&m2m_ctx->cap_q_ctx.q);
+	videobuf_stop(&m2m_ctx->out_q_ctx.q);
+
+	videobuf_mmap_free(&m2m_ctx->cap_q_ctx.q);
+	videobuf_mmap_free(&m2m_ctx->out_q_ctx.q);
+
+	kfree(m2m_ctx);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ctx_release);
+
+/**
+ * v4l2_m2m_buf_queue() - add a buffer to the proper ready buffers list.
+ *
+ * Call from buf_queue(), videobuf_queue_ops callback.
+ *
+ * Locking: Caller holds q->irqlock (taken by videobuf before calling buf_queue
+ * callback in the driver).
+ */
+void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, struct videobuf_queue *vq,
+			struct videobuf_buffer *vb)
+{
+	struct v4l2_m2m_queue_ctx *q_ctx;
+
+	q_ctx = get_queue_ctx(m2m_ctx, vq->type);
+	if (!q_ctx)
+		return;
+
+	list_add_tail(&vb->queue, &q_ctx->rdy_queue);
+	q_ctx->num_rdy++;
+
+	vb->state = VIDEOBUF_QUEUED;
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_buf_queue);
+
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
index bb0a1c8..7d33784 100644
--- a/drivers/media/video/videobuf-core.c
+++ b/drivers/media/video/videobuf-core.c
@@ -24,10 +24,15 @@
 #include <media/videobuf-core.h>
 
 #define MAGIC_BUFFER 0x20070728
-#define MAGIC_CHECK(is, should) do {					   \
-	if (unlikely((is) != (should))) {				   \
-	printk(KERN_ERR "magic mismatch: %x (expected %x)\n", is, should); \
-	BUG(); } } while (0)
+#define MAGIC_CHECK(is, should)						\
+	do {								\
+		if (unlikely((is) != (should))) {			\
+			printk(KERN_ERR					\
+				"magic mismatch: %x (expected %x)\n",	\
+					is, should);			\
+			BUG();						\
+		}							\
+	} while (0)
 
 static int debug;
 module_param(debug, int, 0644);
@@ -36,16 +41,18 @@
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
 MODULE_LICENSE("GPL");
 
-#define dprintk(level, fmt, arg...) do {			\
-	if (debug >= level) 					\
-	printk(KERN_DEBUG "vbuf: " fmt , ## arg); } while (0)
+#define dprintk(level, fmt, arg...)					\
+	do {								\
+		if (debug >= level)					\
+			printk(KERN_DEBUG "vbuf: " fmt, ## arg);	\
+	} while (0)
 
 /* --------------------------------------------------------------------- */
 
 #define CALL(q, f, arg...)						\
 	((q->int_ops->f) ? q->int_ops->f(arg) : 0)
 
-void *videobuf_alloc(struct videobuf_queue *q)
+struct videobuf_buffer *videobuf_alloc(struct videobuf_queue *q)
 {
 	struct videobuf_buffer *vb;
 
@@ -57,14 +64,14 @@
 	}
 
 	vb = q->int_ops->alloc(q->msize);
-
 	if (NULL != vb) {
 		init_waitqueue_head(&vb->done);
-		vb->magic     = MAGIC_BUFFER;
+		vb->magic = MAGIC_BUFFER;
 	}
 
 	return vb;
 }
+EXPORT_SYMBOL_GPL(videobuf_alloc);
 
 #define WAITON_CONDITION (vb->state != VIDEOBUF_ACTIVE &&\
 				vb->state != VIDEOBUF_QUEUED)
@@ -86,6 +93,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(videobuf_waiton);
 
 int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb,
 		    struct v4l2_framebuffer *fbuf)
@@ -95,16 +103,16 @@
 
 	return CALL(q, iolock, q, vb, fbuf);
 }
+EXPORT_SYMBOL_GPL(videobuf_iolock);
 
-void *videobuf_queue_to_vmalloc (struct videobuf_queue *q,
-			   struct videobuf_buffer *buf)
+void *videobuf_queue_to_vaddr(struct videobuf_queue *q,
+			      struct videobuf_buffer *buf)
 {
-	if (q->int_ops->vmalloc)
-		return q->int_ops->vmalloc(buf);
-	else
-		return NULL;
+	if (q->int_ops->vaddr)
+		return q->int_ops->vaddr(buf);
+	return NULL;
 }
-EXPORT_SYMBOL_GPL(videobuf_queue_to_vmalloc);
+EXPORT_SYMBOL_GPL(videobuf_queue_to_vaddr);
 
 /* --------------------------------------------------------------------- */
 
@@ -146,6 +154,7 @@
 	init_waitqueue_head(&q->wait);
 	INIT_LIST_HEAD(&q->stream);
 }
+EXPORT_SYMBOL_GPL(videobuf_queue_core_init);
 
 /* Locking: Only usage in bttv unsafe find way to remove */
 int videobuf_queue_is_busy(struct videobuf_queue *q)
@@ -184,6 +193,7 @@
 	}
 	return 0;
 }
+EXPORT_SYMBOL_GPL(videobuf_queue_is_busy);
 
 /* Locking: Caller holds q->vb_lock */
 void videobuf_queue_cancel(struct videobuf_queue *q)
@@ -216,6 +226,7 @@
 	}
 	INIT_LIST_HEAD(&q->stream);
 }
+EXPORT_SYMBOL_GPL(videobuf_queue_cancel);
 
 /* --------------------------------------------------------------------- */
 
@@ -237,6 +248,7 @@
 	}
 	return field;
 }
+EXPORT_SYMBOL_GPL(videobuf_next_field);
 
 /* Locking: Caller holds q->vb_lock */
 static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
@@ -273,8 +285,10 @@
 	case VIDEOBUF_ACTIVE:
 		b->flags |= V4L2_BUF_FLAG_QUEUED;
 		break;
-	case VIDEOBUF_DONE:
 	case VIDEOBUF_ERROR:
+		b->flags |= V4L2_BUF_FLAG_ERROR;
+		/* fall through */
+	case VIDEOBUF_DONE:
 		b->flags |= V4L2_BUF_FLAG_DONE;
 		break;
 	case VIDEOBUF_NEEDS_INIT:
@@ -298,20 +312,15 @@
 static int __videobuf_mmap_free(struct videobuf_queue *q)
 {
 	int i;
-	int rc;
 
 	if (!q)
 		return 0;
 
 	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
-
-	rc  = CALL(q, mmap_free, q);
-
-	q->is_mmapped = 0;
-
-	if (rc < 0)
-		return rc;
+	for (i = 0; i < VIDEO_MAX_FRAME; i++)
+		if (q->bufs[i] && q->bufs[i]->map)
+			return -EBUSY;
 
 	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
 		if (NULL == q->bufs[i])
@@ -321,7 +330,7 @@
 		q->bufs[i] = NULL;
 	}
 
-	return rc;
+	return 0;
 }
 
 int videobuf_mmap_free(struct videobuf_queue *q)
@@ -332,6 +341,7 @@
 	mutex_unlock(&q->vb_lock);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(videobuf_mmap_free);
 
 /* Locking: Caller holds q->vb_lock */
 int __videobuf_mmap_setup(struct videobuf_queue *q,
@@ -351,7 +361,7 @@
 	for (i = 0; i < bcount; i++) {
 		q->bufs[i] = videobuf_alloc(q);
 
-		if (q->bufs[i] == NULL)
+		if (NULL == q->bufs[i])
 			break;
 
 		q->bufs[i]->i      = i;
@@ -372,11 +382,11 @@
 	if (!i)
 		return -ENOMEM;
 
-	dprintk(1, "mmap setup: %d buffers, %d bytes each\n",
-		i, bsize);
+	dprintk(1, "mmap setup: %d buffers, %d bytes each\n", i, bsize);
 
 	return i;
 }
+EXPORT_SYMBOL_GPL(__videobuf_mmap_setup);
 
 int videobuf_mmap_setup(struct videobuf_queue *q,
 			unsigned int bcount, unsigned int bsize,
@@ -388,6 +398,7 @@
 	mutex_unlock(&q->vb_lock);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(videobuf_mmap_setup);
 
 int videobuf_reqbufs(struct videobuf_queue *q,
 		 struct v4l2_requestbuffers *req)
@@ -432,7 +443,7 @@
 	q->ops->buf_setup(q, &count, &size);
 	dprintk(1, "reqbufs: bufs=%d, size=0x%x [%u pages total]\n",
 		count, size,
-		(unsigned int)((count*PAGE_ALIGN(size))>>PAGE_SHIFT) );
+		(unsigned int)((count * PAGE_ALIGN(size)) >> PAGE_SHIFT));
 
 	retval = __videobuf_mmap_setup(q, count, size, req->memory);
 	if (retval < 0) {
@@ -447,6 +458,7 @@
 	mutex_unlock(&q->vb_lock);
 	return retval;
 }
+EXPORT_SYMBOL_GPL(videobuf_reqbufs);
 
 int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
 {
@@ -473,9 +485,9 @@
 	mutex_unlock(&q->vb_lock);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(videobuf_querybuf);
 
-int videobuf_qbuf(struct videobuf_queue *q,
-	      struct v4l2_buffer *b)
+int videobuf_qbuf(struct videobuf_queue *q, struct v4l2_buffer *b)
 {
 	struct videobuf_buffer *buf;
 	enum v4l2_field field;
@@ -534,6 +546,13 @@
 				   "but buffer addr is zero!\n");
 			goto done;
 		}
+		if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT
+		    || q->type == V4L2_BUF_TYPE_VBI_OUTPUT
+		    || q->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) {
+			buf->size = b->bytesused;
+			buf->field = b->field;
+			buf->ts = b->timestamp;
+		}
 		break;
 	case V4L2_MEMORY_USERPTR:
 		if (b->length < buf->bsize) {
@@ -567,11 +586,11 @@
 		q->ops->buf_queue(q, buf);
 		spin_unlock_irqrestore(q->irqlock, flags);
 	}
-	dprintk(1, "qbuf: succeded\n");
+	dprintk(1, "qbuf: succeeded\n");
 	retval = 0;
 	wake_up_interruptible_sync(&q->wait);
 
- done:
+done:
 	mutex_unlock(&q->vb_lock);
 
 	if (b->memory == V4L2_MEMORY_MMAP)
@@ -579,7 +598,7 @@
 
 	return retval;
 }
-
+EXPORT_SYMBOL_GPL(videobuf_qbuf);
 
 /* Locking: Caller holds q->vb_lock */
 static int stream_next_buffer_check_queue(struct videobuf_queue *q, int noblock)
@@ -624,7 +643,6 @@
 	return retval;
 }
 
-
 /* Locking: Caller holds q->vb_lock */
 static int stream_next_buffer(struct videobuf_queue *q,
 			struct videobuf_buffer **vb, int nonblocking)
@@ -647,13 +665,14 @@
 }
 
 int videobuf_dqbuf(struct videobuf_queue *q,
-	       struct v4l2_buffer *b, int nonblocking)
+		   struct v4l2_buffer *b, int nonblocking)
 {
 	struct videobuf_buffer *buf = NULL;
 	int retval;
 
 	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
+	memset(b, 0, sizeof(*b));
 	mutex_lock(&q->vb_lock);
 
 	retval = stream_next_buffer(q, &buf, nonblocking);
@@ -665,28 +684,25 @@
 	switch (buf->state) {
 	case VIDEOBUF_ERROR:
 		dprintk(1, "dqbuf: state is error\n");
-		retval = -EIO;
-		CALL(q, sync, q, buf);
-		buf->state = VIDEOBUF_IDLE;
 		break;
 	case VIDEOBUF_DONE:
 		dprintk(1, "dqbuf: state is done\n");
-		CALL(q, sync, q, buf);
-		buf->state = VIDEOBUF_IDLE;
 		break;
 	default:
 		dprintk(1, "dqbuf: state invalid\n");
 		retval = -EINVAL;
 		goto done;
 	}
-	list_del(&buf->stream);
-	memset(b, 0, sizeof(*b));
+	CALL(q, sync, q, buf);
 	videobuf_status(q, b, buf, q->type);
-
- done:
+	list_del(&buf->stream);
+	buf->state = VIDEOBUF_IDLE;
+	b->flags &= ~V4L2_BUF_FLAG_DONE;
+done:
 	mutex_unlock(&q->vb_lock);
 	return retval;
 }
+EXPORT_SYMBOL_GPL(videobuf_dqbuf);
 
 int videobuf_streamon(struct videobuf_queue *q)
 {
@@ -709,10 +725,11 @@
 	spin_unlock_irqrestore(q->irqlock, flags);
 
 	wake_up_interruptible_sync(&q->wait);
- done:
+done:
 	mutex_unlock(&q->vb_lock);
 	return retval;
 }
+EXPORT_SYMBOL_GPL(videobuf_streamon);
 
 /* Locking: Caller holds q->vb_lock */
 static int __videobuf_streamoff(struct videobuf_queue *q)
@@ -735,6 +752,7 @@
 
 	return retval;
 }
+EXPORT_SYMBOL_GPL(videobuf_streamoff);
 
 /* Locking: Caller holds q->vb_lock */
 static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
@@ -774,7 +792,7 @@
 			retval = q->read_buf->size;
 	}
 
- done:
+done:
 	/* cleanup */
 	q->ops->buf_release(q, q->read_buf);
 	kfree(q->read_buf);
@@ -782,6 +800,49 @@
 	return retval;
 }
 
+static int __videobuf_copy_to_user(struct videobuf_queue *q,
+				   struct videobuf_buffer *buf,
+				   char __user *data, size_t count,
+				   int nonblocking)
+{
+	void *vaddr = CALL(q, vaddr, buf);
+
+	/* copy to userspace */
+	if (count > buf->size - q->read_off)
+		count = buf->size - q->read_off;
+
+	if (copy_to_user(data, vaddr + q->read_off, count))
+		return -EFAULT;
+
+	return count;
+}
+
+static int __videobuf_copy_stream(struct videobuf_queue *q,
+				  struct videobuf_buffer *buf,
+				  char __user *data, size_t count, size_t pos,
+				  int vbihack, int nonblocking)
+{
+	unsigned int *fc = CALL(q, vaddr, buf);
+
+	if (vbihack) {
+		/* dirty, undocumented hack -- pass the frame counter
+			* within the last four bytes of each vbi data block.
+			* We need that one to maintain backward compatibility
+			* to all vbi decoding software out there ... */
+		fc += (buf->size >> 2) - 1;
+		*fc = buf->field_count >> 1;
+		dprintk(1, "vbihack: %d\n", *fc);
+	}
+
+	/* copy stuff using the common method */
+	count = __videobuf_copy_to_user(q, buf, data, count, nonblocking);
+
+	if ((count == -EFAULT) && (pos == 0))
+		return -EFAULT;
+
+	return count;
+}
+
 ssize_t videobuf_read_one(struct videobuf_queue *q,
 			  char __user *data, size_t count, loff_t *ppos,
 			  int nonblocking)
@@ -850,7 +911,7 @@
 	}
 
 	/* Copy to userspace */
-	retval = CALL(q, video_copy_to_user, q, data, count, nonblocking);
+	retval = __videobuf_copy_to_user(q, q->read_buf, data, count, nonblocking);
 	if (retval < 0)
 		goto done;
 
@@ -862,10 +923,11 @@
 		q->read_buf = NULL;
 	}
 
- done:
+done:
 	mutex_unlock(&q->vb_lock);
 	return retval;
 }
+EXPORT_SYMBOL_GPL(videobuf_read_one);
 
 /* Locking: Caller holds q->vb_lock */
 static int __videobuf_read_start(struct videobuf_queue *q)
@@ -917,7 +979,6 @@
 		q->bufs[i] = NULL;
 	}
 	q->read_buf = NULL;
-
 }
 
 int videobuf_read_start(struct videobuf_queue *q)
@@ -930,6 +991,7 @@
 
 	return rc;
 }
+EXPORT_SYMBOL_GPL(videobuf_read_start);
 
 void videobuf_read_stop(struct videobuf_queue *q)
 {
@@ -937,6 +999,7 @@
 	__videobuf_read_stop(q);
 	mutex_unlock(&q->vb_lock);
 }
+EXPORT_SYMBOL_GPL(videobuf_read_stop);
 
 void videobuf_stop(struct videobuf_queue *q)
 {
@@ -950,7 +1013,7 @@
 
 	mutex_unlock(&q->vb_lock);
 }
-
+EXPORT_SYMBOL_GPL(videobuf_stop);
 
 ssize_t videobuf_read_stream(struct videobuf_queue *q,
 			     char __user *data, size_t count, loff_t *ppos,
@@ -990,7 +1053,7 @@
 		}
 
 		if (q->read_buf->state == VIDEOBUF_DONE) {
-			rc = CALL(q, copy_stream, q, data + retval, count,
+			rc = __videobuf_copy_stream(q, q->read_buf, data + retval, count,
 					retval, vbihack, nonblocking);
 			if (rc < 0) {
 				retval = rc;
@@ -1019,10 +1082,11 @@
 			break;
 	}
 
- done:
+done:
 	mutex_unlock(&q->vb_lock);
 	return retval;
 }
+EXPORT_SYMBOL_GPL(videobuf_read_stream);
 
 unsigned int videobuf_poll_stream(struct file *file,
 				  struct videobuf_queue *q,
@@ -1056,27 +1120,51 @@
 	if (0 == rc) {
 		poll_wait(file, &buf->done, wait);
 		if (buf->state == VIDEOBUF_DONE ||
-		    buf->state == VIDEOBUF_ERROR)
-			rc = POLLIN|POLLRDNORM;
+		    buf->state == VIDEOBUF_ERROR) {
+			switch (q->type) {
+			case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+			case V4L2_BUF_TYPE_VBI_OUTPUT:
+			case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+				rc = POLLOUT | POLLWRNORM;
+				break;
+			default:
+				rc = POLLIN | POLLRDNORM;
+				break;
+			}
+		}
 	}
 	mutex_unlock(&q->vb_lock);
 	return rc;
 }
+EXPORT_SYMBOL_GPL(videobuf_poll_stream);
 
-int videobuf_mmap_mapper(struct videobuf_queue *q,
-			 struct vm_area_struct *vma)
+int videobuf_mmap_mapper(struct videobuf_queue *q, struct vm_area_struct *vma)
 {
-	int retval;
+	int rc = -EINVAL;
+	int i;
 
 	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
+	if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) {
+		dprintk(1, "mmap appl bug: PROT_WRITE and MAP_SHARED are required\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&q->vb_lock);
-	retval = CALL(q, mmap_mapper, q, vma);
-	q->is_mmapped = 1;
+	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+		struct videobuf_buffer *buf = q->bufs[i];
+
+		if (buf && buf->memory == V4L2_MEMORY_MMAP &&
+				buf->boff == (vma->vm_pgoff << PAGE_SHIFT)) {
+			rc = CALL(q, mmap_mapper, q, buf, vma);
+			break;
+		}
+	}
 	mutex_unlock(&q->vb_lock);
 
-	return retval;
+	return rc;
 }
+EXPORT_SYMBOL_GPL(videobuf_mmap_mapper);
 
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
 int videobuf_cgmbuf(struct videobuf_queue *q,
@@ -1107,33 +1195,3 @@
 EXPORT_SYMBOL_GPL(videobuf_cgmbuf);
 #endif
 
-/* --------------------------------------------------------------------- */
-
-EXPORT_SYMBOL_GPL(videobuf_waiton);
-EXPORT_SYMBOL_GPL(videobuf_iolock);
-
-EXPORT_SYMBOL_GPL(videobuf_alloc);
-
-EXPORT_SYMBOL_GPL(videobuf_queue_core_init);
-EXPORT_SYMBOL_GPL(videobuf_queue_cancel);
-EXPORT_SYMBOL_GPL(videobuf_queue_is_busy);
-
-EXPORT_SYMBOL_GPL(videobuf_next_field);
-EXPORT_SYMBOL_GPL(videobuf_reqbufs);
-EXPORT_SYMBOL_GPL(videobuf_querybuf);
-EXPORT_SYMBOL_GPL(videobuf_qbuf);
-EXPORT_SYMBOL_GPL(videobuf_dqbuf);
-EXPORT_SYMBOL_GPL(videobuf_streamon);
-EXPORT_SYMBOL_GPL(videobuf_streamoff);
-
-EXPORT_SYMBOL_GPL(videobuf_read_start);
-EXPORT_SYMBOL_GPL(videobuf_read_stop);
-EXPORT_SYMBOL_GPL(videobuf_stop);
-EXPORT_SYMBOL_GPL(videobuf_read_stream);
-EXPORT_SYMBOL_GPL(videobuf_read_one);
-EXPORT_SYMBOL_GPL(videobuf_poll_stream);
-
-EXPORT_SYMBOL_GPL(__videobuf_mmap_setup);
-EXPORT_SYMBOL_GPL(videobuf_mmap_setup);
-EXPORT_SYMBOL_GPL(videobuf_mmap_free);
-EXPORT_SYMBOL_GPL(videobuf_mmap_mapper);
diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c
index dce4f3a..74730c6 100644
--- a/drivers/media/video/videobuf-dma-contig.c
+++ b/drivers/media/video/videobuf-dma-contig.c
@@ -55,14 +55,14 @@
 	struct videobuf_queue *q = map->q;
 	int i;
 
-	dev_dbg(map->q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n",
+	dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n",
 		map, map->count, vma->vm_start, vma->vm_end);
 
 	map->count--;
 	if (0 == map->count) {
 		struct videobuf_dma_contig_memory *mem;
 
-		dev_dbg(map->q->dev, "munmap %p q=%p\n", map, q);
+		dev_dbg(q->dev, "munmap %p q=%p\n", map, q);
 		mutex_lock(&q->vb_lock);
 
 		/* We need first to cancel streams, before unmapping */
@@ -89,7 +89,7 @@
 				/* vfree is not atomic - can't be
 				   called with IRQ's disabled
 				 */
-				dev_dbg(map->q->dev, "buf[%d] freeing %p\n",
+				dev_dbg(q->dev, "buf[%d] freeing %p\n",
 					i, mem->vaddr);
 
 				dma_free_coherent(q->dev, mem->size,
@@ -190,7 +190,7 @@
 	return ret;
 }
 
-static void *__videobuf_alloc(size_t size)
+static struct videobuf_buffer *__videobuf_alloc(size_t size)
 {
 	struct videobuf_dma_contig_memory *mem;
 	struct videobuf_buffer *vb;
@@ -204,7 +204,7 @@
 	return vb;
 }
 
-static void *__videobuf_to_vmalloc(struct videobuf_buffer *buf)
+static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
 {
 	struct videobuf_dma_contig_memory *mem = buf->priv;
 
@@ -263,65 +263,34 @@
 	return 0;
 }
 
-static int __videobuf_mmap_free(struct videobuf_queue *q)
-{
-	unsigned int i;
-
-	dev_dbg(q->dev, "%s\n", __func__);
-	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
-		if (q->bufs[i] && q->bufs[i]->map)
-			return -EBUSY;
-	}
-
-	return 0;
-}
-
 static int __videobuf_mmap_mapper(struct videobuf_queue *q,
+				  struct videobuf_buffer *buf,
 				  struct vm_area_struct *vma)
 {
 	struct videobuf_dma_contig_memory *mem;
 	struct videobuf_mapping *map;
-	unsigned int first;
 	int retval;
-	unsigned long size, offset = vma->vm_pgoff << PAGE_SHIFT;
+	unsigned long size;
 
 	dev_dbg(q->dev, "%s\n", __func__);
-	if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
-		return -EINVAL;
-
-	/* look for first buffer to map */
-	for (first = 0; first < VIDEO_MAX_FRAME; first++) {
-		if (!q->bufs[first])
-			continue;
-
-		if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
-			continue;
-		if (q->bufs[first]->boff == offset)
-			break;
-	}
-	if (VIDEO_MAX_FRAME == first) {
-		dev_dbg(q->dev, "invalid user space offset [offset=0x%lx]\n",
-			offset);
-		return -EINVAL;
-	}
 
 	/* create mapping + update buffer list */
 	map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
 	if (!map)
 		return -ENOMEM;
 
-	q->bufs[first]->map = map;
+	buf->map = map;
 	map->start = vma->vm_start;
 	map->end = vma->vm_end;
 	map->q = q;
 
-	q->bufs[first]->baddr = vma->vm_start;
+	buf->baddr = vma->vm_start;
 
-	mem = q->bufs[first]->priv;
+	mem = buf->priv;
 	BUG_ON(!mem);
 	MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
 
-	mem->size = PAGE_ALIGN(q->bufs[first]->bsize);
+	mem->size = PAGE_ALIGN(buf->bsize);
 	mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
 					&mem->dma_handle, GFP_KERNEL);
 	if (!mem->vaddr) {
@@ -354,8 +323,8 @@
 
 	dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
 		map, q, vma->vm_start, vma->vm_end,
-		(long int) q->bufs[first]->bsize,
-		vma->vm_pgoff, first);
+		(long int)buf->bsize,
+		vma->vm_pgoff, buf->i);
 
 	videobuf_vm_open(vma);
 
@@ -366,69 +335,13 @@
 	return -ENOMEM;
 }
 
-static int __videobuf_copy_to_user(struct videobuf_queue *q,
-				   char __user *data, size_t count,
-				   int nonblocking)
-{
-	struct videobuf_dma_contig_memory *mem = q->read_buf->priv;
-	void *vaddr;
-
-	BUG_ON(!mem);
-	MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
-	BUG_ON(!mem->vaddr);
-
-	/* copy to userspace */
-	if (count > q->read_buf->size - q->read_off)
-		count = q->read_buf->size - q->read_off;
-
-	vaddr = mem->vaddr;
-
-	if (copy_to_user(data, vaddr + q->read_off, count))
-		return -EFAULT;
-
-	return count;
-}
-
-static int __videobuf_copy_stream(struct videobuf_queue *q,
-				  char __user *data, size_t count, size_t pos,
-				  int vbihack, int nonblocking)
-{
-	unsigned int  *fc;
-	struct videobuf_dma_contig_memory *mem = q->read_buf->priv;
-
-	BUG_ON(!mem);
-	MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
-
-	if (vbihack) {
-		/* dirty, undocumented hack -- pass the frame counter
-			* within the last four bytes of each vbi data block.
-			* We need that one to maintain backward compatibility
-			* to all vbi decoding software out there ... */
-		fc = (unsigned int *)mem->vaddr;
-		fc += (q->read_buf->size >> 2) - 1;
-		*fc = q->read_buf->field_count >> 1;
-		dev_dbg(q->dev, "vbihack: %d\n", *fc);
-	}
-
-	/* copy stuff using the common method */
-	count = __videobuf_copy_to_user(q, data, count, nonblocking);
-
-	if ((count == -EFAULT) && (pos == 0))
-		return -EFAULT;
-
-	return count;
-}
-
 static struct videobuf_qtype_ops qops = {
 	.magic        = MAGIC_QTYPE_OPS,
 
 	.alloc        = __videobuf_alloc,
 	.iolock       = __videobuf_iolock,
-	.mmap_free    = __videobuf_mmap_free,
 	.mmap_mapper  = __videobuf_mmap_mapper,
-	.video_copy_to_user = __videobuf_copy_to_user,
-	.copy_stream  = __videobuf_copy_stream,
-	.vmalloc      = __videobuf_to_vmalloc,
+	.vaddr        = __videobuf_to_vaddr,
 };
 
 void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
index fcd045e..8359e6b 100644
--- a/drivers/media/video/videobuf-dma-sg.c
+++ b/drivers/media/video/videobuf-dma-sg.c
@@ -37,8 +37,12 @@
 #define MAGIC_DMABUF 0x19721112
 #define MAGIC_SG_MEM 0x17890714
 
-#define MAGIC_CHECK(is,should)	if (unlikely((is) != (should))) \
-	{ printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
+#define MAGIC_CHECK(is, should)						\
+	if (unlikely((is) != (should))) {				\
+		printk(KERN_ERR "magic mismatch: %x (expected %x)\n",	\
+				is, should);				\
+		BUG();							\
+	}
 
 static int debug;
 module_param(debug, int, 0644);
@@ -47,13 +51,13 @@
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
 MODULE_LICENSE("GPL");
 
-#define dprintk(level, fmt, arg...)	if (debug >= level) \
-	printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg)
+#define dprintk(level, fmt, arg...)					\
+	if (debug >= level)						\
+		printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg)
 
 /* --------------------------------------------------------------------- */
 
-struct scatterlist*
-videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
+struct scatterlist *videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
 {
 	struct scatterlist *sglist;
 	struct page *pg;
@@ -73,13 +77,14 @@
 	}
 	return sglist;
 
- err:
+err:
 	vfree(sglist);
 	return NULL;
 }
+EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg);
 
-struct scatterlist*
-videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
+struct scatterlist *videobuf_pages_to_sg(struct page **pages, int nr_pages,
+					 int offset)
 {
 	struct scatterlist *sglist;
 	int i;
@@ -104,20 +109,20 @@
 	}
 	return sglist;
 
- nopage:
-	dprintk(2,"sgl: oops - no page\n");
+nopage:
+	dprintk(2, "sgl: oops - no page\n");
 	vfree(sglist);
 	return NULL;
 
- highmem:
-	dprintk(2,"sgl: oops - highmem page\n");
+highmem:
+	dprintk(2, "sgl: oops - highmem page\n");
 	vfree(sglist);
 	return NULL;
 }
 
 /* --------------------------------------------------------------------- */
 
-struct videobuf_dmabuf *videobuf_to_dma (struct videobuf_buffer *buf)
+struct videobuf_dmabuf *videobuf_to_dma(struct videobuf_buffer *buf)
 {
 	struct videobuf_dma_sg_memory *mem = buf->priv;
 	BUG_ON(!mem);
@@ -126,17 +131,19 @@
 
 	return &mem->dma;
 }
+EXPORT_SYMBOL_GPL(videobuf_to_dma);
 
 void videobuf_dma_init(struct videobuf_dmabuf *dma)
 {
-	memset(dma,0,sizeof(*dma));
+	memset(dma, 0, sizeof(*dma));
 	dma->magic = MAGIC_DMABUF;
 }
+EXPORT_SYMBOL_GPL(videobuf_dma_init);
 
 static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
 			int direction, unsigned long data, unsigned long size)
 {
-	unsigned long first,last;
+	unsigned long first, last;
 	int err, rw = 0;
 
 	dma->direction = direction;
@@ -155,21 +162,21 @@
 	last  = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT;
 	dma->offset   = data & ~PAGE_MASK;
 	dma->nr_pages = last-first+1;
-	dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*),
-			     GFP_KERNEL);
+	dma->pages = kmalloc(dma->nr_pages * sizeof(struct page *), GFP_KERNEL);
 	if (NULL == dma->pages)
 		return -ENOMEM;
-	dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n",
-		data,size,dma->nr_pages);
 
-	err = get_user_pages(current,current->mm,
+	dprintk(1, "init user [0x%lx+0x%lx => %d pages]\n",
+		data, size, dma->nr_pages);
+
+	err = get_user_pages(current, current->mm,
 			     data & PAGE_MASK, dma->nr_pages,
 			     rw == READ, 1, /* force */
 			     dma->pages, NULL);
 
 	if (err != dma->nr_pages) {
 		dma->nr_pages = (err >= 0) ? err : 0;
-		dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages);
+		dprintk(1, "get_user_pages: err=%d [%d]\n", err, dma->nr_pages);
 		return err < 0 ? err : -EINVAL;
 	}
 	return 0;
@@ -179,48 +186,58 @@
 			   unsigned long data, unsigned long size)
 {
 	int ret;
+
 	down_read(&current->mm->mmap_sem);
 	ret = videobuf_dma_init_user_locked(dma, direction, data, size);
 	up_read(&current->mm->mmap_sem);
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(videobuf_dma_init_user);
 
 int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
 			     int nr_pages)
 {
-	dprintk(1,"init kernel [%d pages]\n",nr_pages);
+	dprintk(1, "init kernel [%d pages]\n", nr_pages);
+
 	dma->direction = direction;
 	dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT);
 	if (NULL == dma->vmalloc) {
-		dprintk(1,"vmalloc_32(%d pages) failed\n",nr_pages);
+		dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages);
 		return -ENOMEM;
 	}
-	dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n",
+
+	dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n",
 				(unsigned long)dma->vmalloc,
 				nr_pages << PAGE_SHIFT);
-	memset(dma->vmalloc,0,nr_pages << PAGE_SHIFT);
+
+	memset(dma->vmalloc, 0, nr_pages << PAGE_SHIFT);
 	dma->nr_pages = nr_pages;
+
 	return 0;
 }
+EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel);
 
 int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
 			      dma_addr_t addr, int nr_pages)
 {
-	dprintk(1,"init overlay [%d pages @ bus 0x%lx]\n",
-		nr_pages,(unsigned long)addr);
+	dprintk(1, "init overlay [%d pages @ bus 0x%lx]\n",
+		nr_pages, (unsigned long)addr);
 	dma->direction = direction;
+
 	if (0 == addr)
 		return -EINVAL;
 
 	dma->bus_addr = addr;
 	dma->nr_pages = nr_pages;
+
 	return 0;
 }
+EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay);
 
-int videobuf_dma_map(struct videobuf_queue* q, struct videobuf_dmabuf *dma)
+int videobuf_dma_map(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
 {
-	MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
+	MAGIC_CHECK(dma->magic, MAGIC_DMABUF);
 	BUG_ON(0 == dma->nr_pages);
 
 	if (dma->pages) {
@@ -228,20 +245,21 @@
 						   dma->offset);
 	}
 	if (dma->vmalloc) {
-		dma->sglist = videobuf_vmalloc_to_sg
-						(dma->vmalloc,dma->nr_pages);
+		dma->sglist = videobuf_vmalloc_to_sg(dma->vmalloc,
+						     dma->nr_pages);
 	}
 	if (dma->bus_addr) {
 		dma->sglist = vmalloc(sizeof(*dma->sglist));
 		if (NULL != dma->sglist) {
-			dma->sglen  = 1;
-			sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK;
-			dma->sglist[0].offset           = dma->bus_addr & ~PAGE_MASK;
-			sg_dma_len(&dma->sglist[0])     = dma->nr_pages * PAGE_SIZE;
+			dma->sglen = 1;
+			sg_dma_address(&dma->sglist[0])	= dma->bus_addr
+							& PAGE_MASK;
+			dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK;
+			sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE;
 		}
 	}
 	if (NULL == dma->sglist) {
-		dprintk(1,"scatterlist is NULL\n");
+		dprintk(1, "scatterlist is NULL\n");
 		return -ENOMEM;
 	}
 	if (!dma->bus_addr) {
@@ -249,47 +267,43 @@
 					dma->nr_pages, dma->direction);
 		if (0 == dma->sglen) {
 			printk(KERN_WARNING
-			       "%s: videobuf_map_sg failed\n",__func__);
+			       "%s: videobuf_map_sg failed\n", __func__);
 			vfree(dma->sglist);
 			dma->sglist = NULL;
 			dma->sglen = 0;
 			return -ENOMEM;
 		}
 	}
+
 	return 0;
 }
+EXPORT_SYMBOL_GPL(videobuf_dma_map);
 
-int videobuf_dma_sync(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
+int videobuf_dma_unmap(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
 {
 	MAGIC_CHECK(dma->magic, MAGIC_DMABUF);
-	BUG_ON(!dma->sglen);
 
-	dma_sync_sg_for_cpu(q->dev, dma->sglist, dma->nr_pages, dma->direction);
-	return 0;
-}
-
-int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
-{
-	MAGIC_CHECK(dma->magic, MAGIC_DMABUF);
 	if (!dma->sglen)
 		return 0;
 
-	dma_unmap_sg(q->dev, dma->sglist, dma->nr_pages, dma->direction);
+	dma_unmap_sg(q->dev, dma->sglist, dma->sglen, dma->direction);
 
 	vfree(dma->sglist);
 	dma->sglist = NULL;
 	dma->sglen = 0;
+
 	return 0;
 }
+EXPORT_SYMBOL_GPL(videobuf_dma_unmap);
 
 int videobuf_dma_free(struct videobuf_dmabuf *dma)
 {
-	MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
+	int i;
+	MAGIC_CHECK(dma->magic, MAGIC_DMABUF);
 	BUG_ON(dma->sglen);
 
 	if (dma->pages) {
-		int i;
-		for (i=0; i < dma->nr_pages; i++)
+		for (i = 0; i < dma->nr_pages; i++)
 			page_cache_release(dma->pages[i]);
 		kfree(dma->pages);
 		dma->pages = NULL;
@@ -298,12 +312,13 @@
 	vfree(dma->vmalloc);
 	dma->vmalloc = NULL;
 
-	if (dma->bus_addr) {
+	if (dma->bus_addr)
 		dma->bus_addr = 0;
-	}
 	dma->direction = DMA_NONE;
+
 	return 0;
 }
+EXPORT_SYMBOL_GPL(videobuf_dma_free);
 
 /* --------------------------------------------------------------------- */
 
@@ -315,6 +330,7 @@
 
 	return videobuf_dma_map(&q, dma);
 }
+EXPORT_SYMBOL_GPL(videobuf_sg_dma_map);
 
 int videobuf_sg_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma)
 {
@@ -324,49 +340,48 @@
 
 	return videobuf_dma_unmap(&q, dma);
 }
+EXPORT_SYMBOL_GPL(videobuf_sg_dma_unmap);
 
 /* --------------------------------------------------------------------- */
 
-static void
-videobuf_vm_open(struct vm_area_struct *vma)
+static void videobuf_vm_open(struct vm_area_struct *vma)
 {
 	struct videobuf_mapping *map = vma->vm_private_data;
 
-	dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map,
-		map->count,vma->vm_start,vma->vm_end);
+	dprintk(2, "vm_open %p [count=%d,vma=%08lx-%08lx]\n", map,
+		map->count, vma->vm_start, vma->vm_end);
+
 	map->count++;
 }
 
-static void
-videobuf_vm_close(struct vm_area_struct *vma)
+static void videobuf_vm_close(struct vm_area_struct *vma)
 {
 	struct videobuf_mapping *map = vma->vm_private_data;
 	struct videobuf_queue *q = map->q;
 	struct videobuf_dma_sg_memory *mem;
 	int i;
 
-	dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map,
-		map->count,vma->vm_start,vma->vm_end);
+	dprintk(2, "vm_close %p [count=%d,vma=%08lx-%08lx]\n", map,
+		map->count, vma->vm_start, vma->vm_end);
 
 	map->count--;
 	if (0 == map->count) {
-		dprintk(1,"munmap %p q=%p\n",map,q);
+		dprintk(1, "munmap %p q=%p\n", map, q);
 		mutex_lock(&q->vb_lock);
 		for (i = 0; i < VIDEO_MAX_FRAME; i++) {
 			if (NULL == q->bufs[i])
 				continue;
-			mem=q->bufs[i]->priv;
-
+			mem = q->bufs[i]->priv;
 			if (!mem)
 				continue;
 
-			MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+			MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);
 
 			if (q->bufs[i]->map != map)
 				continue;
 			q->bufs[i]->map   = NULL;
 			q->bufs[i]->baddr = 0;
-			q->ops->buf_release(q,q->bufs[i]);
+			q->ops->buf_release(q, q->bufs[i]);
 		}
 		mutex_unlock(&q->vb_lock);
 		kfree(map);
@@ -380,26 +395,27 @@
  * now ...).  Bounce buffers don't work very well for the data rates
  * video capture has.
  */
-static int
-videobuf_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+static int videobuf_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
 	struct page *page;
 
-	dprintk(3,"fault: fault @ %08lx [vma %08lx-%08lx]\n",
-		(unsigned long)vmf->virtual_address,vma->vm_start,vma->vm_end);
+	dprintk(3, "fault: fault @ %08lx [vma %08lx-%08lx]\n",
+		(unsigned long)vmf->virtual_address,
+		vma->vm_start, vma->vm_end);
+
 	page = alloc_page(GFP_USER | __GFP_DMA32);
 	if (!page)
 		return VM_FAULT_OOM;
 	clear_user_highpage(page, (unsigned long)vmf->virtual_address);
 	vmf->page = page;
+
 	return 0;
 }
 
-static const struct vm_operations_struct videobuf_vm_ops =
-{
-	.open     = videobuf_vm_open,
-	.close    = videobuf_vm_close,
-	.fault    = videobuf_vm_fault,
+static const struct vm_operations_struct videobuf_vm_ops = {
+	.open	= videobuf_vm_open,
+	.close	= videobuf_vm_close,
+	.fault	= videobuf_vm_fault,
 };
 
 /* ---------------------------------------------------------------------
@@ -412,28 +428,28 @@
 	struct videobuf_dma_sg_memory
  */
 
-static void *__videobuf_alloc(size_t size)
+static struct videobuf_buffer *__videobuf_alloc(size_t size)
 {
 	struct videobuf_dma_sg_memory *mem;
 	struct videobuf_buffer *vb;
 
-	vb = kzalloc(size+sizeof(*mem),GFP_KERNEL);
+	vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
 	if (!vb)
 		return vb;
 
-	mem = vb->priv = ((char *)vb)+size;
-	mem->magic=MAGIC_SG_MEM;
+	mem = vb->priv = ((char *)vb) + size;
+	mem->magic = MAGIC_SG_MEM;
 
 	videobuf_dma_init(&mem->dma);
 
-	dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
-		__func__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
-		mem,(long)sizeof(*mem));
+	dprintk(1, "%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
+		__func__, vb, (long)sizeof(*vb), (long)size - sizeof(*vb),
+		mem, (long)sizeof(*mem));
 
 	return vb;
 }
 
-static void *__videobuf_to_vmalloc (struct videobuf_buffer *buf)
+static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
 {
 	struct videobuf_dma_sg_memory *mem = buf->priv;
 	BUG_ON(!mem);
@@ -443,11 +459,11 @@
 	return mem->dma.vmalloc;
 }
 
-static int __videobuf_iolock (struct videobuf_queue* q,
-			      struct videobuf_buffer *vb,
-			      struct v4l2_framebuffer *fbuf)
+static int __videobuf_iolock(struct videobuf_queue *q,
+			     struct videobuf_buffer *vb,
+			     struct v4l2_framebuffer *fbuf)
 {
-	int err,pages;
+	int err, pages;
 	dma_addr_t bus;
 	struct videobuf_dma_sg_memory *mem = vb->priv;
 	BUG_ON(!mem);
@@ -460,16 +476,16 @@
 		if (0 == vb->baddr) {
 			/* no userspace addr -- kernel bounce buffer */
 			pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
-			err = videobuf_dma_init_kernel( &mem->dma,
-							DMA_FROM_DEVICE,
-							pages );
+			err = videobuf_dma_init_kernel(&mem->dma,
+						       DMA_FROM_DEVICE,
+						       pages);
 			if (0 != err)
 				return err;
 		} else if (vb->memory == V4L2_MEMORY_USERPTR) {
 			/* dma directly to userspace */
-			err = videobuf_dma_init_user( &mem->dma,
-						      DMA_FROM_DEVICE,
-						      vb->baddr,vb->bsize );
+			err = videobuf_dma_init_user(&mem->dma,
+						     DMA_FROM_DEVICE,
+						     vb->baddr, vb->bsize);
 			if (0 != err)
 				return err;
 		} else {
@@ -515,43 +531,27 @@
 			   struct videobuf_buffer *buf)
 {
 	struct videobuf_dma_sg_memory *mem = buf->priv;
-	BUG_ON(!mem);
-	MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+	BUG_ON(!mem || !mem->dma.sglen);
 
-	return	videobuf_dma_sync(q,&mem->dma);
-}
+	MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);
+	MAGIC_CHECK(mem->dma.magic, MAGIC_DMABUF);
 
-static int __videobuf_mmap_free(struct videobuf_queue *q)
-{
-	int i;
-
-	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
-		if (q->bufs[i]) {
-			if (q->bufs[i]->map)
-				return -EBUSY;
-		}
-	}
+	dma_sync_sg_for_cpu(q->dev, mem->dma.sglist,
+			    mem->dma.sglen, mem->dma.direction);
 
 	return 0;
 }
 
 static int __videobuf_mmap_mapper(struct videobuf_queue *q,
-			 struct vm_area_struct *vma)
+				  struct videobuf_buffer *buf,
+				  struct vm_area_struct *vma)
 {
-	struct videobuf_dma_sg_memory *mem;
+	struct videobuf_dma_sg_memory *mem = buf->priv;
 	struct videobuf_mapping *map;
-	unsigned int first,last,size,i;
+	unsigned int first, last, size = 0, i;
 	int retval;
 
 	retval = -EINVAL;
-	if (!(vma->vm_flags & VM_WRITE)) {
-		dprintk(1,"mmap app bug: PROT_WRITE please\n");
-		goto done;
-	}
-	if (!(vma->vm_flags & VM_SHARED)) {
-		dprintk(1,"mmap app bug: MAP_SHARED please\n");
-		goto done;
-	}
 
 	/* This function maintains backwards compatibility with V4L1 and will
 	 * map more than one buffer if the vma length is equal to the combined
@@ -561,48 +561,52 @@
 	 * TODO: Allow drivers to specify if they support this mode
 	 */
 
+	BUG_ON(!mem);
+	MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);
+
 	/* look for first buffer to map */
 	for (first = 0; first < VIDEO_MAX_FRAME; first++) {
-		if (NULL == q->bufs[first])
-			continue;
-		mem=q->bufs[first]->priv;
-		BUG_ON(!mem);
-		MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
-
-		if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
-			continue;
-		if (q->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT))
+		if (buf == q->bufs[first]) {
+			size = PAGE_ALIGN(q->bufs[first]->bsize);
 			break;
+		}
 	}
-	if (VIDEO_MAX_FRAME == first) {
-		dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n",
-			(vma->vm_pgoff << PAGE_SHIFT));
+
+	/* paranoia, should never happen since buf is always valid. */
+	if (!size) {
+		dprintk(1, "mmap app bug: offset invalid [offset=0x%lx]\n",
+				(vma->vm_pgoff << PAGE_SHIFT));
 		goto done;
 	}
 
-	/* look for last buffer to map */
-	for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) {
-		if (NULL == q->bufs[last])
-			continue;
-		if (V4L2_MEMORY_MMAP != q->bufs[last]->memory)
-			continue;
-		if (q->bufs[last]->map) {
-			retval = -EBUSY;
+	last = first;
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+	if (size != (vma->vm_end - vma->vm_start)) {
+		/* look for last buffer to map */
+		for (last = first + 1; last < VIDEO_MAX_FRAME; last++) {
+			if (NULL == q->bufs[last])
+				continue;
+			if (V4L2_MEMORY_MMAP != q->bufs[last]->memory)
+				continue;
+			if (q->bufs[last]->map) {
+				retval = -EBUSY;
+				goto done;
+			}
+			size += PAGE_ALIGN(q->bufs[last]->bsize);
+			if (size == (vma->vm_end - vma->vm_start))
+				break;
+		}
+		if (VIDEO_MAX_FRAME == last) {
+			dprintk(1, "mmap app bug: size invalid [size=0x%lx]\n",
+					(vma->vm_end - vma->vm_start));
 			goto done;
 		}
-		size += PAGE_ALIGN(q->bufs[last]->bsize);
-		if (size == (vma->vm_end - vma->vm_start))
-			break;
 	}
-	if (VIDEO_MAX_FRAME == last) {
-		dprintk(1,"mmap app bug: size invalid [size=0x%lx]\n",
-			(vma->vm_end - vma->vm_start));
-		goto done;
-	}
+#endif
 
 	/* create mapping + update buffer list */
 	retval = -ENOMEM;
-	map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL);
+	map = kmalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
 	if (NULL == map)
 		goto done;
 
@@ -623,72 +627,22 @@
 	vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
 	vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */
 	vma->vm_private_data = map;
-	dprintk(1,"mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n",
-		map,q,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last);
+	dprintk(1, "mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n",
+		map, q, vma->vm_start, vma->vm_end, vma->vm_pgoff, first, last);
 	retval = 0;
 
- done:
+done:
 	return retval;
 }
 
-static int __videobuf_copy_to_user ( struct videobuf_queue *q,
-				char __user *data, size_t count,
-				int nonblocking )
-{
-	struct videobuf_dma_sg_memory *mem = q->read_buf->priv;
-	BUG_ON(!mem);
-	MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
-
-	/* copy to userspace */
-	if (count > q->read_buf->size - q->read_off)
-		count = q->read_buf->size - q->read_off;
-
-	if (copy_to_user(data, mem->dma.vmalloc+q->read_off, count))
-		return -EFAULT;
-
-	return count;
-}
-
-static int __videobuf_copy_stream ( struct videobuf_queue *q,
-				char __user *data, size_t count, size_t pos,
-				int vbihack, int nonblocking )
-{
-	unsigned int  *fc;
-	struct videobuf_dma_sg_memory *mem = q->read_buf->priv;
-	BUG_ON(!mem);
-	MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
-
-	if (vbihack) {
-		/* dirty, undocumented hack -- pass the frame counter
-			* within the last four bytes of each vbi data block.
-			* We need that one to maintain backward compatibility
-			* to all vbi decoding software out there ... */
-		fc  = (unsigned int*)mem->dma.vmalloc;
-		fc += (q->read_buf->size>>2) -1;
-		*fc = q->read_buf->field_count >> 1;
-		dprintk(1,"vbihack: %d\n",*fc);
-	}
-
-	/* copy stuff using the common method */
-	count = __videobuf_copy_to_user (q,data,count,nonblocking);
-
-	if ( (count==-EFAULT) && (0 == pos) )
-		return -EFAULT;
-
-	return count;
-}
-
 static struct videobuf_qtype_ops sg_ops = {
 	.magic        = MAGIC_QTYPE_OPS,
 
 	.alloc        = __videobuf_alloc,
 	.iolock       = __videobuf_iolock,
 	.sync         = __videobuf_sync,
-	.mmap_free    = __videobuf_mmap_free,
 	.mmap_mapper  = __videobuf_mmap_mapper,
-	.video_copy_to_user = __videobuf_copy_to_user,
-	.copy_stream  = __videobuf_copy_stream,
-	.vmalloc      = __videobuf_to_vmalloc,
+	.vaddr        = __videobuf_to_vaddr,
 };
 
 void *videobuf_sg_alloc(size_t size)
@@ -702,8 +656,9 @@
 
 	return videobuf_alloc(&q);
 }
+EXPORT_SYMBOL_GPL(videobuf_sg_alloc);
 
-void videobuf_queue_sg_init(struct videobuf_queue* q,
+void videobuf_queue_sg_init(struct videobuf_queue *q,
 			 const struct videobuf_queue_ops *ops,
 			 struct device *dev,
 			 spinlock_t *irqlock,
@@ -715,29 +670,5 @@
 	videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
 				 priv, &sg_ops);
 }
-
-/* --------------------------------------------------------------------- */
-
-EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg);
-
-EXPORT_SYMBOL_GPL(videobuf_to_dma);
-EXPORT_SYMBOL_GPL(videobuf_dma_init);
-EXPORT_SYMBOL_GPL(videobuf_dma_init_user);
-EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel);
-EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay);
-EXPORT_SYMBOL_GPL(videobuf_dma_map);
-EXPORT_SYMBOL_GPL(videobuf_dma_sync);
-EXPORT_SYMBOL_GPL(videobuf_dma_unmap);
-EXPORT_SYMBOL_GPL(videobuf_dma_free);
-
-EXPORT_SYMBOL_GPL(videobuf_sg_dma_map);
-EXPORT_SYMBOL_GPL(videobuf_sg_dma_unmap);
-EXPORT_SYMBOL_GPL(videobuf_sg_alloc);
-
 EXPORT_SYMBOL_GPL(videobuf_queue_sg_init);
 
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c
index 0afb62e..3f76398 100644
--- a/drivers/media/video/videobuf-dvb.c
+++ b/drivers/media/video/videobuf-dvb.c
@@ -67,7 +67,7 @@
 		try_to_freeze();
 
 		/* feed buffer data to demux */
-		outp = videobuf_queue_to_vmalloc (&dvb->dvbq, buf);
+		outp = videobuf_queue_to_vaddr(&dvb->dvbq, buf);
 
 		if (buf->state == VIDEOBUF_DONE)
 			dvb_dmx_swfilter(&dvb->demux, outp,
diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c
index 136e093..583728f 100644
--- a/drivers/media/video/videobuf-vmalloc.c
+++ b/drivers/media/video/videobuf-vmalloc.c
@@ -30,8 +30,12 @@
 #define MAGIC_DMABUF   0x17760309
 #define MAGIC_VMAL_MEM 0x18221223
 
-#define MAGIC_CHECK(is,should)	if (unlikely((is) != (should))) \
-	{ printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
+#define MAGIC_CHECK(is, should)						\
+	if (unlikely((is) != (should))) {				\
+		printk(KERN_ERR "magic mismatch: %x (expected %x)\n",	\
+				is, should);				\
+		BUG();							\
+	}
 
 static int debug;
 module_param(debug, int, 0644);
@@ -40,19 +44,19 @@
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
 MODULE_LICENSE("GPL");
 
-#define dprintk(level, fmt, arg...)	if (debug >= level) \
-	printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg)
+#define dprintk(level, fmt, arg...)					\
+	if (debug >= level)						\
+		printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg)
 
 
 /***************************************************************************/
 
-static void
-videobuf_vm_open(struct vm_area_struct *vma)
+static void videobuf_vm_open(struct vm_area_struct *vma)
 {
 	struct videobuf_mapping *map = vma->vm_private_data;
 
-	dprintk(2,"vm_open %p [count=%u,vma=%08lx-%08lx]\n",map,
-		map->count,vma->vm_start,vma->vm_end);
+	dprintk(2, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", map,
+		map->count, vma->vm_start, vma->vm_end);
 
 	map->count++;
 }
@@ -63,7 +67,7 @@
 	struct videobuf_queue *q = map->q;
 	int i;
 
-	dprintk(2,"vm_close %p [count=%u,vma=%08lx-%08lx]\n", map,
+	dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map,
 		map->count, vma->vm_start, vma->vm_end);
 
 	map->count--;
@@ -116,8 +120,7 @@
 	return;
 }
 
-static const struct vm_operations_struct videobuf_vm_ops =
-{
+static const struct vm_operations_struct videobuf_vm_ops = {
 	.open     = videobuf_vm_open,
 	.close    = videobuf_vm_close,
 };
@@ -132,28 +135,28 @@
 	struct videobuf_dma_sg_memory
  */
 
-static void *__videobuf_alloc(size_t size)
+static struct videobuf_buffer *__videobuf_alloc(size_t size)
 {
 	struct videobuf_vmalloc_memory *mem;
 	struct videobuf_buffer *vb;
 
-	vb = kzalloc(size+sizeof(*mem),GFP_KERNEL);
+	vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
 	if (!vb)
 		return vb;
 
-	mem = vb->priv = ((char *)vb)+size;
-	mem->magic=MAGIC_VMAL_MEM;
+	mem = vb->priv = ((char *)vb) + size;
+	mem->magic = MAGIC_VMAL_MEM;
 
-	dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
-		__func__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
-		mem,(long)sizeof(*mem));
+	dprintk(1, "%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
+		__func__, vb, (long)sizeof(*vb), (long)size - sizeof(*vb),
+		mem, (long)sizeof(*mem));
 
 	return vb;
 }
 
-static int __videobuf_iolock (struct videobuf_queue* q,
-			      struct videobuf_buffer *vb,
-			      struct v4l2_framebuffer *fbuf)
+static int __videobuf_iolock(struct videobuf_queue *q,
+			     struct videobuf_buffer *vb,
+			     struct v4l2_framebuffer *fbuf)
 {
 	struct videobuf_vmalloc_memory *mem = vb->priv;
 	int pages;
@@ -177,15 +180,13 @@
 
 		dprintk(1, "%s memory method USERPTR\n", __func__);
 
-#if 1
 		if (vb->baddr) {
 			printk(KERN_ERR "USERPTR is currently not supported\n");
 			return -EINVAL;
 		}
-#endif
 
 		/* The only USERPTR currently supported is the one needed for
-		   read() method.
+		 * read() method.
 		 */
 
 		mem->vmalloc = vmalloc_user(pages);
@@ -210,7 +211,7 @@
 		/* Try to remap memory */
 		rc = remap_vmalloc_range(mem->vma, (void *)vb->baddr, 0);
 		if (rc < 0) {
-			printk(KERN_ERR "mmap: remap failed with error %d. ", rc);
+			printk(KERN_ERR "mmap: remap failed with error %d", rc);
 			return -ENOMEM;
 		}
 #endif
@@ -228,69 +229,29 @@
 	return 0;
 }
 
-static int __videobuf_sync(struct videobuf_queue *q,
-			   struct videobuf_buffer *buf)
-{
-	return 0;
-}
-
-static int __videobuf_mmap_free(struct videobuf_queue *q)
-{
-	unsigned int i;
-
-	dprintk(1, "%s\n", __func__);
-	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
-		if (q->bufs[i]) {
-			if (q->bufs[i]->map)
-				return -EBUSY;
-		}
-	}
-
-	return 0;
-}
-
 static int __videobuf_mmap_mapper(struct videobuf_queue *q,
-			 struct vm_area_struct *vma)
+				  struct videobuf_buffer *buf,
+				  struct vm_area_struct *vma)
 {
 	struct videobuf_vmalloc_memory *mem;
 	struct videobuf_mapping *map;
-	unsigned int first;
 	int retval, pages;
-	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
 
 	dprintk(1, "%s\n", __func__);
-	if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
-		return -EINVAL;
-
-	/* look for first buffer to map */
-	for (first = 0; first < VIDEO_MAX_FRAME; first++) {
-		if (NULL == q->bufs[first])
-			continue;
-
-		if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
-			continue;
-		if (q->bufs[first]->boff == offset)
-			break;
-	}
-	if (VIDEO_MAX_FRAME == first) {
-		dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n",
-			(vma->vm_pgoff << PAGE_SHIFT));
-		return -EINVAL;
-	}
 
 	/* create mapping + update buffer list */
 	map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
 	if (NULL == map)
 		return -ENOMEM;
 
-	q->bufs[first]->map = map;
+	buf->map = map;
 	map->start = vma->vm_start;
 	map->end   = vma->vm_end;
 	map->q     = q;
 
-	q->bufs[first]->baddr = vma->vm_start;
+	buf->baddr = vma->vm_start;
 
-	mem = q->bufs[first]->priv;
+	mem = buf->priv;
 	BUG_ON(!mem);
 	MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 
@@ -300,8 +261,7 @@
 		printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
 		goto error;
 	}
-	dprintk(1, "vmalloc is at addr %p (%d pages)\n",
-		mem->vmalloc, pages);
+	dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vmalloc, pages);
 
 	/* Try to remap memory */
 	retval = remap_vmalloc_range(vma, mem->vmalloc, 0);
@@ -315,10 +275,10 @@
 	vma->vm_flags       |= VM_DONTEXPAND | VM_RESERVED;
 	vma->vm_private_data = map;
 
-	dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
+	dprintk(1, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
 		map, q, vma->vm_start, vma->vm_end,
-		(long int) q->bufs[first]->bsize,
-		vma->vm_pgoff, first);
+		(long int)buf->bsize,
+		vma->vm_pgoff, buf->i);
 
 	videobuf_vm_open(vma);
 
@@ -330,69 +290,16 @@
 	return -ENOMEM;
 }
 
-static int __videobuf_copy_to_user ( struct videobuf_queue *q,
-				char __user *data, size_t count,
-				int nonblocking )
-{
-	struct videobuf_vmalloc_memory *mem=q->read_buf->priv;
-	BUG_ON (!mem);
-	MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
-
-	BUG_ON (!mem->vmalloc);
-
-	/* copy to userspace */
-	if (count > q->read_buf->size - q->read_off)
-		count = q->read_buf->size - q->read_off;
-
-	if (copy_to_user(data, mem->vmalloc+q->read_off, count))
-		return -EFAULT;
-
-	return count;
-}
-
-static int __videobuf_copy_stream ( struct videobuf_queue *q,
-				char __user *data, size_t count, size_t pos,
-				int vbihack, int nonblocking )
-{
-	unsigned int  *fc;
-	struct videobuf_vmalloc_memory *mem=q->read_buf->priv;
-	BUG_ON (!mem);
-	MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
-
-	if (vbihack) {
-		/* dirty, undocumented hack -- pass the frame counter
-			* within the last four bytes of each vbi data block.
-			* We need that one to maintain backward compatibility
-			* to all vbi decoding software out there ... */
-		fc  = (unsigned int*)mem->vmalloc;
-		fc += (q->read_buf->size>>2) -1;
-		*fc = q->read_buf->field_count >> 1;
-		dprintk(1,"vbihack: %d\n",*fc);
-	}
-
-	/* copy stuff using the common method */
-	count = __videobuf_copy_to_user (q,data,count,nonblocking);
-
-	if ( (count==-EFAULT) && (0 == pos) )
-		return -EFAULT;
-
-	return count;
-}
-
 static struct videobuf_qtype_ops qops = {
 	.magic        = MAGIC_QTYPE_OPS,
 
 	.alloc        = __videobuf_alloc,
 	.iolock       = __videobuf_iolock,
-	.sync         = __videobuf_sync,
-	.mmap_free    = __videobuf_mmap_free,
 	.mmap_mapper  = __videobuf_mmap_mapper,
-	.video_copy_to_user = __videobuf_copy_to_user,
-	.copy_stream  = __videobuf_copy_stream,
-	.vmalloc      = videobuf_to_vmalloc,
+	.vaddr        = videobuf_to_vmalloc,
 };
 
-void videobuf_queue_vmalloc_init(struct videobuf_queue* q,
+void videobuf_queue_vmalloc_init(struct videobuf_queue *q,
 			 const struct videobuf_queue_ops *ops,
 			 struct device *dev,
 			 spinlock_t *irqlock,
@@ -404,20 +311,19 @@
 	videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
 				 priv, &qops);
 }
-
 EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init);
 
-void *videobuf_to_vmalloc (struct videobuf_buffer *buf)
+void *videobuf_to_vmalloc(struct videobuf_buffer *buf)
 {
-	struct videobuf_vmalloc_memory *mem=buf->priv;
-	BUG_ON (!mem);
-	MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+	struct videobuf_vmalloc_memory *mem = buf->priv;
+	BUG_ON(!mem);
+	MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 
 	return mem->vmalloc;
 }
 EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
 
-void videobuf_vmalloc_free (struct videobuf_buffer *buf)
+void videobuf_vmalloc_free(struct videobuf_buffer *buf)
 {
 	struct videobuf_vmalloc_memory *mem = buf->priv;
 
@@ -442,8 +348,3 @@
 }
 EXPORT_SYMBOL_GPL(videobuf_vmalloc_free);
 
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index cdbe703..e17b6fe 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -13,29 +13,23 @@
  * License, or (at your option) any later version
  */
 #include <linux/module.h>
-#include <linux/delay.h>
 #include <linux/errno.h>
-#include <linux/fs.h>
 #include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/sched.h>
-#include <linux/pci.h>
-#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/font.h>
 #include <linux/version.h>
 #include <linux/mutex.h>
 #include <linux/videodev2.h>
-#include <linux/dma-mapping.h>
-#include <linux/interrupt.h>
 #include <linux/kthread.h>
-#include <linux/highmem.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
 #include <linux/freezer.h>
+#endif
 #include <media/videobuf-vmalloc.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
-#include "font.h"
+#include <media/v4l2-common.h>
 
 #define VIVI_MODULE_NAME "vivi"
 
@@ -44,8 +38,11 @@
 #define WAKE_DENOMINATOR 1001
 #define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
 
+#define MAX_WIDTH 1920
+#define MAX_HEIGHT 1200
+
 #define VIVI_MAJOR_VERSION 0
-#define VIVI_MINOR_VERSION 6
+#define VIVI_MINOR_VERSION 7
 #define VIVI_RELEASE 0
 #define VIVI_VERSION \
 	KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
@@ -70,56 +67,8 @@
 module_param(vid_limit, uint, 0644);
 MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
 
-
-/* supported controls */
-static struct v4l2_queryctrl vivi_qctrl[] = {
-	{
-		.id            = V4L2_CID_AUDIO_VOLUME,
-		.name          = "Volume",
-		.minimum       = 0,
-		.maximum       = 65535,
-		.step          = 65535/100,
-		.default_value = 65535,
-		.flags         = V4L2_CTRL_FLAG_SLIDER,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-	}, {
-		.id            = V4L2_CID_BRIGHTNESS,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Brightness",
-		.minimum       = 0,
-		.maximum       = 255,
-		.step          = 1,
-		.default_value = 127,
-		.flags         = V4L2_CTRL_FLAG_SLIDER,
-	}, {
-		.id            = V4L2_CID_CONTRAST,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Contrast",
-		.minimum       = 0,
-		.maximum       = 255,
-		.step          = 0x1,
-		.default_value = 0x10,
-		.flags         = V4L2_CTRL_FLAG_SLIDER,
-	}, {
-		.id            = V4L2_CID_SATURATION,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Saturation",
-		.minimum       = 0,
-		.maximum       = 255,
-		.step          = 0x1,
-		.default_value = 127,
-		.flags         = V4L2_CTRL_FLAG_SLIDER,
-	}, {
-		.id            = V4L2_CID_HUE,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Hue",
-		.minimum       = -128,
-		.maximum       = 127,
-		.step          = 0x1,
-		.default_value = 0,
-		.flags         = V4L2_CTRL_FLAG_SLIDER,
-	}
-};
+/* Global font descriptor */
+static const u8 *font8x16;
 
 #define dprintk(dev, level, fmt, arg...) \
 	v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
@@ -214,41 +163,38 @@
 	struct list_head           vivi_devlist;
 	struct v4l2_device 	   v4l2_dev;
 
+	/* controls */
+	int 			   brightness;
+	int 			   contrast;
+	int 			   saturation;
+	int 			   hue;
+	int 			   volume;
+
 	spinlock_t                 slock;
 	struct mutex		   mutex;
 
-	int                        users;
-
 	/* various device info */
 	struct video_device        *vfd;
 
 	struct vivi_dmaqueue       vidq;
 
 	/* Several counters */
-	int                        h, m, s, ms;
+	unsigned 		   ms;
 	unsigned long              jiffies;
-	char                       timestr[13];
 
 	int			   mv_count;	/* Controls bars movement */
 
 	/* Input Number */
 	int			   input;
 
-	/* Control 'registers' */
-	int 			   qctl_regs[ARRAY_SIZE(vivi_qctrl)];
-};
-
-struct vivi_fh {
-	struct vivi_dev            *dev;
-
 	/* video capture */
 	struct vivi_fmt            *fmt;
 	unsigned int               width, height;
 	struct videobuf_queue      vb_vidq;
 
-	enum v4l2_buf_type         type;
-	unsigned char              bars[8][3];
-	int			   input; 	/* Input Number on bars */
+	unsigned long 		   generating;
+	u8 			   bars[9][3];
+	u8 			   line[MAX_WIDTH * 4];
 };
 
 /* ------------------------------------------------------------------
@@ -259,19 +205,20 @@
 
 enum colors {
 	WHITE,
-	AMBAR,
+	AMBER,
 	CYAN,
 	GREEN,
 	MAGENTA,
 	RED,
 	BLUE,
 	BLACK,
+	TEXT_BLACK,
 };
 
-	/* R   G   B */
+/* R   G   B */
 #define COLOR_WHITE	{204, 204, 204}
-#define COLOR_AMBAR	{208, 208,   0}
-#define COLOR_CIAN	{  0, 206, 206}
+#define COLOR_AMBER	{208, 208,   0}
+#define COLOR_CYAN	{  0, 206, 206}
 #define	COLOR_GREEN	{  0, 239,   0}
 #define COLOR_MAGENTA	{239,   0, 239}
 #define COLOR_RED	{205,   0,   0}
@@ -279,56 +226,24 @@
 #define COLOR_BLACK	{  0,   0,   0}
 
 struct bar_std {
-	u8 bar[8][3];
+	u8 bar[9][3];
 };
 
 /* Maximum number of bars are 10 - otherwise, the input print code
    should be modified */
 static struct bar_std bars[] = {
 	{	/* Standard ITU-R color bar sequence */
-		{
-			COLOR_WHITE,
-			COLOR_AMBAR,
-			COLOR_CIAN,
-			COLOR_GREEN,
-			COLOR_MAGENTA,
-			COLOR_RED,
-			COLOR_BLUE,
-			COLOR_BLACK,
-		}
+		{ COLOR_WHITE, COLOR_AMBER, COLOR_CYAN, COLOR_GREEN,
+		  COLOR_MAGENTA, COLOR_RED, COLOR_BLUE, COLOR_BLACK, COLOR_BLACK }
 	}, {
-		{
-			COLOR_WHITE,
-			COLOR_AMBAR,
-			COLOR_BLACK,
-			COLOR_WHITE,
-			COLOR_AMBAR,
-			COLOR_BLACK,
-			COLOR_WHITE,
-			COLOR_AMBAR,
-		}
+		{ COLOR_WHITE, COLOR_AMBER, COLOR_BLACK, COLOR_WHITE,
+		  COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, COLOR_AMBER, COLOR_BLACK }
 	}, {
-		{
-			COLOR_WHITE,
-			COLOR_CIAN,
-			COLOR_BLACK,
-			COLOR_WHITE,
-			COLOR_CIAN,
-			COLOR_BLACK,
-			COLOR_WHITE,
-			COLOR_CIAN,
-		}
+		{ COLOR_WHITE, COLOR_CYAN, COLOR_BLACK, COLOR_WHITE,
+		  COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, COLOR_CYAN, COLOR_BLACK }
 	}, {
-		{
-			COLOR_WHITE,
-			COLOR_GREEN,
-			COLOR_BLACK,
-			COLOR_WHITE,
-			COLOR_GREEN,
-			COLOR_BLACK,
-			COLOR_WHITE,
-			COLOR_GREEN,
-		}
+		{ COLOR_WHITE, COLOR_GREEN, COLOR_BLACK, COLOR_WHITE,
+		  COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, COLOR_GREEN, COLOR_BLACK }
 	},
 };
 
@@ -344,21 +259,18 @@
 	(((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
 
 /* precalculate color bar values to speed up rendering */
-static void precalculate_bars(struct vivi_fh *fh)
+static void precalculate_bars(struct vivi_dev *dev)
 {
-	struct vivi_dev *dev = fh->dev;
-	unsigned char r, g, b;
+	u8 r, g, b;
 	int k, is_yuv;
 
-	fh->input = dev->input;
-
-	for (k = 0; k < 8; k++) {
-		r = bars[fh->input].bar[k][0];
-		g = bars[fh->input].bar[k][1];
-		b = bars[fh->input].bar[k][2];
+	for (k = 0; k < 9; k++) {
+		r = bars[dev->input].bar[k][0];
+		g = bars[dev->input].bar[k][1];
+		b = bars[dev->input].bar[k][2];
 		is_yuv = 0;
 
-		switch (fh->fmt->fourcc) {
+		switch (dev->fmt->fourcc) {
 		case V4L2_PIX_FMT_YUYV:
 		case V4L2_PIX_FMT_UYVY:
 			is_yuv = 1;
@@ -378,16 +290,15 @@
 		}
 
 		if (is_yuv) {
-			fh->bars[k][0] = TO_Y(r, g, b);	/* Luma */
-			fh->bars[k][1] = TO_U(r, g, b);	/* Cb */
-			fh->bars[k][2] = TO_V(r, g, b);	/* Cr */
+			dev->bars[k][0] = TO_Y(r, g, b);	/* Luma */
+			dev->bars[k][1] = TO_U(r, g, b);	/* Cb */
+			dev->bars[k][2] = TO_V(r, g, b);	/* Cr */
 		} else {
-			fh->bars[k][0] = r;
-			fh->bars[k][1] = g;
-			fh->bars[k][2] = b;
+			dev->bars[k][0] = r;
+			dev->bars[k][1] = g;
+			dev->bars[k][2] = b;
 		}
 	}
-
 }
 
 #define TSTAMP_MIN_Y	24
@@ -395,20 +306,20 @@
 #define TSTAMP_INPUT_X	10
 #define TSTAMP_MIN_X	(54 + TSTAMP_INPUT_X)
 
-static void gen_twopix(struct vivi_fh *fh, unsigned char *buf, int colorpos)
+static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos)
 {
-	unsigned char r_y, g_u, b_v;
-	unsigned char *p;
+	u8 r_y, g_u, b_v;
 	int color;
+	u8 *p;
 
-	r_y = fh->bars[colorpos][0]; /* R or precalculated Y */
-	g_u = fh->bars[colorpos][1]; /* G or precalculated U */
-	b_v = fh->bars[colorpos][2]; /* B or precalculated V */
+	r_y = dev->bars[colorpos][0]; /* R or precalculated Y */
+	g_u = dev->bars[colorpos][1]; /* G or precalculated U */
+	b_v = dev->bars[colorpos][2]; /* B or precalculated V */
 
 	for (color = 0; color < 4; color++) {
 		p = buf + color;
 
-		switch (fh->fmt->fourcc) {
+		switch (dev->fmt->fourcc) {
 		case V4L2_PIX_FMT_YUYV:
 			switch (color) {
 			case 0:
@@ -489,123 +400,88 @@
 	}
 }
 
-static void gen_line(struct vivi_fh *fh, char *basep, int inipos, int wmax,
-		int hmax, int line, int count, char *timestr)
+static void precalculate_line(struct vivi_dev *dev)
 {
-	int  w, i, j;
-	int pos = inipos;
-	char *s;
-	u8 chr;
+	int w;
 
-	/* We will just duplicate the second pixel at the packet */
-	wmax /= 2;
+	for (w = 0; w < dev->width * 2; w += 2) {
+		int colorpos = (w / (dev->width / 8) % 8);
 
-	/* Generate a standard color bar pattern */
-	for (w = 0; w < wmax; w++) {
-		int colorpos = ((w + count) * 8/(wmax + 1)) % 8;
-
-		gen_twopix(fh, basep + pos, colorpos);
-		pos += 4; /* only 16 bpp supported for now */
+		gen_twopix(dev, dev->line + w * 2, colorpos);
 	}
+}
 
-	/* Prints input entry number */
+static void gen_text(struct vivi_dev *dev, char *basep,
+					int y, int x, char *text)
+{
+	int line;
 
-	/* Checks if it is possible to input number */
-	if (TSTAMP_MAX_Y >= hmax)
-		goto end;
-
-	if (TSTAMP_INPUT_X + strlen(timestr) >= wmax)
-		goto end;
-
-	if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) {
-		chr = rom8x16_bits[fh->input * 16 + line - TSTAMP_MIN_Y];
-		pos = TSTAMP_INPUT_X;
-		for (i = 0; i < 7; i++) {
-			/* Draw white font on black background */
-			if (chr & 1 << (7 - i))
-				gen_twopix(fh, basep + pos, WHITE);
-			else
-				gen_twopix(fh, basep + pos, BLACK);
-			pos += 2;
-		}
-	}
-
-	/* Checks if it is possible to show timestamp */
-	if (TSTAMP_MIN_X + strlen(timestr) >= wmax)
-		goto end;
+	/* Checks if it is possible to show string */
+	if (y + 16 >= dev->height || x + strlen(text) * 8 >= dev->width)
+		return;
 
 	/* Print stream time */
-	if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) {
-		j = TSTAMP_MIN_X;
-		for (s = timestr; *s; s++) {
-			chr = rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y];
-			for (i = 0; i < 7; i++) {
-				pos = inipos + j * 2;
+	for (line = y; line < y + 16; line++) {
+		int j = 0;
+		char *pos = basep + line * dev->width * 2 + x * 2;
+		char *s;
+
+		for (s = text; *s; s++) {
+			u8 chr = font8x16[*s * 16 + line - y];
+			int i;
+
+			for (i = 0; i < 7; i++, j++) {
 				/* Draw white font on black background */
-				if (chr & 1 << (7 - i))
-					gen_twopix(fh, basep + pos, WHITE);
+				if (chr & (1 << (7 - i)))
+					gen_twopix(dev, pos + j * 2, WHITE);
 				else
-					gen_twopix(fh, basep + pos, BLACK);
-				j++;
+					gen_twopix(dev, pos + j * 2, TEXT_BLACK);
 			}
 		}
 	}
-
-end:
-	return;
 }
 
-static void vivi_fillbuff(struct vivi_fh *fh, struct vivi_buffer *buf)
+static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
 {
-	struct vivi_dev *dev = fh->dev;
-	int h , pos = 0;
-	int hmax  = buf->vb.height;
-	int wmax  = buf->vb.width;
+	int hmax = buf->vb.height;
+	int wmax = buf->vb.width;
 	struct timeval ts;
-	char *tmpbuf;
 	void *vbuf = videobuf_to_vmalloc(&buf->vb);
+	unsigned ms;
+	char str[100];
+	int h, line = 1;
 
 	if (!vbuf)
 		return;
 
-	tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
-	if (!tmpbuf)
-		return;
-
-	for (h = 0; h < hmax; h++) {
-		gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count,
-			 dev->timestr);
-		memcpy(vbuf + pos, tmpbuf, wmax * 2);
-		pos += wmax*2;
-	}
-
-	dev->mv_count++;
-
-	kfree(tmpbuf);
+	for (h = 0; h < hmax; h++)
+		memcpy(vbuf + h * wmax * 2, dev->line + (dev->mv_count % wmax) * 2, wmax * 2);
 
 	/* Updates stream time */
 
-	dev->ms += jiffies_to_msecs(jiffies-dev->jiffies);
+	dev->ms += jiffies_to_msecs(jiffies - dev->jiffies);
 	dev->jiffies = jiffies;
-	if (dev->ms >= 1000) {
-		dev->ms -= 1000;
-		dev->s++;
-		if (dev->s >= 60) {
-			dev->s -= 60;
-			dev->m++;
-			if (dev->m > 60) {
-				dev->m -= 60;
-				dev->h++;
-				if (dev->h > 24)
-					dev->h -= 24;
-			}
-		}
-	}
-	sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
-			dev->h, dev->m, dev->s, dev->ms);
+	ms = dev->ms;
+	snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d ",
+			(ms / (60 * 60 * 1000)) % 24,
+			(ms / (60 * 1000)) % 60,
+			(ms / 1000) % 60,
+			ms % 1000);
+	gen_text(dev, vbuf, line++ * 16, 16, str);
+	snprintf(str, sizeof(str), " %dx%d, input %d ",
+			dev->width, dev->height, dev->input);
+	gen_text(dev, vbuf, line++ * 16, 16, str);
 
-	dprintk(dev, 2, "vivifill at %s: Buffer 0x%08lx size= %d\n",
-			dev->timestr, (unsigned long)tmpbuf, pos);
+	snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ",
+			dev->brightness,
+			dev->contrast,
+			dev->saturation,
+			dev->hue);
+	gen_text(dev, vbuf, line++ * 16, 16, str);
+	snprintf(str, sizeof(str), " volume %3d ", dev->volume);
+	gen_text(dev, vbuf, line++ * 16, 16, str);
+
+	dev->mv_count += 2;
 
 	/* Advice that buffer was filled */
 	buf->vb.field_count++;
@@ -614,12 +490,10 @@
 	buf->vb.state = VIDEOBUF_DONE;
 }
 
-static void vivi_thread_tick(struct vivi_fh *fh)
+static void vivi_thread_tick(struct vivi_dev *dev)
 {
-	struct vivi_buffer *buf;
-	struct vivi_dev *dev = fh->dev;
 	struct vivi_dmaqueue *dma_q = &dev->vidq;
-
+	struct vivi_buffer *buf;
 	unsigned long flags = 0;
 
 	dprintk(dev, 1, "Thread tick\n");
@@ -642,22 +516,20 @@
 	do_gettimeofday(&buf->vb.ts);
 
 	/* Fill buffer */
-	vivi_fillbuff(fh, buf);
+	vivi_fillbuff(dev, buf);
 	dprintk(dev, 1, "filled buffer %p\n", buf);
 
 	wake_up(&buf->vb.done);
 	dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i);
 unlock:
 	spin_unlock_irqrestore(&dev->slock, flags);
-	return;
 }
 
 #define frames_to_ms(frames)					\
 	((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR)
 
-static void vivi_sleep(struct vivi_fh *fh)
+static void vivi_sleep(struct vivi_dev *dev)
 {
-	struct vivi_dev *dev = fh->dev;
 	struct vivi_dmaqueue *dma_q = &dev->vidq;
 	int timeout;
 	DECLARE_WAITQUEUE(wait, current);
@@ -672,7 +544,7 @@
 	/* Calculate time to wake up */
 	timeout = msecs_to_jiffies(frames_to_ms(1));
 
-	vivi_thread_tick(fh);
+	vivi_thread_tick(dev);
 
 	schedule_timeout_interruptible(timeout);
 
@@ -683,15 +555,14 @@
 
 static int vivi_thread(void *data)
 {
-	struct vivi_fh  *fh = data;
-	struct vivi_dev *dev = fh->dev;
+	struct vivi_dev *dev = data;
 
 	dprintk(dev, 1, "thread started\n");
 
 	set_freezable();
 
 	for (;;) {
-		vivi_sleep(fh);
+		vivi_sleep(dev);
 
 		if (kthread_should_stop())
 			break;
@@ -700,39 +571,61 @@
 	return 0;
 }
 
-static int vivi_start_thread(struct vivi_fh *fh)
+static void vivi_start_generating(struct file *file)
 {
-	struct vivi_dev *dev = fh->dev;
+	struct vivi_dev *dev = video_drvdata(file);
 	struct vivi_dmaqueue *dma_q = &dev->vidq;
 
-	dma_q->frame = 0;
-	dma_q->ini_jiffies = jiffies;
-
 	dprintk(dev, 1, "%s\n", __func__);
 
-	dma_q->kthread = kthread_run(vivi_thread, fh, "vivi");
+	if (test_and_set_bit(0, &dev->generating))
+		return;
+	file->private_data = dev;
+
+	/* Resets frame counters */
+	dev->ms = 0;
+	dev->mv_count = 0;
+	dev->jiffies = jiffies;
+
+	dma_q->frame = 0;
+	dma_q->ini_jiffies = jiffies;
+	dma_q->kthread = kthread_run(vivi_thread, dev, dev->v4l2_dev.name);
 
 	if (IS_ERR(dma_q->kthread)) {
 		v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
-		return PTR_ERR(dma_q->kthread);
+		clear_bit(0, &dev->generating);
+		return;
 	}
 	/* Wakes thread */
 	wake_up_interruptible(&dma_q->wq);
 
 	dprintk(dev, 1, "returning from %s\n", __func__);
-	return 0;
 }
 
-static void vivi_stop_thread(struct vivi_dmaqueue  *dma_q)
+static void vivi_stop_generating(struct file *file)
 {
-	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
+	struct vivi_dev *dev = video_drvdata(file);
+	struct vivi_dmaqueue *dma_q = &dev->vidq;
 
 	dprintk(dev, 1, "%s\n", __func__);
+
+	if (!file->private_data)
+		return;
+	if (!test_and_clear_bit(0, &dev->generating))
+		return;
+
 	/* shutdown control thread */
 	if (dma_q->kthread) {
 		kthread_stop(dma_q->kthread);
 		dma_q->kthread = NULL;
 	}
+	videobuf_stop(&dev->vb_vidq);
+	videobuf_mmap_free(&dev->vb_vidq);
+}
+
+static int vivi_is_generating(struct vivi_dev *dev)
+{
+	return test_bit(0, &dev->generating);
 }
 
 /* ------------------------------------------------------------------
@@ -741,10 +634,9 @@
 static int
 buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
 {
-	struct vivi_fh  *fh = vq->priv_data;
-	struct vivi_dev *dev  = fh->dev;
+	struct vivi_dev *dev = vq->priv_data;
 
-	*size = fh->width*fh->height*2;
+	*size = dev->width * dev->height * 2;
 
 	if (0 == *count)
 		*count = 32;
@@ -760,49 +652,43 @@
 
 static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
 {
-	struct vivi_fh  *fh = vq->priv_data;
-	struct vivi_dev *dev  = fh->dev;
+	struct vivi_dev *dev = vq->priv_data;
 
 	dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state);
 
-	if (in_interrupt())
-		BUG();
-
 	videobuf_vmalloc_free(&buf->vb);
 	dprintk(dev, 1, "free_buffer: freed\n");
 	buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
 
-#define norm_maxw() 1024
-#define norm_maxh() 768
 static int
 buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
 						enum v4l2_field field)
 {
-	struct vivi_fh     *fh  = vq->priv_data;
-	struct vivi_dev    *dev = fh->dev;
+	struct vivi_dev *dev = vq->priv_data;
 	struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
 	int rc;
 
 	dprintk(dev, 1, "%s, field=%d\n", __func__, field);
 
-	BUG_ON(NULL == fh->fmt);
+	BUG_ON(NULL == dev->fmt);
 
-	if (fh->width  < 48 || fh->width  > norm_maxw() ||
-	    fh->height < 32 || fh->height > norm_maxh())
+	if (dev->width  < 48 || dev->width  > MAX_WIDTH ||
+	    dev->height < 32 || dev->height > MAX_HEIGHT)
 		return -EINVAL;
 
-	buf->vb.size = fh->width*fh->height*2;
-	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+	buf->vb.size = dev->width * dev->height * 2;
+	if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
 		return -EINVAL;
 
 	/* These properties only change when queue is idle, see s_fmt */
-	buf->fmt       = fh->fmt;
-	buf->vb.width  = fh->width;
-	buf->vb.height = fh->height;
+	buf->fmt       = dev->fmt;
+	buf->vb.width  = dev->width;
+	buf->vb.height = dev->height;
 	buf->vb.field  = field;
 
-	precalculate_bars(fh);
+	precalculate_bars(dev);
+	precalculate_line(dev);
 
 	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
 		rc = videobuf_iolock(vq, &buf->vb, NULL);
@@ -811,7 +697,6 @@
 	}
 
 	buf->vb.state = VIDEOBUF_PREPARED;
-
 	return 0;
 
 fail:
@@ -822,9 +707,8 @@
 static void
 buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 {
-	struct vivi_buffer    *buf  = container_of(vb, struct vivi_buffer, vb);
-	struct vivi_fh        *fh   = vq->priv_data;
-	struct vivi_dev       *dev  = fh->dev;
+	struct vivi_dev *dev = vq->priv_data;
+	struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
 	struct vivi_dmaqueue *vidq = &dev->vidq;
 
 	dprintk(dev, 1, "%s\n", __func__);
@@ -836,9 +720,8 @@
 static void buffer_release(struct videobuf_queue *vq,
 			   struct videobuf_buffer *vb)
 {
-	struct vivi_buffer   *buf  = container_of(vb, struct vivi_buffer, vb);
-	struct vivi_fh       *fh   = vq->priv_data;
-	struct vivi_dev      *dev  = (struct vivi_dev *)fh->dev;
+	struct vivi_dev *dev = vq->priv_data;
+	struct vivi_buffer *buf  = container_of(vb, struct vivi_buffer, vb);
 
 	dprintk(dev, 1, "%s\n", __func__);
 
@@ -858,16 +741,14 @@
 static int vidioc_querycap(struct file *file, void  *priv,
 					struct v4l2_capability *cap)
 {
-	struct vivi_fh  *fh  = priv;
-	struct vivi_dev *dev = fh->dev;
+	struct vivi_dev *dev = video_drvdata(file);
 
 	strcpy(cap->driver, "vivi");
 	strcpy(cap->card, "vivi");
 	strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
 	cap->version = VIVI_VERSION;
-	cap->capabilities =	V4L2_CAP_VIDEO_CAPTURE |
-				V4L2_CAP_STREAMING     |
-				V4L2_CAP_READWRITE;
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \
+			    V4L2_CAP_READWRITE;
 	return 0;
 }
 
@@ -889,28 +770,25 @@
 static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 					struct v4l2_format *f)
 {
-	struct vivi_fh *fh = priv;
+	struct vivi_dev *dev = video_drvdata(file);
 
-	f->fmt.pix.width        = fh->width;
-	f->fmt.pix.height       = fh->height;
-	f->fmt.pix.field        = fh->vb_vidq.field;
-	f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+	f->fmt.pix.width        = dev->width;
+	f->fmt.pix.height       = dev->height;
+	f->fmt.pix.field        = dev->vb_vidq.field;
+	f->fmt.pix.pixelformat  = dev->fmt->fourcc;
 	f->fmt.pix.bytesperline =
-		(f->fmt.pix.width * fh->fmt->depth) >> 3;
+		(f->fmt.pix.width * dev->fmt->depth) >> 3;
 	f->fmt.pix.sizeimage =
 		f->fmt.pix.height * f->fmt.pix.bytesperline;
-
-	return (0);
+	return 0;
 }
 
 static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 			struct v4l2_format *f)
 {
-	struct vivi_fh  *fh  = priv;
-	struct vivi_dev *dev = fh->dev;
+	struct vivi_dev *dev = video_drvdata(file);
 	struct vivi_fmt *fmt;
 	enum v4l2_field field;
-	unsigned int maxw, maxh;
 
 	fmt = get_format(f);
 	if (!fmt) {
@@ -928,113 +806,109 @@
 		return -EINVAL;
 	}
 
-	maxw  = norm_maxw();
-	maxh  = norm_maxh();
-
 	f->fmt.pix.field = field;
-	v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2,
-			      &f->fmt.pix.height, 32, maxh, 0, 0);
+	v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 2,
+			      &f->fmt.pix.height, 32, MAX_HEIGHT, 0, 0);
 	f->fmt.pix.bytesperline =
 		(f->fmt.pix.width * fmt->depth) >> 3;
 	f->fmt.pix.sizeimage =
 		f->fmt.pix.height * f->fmt.pix.bytesperline;
-
 	return 0;
 }
 
-/*FIXME: This seems to be generic enough to be at videodev2 */
 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 					struct v4l2_format *f)
 {
-	struct vivi_fh *fh = priv;
-	struct videobuf_queue *q = &fh->vb_vidq;
+	struct vivi_dev *dev = video_drvdata(file);
+	struct videobuf_queue *q = &dev->vb_vidq;
 
-	int ret = vidioc_try_fmt_vid_cap(file, fh, f);
+	int ret = vidioc_try_fmt_vid_cap(file, priv, f);
 	if (ret < 0)
 		return ret;
 
 	mutex_lock(&q->vb_lock);
 
-	if (videobuf_queue_is_busy(&fh->vb_vidq)) {
-		dprintk(fh->dev, 1, "%s queue busy\n", __func__);
+	if (vivi_is_generating(dev)) {
+		dprintk(dev, 1, "%s device busy\n", __func__);
 		ret = -EBUSY;
 		goto out;
 	}
 
-	fh->fmt           = get_format(f);
-	fh->width         = f->fmt.pix.width;
-	fh->height        = f->fmt.pix.height;
-	fh->vb_vidq.field = f->fmt.pix.field;
-	fh->type          = f->type;
-
+	dev->fmt = get_format(f);
+	dev->width = f->fmt.pix.width;
+	dev->height = f->fmt.pix.height;
+	dev->vb_vidq.field = f->fmt.pix.field;
 	ret = 0;
 out:
 	mutex_unlock(&q->vb_lock);
-
 	return ret;
 }
 
 static int vidioc_reqbufs(struct file *file, void *priv,
 			  struct v4l2_requestbuffers *p)
 {
-	struct vivi_fh  *fh = priv;
+	struct vivi_dev *dev = video_drvdata(file);
 
-	return (videobuf_reqbufs(&fh->vb_vidq, p));
+	return videobuf_reqbufs(&dev->vb_vidq, p);
 }
 
 static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
-	struct vivi_fh  *fh = priv;
+	struct vivi_dev *dev = video_drvdata(file);
 
-	return (videobuf_querybuf(&fh->vb_vidq, p));
+	return videobuf_querybuf(&dev->vb_vidq, p);
 }
 
 static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
-	struct vivi_fh *fh = priv;
+	struct vivi_dev *dev = video_drvdata(file);
 
-	return (videobuf_qbuf(&fh->vb_vidq, p));
+	return videobuf_qbuf(&dev->vb_vidq, p);
 }
 
 static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
-	struct vivi_fh  *fh = priv;
+	struct vivi_dev *dev = video_drvdata(file);
 
-	return (videobuf_dqbuf(&fh->vb_vidq, p,
-				file->f_flags & O_NONBLOCK));
+	return videobuf_dqbuf(&dev->vb_vidq, p,
+				file->f_flags & O_NONBLOCK);
 }
 
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
 static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
 {
-	struct vivi_fh  *fh = priv;
+	struct vivi_dev *dev = video_drvdata(file);
 
-	return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
+	return videobuf_cgmbuf(&dev->vb_vidq, mbuf, 8);
 }
 #endif
 
 static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 {
-	struct vivi_fh  *fh = priv;
+	struct vivi_dev *dev = video_drvdata(file);
+	int ret;
 
-	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
-	if (i != fh->type)
-		return -EINVAL;
+	ret = videobuf_streamon(&dev->vb_vidq);
+	if (ret)
+		return ret;
 
-	return videobuf_streamon(&fh->vb_vidq);
+	vivi_start_generating(file);
+	return 0;
 }
 
 static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
 {
-	struct vivi_fh  *fh = priv;
+	struct vivi_dev *dev = video_drvdata(file);
+	int ret;
 
-	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
-	if (i != fh->type)
-		return -EINVAL;
-
-	return videobuf_streamoff(&fh->vb_vidq);
+	ret = videobuf_streamoff(&dev->vb_vidq);
+	if (!ret)
+		vivi_stop_generating(file);
+	return ret;
 }
 
 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
@@ -1052,80 +926,104 @@
 	inp->type = V4L2_INPUT_TYPE_CAMERA;
 	inp->std = V4L2_STD_525_60;
 	sprintf(inp->name, "Camera %u", inp->index);
-
-	return (0);
+	return 0;
 }
 
 static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
 {
-	struct vivi_fh *fh = priv;
-	struct vivi_dev *dev = fh->dev;
+	struct vivi_dev *dev = video_drvdata(file);
 
 	*i = dev->input;
-
-	return (0);
+	return 0;
 }
+
 static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
 {
-	struct vivi_fh *fh = priv;
-	struct vivi_dev *dev = fh->dev;
+	struct vivi_dev *dev = video_drvdata(file);
 
 	if (i >= NUM_INPUTS)
 		return -EINVAL;
 
 	dev->input = i;
-	precalculate_bars(fh);
-
-	return (0);
+	precalculate_bars(dev);
+	precalculate_line(dev);
+	return 0;
 }
 
-	/* --- controls ---------------------------------------------- */
+/* --- controls ---------------------------------------------- */
 static int vidioc_queryctrl(struct file *file, void *priv,
 			    struct v4l2_queryctrl *qc)
 {
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
-		if (qc->id && qc->id == vivi_qctrl[i].id) {
-			memcpy(qc, &(vivi_qctrl[i]),
-				sizeof(*qc));
-			return (0);
-		}
-
+	switch (qc->id) {
+	case V4L2_CID_AUDIO_VOLUME:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 200);
+	case V4L2_CID_BRIGHTNESS:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 127);
+	case V4L2_CID_CONTRAST:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 16);
+	case V4L2_CID_SATURATION:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 127);
+	case V4L2_CID_HUE:
+		return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
+	}
 	return -EINVAL;
 }
 
 static int vidioc_g_ctrl(struct file *file, void *priv,
 			 struct v4l2_control *ctrl)
 {
-	struct vivi_fh *fh = priv;
-	struct vivi_dev *dev = fh->dev;
-	int i;
+	struct vivi_dev *dev = video_drvdata(file);
 
-	for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
-		if (ctrl->id == vivi_qctrl[i].id) {
-			ctrl->value = dev->qctl_regs[i];
-			return 0;
-		}
-
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_VOLUME:
+		ctrl->value = dev->volume;
+		return 0;
+	case V4L2_CID_BRIGHTNESS:
+		ctrl->value = dev->brightness;
+		return 0;
+	case V4L2_CID_CONTRAST:
+		ctrl->value = dev->contrast;
+		return 0;
+	case V4L2_CID_SATURATION:
+		ctrl->value = dev->saturation;
+		return 0;
+	case V4L2_CID_HUE:
+		ctrl->value = dev->hue;
+		return 0;
+	}
 	return -EINVAL;
 }
+
 static int vidioc_s_ctrl(struct file *file, void *priv,
 				struct v4l2_control *ctrl)
 {
-	struct vivi_fh *fh = priv;
-	struct vivi_dev *dev = fh->dev;
-	int i;
+	struct vivi_dev *dev = video_drvdata(file);
+	struct v4l2_queryctrl qc;
+	int err;
 
-	for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
-		if (ctrl->id == vivi_qctrl[i].id) {
-			if (ctrl->value < vivi_qctrl[i].minimum ||
-			    ctrl->value > vivi_qctrl[i].maximum) {
-				return -ERANGE;
-			}
-			dev->qctl_regs[i] = ctrl->value;
-			return 0;
-		}
+	qc.id = ctrl->id;
+	err = vidioc_queryctrl(file, priv, &qc);
+	if (err < 0)
+		return err;
+	if (ctrl->value < qc.minimum || ctrl->value > qc.maximum)
+		return -ERANGE;
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_VOLUME:
+		dev->volume = ctrl->value;
+		return 0;
+	case V4L2_CID_BRIGHTNESS:
+		dev->brightness = ctrl->value;
+		return 0;
+	case V4L2_CID_CONTRAST:
+		dev->contrast = ctrl->value;
+		return 0;
+	case V4L2_CID_SATURATION:
+		dev->saturation = ctrl->value;
+		return 0;
+	case V4L2_CID_HUE:
+		dev->hue = ctrl->value;
+		return 0;
+	}
 	return -EINVAL;
 }
 
@@ -1133,134 +1031,58 @@
 	File operations for the device
    ------------------------------------------------------------------*/
 
-static int vivi_open(struct file *file)
-{
-	struct vivi_dev *dev = video_drvdata(file);
-	struct vivi_fh *fh = NULL;
-	int retval = 0;
-
-	mutex_lock(&dev->mutex);
-	dev->users++;
-
-	if (dev->users > 1) {
-		dev->users--;
-		mutex_unlock(&dev->mutex);
-		return -EBUSY;
-	}
-
-	dprintk(dev, 1, "open %s type=%s users=%d\n",
-		video_device_node_name(dev->vfd),
-		v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
-
-	/* allocate + initialize per filehandle data */
-	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-	if (NULL == fh) {
-		dev->users--;
-		retval = -ENOMEM;
-	}
-	mutex_unlock(&dev->mutex);
-
-	if (retval)
-		return retval;
-
-	file->private_data = fh;
-	fh->dev      = dev;
-
-	fh->type     = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	fh->fmt      = &formats[0];
-	fh->width    = 640;
-	fh->height   = 480;
-
-	/* Resets frame counters */
-	dev->h = 0;
-	dev->m = 0;
-	dev->s = 0;
-	dev->ms = 0;
-	dev->mv_count = 0;
-	dev->jiffies = jiffies;
-	sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
-			dev->h, dev->m, dev->s, dev->ms);
-
-	videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops,
-			NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED,
-			sizeof(struct vivi_buffer), fh);
-
-	vivi_start_thread(fh);
-
-	return 0;
-}
-
 static ssize_t
 vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 {
-	struct vivi_fh *fh = file->private_data;
+	struct vivi_dev *dev = video_drvdata(file);
 
-	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-		return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0,
+	vivi_start_generating(file);
+	return videobuf_read_stream(&dev->vb_vidq, data, count, ppos, 0,
 					file->f_flags & O_NONBLOCK);
-	}
-	return 0;
 }
 
 static unsigned int
 vivi_poll(struct file *file, struct poll_table_struct *wait)
 {
-	struct vivi_fh        *fh = file->private_data;
-	struct vivi_dev       *dev = fh->dev;
-	struct videobuf_queue *q = &fh->vb_vidq;
+	struct vivi_dev *dev = video_drvdata(file);
+	struct videobuf_queue *q = &dev->vb_vidq;
 
 	dprintk(dev, 1, "%s\n", __func__);
 
-	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
-		return POLLERR;
-
+	vivi_start_generating(file);
 	return videobuf_poll_stream(file, q, wait);
 }
 
 static int vivi_close(struct file *file)
 {
-	struct vivi_fh         *fh = file->private_data;
-	struct vivi_dev *dev       = fh->dev;
-	struct vivi_dmaqueue *vidq = &dev->vidq;
 	struct video_device  *vdev = video_devdata(file);
+	struct vivi_dev *dev = video_drvdata(file);
 
-	vivi_stop_thread(vidq);
-	videobuf_stop(&fh->vb_vidq);
-	videobuf_mmap_free(&fh->vb_vidq);
+	vivi_stop_generating(file);
 
-	kfree(fh);
-
-	mutex_lock(&dev->mutex);
-	dev->users--;
-	mutex_unlock(&dev->mutex);
-
-	dprintk(dev, 1, "close called (dev=%s, users=%d)\n",
-		video_device_node_name(vdev), dev->users);
-
+	dprintk(dev, 1, "close called (dev=%s)\n",
+		video_device_node_name(vdev));
 	return 0;
 }
 
 static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	struct vivi_fh  *fh = file->private_data;
-	struct vivi_dev *dev = fh->dev;
+	struct vivi_dev *dev = video_drvdata(file);
 	int ret;
 
 	dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
 
-	ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+	ret = videobuf_mmap_mapper(&dev->vb_vidq, vma);
 
 	dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n",
 		(unsigned long)vma->vm_start,
-		(unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
+		(unsigned long)vma->vm_end - (unsigned long)vma->vm_start,
 		ret);
-
 	return ret;
 }
 
 static const struct v4l2_file_operations vivi_fops = {
 	.owner		= THIS_MODULE,
-	.open           = vivi_open,
 	.release        = vivi_close,
 	.read           = vivi_read,
 	.poll		= vivi_poll,
@@ -1282,11 +1104,11 @@
 	.vidioc_enum_input    = vidioc_enum_input,
 	.vidioc_g_input       = vidioc_g_input,
 	.vidioc_s_input       = vidioc_s_input,
+	.vidioc_streamon      = vidioc_streamon,
+	.vidioc_streamoff     = vidioc_streamoff,
 	.vidioc_queryctrl     = vidioc_queryctrl,
 	.vidioc_g_ctrl        = vidioc_g_ctrl,
 	.vidioc_s_ctrl        = vidioc_s_ctrl,
-	.vidioc_streamon      = vidioc_streamon,
-	.vidioc_streamoff     = vidioc_streamoff,
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
 	.vidiocgmbuf          = vidiocgmbuf,
 #endif
@@ -1330,7 +1152,7 @@
 {
 	struct vivi_dev *dev;
 	struct video_device *vfd;
-	int ret, i;
+	int ret;
 
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev)
@@ -1342,6 +1164,20 @@
 	if (ret)
 		goto free_dev;
 
+	dev->fmt = &formats[0];
+	dev->width = 640;
+	dev->height = 480;
+	dev->volume = 200;
+	dev->brightness = 127;
+	dev->contrast = 16;
+	dev->saturation = 127;
+	dev->hue = 0;
+
+	videobuf_queue_vmalloc_init(&dev->vb_vidq, &vivi_video_qops,
+			NULL, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			V4L2_FIELD_INTERLACED,
+			sizeof(struct vivi_buffer), dev);
+
 	/* init video dma queues */
 	INIT_LIST_HEAD(&dev->vidq.active);
 	init_waitqueue_head(&dev->vidq.wq);
@@ -1357,6 +1193,7 @@
 
 	*vfd = vivi_template;
 	vfd->debug = debug;
+	vfd->v4l2_dev = &dev->v4l2_dev;
 
 	ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
 	if (ret < 0)
@@ -1364,10 +1201,6 @@
 
 	video_set_drvdata(vfd, dev);
 
-	/* Set all controls to their default value. */
-	for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
-		dev->qctl_regs[i] = vivi_qctrl[i].default_value;
-
 	/* Now that everything is fine, let's add it to device list */
 	list_add_tail(&dev->vivi_devlist, &vivi_devlist);
 
@@ -1396,8 +1229,15 @@
  */
 static int __init vivi_init(void)
 {
+	const struct font_desc *font = find_font("VGA8x16");
 	int ret = 0, i;
 
+	if (font == NULL) {
+		printk(KERN_ERR "vivi: could not find font\n");
+		return -ENODEV;
+	}
+	font8x16 = font->data;
+
 	if (n_devs <= 0)
 		n_devs = 1;
 
@@ -1412,7 +1252,7 @@
 	}
 
 	if (ret < 0) {
-		printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
+		printk(KERN_ERR "vivi: error %d while loading driver\n", ret);
 		return ret;
 	}
 
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
index bf9bf65..635420d 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -1,7 +1,7 @@
 /*
 	Winbond w9966cf Webcam parport driver.
 
-	Version 0.32
+	Version 0.33
 
 	Copyright (C) 2001 Jakob Kemi <jakob.kemi@post.utfors.se>
 
@@ -57,10 +57,12 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <linux/videodev.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
 #include <linux/slab.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
 #include <linux/parport.h>
 
 /*#define DEBUG*/				/* Undef me for production */
@@ -76,12 +78,12 @@
  */
 
 #define W9966_DRIVERNAME	"W9966CF Webcam"
-#define W9966_MAXCAMS		4	// Maximum number of cameras
-#define W9966_RBUFFER		2048	// Read buffer (must be an even number)
-#define W9966_SRAMSIZE		131072	// 128kb
-#define W9966_SRAMID		0x02	// check w9966cf.pdf
+#define W9966_MAXCAMS		4	/* Maximum number of cameras */
+#define W9966_RBUFFER		2048	/* Read buffer (must be an even number) */
+#define W9966_SRAMSIZE		131072	/* 128kb */
+#define W9966_SRAMID		0x02	/* check w9966cf.pdf */
 
-// Empirically determined window limits
+/* Empirically determined window limits */
 #define W9966_WND_MIN_X		16
 #define W9966_WND_MIN_Y		14
 #define W9966_WND_MAX_X		705
@@ -89,7 +91,7 @@
 #define W9966_WND_MAX_W		(W9966_WND_MAX_X - W9966_WND_MIN_X)
 #define W9966_WND_MAX_H		(W9966_WND_MAX_Y - W9966_WND_MIN_Y)
 
-// Keep track of our current state
+/* Keep track of our current state */
 #define W9966_STATE_PDEV	0x01
 #define W9966_STATE_CLAIMED	0x02
 #define W9966_STATE_VDEV	0x04
@@ -101,12 +103,13 @@
 #define W9966_I2C_W_DATA	0x02
 #define W9966_I2C_W_CLOCK	0x01
 
-struct w9966_dev {
+struct w9966 {
+	struct v4l2_device v4l2_dev;
 	unsigned char dev_state;
 	unsigned char i2c_state;
 	unsigned short ppmode;
-	struct parport* pport;
-	struct pardevice* pdev;
+	struct parport *pport;
+	struct pardevice *pdev;
 	struct video_device vdev;
 	unsigned short width;
 	unsigned short height;
@@ -114,7 +117,7 @@
 	signed char contrast;
 	signed char color;
 	signed char hue;
-	unsigned long in_use;
+	struct mutex lock;
 };
 
 /*
@@ -127,15 +130,15 @@
 
 
 #ifdef MODULE
-static const char* pardev[] = {[0 ... W9966_MAXCAMS] = ""};
+static const char *pardev[] = {[0 ... W9966_MAXCAMS] = ""};
 #else
-static const char* pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"};
+static const char *pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"};
 #endif
 module_param_array(pardev, charp, NULL, 0);
-MODULE_PARM_DESC(pardev, "pardev: where to search for\n\
-\teach camera. 'aggressive' means brute-force search.\n\
-\tEg: >pardev=parport3,aggressive,parport2,parport1< would assign\n\
-\tcam 1 to parport3 and search every parport for cam 2 etc...");
+MODULE_PARM_DESC(pardev, "pardev: where to search for\n"
+		"\teach camera. 'aggressive' means brute-force search.\n"
+		"\tEg: >pardev=parport3,aggressive,parport2,parport1< would assign\n"
+		"\tcam 1 to parport3 and search every parport for cam 2 etc...");
 
 static int parmode;
 module_param(parmode, int, 0);
@@ -144,117 +147,49 @@
 static int video_nr = -1;
 module_param(video_nr, int, 0);
 
-/*
- *	Private data
- */
-
-static struct w9966_dev w9966_cams[W9966_MAXCAMS];
-
-/*
- *	Private function declares
- */
-
-static inline void w9966_setState(struct w9966_dev* cam, int mask, int val);
-static inline int  w9966_getState(struct w9966_dev* cam, int mask, int val);
-static inline void w9966_pdev_claim(struct w9966_dev *vdev);
-static inline void w9966_pdev_release(struct w9966_dev *vdev);
-
-static int w9966_rReg(struct w9966_dev* cam, int reg);
-static int w9966_wReg(struct w9966_dev* cam, int reg, int data);
-#if 0
-static int w9966_rReg_i2c(struct w9966_dev* cam, int reg);
-#endif
-static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data);
-static int w9966_findlen(int near, int size, int maxlen);
-static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor);
-static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h);
-
-static int  w9966_init(struct w9966_dev* cam, struct parport* port);
-static void w9966_term(struct w9966_dev* cam);
-
-static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state);
-static inline int  w9966_i2c_setscl(struct w9966_dev* cam, int state);
-static inline int  w9966_i2c_getsda(struct w9966_dev* cam);
-static inline int  w9966_i2c_getscl(struct w9966_dev* cam);
-static int w9966_i2c_wbyte(struct w9966_dev* cam, int data);
-#if 0
-static int w9966_i2c_rbyte(struct w9966_dev* cam);
-#endif
-
-static long w9966_v4l_ioctl(struct file *file,
-			   unsigned int cmd, unsigned long arg);
-static ssize_t w9966_v4l_read(struct file *file, char __user *buf,
-			      size_t count, loff_t *ppos);
-
-static int w9966_exclusive_open(struct file *file)
-{
-	struct w9966_dev *cam = video_drvdata(file);
-
-	return test_and_set_bit(0, &cam->in_use) ? -EBUSY : 0;
-}
-
-static int w9966_exclusive_release(struct file *file)
-{
-	struct w9966_dev *cam = video_drvdata(file);
-
-	clear_bit(0, &cam->in_use);
-	return 0;
-}
-
-static const struct v4l2_file_operations w9966_fops = {
-	.owner		= THIS_MODULE,
-	.open           = w9966_exclusive_open,
-	.release        = w9966_exclusive_release,
-	.ioctl          = w9966_v4l_ioctl,
-	.read           = w9966_v4l_read,
-};
-static struct video_device w9966_template = {
-	.name           = W9966_DRIVERNAME,
-	.fops           = &w9966_fops,
-	.release 	= video_device_release_empty,
-};
+static struct w9966 w9966_cams[W9966_MAXCAMS];
 
 /*
  *	Private function defines
  */
 
 
-// Set camera phase flags, so we know what to uninit when terminating
-static inline void w9966_setState(struct w9966_dev* cam, int mask, int val)
+/* Set camera phase flags, so we know what to uninit when terminating */
+static inline void w9966_set_state(struct w9966 *cam, int mask, int val)
 {
 	cam->dev_state = (cam->dev_state & ~mask) ^ val;
 }
 
-// Get camera phase flags
-static inline int w9966_getState(struct w9966_dev* cam, int mask, int val)
+/* Get camera phase flags */
+static inline int w9966_get_state(struct w9966 *cam, int mask, int val)
 {
 	return ((cam->dev_state & mask) == val);
 }
 
-// Claim parport for ourself
-static inline void w9966_pdev_claim(struct w9966_dev* cam)
+/* Claim parport for ourself */
+static void w9966_pdev_claim(struct w9966 *cam)
 {
-	if (w9966_getState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED))
+	if (w9966_get_state(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED))
 		return;
 	parport_claim_or_block(cam->pdev);
-	w9966_setState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED);
+	w9966_set_state(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED);
 }
 
-// Release parport for others to use
-static inline void w9966_pdev_release(struct w9966_dev* cam)
+/* Release parport for others to use */
+static void w9966_pdev_release(struct w9966 *cam)
 {
-	if (w9966_getState(cam, W9966_STATE_CLAIMED, 0))
+	if (w9966_get_state(cam, W9966_STATE_CLAIMED, 0))
 		return;
 	parport_release(cam->pdev);
-	w9966_setState(cam, W9966_STATE_CLAIMED, 0);
+	w9966_set_state(cam, W9966_STATE_CLAIMED, 0);
 }
 
-// Read register from W9966 interface-chip
-// Expects a claimed pdev
-// -1 on error, else register data (byte)
-static int w9966_rReg(struct w9966_dev* cam, int reg)
+/* Read register from W9966 interface-chip
+   Expects a claimed pdev
+   -1 on error, else register data (byte) */
+static int w9966_read_reg(struct w9966 *cam, int reg)
 {
-	// ECP, read, regtransfer, REG, REG, REG, REG, REG
+	/* ECP, read, regtransfer, REG, REG, REG, REG, REG */
 	const unsigned char addr = 0x80 | (reg & 0x1f);
 	unsigned char val;
 
@@ -270,12 +205,12 @@
 	return val;
 }
 
-// Write register to W9966 interface-chip
-// Expects a claimed pdev
-// -1 on error
-static int w9966_wReg(struct w9966_dev* cam, int reg, int data)
+/* Write register to W9966 interface-chip
+   Expects a claimed pdev
+   -1 on error */
+static int w9966_write_reg(struct w9966 *cam, int reg, int data)
 {
-	// ECP, write, regtransfer, REG, REG, REG, REG, REG
+	/* ECP, write, regtransfer, REG, REG, REG, REG, REG */
 	const unsigned char addr = 0xc0 | (reg & 0x1f);
 	const unsigned char val = data;
 
@@ -291,297 +226,34 @@
 	return 0;
 }
 
-// Initialize camera device. Setup all internal flags, set a
-// default video mode, setup ccd-chip, register v4l device etc..
-// Also used for 'probing' of hardware.
-// -1 on error
-static int w9966_init(struct w9966_dev* cam, struct parport* port)
-{
-	if (cam->dev_state != 0)
-		return -1;
-
-	cam->pport = port;
-	cam->brightness = 128;
-	cam->contrast = 64;
-	cam->color = 64;
-	cam->hue = 0;
-
-// Select requested transfer mode
-	switch(parmode)
-	{
-	default:	// Auto-detect (priority: hw-ecp, hw-epp, sw-ecp)
-	case 0:
-		if (port->modes & PARPORT_MODE_ECP)
-			cam->ppmode = IEEE1284_MODE_ECP;
-		else if (port->modes & PARPORT_MODE_EPP)
-			cam->ppmode = IEEE1284_MODE_EPP;
-		else
-			cam->ppmode = IEEE1284_MODE_ECP;
-		break;
-	case 1:		// hw- or sw-ecp
-		cam->ppmode = IEEE1284_MODE_ECP;
-		break;
-	case 2:		// hw- or sw-epp
-		cam->ppmode = IEEE1284_MODE_EPP;
-	break;
-	}
-
-// Tell the parport driver that we exists
-	cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL);
-	if (cam->pdev == NULL) {
-		DPRINTF("parport_register_device() failed\n");
-		return -1;
-	}
-	w9966_setState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV);
-
-	w9966_pdev_claim(cam);
-
-// Setup a default capture mode
-	if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) {
-		DPRINTF("w9966_setup() failed.\n");
-		return -1;
-	}
-
-	w9966_pdev_release(cam);
-
-// Fill in the video_device struct and register us to v4l
-	memcpy(&cam->vdev, &w9966_template, sizeof(struct video_device));
-	video_set_drvdata(&cam->vdev, cam);
-
-	if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0)
-		return -1;
-
-	w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV);
-
-	// All ok
-	printk(
-		"w9966cf: Found and initialized a webcam on %s.\n",
-		cam->pport->name
-	);
-	return 0;
-}
-
-
-// Terminate everything gracefully
-static void w9966_term(struct w9966_dev* cam)
-{
-// Unregister from v4l
-	if (w9966_getState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) {
-		video_unregister_device(&cam->vdev);
-		w9966_setState(cam, W9966_STATE_VDEV, 0);
-	}
-
-// Terminate from IEEE1284 mode and release pdev block
-	if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
-		w9966_pdev_claim(cam);
-		parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT);
-		w9966_pdev_release(cam);
-	}
-
-// Unregister from parport
-	if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
-		parport_unregister_device(cam->pdev);
-		w9966_setState(cam, W9966_STATE_PDEV, 0);
-	}
-}
-
-
-// Find a good length for capture window (used both for W and H)
-// A bit ugly but pretty functional. The capture length
-// have to match the downscale
-static int w9966_findlen(int near, int size, int maxlen)
-{
-	int bestlen = size;
-	int besterr = abs(near - bestlen);
-	int len;
-
-	for(len = size+1;len < maxlen;len++)
-	{
-		int err;
-		if ( ((64*size) %len) != 0)
-			continue;
-
-		err = abs(near - len);
-
-		// Only continue as long as we keep getting better values
-		if (err > besterr)
-			break;
-
-		besterr = err;
-		bestlen = len;
-	}
-
-	return bestlen;
-}
-
-// Modify capture window (if necessary)
-// and calculate downscaling
-// Return -1 on error
-static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor)
-{
-	int maxlen = max - min;
-	int len = *end - *beg + 1;
-	int newlen = w9966_findlen(len, size, maxlen);
-	int err = newlen - len;
-
-	// Check for bad format
-	if (newlen > maxlen || newlen < size)
-		return -1;
-
-	// Set factor (6 bit fixed)
-	*factor = (64*size) / newlen;
-	if (*factor == 64)
-		*factor = 0x00;	// downscale is disabled
-	else
-		*factor |= 0x80; // set downscale-enable bit
-
-	// Modify old beginning and end
-	*beg -= err / 2;
-	*end += err - (err / 2);
-
-	// Move window if outside borders
-	if (*beg < min) {
-		*end += min - *beg;
-		*beg += min - *beg;
-	}
-	if (*end > max) {
-		*beg -= *end - max;
-		*end -= *end - max;
-	}
-
-	return 0;
-}
-
-// Setup the cameras capture window etc.
-// Expects a claimed pdev
-// return -1 on error
-static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h)
-{
-	unsigned int i;
-	unsigned int enh_s, enh_e;
-	unsigned char scale_x, scale_y;
-	unsigned char regs[0x1c];
-	unsigned char saa7111_regs[] = {
-		0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00,
-		0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00,
-		0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0
-	};
-
-
-	if (w*h*2 > W9966_SRAMSIZE)
-	{
-		DPRINTF("capture window exceeds SRAM size!.\n");
-		w = 200; h = 160;	// Pick default values
-	}
-
-	w &= ~0x1;
-	if (w < 2) w = 2;
-	if (h < 1) h = 1;
-	if (w > W9966_WND_MAX_W) w = W9966_WND_MAX_W;
-	if (h > W9966_WND_MAX_H) h = W9966_WND_MAX_H;
-
-	cam->width = w;
-	cam->height = h;
-
-	enh_s = 0;
-	enh_e = w*h*2;
-
-// Modify capture window if necessary and calculate downscaling
-	if (
-		w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 ||
-		w9966_calcscale(h, W9966_WND_MIN_Y, W9966_WND_MAX_Y, &y1, &y2, &scale_y) != 0
-	) return -1;
-
-	DPRINTF(
-		"%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n",
-		w, h, x1, x2, y1, y2, scale_x&~0x80, scale_y&~0x80
-	);
-
-// Setup registers
-	regs[0x00] = 0x00;			// Set normal operation
-	regs[0x01] = 0x18;			// Capture mode
-	regs[0x02] = scale_y;			// V-scaling
-	regs[0x03] = scale_x;			// H-scaling
-
-	// Capture window
-	regs[0x04] = (x1 & 0x0ff);		// X-start (8 low bits)
-	regs[0x05] = (x1 & 0x300)>>8;		// X-start (2 high bits)
-	regs[0x06] = (y1 & 0x0ff);		// Y-start (8 low bits)
-	regs[0x07] = (y1 & 0x300)>>8;		// Y-start (2 high bits)
-	regs[0x08] = (x2 & 0x0ff);		// X-end (8 low bits)
-	regs[0x09] = (x2 & 0x300)>>8;		// X-end (2 high bits)
-	regs[0x0a] = (y2 & 0x0ff);		// Y-end (8 low bits)
-
-	regs[0x0c] = W9966_SRAMID;		// SRAM-banks (1x 128kb)
-
-	// Enhancement layer
-	regs[0x0d] = (enh_s& 0x000ff);		// Enh. start (0-7)
-	regs[0x0e] = (enh_s& 0x0ff00)>>8;	// Enh. start (8-15)
-	regs[0x0f] = (enh_s& 0x70000)>>16;	// Enh. start (16-17/18??)
-	regs[0x10] = (enh_e& 0x000ff);		// Enh. end (0-7)
-	regs[0x11] = (enh_e& 0x0ff00)>>8;	// Enh. end (8-15)
-	regs[0x12] = (enh_e& 0x70000)>>16;	// Enh. end (16-17/18??)
-
-	// Misc
-	regs[0x13] = 0x40;			// VEE control (raw 4:2:2)
-	regs[0x17] = 0x00;			// ???
-	regs[0x18] = cam->i2c_state = 0x00;	// Serial bus
-	regs[0x19] = 0xff;			// I/O port direction control
-	regs[0x1a] = 0xff;			// I/O port data register
-	regs[0x1b] = 0x10;			// ???
-
-	// SAA7111 chip settings
-	saa7111_regs[0x0a] = cam->brightness;
-	saa7111_regs[0x0b] = cam->contrast;
-	saa7111_regs[0x0c] = cam->color;
-	saa7111_regs[0x0d] = cam->hue;
-
-// Reset (ECP-fifo & serial-bus)
-	if (w9966_wReg(cam, 0x00, 0x03) == -1)
-		return -1;
-
-// Write regs to w9966cf chip
-	for (i = 0; i < 0x1c; i++)
-		if (w9966_wReg(cam, i, regs[i]) == -1)
-			return -1;
-
-// Write regs to saa7111 chip
-	for (i = 0; i < 0x20; i++)
-		if (w9966_wReg_i2c(cam, i, saa7111_regs[i]) == -1)
-			return -1;
-
-	return 0;
-}
-
 /*
  *	Ugly and primitive i2c protocol functions
  */
 
-// Sets the data line on the i2c bus.
-// Expects a claimed pdev.
-static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state)
+/* Sets the data line on the i2c bus.
+   Expects a claimed pdev. */
+static void w9966_i2c_setsda(struct w9966 *cam, int state)
 {
 	if (state)
 		cam->i2c_state |= W9966_I2C_W_DATA;
 	else
 		cam->i2c_state &= ~W9966_I2C_W_DATA;
 
-	w9966_wReg(cam, 0x18, cam->i2c_state);
+	w9966_write_reg(cam, 0x18, cam->i2c_state);
 	udelay(5);
 }
 
-// Get peripheral clock line
-// Expects a claimed pdev.
-static inline int w9966_i2c_getscl(struct w9966_dev* cam)
+/* Get peripheral clock line
+   Expects a claimed pdev. */
+static int w9966_i2c_getscl(struct w9966 *cam)
 {
-	const unsigned char state = w9966_rReg(cam, 0x18);
+	const unsigned char state = w9966_read_reg(cam, 0x18);
 	return ((state & W9966_I2C_R_CLOCK) > 0);
 }
 
-// Sets the clock line on the i2c bus.
-// Expects a claimed pdev. -1 on error
-static inline int w9966_i2c_setscl(struct w9966_dev* cam, int state)
+/* Sets the clock line on the i2c bus.
+   Expects a claimed pdev. -1 on error */
+static int w9966_i2c_setscl(struct w9966 *cam, int state)
 {
 	unsigned long timeout;
 
@@ -590,10 +262,10 @@
 	else
 		cam->i2c_state &= ~W9966_I2C_W_CLOCK;
 
-	w9966_wReg(cam, 0x18, cam->i2c_state);
+	w9966_write_reg(cam, 0x18, cam->i2c_state);
 	udelay(5);
 
-	// we go to high, we also expect the peripheral to ack.
+	/* we go to high, we also expect the peripheral to ack. */
 	if (state) {
 		timeout = jiffies + 100;
 		while (!w9966_i2c_getscl(cam)) {
@@ -604,21 +276,23 @@
 	return 0;
 }
 
-// Get peripheral data line
-// Expects a claimed pdev.
-static inline int w9966_i2c_getsda(struct w9966_dev* cam)
+#if 0
+/* Get peripheral data line
+   Expects a claimed pdev. */
+static int w9966_i2c_getsda(struct w9966 *cam)
 {
-	const unsigned char state = w9966_rReg(cam, 0x18);
+	const unsigned char state = w9966_read_reg(cam, 0x18);
 	return ((state & W9966_I2C_R_DATA) > 0);
 }
+#endif
 
-// Write a byte with ack to the i2c bus.
-// Expects a claimed pdev. -1 on error
-static int w9966_i2c_wbyte(struct w9966_dev* cam, int data)
+/* Write a byte with ack to the i2c bus.
+   Expects a claimed pdev. -1 on error */
+static int w9966_i2c_wbyte(struct w9966 *cam, int data)
 {
 	int i;
-	for (i = 7; i >= 0; i--)
-	{
+
+	for (i = 7; i >= 0; i--) {
 		w9966_i2c_setsda(cam, (data >> i) & 0x01);
 
 		if (w9966_i2c_setscl(cam, 1) == -1)
@@ -635,18 +309,17 @@
 	return 0;
 }
 
-// Read a data byte with ack from the i2c-bus
-// Expects a claimed pdev. -1 on error
+/* Read a data byte with ack from the i2c-bus
+   Expects a claimed pdev. -1 on error */
 #if 0
-static int w9966_i2c_rbyte(struct w9966_dev* cam)
+static int w9966_i2c_rbyte(struct w9966 *cam)
 {
 	unsigned char data = 0x00;
 	int i;
 
 	w9966_i2c_setsda(cam, 1);
 
-	for (i = 0; i < 8; i++)
-	{
+	for (i = 0; i < 8; i++) {
 		if (w9966_i2c_setscl(cam, 1) == -1)
 			return -1;
 		data = data << 1;
@@ -659,20 +332,18 @@
 }
 #endif
 
-// Read a register from the i2c device.
-// Expects claimed pdev. -1 on error
+/* Read a register from the i2c device.
+   Expects claimed pdev. -1 on error */
 #if 0
-static int w9966_rReg_i2c(struct w9966_dev* cam, int reg)
+static int w9966_read_reg_i2c(struct w9966 *cam, int reg)
 {
 	int data;
 
 	w9966_i2c_setsda(cam, 0);
 	w9966_i2c_setscl(cam, 0);
 
-	if (
-		w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
-		w9966_i2c_wbyte(cam, reg) == -1
-	)
+	if (w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
+	    w9966_i2c_wbyte(cam, reg) == -1)
 		return -1;
 
 	w9966_i2c_setsda(cam, 1);
@@ -681,10 +352,10 @@
 	w9966_i2c_setsda(cam, 0);
 	w9966_i2c_setscl(cam, 0);
 
-	if (
-		w9966_i2c_wbyte(cam, W9966_I2C_R_ID) == -1 ||
-		(data = w9966_i2c_rbyte(cam)) == -1
-	)
+	if (w9966_i2c_wbyte(cam, W9966_I2C_R_ID) == -1)
+		return -1;
+	data = w9966_i2c_rbyte(cam);
+	if (data == -1)
 		return -1;
 
 	w9966_i2c_setsda(cam, 0);
@@ -697,18 +368,16 @@
 }
 #endif
 
-// Write a register to the i2c device.
-// Expects claimed pdev. -1 on error
-static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data)
+/* Write a register to the i2c device.
+   Expects claimed pdev. -1 on error */
+static int w9966_write_reg_i2c(struct w9966 *cam, int reg, int data)
 {
 	w9966_i2c_setsda(cam, 0);
 	w9966_i2c_setscl(cam, 0);
 
-	if (
-		w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
-		w9966_i2c_wbyte(cam, reg) == -1 ||
-		w9966_i2c_wbyte(cam, data) == -1
-	)
+	if (w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
+			w9966_i2c_wbyte(cam, reg) == -1 ||
+			w9966_i2c_wbyte(cam, data) == -1)
 		return -1;
 
 	w9966_i2c_setsda(cam, 0);
@@ -720,192 +389,396 @@
 	return 0;
 }
 
+/* Find a good length for capture window (used both for W and H)
+   A bit ugly but pretty functional. The capture length
+   have to match the downscale */
+static int w9966_findlen(int near, int size, int maxlen)
+{
+	int bestlen = size;
+	int besterr = abs(near - bestlen);
+	int len;
+
+	for (len = size + 1; len < maxlen; len++) {
+		int err;
+		if (((64 * size) % len) != 0)
+			continue;
+
+		err = abs(near - len);
+
+		/* Only continue as long as we keep getting better values */
+		if (err > besterr)
+			break;
+
+		besterr = err;
+		bestlen = len;
+	}
+
+	return bestlen;
+}
+
+/* Modify capture window (if necessary)
+   and calculate downscaling
+   Return -1 on error */
+static int w9966_calcscale(int size, int min, int max, int *beg, int *end, unsigned char *factor)
+{
+	int maxlen = max - min;
+	int len = *end - *beg + 1;
+	int newlen = w9966_findlen(len, size, maxlen);
+	int err = newlen - len;
+
+	/* Check for bad format */
+	if (newlen > maxlen || newlen < size)
+		return -1;
+
+	/* Set factor (6 bit fixed) */
+	*factor = (64 * size) / newlen;
+	if (*factor == 64)
+		*factor = 0x00;	/* downscale is disabled */
+	else
+		*factor |= 0x80; /* set downscale-enable bit */
+
+	/* Modify old beginning and end */
+	*beg -= err / 2;
+	*end += err - (err / 2);
+
+	/* Move window if outside borders */
+	if (*beg < min) {
+		*end += min - *beg;
+		*beg += min - *beg;
+	}
+	if (*end > max) {
+		*beg -= *end - max;
+		*end -= *end - max;
+	}
+
+	return 0;
+}
+
+/* Setup the cameras capture window etc.
+   Expects a claimed pdev
+   return -1 on error */
+static int w9966_setup(struct w9966 *cam, int x1, int y1, int x2, int y2, int w, int h)
+{
+	unsigned int i;
+	unsigned int enh_s, enh_e;
+	unsigned char scale_x, scale_y;
+	unsigned char regs[0x1c];
+	unsigned char saa7111_regs[] = {
+		0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00,
+		0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00,
+		0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0
+	};
+
+
+	if (w * h * 2 > W9966_SRAMSIZE) {
+		DPRINTF("capture window exceeds SRAM size!.\n");
+		w = 200; h = 160;	/* Pick default values */
+	}
+
+	w &= ~0x1;
+	if (w < 2)
+		w = 2;
+	if (h < 1)
+		h = 1;
+	if (w > W9966_WND_MAX_W)
+		w = W9966_WND_MAX_W;
+	if (h > W9966_WND_MAX_H)
+		h = W9966_WND_MAX_H;
+
+	cam->width = w;
+	cam->height = h;
+
+	enh_s = 0;
+	enh_e = w * h * 2;
+
+	/* Modify capture window if necessary and calculate downscaling */
+	if (w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 ||
+			w9966_calcscale(h, W9966_WND_MIN_Y, W9966_WND_MAX_Y, &y1, &y2, &scale_y) != 0)
+		return -1;
+
+	DPRINTF("%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n",
+			w, h, x1, x2, y1, y2, scale_x & ~0x80, scale_y & ~0x80);
+
+	/* Setup registers */
+	regs[0x00] = 0x00;			/* Set normal operation */
+	regs[0x01] = 0x18;			/* Capture mode */
+	regs[0x02] = scale_y;			/* V-scaling */
+	regs[0x03] = scale_x;			/* H-scaling */
+
+	/* Capture window */
+	regs[0x04] = (x1 & 0x0ff);		/* X-start (8 low bits) */
+	regs[0x05] = (x1 & 0x300)>>8;		/* X-start (2 high bits) */
+	regs[0x06] = (y1 & 0x0ff);		/* Y-start (8 low bits) */
+	regs[0x07] = (y1 & 0x300)>>8;		/* Y-start (2 high bits) */
+	regs[0x08] = (x2 & 0x0ff);		/* X-end (8 low bits) */
+	regs[0x09] = (x2 & 0x300)>>8;		/* X-end (2 high bits) */
+	regs[0x0a] = (y2 & 0x0ff);		/* Y-end (8 low bits) */
+
+	regs[0x0c] = W9966_SRAMID;		/* SRAM-banks (1x 128kb) */
+
+	/* Enhancement layer */
+	regs[0x0d] = (enh_s & 0x000ff);		/* Enh. start (0-7) */
+	regs[0x0e] = (enh_s & 0x0ff00) >> 8;	/* Enh. start (8-15) */
+	regs[0x0f] = (enh_s & 0x70000) >> 16;	/* Enh. start (16-17/18??) */
+	regs[0x10] = (enh_e & 0x000ff);		/* Enh. end (0-7) */
+	regs[0x11] = (enh_e & 0x0ff00) >> 8;	/* Enh. end (8-15) */
+	regs[0x12] = (enh_e & 0x70000) >> 16;	/* Enh. end (16-17/18??) */
+
+	/* Misc */
+	regs[0x13] = 0x40;			/* VEE control (raw 4:2:2) */
+	regs[0x17] = 0x00;			/* ??? */
+	regs[0x18] = cam->i2c_state = 0x00;	/* Serial bus */
+	regs[0x19] = 0xff;			/* I/O port direction control */
+	regs[0x1a] = 0xff;			/* I/O port data register */
+	regs[0x1b] = 0x10;			/* ??? */
+
+	/* SAA7111 chip settings */
+	saa7111_regs[0x0a] = cam->brightness;
+	saa7111_regs[0x0b] = cam->contrast;
+	saa7111_regs[0x0c] = cam->color;
+	saa7111_regs[0x0d] = cam->hue;
+
+	/* Reset (ECP-fifo & serial-bus) */
+	if (w9966_write_reg(cam, 0x00, 0x03) == -1)
+		return -1;
+
+	/* Write regs to w9966cf chip */
+	for (i = 0; i < 0x1c; i++)
+		if (w9966_write_reg(cam, i, regs[i]) == -1)
+			return -1;
+
+	/* Write regs to saa7111 chip */
+	for (i = 0; i < 0x20; i++)
+		if (w9966_write_reg_i2c(cam, i, saa7111_regs[i]) == -1)
+			return -1;
+
+	return 0;
+}
+
 /*
  *	Video4linux interfacing
  */
 
-static long w9966_v4l_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static int cam_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *vcap)
 {
-	struct w9966_dev *cam = video_drvdata(file);
+	struct w9966 *cam = video_drvdata(file);
 
-	switch(cmd)
-	{
-	case VIDIOCGCAP:
-	{
-		static struct video_capability vcap = {
-			.name      = W9966_DRIVERNAME,
-			.type      = VID_TYPE_CAPTURE | VID_TYPE_SCALES,
-			.channels  = 1,
-			.maxwidth  = W9966_WND_MAX_W,
-			.maxheight = W9966_WND_MAX_H,
-			.minwidth  = 2,
-			.minheight = 1,
-		};
-		struct video_capability *cap = arg;
-		*cap = vcap;
-		return 0;
-	}
-	case VIDIOCGCHAN:
-	{
-		struct video_channel *vch = arg;
-		if(vch->channel != 0)	// We only support one channel (#0)
-			return -EINVAL;
-		memset(vch,0,sizeof(*vch));
-		strcpy(vch->name, "CCD-input");
-		vch->type = VIDEO_TYPE_CAMERA;
-		return 0;
-	}
-	case VIDIOCSCHAN:
-	{
-		struct video_channel *vch = arg;
-		if(vch->channel != 0)
-			return -EINVAL;
-		return 0;
-	}
-	case VIDIOCGTUNER:
-	{
-		struct video_tuner *vtune = arg;
-		if(vtune->tuner != 0)
-			return -EINVAL;
-		strcpy(vtune->name, "no tuner");
-		vtune->rangelow = 0;
-		vtune->rangehigh = 0;
-		vtune->flags = VIDEO_TUNER_NORM;
-		vtune->mode = VIDEO_MODE_AUTO;
-		vtune->signal = 0xffff;
-		return 0;
-	}
-	case VIDIOCSTUNER:
-	{
-		struct video_tuner *vtune = arg;
-		if (vtune->tuner != 0)
-			return -EINVAL;
-		if (vtune->mode != VIDEO_MODE_AUTO)
-			return -EINVAL;
-		return 0;
-	}
-	case VIDIOCGPICT:
-	{
-		struct video_picture vpic = {
-			cam->brightness << 8,	// brightness
-			(cam->hue + 128) << 8,	// hue
-			cam->color << 9,	// color
-			cam->contrast << 9,	// contrast
-			0x8000,			// whiteness
-			16, VIDEO_PALETTE_YUV422// bpp, palette format
-		};
-		struct video_picture *pic = arg;
-		*pic = vpic;
-		return 0;
-	}
-	case VIDIOCSPICT:
-	{
-		struct video_picture *vpic = arg;
-		if (vpic->depth != 16 || (vpic->palette != VIDEO_PALETTE_YUV422 && vpic->palette != VIDEO_PALETTE_YUYV))
-			return -EINVAL;
-
-		cam->brightness = vpic->brightness >> 8;
-		cam->hue = (vpic->hue >> 8) - 128;
-		cam->color = vpic->colour >> 9;
-		cam->contrast = vpic->contrast >> 9;
-
-		w9966_pdev_claim(cam);
-
-		if (
-			w9966_wReg_i2c(cam, 0x0a, cam->brightness) == -1 ||
-			w9966_wReg_i2c(cam, 0x0b, cam->contrast) == -1 ||
-			w9966_wReg_i2c(cam, 0x0c, cam->color) == -1 ||
-			w9966_wReg_i2c(cam, 0x0d, cam->hue) == -1
-		) {
-			w9966_pdev_release(cam);
-			return -EIO;
-		}
-
-		w9966_pdev_release(cam);
-		return 0;
-	}
-	case VIDIOCSWIN:
-	{
-		int ret;
-		struct video_window *vwin = arg;
-
-		if (vwin->flags != 0)
-			return -EINVAL;
-		if (vwin->clipcount != 0)
-			return -EINVAL;
-		if (vwin->width < 2 || vwin->width > W9966_WND_MAX_W)
-			return -EINVAL;
-		if (vwin->height < 1 || vwin->height > W9966_WND_MAX_H)
-			return -EINVAL;
-
-		// Update camera regs
-		w9966_pdev_claim(cam);
-		ret = w9966_setup(cam, 0, 0, 1023, 1023, vwin->width, vwin->height);
-		w9966_pdev_release(cam);
-
-		if (ret != 0) {
-			DPRINTF("VIDIOCSWIN: w9966_setup() failed.\n");
-			return -EIO;
-		}
-
-		return 0;
-	}
-	case VIDIOCGWIN:
-	{
-		struct video_window *vwin = arg;
-		memset(vwin, 0, sizeof(*vwin));
-		vwin->width = cam->width;
-		vwin->height = cam->height;
-		return 0;
-	}
-	// Unimplemented
-	case VIDIOCCAPTURE:
-	case VIDIOCGFBUF:
-	case VIDIOCSFBUF:
-	case VIDIOCKEY:
-	case VIDIOCGFREQ:
-	case VIDIOCSFREQ:
-	case VIDIOCGAUDIO:
-	case VIDIOCSAUDIO:
-		return -EINVAL;
-	default:
-		return -ENOIOCTLCMD;
-	}
+	strlcpy(vcap->driver, cam->v4l2_dev.name, sizeof(vcap->driver));
+	strlcpy(vcap->card, W9966_DRIVERNAME, sizeof(vcap->card));
+	strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
+	vcap->version = KERNEL_VERSION(0, 33, 0);
+	vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
 	return 0;
 }
 
-static long w9966_v4l_ioctl(struct file *file,
-			   unsigned int cmd, unsigned long arg)
+static int cam_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
 {
-	return video_usercopy(file, cmd, arg, w9966_v4l_do_ioctl);
+	if (vin->index > 0)
+		return -EINVAL;
+	strlcpy(vin->name, "Camera", sizeof(vin->name));
+	vin->type = V4L2_INPUT_TYPE_CAMERA;
+	vin->audioset = 0;
+	vin->tuner = 0;
+	vin->std = 0;
+	vin->status = 0;
+	return 0;
 }
 
-// Capture data
-static ssize_t w9966_v4l_read(struct file *file, char  __user *buf,
-			      size_t count, loff_t *ppos)
+static int cam_g_input(struct file *file, void *fh, unsigned int *inp)
 {
-	struct w9966_dev *cam = video_drvdata(file);
-	unsigned char addr = 0xa0;	// ECP, read, CCD-transfer, 00000
+	*inp = 0;
+	return 0;
+}
+
+static int cam_s_input(struct file *file, void *fh, unsigned int inp)
+{
+	return (inp > 0) ? -EINVAL : 0;
+}
+
+static int cam_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *qc)
+{
+	switch (qc->id) {
+	case V4L2_CID_BRIGHTNESS:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
+	case V4L2_CID_CONTRAST:
+		return v4l2_ctrl_query_fill(qc, -64, 64, 1, 64);
+	case V4L2_CID_SATURATION:
+		return v4l2_ctrl_query_fill(qc, -64, 64, 1, 64);
+	case V4L2_CID_HUE:
+		return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
+	}
+	return -EINVAL;
+}
+
+static int cam_g_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct w9966 *cam = video_drvdata(file);
+	int ret = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		ctrl->value = cam->brightness;
+		break;
+	case V4L2_CID_CONTRAST:
+		ctrl->value = cam->contrast;
+		break;
+	case V4L2_CID_SATURATION:
+		ctrl->value = cam->color;
+		break;
+	case V4L2_CID_HUE:
+		ctrl->value = cam->hue;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int cam_s_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct w9966 *cam = video_drvdata(file);
+	int ret = 0;
+
+	mutex_lock(&cam->lock);
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		cam->brightness = ctrl->value;
+		break;
+	case V4L2_CID_CONTRAST:
+		cam->contrast = ctrl->value;
+		break;
+	case V4L2_CID_SATURATION:
+		cam->color = ctrl->value;
+		break;
+	case V4L2_CID_HUE:
+		cam->hue = ctrl->value;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret == 0) {
+		w9966_pdev_claim(cam);
+
+		if (w9966_write_reg_i2c(cam, 0x0a, cam->brightness) == -1 ||
+		    w9966_write_reg_i2c(cam, 0x0b, cam->contrast) == -1 ||
+		    w9966_write_reg_i2c(cam, 0x0c, cam->color) == -1 ||
+		    w9966_write_reg_i2c(cam, 0x0d, cam->hue) == -1) {
+			ret = -EIO;
+		}
+
+		w9966_pdev_release(cam);
+	}
+	mutex_unlock(&cam->lock);
+	return ret;
+}
+
+static int cam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct w9966 *cam = video_drvdata(file);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+	pix->width = cam->width;
+	pix->height = cam->height;
+	pix->pixelformat = V4L2_PIX_FMT_YUYV;
+	pix->field = V4L2_FIELD_NONE;
+	pix->bytesperline = 2 * cam->width;
+	pix->sizeimage = 2 * cam->width * cam->height;
+	/* Just a guess */
+	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	return 0;
+}
+
+static int cam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+	if (pix->width < 2)
+		pix->width = 2;
+	if (pix->height < 1)
+		pix->height = 1;
+	if (pix->width > W9966_WND_MAX_W)
+		pix->width = W9966_WND_MAX_W;
+	if (pix->height > W9966_WND_MAX_H)
+		pix->height = W9966_WND_MAX_H;
+	pix->pixelformat = V4L2_PIX_FMT_YUYV;
+	pix->field = V4L2_FIELD_NONE;
+	pix->bytesperline = 2 * pix->width;
+	pix->sizeimage = 2 * pix->width * pix->height;
+	/* Just a guess */
+	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	return 0;
+}
+
+static int cam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct w9966 *cam = video_drvdata(file);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+	int ret = cam_try_fmt_vid_cap(file, fh, fmt);
+
+	if (ret)
+		return ret;
+
+	mutex_lock(&cam->lock);
+	/* Update camera regs */
+	w9966_pdev_claim(cam);
+	ret = w9966_setup(cam, 0, 0, 1023, 1023, pix->width, pix->height);
+	w9966_pdev_release(cam);
+	mutex_unlock(&cam->lock);
+	return ret;
+}
+
+static int cam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
+{
+	static struct v4l2_fmtdesc formats[] = {
+		{ 0, 0, 0,
+		  "YUV 4:2:2", V4L2_PIX_FMT_YUYV,
+		  { 0, 0, 0, 0 }
+		},
+	};
+	enum v4l2_buf_type type = fmt->type;
+
+	if (fmt->index > 0)
+		return -EINVAL;
+
+	*fmt = formats[fmt->index];
+	fmt->type = type;
+	return 0;
+}
+
+/* Capture data */
+static ssize_t w9966_v4l_read(struct file *file, char  __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct w9966 *cam = video_drvdata(file);
+	unsigned char addr = 0xa0;	/* ECP, read, CCD-transfer, 00000 */
 	unsigned char __user *dest = (unsigned char __user *)buf;
 	unsigned long dleft = count;
 	unsigned char *tbuf;
 
-	// Why would anyone want more than this??
+	/* Why would anyone want more than this?? */
 	if (count > cam->width * cam->height * 2)
 		return -EINVAL;
 
+	mutex_lock(&cam->lock);
 	w9966_pdev_claim(cam);
-	w9966_wReg(cam, 0x00, 0x02);	// Reset ECP-FIFO buffer
-	w9966_wReg(cam, 0x00, 0x00);	// Return to normal operation
-	w9966_wReg(cam, 0x01, 0x98);	// Enable capture
+	w9966_write_reg(cam, 0x00, 0x02);	/* Reset ECP-FIFO buffer */
+	w9966_write_reg(cam, 0x00, 0x00);	/* Return to normal operation */
+	w9966_write_reg(cam, 0x01, 0x98);	/* Enable capture */
 
-	// write special capture-addr and negotiate into data transfer
-	if (
-		(parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0	)||
-		(parport_write(cam->pport, &addr, 1) != 1						)||
-		(parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0	)
-	) {
+	/* write special capture-addr and negotiate into data transfer */
+	if ((parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0) ||
+			(parport_write(cam->pport, &addr, 1) != 1) ||
+			(parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0)) {
 		w9966_pdev_release(cam);
+		mutex_unlock(&cam->lock);
 		return -EFAULT;
 	}
 
@@ -915,8 +788,7 @@
 		goto out;
 	}
 
-	while(dleft > 0)
-	{
+	while (dleft > 0) {
 		unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft;
 
 		if (parport_read(cam->pport, tbuf, tsize) < tsize) {
@@ -931,43 +803,167 @@
 		dleft -= tsize;
 	}
 
-	w9966_wReg(cam, 0x01, 0x18);	// Disable capture
+	w9966_write_reg(cam, 0x01, 0x18);	/* Disable capture */
 
 out:
 	kfree(tbuf);
 	w9966_pdev_release(cam);
+	mutex_unlock(&cam->lock);
 
 	return count;
 }
 
+static const struct v4l2_file_operations w9966_fops = {
+	.owner		= THIS_MODULE,
+	.ioctl          = video_ioctl2,
+	.read           = w9966_v4l_read,
+};
 
-// Called once for every parport on init
+static const struct v4l2_ioctl_ops w9966_ioctl_ops = {
+	.vidioc_querycap    		    = cam_querycap,
+	.vidioc_g_input      		    = cam_g_input,
+	.vidioc_s_input      		    = cam_s_input,
+	.vidioc_enum_input   		    = cam_enum_input,
+	.vidioc_queryctrl 		    = cam_queryctrl,
+	.vidioc_g_ctrl  		    = cam_g_ctrl,
+	.vidioc_s_ctrl 			    = cam_s_ctrl,
+	.vidioc_enum_fmt_vid_cap 	    = cam_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap 		    = cam_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap  		    = cam_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap  	    = cam_try_fmt_vid_cap,
+};
+
+
+/* Initialize camera device. Setup all internal flags, set a
+   default video mode, setup ccd-chip, register v4l device etc..
+   Also used for 'probing' of hardware.
+   -1 on error */
+static int w9966_init(struct w9966 *cam, struct parport *port)
+{
+	struct v4l2_device *v4l2_dev = &cam->v4l2_dev;
+
+	if (cam->dev_state != 0)
+		return -1;
+
+	strlcpy(v4l2_dev->name, "w9966", sizeof(v4l2_dev->name));
+
+	if (v4l2_device_register(NULL, v4l2_dev) < 0) {
+		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+		return -1;
+	}
+	cam->pport = port;
+	cam->brightness = 128;
+	cam->contrast = 64;
+	cam->color = 64;
+	cam->hue = 0;
+
+	/* Select requested transfer mode */
+	switch (parmode) {
+	default:	/* Auto-detect (priority: hw-ecp, hw-epp, sw-ecp) */
+	case 0:
+		if (port->modes & PARPORT_MODE_ECP)
+			cam->ppmode = IEEE1284_MODE_ECP;
+		else if (port->modes & PARPORT_MODE_EPP)
+			cam->ppmode = IEEE1284_MODE_EPP;
+		else
+			cam->ppmode = IEEE1284_MODE_ECP;
+		break;
+	case 1:		/* hw- or sw-ecp */
+		cam->ppmode = IEEE1284_MODE_ECP;
+		break;
+	case 2:		/* hw- or sw-epp */
+		cam->ppmode = IEEE1284_MODE_EPP;
+		break;
+	}
+
+	/* Tell the parport driver that we exists */
+	cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL);
+	if (cam->pdev == NULL) {
+		DPRINTF("parport_register_device() failed\n");
+		return -1;
+	}
+	w9966_set_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV);
+
+	w9966_pdev_claim(cam);
+
+	/* Setup a default capture mode */
+	if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) {
+		DPRINTF("w9966_setup() failed.\n");
+		return -1;
+	}
+
+	w9966_pdev_release(cam);
+
+	/* Fill in the video_device struct and register us to v4l */
+	strlcpy(cam->vdev.name, W9966_DRIVERNAME, sizeof(cam->vdev.name));
+	cam->vdev.v4l2_dev = v4l2_dev;
+	cam->vdev.fops = &w9966_fops;
+	cam->vdev.ioctl_ops = &w9966_ioctl_ops;
+	cam->vdev.release = video_device_release_empty;
+	video_set_drvdata(&cam->vdev, cam);
+
+	mutex_init(&cam->lock);
+
+	if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0)
+		return -1;
+
+	w9966_set_state(cam, W9966_STATE_VDEV, W9966_STATE_VDEV);
+
+	/* All ok */
+	v4l2_info(v4l2_dev, "Found and initialized a webcam on %s.\n",
+			cam->pport->name);
+	return 0;
+}
+
+
+/* Terminate everything gracefully */
+static void w9966_term(struct w9966 *cam)
+{
+	/* Unregister from v4l */
+	if (w9966_get_state(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) {
+		video_unregister_device(&cam->vdev);
+		w9966_set_state(cam, W9966_STATE_VDEV, 0);
+	}
+
+	/* Terminate from IEEE1284 mode and release pdev block */
+	if (w9966_get_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
+		w9966_pdev_claim(cam);
+		parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT);
+		w9966_pdev_release(cam);
+	}
+
+	/* Unregister from parport */
+	if (w9966_get_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
+		parport_unregister_device(cam->pdev);
+		w9966_set_state(cam, W9966_STATE_PDEV, 0);
+	}
+}
+
+
+/* Called once for every parport on init */
 static void w9966_attach(struct parport *port)
 {
 	int i;
 
-	for (i = 0; i < W9966_MAXCAMS; i++)
-	{
-		if (w9966_cams[i].dev_state != 0)	// Cam is already assigned
+	for (i = 0; i < W9966_MAXCAMS; i++) {
+		if (w9966_cams[i].dev_state != 0)	/* Cam is already assigned */
 			continue;
-		if (
-			strcmp(pardev[i], "aggressive") == 0 ||
-			strcmp(pardev[i], port->name) == 0
-		) {
+		if (strcmp(pardev[i], "aggressive") == 0 || strcmp(pardev[i], port->name) == 0) {
 			if (w9966_init(&w9966_cams[i], port) != 0)
-			w9966_term(&w9966_cams[i]);
-			break;	// return
+				w9966_term(&w9966_cams[i]);
+			break;	/* return */
 		}
 	}
 }
 
-// Called once for every parport on termination
+/* Called once for every parport on termination */
 static void w9966_detach(struct parport *port)
 {
 	int i;
+
 	for (i = 0; i < W9966_MAXCAMS; i++)
-	if (w9966_cams[i].dev_state != 0 && w9966_cams[i].pport == port)
-		w9966_term(&w9966_cams[i]);
+		if (w9966_cams[i].dev_state != 0 && w9966_cams[i].pport == port)
+			w9966_term(&w9966_cams[i]);
 }
 
 
@@ -977,17 +973,18 @@
 	.detach = w9966_detach,
 };
 
-// Module entry point
+/* Module entry point */
 static int __init w9966_mod_init(void)
 {
 	int i;
+
 	for (i = 0; i < W9966_MAXCAMS; i++)
 		w9966_cams[i].dev_state = 0;
 
 	return parport_register_driver(&w9966_ppd);
 }
 
-// Module cleanup
+/* Module cleanup */
 static void __exit w9966_mod_term(void)
 {
 	parport_unregister_driver(&w9966_ppd);
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
index e44e4b5..bb51cfb 100644
--- a/drivers/media/video/zc0301/zc0301_core.c
+++ b/drivers/media/video/zc0301/zc0301_core.c
@@ -1153,7 +1153,7 @@
 	if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
 		return -EFAULT;
 
-	for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+	for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) {
 		if (ctrl.id == s->qctrl[i].id) {
 			if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
 				return -EINVAL;
@@ -1163,7 +1163,9 @@
 			ctrl.value -= ctrl.value % s->qctrl[i].step;
 			break;
 		}
-
+	}
+	if (i == ARRAY_SIZE(s->qctrl))
+		return -EINVAL;
 	if ((err = s->set_ctrl(cam, &ctrl)))
 		return err;
 
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
index 3a408de..0be783c 100644
--- a/drivers/media/video/zc0301/zc0301_sensor.h
+++ b/drivers/media/video/zc0301/zc0301_sensor.h
@@ -58,7 +58,7 @@
 	.idProduct = (prod),                                                  \
 	.bInterfaceClass = (intclass)
 
-#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
+#if !defined CONFIG_USB_GSPCA_ZC3XX && !defined CONFIG_USB_GSPCA_ZC3XX_MODULE
 #define ZC0301_ID_TABLE                                                       \
 static const struct usb_device_id zc0301_id_table[] =  {                      \
 	{ ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
diff --git a/drivers/media/video/zoran/zoran.h b/drivers/media/video/zoran/zoran.h
index cb1de7e..8997add 100644
--- a/drivers/media/video/zoran/zoran.h
+++ b/drivers/media/video/zoran/zoran.h
@@ -33,6 +33,10 @@
 
 #include <media/v4l2-device.h>
 
+#define ZORAN_VIDMODE_PAL	0
+#define ZORAN_VIDMODE_NTSC	1
+#define ZORAN_VIDMODE_SECAM	2
+
 struct zoran_requestbuffers {
 	unsigned long count;	/* Number of buffers for MJPEG grabbing */
 	unsigned long size;	/* Size PER BUFFER in bytes */
@@ -48,7 +52,7 @@
 struct zoran_status {
 	int input;		/* Input channel, has to be set prior to BUZIOC_G_STATUS */
 	int signal;		/* Returned: 1 if valid video signal detected */
-	int norm;		/* Returned: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */
+	int norm;		/* Returned: ZORAN_VIDMODE_PAL or ZORAN_VIDMODE_NTSC */
 	int color;		/* Returned: 1 if color signal detected */
 };
 
@@ -62,7 +66,7 @@
 	/* Main control parameters */
 
 	int input;		/* Input channel: 0 = Composite, 1 = S-VHS */
-	int norm;		/* Norm: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */
+	int norm;		/* Norm: ZORAN_VIDMODE_PAL or ZORAN_VIDMODE_NTSC */
 	int decimation;		/* decimation of captured video,
 				 * enlargement of video played back.
 				 * Valid values are 1, 2, 4 or 0.
@@ -131,13 +135,13 @@
 /*
 Private IOCTL to set up for displaying MJPEG
 */
-#define BUZIOC_G_PARAMS       _IOR ('v', BASE_VIDIOCPRIVATE+0,  struct zoran_params)
-#define BUZIOC_S_PARAMS       _IOWR('v', BASE_VIDIOCPRIVATE+1,  struct zoran_params)
-#define BUZIOC_REQBUFS        _IOWR('v', BASE_VIDIOCPRIVATE+2,  struct zoran_requestbuffers)
-#define BUZIOC_QBUF_CAPT      _IOW ('v', BASE_VIDIOCPRIVATE+3,  int)
-#define BUZIOC_QBUF_PLAY      _IOW ('v', BASE_VIDIOCPRIVATE+4,  int)
-#define BUZIOC_SYNC           _IOR ('v', BASE_VIDIOCPRIVATE+5,  struct zoran_sync)
-#define BUZIOC_G_STATUS       _IOWR('v', BASE_VIDIOCPRIVATE+6,  struct zoran_status)
+#define BUZIOC_G_PARAMS       _IOR ('v', BASE_VIDIOC_PRIVATE+0,  struct zoran_params)
+#define BUZIOC_S_PARAMS       _IOWR('v', BASE_VIDIOC_PRIVATE+1,  struct zoran_params)
+#define BUZIOC_REQBUFS        _IOWR('v', BASE_VIDIOC_PRIVATE+2,  struct zoran_requestbuffers)
+#define BUZIOC_QBUF_CAPT      _IOW ('v', BASE_VIDIOC_PRIVATE+3,  int)
+#define BUZIOC_QBUF_PLAY      _IOW ('v', BASE_VIDIOC_PRIVATE+4,  int)
+#define BUZIOC_SYNC           _IOR ('v', BASE_VIDIOC_PRIVATE+5,  struct zoran_sync)
+#define BUZIOC_G_STATUS       _IOWR('v', BASE_VIDIOC_PRIVATE+6,  struct zoran_status)
 
 
 #ifdef __KERNEL__
@@ -401,7 +405,7 @@
 	spinlock_t spinlock;	/* Spinlock */
 
 	/* Video for Linux parameters */
-	int input;	/* card's norm and input - norm=VIDEO_MODE_* */
+	int input;	/* card's norm and input */
 	v4l2_std_id norm;
 
 	/* Current buffer params */
diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c
index ec41303..6f89d0a 100644
--- a/drivers/media/video/zoran/zoran_driver.c
+++ b/drivers/media/video/zoran/zoran_driver.c
@@ -60,7 +60,7 @@
 
 #include <linux/spinlock.h>
 
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include "videocodec.h"
@@ -1549,11 +1549,11 @@
 		mutex_lock(&zr->resource_lock);
 
 		if (zr->norm & V4L2_STD_NTSC)
-			bparams->norm = VIDEO_MODE_NTSC;
-		else if (zr->norm & V4L2_STD_PAL)
-			bparams->norm = VIDEO_MODE_PAL;
+			bparams->norm = ZORAN_VIDMODE_NTSC;
+		else if (zr->norm & V4L2_STD_SECAM)
+			bparams->norm = ZORAN_VIDMODE_SECAM;
 		else
-			bparams->norm = VIDEO_MODE_SECAM;
+			bparams->norm = ZORAN_VIDMODE_PAL;
 
 		bparams->input = zr->input;
 
@@ -1789,11 +1789,11 @@
 			bstat->signal =
 			    (status & V4L2_IN_ST_NO_SIGNAL) ? 0 : 1;
 			if (norm & V4L2_STD_NTSC)
-				bstat->norm = VIDEO_MODE_NTSC;
+				bstat->norm = ZORAN_VIDMODE_NTSC;
 			else if (norm & V4L2_STD_SECAM)
-				bstat->norm = VIDEO_MODE_SECAM;
+				bstat->norm = ZORAN_VIDMODE_SECAM;
 			else
-				bstat->norm = VIDEO_MODE_PAL;
+				bstat->norm = ZORAN_VIDMODE_PAL;
 
 			bstat->color =
 			    (status & V4L2_IN_ST_NO_COLOR) ? 0 : 1;
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
index 3d4bac2..a82b5bd 100644
--- a/drivers/media/video/zr364xx.c
+++ b/drivers/media/video/zr364xx.c
@@ -376,8 +376,8 @@
 	if (*count == 0)
 		*count = ZR364XX_DEF_BUFS;
 
-	while (*size * (*count) > ZR364XX_DEF_BUFS * 1024 * 1024)
-		(*count)--;
+	if (*size * *count > ZR364XX_DEF_BUFS * 1024 * 1024)
+		*count = (ZR364XX_DEF_BUFS * 1024 * 1024) / *size;
 
 	return 0;
 }
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 7696a66..5589616 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -49,6 +49,8 @@
 
 source "drivers/staging/cx25821/Kconfig"
 
+source "drivers/staging/tm6000/Kconfig"
+
 source "drivers/staging/usbip/Kconfig"
 
 source "drivers/staging/winbond/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index ea2e70e..ec45d4b 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -7,6 +7,7 @@
 obj-$(CONFIG_SLICOSS)		+= slicoss/
 obj-$(CONFIG_VIDEO_GO7007)	+= go7007/
 obj-$(CONFIG_VIDEO_CX25821)	+= cx25821/
+obj-$(CONFIG_VIDEO_TM6000)	+= tm6000/
 obj-$(CONFIG_USB_IP_COMMON)	+= usbip/
 obj-$(CONFIG_W35UND)		+= winbond/
 obj-$(CONFIG_PRISM2_USB)	+= wlan-ng/
diff --git a/drivers/staging/cx25821/cx25821-alsa.c b/drivers/staging/cx25821/cx25821-alsa.c
index 061add3..1798975 100644
--- a/drivers/staging/cx25821/cx25821-alsa.c
+++ b/drivers/staging/cx25821/cx25821-alsa.c
@@ -29,7 +29,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 
-#include <asm/delay.h>
+#include <linux/delay.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -42,10 +42,10 @@
 
 #define AUDIO_SRAM_CHANNEL	SRAM_CH08
 
-#define dprintk(level,fmt, arg...)	if (debug >= level) \
+#define dprintk(level, fmt, arg...)	if (debug >= level) \
 	printk(KERN_INFO "%s/1: " fmt, chip->dev->name , ## arg)
 
-#define dprintk_core(level,fmt, arg...)	if (debug >= level) \
+#define dprintk_core(level, fmt, arg...)	if (debug >= level) \
 	printk(KERN_DEBUG "%s/1: " fmt, chip->dev->name , ## arg)
 
 /****************************************************************************
@@ -81,7 +81,6 @@
 
 	struct snd_pcm_substream *substream;
 };
-typedef struct cx25821_audio_dev snd_cx25821_card_t;
 
 
 /****************************************************************************
@@ -90,7 +89,7 @@
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
-static int enable[SNDRV_CARDS] = { 1,[1 ... (SNDRV_CARDS - 1)] = 1 };
+static int enable[SNDRV_CARDS] = { 1, [1 ... (SNDRV_CARDS - 1)] = 1 };
 
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable cx25821 soundcard. default enabled.");
@@ -105,7 +104,7 @@
 MODULE_DESCRIPTION("ALSA driver module for cx25821 based capture cards");
 MODULE_AUTHOR("Hiep Huynh");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Conexant,25821}");	//"{{Conexant,23881},"
+MODULE_SUPPORTED_DEVICE("{{Conexant,25821}");	/* "{{Conexant,23881}," */
 
 static unsigned int debug;
 module_param(debug, int, 0644);
@@ -135,7 +134,7 @@
  * BOARD Specific: Sets audio DMA
  */
 
-static int _cx25821_start_audio_dma(snd_cx25821_card_t * chip)
+static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip)
 {
 	struct cx25821_buffer *buf = chip->buf;
 	struct cx25821_dev *dev = chip->dev;
@@ -143,7 +142,7 @@
 	    &cx25821_sram_channels[AUDIO_SRAM_CHANNEL];
 	u32 tmp = 0;
 
-	// enable output on the GPIO 0 for the MCLK ADC (Audio)
+	/* enable output on the GPIO 0 for the MCLK ADC (Audio) */
 	cx25821_set_gpiopin_direction(chip->dev, 0, 0);
 
 	/* Make sure RISC/FIFO are off before changing FIFO/RISC settings */
@@ -158,18 +157,23 @@
 	cx_write(AUD_A_LNGTH, buf->bpl);
 
 	/* reset counter */
-	cx_write(AUD_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET);	//GP_COUNT_CONTROL_RESET = 0x3
+	/* GP_COUNT_CONTROL_RESET = 0x3 */
+	cx_write(AUD_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET);
 	atomic_set(&chip->count, 0);
 
-	//Set the input mode to 16-bit
+	/* Set the input mode to 16-bit */
 	tmp = cx_read(AUD_A_CFG);
 	cx_write(AUD_A_CFG,
 		 tmp | FLD_AUD_DST_PK_MODE | FLD_AUD_DST_ENABLE |
 		 FLD_AUD_CLK_ENABLE);
 
-	//printk(KERN_INFO "DEBUG: Start audio DMA, %d B/line, cmds_start(0x%x)= %d lines/FIFO, %d periods, %d "
-	//      "byte buffer\n", buf->bpl, audio_ch->cmds_start, cx_read(audio_ch->cmds_start + 12)>>1,
-	//      chip->num_periods, buf->bpl * chip->num_periods);
+	/* printk(KERN_INFO "DEBUG: Start audio DMA, %d B/line,"
+				"cmds_start(0x%x)= %d lines/FIFO, %d periods, "
+				"%d byte buffer\n", buf->bpl,
+				audio_ch->cmds_start,
+				cx_read(audio_ch->cmds_start + 12)>>1,
+				chip->num_periods, buf->bpl *chip->num_periods);
+	*/
 
 	/* Enables corresponding bits at AUD_INT_STAT */
 	cx_write(AUD_A_INT_MSK,
@@ -182,7 +186,7 @@
 	/* enable audio irqs */
 	cx_set(PCI_INT_MSK, chip->dev->pci_irqmask | PCI_MSK_AUD_INT);
 
-	// Turn on audio downstream fifo and risc enable 0x101
+	/* Turn on audio downstream fifo and risc enable 0x101 */
 	tmp = cx_read(AUD_INT_DMA_CTL);
 	cx_set(AUD_INT_DMA_CTL,
 	       tmp | (FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN));
@@ -194,7 +198,7 @@
 /*
  * BOARD Specific: Resets audio DMA
  */
-static int _cx25821_stop_audio_dma(snd_cx25821_card_t * chip)
+static int _cx25821_stop_audio_dma(struct cx25821_audio_dev *chip)
 {
 	struct cx25821_dev *dev = chip->dev;
 
@@ -232,13 +236,13 @@
 /*
  * BOARD Specific: Threats IRQ audio specific calls
  */
-static void cx25821_aud_irq(snd_cx25821_card_t * chip, u32 status, u32 mask)
+static void cx25821_aud_irq(struct cx25821_audio_dev *chip, u32 status,
+			    u32 mask)
 {
 	struct cx25821_dev *dev = chip->dev;
 
-	if (0 == (status & mask)) {
+	if (0 == (status & mask))
 		return;
-	}
 
 	cx_write(AUD_A_INT_STAT, status);
 	if (debug > 1 || (status & mask & ~0xff))
@@ -277,7 +281,7 @@
  */
 static irqreturn_t cx25821_irq(int irq, void *dev_id)
 {
-	snd_cx25821_card_t *chip = dev_id;
+	struct cx25821_audio_dev *chip = dev_id;
 	struct cx25821_dev *dev = chip->dev;
 	u32 status, pci_status;
 	u32 audint_status, audint_mask;
@@ -318,11 +322,11 @@
 	if (handled)
 		cx_write(PCI_INT_STAT, pci_status);
 
-      out:
+out:
 	return IRQ_RETVAL(handled);
 }
 
-static int dsp_buffer_free(snd_cx25821_card_t * chip)
+static int dsp_buffer_free(struct cx25821_audio_dev *chip)
 {
 	BUG_ON(!chip->dma_size);
 
@@ -363,7 +367,8 @@
 	.period_bytes_max = DEFAULT_FIFO_SIZE / 3,
 	.periods_min = 1,
 	.periods_max = AUDIO_LINE_SIZE,
-	.buffer_bytes_max = (AUDIO_LINE_SIZE * AUDIO_LINE_SIZE),	//128*128 = 16384 = 1024 * 16
+	/* 128 * 128 = 16384 = 1024 * 16 */
+	.buffer_bytes_max = (AUDIO_LINE_SIZE * AUDIO_LINE_SIZE),
 };
 
 /*
@@ -371,7 +376,7 @@
  */
 static int snd_cx25821_pcm_open(struct snd_pcm_substream *substream)
 {
-	snd_cx25821_card_t *chip = snd_pcm_substream_chip(substream);
+	struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	int err;
 	unsigned int bpl = 0;
@@ -393,18 +398,19 @@
 
 	if (cx25821_sram_channels[AUDIO_SRAM_CHANNEL].fifo_size !=
 	    DEFAULT_FIFO_SIZE) {
-		bpl = cx25821_sram_channels[AUDIO_SRAM_CHANNEL].fifo_size / 3;	//since there are 3 audio Clusters
+		/* since there are 3 audio Clusters */
+		bpl = cx25821_sram_channels[AUDIO_SRAM_CHANNEL].fifo_size / 3;
 		bpl &= ~7;	/* must be multiple of 8 */
 
-		if (bpl > AUDIO_LINE_SIZE) {
+		if (bpl > AUDIO_LINE_SIZE)
 			bpl = AUDIO_LINE_SIZE;
-		}
+
 		runtime->hw.period_bytes_min = bpl;
 		runtime->hw.period_bytes_max = bpl;
 	}
 
 	return 0;
-      _error:
+_error:
 	dprintk(1, "Error opening PCM!\n");
 	return err;
 }
@@ -423,7 +429,7 @@
 static int snd_cx25821_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *hw_params)
 {
-	snd_cx25821_card_t *chip = snd_pcm_substream_chip(substream);
+	struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream);
 	struct videobuf_dmabuf *dma;
 
 	struct cx25821_buffer *buf;
@@ -445,9 +451,8 @@
 	if (NULL == buf)
 		return -ENOMEM;
 
-	if (chip->period_size > AUDIO_LINE_SIZE) {
+	if (chip->period_size > AUDIO_LINE_SIZE)
 		chip->period_size = AUDIO_LINE_SIZE;
-	}
 
 	buf->vb.memory = V4L2_MEMORY_MMAP;
 	buf->vb.field = V4L2_FIELD_NONE;
@@ -474,7 +479,7 @@
 					  buf->vb.width, buf->vb.height, 1);
 	if (ret < 0) {
 		printk(KERN_INFO
-		       "DEBUG: ERROR after cx25821_risc_databuffer_audio() \n");
+			"DEBUG: ERROR after cx25821_risc_databuffer_audio()\n");
 		goto error;
 	}
 
@@ -494,7 +499,7 @@
 
 	return 0;
 
-      error:
+error:
 	kfree(buf);
 	return ret;
 }
@@ -504,7 +509,7 @@
  */
 static int snd_cx25821_hw_free(struct snd_pcm_substream *substream)
 {
-	snd_cx25821_card_t *chip = snd_pcm_substream_chip(substream);
+	struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream);
 
 	if (substream->runtime->dma_area) {
 		dsp_buffer_free(chip);
@@ -528,7 +533,7 @@
 static int snd_cx25821_card_trigger(struct snd_pcm_substream *substream,
 				    int cmd)
 {
-	snd_cx25821_card_t *chip = snd_pcm_substream_chip(substream);
+	struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream);
 	int err = 0;
 
 	/* Local interrupts are already disabled by ALSA */
@@ -557,7 +562,7 @@
 static snd_pcm_uframes_t snd_cx25821_pointer(struct snd_pcm_substream
 					     *substream)
 {
-	snd_cx25821_card_t *chip = snd_pcm_substream_chip(substream);
+	struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	u16 count;
 
@@ -593,10 +598,11 @@
 };
 
 /*
- * ALSA create a PCM device:  Called when initializing the board. Sets up the name and hooks up
- *  the callbacks
+ * ALSA create a PCM device:  Called when initializing the board.
+ * Sets up the name and hooks up the callbacks
  */
-static int snd_cx25821_pcm(snd_cx25821_card_t * chip, int device, char *name)
+static int snd_cx25821_pcm(struct cx25821_audio_dev *chip, int device,
+			   char *name)
 {
 	struct snd_pcm *pcm;
 	int err;
@@ -636,7 +642,7 @@
  * from the file.
  */
 /*
-static int snd_cx25821_free(snd_cx25821_card_t *chip)
+static int snd_cx25821_free(struct cx25821_audio_dev *chip)
 {
 	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
@@ -653,9 +659,9 @@
  */
 static void snd_cx25821_dev_free(struct snd_card *card)
 {
-	snd_cx25821_card_t *chip = card->private_data;
+	struct cx25821_audio_dev *chip = card->private_data;
 
-	//snd_cx25821_free(chip);
+	/* snd_cx25821_free(chip); */
 	snd_card_free(chip->card);
 }
 
@@ -665,23 +671,23 @@
 static int cx25821_audio_initdev(struct cx25821_dev *dev)
 {
 	struct snd_card *card;
-	snd_cx25821_card_t *chip;
+	struct cx25821_audio_dev *chip;
 	int err;
 
 	if (devno >= SNDRV_CARDS) {
 		printk(KERN_INFO "DEBUG ERROR: devno >= SNDRV_CARDS %s\n",
 		       __func__);
-		return (-ENODEV);
+		return -ENODEV;
 	}
 
 	if (!enable[devno]) {
 		++devno;
 		printk(KERN_INFO "DEBUG ERROR: !enable[devno] %s\n", __func__);
-		return (-ENOENT);
+		return -ENOENT;
 	}
 
 	err = snd_card_create(index[devno], id[devno], THIS_MODULE,
-			 sizeof(snd_cx25821_card_t), &card);
+			 sizeof(struct cx25821_audio_dev), &card);
 	if (err < 0) {
 		printk(KERN_INFO
 		       "DEBUG ERROR: cannot create snd_card_new in %s\n",
@@ -693,7 +699,7 @@
 
 	/* Card "creation" */
 	card->private_free = snd_cx25821_dev_free;
-	chip = (snd_cx25821_card_t *) card->private_data;
+	chip = (struct cx25821_audio_dev *) card->private_data;
 	spin_lock_init(&chip->reg_lock);
 
 	chip->dev = dev;
@@ -712,7 +718,8 @@
 		goto error;
 	}
 
-	if ((err = snd_cx25821_pcm(chip, 0, "cx25821 Digital")) < 0) {
+	err = snd_cx25821_pcm(chip, 0, "cx25821 Digital");
+	if (err < 0) {
 		printk(KERN_INFO
 		       "DEBUG ERROR: cannot create snd_cx25821_pcm %s\n",
 		       __func__);
@@ -741,7 +748,7 @@
 	devno++;
 	return 0;
 
-      error:
+error:
 	snd_card_free(card);
 	return err;
 }
diff --git a/drivers/staging/cx25821/cx25821-audio-upstream.c b/drivers/staging/cx25821/cx25821-audio-upstream.c
index 11c56bd..6a4e872 100644
--- a/drivers/staging/cx25821/cx25821-audio-upstream.c
+++ b/drivers/staging/cx25821/cx25821-audio-upstream.c
@@ -33,7 +33,7 @@
 #include <linux/fcntl.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards");
 MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
@@ -62,9 +62,8 @@
 	cdt = ch->cdt;
 	lines = ch->fifo_size / bpl;
 
-	if (lines > 3) {
+	if (lines > 3)
 		lines = 3;
-	}
 
 	BUG_ON(lines < 2);
 
@@ -84,7 +83,7 @@
 	cx_write(ch->cmds_start + 12, AUDIO_CDT_SIZE_QW);
 	cx_write(ch->cmds_start + 16, ch->ctrl_start);
 
-	//IQ size
+	/* IQ size */
 	cx_write(ch->cmds_start + 20, AUDIO_IQ_SIZE_DW);
 
 	for (i = 24; i < 80; i += 4)
@@ -100,7 +99,7 @@
 }
 
 static __le32 *cx25821_risc_field_upstream_audio(struct cx25821_dev *dev,
-						 __le32 * rp,
+						 __le32 *rp,
 						 dma_addr_t databuf_phys_addr,
 						 unsigned int bpl,
 						 int fifo_enable)
@@ -116,8 +115,10 @@
 		*(rp++) = cpu_to_le32(databuf_phys_addr + offset);
 		*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
 
-		// Check if we need to enable the FIFO after the first 3 lines
-		// For the upstream audio channel, the risc engine will enable the FIFO.
+		/* Check if we need to enable the FIFO
+		 * after the first 3 lines.
+		 * For the upstream audio channel,
+		 * the risc engine will enable the FIFO */
 		if (fifo_enable && line == 2) {
 			*(rp++) = RISC_WRITECR;
 			*(rp++) = sram_ch->dma_ctl;
@@ -160,7 +161,7 @@
 			risc_flag = RISC_CNT_INC;
 		}
 
-		//Calculate physical jump address
+		/* Calculate physical jump address */
 		if ((frame + 1) == NUM_AUDIO_FRAMES) {
 			risc_phys_jump_addr =
 			    dev->_risc_phys_start_addr +
@@ -179,17 +180,17 @@
 						       fifo_enable);
 
 		if (USE_RISC_NOOP_AUDIO) {
-			for (i = 0; i < NUM_NO_OPS; i++) {
+			for (i = 0; i < NUM_NO_OPS; i++)
 				*(rp++) = cpu_to_le32(RISC_NOOP);
-			}
 		}
 
-		// Loop to (Nth)FrameRISC or to Start of Risc program & generate IRQ
+		/* Loop to (Nth)FrameRISC or to Start of Risc program &
+		 * generate IRQ */
 		*(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag);
 		*(rp++) = cpu_to_le32(risc_phys_jump_addr);
 		*(rp++) = cpu_to_le32(0);
 
-		//Recalculate virtual address based on frame index
+		/* Recalculate virtual address based on frame index */
 		rp = dev->_risc_virt_addr + RISC_SYNC_INSTRUCTION_SIZE / 4 +
 		    (AUDIO_RISC_DMA_BUF_SIZE * (frame + 1) / 4);
 	}
@@ -220,19 +221,19 @@
 	u32 tmp = 0;
 
 	if (!dev->_audio_is_running) {
-		printk
-		    ("cx25821: No audio file is currently running so return!\n");
+		printk(KERN_DEBUG
+		    "cx25821: No audio file is currently running so return!\n");
 		return;
 	}
-	//Disable RISC interrupts
+	/* Disable RISC interrupts */
 	cx_write(sram_ch->int_msk, 0);
 
-	//Turn OFF risc and fifo enable in AUD_DMA_CNTRL
+	/* Turn OFF risc and fifo enable in AUD_DMA_CNTRL */
 	tmp = cx_read(sram_ch->dma_ctl);
 	cx_write(sram_ch->dma_ctl,
 		 tmp & ~(sram_ch->fld_aud_fifo_en | sram_ch->fld_aud_risc_en));
 
-	//Clear data buffer memory
+	/* Clear data buffer memory */
 	if (dev->_audiodata_buf_virt_addr)
 		memset(dev->_audiodata_buf_virt_addr, 0,
 		       dev->_audiodata_buf_size);
@@ -253,9 +254,8 @@
 
 void cx25821_free_mem_upstream_audio(struct cx25821_dev *dev)
 {
-	if (dev->_audio_is_running) {
+	if (dev->_audio_is_running)
 		cx25821_stop_upstream_audio(dev);
-	}
 
 	cx25821_free_memory_audio(dev);
 }
@@ -282,7 +282,7 @@
 
 	if (IS_ERR(myfile)) {
 		const int open_errno = -PTR_ERR(myfile);
-		printk("%s(): ERROR opening file(%s) with errno = %d! \n",
+		printk(KERN_ERR "%s(): ERROR opening file(%s) with errno = %d!\n",
 		       __func__, dev->_audiofilename, open_errno);
 		return PTR_ERR(myfile);
 	} else {
@@ -294,7 +294,7 @@
 		}
 
 		if (!myfile->f_op->read) {
-			printk("%s: File has no READ operations registered! \n",
+			printk("%s: File has no READ operations registered!\n",
 			       __func__);
 			filp_close(myfile, NULL);
 			return -EIO;
@@ -347,7 +347,7 @@
 	    container_of(work, struct cx25821_dev, _audio_work_entry);
 
 	if (!dev) {
-		printk("ERROR %s(): since container_of(work_struct) FAILED! \n",
+		printk(KERN_ERR "ERROR %s(): since container_of(work_struct) FAILED!\n",
 		       __func__);
 		return;
 	}
@@ -373,19 +373,19 @@
 
 	if (IS_ERR(myfile)) {
 		const int open_errno = -PTR_ERR(myfile);
-		printk("%s(): ERROR opening file(%s) with errno = %d! \n",
+		printk(KERN_ERR "%s(): ERROR opening file(%s) with errno = %d!\n",
 		       __func__, dev->_audiofilename, open_errno);
 		return PTR_ERR(myfile);
 	} else {
 		if (!(myfile->f_op)) {
-			printk("%s: File has no file operations registered! \n",
+			printk("%s: File has no file operations registered!\n",
 			       __func__);
 			filp_close(myfile, NULL);
 			return -EIO;
 		}
 
 		if (!myfile->f_op->read) {
-			printk("%s: File has no READ operations registered! \n",
+			printk("%s: File has no READ operations registered!\n",
 			       __func__);
 			filp_close(myfile, NULL);
 			return -EIO;
@@ -421,13 +421,11 @@
 				}
 			}
 
-			if (i > 0) {
+			if (i > 0)
 				dev->_audioframe_count++;
-			}
 
-			if (vfs_read_retval < line_size) {
+			if (vfs_read_retval < line_size)
 				break;
-			}
 		}
 
 		dev->_audiofile_status =
@@ -460,14 +458,14 @@
 	dev->_audiorisc_size = dev->audio_upstream_riscbuf_size;
 
 	if (!dev->_risc_virt_addr) {
-		printk
-		    ("cx25821 ERROR: pci_alloc_consistent() FAILED to allocate memory for RISC program! Returning.\n");
+		printk(KERN_DEBUG
+			"cx25821 ERROR: pci_alloc_consistent() FAILED to allocate memory for RISC program! Returning.\n");
 		return -ENOMEM;
 	}
-	//Clear out memory at address
+	/* Clear out memory at address */
 	memset(dev->_risc_virt_addr, 0, dev->_audiorisc_size);
 
-	//For Audio Data buffer allocation
+	/* For Audio Data buffer allocation */
 	dev->_audiodata_buf_virt_addr =
 	    pci_alloc_consistent(dev->pci, dev->audio_upstream_databuf_size,
 				 &data_dma_addr);
@@ -475,30 +473,30 @@
 	dev->_audiodata_buf_size = dev->audio_upstream_databuf_size;
 
 	if (!dev->_audiodata_buf_virt_addr) {
-		printk
-		    ("cx25821 ERROR: pci_alloc_consistent() FAILED to allocate memory for data buffer! Returning. \n");
+		printk(KERN_DEBUG
+			"cx25821 ERROR: pci_alloc_consistent() FAILED to allocate memory for data buffer! Returning.\n");
 		return -ENOMEM;
 	}
-	//Clear out memory at address
+	/* Clear out memory at address */
 	memset(dev->_audiodata_buf_virt_addr, 0, dev->_audiodata_buf_size);
 
 	ret = cx25821_openfile_audio(dev, sram_ch);
 	if (ret < 0)
 		return ret;
 
-	//Creating RISC programs
+	/* Creating RISC programs */
 	ret =
 	    cx25821_risc_buffer_upstream_audio(dev, dev->pci, bpl,
 					       dev->_audio_lines_count);
 	if (ret < 0) {
 		printk(KERN_DEBUG
-		       "cx25821 ERROR creating audio upstream RISC programs! \n");
+		      "cx25821 ERROR creating audio upstream RISC programs!\n");
 		goto error;
 	}
 
 	return 0;
 
-      error:
+error:
 	return ret;
 }
 
@@ -512,22 +510,22 @@
 	__le32 *rp;
 
 	if (status & FLD_AUD_SRC_RISCI1) {
-		//Get interrupt_index of the program that interrupted
+		/* Get interrupt_index of the program that interrupted */
 		u32 prog_cnt = cx_read(channel->gpcnt);
 
-		//Since we've identified our IRQ, clear our bits from the interrupt mask and interrupt status registers
+		/* Since we've identified our IRQ, clear our bits from the
+		 * interrupt mask and interrupt status registers */
 		cx_write(channel->int_msk, 0);
 		cx_write(channel->int_stat, cx_read(channel->int_stat));
 
 		spin_lock(&dev->slock);
 
 		while (prog_cnt != dev->_last_index_irq) {
-			//Update _last_index_irq
-			if (dev->_last_index_irq < (NUMBER_OF_PROGRAMS - 1)) {
+			/* Update _last_index_irq */
+			if (dev->_last_index_irq < (NUMBER_OF_PROGRAMS - 1))
 				dev->_last_index_irq++;
-			} else {
+			else
 				dev->_last_index_irq = 0;
-			}
 
 			dev->_audioframe_index = dev->_last_index_irq;
 
@@ -559,7 +557,7 @@
 						    cpu_to_le32(RISC_NOOP);
 					}
 				}
-				// Jump to 2nd Audio Frame
+				/* Jump to 2nd Audio Frame */
 				*(rp++) =
 				    cpu_to_le32(RISC_JUMP | RISC_IRQ1 |
 						RISC_CNT_RESET);
@@ -582,7 +580,8 @@
 			printk("%s: Audio Received OpCode Error Interrupt!\n",
 			       __func__);
 
-		// Read and write back the interrupt status register to clear our bits
+		/* Read and write back the interrupt status register to clear
+		 * our bits */
 		cx_write(channel->int_stat, cx_read(channel->int_stat));
 	}
 
@@ -591,7 +590,7 @@
 		       dev->_audioframe_count);
 		return -1;
 	}
-	//ElSE, set the interrupt mask register, re-enable irq.
+	/* ElSE, set the interrupt mask register, re-enable irq. */
 	int_msk_tmp = cx_read(channel->int_msk);
 	cx_write(channel->int_msk, int_msk_tmp |= _intr_msk);
 
@@ -613,7 +612,7 @@
 	msk_stat = cx_read(sram_ch->int_mstat);
 	audio_status = cx_read(sram_ch->int_stat);
 
-	// Only deal with our interrupt
+	/* Only deal with our interrupt */
 	if (audio_status) {
 		handled =
 		    cx25821_audio_upstream_irq(dev,
@@ -622,11 +621,10 @@
 					       audio_status);
 	}
 
-	if (handled < 0) {
+	if (handled < 0)
 		cx25821_stop_upstream_audio(dev);
-	} else {
+	else
 		handled += handled;
-	}
 
 	return IRQ_RETVAL(handled);
 }
@@ -638,13 +636,14 @@
 	u32 tmp;
 
 	do {
-		//Wait 10 microsecond before checking to see if the FIFO is turned ON.
+		/* Wait 10 microsecond before checking to see if the FIFO is
+		 * turned ON. */
 		udelay(10);
 
 		tmp = cx_read(sram_ch->dma_ctl);
 
-		if (count++ > 1000)	//10 millisecond timeout
-		{
+		/* 10 millisecond timeout */
+		if (count++ > 1000) {
 			printk
 			    ("cx25821 ERROR: %s() fifo is NOT turned on. Timeout!\n",
 			     __func__);
@@ -661,31 +660,34 @@
 	u32 tmp = 0;
 	int err = 0;
 
-	// Set the physical start address of the RISC program in the initial program counter(IPC) member of the CMDS.
+	/* Set the physical start address of the RISC program in the initial
+	 * program counter(IPC) member of the CMDS. */
 	cx_write(sram_ch->cmds_start + 0, dev->_risc_phys_addr);
-	cx_write(sram_ch->cmds_start + 4, 0);	/* Risc IPC High 64 bits 63-32 */
+	/* Risc IPC High 64 bits 63-32 */
+	cx_write(sram_ch->cmds_start + 4, 0);
 
 	/* reset counter */
 	cx_write(sram_ch->gpcnt_ctl, 3);
 
-	//Set the line length       (It looks like we do not need to set the line length)
+	/* Set the line length       (It looks like we do not need to set the
+	 * line length) */
 	cx_write(sram_ch->aud_length, AUDIO_LINE_SIZE & FLD_AUD_DST_LN_LNGTH);
 
-	//Set the input mode to 16-bit
+	/* Set the input mode to 16-bit */
 	tmp = cx_read(sram_ch->aud_cfg);
 	tmp |=
 	    FLD_AUD_SRC_ENABLE | FLD_AUD_DST_PK_MODE | FLD_AUD_CLK_ENABLE |
 	    FLD_AUD_MASTER_MODE | FLD_AUD_CLK_SELECT_PLL_D | FLD_AUD_SONY_MODE;
 	cx_write(sram_ch->aud_cfg, tmp);
 
-	// Read and write back the interrupt status register to clear it
+	/* Read and write back the interrupt status register to clear it */
 	tmp = cx_read(sram_ch->int_stat);
 	cx_write(sram_ch->int_stat, tmp);
 
-	// Clear our bits from the interrupt status register.
+	/* Clear our bits from the interrupt status register. */
 	cx_write(sram_ch->int_stat, _intr_msk);
 
-	//Set the interrupt mask register, enable irq.
+	/* Set the interrupt mask register, enable irq. */
 	cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit));
 	tmp = cx_read(sram_ch->int_msk);
 	cx_write(sram_ch->int_msk, tmp |= _intr_msk);
@@ -699,19 +701,19 @@
 		goto fail_irq;
 	}
 
-	// Start the DMA  engine
+	/* Start the DMA  engine */
 	tmp = cx_read(sram_ch->dma_ctl);
 	cx_set(sram_ch->dma_ctl, tmp | sram_ch->fld_aud_risc_en);
 
 	dev->_audio_is_running = 1;
 	dev->_is_first_audio_frame = 1;
 
-	// The fifo_en bit turns on by the first Risc program
+	/* The fifo_en bit turns on by the first Risc program */
 	cx25821_wait_fifo_enable(dev, sram_ch);
 
 	return 0;
 
-      fail_irq:
+fail_irq:
 	cx25821_dev_unregister(dev);
 	return err;
 }
@@ -731,14 +733,14 @@
 	dev->_audio_upstream_channel_select = channel_select;
 	sram_ch = &dev->sram_channels[channel_select];
 
-	//Work queue
+	/* Work queue */
 	INIT_WORK(&dev->_audio_work_entry, cx25821_audioups_handler);
 	dev->_irq_audio_queues =
 	    create_singlethread_workqueue("cx25821_audioworkqueue");
 
 	if (!dev->_irq_audio_queues) {
-		printk
-		    ("cx25821 ERROR: create_singlethread_workqueue() for Audio FAILED!\n");
+		printk(KERN_DEBUG
+			"cx25821 ERROR: create_singlethread_workqueue() for Audio FAILED!\n");
 		return -ENOMEM;
 	}
 
@@ -760,7 +762,7 @@
 		memcpy(dev->_audiofilename, dev->input_audiofilename,
 		       str_length + 1);
 
-		//Default if filename is empty string
+		/* Default if filename is empty string */
 		if (strcmp(dev->input_audiofilename, "") == 0) {
 			dev->_audiofilename = "/root/audioGOOD.wav";
 		}
@@ -784,7 +786,7 @@
 	    RISC_SYNC_INSTRUCTION_SIZE;
 	dev->audio_upstream_databuf_size = AUDIO_DATA_BUF_SZ * NUM_AUDIO_PROGS;
 
-	//Allocating buffers and prepare RISC program
+	/* Allocating buffers and prepare RISC program */
 	retval =
 	    cx25821_audio_upstream_buffer_prepare(dev, sram_ch, _line_size);
 	if (retval < 0) {
@@ -793,12 +795,12 @@
 		       dev->name);
 		goto error;
 	}
-	//Start RISC engine
+	/* Start RISC engine */
 	cx25821_start_audio_dma_upstream(dev, sram_ch);
 
 	return 0;
 
-      error:
+error:
 	cx25821_dev_unregister(dev);
 
 	return err;
diff --git a/drivers/staging/cx25821/cx25821-audups11.c b/drivers/staging/cx25821/cx25821-audups11.c
index e76451c..e49ead9 100644
--- a/drivers/staging/cx25821/cx25821-audups11.c
+++ b/drivers/staging/cx25821/cx25821-audups11.c
@@ -88,10 +88,10 @@
 }
 
 static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = buffer_setup,
-	.buf_prepare = buffer_prepare,
+	.buf_setup = cx25821_buffer_setup,
+	.buf_prepare = cx25821_buffer_prepare,
 	.buf_queue = buffer_queue,
-	.buf_release = buffer_release,
+	.buf_release = cx25821_buffer_release,
 };
 
 static int video_open(struct file *file)
@@ -145,7 +145,7 @@
 
 	switch (fh->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (res_locked(fh->dev, RESOURCE_VIDEO11))
+		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO11))
 			return -EBUSY;
 
 		return videobuf_read_one(&fh->vidq, data, count, ppos,
@@ -163,7 +163,7 @@
 	struct cx25821_fh *fh = file->private_data;
 	struct cx25821_buffer *buf;
 
-	if (res_check(fh, RESOURCE_VIDEO11)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO11)) {
 		/* streaming capture */
 		if (list_empty(&fh->vidq.stream))
 			return POLLERR;
@@ -191,19 +191,19 @@
 	//cx_write(channel11->dma_ctl, 0);
 
 	/* stop video capture */
-	if (res_check(fh, RESOURCE_VIDEO11)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO11)) {
 		videobuf_queue_cancel(&fh->vidq);
-		res_free(dev, fh, RESOURCE_VIDEO11);
+		cx25821_res_free(dev, fh, RESOURCE_VIDEO11);
 	}
 
 	if (fh->vidq.read_buf) {
-		buffer_release(&fh->vidq, fh->vidq.read_buf);
+		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
 		kfree(fh->vidq.read_buf);
 	}
 
 	videobuf_mmap_free(&fh->vidq);
 
-	v4l2_prio_close(&dev->prio, &fh->prio);
+	v4l2_prio_close(&dev->prio, fh->prio);
 
 	file->private_data = NULL;
 	kfree(fh);
@@ -224,7 +224,7 @@
 		return -EINVAL;
 	}
 
-	if (unlikely(!res_get(dev, fh, get_resource(fh, RESOURCE_VIDEO11)))) {
+	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO11)))) {
 		return -EBUSY;
 	}
 
@@ -242,11 +242,11 @@
 	if (i != fh->type)
 		return -EINVAL;
 
-	res = get_resource(fh, RESOURCE_VIDEO11);
+	res = cx25821_get_resource(fh, RESOURCE_VIDEO11);
 	err = videobuf_streamoff(get_queue(fh));
 	if (err < 0)
 		return err;
-	res_free(dev, fh, res);
+	cx25821_res_free(dev, fh, res);
 	return 0;
 }
 
@@ -258,13 +258,13 @@
 	int err;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
 
 	dprintk(2, "%s()\n", __func__);
-	err = vidioc_try_fmt_vid_cap(file, priv, f);
+	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
 
 	if (0 != err)
 		return err;
@@ -350,7 +350,7 @@
 
 	if (fh) {
 		dev = fh->dev;
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
@@ -364,50 +364,50 @@
 	.release = video_release,
 	.read = video_read,
 	.poll = video_poll,
-	.mmap = video_mmap,
+	.mmap = cx25821_video_mmap,
 	.ioctl = video_ioctl_upstream11,
 };
 
 static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+	.vidioc_querycap = cx25821_vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
 	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = vidioc_reqbufs,
-	.vidioc_querybuf = vidioc_querybuf,
-	.vidioc_qbuf = vidioc_qbuf,
+	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
+	.vidioc_querybuf = cx25821_vidioc_querybuf,
+	.vidioc_qbuf = cx25821_vidioc_qbuf,
 	.vidioc_dqbuf = vidioc_dqbuf,
 #ifdef TUNER_FLAG
-	.vidioc_s_std = vidioc_s_std,
-	.vidioc_querystd = vidioc_querystd,
+	.vidioc_s_std = cx25821_vidioc_s_std,
+	.vidioc_querystd = cx25821_vidioc_querystd,
 #endif
-	.vidioc_cropcap = vidioc_cropcap,
-	.vidioc_s_crop = vidioc_s_crop,
-	.vidioc_g_crop = vidioc_g_crop,
-	.vidioc_enum_input = vidioc_enum_input,
-	.vidioc_g_input = vidioc_g_input,
-	.vidioc_s_input = vidioc_s_input,
-	.vidioc_g_ctrl = vidioc_g_ctrl,
+	.vidioc_cropcap = cx25821_vidioc_cropcap,
+	.vidioc_s_crop = cx25821_vidioc_s_crop,
+	.vidioc_g_crop = cx25821_vidioc_g_crop,
+	.vidioc_enum_input = cx25821_vidioc_enum_input,
+	.vidioc_g_input = cx25821_vidioc_g_input,
+	.vidioc_s_input = cx25821_vidioc_s_input,
+	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
 	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = vidioc_queryctrl,
+	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
 	.vidioc_streamon = vidioc_streamon,
 	.vidioc_streamoff = vidioc_streamoff,
 	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = vidioc_g_priority,
-	.vidioc_s_priority = vidioc_s_priority,
+	.vidioc_g_priority = cx25821_vidioc_g_priority,
+	.vidioc_s_priority = cx25821_vidioc_s_priority,
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = vidiocgmbuf,
+	.vidiocgmbuf = cx25821_vidiocgmbuf,
 #endif
 #ifdef TUNER_FLAG
-	.vidioc_g_tuner = vidioc_g_tuner,
-	.vidioc_s_tuner = vidioc_s_tuner,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
+	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
+	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
+	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
 #endif
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = vidioc_g_register,
-	.vidioc_s_register = vidioc_s_register,
+	.vidioc_g_register = cx25821_vidioc_g_register,
+	.vidioc_s_register = cx25821_vidioc_s_register,
 #endif
 };
 
diff --git a/drivers/staging/cx25821/cx25821-cards.c b/drivers/staging/cx25821/cx25821-cards.c
index 4d0b9ea..da0f56d 100644
--- a/drivers/staging/cx25821/cx25821-cards.c
+++ b/drivers/staging/cx25821/cx25821-cards.c
@@ -30,12 +30,12 @@
 #include "cx25821.h"
 #include "tuner-xc2028.h"
 
-// board config info
+/* board config info */
 
 struct cx25821_board cx25821_boards[] = {
 	[UNKNOWN_BOARD] = {
 			   .name = "UNKNOWN/GENERIC",
-			   // Ensure safe default for unknown boards
+			   /* Ensure safe default for unknown boards */
 			   .clk_freq = 0,
 			   },
 
diff --git a/drivers/staging/cx25821/cx25821-core.c b/drivers/staging/cx25821/cx25821-core.c
index 9e9b8c3..d90abb3 100644
--- a/drivers/staging/cx25821/cx25821-core.c
+++ b/drivers/staging/cx25821/cx25821-core.c
@@ -32,6 +32,7 @@
 MODULE_LICENSE("GPL");
 
 struct list_head cx25821_devlist;
+EXPORT_SYMBOL(cx25821_devlist);
 
 static unsigned int debug;
 module_param(debug, int, 0644);
@@ -313,6 +314,7 @@
 		       .irq_bit = 11,
 		       },
 };
+EXPORT_SYMBOL(cx25821_sram_channels);
 
 struct sram_channel *channel0 = &cx25821_sram_channels[SRAM_CH00];
 struct sram_channel *channel1 = &cx25821_sram_channels[SRAM_CH01];
@@ -388,70 +390,74 @@
 {
 	u32 tmp;
 
-	// enable RUN_RISC in Pecos
+	/* enable RUN_RISC in Pecos */
 	cx_write(DEV_CNTRL2, 0x20);
 
-	// Set the master PCI interrupt masks to enable video, audio, MBIF, and GPIO interrupts
-	// I2C interrupt masking is handled by the I2C objects themselves.
+	/* Set the master PCI interrupt masks to enable video, audio, MBIF,
+	 * and GPIO interrupts
+	 * I2C interrupt masking is handled by the I2C objects themselves. */
 	cx_write(PCI_INT_MSK, 0x2001FFFF);
 
 	tmp = cx_read(RDR_TLCTL0);
-	tmp &= ~FLD_CFG_RCB_CK_EN;	// Clear the RCB_CK_EN bit
+	tmp &= ~FLD_CFG_RCB_CK_EN;	/* Clear the RCB_CK_EN bit */
 	cx_write(RDR_TLCTL0, tmp);
 
-	// PLL-A setting for the Audio Master Clock
+	/* PLL-A setting for the Audio Master Clock */
 	cx_write(PLL_A_INT_FRAC, 0x9807A58B);
 
-	// PLL_A_POST = 0x1C, PLL_A_OUT_TO_PIN = 0x1
+	/* PLL_A_POST = 0x1C, PLL_A_OUT_TO_PIN = 0x1 */
 	cx_write(PLL_A_POST_STAT_BIST, 0x8000019C);
 
-	// clear reset bit [31]
+	/* clear reset bit [31] */
 	tmp = cx_read(PLL_A_INT_FRAC);
 	cx_write(PLL_A_INT_FRAC, tmp & 0x7FFFFFFF);
 
-	// PLL-B setting for Mobilygen Host Bus Interface
+	/* PLL-B setting for Mobilygen Host Bus Interface */
 	cx_write(PLL_B_INT_FRAC, 0x9883A86F);
 
-	// PLL_B_POST = 0xD, PLL_B_OUT_TO_PIN = 0x0
+	/* PLL_B_POST = 0xD, PLL_B_OUT_TO_PIN = 0x0 */
 	cx_write(PLL_B_POST_STAT_BIST, 0x8000018D);
 
-	// clear reset bit [31]
+	/* clear reset bit [31] */
 	tmp = cx_read(PLL_B_INT_FRAC);
 	cx_write(PLL_B_INT_FRAC, tmp & 0x7FFFFFFF);
 
-	// PLL-C setting for video upstream channel
+	/* PLL-C setting for video upstream channel */
 	cx_write(PLL_C_INT_FRAC, 0x96A0EA3F);
 
-	// PLL_C_POST = 0x3, PLL_C_OUT_TO_PIN = 0x0
+	/* PLL_C_POST = 0x3, PLL_C_OUT_TO_PIN = 0x0 */
 	cx_write(PLL_C_POST_STAT_BIST, 0x80000103);
 
-	// clear reset bit [31]
+	/* clear reset bit [31] */
 	tmp = cx_read(PLL_C_INT_FRAC);
 	cx_write(PLL_C_INT_FRAC, tmp & 0x7FFFFFFF);
 
-	// PLL-D setting for audio upstream channel
+	/* PLL-D setting for audio upstream channel */
 	cx_write(PLL_D_INT_FRAC, 0x98757F5B);
 
-	// PLL_D_POST = 0x13, PLL_D_OUT_TO_PIN = 0x0
+	/* PLL_D_POST = 0x13, PLL_D_OUT_TO_PIN = 0x0 */
 	cx_write(PLL_D_POST_STAT_BIST, 0x80000113);
 
-	// clear reset bit [31]
+	/* clear reset bit [31] */
 	tmp = cx_read(PLL_D_INT_FRAC);
 	cx_write(PLL_D_INT_FRAC, tmp & 0x7FFFFFFF);
 
-	// This selects the PLL C clock source for the video upstream channel I and J
+	/* This selects the PLL C clock source for the video upstream channel
+	 * I and J */
 	tmp = cx_read(VID_CH_CLK_SEL);
 	cx_write(VID_CH_CLK_SEL, (tmp & 0x00FFFFFF) | 0x24000000);
 
-	// 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for channel A-C
-	//select 656/VIP DST for downstream Channel A - C
+	/* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for
+	 * channel A-C
+	 * select 656/VIP DST for downstream Channel A - C */
 	tmp = cx_read(VID_CH_MODE_SEL);
-	//cx_write( VID_CH_MODE_SEL, tmp | 0x1B0001FF);
+	/* cx_write( VID_CH_MODE_SEL, tmp | 0x1B0001FF); */
 	cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00);
 
-	// enables 656 port I and J as output
+	/* enables 656 port I and J as output */
 	tmp = cx_read(CLK_RST);
-	tmp |= FLD_USE_ALT_PLL_REF;	// use external ALT_PLL_REF pin as its reference clock instead
+	/* use external ALT_PLL_REF pin as its reference clock instead */
+	tmp |= FLD_USE_ALT_PLL_REF;
 	cx_write(CLK_RST, tmp & ~(FLD_VID_I_CLK_NOE | FLD_VID_J_CLK_NOE));
 
 	mdelay(100);
@@ -476,9 +482,8 @@
 	cdt = ch->cdt;
 	lines = ch->fifo_size / bpl;
 
-	if (lines > 4) {
+	if (lines > 4)
 		lines = 4;
-	}
 
 	BUG_ON(lines < 2);
 
@@ -494,16 +499,15 @@
 		cx_write(cdt + 16 * i + 12, 0);
 	}
 
-	//init the first cdt buffer
+	/* init the first cdt buffer */
 	for (i = 0; i < 128; i++)
 		cx_write(ch->fifo_start + 4 * i, i);
 
 	/* write CMDS */
-	if (ch->jumponly) {
+	if (ch->jumponly)
 		cx_write(ch->cmds_start + 0, 8);
-	} else {
+	else
 		cx_write(ch->cmds_start + 0, risc);
-	}
 
 	cx_write(ch->cmds_start + 4, 0);	/* 64 bits 63-32 */
 	cx_write(ch->cmds_start + 8, cdt);
@@ -526,6 +530,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(cx25821_sram_channel_setup);
 
 int cx25821_sram_channel_setup_audio(struct cx25821_dev *dev,
 				     struct sram_channel *ch,
@@ -546,9 +551,8 @@
 	cdt = ch->cdt;
 	lines = ch->fifo_size / bpl;
 
-	if (lines > 3) {
-		lines = 3;	//for AUDIO
-	}
+	if (lines > 3)
+		lines = 3;	/* for AUDIO */
 
 	BUG_ON(lines < 2);
 
@@ -565,25 +569,23 @@
 	}
 
 	/* write CMDS */
-	if (ch->jumponly) {
+	if (ch->jumponly)
 		cx_write(ch->cmds_start + 0, 8);
-	} else {
+	else
 		cx_write(ch->cmds_start + 0, risc);
-	}
 
 	cx_write(ch->cmds_start + 4, 0);	/* 64 bits 63-32 */
 	cx_write(ch->cmds_start + 8, cdt);
 	cx_write(ch->cmds_start + 12, (lines * 16) >> 3);
 	cx_write(ch->cmds_start + 16, ch->ctrl_start);
 
-	//IQ size
-	if (ch->jumponly) {
+	/* IQ size */
+	if (ch->jumponly)
 		cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2));
-	} else {
+	else
 		cx_write(ch->cmds_start + 20, 64 >> 2);
-	}
 
-	//zero out
+	/* zero out */
 	for (i = 24; i < 80; i += 4)
 		cx_write(ch->cmds_start + i, 0);
 
@@ -595,6 +597,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(cx25821_sram_channel_setup_audio);
 
 void cx25821_sram_channel_dump(struct cx25821_dev *dev, struct sram_channel *ch)
 {
@@ -658,6 +661,7 @@
 	printk(KERN_WARNING "        :   cnt2_reg: 0x%08x\n",
 	       cx_read(ch->cnt2_reg));
 }
+EXPORT_SYMBOL(cx25821_sram_channel_dump);
 
 void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev,
 				     struct sram_channel *ch)
@@ -731,7 +735,7 @@
 		printk(KERN_WARNING "instruction %d = 0x%x\n", i, risc);
 	}
 
-	//read data from the first cdt buffer
+	/* read data from the first cdt buffer */
 	risc = cx_read(AUD_A_CDT);
 	printk(KERN_WARNING "\nread cdt loc=0x%x\n", risc);
 	for (i = 0; i < 8; i++) {
@@ -741,31 +745,32 @@
 	printk(KERN_WARNING "\n\n");
 
 	value = cx_read(CLK_RST);
-	CX25821_INFO(" CLK_RST = 0x%x \n\n", value);
+	CX25821_INFO(" CLK_RST = 0x%x\n\n", value);
 
 	value = cx_read(PLL_A_POST_STAT_BIST);
-	CX25821_INFO(" PLL_A_POST_STAT_BIST = 0x%x \n\n", value);
+	CX25821_INFO(" PLL_A_POST_STAT_BIST = 0x%x\n\n", value);
 	value = cx_read(PLL_A_INT_FRAC);
-	CX25821_INFO(" PLL_A_INT_FRAC = 0x%x \n\n", value);
+	CX25821_INFO(" PLL_A_INT_FRAC = 0x%x\n\n", value);
 
 	value = cx_read(PLL_B_POST_STAT_BIST);
-	CX25821_INFO(" PLL_B_POST_STAT_BIST = 0x%x \n\n", value);
+	CX25821_INFO(" PLL_B_POST_STAT_BIST = 0x%x\n\n", value);
 	value = cx_read(PLL_B_INT_FRAC);
-	CX25821_INFO(" PLL_B_INT_FRAC = 0x%x \n\n", value);
+	CX25821_INFO(" PLL_B_INT_FRAC = 0x%x\n\n", value);
 
 	value = cx_read(PLL_C_POST_STAT_BIST);
-	CX25821_INFO(" PLL_C_POST_STAT_BIST = 0x%x \n\n", value);
+	CX25821_INFO(" PLL_C_POST_STAT_BIST = 0x%x\n\n", value);
 	value = cx_read(PLL_C_INT_FRAC);
-	CX25821_INFO(" PLL_C_INT_FRAC = 0x%x \n\n", value);
+	CX25821_INFO(" PLL_C_INT_FRAC = 0x%x\n\n", value);
 
 	value = cx_read(PLL_D_POST_STAT_BIST);
-	CX25821_INFO(" PLL_D_POST_STAT_BIST = 0x%x \n\n", value);
+	CX25821_INFO(" PLL_D_POST_STAT_BIST = 0x%x\n\n", value);
 	value = cx_read(PLL_D_INT_FRAC);
-	CX25821_INFO(" PLL_D_INT_FRAC = 0x%x \n\n", value);
+	CX25821_INFO(" PLL_D_INT_FRAC = 0x%x\n\n", value);
 
 	value = cx25821_i2c_read(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, &tmp);
-	CX25821_INFO(" AFE_AB_DIAG_CTRL (0x10900090) = 0x%x \n\n", value);
+	CX25821_INFO(" AFE_AB_DIAG_CTRL (0x10900090) = 0x%x\n\n", value);
 }
+EXPORT_SYMBOL(cx25821_sram_channel_dump_audio);
 
 static void cx25821_shutdown(struct cx25821_dev *dev)
 {
@@ -835,8 +840,8 @@
 	cx_write(AUD_E_INT_STAT, 0xffffffff);
 
 	cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000);
-	cx_write(PAD_CTRL, 0x12);	//for I2C
-	cx25821_registers_init(dev);	//init Pecos registers
+	cx_write(PAD_CTRL, 0x12);	/* for I2C */
+	cx25821_registers_init(dev);	/* init Pecos registers */
 	mdelay(100);
 
 	for (i = 0; i < VID_CHANNEL_NUM; i++) {
@@ -847,7 +852,7 @@
 		dev->use_cif_resolution[i] = FALSE;
 	}
 
-	//Probably only affect Downstream
+	/* Probably only affect Downstream */
 	for (i = VID_UPSTREAM_SRAM_CHANNEL_I; i <= VID_UPSTREAM_SRAM_CHANNEL_J;
 	     i++) {
 		cx25821_set_vip_mode(dev, &dev->sram_channels[i]);
@@ -859,7 +864,7 @@
 	cx25821_gpio_init(dev);
 }
 
-static int get_resources(struct cx25821_dev *dev)
+static int cx25821_get_resources(struct cx25821_dev *dev)
 {
 	if (request_mem_region
 	    (pci_resource_start(dev->pci, 0), pci_resource_len(dev->pci, 0),
@@ -944,12 +949,11 @@
 	dev->clk_freq = 28000000;
 	dev->sram_channels = cx25821_sram_channels;
 
-	if (dev->nr > 1) {
+	if (dev->nr > 1)
 		CX25821_INFO("dev->nr > 1!");
-	}
 
 	/* board config */
-	dev->board = 1;		//card[dev->nr];
+	dev->board = 1;		/* card[dev->nr]; */
 	dev->_max_num_decoders = MAX_DECODERS;
 
 	dev->pci_bus = dev->pci->bus->number;
@@ -967,7 +971,7 @@
 	dev->i2c_bus[0].i2c_period = (0x07 << 24);	/* 1.95MHz */
 
 
-	if (get_resources(dev) < 0) {
+	if (cx25821_get_resources(dev) < 0) {
 		printk(KERN_ERR "%s No more PCIe resources for "
 		       "subsystem: %04x:%04x\n",
 		       dev->name, dev->pci->subsystem_vendor,
@@ -1007,8 +1011,8 @@
 	cx25821_initialize(dev);
 
 	cx25821_i2c_register(&dev->i2c_bus[0]);
-//  cx25821_i2c_register(&dev->i2c_bus[1]);
-//  cx25821_i2c_register(&dev->i2c_bus[2]);
+/*  cx25821_i2c_register(&dev->i2c_bus[1]);
+ *  cx25821_i2c_register(&dev->i2c_bus[2]); */
 
 	CX25821_INFO("i2c register! bus->i2c_rc = %d\n",
 		     dev->i2c_bus[0].i2c_rc);
@@ -1026,7 +1030,7 @@
 
 	for (i = VID_UPSTREAM_SRAM_CHANNEL_I;
 	     i <= AUDIO_UPSTREAM_SRAM_CHANNEL_B; i++) {
-		//Since we don't have template8 for Audio Downstream
+		/* Since we don't have template8 for Audio Downstream */
 		if (cx25821_video_register(dev, i, video_template[i - 1]) < 0) {
 			printk(KERN_ERR
 			       "%s() Failed to register analog video adapters for Upstream channel %d.\n",
@@ -1034,7 +1038,7 @@
 		}
 	}
 
-	// register IOCTL device
+	/* register IOCTL device */
 	dev->ioctl_dev =
 	    cx25821_vdev_init(dev, dev->pci, video_template[VIDEO_IOCTL_CH],
 			      "video");
@@ -1112,6 +1116,7 @@
 	cx25821_i2c_unregister(&dev->i2c_bus[0]);
 	cx25821_iounmap(dev);
 }
+EXPORT_SYMBOL(cx25821_dev_unregister);
 
 static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist,
 				  unsigned int offset, u32 sync_line,
@@ -1122,9 +1127,8 @@
 	unsigned int line, todo;
 
 	/* sync instruction */
-	if (sync_line != NO_SYNC_LINE) {
+	if (sync_line != NO_SYNC_LINE)
 		*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
-	}
 
 	/* scan lines */
 	sg = sglist;
@@ -1299,7 +1303,8 @@
 	instructions = 1 + (bpl * lines) / PAGE_SIZE + lines;
 	instructions += 1;
 
-	if ((rc = btcx_riscmem_alloc(pci, risc, instructions * 12)) < 0)
+	rc = btcx_riscmem_alloc(pci, risc, instructions * 12);
+	if (rc < 0)
 		return rc;
 
 	/* write risc instructions */
@@ -1312,6 +1317,7 @@
 	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
 	return 0;
 }
+EXPORT_SYMBOL(cx25821_risc_databuffer_audio);
 
 int cx25821_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
 			 u32 reg, u32 mask, u32 value)
@@ -1375,7 +1381,7 @@
 		}
 	}
 
-      out:
+out:
 	return IRQ_RETVAL(handled);
 }
 
@@ -1399,12 +1405,14 @@
 	}
 	printk("\n");
 }
+EXPORT_SYMBOL(cx25821_print_irqbits);
 
 struct cx25821_dev *cx25821_dev_get(struct pci_dev *pci)
 {
 	struct cx25821_dev *dev = pci_get_drvdata(pci);
 	return dev;
 }
+EXPORT_SYMBOL(cx25821_dev_get);
 
 static int __devinit cx25821_initdev(struct pci_dev *pci_dev,
 				     const struct pci_device_id *pci_id)
@@ -1430,7 +1438,7 @@
 		goto fail_unregister_device;
 	}
 
-	printk(KERN_INFO "cx25821 Athena pci enable ! \n");
+	printk(KERN_INFO "cx25821 Athena pci enable !\n");
 
 	if (cx25821_dev_setup(dev) < 0) {
 		err = -EINVAL;
@@ -1464,14 +1472,14 @@
 
 	return 0;
 
-      fail_irq:
-	printk(KERN_INFO "cx25821 cx25821_initdev() can't get IRQ ! \n");
+fail_irq:
+	printk(KERN_INFO "cx25821 cx25821_initdev() can't get IRQ !\n");
 	cx25821_dev_unregister(dev);
 
-      fail_unregister_device:
+fail_unregister_device:
 	v4l2_device_unregister(&dev->v4l2_dev);
 
-      fail_free:
+fail_free:
 	kfree(dev);
 	return err;
 }
@@ -1536,16 +1544,6 @@
 	pci_unregister_driver(&cx25821_pci_driver);
 }
 
-EXPORT_SYMBOL(cx25821_devlist);
-EXPORT_SYMBOL(cx25821_sram_channels);
-EXPORT_SYMBOL(cx25821_print_irqbits);
-EXPORT_SYMBOL(cx25821_dev_get);
-EXPORT_SYMBOL(cx25821_dev_unregister);
-EXPORT_SYMBOL(cx25821_sram_channel_setup);
-EXPORT_SYMBOL(cx25821_sram_channel_dump);
-EXPORT_SYMBOL(cx25821_sram_channel_setup_audio);
-EXPORT_SYMBOL(cx25821_sram_channel_dump_audio);
-EXPORT_SYMBOL(cx25821_risc_databuffer_audio);
 EXPORT_SYMBOL(cx25821_set_gpiopin_direction);
 
 module_init(cx25821_init);
diff --git a/drivers/staging/cx25821/cx25821-gpio.c b/drivers/staging/cx25821/cx25821-gpio.c
index e8a37b4..2f154b3 100644
--- a/drivers/staging/cx25821/cx25821-gpio.c
+++ b/drivers/staging/cx25821/cx25821-gpio.c
@@ -31,7 +31,7 @@
 	u32 gpio_register = 0;
 	u32 value = 0;
 
-	// Check for valid pinNumber
+	/* Check for valid pinNumber */
 	if (pin_number >= 47)
 		return;
 
@@ -39,14 +39,14 @@
 		bit = pin_number - 31;
 		gpio_oe_reg = GPIO_HI_OE;
 	}
-	// Here we will make sure that the GPIOs 0 and 1 are output. keep the rest as is
+	/* Here we will make sure that the GPIOs 0 and 1 are output. keep the
+	 * rest as is */
 	gpio_register = cx_read(gpio_oe_reg);
 
-	if (pin_logic_value == 1) {
+	if (pin_logic_value == 1)
 		value = gpio_register | Set_GPIO_Bit(bit);
-	} else {
+	else
 		value = gpio_register & Clear_GPIO_Bit(bit);
-	}
 
 	cx_write(gpio_oe_reg, value);
 }
@@ -58,11 +58,12 @@
 	u32 gpio_reg = GPIO_LO;
 	u32 value = 0;
 
-	// Check for valid pinNumber
+	/* Check for valid pinNumber */
 	if (pin_number >= 47)
 		return;
 
-	cx25821_set_gpiopin_direction(dev, pin_number, 0);	// change to output direction
+	/* change to output direction */
+	cx25821_set_gpiopin_direction(dev, pin_number, 0);
 
 	if (pin_number > 31) {
 		bit = pin_number - 31;
@@ -71,25 +72,23 @@
 
 	value = cx_read(gpio_reg);
 
-	if (pin_logic_value == 0) {
+	if (pin_logic_value == 0)
 		value &= Clear_GPIO_Bit(bit);
-	} else {
+	else
 		value |= Set_GPIO_Bit(bit);
-	}
 
 	cx_write(gpio_reg, value);
 }
 
 void cx25821_gpio_init(struct cx25821_dev *dev)
 {
-	if (dev == NULL) {
+	if (dev == NULL)
 		return;
-	}
 
 	switch (dev->board) {
 	case CX25821_BOARD_CONEXANT_ATHENA10:
 	default:
-		//set GPIO 5 to select the path for Medusa/Athena
+		/* set GPIO 5 to select the path for Medusa/Athena */
 		cx25821_set_gpiopin_logicvalue(dev, 5, 1);
 		mdelay(20);
 		break;
diff --git a/drivers/staging/cx25821/cx25821-i2c.c b/drivers/staging/cx25821/cx25821-i2c.c
index f4f2681..08f45b5 100644
--- a/drivers/staging/cx25821/cx25821-i2c.c
+++ b/drivers/staging/cx25821/cx25821-i2c.c
@@ -28,7 +28,7 @@
 module_param(i2c_debug, int, 0644);
 MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
 
-static unsigned int i2c_scan = 0;
+static unsigned int i2c_scan;
 module_param(i2c_scan, int, 0444);
 MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
 
@@ -159,9 +159,9 @@
 
 	return msg->len;
 
-      eio:
+eio:
 	retval = -EIO;
-      err:
+err:
 	if (i2c_debug)
 		printk(KERN_ERR " ERR: %d\n", retval);
 	return retval;
@@ -223,9 +223,9 @@
 	}
 
 	return msg->len;
-      eio:
+eio:
 	retval = -EIO;
-      err:
+err:
 	if (i2c_debug)
 		printk(KERN_ERR " ERR: %d\n", retval);
 	return retval;
@@ -266,7 +266,7 @@
 	}
 	return num;
 
-      err:
+err:
 	return retval;
 }
 
@@ -319,7 +319,7 @@
 
 	bus->i2c_client.adapter = &bus->i2c_adap;
 
-	//set up the I2c
+	/* set up the I2c */
 	bus->i2c_client.addr = (0x88 >> 1);
 
 	return bus->i2c_rc;
diff --git a/drivers/staging/cx25821/cx25821-medusa-video.c b/drivers/staging/cx25821/cx25821-medusa-video.c
index d601620..34616dc 100644
--- a/drivers/staging/cx25821/cx25821-medusa-video.c
+++ b/drivers/staging/cx25821/cx25821-medusa-video.c
@@ -24,11 +24,12 @@
 #include "cx25821-medusa-video.h"
 #include "cx25821-biffuncs.h"
 
-/////////////////////////////////////////////////////////////////////////////////////////
-//medusa_enable_bluefield_output()
-//
-// Enable the generation of blue filed output if no video
-//
+/*
+ * medusa_enable_bluefield_output()
+ *
+ * Enable the generation of blue filed output if no video
+ *
+ */
 static void medusa_enable_bluefield_output(struct cx25821_dev *dev, int channel,
 					   int enable)
 {
@@ -73,15 +74,15 @@
 	}
 
 	value = cx25821_i2c_read(&dev->i2c_bus[0], out_ctrl, &tmp);
-	value &= 0xFFFFFF7F;	// clear BLUE_FIELD_EN
+	value &= 0xFFFFFF7F;	/* clear BLUE_FIELD_EN */
 	if (enable)
-		value |= 0x00000080;	// set BLUE_FIELD_EN
+		value |= 0x00000080;	/* set BLUE_FIELD_EN */
 	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], out_ctrl, value);
 
 	value = cx25821_i2c_read(&dev->i2c_bus[0], out_ctrl_ns, &tmp);
 	value &= 0xFFFFFF7F;
 	if (enable)
-		value |= 0x00000080;	// set BLUE_FIELD_EN
+		value |= 0x00000080;	/* set BLUE_FIELD_EN */
 	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], out_ctrl_ns, value);
 }
 
@@ -95,17 +96,18 @@
 	mutex_lock(&dev->lock);
 
 	for (i = 0; i < MAX_DECODERS; i++) {
-		// set video format NTSC-M
+		/* set video format NTSC-M */
 		value =
 		    cx25821_i2c_read(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i),
 				     &tmp);
 		value &= 0xFFFFFFF0;
-		value |= 0x10001;	// enable the fast locking mode bit[16]
+		/* enable the fast locking mode bit[16] */
+		value |= 0x10001;
 		ret_val =
 		    cx25821_i2c_write(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i),
 				      value);
 
-		// resolution NTSC 720x480
+		/* resolution NTSC 720x480 */
 		value =
 		    cx25821_i2c_read(&dev->i2c_bus[0],
 				     HORIZ_TIM_CTRL + (0x200 * i), &tmp);
@@ -119,17 +121,17 @@
 		    cx25821_i2c_read(&dev->i2c_bus[0],
 				     VERT_TIM_CTRL + (0x200 * i), &tmp);
 		value &= 0x00C00C00;
-		value |= 0x1C1E001A;	// vblank_cnt + 2 to get camera ID
+		value |= 0x1C1E001A;	/* vblank_cnt + 2 to get camera ID */
 		ret_val =
 		    cx25821_i2c_write(&dev->i2c_bus[0],
 				      VERT_TIM_CTRL + (0x200 * i), value);
 
-		// chroma subcarrier step size
+		/* chroma subcarrier step size */
 		ret_val =
 		    cx25821_i2c_write(&dev->i2c_bus[0],
 				      SC_STEP_SIZE + (0x200 * i), 0x43E00000);
 
-		// enable VIP optional active
+		/* enable VIP optional active */
 		value =
 		    cx25821_i2c_read(&dev->i2c_bus[0],
 				     OUT_CTRL_NS + (0x200 * i), &tmp);
@@ -139,7 +141,7 @@
 		    cx25821_i2c_write(&dev->i2c_bus[0],
 				      OUT_CTRL_NS + (0x200 * i), value);
 
-		// enable VIP optional active (VIP_OPT_AL) for direct output.
+		/* enable VIP optional active (VIP_OPT_AL) for direct output. */
 		value =
 		    cx25821_i2c_read(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i),
 				     &tmp);
@@ -149,19 +151,21 @@
 		    cx25821_i2c_write(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i),
 				      value);
 
-		// clear VPRES_VERT_EN bit, fixes the chroma run away problem
-		// when the input switching rate < 16 fields
-		//
+		/*
+		 * clear VPRES_VERT_EN bit, fixes the chroma run away problem
+		 * when the input switching rate < 16 fields
+		*/
 		value =
 		    cx25821_i2c_read(&dev->i2c_bus[0],
 				     MISC_TIM_CTRL + (0x200 * i), &tmp);
-		value = setBitAtPos(value, 14);	// disable special play detection
+		/* disable special play detection */
+		value = setBitAtPos(value, 14);
 		value = clearBitAtPos(value, 15);
 		ret_val =
 		    cx25821_i2c_write(&dev->i2c_bus[0],
 				      MISC_TIM_CTRL + (0x200 * i), value);
 
-		// set vbi_gate_en to 0
+		/* set vbi_gate_en to 0 */
 		value =
 		    cx25821_i2c_read(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i),
 				     &tmp);
@@ -170,12 +174,12 @@
 		    cx25821_i2c_write(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i),
 				      value);
 
-		// Enable the generation of blue field output if no video
+		/* Enable the generation of blue field output if no video */
 		medusa_enable_bluefield_output(dev, i, 1);
 	}
 
 	for (i = 0; i < MAX_ENCODERS; i++) {
-		// NTSC hclock
+		/* NTSC hclock */
 		value =
 		    cx25821_i2c_read(&dev->i2c_bus[0],
 				     DENC_A_REG_1 + (0x100 * i), &tmp);
@@ -185,7 +189,7 @@
 		    cx25821_i2c_write(&dev->i2c_bus[0],
 				      DENC_A_REG_1 + (0x100 * i), value);
 
-		// burst begin and burst end
+		/* burst begin and burst end */
 		value =
 		    cx25821_i2c_read(&dev->i2c_bus[0],
 				     DENC_A_REG_2 + (0x100 * i), &tmp);
@@ -204,7 +208,7 @@
 		    cx25821_i2c_write(&dev->i2c_bus[0],
 				      DENC_A_REG_3 + (0x100 * i), value);
 
-		// set NTSC vblank, no phase alternation, 7.5 IRE pedestal
+		/* set NTSC vblank, no phase alternation, 7.5 IRE pedestal */
 		value =
 		    cx25821_i2c_read(&dev->i2c_bus[0],
 				     DENC_A_REG_4 + (0x100 * i), &tmp);
@@ -227,17 +231,19 @@
 		    cx25821_i2c_write(&dev->i2c_bus[0],
 				      DENC_A_REG_6 + (0x100 * i), 0x009A89C1);
 
-		// Subcarrier Increment
+		/* Subcarrier Increment */
 		ret_val =
 		    cx25821_i2c_write(&dev->i2c_bus[0],
 				      DENC_A_REG_7 + (0x100 * i), 0x21F07C1F);
 	}
 
-	//set picture resolutions
-	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], HSCALE_CTRL, 0x0);	//0 - 720
-	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], VSCALE_CTRL, 0x0);	//0 - 480
+	/* set picture resolutions */
+	/* 0 - 720 */
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], HSCALE_CTRL, 0x0);
+	/* 0 - 480 */
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], VSCALE_CTRL, 0x0);
 
-	// set Bypass input format to NTSC 525 lines
+	/* set Bypass input format to NTSC 525 lines */
 	value = cx25821_i2c_read(&dev->i2c_bus[0], BYP_AB_CTRL, &tmp);
 	value |= 0x00080200;
 	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], BYP_AB_CTRL, value);
@@ -252,7 +258,7 @@
 	int ret_val = -1;
 	u32 value = 0, tmp = 0;
 
-	// Setup for 2D threshold
+	/* Setup for 2D threshold */
 	ret_val =
 	    cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_HFS_CFG + (0x200 * dec),
 			      0x20002861);
@@ -263,7 +269,7 @@
 	    cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_LF_CFG + (0x200 * dec),
 			      0x200A1023);
 
-	// Setup flat chroma and luma thresholds
+	/* Setup flat chroma and luma thresholds */
 	value =
 	    cx25821_i2c_read(&dev->i2c_bus[0],
 			     COMB_FLAT_THRESH_CTRL + (0x200 * dec), &tmp);
@@ -272,12 +278,12 @@
 	    cx25821_i2c_write(&dev->i2c_bus[0],
 			      COMB_FLAT_THRESH_CTRL + (0x200 * dec), value);
 
-	// set comb 2D blend
+	/* set comb 2D blend */
 	ret_val =
 	    cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_BLEND + (0x200 * dec),
 			      0x210F0F0F);
 
-	// COMB MISC CONTROL
+	/* COMB MISC CONTROL */
 	ret_val =
 	    cx25821_i2c_write(&dev->i2c_bus[0], COMB_MISC_CTRL + (0x200 * dec),
 			      0x41120A7F);
@@ -295,17 +301,18 @@
 	mutex_lock(&dev->lock);
 
 	for (i = 0; i < MAX_DECODERS; i++) {
-		// set video format PAL-BDGHI
+		/* set video format PAL-BDGHI */
 		value =
 		    cx25821_i2c_read(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i),
 				     &tmp);
 		value &= 0xFFFFFFF0;
-		value |= 0x10004;	// enable the fast locking mode bit[16]
+		/* enable the fast locking mode bit[16] */
+		value |= 0x10004;
 		ret_val =
 		    cx25821_i2c_write(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i),
 				      value);
 
-		// resolution PAL 720x576
+		/* resolution PAL 720x576 */
 		value =
 		    cx25821_i2c_read(&dev->i2c_bus[0],
 				     HORIZ_TIM_CTRL + (0x200 * i), &tmp);
@@ -315,22 +322,22 @@
 		    cx25821_i2c_write(&dev->i2c_bus[0],
 				      HORIZ_TIM_CTRL + (0x200 * i), value);
 
-		// vblank656_cnt=x26, vactive_cnt=240h, vblank_cnt=x24
+		/* vblank656_cnt=x26, vactive_cnt=240h, vblank_cnt=x24 */
 		value =
 		    cx25821_i2c_read(&dev->i2c_bus[0],
 				     VERT_TIM_CTRL + (0x200 * i), &tmp);
 		value &= 0x00C00C00;
-		value |= 0x28240026;	// vblank_cnt + 2 to get camera ID
+		value |= 0x28240026;	/* vblank_cnt + 2 to get camera ID */
 		ret_val =
 		    cx25821_i2c_write(&dev->i2c_bus[0],
 				      VERT_TIM_CTRL + (0x200 * i), value);
 
-		// chroma subcarrier step size
+		/* chroma subcarrier step size */
 		ret_val =
 		    cx25821_i2c_write(&dev->i2c_bus[0],
 				      SC_STEP_SIZE + (0x200 * i), 0x5411E2D0);
 
-		// enable VIP optional active
+		/* enable VIP optional active */
 		value =
 		    cx25821_i2c_read(&dev->i2c_bus[0],
 				     OUT_CTRL_NS + (0x200 * i), &tmp);
@@ -340,7 +347,7 @@
 		    cx25821_i2c_write(&dev->i2c_bus[0],
 				      OUT_CTRL_NS + (0x200 * i), value);
 
-		// enable VIP optional active (VIP_OPT_AL) for direct output.
+		/* enable VIP optional active (VIP_OPT_AL) for direct output. */
 		value =
 		    cx25821_i2c_read(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i),
 				     &tmp);
@@ -350,18 +357,21 @@
 		    cx25821_i2c_write(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i),
 				      value);
 
-		// clear VPRES_VERT_EN bit, fixes the chroma run away problem
-		// when the input switching rate < 16 fields
+		/*
+		 * clear VPRES_VERT_EN bit, fixes the chroma run away problem
+		 * when the input switching rate < 16 fields
+		 */
 		value =
 		    cx25821_i2c_read(&dev->i2c_bus[0],
 				     MISC_TIM_CTRL + (0x200 * i), &tmp);
-		value = setBitAtPos(value, 14);	// disable special play detection
+		/* disable special play detection */
+		value = setBitAtPos(value, 14);
 		value = clearBitAtPos(value, 15);
 		ret_val =
 		    cx25821_i2c_write(&dev->i2c_bus[0],
 				      MISC_TIM_CTRL + (0x200 * i), value);
 
-		// set vbi_gate_en to 0
+		/* set vbi_gate_en to 0 */
 		value =
 		    cx25821_i2c_read(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i),
 				     &tmp);
@@ -372,12 +382,12 @@
 
 		medusa_PALCombInit(dev, i);
 
-		// Enable the generation of blue field output if no video
+		/* Enable the generation of blue field output if no video */
 		medusa_enable_bluefield_output(dev, i, 1);
 	}
 
 	for (i = 0; i < MAX_ENCODERS; i++) {
-		// PAL hclock
+		/* PAL hclock */
 		value =
 		    cx25821_i2c_read(&dev->i2c_bus[0],
 				     DENC_A_REG_1 + (0x100 * i), &tmp);
@@ -387,7 +397,7 @@
 		    cx25821_i2c_write(&dev->i2c_bus[0],
 				      DENC_A_REG_1 + (0x100 * i), value);
 
-		// burst begin and burst end
+		/* burst begin and burst end */
 		value =
 		    cx25821_i2c_read(&dev->i2c_bus[0],
 				     DENC_A_REG_2 + (0x100 * i), &tmp);
@@ -397,7 +407,7 @@
 		    cx25821_i2c_write(&dev->i2c_bus[0],
 				      DENC_A_REG_2 + (0x100 * i), value);
 
-		// hblank and vactive
+		/* hblank and vactive */
 		value =
 		    cx25821_i2c_read(&dev->i2c_bus[0],
 				     DENC_A_REG_3 + (0x100 * i), &tmp);
@@ -407,7 +417,7 @@
 		    cx25821_i2c_write(&dev->i2c_bus[0],
 				      DENC_A_REG_3 + (0x100 * i), value);
 
-		// set PAL vblank, phase alternation, 0 IRE pedestal
+		/* set PAL vblank, phase alternation, 0 IRE pedestal */
 		value =
 		    cx25821_i2c_read(&dev->i2c_bus[0],
 				     DENC_A_REG_4 + (0x100 * i), &tmp);
@@ -430,17 +440,19 @@
 		    cx25821_i2c_write(&dev->i2c_bus[0],
 				      DENC_A_REG_6 + (0x100 * i), 0x00A493CF);
 
-		// Subcarrier Increment
+		/* Subcarrier Increment */
 		ret_val =
 		    cx25821_i2c_write(&dev->i2c_bus[0],
 				      DENC_A_REG_7 + (0x100 * i), 0x2A098ACB);
 	}
 
-	//set picture resolutions
-	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], HSCALE_CTRL, 0x0);	//0 - 720
-	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], VSCALE_CTRL, 0x0);	//0 - 576
+	/* set picture resolutions */
+	/* 0 - 720 */
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], HSCALE_CTRL, 0x0);
+	/* 0 - 576 */
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], VSCALE_CTRL, 0x0);
 
-	// set Bypass input format to PAL 625 lines
+	/* set Bypass input format to PAL 625 lines */
 	value = cx25821_i2c_read(&dev->i2c_bus[0], BYP_AB_CTRL, &tmp);
 	value &= 0xFFF7FDFF;
 	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], BYP_AB_CTRL, value);
@@ -455,18 +467,17 @@
 	int status = STATUS_SUCCESS;
 	u32 value = 0, tmp = 0;
 
-	if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK) {
+	if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
 		status = medusa_initialize_pal(dev);
-	} else {
+	else
 		status = medusa_initialize_ntsc(dev);
-	}
 
-	// Enable DENC_A output
+	/* Enable DENC_A output */
 	value = cx25821_i2c_read(&dev->i2c_bus[0], DENC_A_REG_4, &tmp);
 	value = setBitAtPos(value, 4);
 	status = cx25821_i2c_write(&dev->i2c_bus[0], DENC_A_REG_4, value);
 
-	// Enable DENC_B output
+	/* Enable DENC_B output */
 	value = cx25821_i2c_read(&dev->i2c_bus[0], DENC_B_REG_4, &tmp);
 	value = setBitAtPos(value, 4);
 	status = cx25821_i2c_write(&dev->i2c_bus[0], DENC_B_REG_4, value);
@@ -486,10 +497,10 @@
 
 	mutex_lock(&dev->lock);
 
-	// validate the width - cannot be negative
+	/* validate the width - cannot be negative */
 	if (width > MAX_WIDTH) {
 		printk
-		    ("cx25821 %s() : width %d > MAX_WIDTH %d ! resetting to MAX_WIDTH \n",
+		    ("cx25821 %s() : width %d > MAX_WIDTH %d ! resetting to MAX_WIDTH\n",
 		     __func__, width, MAX_WIDTH);
 		width = MAX_WIDTH;
 	}
@@ -523,14 +534,14 @@
 		vscale = 0x1E00;
 		break;
 
-	default:		//720
+	default:		/* 720 */
 		hscale = 0x0;
 		vscale = 0x0;
 		break;
 	}
 
 	for (; decoder < decoder_count; decoder++) {
-		// write scaling values for each decoder
+		/* write scaling values for each decoder */
 		ret_val =
 		    cx25821_i2c_write(&dev->i2c_bus[0],
 				      HSCALE_CTRL + (0x200 * decoder), hscale);
@@ -552,7 +563,7 @@
 
 	mutex_lock(&dev->lock);
 
-	// no support
+	/* no support */
 	if (decoder < VDEC_A && decoder > VDEC_H) {
 		mutex_unlock(&dev->lock);
 		return;
@@ -577,11 +588,10 @@
 
 	_display_field_cnt[decoder] = duration;
 
-	// update hardware
+	/* update hardware */
 	fld_cnt = cx25821_i2c_read(&dev->i2c_bus[0], disp_cnt_reg, &tmp);
 
-	if (!(decoder % 2))	// EVEN decoder
-	{
+	if (!(decoder % 2)) {	/* EVEN decoder */
 		fld_cnt &= 0xFFFF0000;
 		fld_cnt |= duration;
 	} else {
@@ -594,8 +604,7 @@
 	mutex_unlock(&dev->lock);
 }
 
-/////////////////////////////////////////////////////////////////////////////////////////
-// Map to Medusa register setting
+/* Map to Medusa register setting */
 static int mapM(int srcMin,
 		int srcMax, int srcVal, int dstMin, int dstMax, int *dstVal)
 {
@@ -603,20 +612,21 @@
 	int denominator;
 	int quotient;
 
-	if ((srcMin == srcMax) || (srcVal < srcMin) || (srcVal > srcMax)) {
+	if ((srcMin == srcMax) || (srcVal < srcMin) || (srcVal > srcMax))
 		return -1;
-	}
-	// This is the overall expression used:
-	// *dstVal = (srcVal - srcMin)*(dstMax - dstMin) / (srcMax - srcMin) + dstMin;
-	// but we need to account for rounding so below we use the modulus
-	// operator to find the remainder and increment if necessary.
+	/*
+	 * This is the overall expression used:
+	 * *dstVal =
+	 *   (srcVal - srcMin)*(dstMax - dstMin) / (srcMax - srcMin) + dstMin;
+	 * but we need to account for rounding so below we use the modulus
+	 * operator to find the remainder and increment if necessary.
+	 */
 	numerator = (srcVal - srcMin) * (dstMax - dstMin);
 	denominator = srcMax - srcMin;
 	quotient = numerator / denominator;
 
-	if (2 * (numerator % denominator) >= denominator) {
+	if (2 * (numerator % denominator) >= denominator)
 		quotient++;
-	}
 
 	*dstVal = quotient + dstMin;
 
@@ -636,7 +646,6 @@
 	}
 }
 
-/////////////////////////////////////////////////////////////////////////////////////////
 int medusa_set_brightness(struct cx25821_dev *dev, int brightness, int decoder)
 {
 	int ret_val = 0;
@@ -665,7 +674,6 @@
 	return ret_val;
 }
 
-/////////////////////////////////////////////////////////////////////////////////////////
 int medusa_set_contrast(struct cx25821_dev *dev, int contrast, int decoder)
 {
 	int ret_val = 0;
@@ -695,7 +703,6 @@
 	return ret_val;
 }
 
-/////////////////////////////////////////////////////////////////////////////////////////
 int medusa_set_hue(struct cx25821_dev *dev, int hue, int decoder)
 {
 	int ret_val = 0;
@@ -727,7 +734,6 @@
 	return ret_val;
 }
 
-/////////////////////////////////////////////////////////////////////////////////////////
 int medusa_set_saturation(struct cx25821_dev *dev, int saturation, int decoder)
 {
 	int ret_val = 0;
@@ -768,98 +774,90 @@
 	return ret_val;
 }
 
-/////////////////////////////////////////////////////////////////////////////////////////
-// Program the display sequence and monitor output.
-//
+/* Program the display sequence and monitor output. */
+
 int medusa_video_init(struct cx25821_dev *dev)
 {
-	u32 value = 0, tmp = 0;
-	int ret_val = 0;
-	int i = 0;
+	u32 value, tmp = 0;
+	int ret_val;
+	int i;
 
 	mutex_lock(&dev->lock);
 
 	_num_decoders = dev->_max_num_decoders;
 
-	// disable Auto source selection on all video decoders
+	/* disable Auto source selection on all video decoders */
 	value = cx25821_i2c_read(&dev->i2c_bus[0], MON_A_CTRL, &tmp);
 	value &= 0xFFFFF0FF;
 	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], MON_A_CTRL, value);
+	if (ret_val < 0)
+		goto error;
 
-	if (ret_val < 0) {
-		mutex_unlock(&dev->lock);
-		return -EINVAL;
-	}
-	// Turn off Master source switch enable
+	/* Turn off Master source switch enable */
 	value = cx25821_i2c_read(&dev->i2c_bus[0], MON_A_CTRL, &tmp);
 	value &= 0xFFFFFFDF;
 	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], MON_A_CTRL, value);
-
 	if (ret_val < 0)
-		return -EINVAL;
+		goto error;
 
 	mutex_unlock(&dev->lock);
 
-	for (i = 0; i < _num_decoders; i++) {
+	for (i = 0; i < _num_decoders; i++)
 		medusa_set_decoderduration(dev, i, _display_field_cnt[i]);
-	}
 
 	mutex_lock(&dev->lock);
 
-	// Select monitor as DENC A input, power up the DAC
+	/* Select monitor as DENC A input, power up the DAC */
 	value = cx25821_i2c_read(&dev->i2c_bus[0], DENC_AB_CTRL, &tmp);
 	value &= 0xFF70FF70;
-	value |= 0x00090008;	// set en_active
+	value |= 0x00090008;	/* set en_active */
 	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], DENC_AB_CTRL, value);
+	if (ret_val < 0)
+		goto error;
 
-	if (ret_val < 0) {
-		mutex_unlock(&dev->lock);
-		return -EINVAL;
-	}
-	// enable input is VIP/656
+	/* enable input is VIP/656 */
 	value = cx25821_i2c_read(&dev->i2c_bus[0], BYP_AB_CTRL, &tmp);
-	value |= 0x00040100;	// enable VIP
+	value |= 0x00040100;	/* enable VIP */
 	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], BYP_AB_CTRL, value);
 
-	if (ret_val < 0) {
-		mutex_unlock(&dev->lock);
-		return -EINVAL;
-	}
-	// select AFE clock to output mode
+	if (ret_val < 0)
+		goto error;
+
+	/* select AFE clock to output mode */
 	value = cx25821_i2c_read(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, &tmp);
 	value &= 0x83FFFFFF;
-	ret_val =
-	    cx25821_i2c_write(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL,
-			      value | 0x10000000);
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL,
+				    value | 0x10000000);
+	if (ret_val < 0)
+		goto error;
 
-	if (ret_val < 0) {
-		mutex_unlock(&dev->lock);
-		return -EINVAL;
-	}
-	// Turn on all of the data out and control output pins.
+	/* Turn on all of the data out and control output pins. */
 	value = cx25821_i2c_read(&dev->i2c_bus[0], PIN_OE_CTRL, &tmp);
 	value &= 0xFEF0FE00;
 	if (_num_decoders == MAX_DECODERS) {
-		// Note: The octal board does not support control pins(bit16-19).
-		// These bits are ignored in the octal board.
-		value |= 0x010001F8;	// disable VDEC A-C port, default to Mobilygen Interface
+		/*
+		 * Note: The octal board does not support control pins(bit16-19)
+		 * These bits are ignored in the octal board.
+		 *
+		 * disable VDEC A-C port, default to Mobilygen Interface
+		 */
+		value |= 0x010001F8;
 	} else {
-		value |= 0x010F0108;	// disable VDEC A-C port, default to Mobilygen Interface
+		/* disable VDEC A-C port, default to Mobilygen Interface */
+		value |= 0x010F0108;
 	}
 
 	value |= 7;
 	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], PIN_OE_CTRL, value);
-	if (ret_val < 0) {
-		mutex_unlock(&dev->lock);
-		return -EINVAL;
-	}
+	if (ret_val < 0)
+		goto error;
 
 	mutex_unlock(&dev->lock);
 
 	ret_val = medusa_set_videostandard(dev);
+	return ret_val;
 
-	if (ret_val < 0)
-		return -EINVAL;
-
-	return 1;
+error:
+	mutex_unlock(&dev->lock);
+	return ret_val;
 }
diff --git a/drivers/staging/cx25821/cx25821-video-upstream.c b/drivers/staging/cx25821/cx25821-video-upstream.c
index 6d48a1e..c842d8f 100644
--- a/drivers/staging/cx25821/cx25821-video-upstream.c
+++ b/drivers/staging/cx25821/cx25821-video-upstream.c
@@ -32,7 +32,7 @@
 #include <linux/file.h>
 #include <linux/fcntl.h>
 #include <linux/slab.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards");
 MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
@@ -60,9 +60,8 @@
 	cdt = ch->cdt;
 	lines = ch->fifo_size / bpl;
 
-	if (lines > 4) {
+	if (lines > 4)
 		lines = 4;
-	}
 
 	BUG_ON(lines < 2);
 
@@ -97,7 +96,7 @@
 }
 
 static __le32 *cx25821_update_riscprogram(struct cx25821_dev *dev,
-					  __le32 * rp, unsigned int offset,
+					  __le32 *rp, unsigned int offset,
 					  unsigned int bpl, u32 sync_line,
 					  unsigned int lines, int fifo_enable,
 					  int field_type)
@@ -108,9 +107,8 @@
 	*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
 
 	if (USE_RISC_NOOP_VIDEO) {
-		for (i = 0; i < NUM_NO_OPS; i++) {
+		for (i = 0; i < NUM_NO_OPS; i++)
 			*(rp++) = cpu_to_le32(RISC_NOOP);
-		}
 	}
 
 	/* scan lines */
@@ -140,14 +138,12 @@
 	int dist_betwn_starts = bpl * 2;
 
 	/* sync instruction */
-	if (sync_line != NO_SYNC_LINE) {
+	if (sync_line != NO_SYNC_LINE)
 		*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
-	}
 
 	if (USE_RISC_NOOP_VIDEO) {
-		for (i = 0; i < NUM_NO_OPS; i++) {
+		for (i = 0; i < NUM_NO_OPS; i++)
 			*(rp++) = cpu_to_le32(RISC_NOOP);
-		}
 	}
 
 	/* scan lines */
@@ -157,12 +153,13 @@
 		*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
 
 		if ((lines <= NTSC_FIELD_HEIGHT)
-		    || (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC)) {
-			offset += dist_betwn_starts;	//to skip the other field line
-		}
+		    || (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC))
+			/* to skip the other field line */
+			offset += dist_betwn_starts;
 
-		// check if we need to enable the FIFO after the first 4 lines
-		// For the upstream video channel, the risc engine will enable the FIFO.
+		/* check if we need to enable the FIFO after the first 4 lines
+		 * For the upstream video channel, the risc engine will enable
+		 * the FIFO. */
 		if (fifo_enable && line == 3) {
 			*(rp++) = RISC_WRITECR;
 			*(rp++) = sram_ch->dma_ctl;
@@ -181,7 +178,8 @@
 {
 	__le32 *rp;
 	int fifo_enable = 0;
-	int singlefield_lines = lines >> 1;	//get line count for single field
+	/* get line count for single field */
+	int singlefield_lines = lines >> 1;
 	int odd_num_lines = singlefield_lines;
 	int frame = 0;
 	int frame_size = 0;
@@ -225,7 +223,7 @@
 
 		fifo_enable = FIFO_DISABLE;
 
-		//Even Field
+		/* Even Field */
 		rp = cx25821_risc_field_upstream(dev, rp,
 						 dev->_data_buf_phys_addr +
 						 databuf_offset, bottom_offset,
@@ -241,7 +239,9 @@
 			risc_flag = RISC_CNT_INC;
 		}
 
-		// Loop to 2ndFrameRISC or to Start of Risc program & generate IRQ
+		/* Loop to 2ndFrameRISC or to Start of Risc
+		 * program & generate IRQ
+		 */
 		*(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag);
 		*(rp++) = cpu_to_le32(risc_phys_jump_addr);
 		*(rp++) = cpu_to_le32(0);
@@ -258,18 +258,18 @@
 
 	if (!dev->_is_running) {
 		printk
-		    ("cx25821: No video file is currently running so return!\n");
+		   (KERN_INFO "cx25821: No video file is currently running so return!\n");
 		return;
 	}
-	//Disable RISC interrupts
+	/* Disable RISC interrupts */
 	tmp = cx_read(sram_ch->int_msk);
 	cx_write(sram_ch->int_msk, tmp & ~_intr_msk);
 
-	//Turn OFF risc and fifo enable
+	/* Turn OFF risc and fifo enable */
 	tmp = cx_read(sram_ch->dma_ctl);
 	cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN));
 
-	//Clear data buffer memory
+	/* Clear data buffer memory */
 	if (dev->_data_buf_virt_addr)
 		memset(dev->_data_buf_virt_addr, 0, dev->_data_buf_size);
 
@@ -292,9 +292,8 @@
 
 void cx25821_free_mem_upstream_ch1(struct cx25821_dev *dev)
 {
-	if (dev->_is_running) {
+	if (dev->_is_running)
 		cx25821_stop_upstream_video_ch1(dev);
-	}
 
 	if (dev->_dma_virt_addr) {
 		pci_free_consistent(dev->pci, dev->_risc_size,
@@ -347,19 +346,19 @@
 
 	if (IS_ERR(myfile)) {
 		const int open_errno = -PTR_ERR(myfile);
-		printk("%s(): ERROR opening file(%s) with errno = %d! \n",
+		printk(KERN_ERR "%s(): ERROR opening file(%s) with errno = %d!\n",
 		       __func__, dev->_filename, open_errno);
 		return PTR_ERR(myfile);
 	} else {
 		if (!(myfile->f_op)) {
-			printk("%s: File has no file operations registered!",
+			printk(KERN_ERR "%s: File has no file operations registered!",
 			       __func__);
 			filp_close(myfile, NULL);
 			return -EIO;
 		}
 
 		if (!myfile->f_op->read) {
-			printk("%s: File has no READ operations registered!",
+			printk(KERN_ERR "%s: File has no READ operations registered!",
 			       __func__);
 			filp_close(myfile, NULL);
 			return -EIO;
@@ -412,7 +411,7 @@
 	    container_of(work, struct cx25821_dev, _irq_work_entry);
 
 	if (!dev) {
-		printk("ERROR %s(): since container_of(work_struct) FAILED! \n",
+		printk(KERN_ERR "ERROR %s(): since container_of(work_struct) FAILED!\n",
 		       __func__);
 		return;
 	}
@@ -438,12 +437,12 @@
 
 	if (IS_ERR(myfile)) {
 		const int open_errno = -PTR_ERR(myfile);
-		printk("%s(): ERROR opening file(%s) with errno = %d! \n",
+		printk(KERN_ERR "%s(): ERROR opening file(%s) with errno = %d!\n",
 		       __func__, dev->_filename, open_errno);
 		return PTR_ERR(myfile);
 	} else {
 		if (!(myfile->f_op)) {
-			printk("%s: File has no file operations registered!",
+			printk(KERN_ERR "%s: File has no file operations registered!",
 			       __func__);
 			filp_close(myfile, NULL);
 			return -EIO;
@@ -451,7 +450,7 @@
 
 		if (!myfile->f_op->read) {
 			printk
-			    ("%s: File has no READ operations registered!  Returning.",
+			    (KERN_ERR "%s: File has no READ operations registered!  Returning.",
 			     __func__);
 			filp_close(myfile, NULL);
 			return -EIO;
@@ -490,9 +489,8 @@
 			if (i > 0)
 				dev->_frame_count++;
 
-			if (vfs_read_retval < line_size) {
+			if (vfs_read_retval < line_size)
 				break;
-			}
 		}
 
 		dev->_file_status =
@@ -528,11 +526,11 @@
 
 	if (!dev->_dma_virt_addr) {
 		printk
-		    ("cx25821: FAILED to allocate memory for Risc buffer! Returning.\n");
+		    (KERN_ERR "cx25821: FAILED to allocate memory for Risc buffer! Returning.\n");
 		return -ENOMEM;
 	}
 
-	//Clear memory at address
+	/* Clear memory at address */
 	memset(dev->_dma_virt_addr, 0, dev->_risc_size);
 
 	if (dev->_data_buf_virt_addr != NULL) {
@@ -540,7 +538,7 @@
 				    dev->_data_buf_virt_addr,
 				    dev->_data_buf_phys_addr);
 	}
-	//For Video Data buffer allocation
+	/* For Video Data buffer allocation */
 	dev->_data_buf_virt_addr =
 	    pci_alloc_consistent(dev->pci, dev->upstream_databuf_size,
 				 &data_dma_addr);
@@ -549,30 +547,30 @@
 
 	if (!dev->_data_buf_virt_addr) {
 		printk
-		    ("cx25821: FAILED to allocate memory for data buffer! Returning.\n");
+		    (KERN_ERR "cx25821: FAILED to allocate memory for data buffer! Returning.\n");
 		return -ENOMEM;
 	}
 
-	//Clear memory at address
+	/* Clear memory at address */
 	memset(dev->_data_buf_virt_addr, 0, dev->_data_buf_size);
 
 	ret = cx25821_openfile(dev, sram_ch);
 	if (ret < 0)
 		return ret;
 
-	//Create RISC programs
+	/* Create RISC programs */
 	ret =
 	    cx25821_risc_buffer_upstream(dev, dev->pci, 0, bpl,
 					 dev->_lines_count);
 	if (ret < 0) {
 		printk(KERN_INFO
-		       "cx25821: Failed creating Video Upstream Risc programs! \n");
+		    "cx25821: Failed creating Video Upstream Risc programs!\n");
 		goto error;
 	}
 
 	return 0;
 
-      error:
+error:
 	return ret;
 }
 
@@ -588,10 +586,11 @@
 	__le32 *rp;
 
 	if (status & FLD_VID_SRC_RISC1) {
-		// We should only process one program per call
+		/* We should only process one program per call */
 		u32 prog_cnt = cx_read(channel->gpcnt);
 
-		//Since we've identified our IRQ, clear our bits from the interrupt mask and interrupt status registers
+		/* Since we've identified our IRQ, clear our bits from the
+		 * interrupt mask and interrupt status registers */
 		int_msk_tmp = cx_read(channel->int_msk);
 		cx_write(channel->int_msk, int_msk_tmp & ~_intr_msk);
 		cx_write(channel->int_stat, _intr_msk);
@@ -632,7 +631,7 @@
 								FIFO_DISABLE,
 								ODD_FIELD);
 
-				// Jump to Even Risc program of 1st Frame
+				/* Jump to Even Risc program of 1st Frame */
 				*(rp++) = cpu_to_le32(RISC_JUMP);
 				*(rp++) = cpu_to_le32(risc_phys_jump_addr);
 				*(rp++) = cpu_to_le32(0);
@@ -643,24 +642,24 @@
 	} else {
 		if (status & FLD_VID_SRC_UF)
 			printk
-			    ("%s: Video Received Underflow Error Interrupt!\n",
+			    (KERN_ERR "%s: Video Received Underflow Error Interrupt!\n",
 			     __func__);
 
 		if (status & FLD_VID_SRC_SYNC)
-			printk("%s: Video Received Sync Error Interrupt!\n",
+			printk(KERN_ERR "%s: Video Received Sync Error Interrupt!\n",
 			       __func__);
 
 		if (status & FLD_VID_SRC_OPC_ERR)
-			printk("%s: Video Received OpCode Error Interrupt!\n",
+			printk(KERN_ERR "%s: Video Received OpCode Error Interrupt!\n",
 			       __func__);
 	}
 
 	if (dev->_file_status == END_OF_FILE) {
-		printk("cx25821: EOF Channel 1 Framecount = %d\n",
+		printk(KERN_ERR "cx25821: EOF Channel 1 Framecount = %d\n",
 		       dev->_frame_count);
 		return -1;
 	}
-	//ElSE, set the interrupt mask register, re-enable irq.
+	/* ElSE, set the interrupt mask register, re-enable irq. */
 	int_msk_tmp = cx_read(channel->int_msk);
 	cx_write(channel->int_msk, int_msk_tmp |= _intr_msk);
 
@@ -685,17 +684,16 @@
 	msk_stat = cx_read(sram_ch->int_mstat);
 	vid_status = cx_read(sram_ch->int_stat);
 
-	// Only deal with our interrupt
+	/* Only deal with our interrupt */
 	if (vid_status) {
 		handled =
 		    cx25821_video_upstream_irq(dev, channel_num, vid_status);
 	}
 
-	if (handled < 0) {
+	if (handled < 0)
 		cx25821_stop_upstream_video_ch1(dev);
-	} else {
+	else
 		handled += handled;
-	}
 
 	return IRQ_RETVAL(handled);
 }
@@ -714,19 +712,19 @@
 	value |= dev->_isNTSC ? 0 : 0x10;
 	cx_write(ch->vid_fmt_ctl, value);
 
-	// set number of active pixels in each line. Default is 720 pixels in both NTSC and PAL format
+	/* set number of active pixels in each line.
+	 * Default is 720 pixels in both NTSC and PAL format */
 	cx_write(ch->vid_active_ctl1, width);
 
 	num_lines = (height / 2) & 0x3FF;
 	odd_num_lines = num_lines;
 
-	if (dev->_isNTSC) {
+	if (dev->_isNTSC)
 		odd_num_lines += 1;
-	}
 
 	value = (num_lines << 16) | odd_num_lines;
 
-	// set number of active lines in field 0 (top) and field 1 (bottom)
+	/* set number of active lines in field 0 (top) and field 1 (bottom) */
 	cx_write(ch->vid_active_ctl2, value);
 
 	cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3);
@@ -738,21 +736,26 @@
 	u32 tmp = 0;
 	int err = 0;
 
-	// 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for channel A-C
+	/* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for
+	 * channel A-C
+	 */
 	tmp = cx_read(VID_CH_MODE_SEL);
 	cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF);
 
-	// Set the physical start address of the RISC program in the initial program counter(IPC) member of the cmds.
+	/* Set the physical start address of the RISC program in the initial
+	 * program counter(IPC) member of the cmds.
+	 */
 	cx_write(sram_ch->cmds_start + 0, dev->_dma_phys_addr);
-	cx_write(sram_ch->cmds_start + 4, 0);	/* Risc IPC High 64 bits 63-32 */
+	/* Risc IPC High 64 bits 63-32 */
+	cx_write(sram_ch->cmds_start + 4, 0);
 
 	/* reset counter */
 	cx_write(sram_ch->gpcnt_ctl, 3);
 
-	// Clear our bits from the interrupt status register.
+	/* Clear our bits from the interrupt status register. */
 	cx_write(sram_ch->int_stat, _intr_msk);
 
-	//Set the interrupt mask register, enable irq.
+	/* Set the interrupt mask register, enable irq. */
 	cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit));
 	tmp = cx_read(sram_ch->int_msk);
 	cx_write(sram_ch->int_msk, tmp |= _intr_msk);
@@ -766,7 +769,7 @@
 		goto fail_irq;
 	}
 
-	// Start the DMA  engine
+	/* Start the DMA  engine */
 	tmp = cx_read(sram_ch->dma_ctl);
 	cx_set(sram_ch->dma_ctl, tmp | FLD_VID_RISC_EN);
 
@@ -775,7 +778,7 @@
 
 	return 0;
 
-      fail_irq:
+fail_irq:
 	cx25821_dev_unregister(dev);
 	return err;
 }
@@ -792,7 +795,7 @@
 	int str_length = 0;
 
 	if (dev->_is_running) {
-		printk("Video Channel is still running so return!\n");
+		printk(KERN_INFO "Video Channel is still running so return!\n");
 		return 0;
 	}
 
@@ -804,10 +807,12 @@
 
 	if (!dev->_irq_queues) {
 		printk
-		    ("cx25821: create_singlethread_workqueue() for Video FAILED!\n");
+		    (KERN_ERR "cx25821: create_singlethread_workqueue() for Video FAILED!\n");
 		return -ENOMEM;
 	}
-	// 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for channel A-C
+	/* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for
+	 * channel A-C
+	 */
 	tmp = cx_read(VID_CH_MODE_SEL);
 	cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF);
 
@@ -841,7 +846,7 @@
 		memcpy(dev->_filename, dev->_defaultname, str_length + 1);
 	}
 
-	//Default if filename is empty string
+	/* Default if filename is empty string */
 	if (strcmp(dev->input_filename, "") == 0) {
 		if (dev->_isNTSC) {
 			dev->_filename =
@@ -875,7 +880,7 @@
 	dev->upstream_riscbuf_size = risc_buffer_size * 2;
 	dev->upstream_databuf_size = data_frame_size * 2;
 
-	//Allocating buffers and prepare RISC program
+	/* Allocating buffers and prepare RISC program */
 	retval = cx25821_upstream_buffer_prepare(dev, sram_ch, dev->_line_size);
 	if (retval < 0) {
 		printk(KERN_ERR
@@ -888,7 +893,7 @@
 
 	return 0;
 
-      error:
+error:
 	cx25821_dev_unregister(dev);
 
 	return err;
diff --git a/drivers/staging/cx25821/cx25821-video.c b/drivers/staging/cx25821/cx25821-video.c
index 8cd3986..791212c 100644
--- a/drivers/staging/cx25821/cx25821-video.c
+++ b/drivers/staging/cx25821/cx25821-video.c
@@ -54,34 +54,34 @@
 
 struct cx25821_fmt formats[] = {
 	{
-	 .name = "8 bpp, gray",
-	 .fourcc = V4L2_PIX_FMT_GREY,
-	 .depth = 8,
-	 .flags = FORMAT_FLAGS_PACKED,
+		.name = "8 bpp, gray",
+		.fourcc = V4L2_PIX_FMT_GREY,
+		.depth = 8,
+		.flags = FORMAT_FLAGS_PACKED,
 	 }, {
-	     .name = "4:1:1, packed, Y41P",
-	     .fourcc = V4L2_PIX_FMT_Y41P,
-	     .depth = 12,
-	     .flags = FORMAT_FLAGS_PACKED,
-	     }, {
-		 .name = "4:2:2, packed, YUYV",
-		 .fourcc = V4L2_PIX_FMT_YUYV,
-		 .depth = 16,
-		 .flags = FORMAT_FLAGS_PACKED,
-		 }, {
-		     .name = "4:2:2, packed, UYVY",
-		     .fourcc = V4L2_PIX_FMT_UYVY,
-		     .depth = 16,
-		     .flags = FORMAT_FLAGS_PACKED,
-		     }, {
-			 .name = "4:2:0, YUV",
-			 .fourcc = V4L2_PIX_FMT_YUV420,
-			 .depth = 12,
-			 .flags = FORMAT_FLAGS_PACKED,
-			 },
+		.name = "4:1:1, packed, Y41P",
+		.fourcc = V4L2_PIX_FMT_Y41P,
+		.depth = 12,
+		.flags = FORMAT_FLAGS_PACKED,
+	}, {
+		.name = "4:2:2, packed, YUYV",
+		.fourcc = V4L2_PIX_FMT_YUYV,
+		.depth = 16,
+		.flags = FORMAT_FLAGS_PACKED,
+	}, {
+		.name = "4:2:2, packed, UYVY",
+		.fourcc = V4L2_PIX_FMT_UYVY,
+		.depth = 16,
+		.flags = FORMAT_FLAGS_PACKED,
+	}, {
+		.name = "4:2:0, YUV",
+		.fourcc = V4L2_PIX_FMT_YUV420,
+		.depth = 12,
+		.flags = FORMAT_FLAGS_PACKED,
+	},
 };
 
-int get_format_size(void)
+int cx25821_get_format_size(void)
 {
 	return ARRAY_SIZE(formats);
 }
@@ -102,7 +102,7 @@
 	return NULL;
 }
 
-void dump_video_queue(struct cx25821_dev *dev, struct cx25821_dmaqueue *q)
+void cx25821_dump_video_queue(struct cx25821_dev *dev, struct cx25821_dmaqueue *q)
 {
 	struct cx25821_buffer *buf;
 	struct list_head *item;
@@ -212,7 +212,7 @@
 */
 
 // resource management
-int res_get(struct cx25821_dev *dev, struct cx25821_fh *fh, unsigned int bit)
+int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh, unsigned int bit)
 {
 	dprintk(1, "%s()\n", __func__);
 	if (fh->resources & bit)
@@ -234,17 +234,17 @@
 	return 1;
 }
 
-int res_check(struct cx25821_fh *fh, unsigned int bit)
+int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit)
 {
 	return fh->resources & bit;
 }
 
-int res_locked(struct cx25821_dev *dev, unsigned int bit)
+int cx25821_res_locked(struct cx25821_dev *dev, unsigned int bit)
 {
 	return dev->resources & bit;
 }
 
-void res_free(struct cx25821_dev *dev, struct cx25821_fh *fh, unsigned int bits)
+void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh, unsigned int bits)
 {
 	BUG_ON((fh->resources & bits) != bits);
 	dprintk(1, "%s()\n", __func__);
@@ -506,7 +506,7 @@
 	return err;
 }
 
-int buffer_setup(struct videobuf_queue *q, unsigned int *count,
+int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count,
 		 unsigned int *size)
 {
 	struct cx25821_fh *fh = q->priv_data;
@@ -516,13 +516,13 @@
 	if (0 == *count)
 		*count = 32;
 
-	while (*size * *count > vid_limit * 1024 * 1024)
-		(*count)--;
+	if (*size * *count > vid_limit * 1024 * 1024)
+		*count = (vid_limit * 1024 * 1024) / *size;
 
 	return 0;
 }
 
-int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
 		   enum v4l2_field field)
 {
 	struct cx25821_fh *fh = q->priv_data;
@@ -648,7 +648,7 @@
 	return rc;
 }
 
-void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+void cx25821_buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
 	struct cx25821_buffer *buf =
 	    container_of(vb, struct cx25821_buffer, vb);
@@ -667,7 +667,7 @@
 	}
 }
 
-int get_resource(struct cx25821_fh *fh, int resource)
+int cx25821_get_resource(struct cx25821_fh *fh, int resource)
 {
 	switch (fh->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
@@ -678,7 +678,7 @@
 	}
 }
 
-int video_mmap(struct file *file, struct vm_area_struct *vma)
+int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	struct cx25821_fh *fh = file->private_data;
 
@@ -686,7 +686,7 @@
 }
 
 /* VIDEO IOCTLS                                                       */
-int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f)
+int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f)
 {
 	struct cx25821_fh *fh = priv;
 
@@ -700,7 +700,7 @@
 	return 0;
 }
 
-int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f)
+int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f)
 {
 	struct cx25821_fmt *fmt;
 	enum v4l2_field field;
@@ -746,7 +746,7 @@
 	return 0;
 }
 
-int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
+int cx25821_vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
 {
 	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
 
@@ -761,7 +761,7 @@
 	return 0;
 }
 
-int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
 			    struct v4l2_fmtdesc *f)
 {
 	if (unlikely(f->index >= ARRAY_SIZE(formats)))
@@ -774,7 +774,7 @@
 }
 
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
+int cx25821_vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
 {
 	struct cx25821_fh *fh = priv;
 	struct videobuf_queue *q;
@@ -801,25 +801,25 @@
 }
 #endif
 
-int vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p)
+int cx25821_vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p)
 {
 	struct cx25821_fh *fh = priv;
 	return videobuf_reqbufs(get_queue(fh), p);
 }
 
-int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
+int cx25821_vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
 	struct cx25821_fh *fh = priv;
 	return videobuf_querybuf(get_queue(fh), p);
 }
 
-int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
 	struct cx25821_fh *fh = priv;
 	return videobuf_qbuf(get_queue(fh), p);
 }
 
-int vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p)
+int cx25821_vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p)
 {
 	struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev;
 
@@ -828,7 +828,7 @@
 	return 0;
 }
 
-int vidioc_s_priority(struct file *file, void *f, enum v4l2_priority prio)
+int cx25821_vidioc_s_priority(struct file *file, void *f, enum v4l2_priority prio)
 {
 	struct cx25821_fh *fh = f;
 	struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev;
@@ -837,7 +837,7 @@
 }
 
 #ifdef TUNER_FLAG
-int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * tvnorms)
+int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id * tvnorms)
 {
 	struct cx25821_fh *fh = priv;
 	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
@@ -846,7 +846,7 @@
 	dprintk(1, "%s()\n", __func__);
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
@@ -891,14 +891,14 @@
 	return 0;
 }
 
-int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i)
+int cx25821_vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i)
 {
 	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
 	dprintk(1, "%s()\n", __func__);
 	return cx25821_enum_input(dev, i);
 }
 
-int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i)
 {
 	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
 
@@ -907,7 +907,7 @@
 	return 0;
 }
 
-int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i)
 {
 	struct cx25821_fh *fh = priv;
 	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
@@ -916,7 +916,7 @@
 	dprintk(1, "%s(%d)\n", __func__, i);
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
@@ -933,7 +933,7 @@
 }
 
 #ifdef TUNER_FLAG
-int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f)
+int cx25821_vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f)
 {
 	struct cx25821_fh *fh = priv;
 	struct cx25821_dev *dev = fh->dev;
@@ -960,15 +960,14 @@
 	return 0;
 }
 
-int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f)
+int cx25821_vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f)
 {
 	struct cx25821_fh *fh = priv;
 	struct cx25821_dev *dev;
 	int err;
 
 	if (fh) {
-		dev = fh->dev;
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
@@ -978,7 +977,7 @@
 #endif
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-int vidioc_g_register(struct file *file, void *fh,
+int cx25821_vidioc_g_register(struct file *file, void *fh,
 		      struct v4l2_dbg_register *reg)
 {
 	struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev;
@@ -991,7 +990,7 @@
 	return 0;
 }
 
-int vidioc_s_register(struct file *file, void *fh,
+int cx25821_vidioc_s_register(struct file *file, void *fh,
 		      struct v4l2_dbg_register *reg)
 {
 	struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev;
@@ -1007,7 +1006,7 @@
 #endif
 
 #ifdef TUNER_FLAG
-int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+int cx25821_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
 {
 	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
 
@@ -1025,14 +1024,14 @@
 	return 0;
 }
 
-int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+int cx25821_vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
 {
 	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
 	struct cx25821_fh *fh = priv;
 	int err;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
@@ -1108,7 +1107,7 @@
 	return 0;
 }
 
-int vidioc_queryctrl(struct file *file, void *priv,
+int cx25821_vidioc_queryctrl(struct file *file, void *priv,
 		     struct v4l2_queryctrl *qctrl)
 {
 	return cx25821_ctrl_query(qctrl);
@@ -1127,7 +1126,7 @@
 	return NULL;
 }
 
-int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctl)
+int cx25821_vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctl)
 {
 	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
 
@@ -1216,7 +1215,7 @@
 	}
 }
 
-int vidioc_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cropcap)
+int cx25821_vidioc_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cropcap)
 {
 	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
 
@@ -1233,28 +1232,28 @@
 	return 0;
 }
 
-int vidioc_s_crop(struct file *file, void *priv, struct v4l2_crop *crop)
+int cx25821_vidioc_s_crop(struct file *file, void *priv, struct v4l2_crop *crop)
 {
 	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
 	struct cx25821_fh *fh = priv;
 	int err;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
-	// vidioc_s_crop not supported
+	// cx25821_vidioc_s_crop not supported
 	return -EINVAL;
 }
 
-int vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop)
+int cx25821_vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop)
 {
-	// vidioc_g_crop not supported
+	// cx25821_vidioc_g_crop not supported
 	return -EINVAL;
 }
 
-int vidioc_querystd(struct file *file, void *priv, v4l2_std_id * norm)
+int cx25821_vidioc_querystd(struct file *file, void *priv, v4l2_std_id * norm)
 {
 	// medusa does not support video standard sensing of current input
 	*norm = CX25821_NORMS;
@@ -1262,7 +1261,7 @@
 	return 0;
 }
 
-int is_valid_width(u32 width, v4l2_std_id tvnorm)
+int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm)
 {
 	if (tvnorm == V4L2_STD_PAL_BG) {
 		if (width == 352 || width == 720)
@@ -1280,7 +1279,7 @@
 	return 0;
 }
 
-int is_valid_height(u32 height, v4l2_std_id tvnorm)
+int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm)
 {
 	if (tvnorm == V4L2_STD_PAL_BG) {
 		if (height == 576 || height == 288)
diff --git a/drivers/staging/cx25821/cx25821-video.h b/drivers/staging/cx25821/cx25821-video.h
index 4417ff5..0bddc02 100644
--- a/drivers/staging/cx25821/cx25821-video.h
+++ b/drivers/staging/cx25821/cx25821-video.h
@@ -101,7 +101,7 @@
 extern struct cx25821_fmt *format_by_fourcc(unsigned int fourcc);
 extern struct cx25821_data timeout_data[MAX_VID_CHANNEL_NUM];
 
-extern void dump_video_queue(struct cx25821_dev *dev,
+extern void cx25821_dump_video_queue(struct cx25821_dev *dev,
 			     struct cx25821_dmaqueue *q);
 extern void cx25821_video_wakeup(struct cx25821_dev *dev,
 				 struct cx25821_dmaqueue *q, u32 count);
@@ -110,11 +110,11 @@
 extern int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm);
 #endif
 
-extern int res_get(struct cx25821_dev *dev, struct cx25821_fh *fh,
+extern int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh,
 		   unsigned int bit);
-extern int res_check(struct cx25821_fh *fh, unsigned int bit);
-extern int res_locked(struct cx25821_dev *dev, unsigned int bit);
-extern void res_free(struct cx25821_dev *dev, struct cx25821_fh *fh,
+extern int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit);
+extern int cx25821_res_locked(struct cx25821_dev *dev, unsigned int bit);
+extern void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh,
 		     unsigned int bits);
 extern int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input);
 extern int cx25821_start_video_dma(struct cx25821_dev *dev,
@@ -128,67 +128,67 @@
 extern void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num);
 extern int cx25821_video_register(struct cx25821_dev *dev, int chan_num,
 				  struct video_device *video_template);
-extern int get_format_size(void);
+extern int cx25821_get_format_size(void);
 
-extern int buffer_setup(struct videobuf_queue *q, unsigned int *count,
+extern int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count,
 			unsigned int *size);
-extern int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+extern int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
 			  enum v4l2_field field);
-extern void buffer_release(struct videobuf_queue *q,
+extern void cx25821_buffer_release(struct videobuf_queue *q,
 			   struct videobuf_buffer *vb);
 extern struct videobuf_queue *get_queue(struct cx25821_fh *fh);
-extern int get_resource(struct cx25821_fh *fh, int resource);
-extern int video_mmap(struct file *file, struct vm_area_struct *vma);
-extern int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+extern int cx25821_get_resource(struct cx25821_fh *fh, int resource);
+extern int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma);
+extern int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 				  struct v4l2_format *f);
-extern int vidioc_querycap(struct file *file, void *priv,
+extern int cx25821_vidioc_querycap(struct file *file, void *priv,
 			   struct v4l2_capability *cap);
-extern int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+extern int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
 				   struct v4l2_fmtdesc *f);
-extern int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf);
-extern int vidioc_reqbufs(struct file *file, void *priv,
+extern int cx25821_vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf);
+extern int cx25821_vidioc_reqbufs(struct file *file, void *priv,
 			  struct v4l2_requestbuffers *p);
-extern int vidioc_querybuf(struct file *file, void *priv,
+extern int cx25821_vidioc_querybuf(struct file *file, void *priv,
 			   struct v4l2_buffer *p);
-extern int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p);
-extern int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * tvnorms);
+extern int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p);
+extern int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id * tvnorms);
 extern int cx25821_enum_input(struct cx25821_dev *dev, struct v4l2_input *i);
-extern int vidioc_enum_input(struct file *file, void *priv,
+extern int cx25821_vidioc_enum_input(struct file *file, void *priv,
 			     struct v4l2_input *i);
-extern int vidioc_g_input(struct file *file, void *priv, unsigned int *i);
-extern int vidioc_s_input(struct file *file, void *priv, unsigned int i);
-extern int vidioc_g_ctrl(struct file *file, void *priv,
+extern int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i);
+extern int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i);
+extern int cx25821_vidioc_g_ctrl(struct file *file, void *priv,
 			 struct v4l2_control *ctl);
-extern int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+extern int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 				struct v4l2_format *f);
-extern int vidioc_g_frequency(struct file *file, void *priv,
+extern int cx25821_vidioc_g_frequency(struct file *file, void *priv,
 			      struct v4l2_frequency *f);
 extern int cx25821_set_freq(struct cx25821_dev *dev, struct v4l2_frequency *f);
-extern int vidioc_s_frequency(struct file *file, void *priv,
+extern int cx25821_vidioc_s_frequency(struct file *file, void *priv,
 			      struct v4l2_frequency *f);
-extern int vidioc_g_register(struct file *file, void *fh,
+extern int cx25821_vidioc_g_register(struct file *file, void *fh,
 			     struct v4l2_dbg_register *reg);
-extern int vidioc_s_register(struct file *file, void *fh,
+extern int cx25821_vidioc_s_register(struct file *file, void *fh,
 			     struct v4l2_dbg_register *reg);
-extern int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t);
-extern int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t);
+extern int cx25821_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t);
+extern int cx25821_vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t);
 
-extern int is_valid_width(u32 width, v4l2_std_id tvnorm);
-extern int is_valid_height(u32 height, v4l2_std_id tvnorm);
+extern int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm);
+extern int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm);
 
-extern int vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p);
-extern int vidioc_s_priority(struct file *file, void *f,
+extern int cx25821_vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p);
+extern int cx25821_vidioc_s_priority(struct file *file, void *f,
 			     enum v4l2_priority prio);
 
-extern int vidioc_queryctrl(struct file *file, void *priv,
+extern int cx25821_vidioc_queryctrl(struct file *file, void *priv,
 			    struct v4l2_queryctrl *qctrl);
 extern int cx25821_set_control(struct cx25821_dev *dev,
 			       struct v4l2_control *ctrl, int chan_num);
 
-extern int vidioc_cropcap(struct file *file, void *fh,
+extern int cx25821_vidioc_cropcap(struct file *file, void *fh,
 			  struct v4l2_cropcap *cropcap);
-extern int vidioc_s_crop(struct file *file, void *priv, struct v4l2_crop *crop);
-extern int vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop);
+extern int cx25821_vidioc_s_crop(struct file *file, void *priv, struct v4l2_crop *crop);
+extern int cx25821_vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop);
 
-extern int vidioc_querystd(struct file *file, void *priv, v4l2_std_id * norm);
+extern int cx25821_vidioc_querystd(struct file *file, void *priv, v4l2_std_id * norm);
 #endif
diff --git a/drivers/staging/cx25821/cx25821-video0.c b/drivers/staging/cx25821/cx25821-video0.c
index ad7a691..0be2cc1 100644
--- a/drivers/staging/cx25821/cx25821-video0.c
+++ b/drivers/staging/cx25821/cx25821-video0.c
@@ -86,10 +86,10 @@
 }
 
 static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = buffer_setup,
-	.buf_prepare = buffer_prepare,
+	.buf_setup = cx25821_buffer_setup,
+	.buf_prepare = cx25821_buffer_prepare,
 	.buf_queue = buffer_queue,
-	.buf_release = buffer_release,
+	.buf_release = cx25821_buffer_release,
 };
 
 static int video_open(struct file *file)
@@ -147,7 +147,7 @@
 
 	switch (fh->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (res_locked(fh->dev, RESOURCE_VIDEO0))
+		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO0))
 			return -EBUSY;
 
 		return videobuf_read_one(&fh->vidq, data, count, ppos,
@@ -165,7 +165,7 @@
 	struct cx25821_fh *fh = file->private_data;
 	struct cx25821_buffer *buf;
 
-	if (res_check(fh, RESOURCE_VIDEO0)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
 		/* streaming capture */
 		if (list_empty(&fh->vidq.stream))
 			return POLLERR;
@@ -207,19 +207,19 @@
 	cx_write(channel0->dma_ctl, 0);	/* FIFO and RISC disable */
 
 	/* stop video capture */
-	if (res_check(fh, RESOURCE_VIDEO0)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
 		videobuf_queue_cancel(&fh->vidq);
-		res_free(dev, fh, RESOURCE_VIDEO0);
+		cx25821_res_free(dev, fh, RESOURCE_VIDEO0);
 	}
 
 	if (fh->vidq.read_buf) {
-		buffer_release(&fh->vidq, fh->vidq.read_buf);
+		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
 		kfree(fh->vidq.read_buf);
 	}
 
 	videobuf_mmap_free(&fh->vidq);
 
-	v4l2_prio_close(&dev->prio, &fh->prio);
+	v4l2_prio_close(&dev->prio, fh->prio);
 	file->private_data = NULL;
 	kfree(fh);
 
@@ -239,7 +239,7 @@
 		return -EINVAL;
 	}
 
-	if (unlikely(!res_get(dev, fh, get_resource(fh, RESOURCE_VIDEO0)))) {
+	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO0)))) {
 		return -EBUSY;
 	}
 
@@ -257,11 +257,11 @@
 	if (i != fh->type)
 		return -EINVAL;
 
-	res = get_resource(fh, RESOURCE_VIDEO0);
+	res = cx25821_get_resource(fh, RESOURCE_VIDEO0);
 	err = videobuf_streamoff(get_queue(fh));
 	if (err < 0)
 		return err;
-	res_free(dev, fh, res);
+	cx25821_res_free(dev, fh, res);
 	return 0;
 }
 
@@ -274,13 +274,13 @@
 	int pix_format = PIXEL_FRMT_422;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
 
 	dprintk(2, "%s()\n", __func__);
-	err = vidioc_try_fmt_vid_cap(file, priv, f);
+	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
 
 	if (0 != err)
 		return err;
@@ -289,11 +289,11 @@
 	fh->vidq.field = f->fmt.pix.field;
 
 	// check if width and height is valid based on set standard
-	if (is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
+	if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
 		fh->width = f->fmt.pix.width;
 	}
 
-	if (is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
+	if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
 		fh->height = f->fmt.pix.height;
 	}
 
@@ -363,7 +363,7 @@
 	int err;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
@@ -378,50 +378,50 @@
 	.release = video_release,
 	.read = video_read,
 	.poll = video_poll,
-	.mmap = video_mmap,
+	.mmap = cx25821_video_mmap,
 	.ioctl = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+	.vidioc_querycap = cx25821_vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
 	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = vidioc_reqbufs,
-	.vidioc_querybuf = vidioc_querybuf,
-	.vidioc_qbuf = vidioc_qbuf,
+	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
+	.vidioc_querybuf = cx25821_vidioc_querybuf,
+	.vidioc_qbuf = cx25821_vidioc_qbuf,
 	.vidioc_dqbuf = vidioc_dqbuf,
 #ifdef TUNER_FLAG
-	.vidioc_s_std = vidioc_s_std,
-	.vidioc_querystd = vidioc_querystd,
+	.vidioc_s_std = cx25821_vidioc_s_std,
+	.vidioc_querystd = cx25821_vidioc_querystd,
 #endif
-	.vidioc_cropcap = vidioc_cropcap,
-	.vidioc_s_crop = vidioc_s_crop,
-	.vidioc_g_crop = vidioc_g_crop,
-	.vidioc_enum_input = vidioc_enum_input,
-	.vidioc_g_input = vidioc_g_input,
-	.vidioc_s_input = vidioc_s_input,
-	.vidioc_g_ctrl = vidioc_g_ctrl,
+	.vidioc_cropcap = cx25821_vidioc_cropcap,
+	.vidioc_s_crop = cx25821_vidioc_s_crop,
+	.vidioc_g_crop = cx25821_vidioc_g_crop,
+	.vidioc_enum_input = cx25821_vidioc_enum_input,
+	.vidioc_g_input = cx25821_vidioc_g_input,
+	.vidioc_s_input = cx25821_vidioc_s_input,
+	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
 	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = vidioc_queryctrl,
+	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
 	.vidioc_streamon = vidioc_streamon,
 	.vidioc_streamoff = vidioc_streamoff,
 	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = vidioc_g_priority,
-	.vidioc_s_priority = vidioc_s_priority,
+	.vidioc_g_priority = cx25821_vidioc_g_priority,
+	.vidioc_s_priority = cx25821_vidioc_s_priority,
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = vidiocgmbuf,
+	.vidiocgmbuf = cx25821_vidiocgmbuf,
 #endif
 #ifdef TUNER_FLAG
-	.vidioc_g_tuner = vidioc_g_tuner,
-	.vidioc_s_tuner = vidioc_s_tuner,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
+	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
+	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
+	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
 #endif
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = vidioc_g_register,
-	.vidioc_s_register = vidioc_s_register,
+	.vidioc_g_register = cx25821_vidioc_g_register,
+	.vidioc_s_register = cx25821_vidioc_s_register,
 #endif
 };
 
diff --git a/drivers/staging/cx25821/cx25821-video1.c b/drivers/staging/cx25821/cx25821-video1.c
index e3f3c4a..b0bae627 100644
--- a/drivers/staging/cx25821/cx25821-video1.c
+++ b/drivers/staging/cx25821/cx25821-video1.c
@@ -86,10 +86,10 @@
 }
 
 static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = buffer_setup,
-	.buf_prepare = buffer_prepare,
+	.buf_setup = cx25821_buffer_setup,
+	.buf_prepare = cx25821_buffer_prepare,
 	.buf_queue = buffer_queue,
-	.buf_release = buffer_release,
+	.buf_release = cx25821_buffer_release,
 };
 
 static int video_open(struct file *file)
@@ -147,7 +147,7 @@
 
 	switch (fh->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (res_locked(fh->dev, RESOURCE_VIDEO1))
+		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO1))
 			return -EBUSY;
 
 		return videobuf_read_one(&fh->vidq, data, count, ppos,
@@ -165,7 +165,7 @@
 	struct cx25821_fh *fh = file->private_data;
 	struct cx25821_buffer *buf;
 
-	if (res_check(fh, RESOURCE_VIDEO1)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO1)) {
 		/* streaming capture */
 		if (list_empty(&fh->vidq.stream))
 			return POLLERR;
@@ -207,19 +207,19 @@
 	cx_write(channel1->dma_ctl, 0);	/* FIFO and RISC disable */
 
 	/* stop video capture */
-	if (res_check(fh, RESOURCE_VIDEO1)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO1)) {
 		videobuf_queue_cancel(&fh->vidq);
-		res_free(dev, fh, RESOURCE_VIDEO1);
+		cx25821_res_free(dev, fh, RESOURCE_VIDEO1);
 	}
 
 	if (fh->vidq.read_buf) {
-		buffer_release(&fh->vidq, fh->vidq.read_buf);
+		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
 		kfree(fh->vidq.read_buf);
 	}
 
 	videobuf_mmap_free(&fh->vidq);
 
-	v4l2_prio_close(&dev->prio, &fh->prio);
+	v4l2_prio_close(&dev->prio, fh->prio);
 	file->private_data = NULL;
 	kfree(fh);
 
@@ -239,7 +239,7 @@
 		return -EINVAL;
 	}
 
-	if (unlikely(!res_get(dev, fh, get_resource(fh, RESOURCE_VIDEO1)))) {
+	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO1)))) {
 		return -EBUSY;
 	}
 
@@ -257,11 +257,11 @@
 	if (i != fh->type)
 		return -EINVAL;
 
-	res = get_resource(fh, RESOURCE_VIDEO1);
+	res = cx25821_get_resource(fh, RESOURCE_VIDEO1);
 	err = videobuf_streamoff(get_queue(fh));
 	if (err < 0)
 		return err;
-	res_free(dev, fh, res);
+	cx25821_res_free(dev, fh, res);
 	return 0;
 }
 
@@ -274,13 +274,13 @@
 	int pix_format = 0;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
 
 	dprintk(2, "%s()\n", __func__);
-	err = vidioc_try_fmt_vid_cap(file, priv, f);
+	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
 
 	if (0 != err)
 		return err;
@@ -289,11 +289,11 @@
 	fh->vidq.field = f->fmt.pix.field;
 
 	// check if width and height is valid based on set standard
-	if (is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
+	if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
 		fh->width = f->fmt.pix.width;
 	}
 
-	if (is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
+	if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
 		fh->height = f->fmt.pix.height;
 	}
 
@@ -363,7 +363,7 @@
 	int err;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
@@ -378,50 +378,50 @@
 	.release = video_release,
 	.read = video_read,
 	.poll = video_poll,
-	.mmap = video_mmap,
+	.mmap = cx25821_video_mmap,
 	.ioctl = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+	.vidioc_querycap = cx25821_vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
 	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = vidioc_reqbufs,
-	.vidioc_querybuf = vidioc_querybuf,
-	.vidioc_qbuf = vidioc_qbuf,
+	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
+	.vidioc_querybuf = cx25821_vidioc_querybuf,
+	.vidioc_qbuf = cx25821_vidioc_qbuf,
 	.vidioc_dqbuf = vidioc_dqbuf,
 #ifdef TUNER_FLAG
-	.vidioc_s_std = vidioc_s_std,
-	.vidioc_querystd = vidioc_querystd,
+	.vidioc_s_std = cx25821_vidioc_s_std,
+	.vidioc_querystd = cx25821_vidioc_querystd,
 #endif
-	.vidioc_cropcap = vidioc_cropcap,
-	.vidioc_s_crop = vidioc_s_crop,
-	.vidioc_g_crop = vidioc_g_crop,
-	.vidioc_enum_input = vidioc_enum_input,
-	.vidioc_g_input = vidioc_g_input,
-	.vidioc_s_input = vidioc_s_input,
-	.vidioc_g_ctrl = vidioc_g_ctrl,
+	.vidioc_cropcap = cx25821_vidioc_cropcap,
+	.vidioc_s_crop = cx25821_vidioc_s_crop,
+	.vidioc_g_crop = cx25821_vidioc_g_crop,
+	.vidioc_enum_input = cx25821_vidioc_enum_input,
+	.vidioc_g_input = cx25821_vidioc_g_input,
+	.vidioc_s_input = cx25821_vidioc_s_input,
+	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
 	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = vidioc_queryctrl,
+	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
 	.vidioc_streamon = vidioc_streamon,
 	.vidioc_streamoff = vidioc_streamoff,
 	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = vidioc_g_priority,
-	.vidioc_s_priority = vidioc_s_priority,
+	.vidioc_g_priority = cx25821_vidioc_g_priority,
+	.vidioc_s_priority = cx25821_vidioc_s_priority,
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = vidiocgmbuf,
+	.vidiocgmbuf = cx25821_vidiocgmbuf,
 #endif
 #ifdef TUNER_FLAG
-	.vidioc_g_tuner = vidioc_g_tuner,
-	.vidioc_s_tuner = vidioc_s_tuner,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
+	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
+	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
+	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
 #endif
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = vidioc_g_register,
-	.vidioc_s_register = vidioc_s_register,
+	.vidioc_g_register = cx25821_vidioc_g_register,
+	.vidioc_s_register = cx25821_vidioc_s_register,
 #endif
 };
 
diff --git a/drivers/staging/cx25821/cx25821-video2.c b/drivers/staging/cx25821/cx25821-video2.c
index 36fb855..400cdb8 100644
--- a/drivers/staging/cx25821/cx25821-video2.c
+++ b/drivers/staging/cx25821/cx25821-video2.c
@@ -86,10 +86,10 @@
 }
 
 static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = buffer_setup,
-	.buf_prepare = buffer_prepare,
+	.buf_setup = cx25821_buffer_setup,
+	.buf_prepare = cx25821_buffer_prepare,
 	.buf_queue = buffer_queue,
-	.buf_release = buffer_release,
+	.buf_release = cx25821_buffer_release,
 };
 
 static int video_open(struct file *file)
@@ -147,7 +147,7 @@
 
 	switch (fh->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (res_locked(fh->dev, RESOURCE_VIDEO2))
+		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO2))
 			return -EBUSY;
 
 		return videobuf_read_one(&fh->vidq, data, count, ppos,
@@ -165,7 +165,7 @@
 	struct cx25821_fh *fh = file->private_data;
 	struct cx25821_buffer *buf;
 
-	if (res_check(fh, RESOURCE_VIDEO2)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO2)) {
 		/* streaming capture */
 		if (list_empty(&fh->vidq.stream))
 			return POLLERR;
@@ -207,19 +207,19 @@
 	cx_write(channel2->dma_ctl, 0);	/* FIFO and RISC disable */
 
 	/* stop video capture */
-	if (res_check(fh, RESOURCE_VIDEO2)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO2)) {
 		videobuf_queue_cancel(&fh->vidq);
-		res_free(dev, fh, RESOURCE_VIDEO2);
+		cx25821_res_free(dev, fh, RESOURCE_VIDEO2);
 	}
 
 	if (fh->vidq.read_buf) {
-		buffer_release(&fh->vidq, fh->vidq.read_buf);
+		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
 		kfree(fh->vidq.read_buf);
 	}
 
 	videobuf_mmap_free(&fh->vidq);
 
-	v4l2_prio_close(&dev->prio, &fh->prio);
+	v4l2_prio_close(&dev->prio, fh->prio);
 	file->private_data = NULL;
 	kfree(fh);
 
@@ -239,7 +239,7 @@
 		return -EINVAL;
 	}
 
-	if (unlikely(!res_get(dev, fh, get_resource(fh, RESOURCE_VIDEO2)))) {
+	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO2)))) {
 		return -EBUSY;
 	}
 
@@ -257,11 +257,11 @@
 	if (i != fh->type)
 		return -EINVAL;
 
-	res = get_resource(fh, RESOURCE_VIDEO2);
+	res = cx25821_get_resource(fh, RESOURCE_VIDEO2);
 	err = videobuf_streamoff(get_queue(fh));
 	if (err < 0)
 		return err;
-	res_free(dev, fh, res);
+	cx25821_res_free(dev, fh, res);
 	return 0;
 }
 
@@ -274,13 +274,13 @@
 	int pix_format = 0;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
 
 	dprintk(2, "%s()\n", __func__);
-	err = vidioc_try_fmt_vid_cap(file, priv, f);
+	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
 
 	if (0 != err)
 		return err;
@@ -289,11 +289,11 @@
 	fh->vidq.field = f->fmt.pix.field;
 
 	// check if width and height is valid based on set standard
-	if (is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
+	if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
 		fh->width = f->fmt.pix.width;
 	}
 
-	if (is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
+	if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
 		fh->height = f->fmt.pix.height;
 	}
 
@@ -365,7 +365,7 @@
 	int err;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
@@ -380,50 +380,50 @@
 	.release = video_release,
 	.read = video_read,
 	.poll = video_poll,
-	.mmap = video_mmap,
+	.mmap = cx25821_video_mmap,
 	.ioctl = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+	.vidioc_querycap = cx25821_vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
 	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = vidioc_reqbufs,
-	.vidioc_querybuf = vidioc_querybuf,
-	.vidioc_qbuf = vidioc_qbuf,
+	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
+	.vidioc_querybuf = cx25821_vidioc_querybuf,
+	.vidioc_qbuf = cx25821_vidioc_qbuf,
 	.vidioc_dqbuf = vidioc_dqbuf,
 #ifdef TUNER_FLAG
-	.vidioc_s_std = vidioc_s_std,
-	.vidioc_querystd = vidioc_querystd,
+	.vidioc_s_std = cx25821_vidioc_s_std,
+	.vidioc_querystd = cx25821_vidioc_querystd,
 #endif
-	.vidioc_cropcap = vidioc_cropcap,
-	.vidioc_s_crop = vidioc_s_crop,
-	.vidioc_g_crop = vidioc_g_crop,
-	.vidioc_enum_input = vidioc_enum_input,
-	.vidioc_g_input = vidioc_g_input,
-	.vidioc_s_input = vidioc_s_input,
-	.vidioc_g_ctrl = vidioc_g_ctrl,
+	.vidioc_cropcap = cx25821_vidioc_cropcap,
+	.vidioc_s_crop = cx25821_vidioc_s_crop,
+	.vidioc_g_crop = cx25821_vidioc_g_crop,
+	.vidioc_enum_input = cx25821_vidioc_enum_input,
+	.vidioc_g_input = cx25821_vidioc_g_input,
+	.vidioc_s_input = cx25821_vidioc_s_input,
+	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
 	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = vidioc_queryctrl,
+	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
 	.vidioc_streamon = vidioc_streamon,
 	.vidioc_streamoff = vidioc_streamoff,
 	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = vidioc_g_priority,
-	.vidioc_s_priority = vidioc_s_priority,
+	.vidioc_g_priority = cx25821_vidioc_g_priority,
+	.vidioc_s_priority = cx25821_vidioc_s_priority,
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = vidiocgmbuf,
+	.vidiocgmbuf = cx25821_vidiocgmbuf,
 #endif
 #ifdef TUNER_FLAG
-	.vidioc_g_tuner = vidioc_g_tuner,
-	.vidioc_s_tuner = vidioc_s_tuner,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
+	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
+	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
+	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
 #endif
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = vidioc_g_register,
-	.vidioc_s_register = vidioc_s_register,
+	.vidioc_g_register = cx25821_vidioc_g_register,
+	.vidioc_s_register = cx25821_vidioc_s_register,
 #endif
 };
 
diff --git a/drivers/staging/cx25821/cx25821-video3.c b/drivers/staging/cx25821/cx25821-video3.c
index 1e0f10a..3b216ed 100644
--- a/drivers/staging/cx25821/cx25821-video3.c
+++ b/drivers/staging/cx25821/cx25821-video3.c
@@ -86,10 +86,10 @@
 }
 
 static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = buffer_setup,
-	.buf_prepare = buffer_prepare,
+	.buf_setup = cx25821_buffer_setup,
+	.buf_prepare = cx25821_buffer_prepare,
 	.buf_queue = buffer_queue,
-	.buf_release = buffer_release,
+	.buf_release = cx25821_buffer_release,
 };
 
 static int video_open(struct file *file)
@@ -147,7 +147,7 @@
 
 	switch (fh->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (res_locked(fh->dev, RESOURCE_VIDEO3))
+		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO3))
 			return -EBUSY;
 
 		return videobuf_read_one(&fh->vidq, data, count, ppos,
@@ -165,7 +165,7 @@
 	struct cx25821_fh *fh = file->private_data;
 	struct cx25821_buffer *buf;
 
-	if (res_check(fh, RESOURCE_VIDEO3)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO3)) {
 		/* streaming capture */
 		if (list_empty(&fh->vidq.stream))
 			return POLLERR;
@@ -207,19 +207,19 @@
 	cx_write(channel3->dma_ctl, 0);	/* FIFO and RISC disable */
 
 	/* stop video capture */
-	if (res_check(fh, RESOURCE_VIDEO3)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO3)) {
 		videobuf_queue_cancel(&fh->vidq);
-		res_free(dev, fh, RESOURCE_VIDEO3);
+		cx25821_res_free(dev, fh, RESOURCE_VIDEO3);
 	}
 
 	if (fh->vidq.read_buf) {
-		buffer_release(&fh->vidq, fh->vidq.read_buf);
+		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
 		kfree(fh->vidq.read_buf);
 	}
 
 	videobuf_mmap_free(&fh->vidq);
 
-	v4l2_prio_close(&dev->prio, &fh->prio);
+	v4l2_prio_close(&dev->prio, fh->prio);
 	file->private_data = NULL;
 	kfree(fh);
 
@@ -239,7 +239,7 @@
 		return -EINVAL;
 	}
 
-	if (unlikely(!res_get(dev, fh, get_resource(fh, RESOURCE_VIDEO3)))) {
+	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO3)))) {
 		return -EBUSY;
 	}
 
@@ -257,11 +257,11 @@
 	if (i != fh->type)
 		return -EINVAL;
 
-	res = get_resource(fh, RESOURCE_VIDEO3);
+	res = cx25821_get_resource(fh, RESOURCE_VIDEO3);
 	err = videobuf_streamoff(get_queue(fh));
 	if (err < 0)
 		return err;
-	res_free(dev, fh, res);
+	cx25821_res_free(dev, fh, res);
 	return 0;
 }
 
@@ -274,13 +274,13 @@
 	int pix_format = 0;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
 
 	dprintk(2, "%s()\n", __func__);
-	err = vidioc_try_fmt_vid_cap(file, priv, f);
+	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
 
 	if (0 != err)
 		return err;
@@ -289,11 +289,11 @@
 	fh->vidq.field = f->fmt.pix.field;
 
 	// check if width and height is valid based on set standard
-	if (is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
+	if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
 		fh->width = f->fmt.pix.width;
 	}
 
-	if (is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
+	if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
 		fh->height = f->fmt.pix.height;
 	}
 
@@ -364,7 +364,7 @@
 	int err;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
@@ -379,50 +379,50 @@
 	.release = video_release,
 	.read = video_read,
 	.poll = video_poll,
-	.mmap = video_mmap,
+	.mmap = cx25821_video_mmap,
 	.ioctl = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+	.vidioc_querycap = cx25821_vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
 	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = vidioc_reqbufs,
-	.vidioc_querybuf = vidioc_querybuf,
-	.vidioc_qbuf = vidioc_qbuf,
+	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
+	.vidioc_querybuf = cx25821_vidioc_querybuf,
+	.vidioc_qbuf = cx25821_vidioc_qbuf,
 	.vidioc_dqbuf = vidioc_dqbuf,
 #ifdef TUNER_FLAG
-	.vidioc_s_std = vidioc_s_std,
-	.vidioc_querystd = vidioc_querystd,
+	.vidioc_s_std = cx25821_vidioc_s_std,
+	.vidioc_querystd = cx25821_vidioc_querystd,
 #endif
-	.vidioc_cropcap = vidioc_cropcap,
-	.vidioc_s_crop = vidioc_s_crop,
-	.vidioc_g_crop = vidioc_g_crop,
-	.vidioc_enum_input = vidioc_enum_input,
-	.vidioc_g_input = vidioc_g_input,
-	.vidioc_s_input = vidioc_s_input,
-	.vidioc_g_ctrl = vidioc_g_ctrl,
+	.vidioc_cropcap = cx25821_vidioc_cropcap,
+	.vidioc_s_crop = cx25821_vidioc_s_crop,
+	.vidioc_g_crop = cx25821_vidioc_g_crop,
+	.vidioc_enum_input = cx25821_vidioc_enum_input,
+	.vidioc_g_input = cx25821_vidioc_g_input,
+	.vidioc_s_input = cx25821_vidioc_s_input,
+	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
 	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = vidioc_queryctrl,
+	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
 	.vidioc_streamon = vidioc_streamon,
 	.vidioc_streamoff = vidioc_streamoff,
 	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = vidioc_g_priority,
-	.vidioc_s_priority = vidioc_s_priority,
+	.vidioc_g_priority = cx25821_vidioc_g_priority,
+	.vidioc_s_priority = cx25821_vidioc_s_priority,
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = vidiocgmbuf,
+	.vidiocgmbuf = cx25821_vidiocgmbuf,
 #endif
 #ifdef TUNER_FLAG
-	.vidioc_g_tuner = vidioc_g_tuner,
-	.vidioc_s_tuner = vidioc_s_tuner,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
+	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
+	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
+	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
 #endif
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = vidioc_g_register,
-	.vidioc_s_register = vidioc_s_register,
+	.vidioc_g_register = cx25821_vidioc_g_register,
+	.vidioc_s_register = cx25821_vidioc_s_register,
 #endif
 };
 
diff --git a/drivers/staging/cx25821/cx25821-video4.c b/drivers/staging/cx25821/cx25821-video4.c
index 0cbe7a7..f7b08c5 100644
--- a/drivers/staging/cx25821/cx25821-video4.c
+++ b/drivers/staging/cx25821/cx25821-video4.c
@@ -86,10 +86,10 @@
 }
 
 static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = buffer_setup,
-	.buf_prepare = buffer_prepare,
+	.buf_setup = cx25821_buffer_setup,
+	.buf_prepare = cx25821_buffer_prepare,
 	.buf_queue = buffer_queue,
-	.buf_release = buffer_release,
+	.buf_release = cx25821_buffer_release,
 };
 
 static int video_open(struct file *file)
@@ -146,7 +146,7 @@
 
 	switch (fh->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (res_locked(fh->dev, RESOURCE_VIDEO4))
+		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO4))
 			return -EBUSY;
 
 		return videobuf_read_one(&fh->vidq, data, count, ppos,
@@ -164,7 +164,7 @@
 	struct cx25821_fh *fh = file->private_data;
 	struct cx25821_buffer *buf;
 
-	if (res_check(fh, RESOURCE_VIDEO4)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO4)) {
 		/* streaming capture */
 		if (list_empty(&fh->vidq.stream))
 			return POLLERR;
@@ -206,19 +206,19 @@
 	cx_write(channel4->dma_ctl, 0);	/* FIFO and RISC disable */
 
 	/* stop video capture */
-	if (res_check(fh, RESOURCE_VIDEO4)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO4)) {
 		videobuf_queue_cancel(&fh->vidq);
-		res_free(dev, fh, RESOURCE_VIDEO4);
+		cx25821_res_free(dev, fh, RESOURCE_VIDEO4);
 	}
 
 	if (fh->vidq.read_buf) {
-		buffer_release(&fh->vidq, fh->vidq.read_buf);
+		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
 		kfree(fh->vidq.read_buf);
 	}
 
 	videobuf_mmap_free(&fh->vidq);
 
-	v4l2_prio_close(&dev->prio, &fh->prio);
+	v4l2_prio_close(&dev->prio, fh->prio);
 	file->private_data = NULL;
 	kfree(fh);
 
@@ -238,7 +238,7 @@
 		return -EINVAL;
 	}
 
-	if (unlikely(!res_get(dev, fh, get_resource(fh, RESOURCE_VIDEO4)))) {
+	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO4)))) {
 		return -EBUSY;
 	}
 
@@ -256,11 +256,11 @@
 	if (i != fh->type)
 		return -EINVAL;
 
-	res = get_resource(fh, RESOURCE_VIDEO4);
+	res = cx25821_get_resource(fh, RESOURCE_VIDEO4);
 	err = videobuf_streamoff(get_queue(fh));
 	if (err < 0)
 		return err;
-	res_free(dev, fh, res);
+	cx25821_res_free(dev, fh, res);
 	return 0;
 }
 
@@ -274,12 +274,12 @@
 
 	// check priority
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
 	dprintk(2, "%s()\n", __func__);
-	err = vidioc_try_fmt_vid_cap(file, priv, f);
+	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
 
 	if (0 != err)
 		return err;
@@ -288,11 +288,11 @@
 	fh->vidq.field = f->fmt.pix.field;
 
 	// check if width and height is valid based on set standard
-	if (is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
+	if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
 		fh->width = f->fmt.pix.width;
 	}
 
-	if (is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
+	if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
 		fh->height = f->fmt.pix.height;
 	}
 
@@ -363,7 +363,7 @@
 	int err;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
@@ -378,50 +378,50 @@
 	.release = video_release,
 	.read = video_read,
 	.poll = video_poll,
-	.mmap = video_mmap,
+	.mmap = cx25821_video_mmap,
 	.ioctl = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+	.vidioc_querycap = cx25821_vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
 	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = vidioc_reqbufs,
-	.vidioc_querybuf = vidioc_querybuf,
-	.vidioc_qbuf = vidioc_qbuf,
+	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
+	.vidioc_querybuf = cx25821_vidioc_querybuf,
+	.vidioc_qbuf = cx25821_vidioc_qbuf,
 	.vidioc_dqbuf = vidioc_dqbuf,
 #ifdef TUNER_FLAG
-	.vidioc_s_std = vidioc_s_std,
-	.vidioc_querystd = vidioc_querystd,
+	.vidioc_s_std = cx25821_vidioc_s_std,
+	.vidioc_querystd = cx25821_vidioc_querystd,
 #endif
-	.vidioc_cropcap = vidioc_cropcap,
-	.vidioc_s_crop = vidioc_s_crop,
-	.vidioc_g_crop = vidioc_g_crop,
-	.vidioc_enum_input = vidioc_enum_input,
-	.vidioc_g_input = vidioc_g_input,
-	.vidioc_s_input = vidioc_s_input,
-	.vidioc_g_ctrl = vidioc_g_ctrl,
+	.vidioc_cropcap = cx25821_vidioc_cropcap,
+	.vidioc_s_crop = cx25821_vidioc_s_crop,
+	.vidioc_g_crop = cx25821_vidioc_g_crop,
+	.vidioc_enum_input = cx25821_vidioc_enum_input,
+	.vidioc_g_input = cx25821_vidioc_g_input,
+	.vidioc_s_input = cx25821_vidioc_s_input,
+	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
 	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = vidioc_queryctrl,
+	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
 	.vidioc_streamon = vidioc_streamon,
 	.vidioc_streamoff = vidioc_streamoff,
 	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = vidioc_g_priority,
-	.vidioc_s_priority = vidioc_s_priority,
+	.vidioc_g_priority = cx25821_vidioc_g_priority,
+	.vidioc_s_priority = cx25821_vidioc_s_priority,
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = vidiocgmbuf,
+	.vidiocgmbuf = cx25821_vidiocgmbuf,
 #endif
 #ifdef TUNER_FLAG
-	.vidioc_g_tuner = vidioc_g_tuner,
-	.vidioc_s_tuner = vidioc_s_tuner,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
+	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
+	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
+	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
 #endif
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = vidioc_g_register,
-	.vidioc_s_register = vidioc_s_register,
+	.vidioc_g_register = cx25821_vidioc_g_register,
+	.vidioc_s_register = cx25821_vidioc_s_register,
 #endif
 };
 
diff --git a/drivers/staging/cx25821/cx25821-video5.c b/drivers/staging/cx25821/cx25821-video5.c
index 5dc08ad..5937033 100644
--- a/drivers/staging/cx25821/cx25821-video5.c
+++ b/drivers/staging/cx25821/cx25821-video5.c
@@ -86,10 +86,10 @@
 }
 
 static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = buffer_setup,
-	.buf_prepare = buffer_prepare,
+	.buf_setup = cx25821_buffer_setup,
+	.buf_prepare = cx25821_buffer_prepare,
 	.buf_queue = buffer_queue,
-	.buf_release = buffer_release,
+	.buf_release = cx25821_buffer_release,
 };
 
 static int video_open(struct file *file)
@@ -147,7 +147,7 @@
 
 	switch (fh->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (res_locked(fh->dev, RESOURCE_VIDEO5))
+		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO5))
 			return -EBUSY;
 
 		return videobuf_read_one(&fh->vidq, data, count, ppos,
@@ -165,7 +165,7 @@
 	struct cx25821_fh *fh = file->private_data;
 	struct cx25821_buffer *buf;
 
-	if (res_check(fh, RESOURCE_VIDEO5)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO5)) {
 		/* streaming capture */
 		if (list_empty(&fh->vidq.stream))
 			return POLLERR;
@@ -207,19 +207,19 @@
 	cx_write(channel5->dma_ctl, 0);	/* FIFO and RISC disable */
 
 	/* stop video capture */
-	if (res_check(fh, RESOURCE_VIDEO5)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO5)) {
 		videobuf_queue_cancel(&fh->vidq);
-		res_free(dev, fh, RESOURCE_VIDEO5);
+		cx25821_res_free(dev, fh, RESOURCE_VIDEO5);
 	}
 
 	if (fh->vidq.read_buf) {
-		buffer_release(&fh->vidq, fh->vidq.read_buf);
+		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
 		kfree(fh->vidq.read_buf);
 	}
 
 	videobuf_mmap_free(&fh->vidq);
 
-	v4l2_prio_close(&dev->prio, &fh->prio);
+	v4l2_prio_close(&dev->prio, fh->prio);
 	file->private_data = NULL;
 	kfree(fh);
 
@@ -239,7 +239,7 @@
 		return -EINVAL;
 	}
 
-	if (unlikely(!res_get(dev, fh, get_resource(fh, RESOURCE_VIDEO5)))) {
+	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO5)))) {
 		return -EBUSY;
 	}
 
@@ -257,11 +257,11 @@
 	if (i != fh->type)
 		return -EINVAL;
 
-	res = get_resource(fh, RESOURCE_VIDEO5);
+	res = cx25821_get_resource(fh, RESOURCE_VIDEO5);
 	err = videobuf_streamoff(get_queue(fh));
 	if (err < 0)
 		return err;
-	res_free(dev, fh, res);
+	cx25821_res_free(dev, fh, res);
 	return 0;
 }
 
@@ -274,13 +274,13 @@
 	int pix_format = 0;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
 
 	dprintk(2, "%s()\n", __func__);
-	err = vidioc_try_fmt_vid_cap(file, priv, f);
+	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
 
 	if (0 != err)
 		return err;
@@ -289,11 +289,11 @@
 	fh->vidq.field = f->fmt.pix.field;
 
 	// check if width and height is valid based on set standard
-	if (is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
+	if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
 		fh->width = f->fmt.pix.width;
 	}
 
-	if (is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
+	if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
 		fh->height = f->fmt.pix.height;
 	}
 
@@ -363,7 +363,7 @@
 	int err;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
@@ -378,50 +378,50 @@
 	.release = video_release,
 	.read = video_read,
 	.poll = video_poll,
-	.mmap = video_mmap,
+	.mmap = cx25821_video_mmap,
 	.ioctl = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+	.vidioc_querycap = cx25821_vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
 	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = vidioc_reqbufs,
-	.vidioc_querybuf = vidioc_querybuf,
-	.vidioc_qbuf = vidioc_qbuf,
+	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
+	.vidioc_querybuf = cx25821_vidioc_querybuf,
+	.vidioc_qbuf = cx25821_vidioc_qbuf,
 	.vidioc_dqbuf = vidioc_dqbuf,
 #ifdef TUNER_FLAG
-	.vidioc_s_std = vidioc_s_std,
-	.vidioc_querystd = vidioc_querystd,
+	.vidioc_s_std = cx25821_vidioc_s_std,
+	.vidioc_querystd = cx25821_vidioc_querystd,
 #endif
-	.vidioc_cropcap = vidioc_cropcap,
-	.vidioc_s_crop = vidioc_s_crop,
-	.vidioc_g_crop = vidioc_g_crop,
-	.vidioc_enum_input = vidioc_enum_input,
-	.vidioc_g_input = vidioc_g_input,
-	.vidioc_s_input = vidioc_s_input,
-	.vidioc_g_ctrl = vidioc_g_ctrl,
+	.vidioc_cropcap = cx25821_vidioc_cropcap,
+	.vidioc_s_crop = cx25821_vidioc_s_crop,
+	.vidioc_g_crop = cx25821_vidioc_g_crop,
+	.vidioc_enum_input = cx25821_vidioc_enum_input,
+	.vidioc_g_input = cx25821_vidioc_g_input,
+	.vidioc_s_input = cx25821_vidioc_s_input,
+	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
 	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = vidioc_queryctrl,
+	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
 	.vidioc_streamon = vidioc_streamon,
 	.vidioc_streamoff = vidioc_streamoff,
 	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = vidioc_g_priority,
-	.vidioc_s_priority = vidioc_s_priority,
+	.vidioc_g_priority = cx25821_vidioc_g_priority,
+	.vidioc_s_priority = cx25821_vidioc_s_priority,
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = vidiocgmbuf,
+	.vidiocgmbuf = cx25821_vidiocgmbuf,
 #endif
 #ifdef TUNER_FLAG
-	.vidioc_g_tuner = vidioc_g_tuner,
-	.vidioc_s_tuner = vidioc_s_tuner,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
+	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
+	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
+	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
 #endif
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = vidioc_g_register,
-	.vidioc_s_register = vidioc_s_register,
+	.vidioc_g_register = cx25821_vidioc_g_register,
+	.vidioc_s_register = cx25821_vidioc_s_register,
 #endif
 };
 
diff --git a/drivers/staging/cx25821/cx25821-video6.c b/drivers/staging/cx25821/cx25821-video6.c
index 2938ad3..4db2eb8 100644
--- a/drivers/staging/cx25821/cx25821-video6.c
+++ b/drivers/staging/cx25821/cx25821-video6.c
@@ -86,10 +86,10 @@
 }
 
 static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = buffer_setup,
-	.buf_prepare = buffer_prepare,
+	.buf_setup = cx25821_buffer_setup,
+	.buf_prepare = cx25821_buffer_prepare,
 	.buf_queue = buffer_queue,
-	.buf_release = buffer_release,
+	.buf_release = cx25821_buffer_release,
 };
 
 static int video_open(struct file *file)
@@ -147,7 +147,7 @@
 
 	switch (fh->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (res_locked(fh->dev, RESOURCE_VIDEO6))
+		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO6))
 			return -EBUSY;
 
 		return videobuf_read_one(&fh->vidq, data, count, ppos,
@@ -165,7 +165,7 @@
 	struct cx25821_fh *fh = file->private_data;
 	struct cx25821_buffer *buf;
 
-	if (res_check(fh, RESOURCE_VIDEO6)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO6)) {
 		/* streaming capture */
 		if (list_empty(&fh->vidq.stream))
 			return POLLERR;
@@ -207,18 +207,18 @@
 	cx_write(channel6->dma_ctl, 0);	/* FIFO and RISC disable */
 
 	/* stop video capture */
-	if (res_check(fh, RESOURCE_VIDEO6)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO6)) {
 		videobuf_queue_cancel(&fh->vidq);
-		res_free(dev, fh, RESOURCE_VIDEO6);
+		cx25821_res_free(dev, fh, RESOURCE_VIDEO6);
 	}
 	if (fh->vidq.read_buf) {
-		buffer_release(&fh->vidq, fh->vidq.read_buf);
+		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
 		kfree(fh->vidq.read_buf);
 	}
 
 	videobuf_mmap_free(&fh->vidq);
 
-	v4l2_prio_close(&dev->prio, &fh->prio);
+	v4l2_prio_close(&dev->prio, fh->prio);
 	file->private_data = NULL;
 	kfree(fh);
 
@@ -238,7 +238,7 @@
 		return -EINVAL;
 	}
 
-	if (unlikely(!res_get(dev, fh, get_resource(fh, RESOURCE_VIDEO6)))) {
+	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO6)))) {
 		return -EBUSY;
 	}
 
@@ -256,11 +256,11 @@
 	if (i != fh->type)
 		return -EINVAL;
 
-	res = get_resource(fh, RESOURCE_VIDEO6);
+	res = cx25821_get_resource(fh, RESOURCE_VIDEO6);
 	err = videobuf_streamoff(get_queue(fh));
 	if (err < 0)
 		return err;
-	res_free(dev, fh, res);
+	cx25821_res_free(dev, fh, res);
 	return 0;
 }
 
@@ -273,13 +273,13 @@
 	int pix_format = 0;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
 
 	dprintk(2, "%s()\n", __func__);
-	err = vidioc_try_fmt_vid_cap(file, priv, f);
+	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
 
 	if (0 != err)
 		return err;
@@ -288,11 +288,11 @@
 	fh->vidq.field = f->fmt.pix.field;
 
 	// check if width and height is valid based on set standard
-	if (is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
+	if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
 		fh->width = f->fmt.pix.width;
 	}
 
-	if (is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
+	if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
 		fh->height = f->fmt.pix.height;
 	}
 
@@ -363,7 +363,7 @@
 	int err;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
@@ -378,50 +378,50 @@
 	.release = video_release,
 	.read = video_read,
 	.poll = video_poll,
-	.mmap = video_mmap,
+	.mmap = cx25821_video_mmap,
 	.ioctl = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+	.vidioc_querycap = cx25821_vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
 	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = vidioc_reqbufs,
-	.vidioc_querybuf = vidioc_querybuf,
-	.vidioc_qbuf = vidioc_qbuf,
+	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
+	.vidioc_querybuf = cx25821_vidioc_querybuf,
+	.vidioc_qbuf = cx25821_vidioc_qbuf,
 	.vidioc_dqbuf = vidioc_dqbuf,
 #ifdef TUNER_FLAG
-	.vidioc_s_std = vidioc_s_std,
-	.vidioc_querystd = vidioc_querystd,
+	.vidioc_s_std = cx25821_vidioc_s_std,
+	.vidioc_querystd = cx25821_vidioc_querystd,
 #endif
-	.vidioc_cropcap = vidioc_cropcap,
-	.vidioc_s_crop = vidioc_s_crop,
-	.vidioc_g_crop = vidioc_g_crop,
-	.vidioc_enum_input = vidioc_enum_input,
-	.vidioc_g_input = vidioc_g_input,
-	.vidioc_s_input = vidioc_s_input,
-	.vidioc_g_ctrl = vidioc_g_ctrl,
+	.vidioc_cropcap = cx25821_vidioc_cropcap,
+	.vidioc_s_crop = cx25821_vidioc_s_crop,
+	.vidioc_g_crop = cx25821_vidioc_g_crop,
+	.vidioc_enum_input = cx25821_vidioc_enum_input,
+	.vidioc_g_input = cx25821_vidioc_g_input,
+	.vidioc_s_input = cx25821_vidioc_s_input,
+	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
 	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = vidioc_queryctrl,
+	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
 	.vidioc_streamon = vidioc_streamon,
 	.vidioc_streamoff = vidioc_streamoff,
 	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = vidioc_g_priority,
-	.vidioc_s_priority = vidioc_s_priority,
+	.vidioc_g_priority = cx25821_vidioc_g_priority,
+	.vidioc_s_priority = cx25821_vidioc_s_priority,
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = vidiocgmbuf,
+	.vidiocgmbuf = cx25821_vidiocgmbuf,
 #endif
 #ifdef TUNER_FLAG
-	.vidioc_g_tuner = vidioc_g_tuner,
-	.vidioc_s_tuner = vidioc_s_tuner,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
+	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
+	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
+	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
 #endif
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = vidioc_g_register,
-	.vidioc_s_register = vidioc_s_register,
+	.vidioc_g_register = cx25821_vidioc_g_register,
+	.vidioc_s_register = cx25821_vidioc_s_register,
 #endif
 };
 
diff --git a/drivers/staging/cx25821/cx25821-video7.c b/drivers/staging/cx25821/cx25821-video7.c
index 458e525..5e4a769 100644
--- a/drivers/staging/cx25821/cx25821-video7.c
+++ b/drivers/staging/cx25821/cx25821-video7.c
@@ -85,10 +85,10 @@
 }
 
 static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = buffer_setup,
-	.buf_prepare = buffer_prepare,
+	.buf_setup = cx25821_buffer_setup,
+	.buf_prepare = cx25821_buffer_prepare,
 	.buf_queue = buffer_queue,
-	.buf_release = buffer_release,
+	.buf_release = cx25821_buffer_release,
 };
 
 static int video_open(struct file *file)
@@ -146,7 +146,7 @@
 
 	switch (fh->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (res_locked(fh->dev, RESOURCE_VIDEO7))
+		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO7))
 			return -EBUSY;
 
 		return videobuf_read_one(&fh->vidq, data, count, ppos,
@@ -164,7 +164,7 @@
 	struct cx25821_fh *fh = file->private_data;
 	struct cx25821_buffer *buf;
 
-	if (res_check(fh, RESOURCE_VIDEO7)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO7)) {
 		/* streaming capture */
 		if (list_empty(&fh->vidq.stream))
 			return POLLERR;
@@ -206,19 +206,19 @@
 	cx_write(channel7->dma_ctl, 0);	/* FIFO and RISC disable */
 
 	/* stop video capture */
-	if (res_check(fh, RESOURCE_VIDEO7)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO7)) {
 		videobuf_queue_cancel(&fh->vidq);
-		res_free(dev, fh, RESOURCE_VIDEO7);
+		cx25821_res_free(dev, fh, RESOURCE_VIDEO7);
 	}
 
 	if (fh->vidq.read_buf) {
-		buffer_release(&fh->vidq, fh->vidq.read_buf);
+		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
 		kfree(fh->vidq.read_buf);
 	}
 
 	videobuf_mmap_free(&fh->vidq);
 
-	v4l2_prio_close(&dev->prio, &fh->prio);
+	v4l2_prio_close(&dev->prio, fh->prio);
 	file->private_data = NULL;
 	kfree(fh);
 
@@ -238,7 +238,7 @@
 		return -EINVAL;
 	}
 
-	if (unlikely(!res_get(dev, fh, get_resource(fh, RESOURCE_VIDEO7)))) {
+	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO7)))) {
 		return -EBUSY;
 	}
 
@@ -256,11 +256,11 @@
 	if (i != fh->type)
 		return -EINVAL;
 
-	res = get_resource(fh, RESOURCE_VIDEO7);
+	res = cx25821_get_resource(fh, RESOURCE_VIDEO7);
 	err = videobuf_streamoff(get_queue(fh));
 	if (err < 0)
 		return err;
-	res_free(dev, fh, res);
+	cx25821_res_free(dev, fh, res);
 	return 0;
 }
 
@@ -273,13 +273,13 @@
 	int pix_format = 0;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
 
 	dprintk(2, "%s()\n", __func__);
-	err = vidioc_try_fmt_vid_cap(file, priv, f);
+	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
 
 	if (0 != err)
 		return err;
@@ -288,11 +288,11 @@
 	fh->vidq.field = f->fmt.pix.field;
 
 	// check if width and height is valid based on set standard
-	if (is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
+	if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
 		fh->width = f->fmt.pix.width;
 	}
 
-	if (is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
+	if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
 		fh->height = f->fmt.pix.height;
 	}
 
@@ -362,7 +362,7 @@
 	int err;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
@@ -377,50 +377,50 @@
 	.release = video_release,
 	.read = video_read,
 	.poll = video_poll,
-	.mmap = video_mmap,
+	.mmap = cx25821_video_mmap,
 	.ioctl = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+	.vidioc_querycap = cx25821_vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
 	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = vidioc_reqbufs,
-	.vidioc_querybuf = vidioc_querybuf,
-	.vidioc_qbuf = vidioc_qbuf,
+	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
+	.vidioc_querybuf = cx25821_vidioc_querybuf,
+	.vidioc_qbuf = cx25821_vidioc_qbuf,
 	.vidioc_dqbuf = vidioc_dqbuf,
 #ifdef TUNER_FLAG
-	.vidioc_s_std = vidioc_s_std,
-	.vidioc_querystd = vidioc_querystd,
+	.vidioc_s_std = cx25821_vidioc_s_std,
+	.vidioc_querystd = cx25821_vidioc_querystd,
 #endif
-	.vidioc_cropcap = vidioc_cropcap,
-	.vidioc_s_crop = vidioc_s_crop,
-	.vidioc_g_crop = vidioc_g_crop,
-	.vidioc_enum_input = vidioc_enum_input,
-	.vidioc_g_input = vidioc_g_input,
-	.vidioc_s_input = vidioc_s_input,
-	.vidioc_g_ctrl = vidioc_g_ctrl,
+	.vidioc_cropcap = cx25821_vidioc_cropcap,
+	.vidioc_s_crop = cx25821_vidioc_s_crop,
+	.vidioc_g_crop = cx25821_vidioc_g_crop,
+	.vidioc_enum_input = cx25821_vidioc_enum_input,
+	.vidioc_g_input = cx25821_vidioc_g_input,
+	.vidioc_s_input = cx25821_vidioc_s_input,
+	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
 	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = vidioc_queryctrl,
+	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
 	.vidioc_streamon = vidioc_streamon,
 	.vidioc_streamoff = vidioc_streamoff,
 	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = vidioc_g_priority,
-	.vidioc_s_priority = vidioc_s_priority,
+	.vidioc_g_priority = cx25821_vidioc_g_priority,
+	.vidioc_s_priority = cx25821_vidioc_s_priority,
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = vidiocgmbuf,
+	.vidiocgmbuf = cx25821_vidiocgmbuf,
 #endif
 #ifdef TUNER_FLAG
-	.vidioc_g_tuner = vidioc_g_tuner,
-	.vidioc_s_tuner = vidioc_s_tuner,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
+	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
+	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
+	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
 #endif
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = vidioc_g_register,
-	.vidioc_s_register = vidioc_s_register,
+	.vidioc_g_register = cx25821_vidioc_g_register,
+	.vidioc_s_register = cx25821_vidioc_s_register,
 #endif
 };
 
diff --git a/drivers/staging/cx25821/cx25821-videoioctl.c b/drivers/staging/cx25821/cx25821-videoioctl.c
index 1da52b5..d16807d 100644
--- a/drivers/staging/cx25821/cx25821-videoioctl.c
+++ b/drivers/staging/cx25821/cx25821-videoioctl.c
@@ -86,10 +86,10 @@
 }
 
 static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = buffer_setup,
-	.buf_prepare = buffer_prepare,
+	.buf_setup = cx25821_buffer_setup,
+	.buf_prepare = cx25821_buffer_prepare,
 	.buf_queue = buffer_queue,
-	.buf_release = buffer_release,
+	.buf_release = cx25821_buffer_release,
 };
 
 static int video_open(struct file *file)
@@ -145,7 +145,7 @@
 
 	switch (fh->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (res_locked(fh->dev, RESOURCE_VIDEO_IOCTL))
+		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO_IOCTL))
 			return -EBUSY;
 
 		return videobuf_read_one(&fh->vidq, data, count, ppos,
@@ -163,7 +163,7 @@
 	struct cx25821_fh *fh = file->private_data;
 	struct cx25821_buffer *buf;
 
-	if (res_check(fh, RESOURCE_VIDEO_IOCTL)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO_IOCTL)) {
 		/* streaming capture */
 		if (list_empty(&fh->vidq.stream))
 			return POLLERR;
@@ -189,19 +189,19 @@
 	struct cx25821_dev *dev = fh->dev;
 
 	/* stop video capture */
-	if (res_check(fh, RESOURCE_VIDEO_IOCTL)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO_IOCTL)) {
 		videobuf_queue_cancel(&fh->vidq);
-		res_free(dev, fh, RESOURCE_VIDEO_IOCTL);
+		cx25821_res_free(dev, fh, RESOURCE_VIDEO_IOCTL);
 	}
 
 	if (fh->vidq.read_buf) {
-		buffer_release(&fh->vidq, fh->vidq.read_buf);
+		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
 		kfree(fh->vidq.read_buf);
 	}
 
 	videobuf_mmap_free(&fh->vidq);
 
-	v4l2_prio_close(&dev->prio, &fh->prio);
+	v4l2_prio_close(&dev->prio, fh->prio);
 
 	file->private_data = NULL;
 	kfree(fh);
@@ -222,7 +222,7 @@
 		return -EINVAL;
 	}
 
-	if (unlikely(!res_get(dev, fh, get_resource(fh, RESOURCE_VIDEO_IOCTL)))) {
+	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO_IOCTL)))) {
 		return -EBUSY;
 	}
 
@@ -240,11 +240,11 @@
 	if (i != fh->type)
 		return -EINVAL;
 
-	res = get_resource(fh, RESOURCE_VIDEO_IOCTL);
+	res = cx25821_get_resource(fh, RESOURCE_VIDEO_IOCTL);
 	err = videobuf_streamoff(get_queue(fh));
 	if (err < 0)
 		return err;
-	res_free(dev, fh, res);
+	cx25821_res_free(dev, fh, res);
 	return 0;
 }
 
@@ -256,13 +256,13 @@
 	int err;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
 
 	dprintk(2, "%s()\n", __func__);
-	err = vidioc_try_fmt_vid_cap(file, priv, f);
+	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
 
 	if (0 != err)
 		return err;
@@ -409,7 +409,7 @@
 	int err;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
@@ -424,50 +424,50 @@
 	.release = video_release,
 	.read = video_read,
 	.poll = video_poll,
-	.mmap = video_mmap,
+	.mmap = cx25821_video_mmap,
 	.ioctl = video_ioctl_set,
 };
 
 static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+	.vidioc_querycap = cx25821_vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
 	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = vidioc_reqbufs,
-	.vidioc_querybuf = vidioc_querybuf,
-	.vidioc_qbuf = vidioc_qbuf,
+	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
+	.vidioc_querybuf = cx25821_vidioc_querybuf,
+	.vidioc_qbuf = cx25821_vidioc_qbuf,
 	.vidioc_dqbuf = vidioc_dqbuf,
 #ifdef TUNER_FLAG
-	.vidioc_s_std = vidioc_s_std,
-	.vidioc_querystd = vidioc_querystd,
+	.vidioc_s_std = cx25821_vidioc_s_std,
+	.vidioc_querystd = cx25821_vidioc_querystd,
 #endif
-	.vidioc_cropcap = vidioc_cropcap,
-	.vidioc_s_crop = vidioc_s_crop,
-	.vidioc_g_crop = vidioc_g_crop,
-	.vidioc_enum_input = vidioc_enum_input,
-	.vidioc_g_input = vidioc_g_input,
-	.vidioc_s_input = vidioc_s_input,
-	.vidioc_g_ctrl = vidioc_g_ctrl,
+	.vidioc_cropcap = cx25821_vidioc_cropcap,
+	.vidioc_s_crop = cx25821_vidioc_s_crop,
+	.vidioc_g_crop = cx25821_vidioc_g_crop,
+	.vidioc_enum_input = cx25821_vidioc_enum_input,
+	.vidioc_g_input = cx25821_vidioc_g_input,
+	.vidioc_s_input = cx25821_vidioc_s_input,
+	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
 	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = vidioc_queryctrl,
+	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
 	.vidioc_streamon = vidioc_streamon,
 	.vidioc_streamoff = vidioc_streamoff,
 	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = vidioc_g_priority,
-	.vidioc_s_priority = vidioc_s_priority,
+	.vidioc_g_priority = cx25821_vidioc_g_priority,
+	.vidioc_s_priority = cx25821_vidioc_s_priority,
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = vidiocgmbuf,
+	.vidiocgmbuf = cx25821_vidiocgmbuf,
 #endif
 #ifdef TUNER_FLAG
-	.vidioc_g_tuner = vidioc_g_tuner,
-	.vidioc_s_tuner = vidioc_s_tuner,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
+	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
+	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
+	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
 #endif
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = vidioc_g_register,
-	.vidioc_s_register = vidioc_s_register,
+	.vidioc_g_register = cx25821_vidioc_g_register,
+	.vidioc_s_register = cx25821_vidioc_s_register,
 #endif
 };
 
diff --git a/drivers/staging/cx25821/cx25821-vidups10.c b/drivers/staging/cx25821/cx25821-vidups10.c
index b76d9f6..c746a17 100644
--- a/drivers/staging/cx25821/cx25821-vidups10.c
+++ b/drivers/staging/cx25821/cx25821-vidups10.c
@@ -86,10 +86,10 @@
 }
 
 static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = buffer_setup,
-	.buf_prepare = buffer_prepare,
+	.buf_setup = cx25821_buffer_setup,
+	.buf_prepare = cx25821_buffer_prepare,
 	.buf_queue = buffer_queue,
-	.buf_release = buffer_release,
+	.buf_release = cx25821_buffer_release,
 };
 
 static int video_open(struct file *file)
@@ -143,7 +143,7 @@
 
 	switch (fh->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (res_locked(fh->dev, RESOURCE_VIDEO10))
+		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO10))
 			return -EBUSY;
 
 		return videobuf_read_one(&fh->vidq, data, count, ppos,
@@ -161,7 +161,7 @@
 	struct cx25821_fh *fh = file->private_data;
 	struct cx25821_buffer *buf;
 
-	if (res_check(fh, RESOURCE_VIDEO10)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO10)) {
 		/* streaming capture */
 		if (list_empty(&fh->vidq.stream))
 			return POLLERR;
@@ -189,19 +189,19 @@
 	//cx_write(channel10->dma_ctl, 0);
 
 	/* stop video capture */
-	if (res_check(fh, RESOURCE_VIDEO10)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO10)) {
 		videobuf_queue_cancel(&fh->vidq);
-		res_free(dev, fh, RESOURCE_VIDEO10);
+		cx25821_res_free(dev, fh, RESOURCE_VIDEO10);
 	}
 
 	if (fh->vidq.read_buf) {
-		buffer_release(&fh->vidq, fh->vidq.read_buf);
+		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
 		kfree(fh->vidq.read_buf);
 	}
 
 	videobuf_mmap_free(&fh->vidq);
 
-	v4l2_prio_close(&dev->prio, &fh->prio);
+	v4l2_prio_close(&dev->prio, fh->prio);
 
 	file->private_data = NULL;
 	kfree(fh);
@@ -222,7 +222,7 @@
 		return -EINVAL;
 	}
 
-	if (unlikely(!res_get(dev, fh, get_resource(fh, RESOURCE_VIDEO10)))) {
+	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO10)))) {
 		return -EBUSY;
 	}
 
@@ -240,11 +240,11 @@
 	if (i != fh->type)
 		return -EINVAL;
 
-	res = get_resource(fh, RESOURCE_VIDEO10);
+	res = cx25821_get_resource(fh, RESOURCE_VIDEO10);
 	err = videobuf_streamoff(get_queue(fh));
 	if (err < 0)
 		return err;
-	res_free(dev, fh, res);
+	cx25821_res_free(dev, fh, res);
 	return 0;
 }
 
@@ -299,13 +299,13 @@
 	int err;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
 
 	dprintk(2, "%s()\n", __func__);
-	err = vidioc_try_fmt_vid_cap(file, priv, f);
+	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
 
 	if (0 != err)
 		return err;
@@ -347,7 +347,7 @@
 	int err;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
@@ -362,50 +362,50 @@
 	.release = video_release,
 	.read = video_read,
 	.poll = video_poll,
-	.mmap = video_mmap,
+	.mmap = cx25821_video_mmap,
 	.ioctl = video_ioctl_upstream10,
 };
 
 static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+	.vidioc_querycap = cx25821_vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
 	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = vidioc_reqbufs,
-	.vidioc_querybuf = vidioc_querybuf,
-	.vidioc_qbuf = vidioc_qbuf,
+	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
+	.vidioc_querybuf = cx25821_vidioc_querybuf,
+	.vidioc_qbuf = cx25821_vidioc_qbuf,
 	.vidioc_dqbuf = vidioc_dqbuf,
 #ifdef TUNER_FLAG
-	.vidioc_s_std = vidioc_s_std,
-	.vidioc_querystd = vidioc_querystd,
+	.vidioc_s_std = cx25821_vidioc_s_std,
+	.vidioc_querystd = cx25821_vidioc_querystd,
 #endif
-	.vidioc_cropcap = vidioc_cropcap,
-	.vidioc_s_crop = vidioc_s_crop,
-	.vidioc_g_crop = vidioc_g_crop,
-	.vidioc_enum_input = vidioc_enum_input,
-	.vidioc_g_input = vidioc_g_input,
-	.vidioc_s_input = vidioc_s_input,
-	.vidioc_g_ctrl = vidioc_g_ctrl,
+	.vidioc_cropcap = cx25821_vidioc_cropcap,
+	.vidioc_s_crop = cx25821_vidioc_s_crop,
+	.vidioc_g_crop = cx25821_vidioc_g_crop,
+	.vidioc_enum_input = cx25821_vidioc_enum_input,
+	.vidioc_g_input = cx25821_vidioc_g_input,
+	.vidioc_s_input = cx25821_vidioc_s_input,
+	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
 	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = vidioc_queryctrl,
+	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
 	.vidioc_streamon = vidioc_streamon,
 	.vidioc_streamoff = vidioc_streamoff,
 	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = vidioc_g_priority,
-	.vidioc_s_priority = vidioc_s_priority,
+	.vidioc_g_priority = cx25821_vidioc_g_priority,
+	.vidioc_s_priority = cx25821_vidioc_s_priority,
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = vidiocgmbuf,
+	.vidiocgmbuf = cx25821_vidiocgmbuf,
 #endif
 #ifdef TUNER_FLAG
-	.vidioc_g_tuner = vidioc_g_tuner,
-	.vidioc_s_tuner = vidioc_s_tuner,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
+	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
+	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
+	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
 #endif
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = vidioc_g_register,
-	.vidioc_s_register = vidioc_s_register,
+	.vidioc_g_register = cx25821_vidioc_g_register,
+	.vidioc_s_register = cx25821_vidioc_s_register,
 #endif
 };
 
diff --git a/drivers/staging/cx25821/cx25821-vidups9.c b/drivers/staging/cx25821/cx25821-vidups9.c
index 1580da3..466e0f3 100644
--- a/drivers/staging/cx25821/cx25821-vidups9.c
+++ b/drivers/staging/cx25821/cx25821-vidups9.c
@@ -86,10 +86,10 @@
 }
 
 static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = buffer_setup,
-	.buf_prepare = buffer_prepare,
+	.buf_setup = cx25821_buffer_setup,
+	.buf_prepare = cx25821_buffer_prepare,
 	.buf_queue = buffer_queue,
-	.buf_release = buffer_release,
+	.buf_release = cx25821_buffer_release,
 };
 
 static int video_open(struct file *file)
@@ -143,7 +143,7 @@
 
 	switch (fh->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (res_locked(fh->dev, RESOURCE_VIDEO9))
+		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO9))
 			return -EBUSY;
 
 		return videobuf_read_one(&fh->vidq, data, count, ppos,
@@ -161,7 +161,7 @@
 	struct cx25821_fh *fh = file->private_data;
 	struct cx25821_buffer *buf;
 
-	if (res_check(fh, RESOURCE_VIDEO9)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO9)) {
 		/* streaming capture */
 		if (list_empty(&fh->vidq.stream))
 			return POLLERR;
@@ -189,19 +189,19 @@
 	//cx_write(channel9->dma_ctl, 0);
 
 	/* stop video capture */
-	if (res_check(fh, RESOURCE_VIDEO9)) {
+	if (cx25821_res_check(fh, RESOURCE_VIDEO9)) {
 		videobuf_queue_cancel(&fh->vidq);
-		res_free(dev, fh, RESOURCE_VIDEO9);
+		cx25821_res_free(dev, fh, RESOURCE_VIDEO9);
 	}
 
 	if (fh->vidq.read_buf) {
-		buffer_release(&fh->vidq, fh->vidq.read_buf);
+		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
 		kfree(fh->vidq.read_buf);
 	}
 
 	videobuf_mmap_free(&fh->vidq);
 
-	v4l2_prio_close(&dev->prio, &fh->prio);
+	v4l2_prio_close(&dev->prio, fh->prio);
 
 	file->private_data = NULL;
 	kfree(fh);
@@ -222,7 +222,7 @@
 		return -EINVAL;
 	}
 
-	if (unlikely(!res_get(dev, fh, get_resource(fh, RESOURCE_VIDEO9)))) {
+	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO9)))) {
 		return -EBUSY;
 	}
 
@@ -240,11 +240,11 @@
 	if (i != fh->type)
 		return -EINVAL;
 
-	res = get_resource(fh, RESOURCE_VIDEO9);
+	res = cx25821_get_resource(fh, RESOURCE_VIDEO9);
 	err = videobuf_streamoff(get_queue(fh));
 	if (err < 0)
 		return err;
-	res_free(dev, fh, res);
+	cx25821_res_free(dev, fh, res);
 	return 0;
 }
 
@@ -299,13 +299,13 @@
 	int err;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
 
 	dprintk(2, "%s()\n", __func__);
-	err = vidioc_try_fmt_vid_cap(file, priv, f);
+	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
 
 	if (0 != err)
 		return err;
@@ -345,7 +345,7 @@
 	struct cx25821_fh *fh = priv;
 	int err;
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		err = v4l2_prio_check(&dev->prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
@@ -360,50 +360,50 @@
 	.release = video_release,
 	.read = video_read,
 	.poll = video_poll,
-	.mmap = video_mmap,
+	.mmap = cx25821_video_mmap,
 	.ioctl = video_ioctl_upstream9,
 };
 
 static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+	.vidioc_querycap = cx25821_vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
 	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = vidioc_reqbufs,
-	.vidioc_querybuf = vidioc_querybuf,
-	.vidioc_qbuf = vidioc_qbuf,
+	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
+	.vidioc_querybuf = cx25821_vidioc_querybuf,
+	.vidioc_qbuf = cx25821_vidioc_qbuf,
 	.vidioc_dqbuf = vidioc_dqbuf,
 #ifdef TUNER_FLAG
-	.vidioc_s_std = vidioc_s_std,
-	.vidioc_querystd = vidioc_querystd,
+	.vidioc_s_std = cx25821_vidioc_s_std,
+	.vidioc_querystd = cx25821_vidioc_querystd,
 #endif
-	.vidioc_cropcap = vidioc_cropcap,
-	.vidioc_s_crop = vidioc_s_crop,
-	.vidioc_g_crop = vidioc_g_crop,
-	.vidioc_enum_input = vidioc_enum_input,
-	.vidioc_g_input = vidioc_g_input,
-	.vidioc_s_input = vidioc_s_input,
-	.vidioc_g_ctrl = vidioc_g_ctrl,
+	.vidioc_cropcap = cx25821_vidioc_cropcap,
+	.vidioc_s_crop = cx25821_vidioc_s_crop,
+	.vidioc_g_crop = cx25821_vidioc_g_crop,
+	.vidioc_enum_input = cx25821_vidioc_enum_input,
+	.vidioc_g_input = cx25821_vidioc_g_input,
+	.vidioc_s_input = cx25821_vidioc_s_input,
+	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
 	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = vidioc_queryctrl,
+	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
 	.vidioc_streamon = vidioc_streamon,
 	.vidioc_streamoff = vidioc_streamoff,
 	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = vidioc_g_priority,
-	.vidioc_s_priority = vidioc_s_priority,
+	.vidioc_g_priority = cx25821_vidioc_g_priority,
+	.vidioc_s_priority = cx25821_vidioc_s_priority,
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = vidiocgmbuf,
+	.vidiocgmbuf = cx25821_vidiocgmbuf,
 #endif
 #ifdef TUNER_FLAG
-	.vidioc_g_tuner = vidioc_g_tuner,
-	.vidioc_s_tuner = vidioc_s_tuner,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
+	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
+	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
+	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
 #endif
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = vidioc_g_register,
-	.vidioc_s_register = vidioc_s_register,
+	.vidioc_g_register = cx25821_vidioc_g_register,
+	.vidioc_s_register = cx25821_vidioc_s_register,
 #endif
 };
 
diff --git a/drivers/staging/tm6000/Kconfig b/drivers/staging/tm6000/Kconfig
new file mode 100644
index 0000000..5fe759c
--- /dev/null
+++ b/drivers/staging/tm6000/Kconfig
@@ -0,0 +1,32 @@
+config VIDEO_TM6000
+	tristate "TV Master TM5600/6000/6010 driver"
+	depends on VIDEO_DEV && I2C && INPUT && USB && EXPERIMENTAL
+	select VIDEO_TUNER
+	select TUNER_XC2028
+	select VIDEOBUF_VMALLOC
+	help
+	  Support for TM5600/TM6000/TM6010 USB Device
+
+	  Since these cards have no MPEG decoder onboard, they transmit
+	  only compressed MPEG data over the usb bus, so you need
+	  an external software decoder to watch TV on your computer.
+
+	  Say Y if you own such a device and want to use it.
+
+config VIDEO_TM6000_ALSA
+	tristate "TV Master TM5600/6000/6010 audio support"
+	depends on VIDEO_TM6000 && SND && EXPERIMENTAL
+	select SND_PCM
+	---help---
+	  This is a video4linux driver for direct (DMA) audio for
+	  TM5600/TM6000/TM6010 USB Devices.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tm6000-alsa.
+
+config VIDEO_TM6000_DVB
+	bool "DVB Support for tm6000 based TV cards"
+	depends on VIDEO_TM6000 && DVB_CORE && EXPERIMENTAL
+	select DVB_ZL10353
+	---help---
+	  This adds support for DVB cards based on the tm5600/tm6000 chip.
diff --git a/drivers/staging/tm6000/Makefile b/drivers/staging/tm6000/Makefile
new file mode 100644
index 0000000..93370fc
--- /dev/null
+++ b/drivers/staging/tm6000/Makefile
@@ -0,0 +1,17 @@
+tm6000-objs := tm6000-cards.o \
+		   tm6000-core.o  \
+		   tm6000-i2c.o   \
+		   tm6000-video.o \
+		   tm6000-stds.o
+
+ifeq ($(CONFIG_VIDEO_TM6000_DVB),y)
+tm6000-objs += tm6000-dvb.o
+endif
+
+obj-$(CONFIG_VIDEO_TM6000) += tm6000.o
+obj-$(CONFIG_VIDEO_TM6000_ALSA) += tm6000-alsa.o
+
+EXTRA_CFLAGS = -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/staging/tm6000/README b/drivers/staging/tm6000/README
new file mode 100644
index 0000000..c340ebc
--- /dev/null
+++ b/drivers/staging/tm6000/README
@@ -0,0 +1,22 @@
+Todo:
+	- Fix the loss of some blocks when receiving the video URB's
+	- Add a lock at tm6000_read_write_usb() to prevent two simultaneous access to the
+	  URB control transfers
+	- Properly add the locks at tm6000-video
+	- Add audio support
+	- Add vbi support
+	- Add IR support
+	- Do several cleanups
+	- I think that frame1/frame0 are inverted. This causes a funny effect at the image.
+	  the fix is trivial, but require some tests
+	- My tm6010 devices sometimes insist on stop working. I need to turn them off, removing
+	  from my machine and wait for a while for it to work again. I'm starting to think that
+	  it is an overheat issue - is there a workaround that we could do?
+	- Sometimes, tm6010 doesn't read eeprom at the proper time (hardware bug). So, the device
+	  got miss-detected as a "generic" tm6000. This can be really bad if the tuner is the
+	  Low Power one, as it may result on loading the high power firmware, that could damage
+	  the device. Maybe we may read eeprom to double check, when the device is marked as "generic"
+	- Coding Style fixes
+	- sparse cleanups
+
+Please send patches to linux-media@vger.kernel.org
diff --git a/drivers/staging/tm6000/tm6000-alsa.c b/drivers/staging/tm6000/tm6000-alsa.c
new file mode 100644
index 0000000..bc89f9d
--- /dev/null
+++ b/drivers/staging/tm6000/tm6000-alsa.c
@@ -0,0 +1,414 @@
+/*
+ *
+ *  Support for audio capture for tm5600/6000/6010
+ *    (c) 2007-2008 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ *  Based on cx88-alsa.c
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+
+#include <asm/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+
+
+#include "tm6000.h"
+#include "tm6000-regs.h"
+
+#undef dprintk
+
+#define dprintk(level, fmt, arg...) do {				   \
+	if (debug >= level)						   \
+		printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg); \
+	} while (0)
+
+/****************************************************************************
+	Data type declarations - Can be moded to a header file later
+ ****************************************************************************/
+
+struct snd_tm6000_card {
+	struct snd_card            *card;
+
+	spinlock_t                 reg_lock;
+
+	atomic_t		   count;
+
+	unsigned int               period_size;
+	unsigned int               num_periods;
+
+	struct tm6000_core         *core;
+	struct tm6000_buffer       *buf;
+
+	int			   bufsize;
+
+	struct snd_pcm_substream *substream;
+};
+
+
+/****************************************************************************
+			Module global static vars
+ ****************************************************************************/
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;       /* ID for this card */
+static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
+
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable tm6000x soundcard. default enabled.");
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for tm6000x capture interface(s).");
+
+
+/****************************************************************************
+				Module macros
+ ****************************************************************************/
+
+MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Trident,tm5600},"
+			"{{Trident,tm6000},"
+			"{{Trident,tm6010}");
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
+
+/****************************************************************************
+			Module specific funtions
+ ****************************************************************************/
+
+/*
+ * BOARD Specific: Sets audio DMA
+ */
+
+static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip)
+{
+	struct tm6000_core *core = chip->core;
+	int val;
+
+	/* Enables audio */
+	val = tm6000_get_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x0);
+	val |= 0x20;
+	tm6000_set_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
+
+	tm6000_set_reg(core, TM6010_REQ08_R01_A_INIT, 0x80);
+
+	return 0;
+}
+
+/*
+ * BOARD Specific: Resets audio DMA
+ */
+static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip)
+{
+	struct tm6000_core *core = chip->core;
+	int val;
+	dprintk(1, "Stopping audio DMA\n");
+
+	/* Enables audio */
+	val = tm6000_get_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x0);
+	val &= ~0x20;
+	tm6000_set_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
+
+	tm6000_set_reg(core, TM6010_REQ08_R01_A_INIT, 0);
+
+	return 0;
+}
+
+static int dsp_buffer_free(struct snd_tm6000_card *chip)
+{
+	BUG_ON(!chip->bufsize);
+
+	dprintk(2, "Freeing buffer\n");
+
+	/* FIXME: Frees buffer */
+
+	chip->bufsize = 0;
+
+       return 0;
+}
+
+/****************************************************************************
+				ALSA PCM Interface
+ ****************************************************************************/
+
+/*
+ * Digital hardware definition
+ */
+#define DEFAULT_FIFO_SIZE	4096
+
+static struct snd_pcm_hardware snd_tm6000_digital_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_44100 | SNDRV_PCM_RATE_48000,
+	.rate_min =		44100,
+	.rate_max =		48000,
+	.channels_min = 2,
+	.channels_max = 2,
+	.period_bytes_min = DEFAULT_FIFO_SIZE/4,
+	.period_bytes_max = DEFAULT_FIFO_SIZE/4,
+	.periods_min = 1,
+	.periods_max = 1024,
+	.buffer_bytes_max = (1024*1024),
+};
+
+/*
+ * audio pcm capture open callback
+ */
+static int snd_tm6000_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int err;
+
+	err = snd_pcm_hw_constraint_pow2(runtime, 0,
+					 SNDRV_PCM_HW_PARAM_PERIODS);
+	if (err < 0)
+		goto _error;
+
+	chip->substream = substream;
+
+	runtime->hw = snd_tm6000_digital_hw;
+
+	return 0;
+_error:
+	dprintk(1, "Error opening PCM!\n");
+	return err;
+}
+
+/*
+ * audio close callback
+ */
+static int snd_tm6000_close(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+/*
+ * hw_params callback
+ */
+static int snd_tm6000_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *hw_params)
+{
+	struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+	if (substream->runtime->dma_area) {
+		dsp_buffer_free(chip);
+		substream->runtime->dma_area = NULL;
+	}
+
+	chip->period_size = params_period_bytes(hw_params);
+	chip->num_periods = params_periods(hw_params);
+	chip->bufsize = chip->period_size * params_periods(hw_params);
+
+	BUG_ON(!chip->bufsize);
+
+	dprintk(1, "Setting buffer\n");
+
+	/* FIXME: Allocate buffer for audio */
+
+
+	return 0;
+}
+
+/*
+ * hw free callback
+ */
+static int snd_tm6000_hw_free(struct snd_pcm_substream *substream)
+{
+
+	struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+	if (substream->runtime->dma_area) {
+		dsp_buffer_free(chip);
+		substream->runtime->dma_area = NULL;
+	}
+
+	return 0;
+}
+
+/*
+ * prepare callback
+ */
+static int snd_tm6000_prepare(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+
+/*
+ * trigger callback
+ */
+static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+	int err;
+
+	spin_lock(&chip->reg_lock);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		err = _tm6000_start_audio_dma(chip);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		err = _tm6000_stop_audio_dma(chip);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	spin_unlock(&chip->reg_lock);
+
+	return err;
+}
+
+/*
+ * pointer callback
+ */
+static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	u16 count;
+
+	count = atomic_read(&chip->count);
+
+	return runtime->period_size * (count & (runtime->periods-1));
+}
+
+/*
+ * operators
+ */
+static struct snd_pcm_ops snd_tm6000_pcm_ops = {
+	.open = snd_tm6000_pcm_open,
+	.close = snd_tm6000_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = snd_tm6000_hw_params,
+	.hw_free = snd_tm6000_hw_free,
+	.prepare = snd_tm6000_prepare,
+	.trigger = snd_tm6000_card_trigger,
+	.pointer = snd_tm6000_pointer,
+};
+
+/*
+ * create a PCM device
+ */
+static int __devinit snd_tm6000_pcm(struct snd_tm6000_card *chip,
+				    int device, char *name)
+{
+	int err;
+	struct snd_pcm *pcm;
+
+	err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
+	if (err < 0)
+		return err;
+	pcm->private_data = chip;
+	strcpy(pcm->name, name);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
+
+	return 0;
+}
+
+/* FIXME: Control interface - How to control volume/mute? */
+
+/****************************************************************************
+			Basic Flow for Sound Devices
+ ****************************************************************************/
+
+/*
+ * Alsa Constructor - Component probe
+ */
+
+int tm6000_audio_init(struct tm6000_core *dev, int idx)
+{
+	struct snd_card         *card;
+	struct snd_tm6000_card  *chip;
+	int                     rc, len;
+	char                    component[14];
+
+	if (idx >= SNDRV_CARDS)
+		return -ENODEV;
+
+	if (!enable[idx])
+		return -ENOENT;
+
+	rc = snd_card_create(index[idx], id[idx], THIS_MODULE, 0, &card);
+	if (rc < 0) {
+		snd_printk(KERN_ERR "cannot create card instance %d\n", idx);
+		return rc;
+	}
+
+	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	if (!chip) {
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	chip->core = dev;
+	chip->card = card;
+
+	strcpy(card->driver, "tm6000-alsa");
+	sprintf(component, "USB%04x:%04x",
+		le16_to_cpu(dev->udev->descriptor.idVendor),
+		le16_to_cpu(dev->udev->descriptor.idProduct));
+	snd_component_add(card, component);
+
+	if (dev->udev->descriptor.iManufacturer)
+		len = usb_string(dev->udev,
+				 dev->udev->descriptor.iManufacturer,
+				 card->longname, sizeof(card->longname));
+	else
+		len = 0;
+
+	if (len > 0)
+		strlcat(card->longname, " ", sizeof(card->longname));
+
+	strlcat(card->longname, card->shortname, sizeof(card->longname));
+
+	len = strlcat(card->longname, " at ", sizeof(card->longname));
+
+	if (len < sizeof(card->longname))
+		usb_make_path(dev->udev, card->longname + len,
+			      sizeof(card->longname) - len);
+
+	strlcat(card->longname,
+		dev->udev->speed == USB_SPEED_LOW ? ", low speed" :
+		dev->udev->speed == USB_SPEED_FULL ? ", full speed" :
+							   ", high speed",
+		sizeof(card->longname));
+
+	rc = snd_tm6000_pcm(chip, 0, "tm6000 Digital");
+	if (rc < 0)
+		goto error;
+
+	rc = snd_card_register(card);
+	if (rc < 0)
+		goto error;
+
+
+	return 0;
+
+error:
+	snd_card_free(card);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(tm6000_audio_init);
+
diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c
new file mode 100644
index 0000000..6143e20
--- /dev/null
+++ b/drivers/staging/tm6000/tm6000-cards.c
@@ -0,0 +1,973 @@
+/*
+   tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+
+   Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation version 2
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/usb.h>
+#include <linux/version.h>
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+#include <media/tvaudio.h>
+#include <media/i2c-addr.h>
+
+#include "tm6000.h"
+#include "tm6000-regs.h"
+#include "tuner-xc2028.h"
+#include "xc5000.h"
+
+#define TM6000_BOARD_UNKNOWN			0
+#define TM5600_BOARD_GENERIC			1
+#define TM6000_BOARD_GENERIC			2
+#define TM6010_BOARD_GENERIC			3
+#define TM5600_BOARD_10MOONS_UT821		4
+#define TM5600_BOARD_10MOONS_UT330		5
+#define TM6000_BOARD_ADSTECH_DUAL_TV		6
+#define TM6000_BOARD_FREECOM_AND_SIMILAR	7
+#define TM6000_BOARD_ADSTECH_MINI_DUAL_TV	8
+#define TM6010_BOARD_HAUPPAUGE_900H		9
+#define TM6010_BOARD_BEHOLD_WANDER		10
+#define TM6010_BOARD_BEHOLD_VOYAGER		11
+#define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE	12
+#define TM6010_BOARD_TWINHAN_TU501		13
+
+#define TM6000_MAXBOARDS        16
+static unsigned int card[]     = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET };
+
+module_param_array(card,  int, NULL, 0444);
+
+static unsigned long tm6000_devused;
+
+
+struct tm6000_board {
+	char            *name;
+
+	struct tm6000_capabilities caps;
+
+	enum		tm6000_devtype type;	/* variant of the chipset */
+	int             tuner_type;     /* type of the tuner */
+	int             tuner_addr;     /* tuner address */
+	int             demod_addr;     /* demodulator address */
+
+	struct tm6000_gpio gpio;
+};
+
+struct tm6000_board tm6000_boards[] = {
+	[TM6000_BOARD_UNKNOWN] = {
+		.name         = "Unknown tm6000 video grabber",
+		.caps = {
+			.has_tuner    = 1,
+		},
+		.gpio = {
+			.tuner_reset	= TM6000_GPIO_1,
+		},
+	},
+	[TM5600_BOARD_GENERIC] = {
+		.name         = "Generic tm5600 board",
+		.type         = TM5600,
+		.tuner_type   = TUNER_XC2028,
+		.tuner_addr   = 0xc2 >> 1,
+		.caps = {
+			.has_tuner	= 1,
+		},
+		.gpio = {
+			.tuner_reset	= TM6000_GPIO_1,
+		},
+	},
+	[TM6000_BOARD_GENERIC] = {
+		.name         = "Generic tm6000 board",
+		.tuner_type   = TUNER_XC2028,
+		.tuner_addr   = 0xc2 >> 1,
+		.caps = {
+			.has_tuner	= 1,
+			.has_dvb	= 1,
+		},
+		.gpio = {
+			.tuner_reset	= TM6000_GPIO_1,
+		},
+	},
+	[TM6010_BOARD_GENERIC] = {
+		.name         = "Generic tm6010 board",
+		.type         = TM6010,
+		.tuner_type   = TUNER_XC2028,
+		.tuner_addr   = 0xc2 >> 1,
+		.demod_addr   = 0x1e >> 1,
+		.caps = {
+			.has_tuner	= 1,
+			.has_dvb	= 1,
+			.has_zl10353	= 1,
+			.has_eeprom	= 1,
+			.has_remote	= 1,
+		},
+		.gpio = {
+			.tuner_reset	= TM6010_GPIO_2,
+			.tuner_on	= TM6010_GPIO_3,
+			.demod_reset	= TM6010_GPIO_1,
+			.demod_on	= TM6010_GPIO_4,
+			.power_led	= TM6010_GPIO_7,
+			.dvb_led	= TM6010_GPIO_5,
+			.ir		= TM6010_GPIO_0,
+		},
+	},
+	[TM5600_BOARD_10MOONS_UT821] = {
+		.name         = "10Moons UT 821",
+		.tuner_type   = TUNER_XC2028,
+		.type         = TM5600,
+		.tuner_addr   = 0xc2 >> 1,
+		.caps = {
+			.has_tuner    = 1,
+			.has_eeprom   = 1,
+		},
+		.gpio = {
+			.tuner_reset	= TM6000_GPIO_1,
+		},
+	},
+	[TM5600_BOARD_10MOONS_UT330] = {
+		.name         = "10Moons UT 330",
+		.tuner_type   = TUNER_PHILIPS_FQ1216AME_MK4,
+		.tuner_addr   = 0xc8 >> 1,
+		.caps = {
+			.has_tuner    = 1,
+			.has_dvb      = 0,
+			.has_zl10353  = 0,
+			.has_eeprom   = 1,
+		},
+	},
+	[TM6000_BOARD_ADSTECH_DUAL_TV] = {
+		.name         = "ADSTECH Dual TV USB",
+		.tuner_type   = TUNER_XC2028,
+		.tuner_addr   = 0xc8 >> 1,
+		.caps = {
+			.has_tuner    = 1,
+			.has_tda9874  = 1,
+			.has_dvb      = 1,
+			.has_zl10353  = 1,
+			.has_eeprom   = 1,
+		},
+	},
+	[TM6000_BOARD_FREECOM_AND_SIMILAR] = {
+		.name         = "Freecom Hybrid Stick / Moka DVB-T Receiver Dual",
+		.tuner_type   = TUNER_XC2028, /* has a XC3028 */
+		.tuner_addr   = 0xc2 >> 1,
+		.demod_addr   = 0x1e >> 1,
+		.caps = {
+			.has_tuner    = 1,
+			.has_dvb      = 1,
+			.has_zl10353  = 1,
+			.has_eeprom   = 0,
+			.has_remote   = 1,
+		},
+		.gpio = {
+			.tuner_reset	= TM6000_GPIO_4,
+		},
+	},
+	[TM6000_BOARD_ADSTECH_MINI_DUAL_TV] = {
+		.name         = "ADSTECH Mini Dual TV USB",
+		.tuner_type   = TUNER_XC2028, /* has a XC3028 */
+		.tuner_addr   = 0xc8 >> 1,
+		.demod_addr   = 0x1e >> 1,
+		.caps = {
+			.has_tuner    = 1,
+			.has_dvb      = 1,
+			.has_zl10353  = 1,
+			.has_eeprom   = 0,
+		},
+		.gpio = {
+			.tuner_reset	= TM6000_GPIO_4,
+		},
+	},
+	[TM6010_BOARD_HAUPPAUGE_900H] = {
+		.name         = "Hauppauge WinTV HVR-900H / WinTV USB2-Stick",
+		.tuner_type   = TUNER_XC2028, /* has a XC3028 */
+		.tuner_addr   = 0xc2 >> 1,
+		.demod_addr   = 0x1e >> 1,
+		.type         = TM6010,
+		.caps = {
+			.has_tuner    = 1,
+			.has_dvb      = 1,
+			.has_zl10353  = 1,
+			.has_eeprom   = 1,
+			.has_remote   = 1,
+		},
+		.gpio = {
+			.tuner_reset	= TM6010_GPIO_2,
+			.tuner_on	= TM6010_GPIO_3,
+			.demod_reset	= TM6010_GPIO_1,
+			.demod_on	= TM6010_GPIO_4,
+			.power_led	= TM6010_GPIO_7,
+			.dvb_led	= TM6010_GPIO_5,
+			.ir		= TM6010_GPIO_0,
+		},
+	},
+	[TM6010_BOARD_BEHOLD_WANDER] = {
+		.name         = "Beholder Wander DVB-T/TV/FM USB2.0",
+		.tuner_type   = TUNER_XC5000,
+		.tuner_addr   = 0xc2 >> 1,
+		.demod_addr   = 0x1e >> 1,
+		.type         = TM6010,
+		.caps = {
+			.has_tuner    = 1,
+			.has_dvb      = 1,
+			.has_zl10353  = 1,
+			.has_eeprom   = 1,
+			.has_remote   = 1,
+		},
+		.gpio = {
+			.tuner_reset	= TM6010_GPIO_0,
+			.demod_reset	= TM6010_GPIO_1,
+			.power_led	= TM6010_GPIO_6,
+		},
+	},
+	[TM6010_BOARD_BEHOLD_VOYAGER] = {
+		.name         = "Beholder Voyager TV/FM USB2.0",
+		.tuner_type   = TUNER_XC5000,
+		.tuner_addr   = 0xc2 >> 1,
+		.type         = TM6010,
+		.caps = {
+			.has_tuner    = 1,
+			.has_dvb      = 0,
+			.has_zl10353  = 0,
+			.has_eeprom   = 1,
+			.has_remote   = 1,
+		},
+		.gpio = {
+			.tuner_reset	= TM6010_GPIO_0,
+			.power_led	= TM6010_GPIO_6,
+		},
+	},
+	[TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = {
+		.name         = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick",
+		.tuner_type   = TUNER_XC2028, /* has a XC3028 */
+		.tuner_addr   = 0xc2 >> 1,
+		.demod_addr   = 0x1e >> 1,
+		.type         = TM6010,
+		.caps = {
+			.has_tuner    = 1,
+			.has_dvb      = 1,
+			.has_zl10353  = 1,
+			.has_eeprom   = 1,
+			.has_remote   = 1,
+		},
+		.gpio = {
+			.tuner_reset	= TM6010_GPIO_2,
+			.tuner_on	= TM6010_GPIO_3,
+			.demod_reset	= TM6010_GPIO_1,
+			.demod_on	= TM6010_GPIO_4,
+			.power_led	= TM6010_GPIO_7,
+			.dvb_led	= TM6010_GPIO_5,
+			.ir		= TM6010_GPIO_0,
+		},
+	},
+	[TM6010_BOARD_TWINHAN_TU501] = {
+		.name         = "Twinhan TU501(704D1)",
+		.tuner_type   = TUNER_XC2028, /* has a XC3028 */
+		.tuner_addr   = 0xc2 >> 1,
+		.demod_addr   = 0x1e >> 1,
+		.type         = TM6010,
+		.caps = {
+			.has_tuner    = 1,
+			.has_dvb      = 1,
+			.has_zl10353  = 1,
+			.has_eeprom   = 1,
+			.has_remote   = 1,
+		},
+		.gpio = {
+			.tuner_reset	= TM6010_GPIO_2,
+			.tuner_on	= TM6010_GPIO_3,
+			.demod_reset	= TM6010_GPIO_1,
+			.demod_on	= TM6010_GPIO_4,
+			.power_led	= TM6010_GPIO_7,
+			.dvb_led	= TM6010_GPIO_5,
+			.ir		= TM6010_GPIO_0,
+		},
+	}
+};
+
+/* table of devices that work with this driver */
+struct usb_device_id tm6000_id_table[] = {
+	{ USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_10MOONS_UT821 },
+	{ USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC },
+	{ USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV },
+	{ USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR },
+	{ USB_DEVICE(0x06e1, 0xb339), .driver_info = TM6000_BOARD_ADSTECH_MINI_DUAL_TV },
+	{ USB_DEVICE(0x2040, 0x6600), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
+	{ USB_DEVICE(0x2040, 0x6601), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
+	{ USB_DEVICE(0x2040, 0x6610), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
+	{ USB_DEVICE(0x2040, 0x6611), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
+	{ USB_DEVICE(0x6000, 0xdec0), .driver_info = TM6010_BOARD_BEHOLD_WANDER },
+	{ USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER },
+	{ USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
+	{ USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
+	{ USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
+	{ USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
+	{ USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
+	{ USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
+	{ },
+};
+
+/* Tuner callback to provide the proper gpio changes needed for xc5000 */
+int tm6000_xc5000_callback(void *ptr, int component, int command, int arg)
+{
+	int rc = 0;
+	struct tm6000_core *dev = ptr;
+
+	if (dev->tuner_type != TUNER_XC5000)
+		return 0;
+
+	switch (command) {
+	case XC5000_TUNER_RESET:
+		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+			       dev->gpio.tuner_reset, 0x01);
+		msleep(15);
+		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+			       dev->gpio.tuner_reset, 0x00);
+		msleep(15);
+		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+			       dev->gpio.tuner_reset, 0x01);
+		break;
+	}
+	return (rc);
+}
+
+
+/* Tuner callback to provide the proper gpio changes needed for xc2028 */
+
+int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
+{
+	int rc = 0;
+	struct tm6000_core *dev = ptr;
+
+	if (dev->tuner_type != TUNER_XC2028)
+		return 0;
+
+	switch (command) {
+	case XC2028_RESET_CLK:
+		tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
+					0x02, arg);
+		msleep(10);
+		rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+					TM6000_GPIO_CLK, 0);
+		if (rc < 0)
+			return rc;
+		msleep(10);
+		rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+					TM6000_GPIO_CLK, 1);
+		break;
+	case XC2028_TUNER_RESET:
+		/* Reset codes during load firmware */
+		switch (arg) {
+		case 0:
+			/* newer tuner can faster reset */
+			switch (dev->model) {
+			case TM5600_BOARD_10MOONS_UT821:
+				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+					       dev->gpio.tuner_reset, 0x01);
+				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+					       0x300, 0x01);
+				msleep(10);
+				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+					       dev->gpio.tuner_reset, 0x00);
+				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+					       0x300, 0x00);
+				msleep(10);
+				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+					       dev->gpio.tuner_reset, 0x01);
+				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+					       0x300, 0x01);
+				break;
+			case TM6010_BOARD_HAUPPAUGE_900H:
+			case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
+			case TM6010_BOARD_TWINHAN_TU501:
+				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+					       dev->gpio.tuner_reset, 0x01);
+				msleep(60);
+				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+					       dev->gpio.tuner_reset, 0x00);
+				msleep(75);
+				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+					       dev->gpio.tuner_reset, 0x01);
+				msleep(60);
+				break;
+			default:
+				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+					       dev->gpio.tuner_reset, 0x00);
+				msleep(130);
+				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+					       dev->gpio.tuner_reset, 0x01);
+				msleep(130);
+				break;
+			}
+			break;
+		case 1:
+			tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
+						0x02, 0x01);
+			msleep(10);
+			break;
+
+		case 2:
+			rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+						TM6000_GPIO_CLK, 0);
+			if (rc < 0)
+				return rc;
+			msleep(100);
+			rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+						TM6000_GPIO_CLK, 1);
+			msleep(100);
+			break;
+		}
+	}
+	return rc;
+}
+
+int tm6000_cards_setup(struct tm6000_core *dev)
+{
+	int i, rc;
+
+	/*
+	 * Board-specific initialization sequence. Handles all GPIO
+	 * initialization sequences that are board-specific.
+	 * Up to now, all found devices use GPIO1 and GPIO4 at the same way.
+	 * Probably, they're all based on some reference device. Due to that,
+	 * there's a common routine at the end to handle those GPIO's. Devices
+	 * that use different pinups or init sequences can just return at
+	 * the board-specific session.
+	 */
+	switch (dev->model) {
+	case TM6010_BOARD_HAUPPAUGE_900H:
+	case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
+	case TM6010_BOARD_TWINHAN_TU501:
+	case TM6010_BOARD_GENERIC:
+		/* Turn xceive 3028 on */
+		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_on, 0x01);
+		msleep(15);
+		/* Turn zarlink zl10353 on */
+		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
+		msleep(15);
+		/* Reset zarlink zl10353 */
+		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
+		msleep(50);
+		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
+		msleep(15);
+		/* Turn zarlink zl10353 off */
+		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x01);
+		msleep(15);
+		/* ir ? */
+		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.ir, 0x01);
+		msleep(15);
+		/* Power led on (blue) */
+		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00);
+		msleep(15);
+		/* DVB led off (orange) */
+		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.dvb_led, 0x01);
+		msleep(15);
+		/* Turn zarlink zl10353 on */
+		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
+		msleep(15);
+		break;
+	case TM6010_BOARD_BEHOLD_WANDER:
+		/* Power led on (blue) */
+		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
+		msleep(15);
+		/* Reset zarlink zl10353 */
+		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
+		msleep(50);
+		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
+		msleep(15);
+		break;
+	case TM6010_BOARD_BEHOLD_VOYAGER:
+		/* Power led on (blue) */
+		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
+		msleep(15);
+		break;
+	default:
+		break;
+	}
+
+	/*
+	 * Default initialization. Most of the devices seem to use GPIO1
+	 * and GPIO4.on the same way, so, this handles the common sequence
+	 * used by most devices.
+	 * If a device uses a different sequence or different GPIO pins for
+	 * reset, just add the code at the board-specific part
+	 */
+
+	if (dev->gpio.tuner_reset) {
+		for (i = 0; i < 2; i++) {
+			rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+						dev->gpio.tuner_reset, 0x00);
+			if (rc < 0) {
+				printk(KERN_ERR "Error %i doing tuner reset\n", rc);
+				return rc;
+			}
+
+			msleep(10); /* Just to be conservative */
+			rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+						dev->gpio.tuner_reset, 0x01);
+			if (rc < 0) {
+				printk(KERN_ERR "Error %i doing tuner reset\n", rc);
+				return rc;
+			}
+			msleep(10);
+
+			if (!i) {
+				rc = tm6000_get_reg32(dev, REQ_40_GET_VERSION, 0, 0);
+				if (rc >= 0)
+					printk(KERN_DEBUG "board=0x%08x\n", rc);
+			}
+		}
+	} else {
+		printk(KERN_ERR "Tuner reset is not configured\n");
+		return -1;
+	}
+
+	msleep(50);
+
+	return 0;
+};
+
+static void tm6000_config_tuner(struct tm6000_core *dev)
+{
+	struct tuner_setup tun_setup;
+
+	/* Load tuner module */
+	v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+		"tuner", "tuner", dev->tuner_addr, NULL);
+
+	memset(&tun_setup, 0, sizeof(tun_setup));
+	tun_setup.type = dev->tuner_type;
+	tun_setup.addr = dev->tuner_addr;
+
+	tun_setup.mode_mask = 0;
+	if (dev->caps.has_tuner)
+		tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO);
+	if (dev->caps.has_dvb)
+		tun_setup.mode_mask |= T_DIGITAL_TV;
+
+	switch (dev->tuner_type) {
+	case TUNER_XC2028:
+		tun_setup.tuner_callback = tm6000_tuner_callback;;
+		break;
+	case TUNER_XC5000:
+		tun_setup.tuner_callback = tm6000_xc5000_callback;
+		break;
+	}
+
+	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
+
+	switch (dev->tuner_type) {
+	case TUNER_XC2028: {
+		struct v4l2_priv_tun_config xc2028_cfg;
+		struct xc2028_ctrl ctl;
+
+		memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
+		memset(&ctl, 0, sizeof(ctl));
+
+		ctl.input1 = 1;
+		ctl.read_not_reliable = 0;
+		ctl.msleep = 10;
+		ctl.demod = XC3028_FE_ZARLINK456;
+		ctl.vhfbw7 = 1;
+		ctl.uhfbw8 = 1;
+		xc2028_cfg.tuner = TUNER_XC2028;
+		xc2028_cfg.priv  = &ctl;
+
+		switch (dev->model) {
+		case TM6010_BOARD_HAUPPAUGE_900H:
+		case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
+		case TM6010_BOARD_TWINHAN_TU501:
+			ctl.fname = "xc3028L-v36.fw";
+			break;
+		default:
+			if (dev->dev_type == TM6010)
+				ctl.fname = "xc3028-v27.fw";
+			else
+				ctl.fname = "xc3028-v24.fw";
+		}
+
+		printk(KERN_INFO "Setting firmware parameters for xc2028\n");
+		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
+				     &xc2028_cfg);
+
+		}
+		break;
+	case TUNER_XC5000:
+		{
+		struct v4l2_priv_tun_config  xc5000_cfg;
+		struct xc5000_config ctl = {
+			.i2c_address = dev->tuner_addr,
+			.if_khz      = 4570,
+			.radio_input = XC5000_RADIO_FM1,
+			};
+
+		xc5000_cfg.tuner = TUNER_XC5000;
+		xc5000_cfg.priv  = &ctl;
+
+
+		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
+				     &xc5000_cfg);
+		}
+		break;
+	default:
+		printk(KERN_INFO "Unknown tuner type. Tuner is not configured.\n");
+		break;
+	}
+}
+
+static int tm6000_init_dev(struct tm6000_core *dev)
+{
+	struct v4l2_frequency f;
+	int rc = 0;
+
+	mutex_init(&dev->lock);
+
+	mutex_lock(&dev->lock);
+
+	/* Initializa board-specific data */
+	dev->dev_type   = tm6000_boards[dev->model].type;
+	dev->tuner_type = tm6000_boards[dev->model].tuner_type;
+	dev->tuner_addr = tm6000_boards[dev->model].tuner_addr;
+
+	dev->gpio = tm6000_boards[dev->model].gpio;
+
+	dev->demod_addr = tm6000_boards[dev->model].demod_addr;
+
+	dev->caps = tm6000_boards[dev->model].caps;
+
+	/* initialize hardware */
+	rc = tm6000_init(dev);
+	if (rc < 0)
+		goto err;
+
+	rc = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
+	if (rc < 0)
+		goto err;
+
+	/* register i2c bus */
+	rc = tm6000_i2c_register(dev);
+	if (rc < 0)
+		goto err;
+
+	/* Default values for STD and resolutions */
+	dev->width = 720;
+	dev->height = 480;
+	dev->norm = V4L2_STD_PAL_M;
+
+	/* Configure tuner */
+	tm6000_config_tuner(dev);
+
+	/* Set video standard */
+	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
+
+	/* Set tuner frequency - also loads firmware on xc2028/xc3028 */
+	f.tuner = 0;
+	f.type = V4L2_TUNER_ANALOG_TV;
+	f.frequency = 3092;	/* 193.25 MHz */
+	dev->freq = f.frequency;
+	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
+
+	if (dev->caps.has_tda9874)
+		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+			"tvaudio", "tvaudio", I2C_ADDR_TDA9874, NULL);
+
+	/* register and initialize V4L2 */
+	rc = tm6000_v4l2_register(dev);
+	if (rc < 0)
+		goto err;
+
+	if (dev->caps.has_dvb) {
+		dev->dvb = kzalloc(sizeof(*(dev->dvb)), GFP_KERNEL);
+		if (!dev->dvb) {
+			rc = -ENOMEM;
+			goto err2;
+		}
+
+#ifdef CONFIG_VIDEO_TM6000_DVB
+		rc = tm6000_dvb_register(dev);
+		if (rc < 0) {
+			kfree(dev->dvb);
+			dev->dvb = NULL;
+			goto err2;
+		}
+#endif
+	}
+	mutex_unlock(&dev->lock);
+	return 0;
+
+err2:
+	v4l2_device_unregister(&dev->v4l2_dev);
+
+err:
+	mutex_unlock(&dev->lock);
+	return rc;
+}
+
+/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
+#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+
+static void get_max_endpoint(struct usb_device *udev,
+			     struct usb_host_interface *alt,
+			     char *msgtype,
+			     struct usb_host_endpoint *curr_e,
+			     struct tm6000_endpoint *tm_ep)
+{
+	u16 tmp = le16_to_cpu(curr_e->desc.wMaxPacketSize);
+	unsigned int size = tmp & 0x7ff;
+
+	if (udev->speed == USB_SPEED_HIGH)
+		size = size * hb_mult (tmp);
+
+	if (size > tm_ep->maxsize) {
+		tm_ep->endp = curr_e;
+		tm_ep->maxsize = size;
+		tm_ep->bInterfaceNumber = alt->desc.bInterfaceNumber;
+		tm_ep->bAlternateSetting = alt->desc.bAlternateSetting;
+
+		printk(KERN_INFO "tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n",
+					msgtype, curr_e->desc.bEndpointAddress,
+					size);
+	}
+}
+
+/*
+ * tm6000_usb_probe()
+ * checks for supported devices
+ */
+static int tm6000_usb_probe(struct usb_interface *interface,
+			    const struct usb_device_id *id)
+{
+	struct usb_device *usbdev;
+	struct tm6000_core *dev = NULL;
+	int i, rc = 0;
+	int nr = 0;
+	char *speed;
+
+	usbdev = usb_get_dev(interface_to_usbdev(interface));
+
+	/* Selects the proper interface */
+	rc = usb_set_interface(usbdev, 0, 1);
+	if (rc < 0)
+		goto err;
+
+	/* Check to see next free device and mark as used */
+	nr = find_first_zero_bit(&tm6000_devused, TM6000_MAXBOARDS);
+	if (nr >= TM6000_MAXBOARDS) {
+		printk(KERN_ERR "tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS);
+		usb_put_dev(usbdev);
+		return -ENOMEM;
+	}
+
+	/* Create and initialize dev struct */
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (dev == NULL) {
+		printk(KERN_ERR "tm6000" ": out of memory!\n");
+		usb_put_dev(usbdev);
+		return -ENOMEM;
+	}
+	spin_lock_init(&dev->slock);
+
+	/* Increment usage count */
+	tm6000_devused |= 1<<nr;
+	snprintf(dev->name, 29, "tm6000 #%d", nr);
+
+	dev->model = id->driver_info;
+	if ((card[nr] >= 0) && (card[nr] < ARRAY_SIZE(tm6000_boards)))
+		dev->model = card[nr];
+
+	dev->udev = usbdev;
+	dev->devno = nr;
+
+	switch (usbdev->speed) {
+	case USB_SPEED_LOW:
+		speed = "1.5";
+		break;
+	case USB_SPEED_UNKNOWN:
+	case USB_SPEED_FULL:
+		speed = "12";
+		break;
+	case USB_SPEED_HIGH:
+		speed = "480";
+		break;
+	default:
+		speed = "unknown";
+	}
+
+
+
+	/* Get endpoints */
+	for (i = 0; i < interface->num_altsetting; i++) {
+		int ep;
+
+		for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
+			struct usb_host_endpoint	*e;
+			int dir_out;
+
+			e = &interface->altsetting[i].endpoint[ep];
+
+			dir_out = ((e->desc.bEndpointAddress &
+					USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
+
+			printk(KERN_INFO "tm6000: alt %d, interface %i, class %i\n",
+			       i,
+			       interface->altsetting[i].desc.bInterfaceNumber,
+			       interface->altsetting[i].desc.bInterfaceClass);
+
+			switch (e->desc.bmAttributes) {
+			case USB_ENDPOINT_XFER_BULK:
+				if (!dir_out) {
+					get_max_endpoint(usbdev,
+							 &interface->altsetting[i],
+							 "Bulk IN", e,
+							 &dev->bulk_in);
+				} else {
+					get_max_endpoint(usbdev,
+							 &interface->altsetting[i],
+							 "Bulk OUT", e,
+							 &dev->bulk_out);
+				}
+				break;
+			case USB_ENDPOINT_XFER_ISOC:
+				if (!dir_out) {
+					get_max_endpoint(usbdev,
+							 &interface->altsetting[i],
+							 "ISOC IN", e,
+							 &dev->isoc_in);
+				} else {
+					get_max_endpoint(usbdev,
+							 &interface->altsetting[i],
+							 "ISOC OUT", e,
+							 &dev->isoc_out);
+				}
+				break;
+			}
+		}
+	}
+
+
+	printk(KERN_INFO "tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n",
+		speed,
+		le16_to_cpu(dev->udev->descriptor.idVendor),
+		le16_to_cpu(dev->udev->descriptor.idProduct),
+		interface->altsetting->desc.bInterfaceNumber);
+
+/* check if the the device has the iso in endpoint at the correct place */
+	if (!dev->isoc_in.endp) {
+		printk(KERN_ERR "tm6000: probing error: no IN ISOC endpoint!\n");
+		rc = -ENODEV;
+
+		goto err;
+	}
+
+	/* save our data pointer in this interface device */
+	usb_set_intfdata(interface, dev);
+
+	printk(KERN_INFO "tm6000: Found %s\n", tm6000_boards[dev->model].name);
+
+	rc = tm6000_init_dev(dev);
+
+	if (rc < 0)
+		goto err;
+
+	return 0;
+
+err:
+	printk(KERN_ERR "tm6000: Error %d while registering\n", rc);
+
+	tm6000_devused &= ~(1<<nr);
+	usb_put_dev(usbdev);
+
+	kfree(dev);
+	return rc;
+}
+
+/*
+ * tm6000_usb_disconnect()
+ * called when the device gets diconencted
+ * video device will be unregistered on v4l2_close in case it is still open
+ */
+static void tm6000_usb_disconnect(struct usb_interface *interface)
+{
+	struct tm6000_core *dev = usb_get_intfdata(interface);
+	usb_set_intfdata(interface, NULL);
+
+	if (!dev)
+		return;
+
+	printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name);
+
+	mutex_lock(&dev->lock);
+
+#ifdef CONFIG_VIDEO_TM6000_DVB
+	if (dev->dvb) {
+		tm6000_dvb_unregister(dev);
+		kfree(dev->dvb);
+	}
+#endif
+
+	tm6000_v4l2_unregister(dev);
+
+	tm6000_i2c_unregister(dev);
+
+	v4l2_device_unregister(&dev->v4l2_dev);
+
+	dev->state |= DEV_DISCONNECTED;
+
+	usb_put_dev(dev->udev);
+
+	mutex_unlock(&dev->lock);
+	kfree(dev);
+}
+
+static struct usb_driver tm6000_usb_driver = {
+		.name = "tm6000",
+		.probe = tm6000_usb_probe,
+		.disconnect = tm6000_usb_disconnect,
+		.id_table = tm6000_id_table,
+};
+
+static int __init tm6000_module_init(void)
+{
+	int result;
+
+	printk(KERN_INFO "tm6000" " v4l2 driver version %d.%d.%d loaded\n",
+	       (TM6000_VERSION  >> 16) & 0xff,
+	       (TM6000_VERSION  >> 8) & 0xff, TM6000_VERSION  & 0xff);
+
+	/* register this driver with the USB subsystem */
+	result = usb_register(&tm6000_usb_driver);
+	if (result)
+		printk(KERN_ERR "tm6000"
+			   " usb_register failed. Error number %d.\n", result);
+
+	return result;
+}
+
+static void __exit tm6000_module_exit(void)
+{
+	/* deregister at USB subsystem */
+	usb_deregister(&tm6000_usb_driver);
+}
+
+module_init(tm6000_module_init);
+module_exit(tm6000_module_exit);
+
+MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c
new file mode 100644
index 0000000..bfbc53b
--- /dev/null
+++ b/drivers/staging/tm6000/tm6000-core.c
@@ -0,0 +1,602 @@
+/*
+   tm6000-core.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+
+   Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+
+   Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
+       - DVB-T support
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation version 2
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include "tm6000.h"
+#include "tm6000-regs.h"
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+
+#define USB_TIMEOUT	5*HZ /* ms */
+
+int tm6000_read_write_usb (struct tm6000_core *dev, u8 req_type, u8 req,
+			   u16 value, u16 index, u8 *buf, u16 len)
+{
+	int          ret, i;
+	unsigned int pipe;
+	static int   ini=0, last=0, n=0;
+	u8	     *data=NULL;
+
+	if (len)
+		data = kzalloc(len, GFP_KERNEL);
+
+
+	if (req_type & USB_DIR_IN)
+		pipe=usb_rcvctrlpipe(dev->udev, 0);
+	else {
+		pipe=usb_sndctrlpipe(dev->udev, 0);
+		memcpy(data, buf, len);
+	}
+
+	if (tm6000_debug & V4L2_DEBUG_I2C) {
+		if (!ini)
+			last=ini=jiffies;
+
+		printk("%06i (dev %p, pipe %08x): ", n, dev->udev, pipe);
+
+		printk( "%s: %06u ms %06u ms %02x %02x %02x %02x %02x %02x %02x %02x ",
+			(req_type & USB_DIR_IN)?" IN":"OUT",
+			jiffies_to_msecs(jiffies-last),
+			jiffies_to_msecs(jiffies-ini),
+			req_type, req,value&0xff,value>>8, index&0xff, index>>8,
+			len&0xff, len>>8);
+		last=jiffies;
+		n++;
+
+		if ( !(req_type & USB_DIR_IN) ) {
+			printk(">>> ");
+			for (i=0;i<len;i++) {
+				printk(" %02x",buf[i]);
+			}
+		printk("\n");
+		}
+	}
+
+	ret = usb_control_msg(dev->udev, pipe, req, req_type, value, index, data,
+			      len, USB_TIMEOUT);
+
+	if (req_type &  USB_DIR_IN)
+		memcpy(buf, data, len);
+
+	if (tm6000_debug & V4L2_DEBUG_I2C) {
+		if (ret<0) {
+			if (req_type &  USB_DIR_IN)
+				printk("<<< (len=%d)\n",len);
+
+			printk("%s: Error #%d\n", __FUNCTION__, ret);
+		} else if (req_type &  USB_DIR_IN) {
+			printk("<<< ");
+			for (i=0;i<len;i++) {
+				printk(" %02x",buf[i]);
+			}
+			printk("\n");
+		}
+	}
+
+	kfree(data);
+
+	msleep(5);
+
+	return ret;
+}
+
+int tm6000_set_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index)
+{
+	return
+		tm6000_read_write_usb (dev, USB_DIR_OUT | USB_TYPE_VENDOR,
+				       req, value, index, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(tm6000_set_reg);
+
+int tm6000_get_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index)
+{
+	int rc;
+	u8 buf[1];
+
+	rc=tm6000_read_write_usb (dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
+				       value, index, buf, 1);
+
+	if (rc<0)
+		return rc;
+
+	return *buf;
+}
+EXPORT_SYMBOL_GPL(tm6000_get_reg);
+
+int tm6000_get_reg16 (struct tm6000_core *dev, u8 req, u16 value, u16 index)
+{
+	int rc;
+	u8 buf[2];
+
+	rc=tm6000_read_write_usb (dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
+				       value, index, buf, 2);
+
+	if (rc<0)
+		return rc;
+
+	return buf[1]|buf[0]<<8;
+}
+
+int tm6000_get_reg32 (struct tm6000_core *dev, u8 req, u16 value, u16 index)
+{
+	int rc;
+	u8 buf[4];
+
+	rc=tm6000_read_write_usb (dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
+				       value, index, buf, 4);
+
+	if (rc<0)
+		return rc;
+
+	return buf[3] | buf[2] << 8 | buf[1] << 16 | buf[0] << 24;
+}
+
+void tm6000_set_fourcc_format(struct tm6000_core *dev)
+{
+	if (dev->dev_type == TM6010) {
+		int val;
+
+		val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0) & 0xfc;
+		if (dev->fourcc == V4L2_PIX_FMT_UYVY)
+			tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
+		else
+			tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val | 1);
+	} else {
+		if (dev->fourcc == V4L2_PIX_FMT_UYVY)
+			tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0);
+		else
+			tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0x90);
+	}
+}
+
+int tm6000_init_analog_mode (struct tm6000_core *dev)
+{
+	if (dev->dev_type == TM6010) {
+		int val;
+
+		/* Enable video */
+		val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0);
+		val |= 0x60;
+		tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
+		val = tm6000_get_reg(dev,
+			TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0);
+		val &= ~0x40;
+		tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, val);
+
+		/* Init teletext */
+		tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
+		tm6000_set_reg(dev, TM6010_REQ07_R41_TELETEXT_VBI_CODE1, 0x27);
+		tm6000_set_reg(dev, TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55);
+		tm6000_set_reg(dev, TM6010_REQ07_R43_VBI_DATA_TYPE_LINE7, 0x66);
+		tm6000_set_reg(dev, TM6010_REQ07_R44_VBI_DATA_TYPE_LINE8, 0x66);
+		tm6000_set_reg(dev, TM6010_REQ07_R45_VBI_DATA_TYPE_LINE9, 0x66);
+		tm6000_set_reg(dev,
+			TM6010_REQ07_R46_VBI_DATA_TYPE_LINE10, 0x66);
+		tm6000_set_reg(dev,
+			TM6010_REQ07_R47_VBI_DATA_TYPE_LINE11, 0x66);
+		tm6000_set_reg(dev,
+			TM6010_REQ07_R48_VBI_DATA_TYPE_LINE12, 0x66);
+		tm6000_set_reg(dev,
+			TM6010_REQ07_R49_VBI_DATA_TYPE_LINE13, 0x66);
+		tm6000_set_reg(dev,
+			TM6010_REQ07_R4A_VBI_DATA_TYPE_LINE14, 0x66);
+		tm6000_set_reg(dev,
+			TM6010_REQ07_R4B_VBI_DATA_TYPE_LINE15, 0x66);
+		tm6000_set_reg(dev,
+			TM6010_REQ07_R4C_VBI_DATA_TYPE_LINE16, 0x66);
+		tm6000_set_reg(dev,
+			TM6010_REQ07_R4D_VBI_DATA_TYPE_LINE17, 0x66);
+		tm6000_set_reg(dev,
+			TM6010_REQ07_R4E_VBI_DATA_TYPE_LINE18, 0x66);
+		tm6000_set_reg(dev,
+			TM6010_REQ07_R4F_VBI_DATA_TYPE_LINE19, 0x66);
+		tm6000_set_reg(dev,
+			TM6010_REQ07_R50_VBI_DATA_TYPE_LINE20, 0x66);
+		tm6000_set_reg(dev,
+			TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x66);
+		tm6000_set_reg(dev,
+			TM6010_REQ07_R52_VBI_DATA_TYPE_LINE22, 0x66);
+		tm6000_set_reg(dev,
+			TM6010_REQ07_R53_VBI_DATA_TYPE_LINE23, 0x00);
+		tm6000_set_reg(dev,
+			TM6010_REQ07_R54_VBI_DATA_TYPE_RLINES, 0x00);
+		tm6000_set_reg(dev,
+			TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01);
+		tm6000_set_reg(dev,
+			TM6010_REQ07_R56_VBI_LOOP_FILTER_I_GAIN, 0x00);
+		tm6000_set_reg(dev,
+			TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02);
+		tm6000_set_reg(dev, TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35);
+		tm6000_set_reg(dev, TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0);
+		tm6000_set_reg(dev, TM6010_REQ07_R5A_VBI_TELETEXT_DTO1, 0x11);
+		tm6000_set_reg(dev, TM6010_REQ07_R5B_VBI_TELETEXT_DTO0, 0x4c);
+		tm6000_set_reg(dev, TM6010_REQ07_R40_TELETEXT_VBI_CODE0, 0x01);
+		tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00);
+
+
+		/* Init audio */
+		tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
+		tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, 0x04);
+		tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00);
+		tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0xa0);
+		tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, 0x05);
+		tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x06);
+		tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, 0x00);
+		tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, 0x00);
+		tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x08);
+		tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0x91);
+		tm6000_set_reg(dev, TM6010_REQ08_R0B_A_ASD_THRES1, 0x20);
+		tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x12);
+		tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x20);
+		tm6000_set_reg(dev, TM6010_REQ08_R0E_A_MONO_THRES1, 0xf0);
+		tm6000_set_reg(dev, TM6010_REQ08_R0F_A_MONO_THRES2, 0x80);
+		tm6000_set_reg(dev, TM6010_REQ08_R10_A_MUTE_THRES1, 0xc0);
+		tm6000_set_reg(dev, TM6010_REQ08_R11_A_MUTE_THRES2, 0x80);
+		tm6000_set_reg(dev, TM6010_REQ08_R12_A_AGC_U, 0x12);
+		tm6000_set_reg(dev, TM6010_REQ08_R13_A_AGC_ERR_T, 0xfe);
+		tm6000_set_reg(dev, TM6010_REQ08_R14_A_AGC_GAIN_INIT, 0x20);
+		tm6000_set_reg(dev, TM6010_REQ08_R15_A_AGC_STEP_THR, 0x14);
+		tm6000_set_reg(dev, TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe);
+		tm6000_set_reg(dev, TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01);
+		tm6000_set_reg(dev, TM6010_REQ08_R18_A_TR_CTRL, 0xa0);
+		tm6000_set_reg(dev, TM6010_REQ08_R19_A_FH_2FH_GAIN, 0x32);
+		tm6000_set_reg(dev, TM6010_REQ08_R1A_A_NICAM_SER_MAX, 0x64);
+		tm6000_set_reg(dev, TM6010_REQ08_R1B_A_NICAM_SER_MIN, 0x20);
+		tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1c, 0x00);
+		tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1d, 0x00);
+		tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13);
+		tm6000_set_reg(dev, TM6010_REQ08_R1F_A_TEST_INTF_SEL, 0x00);
+		tm6000_set_reg(dev, TM6010_REQ08_R20_A_TEST_PIN_SEL, 0x00);
+		tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3);
+		tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00);
+		tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80);
+
+	} else {
+		/* Enables soft reset */
+		tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
+
+		if (dev->scaler) {
+			tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x20);
+		} else {
+			/* Enable Hfilter and disable TS Drop err */
+			tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x80);
+		}
+
+		tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x88);
+		tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0x23);
+		tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xc0);
+		tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xd8);
+		tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x06);
+		tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0x1f);
+
+		/* AP Software reset */
+		tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08);
+		tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00);
+
+		tm6000_set_fourcc_format(dev);
+
+		/* Disables soft reset */
+		tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00);
+
+		/* E3: Select input 0 - TV tuner */
+		tm6000_set_reg(dev, TM6010_REQ07_RE3_OUT_SEL1, 0x00);
+		tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, 0x60);
+
+		/* This controls input */
+		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_2, 0x0);
+		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_3, 0x01);
+	}
+	msleep(20);
+
+	/* Tuner firmware can now be loaded */
+
+	/*FIXME: Hack!!! */
+	struct v4l2_frequency f;
+	mutex_lock(&dev->lock);
+	f.frequency=dev->freq;
+	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
+	mutex_unlock(&dev->lock);
+
+	msleep(100);
+	tm6000_set_standard (dev, &dev->norm);
+	tm6000_set_audio_bitrate (dev,48000);
+
+	return 0;
+}
+
+int tm6000_init_digital_mode (struct tm6000_core *dev)
+{
+	if (dev->dev_type == TM6010) {
+		int val;
+		u8 buf[2];
+
+		/* digital init */
+		val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0);
+		val &= ~0x60;
+		tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
+		val = tm6000_get_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0);
+		val |= 0x40;
+		tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, val);
+		tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, 0x28);
+		tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xfc);
+		tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0xff);
+		tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe);
+		tm6000_read_write_usb (dev, 0xc0, 0x0e, 0x00c2, 0x0008, buf, 2);
+		printk (KERN_INFO "buf %#x %#x \n", buf[0], buf[1]);
+
+
+	} else  {
+		tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08);
+		tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00);
+		tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
+		tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0x08);
+		tm6000_set_reg(dev, TM6010_REQ07_RE2_OUT_SEL2, 0x0c);
+		tm6000_set_reg(dev, TM6010_REQ07_RE8_TYPESEL_MOS_I2S, 0xff);
+		tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00eb, 0xd8);
+		tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x40);
+		tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0);
+		tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x09);
+		tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0x37);
+		tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xd8);
+		tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xc0);
+		tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x60);
+
+		tm6000_set_reg(dev, TM6010_REQ07_RE2_OUT_SEL2, 0x0c);
+		tm6000_set_reg(dev, TM6010_REQ07_RE8_TYPESEL_MOS_I2S, 0xff);
+		tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00eb, 0x08);
+		msleep(50);
+
+		tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
+		msleep(50);
+		tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01);
+		msleep(50);
+		tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
+		msleep(100);
+	}
+	return 0;
+}
+
+struct reg_init {
+	u8 req;
+	u8 reg;
+	u8 val;
+};
+
+/* The meaning of those initializations are unknown */
+struct reg_init tm6000_init_tab[] = {
+	/* REG  VALUE */
+	{ TM6010_REQ07_RD8_IR_PULSE_CNT0, 0x1f },
+	{ TM6010_REQ07_RFF_SOFT_RESET, 0x08 },
+	{ TM6010_REQ07_RFF_SOFT_RESET, 0x00 },
+	{ TM6010_REQ07_RD5_POWERSAVE, 0x4f },
+	{ TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0x23 },
+	{ TM6010_REQ07_RD8_IR_WAKEUP_ADD, 0x08 },
+	{ TM6010_REQ07_RE2_OUT_SEL2, 0x00 },
+	{ TM6010_REQ07_RE3_OUT_SEL1, 0x10 },
+	{ TM6010_REQ07_RE5_REMOTE_WAKEUP, 0x00 },
+	{ TM6010_REQ07_RE8_TYPESEL_MOS_I2S, 0x00 },
+	{ REQ_07_SET_GET_AVREG,  0xeb, 0x64 },		/* 48000 bits/sample, external input */
+	{ REQ_07_SET_GET_AVREG,  0xee, 0xc2 },
+	{ TM6010_REQ07_R3F_RESET, 0x01 },		/* Start of soft reset */
+	{ TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 },
+	{ TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 },
+	{ TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
+	{ TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 },
+	{ TM6010_REQ07_R05_NOISE_THRESHOLD, 0x64 },
+	{ TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01 },
+	{ TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0x82 },
+	{ TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0x36 },
+	{ TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0x50 },
+	{ TM6010_REQ07_R0C_CHROMA_AGC_CONTROL, 0x6a },
+	{ TM6010_REQ07_R11_AGC_PEAK_CONTROL, 0xc9 },
+	{ TM6010_REQ07_R12_AGC_GATE_STARTH, 0x07 },
+	{ TM6010_REQ07_R13_AGC_GATE_STARTL, 0x3b },
+	{ TM6010_REQ07_R14_AGC_GATE_WIDTH, 0x47 },
+	{ TM6010_REQ07_R15_AGC_BP_DELAY, 0x6f },
+	{ TM6010_REQ07_R17_HLOOP_MAXSTATE, 0xcd },
+	{ TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
+	{ TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b },
+	{ TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 },
+	{ TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 },
+	{ TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
+	{ TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
+	{ TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
+	{ TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
+	{ TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME, 0x3c },
+	{ TM6010_REQ07_R21_HSYNC_PHASE_OFFSET, 0x3c },
+	{ TM6010_REQ07_R2D_CHROMA_BURST_END, 0x48 },
+	{ TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
+	{ TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
+	{ TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
+	{ TM6010_REQ07_R32_VSYNC_HLOCK_MIN, 0x74 },
+	{ TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c },
+	{ TM6010_REQ07_R34_VSYNC_AGC_MIN, 0x74 },
+	{ TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
+	{ TM6010_REQ07_R36_VSYNC_VBI_MIN, 0x7a },
+	{ TM6010_REQ07_R37_VSYNC_VBI_MAX, 0x26 },
+	{ TM6010_REQ07_R38_VSYNC_THRESHOLD, 0x40 },
+	{ TM6010_REQ07_R39_VSYNC_TIME_CONSTANT, 0x0a },
+	{ TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55 },
+	{ TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x11 },
+	{ TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01 },
+	{ TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02 },
+	{ TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35 },
+	{ TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0 },
+	{ TM6010_REQ07_R80_COMB_FILTER_TRESHOLD, 0x15 },
+	{ TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
+	{ TM6010_REQ07_RC1_TRESHOLD, 0xd0 },
+	{ TM6010_REQ07_RC3_HSTART1, 0x88 },
+	{ TM6010_REQ07_R3F_RESET, 0x00 },		/* End of the soft reset */
+	{ TM6010_REQ05_R18_IMASK7, 0x00 },
+};
+
+struct reg_init tm6010_init_tab[] = {
+	{ TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x00 },
+	{ TM6010_REQ07_RC4_HSTART0, 0xa0 },
+	{ TM6010_REQ07_RC6_HEND0, 0x40 },
+	{ TM6010_REQ07_RCA_VEND0, 0x31 },
+	{ TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0xe1 },
+	{ TM6010_REQ07_RE0_DVIDEO_SOURCE, 0x03 },
+	{ TM6010_REQ07_RFE_POWER_DOWN, 0x7f },
+
+	{ TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0 },
+	{ TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4 },
+	{ TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8 },
+	{ TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00 },
+	{ TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2 },
+	{ TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0 },
+	{ TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2 },
+	{ TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60 },
+	{ TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc },
+
+	{ TM6010_REQ07_R3F_RESET, 0x01 },
+	{ TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 },
+	{ TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 },
+	{ TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
+	{ TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 },
+	{ TM6010_REQ07_R05_NOISE_THRESHOLD, 0x64 },
+	{ TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01 },
+	{ TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0x82 },
+	{ TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0x36 },
+	{ TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0x50 },
+	{ TM6010_REQ07_R0C_CHROMA_AGC_CONTROL, 0x6a },
+	{ TM6010_REQ07_R11_AGC_PEAK_CONTROL, 0xc9 },
+	{ TM6010_REQ07_R12_AGC_GATE_STARTH, 0x07 },
+	{ TM6010_REQ07_R13_AGC_GATE_STARTL, 0x3b },
+	{ TM6010_REQ07_R14_AGC_GATE_WIDTH, 0x47 },
+	{ TM6010_REQ07_R15_AGC_BP_DELAY, 0x6f },
+	{ TM6010_REQ07_R17_HLOOP_MAXSTATE, 0xcd },
+	{ TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
+	{ TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b },
+	{ TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 },
+	{ TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 },
+	{ TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
+	{ TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
+	{ TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
+	{ TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
+	{ TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME, 0x3c },
+	{ TM6010_REQ07_R21_HSYNC_PHASE_OFFSET, 0x3c },
+	{ TM6010_REQ07_R2D_CHROMA_BURST_END, 0x48 },
+	{ TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
+	{ TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
+	{ TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
+	{ TM6010_REQ07_R32_VSYNC_HLOCK_MIN, 0x74 },
+	{ TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c },
+	{ TM6010_REQ07_R34_VSYNC_AGC_MIN, 0x74 },
+	{ TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
+	{ TM6010_REQ07_R36_VSYNC_VBI_MIN, 0x7a },
+	{ TM6010_REQ07_R37_VSYNC_VBI_MAX, 0x26 },
+	{ TM6010_REQ07_R38_VSYNC_THRESHOLD, 0x40 },
+	{ TM6010_REQ07_R39_VSYNC_TIME_CONSTANT, 0x0a },
+	{ TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55 },
+	{ TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x11 },
+	{ TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01 },
+	{ TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02 },
+	{ TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35 },
+	{ TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0 },
+	{ TM6010_REQ07_R80_COMB_FILTER_TRESHOLD, 0x15 },
+	{ TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
+	{ TM6010_REQ07_RC1_TRESHOLD, 0xd0 },
+	{ TM6010_REQ07_RC3_HSTART1, 0x88 },
+	{ TM6010_REQ07_R3F_RESET, 0x00 },
+
+	{ TM6010_REQ05_R18_IMASK7, 0x00 },
+
+	{ TM6010_REQ07_RD8_IR_LEADER1, 0xaa },
+	{ TM6010_REQ07_RD8_IR_LEADER0, 0x30 },
+	{ TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20 },
+	{ TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0 },
+	{ REQ_04_EN_DISABLE_MCU_INT, 0x02, 0x00 },
+	{ TM6010_REQ07_RD8_IR, 0x2f },
+
+	/* set remote wakeup key:any key wakeup */
+	{ TM6010_REQ07_RE5_REMOTE_WAKEUP,  0xfe },
+	{ TM6010_REQ07_RD8_IR_WAKEUP_SEL,  0xff },
+};
+
+int tm6000_init (struct tm6000_core *dev)
+{
+	int board, rc=0, i, size;
+	struct reg_init *tab;
+
+	if (dev->dev_type == TM6010) {
+		tab = tm6010_init_tab;
+		size = ARRAY_SIZE(tm6010_init_tab);
+	} else {
+		tab = tm6000_init_tab;
+		size = ARRAY_SIZE(tm6000_init_tab);
+	}
+
+	/* Load board's initialization table */
+	for (i=0; i< size; i++) {
+		rc= tm6000_set_reg (dev, tab[i].req, tab[i].reg, tab[i].val);
+		if (rc<0) {
+			printk (KERN_ERR "Error %i while setting req %d, "
+					 "reg %d to value %d\n", rc,
+					 tab[i].req,tab[i].reg, tab[i].val);
+			return rc;
+		}
+	}
+
+	msleep(5); /* Just to be conservative */
+
+	/* Check board version - maybe 10Moons specific */
+	board=tm6000_get_reg32 (dev, REQ_40_GET_VERSION, 0, 0);
+	if (board >=0) {
+		printk (KERN_INFO "Board version = 0x%08x\n",board);
+	} else {
+		printk (KERN_ERR "Error %i while retrieving board version\n",board);
+	}
+
+	rc = tm6000_cards_setup(dev);
+
+	return rc;
+}
+
+int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate)
+{
+	int val;
+
+	val=tm6000_get_reg (dev, REQ_07_SET_GET_AVREG, 0xeb, 0x0);
+printk("Original value=%d\n",val);
+	if (val<0)
+		return val;
+
+	val &= 0x0f;		/* Preserve the audio input control bits */
+	switch (bitrate) {
+	case 44100:
+		val|=0xd0;
+		dev->audio_bitrate=bitrate;
+		break;
+	case 48000:
+		val|=0x60;
+		dev->audio_bitrate=bitrate;
+		break;
+	}
+	val=tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xeb, val);
+
+	return val;
+}
+EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate);
diff --git a/drivers/staging/tm6000/tm6000-dvb.c b/drivers/staging/tm6000/tm6000-dvb.c
new file mode 100644
index 0000000..eafc89c
--- /dev/null
+++ b/drivers/staging/tm6000/tm6000-dvb.c
@@ -0,0 +1,346 @@
+/*
+   tm6000-dvb.c - dvb-t support for TM5600/TM6000/TM6010 USB video capture devices
+
+   Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation version 2
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/usb.h>
+
+#include "tm6000.h"
+#include "tm6000-regs.h"
+
+#include "zl10353.h"
+
+#include <media/tuner.h>
+
+#include "tuner-xc2028.h"
+
+static void inline print_err_status (struct tm6000_core *dev,
+				     int packet, int status)
+{
+	char *errmsg = "Unknown";
+
+	switch(status) {
+	case -ENOENT:
+		errmsg = "unlinked synchronuously";
+		break;
+	case -ECONNRESET:
+		errmsg = "unlinked asynchronuously";
+		break;
+	case -ENOSR:
+		errmsg = "Buffer error (overrun)";
+		break;
+	case -EPIPE:
+		errmsg = "Stalled (device not responding)";
+		break;
+	case -EOVERFLOW:
+		errmsg = "Babble (bad cable?)";
+		break;
+	case -EPROTO:
+		errmsg = "Bit-stuff error (bad cable?)";
+		break;
+	case -EILSEQ:
+		errmsg = "CRC/Timeout (could be anything)";
+		break;
+	case -ETIME:
+		errmsg = "Device does not respond";
+		break;
+	}
+	if (packet<0) {
+		dprintk(dev, 1, "URB status %d [%s].\n",
+			status, errmsg);
+	} else {
+		dprintk(dev, 1, "URB packet %d, status %d [%s].\n",
+			packet, status, errmsg);
+	}
+}
+
+static void tm6000_urb_received(struct urb *urb)
+{
+	int ret;
+	struct tm6000_core* dev = urb->context;
+
+	if(urb->status != 0) {
+		print_err_status (dev,0,urb->status);
+	}
+	else if(urb->actual_length>0){
+		dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
+						   urb->actual_length);
+	}
+
+	if(dev->dvb->streams > 0) {
+		ret = usb_submit_urb(urb, GFP_ATOMIC);
+		if(ret < 0) {
+			printk(KERN_ERR "tm6000:  error %s\n", __FUNCTION__);
+			kfree(urb->transfer_buffer);
+			usb_free_urb(urb);
+		}
+	}
+}
+
+int tm6000_start_stream(struct tm6000_core *dev)
+{
+	int ret;
+	unsigned int pipe, size;
+	struct tm6000_dvb *dvb = dev->dvb;
+
+	printk(KERN_INFO "tm6000: got start stream request %s\n",__FUNCTION__);
+
+	tm6000_init_digital_mode(dev);
+
+	dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if(dvb->bulk_urb == NULL) {
+		printk(KERN_ERR "tm6000: couldn't allocate urb\n");
+		return -ENOMEM;
+	}
+
+	pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in.endp->desc.bEndpointAddress
+							  & USB_ENDPOINT_NUMBER_MASK);
+
+	size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
+	size = size * 15; /* 512 x 8 or 12 or 15 */
+
+	dvb->bulk_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
+	if(dvb->bulk_urb->transfer_buffer == NULL) {
+		usb_free_urb(dvb->bulk_urb);
+		printk(KERN_ERR "tm6000: couldn't allocate transfer buffer!\n");
+		return -ENOMEM;
+	}
+
+	usb_fill_bulk_urb(dvb->bulk_urb, dev->udev, pipe,
+						 dvb->bulk_urb->transfer_buffer,
+						 size,
+						 tm6000_urb_received, dev);
+
+	ret = usb_clear_halt(dev->udev, pipe);
+	if(ret < 0) {
+		printk(KERN_ERR "tm6000: error %i in %s during pipe reset\n",ret,__FUNCTION__);
+		return ret;
+	}
+	else {
+		printk(KERN_ERR "tm6000: pipe resetted\n");
+	}
+
+/*	mutex_lock(&tm6000_driver.open_close_mutex); */
+	ret = usb_submit_urb(dvb->bulk_urb, GFP_KERNEL);
+
+/*	mutex_unlock(&tm6000_driver.open_close_mutex); */
+	if (ret) {
+		printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n",ret);
+
+		kfree(dvb->bulk_urb->transfer_buffer);
+		usb_free_urb(dvb->bulk_urb);
+		return ret;
+	}
+
+	return 0;
+}
+
+void tm6000_stop_stream(struct tm6000_core *dev)
+{
+	struct tm6000_dvb *dvb = dev->dvb;
+
+	if(dvb->bulk_urb) {
+		printk (KERN_INFO "urb killing\n");
+		usb_kill_urb(dvb->bulk_urb);
+		printk (KERN_INFO "urb buffer free\n");
+		kfree(dvb->bulk_urb->transfer_buffer);
+		usb_free_urb(dvb->bulk_urb);
+		dvb->bulk_urb = NULL;
+	}
+}
+
+int tm6000_start_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct tm6000_core *dev = demux->priv;
+	struct tm6000_dvb *dvb = dev->dvb;
+	printk(KERN_INFO "tm6000: got start feed request %s\n",__FUNCTION__);
+
+	mutex_lock(&dvb->mutex);
+	if(dvb->streams == 0) {
+		dvb->streams = 1;
+/*		mutex_init(&tm6000_dev->streming_mutex); */
+		tm6000_start_stream(dev);
+	}
+	else {
+		++(dvb->streams);
+	}
+	mutex_unlock(&dvb->mutex);
+
+	return 0;
+}
+
+int tm6000_stop_feed(struct dvb_demux_feed *feed) {
+	struct dvb_demux *demux = feed->demux;
+	struct tm6000_core *dev = demux->priv;
+	struct tm6000_dvb *dvb = dev->dvb;
+
+	printk(KERN_INFO "tm6000: got stop feed request %s\n",__FUNCTION__);
+
+	mutex_lock(&dvb->mutex);
+
+	printk (KERN_INFO "stream %#x\n", dvb->streams);
+	--(dvb->streams);
+	if(dvb->streams == 0) {
+		printk (KERN_INFO "stop stream\n");
+		tm6000_stop_stream(dev);
+/*		mutex_destroy(&tm6000_dev->streaming_mutex); */
+	}
+	mutex_unlock(&dvb->mutex);
+/*	mutex_destroy(&tm6000_dev->streaming_mutex); */
+
+	return 0;
+}
+
+int tm6000_dvb_attach_frontend(struct tm6000_core *dev)
+{
+	struct tm6000_dvb *dvb = dev->dvb;
+
+	if(dev->caps.has_zl10353) {
+		struct zl10353_config config =
+				    {.demod_address = dev->demod_addr,
+				     .no_tuner = 1,
+				     .parallel_ts = 1,
+				     .if2 = 45700,
+				     .disable_i2c_gate_ctrl = 1,
+				    };
+
+		dvb->frontend = dvb_attach(zl10353_attach, &config,
+							   &dev->i2c_adap);
+	}
+	else {
+		printk(KERN_ERR "tm6000: no frontend defined for the device!\n");
+		return -1;
+	}
+
+	return (!dvb->frontend) ? -1 : 0;
+}
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+int tm6000_dvb_register(struct tm6000_core *dev)
+{
+	int ret = -1;
+	struct tm6000_dvb *dvb = dev->dvb;
+
+	mutex_init(&dvb->mutex);
+
+	dvb->streams = 0;
+
+	/* attach the frontend */
+	ret = tm6000_dvb_attach_frontend(dev);
+	if(ret < 0) {
+		printk(KERN_ERR "tm6000: couldn't attach the frontend!\n");
+		goto err;
+	}
+
+	ret = dvb_register_adapter(&dvb->adapter, "Trident TVMaster 6000 DVB-T",
+							  THIS_MODULE, &dev->udev->dev, adapter_nr);
+	dvb->adapter.priv = dev;
+
+	if (dvb->frontend) {
+		struct xc2028_config cfg = {
+			.i2c_adap = &dev->i2c_adap,
+			.i2c_addr = dev->tuner_addr,
+		};
+
+		dvb->frontend->callback = tm6000_tuner_callback;
+		ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+		if (ret < 0) {
+			printk(KERN_ERR
+				"tm6000: couldn't register frontend\n");
+			goto adapter_err;
+		}
+
+		if (!dvb_attach(xc2028_attach, dvb->frontend, &cfg)) {
+			printk(KERN_ERR "tm6000: couldn't register "
+					"frontend (xc3028)\n");
+			ret = -EINVAL;
+			goto frontend_err;
+		}
+		printk(KERN_INFO "tm6000: XC2028/3028 asked to be "
+				 "attached to frontend!\n");
+	} else {
+		printk(KERN_ERR "tm6000: no frontend found\n");
+	}
+
+	dvb->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING
+							    | DMX_MEMORY_BASED_FILTERING;
+	dvb->demux.priv = dev;
+	dvb->demux.filternum = 8;
+	dvb->demux.feednum = 8;
+	dvb->demux.start_feed = tm6000_start_feed;
+	dvb->demux.stop_feed = tm6000_stop_feed;
+	dvb->demux.write_to_decoder = NULL;
+	ret = dvb_dmx_init(&dvb->demux);
+	if(ret < 0) {
+		printk("tm6000: dvb_dmx_init failed (errno = %d)\n", ret);
+		goto frontend_err;
+	}
+
+	dvb->dmxdev.filternum = dev->dvb->demux.filternum;
+	dvb->dmxdev.demux = &dev->dvb->demux.dmx;
+	dvb->dmxdev.capabilities = 0;
+
+	ret =  dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
+	if(ret < 0) {
+		printk("tm6000: dvb_dmxdev_init failed (errno = %d)\n", ret);
+		goto dvb_dmx_err;
+	}
+
+	return 0;
+
+dvb_dmx_err:
+	dvb_dmx_release(&dvb->demux);
+frontend_err:
+	if(dvb->frontend) {
+		dvb_frontend_detach(dvb->frontend);
+		dvb_unregister_frontend(dvb->frontend);
+	}
+adapter_err:
+	dvb_unregister_adapter(&dvb->adapter);
+err:
+	return ret;
+}
+
+void tm6000_dvb_unregister(struct tm6000_core *dev)
+{
+	struct tm6000_dvb *dvb = dev->dvb;
+
+	if(dvb->bulk_urb != NULL) {
+		struct urb *bulk_urb = dvb->bulk_urb;
+
+		kfree(bulk_urb->transfer_buffer);
+		bulk_urb->transfer_buffer = NULL;
+		usb_unlink_urb(bulk_urb);
+		usb_free_urb(bulk_urb);
+	}
+
+/*	mutex_lock(&tm6000_driver.open_close_mutex); */
+	if(dvb->frontend) {
+		dvb_frontend_detach(dvb->frontend);
+		dvb_unregister_frontend(dvb->frontend);
+	}
+
+	dvb_dmxdev_release(&dvb->dmxdev);
+	dvb_dmx_release(&dvb->demux);
+	dvb_unregister_adapter(&dvb->adapter);
+	mutex_destroy(&dvb->mutex);
+/*	mutex_unlock(&tm6000_driver.open_close_mutex); */
+
+}
diff --git a/drivers/staging/tm6000/tm6000-i2c.c b/drivers/staging/tm6000/tm6000-i2c.c
new file mode 100644
index 0000000..94ff489
--- /dev/null
+++ b/drivers/staging/tm6000/tm6000-i2c.c
@@ -0,0 +1,370 @@
+/*
+   tm6000-i2c.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+
+   Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+
+   Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
+	- Fix SMBus Read Byte command
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation version 2
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+
+#include "tm6000.h"
+#include "tm6000-regs.h"
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+#include "tuner-xc2028.h"
+
+
+/*FIXME: Hack to avoid needing to patch i2c-id.h */
+#define I2C_HW_B_TM6000 I2C_HW_B_EM28XX
+/* ----------------------------------------------------------- */
+
+static unsigned int i2c_debug = 0;
+module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+
+#define i2c_dprintk(lvl,fmt, args...) if (i2c_debug>=lvl) do{ \
+			printk(KERN_DEBUG "%s at %s: " fmt, \
+			dev->name, __FUNCTION__ , ##args); } while (0)
+
+static int tm6000_i2c_send_regs(struct tm6000_core *dev, unsigned char addr,
+				__u8 reg, char *buf, int len)
+{
+	int rc;
+	unsigned int tsleep;
+	unsigned int i2c_packet_limit = 16;
+
+	if (dev->dev_type == TM6010)
+		i2c_packet_limit = 64;
+
+	if (!buf)
+		return -1;
+
+	if (len < 1 || len > i2c_packet_limit) {
+		printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n",
+			len, i2c_packet_limit);
+		return -1;
+	}
+
+	/* capture mutex */
+	rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
+		USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN,
+		addr | reg << 8, 0, buf, len);
+
+	if (rc < 0) {
+		/* release mutex */
+		return rc;
+	}
+
+	/* Calculate delay time, 14000us for 64 bytes */
+	tsleep = ((len * 200) + 200 + 1000) / 1000;
+	msleep(tsleep);
+
+	/* release mutex */
+	return rc;
+}
+
+/* Generic read - doesn't work fine with 16bit registers */
+static int tm6000_i2c_recv_regs(struct tm6000_core *dev, unsigned char addr,
+				__u8 reg, char *buf, int len)
+{
+	int rc;
+	u8 b[2];
+	unsigned int i2c_packet_limit = 16;
+
+	if (dev->dev_type == TM6010)
+		i2c_packet_limit = 64;
+
+	if (!buf)
+		return -1;
+
+	if (len < 1 || len > i2c_packet_limit) {
+		printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n",
+			len, i2c_packet_limit);
+		return -1;
+	}
+
+	/* capture mutex */
+	if ((dev->caps.has_zl10353) && (dev->demod_addr << 1 == addr) && (reg % 2 == 0)) {
+		/*
+		 * Workaround an I2C bug when reading from zl10353
+		 */
+		reg -= 1;
+		len += 1;
+
+		rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, b, len);
+
+		*buf = b[1];
+	} else {
+		rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, buf, len);
+	}
+
+	/* release mutex */
+	return rc;
+}
+
+/*
+ * read from a 16bit register
+ * for example xc2028, xc3028 or xc3028L
+ */
+static int tm6000_i2c_recv_regs16(struct tm6000_core *dev, unsigned char addr,
+				  __u16 reg, char *buf, int len)
+{
+	int rc;
+	unsigned char ureg;
+
+	if (!buf || len != 2)
+		return -1;
+
+	/* capture mutex */
+	if (dev->dev_type == TM6010) {
+		ureg = reg & 0xFF;
+		rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
+			USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN,
+			addr | (reg & 0xFF00), 0, &ureg, 1);
+
+		if (rc < 0) {
+			/* release mutex */
+			return rc;
+		}
+
+		msleep(1400 / 1000);
+		rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR |
+			USB_RECIP_DEVICE, REQ_35_AFTEK_TUNER_READ,
+			reg, 0, buf, len);
+	} else {
+		rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR |
+			USB_RECIP_DEVICE, REQ_14_SET_GET_I2C_WR2_RDN,
+			addr, reg, buf, len);
+	}
+
+	/* release mutex */
+	return rc;
+}
+
+static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
+			   struct i2c_msg msgs[], int num)
+{
+	struct tm6000_core *dev = i2c_adap->algo_data;
+	int addr, rc, i, byte;
+
+	if (num <= 0)
+		return 0;
+	for (i = 0; i < num; i++) {
+		addr = (msgs[i].addr << 1) & 0xff;
+		i2c_dprintk(2,"%s %s addr=0x%x len=%d:",
+			 (msgs[i].flags & I2C_M_RD) ? "read" : "write",
+			 i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
+		if (msgs[i].flags & I2C_M_RD) {
+			/* read request without preceding register selection */
+			/*
+			 * The TM6000 only supports a read transaction
+			 * immediately after a 1 or 2 byte write to select
+			 * a register.  We cannot fulfil this request.
+			 */
+			i2c_dprintk(2, " read without preceding write not"
+				       " supported");
+			rc = -EOPNOTSUPP;
+			goto err;
+		} else if (i + 1 < num && msgs[i].len <= 2 &&
+			   (msgs[i + 1].flags & I2C_M_RD) &&
+			   msgs[i].addr == msgs[i + 1].addr) {
+			/* 1 or 2 byte write followed by a read */
+			if (i2c_debug >= 2)
+				for (byte = 0; byte < msgs[i].len; byte++)
+					printk(" %02x", msgs[i].buf[byte]);
+			i2c_dprintk(2, "; joined to read %s len=%d:",
+				    i == num - 2 ? "stop" : "nonstop",
+				    msgs[i + 1].len);
+
+			if (msgs[i].len == 2) {
+				rc = tm6000_i2c_recv_regs16(dev, addr,
+					msgs[i].buf[0] << 8 | msgs[i].buf[1],
+					msgs[i + 1].buf, msgs[i + 1].len);
+			} else {
+				rc = tm6000_i2c_recv_regs(dev, addr, msgs[i].buf[0],
+					msgs[i + 1].buf, msgs[i + 1].len);
+			}
+
+			i++;
+
+			if (addr == dev->tuner_addr << 1) {
+				tm6000_set_reg(dev, REQ_50_SET_START, 0, 0);
+				tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0);
+			}
+			if (i2c_debug >= 2)
+				for (byte = 0; byte < msgs[i].len; byte++)
+					printk(" %02x", msgs[i].buf[byte]);
+		} else {
+			/* write bytes */
+			if (i2c_debug >= 2)
+				for (byte = 0; byte < msgs[i].len; byte++)
+					printk(" %02x", msgs[i].buf[byte]);
+			rc = tm6000_i2c_send_regs(dev, addr, msgs[i].buf[0],
+				msgs[i].buf + 1, msgs[i].len - 1);
+
+			if (addr == dev->tuner_addr  << 1) {
+				tm6000_set_reg(dev, REQ_50_SET_START, 0, 0);
+				tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0);
+			}
+		}
+		if (i2c_debug >= 2)
+			printk("\n");
+		if (rc < 0)
+			goto err;
+	}
+
+	return num;
+err:
+	i2c_dprintk(2," ERROR: %i\n", rc);
+	return rc;
+}
+
+static int tm6000_i2c_eeprom(struct tm6000_core *dev,
+			     unsigned char *eedata, int len)
+{
+	int i, rc;
+	unsigned char *p = eedata;
+	unsigned char bytes[17];
+
+	dev->i2c_client.addr = 0xa0 >> 1;
+
+	bytes[16] = '\0';
+	for (i = 0; i < len; ) {
+	*p = i;
+	rc = tm6000_i2c_recv_regs(dev, 0xa0, i, p, 1);
+		if (rc < 1) {
+			if (p == eedata)
+				goto noeeprom;
+			else {
+				printk(KERN_WARNING
+				"%s: i2c eeprom read error (err=%d)\n",
+				dev->name, rc);
+			}
+			return -1;
+		}
+		p++;
+		if (0 == (i % 16))
+			printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
+		printk(" %02x", eedata[i]);
+		if ((eedata[i] >= ' ') && (eedata[i] <= 'z')) {
+			bytes[i%16] = eedata[i];
+		} else {
+			bytes[i%16]='.';
+		}
+
+		i++;
+
+		if (0 == (i % 16)) {
+			bytes[16] = '\0';
+			printk("  %s\n", bytes);
+		}
+	}
+	if (0 != (i%16)) {
+		bytes[i%16] = '\0';
+		for (i %= 16; i < 16; i++)
+			printk("   ");
+	}
+	printk("  %s\n", bytes);
+
+	return 0;
+
+noeeprom:
+	printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
+		       dev->name, rc);
+	return rc;
+}
+
+/* ----------------------------------------------------------- */
+
+/*
+ * functionality()
+ */
+static u32 functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL;
+}
+
+#define mass_write(addr, reg, data...)					\
+	{ const static u8 _val[] = data;				\
+	rc=tm6000_read_write_usb(dev,USB_DIR_OUT | USB_TYPE_VENDOR,	\
+	REQ_16_SET_GET_I2C_WR1_RDN,(reg<<8)+addr, 0x00, (u8 *) _val,	\
+	ARRAY_SIZE(_val));						\
+	if (rc<0) {							\
+		printk(KERN_ERR "Error on line %d: %d\n",__LINE__,rc);	\
+		return rc;						\
+	}								\
+	msleep (10);							\
+	}
+
+static struct i2c_algorithm tm6000_algo = {
+	.master_xfer   = tm6000_i2c_xfer,
+	.functionality = functionality,
+};
+
+static struct i2c_adapter tm6000_adap_template = {
+	.owner = THIS_MODULE,
+	.class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
+	.name = "tm6000",
+	.id = I2C_HW_B_TM6000,
+	.algo = &tm6000_algo,
+};
+
+static struct i2c_client tm6000_client_template = {
+	.name = "tm6000 internal",
+};
+
+/* ----------------------------------------------------------- */
+
+/*
+ * tm6000_i2c_register()
+ * register i2c bus
+ */
+int tm6000_i2c_register(struct tm6000_core *dev)
+{
+	unsigned char eedata[256];
+
+	dev->i2c_adap = tm6000_adap_template;
+	dev->i2c_adap.dev.parent = &dev->udev->dev;
+	strcpy(dev->i2c_adap.name, dev->name);
+	dev->i2c_adap.algo_data = dev;
+	i2c_add_adapter(&dev->i2c_adap);
+
+	dev->i2c_client = tm6000_client_template;
+	dev->i2c_client.adapter = &dev->i2c_adap;
+
+	i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
+
+	tm6000_i2c_eeprom(dev, eedata, sizeof(eedata));
+
+	return 0;
+}
+
+/*
+ * tm6000_i2c_unregister()
+ * unregister i2c_bus
+ */
+int tm6000_i2c_unregister(struct tm6000_core *dev)
+{
+	i2c_del_adapter(&dev->i2c_adap);
+	return 0;
+}
diff --git a/drivers/staging/tm6000/tm6000-regs.h b/drivers/staging/tm6000/tm6000-regs.h
new file mode 100644
index 0000000..1c5289c
--- /dev/null
+++ b/drivers/staging/tm6000/tm6000-regs.h
@@ -0,0 +1,541 @@
+/*
+   tm6000-regs.h - driver for TM5600/TM6000/TM6010 USB video capture devices
+
+   Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation version 2
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Define TV Master TM5600/TM6000/TM6010 Request codes
+ */
+#define REQ_00_SET_IR_VALUE		0
+#define REQ_01_SET_WAKEUP_IRCODE	1
+#define REQ_02_GET_IR_CODE		2
+#define REQ_03_SET_GET_MCU_PIN		3
+#define REQ_04_EN_DISABLE_MCU_INT	4
+#define REQ_05_SET_GET_USBREG		5
+	/* Write: RegNum, Value, 0 */
+	/* Read : RegNum, Value, 1, RegStatus */
+#define REQ_06_SET_GET_USBREG_BIT	6
+#define REQ_07_SET_GET_AVREG		7
+	/* Write: RegNum, Value, 0 */
+	/* Read : RegNum, Value, 1, RegStatus */
+#define REQ_08_SET_GET_AVREG_BIT	8
+#define REQ_09_SET_GET_TUNER_FQ		9
+#define REQ_10_SET_TUNER_SYSTEM		10
+#define REQ_11_SET_EEPROM_ADDR		11
+#define REQ_12_SET_GET_EEPROMBYTE	12
+#define REQ_13_GET_EEPROM_SEQREAD	13
+#define REQ_14_SET_GET_I2C_WR2_RDN	14
+#define REQ_15_SET_GET_I2CBYTE		15
+	/* Write: Subaddr, Slave Addr, value, 0 */
+	/* Read : Subaddr, Slave Addr, value, 1 */
+#define REQ_16_SET_GET_I2C_WR1_RDN	16
+	/* Subaddr, Slave Addr, 0, length */
+#define REQ_17_SET_GET_I2CFP		17
+	/* Write: Slave Addr, register, value */
+	/* Read : Slave Addr, register, 2, data */
+#define REQ_20_DATA_TRANSFER		20
+#define REQ_30_I2C_WRITE		30
+#define REQ_31_I2C_READ			31
+#define REQ_35_AFTEK_TUNER_READ		35
+#define REQ_40_GET_VERSION		40
+#define REQ_50_SET_START		50
+#define REQ_51_SET_STOP			51
+#define REQ_52_TRANSMIT_DATA		52
+#define REQ_53_SPI_INITIAL		53
+#define REQ_54_SPI_SETSTART		54
+#define REQ_55_SPI_INOUTDATA		55
+#define REQ_56_SPI_SETSTOP		56
+
+/*
+ * Define TV Master TM5600/TM6000/TM6010 GPIO lines
+ */
+
+#define TM6000_GPIO_CLK		0x101
+#define TM6000_GPIO_DATA	0x100
+
+#define TM6000_GPIO_1		0x102
+#define TM6000_GPIO_2		0x103
+#define TM6000_GPIO_3		0x104
+#define TM6000_GPIO_4		0x300
+#define TM6000_GPIO_5		0x301
+#define TM6000_GPIO_6		0x304
+#define TM6000_GPIO_7		0x305
+
+/* tm6010 defines GPIO with different values */
+#define TM6010_GPIO_0      0x0102
+#define TM6010_GPIO_1      0x0103
+#define TM6010_GPIO_2      0x0104
+#define TM6010_GPIO_3      0x0105
+#define TM6010_GPIO_4      0x0106
+#define TM6010_GPIO_5      0x0107
+#define TM6010_GPIO_6      0x0300
+#define TM6010_GPIO_7      0x0301
+#define TM6010_GPIO_9      0x0305
+/*
+ * Define TV Master TM5600/TM6000/TM6010 URB message codes and length
+ */
+
+enum {
+	TM6000_URB_MSG_VIDEO=1,
+	TM6000_URB_MSG_AUDIO,
+	TM6000_URB_MSG_VBI,
+	TM6000_URB_MSG_PTS,
+	TM6000_URB_MSG_ERR,
+};
+
+/* Define TM6000/TM6010 Video decoder registers */
+#define TM6010_REQ07_R00_VIDEO_CONTROL0			0x07, 0x00
+#define TM6010_REQ07_R01_VIDEO_CONTROL1			0x07, 0x01
+#define TM6010_REQ07_R02_VIDEO_CONTROL2			0x07, 0x02
+#define TM6010_REQ07_R03_YC_SEP_CONTROL			0x07, 0x03
+#define TM6010_REQ07_R04_LUMA_HAGC_CONTROL		0x07, 0x04
+#define TM6010_REQ07_R05_NOISE_THRESHOLD		0x07, 0x05
+#define TM6010_REQ07_R06_AGC_GATE_THRESHOLD		0x07, 0x06
+#define TM6010_REQ07_R07_OUTPUT_CONTROL			0x07, 0x07
+#define TM6010_REQ07_R08_LUMA_CONTRAST_ADJ		0x07, 0x08
+#define TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ		0x07, 0x09
+#define TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ		0x07, 0x0a
+#define TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ		0x07, 0x0b
+#define TM6010_REQ07_R0C_CHROMA_AGC_CONTROL		0x07, 0x0c
+#define TM6010_REQ07_R0D_CHROMA_KILL_LEVEL		0x07, 0x0d
+#define TM6010_REQ07_R0F_CHROMA_AUTO_POSITION		0x07, 0x0f
+#define TM6010_REQ07_R10_AGC_PEAK_NOMINAL		0x07, 0x10
+#define TM6010_REQ07_R11_AGC_PEAK_CONTROL		0x07, 0x11
+#define TM6010_REQ07_R12_AGC_GATE_STARTH		0x07, 0x12
+#define TM6010_REQ07_R13_AGC_GATE_STARTL		0x07, 0x13
+#define TM6010_REQ07_R14_AGC_GATE_WIDTH			0x07, 0x14
+#define TM6010_REQ07_R15_AGC_BP_DELAY			0x07, 0x15
+#define TM6010_REQ07_R16_LOCK_COUNT			0x07, 0x16
+#define TM6010_REQ07_R17_HLOOP_MAXSTATE			0x07, 0x17
+#define TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3		0x07, 0x18
+#define TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2		0x07, 0x19
+#define TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1		0x07, 0x1a
+#define TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0		0x07, 0x1b
+#define TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3		0x07, 0x1c
+#define TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2		0x07, 0x1d
+#define TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1		0x07, 0x1e
+#define TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0		0x07, 0x1f
+#define TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME		0x07, 0x20
+#define TM6010_REQ07_R21_HSYNC_PHASE_OFFSET		0x07, 0x21
+#define TM6010_REQ07_R22_HSYNC_PLL_START_TIME		0x07, 0x22
+#define TM6010_REQ07_R23_HSYNC_PLL_END_TIME		0x07, 0x23
+#define TM6010_REQ07_R24_HSYNC_TIP_START_TIME		0x07, 0x24
+#define TM6010_REQ07_R25_HSYNC_TIP_END_TIME		0x07, 0x25
+#define TM6010_REQ07_R26_HSYNC_RISING_EDGE_START	0x07, 0x26
+#define TM6010_REQ07_R27_HSYNC_RISING_EDGE_END		0x07, 0x27
+#define TM6010_REQ07_R28_BACKPORCH_START		0x07, 0x28
+#define TM6010_REQ07_R29_BACKPORCH_END			0x07, 0x29
+#define TM6010_REQ07_R2A_HSYNC_FILTER_START		0x07, 0x2a
+#define TM6010_REQ07_R2B_HSYNC_FILTER_END		0x07, 0x2b
+#define TM6010_REQ07_R2C_CHROMA_BURST_START		0x07, 0x2c
+#define TM6010_REQ07_R2D_CHROMA_BURST_END		0x07, 0x2d
+#define TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART		0x07, 0x2e
+#define TM6010_REQ07_R2F_ACTIVE_VIDEO_HWIDTH		0x07, 0x2f
+#define TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART		0x07, 0x30
+#define TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT		0x07, 0x31
+#define TM6010_REQ07_R32_VSYNC_HLOCK_MIN		0x07, 0x32
+#define TM6010_REQ07_R33_VSYNC_HLOCK_MAX		0x07, 0x33
+#define TM6010_REQ07_R34_VSYNC_AGC_MIN			0x07, 0x34
+#define TM6010_REQ07_R35_VSYNC_AGC_MAX			0x07, 0x35
+#define TM6010_REQ07_R36_VSYNC_VBI_MIN			0x07, 0x36
+#define TM6010_REQ07_R37_VSYNC_VBI_MAX			0x07, 0x37
+#define TM6010_REQ07_R38_VSYNC_THRESHOLD		0x07, 0x38
+#define TM6010_REQ07_R39_VSYNC_TIME_CONSTANT		0x07, 0x39
+#define TM6010_REQ07_R3A_STATUS1			0x07, 0x3a
+#define TM6010_REQ07_R3B_STATUS2			0x07, 0x3b
+#define TM6010_REQ07_R3C_STATUS3			0x07, 0x3c
+#define TM6010_REQ07_R3F_RESET				0x07, 0x3f
+#define TM6010_REQ07_R40_TELETEXT_VBI_CODE0		0x07, 0x40
+#define TM6010_REQ07_R41_TELETEXT_VBI_CODE1		0x07, 0x41
+#define TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL		0x07, 0x42
+#define TM6010_REQ07_R43_VBI_DATA_TYPE_LINE7		0x07, 0x43
+#define TM6010_REQ07_R44_VBI_DATA_TYPE_LINE8		0x07, 0x44
+#define TM6010_REQ07_R45_VBI_DATA_TYPE_LINE9		0x07, 0x45
+#define TM6010_REQ07_R46_VBI_DATA_TYPE_LINE10		0x07, 0x46
+#define TM6010_REQ07_R47_VBI_DATA_TYPE_LINE11		0x07, 0x47
+#define TM6010_REQ07_R48_VBI_DATA_TYPE_LINE12		0x07, 0x48
+#define TM6010_REQ07_R49_VBI_DATA_TYPE_LINE13		0x07, 0x49
+#define TM6010_REQ07_R4A_VBI_DATA_TYPE_LINE14		0x07, 0x4a
+#define TM6010_REQ07_R4B_VBI_DATA_TYPE_LINE15		0x07, 0x4b
+#define TM6010_REQ07_R4C_VBI_DATA_TYPE_LINE16		0x07, 0x4c
+#define TM6010_REQ07_R4D_VBI_DATA_TYPE_LINE17		0x07, 0x4d
+#define TM6010_REQ07_R4E_VBI_DATA_TYPE_LINE18		0x07, 0x4e
+#define TM6010_REQ07_R4F_VBI_DATA_TYPE_LINE19		0x07, 0x4f
+#define TM6010_REQ07_R50_VBI_DATA_TYPE_LINE20		0x07, 0x50
+#define TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21		0x07, 0x51
+#define TM6010_REQ07_R52_VBI_DATA_TYPE_LINE22		0x07, 0x52
+#define TM6010_REQ07_R53_VBI_DATA_TYPE_LINE23		0x07, 0x53
+#define TM6010_REQ07_R54_VBI_DATA_TYPE_RLINES		0x07, 0x54
+#define TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN		0x07, 0x55
+#define TM6010_REQ07_R56_VBI_LOOP_FILTER_I_GAIN		0x07, 0x56
+#define TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN		0x07, 0x57
+#define TM6010_REQ07_R58_VBI_CAPTION_DTO1		0x07, 0x58
+#define TM6010_REQ07_R59_VBI_CAPTION_DTO0		0x07, 0x59
+#define TM6010_REQ07_R5A_VBI_TELETEXT_DTO1		0x07, 0x5a
+#define TM6010_REQ07_R5B_VBI_TELETEXT_DTO0		0x07, 0x5b
+#define TM6010_REQ07_R5C_VBI_WSS625_DTO1		0x07, 0x5c
+#define TM6010_REQ07_R5D_VBI_WSS625_DTO0		0x07, 0x5d
+#define TM6010_REQ07_R5E_VBI_CAPTION_FRAME_START	0x07, 0x5e
+#define TM6010_REQ07_R5F_VBI_WSS625_FRAME_START		0x07, 0x5f
+#define TM6010_REQ07_R60_TELETEXT_FRAME_START		0x07, 0x60
+#define TM6010_REQ07_R61_VBI_CCDATA1			0x07, 0x61
+#define TM6010_REQ07_R62_VBI_CCDATA2			0x07, 0x62
+#define TM6010_REQ07_R63_VBI_WSS625_DATA1		0x07, 0x63
+#define TM6010_REQ07_R64_VBI_WSS625_DATA2		0x07, 0x64
+#define TM6010_REQ07_R65_VBI_DATA_STATUS		0x07, 0x65
+#define TM6010_REQ07_R66_VBI_CAPTION_START		0x07, 0x66
+#define TM6010_REQ07_R67_VBI_WSS625_START		0x07, 0x67
+#define TM6010_REQ07_R68_VBI_TELETEXT_START		0x07, 0x68
+#define TM6010_REQ07_R70_HSYNC_DTO_INC_STATUS3		0x07, 0x70
+#define TM6010_REQ07_R71_HSYNC_DTO_INC_STATUS2		0x07, 0x71
+#define TM6010_REQ07_R72_HSYNC_DTO_INC_STATUS1		0x07, 0x72
+#define TM6010_REQ07_R73_HSYNC_DTO_INC_STATUS0		0x07, 0x73
+#define TM6010_REQ07_R74_CHROMA_DTO_INC_STATUS3		0x07, 0x74
+#define TM6010_REQ07_R75_CHROMA_DTO_INC_STATUS2		0x07, 0x75
+#define TM6010_REQ07_R76_CHROMA_DTO_INC_STATUS1		0x07, 0x76
+#define TM6010_REQ07_R77_CHROMA_DTO_INC_STATUS0		0x07, 0x77
+#define TM6010_REQ07_R78_AGC_AGAIN_STATUS		0x07, 0x78
+#define TM6010_REQ07_R79_AGC_DGAIN_STATUS		0x07, 0x79
+#define TM6010_REQ07_R7A_CHROMA_MAG_STATUS		0x07, 0x7a
+#define TM6010_REQ07_R7B_CHROMA_GAIN_STATUS1		0x07, 0x7b
+#define TM6010_REQ07_R7C_CHROMA_GAIN_STATUS0		0x07, 0x7c
+#define TM6010_REQ07_R7D_CORDIC_FREQ_STATUS		0x07, 0x7d
+#define TM6010_REQ07_R7F_STATUS_NOISE			0x07, 0x7f
+#define TM6010_REQ07_R80_COMB_FILTER_TRESHOLD		0x07, 0x80
+#define TM6010_REQ07_R82_COMB_FILTER_CONFIG		0x07, 0x82
+#define TM6010_REQ07_R83_CHROMA_LOCK_CONFIG		0x07, 0x83
+#define TM6010_REQ07_R84_NOISE_NTSC_C			0x07, 0x84
+#define TM6010_REQ07_R85_NOISE_PAL_C			0x07, 0x85
+#define TM6010_REQ07_R86_NOISE_PHASE_C			0x07, 0x86
+#define TM6010_REQ07_R87_NOISE_PHASE_Y			0x07, 0x87
+#define TM6010_REQ07_R8A_CHROMA_LOOPFILTER_STATE	0x07, 0x8a
+#define TM6010_REQ07_R8B_CHROMA_HRESAMPLER		0x07, 0x8b
+#define TM6010_REQ07_R8D_CPUMP_DELAY_ADJ		0x07, 0x8d
+#define TM6010_REQ07_R8E_CPUMP_ADJ			0x07, 0x8e
+#define TM6010_REQ07_R8F_CPUMP_DELAY			0x07, 0x8f
+
+/* Define TM6000/TM6010 Miscellaneous registers */
+#define TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE		0x07, 0xc0
+#define TM6010_REQ07_RC1_TRESHOLD			0x07, 0xc1
+#define TM6010_REQ07_RC2_HSYNC_WIDTH			0x07, 0xc2
+#define TM6010_REQ07_RC3_HSTART1			0x07, 0xc3
+#define TM6010_REQ07_RC4_HSTART0			0x07, 0xc4
+#define TM6010_REQ07_RC5_HEND1				0x07, 0xc5
+#define TM6010_REQ07_RC6_HEND0				0x07, 0xc6
+#define TM6010_REQ07_RC7_VSTART1			0x07, 0xc7
+#define TM6010_REQ07_RC8_VSTART0			0x07, 0xc8
+#define TM6010_REQ07_RC9_VEND1				0x07, 0xc9
+#define TM6010_REQ07_RCA_VEND0				0x07, 0xca
+#define TM6010_REQ07_RCB_DELAY				0x07, 0xcb
+#define TM6010_REQ07_RCC_ACTIVE_VIDEO_IF		0x07, 0xcc
+#define TM6010_REQ07_RD0_USB_PERIPHERY_CONTROL		0x07, 0xd0
+#define TM6010_REQ07_RD1_ADDR_FOR_REQ1			0x07, 0xd1
+#define TM6010_REQ07_RD2_ADDR_FOR_REQ2			0x07, 0xd2
+#define TM6010_REQ07_RD3_ADDR_FOR_REQ3			0x07, 0xd3
+#define TM6010_REQ07_RD4_ADDR_FOR_REQ4			0x07, 0xd4
+#define TM6010_REQ07_RD5_POWERSAVE			0x07, 0xd5
+#define TM6010_REQ07_RD6_ENDP_REQ1_REQ2			0x07, 0xd6
+#define TM6010_REQ07_RD7_ENDP_REQ3_REQ4			0x07, 0xd7
+#define TM6010_REQ07_RD8_IR				0x07, 0xd8
+#define TM6010_REQ07_RD8_IR_BSIZE			0x07, 0xd9
+#define TM6010_REQ07_RD8_IR_WAKEUP_SEL			0x07, 0xda
+#define TM6010_REQ07_RD8_IR_WAKEUP_ADD			0x07, 0xdb
+#define TM6010_REQ07_RD8_IR_LEADER1			0x07, 0xdc
+#define TM6010_REQ07_RD8_IR_LEADER0			0x07, 0xdd
+#define TM6010_REQ07_RD8_IR_PULSE_CNT1			0x07, 0xde
+#define TM6010_REQ07_RD8_IR_PULSE_CNT0			0x07, 0xdf
+#define TM6010_REQ07_RE0_DVIDEO_SOURCE			0x07, 0xe0
+#define TM6010_REQ07_RE0_DVIDEO_SOURCE_IF		0x07, 0xe1
+#define TM6010_REQ07_RE2_OUT_SEL2			0x07, 0xe2
+#define TM6010_REQ07_RE3_OUT_SEL1			0x07, 0xe3
+#define TM6010_REQ07_RE4_OUT_SEL0			0x07, 0xe4
+#define TM6010_REQ07_RE5_REMOTE_WAKEUP			0x07, 0xe5
+#define TM6010_REQ07_RE7_PUB_GPIO			0x07, 0xe7
+#define TM6010_REQ07_RE8_TYPESEL_MOS_I2S		0x07, 0xe8
+#define TM6010_REQ07_RE9_TYPESEL_MOS_TS			0x07, 0xe9
+#define TM6010_REQ07_REA_TYPESEL_MOS_CCIR		0x07, 0xea
+#define TM6010_REQ07_RF0_BIST_CRC_RESULT0		0x07, 0xf0
+#define TM6010_REQ07_RF1_BIST_CRC_RESULT1		0x07, 0xf1
+#define TM6010_REQ07_RF2_BIST_CRC_RESULT2		0x07, 0xf2
+#define TM6010_REQ07_RF3_BIST_CRC_RESULT3		0x07, 0xf3
+#define TM6010_REQ07_RF4_BIST_ERR_VST2			0x07, 0xf4
+#define TM6010_REQ07_RF5_BIST_ERR_VST1			0x07, 0xf5
+#define TM6010_REQ07_RF6_BIST_ERR_VST0			0x07, 0xf6
+#define TM6010_REQ07_RF7_BIST				0x07, 0xf7
+#define TM6010_REQ07_RFE_POWER_DOWN			0x07, 0xfe
+#define TM6010_REQ07_RFF_SOFT_RESET			0x07, 0xff
+
+/* Define TM6000/TM6010 USB registers */
+#define TM6010_REQ05_R00_MAIN_CTRL		0x05, 0x00
+#define TM6010_REQ05_R01_DEVADDR		0x05, 0x01
+#define TM6010_REQ05_R02_TEST			0x05, 0x02
+#define TM6010_REQ05_R04_SOFN0			0x05, 0x04
+#define TM6010_REQ05_R05_SOFN1			0x05, 0x05
+#define TM6010_REQ05_R06_SOFTM0			0x05, 0x06
+#define TM6010_REQ05_R07_SOFTM1			0x05, 0x07
+#define TM6010_REQ05_R08_PHY_TEST		0x05, 0x08
+#define TM6010_REQ05_R09_VCTL			0x05, 0x09
+#define TM6010_REQ05_R0A_VSTA			0x05, 0x0a
+#define TM6010_REQ05_R0B_CX_CFG			0x05, 0x0b
+#define TM6010_REQ05_R0C_ENDP0_REG0		0x05, 0x0c
+#define TM6010_REQ05_R10_GMASK			0x05, 0x10
+#define TM6010_REQ05_R11_IMASK0			0x05, 0x11
+#define TM6010_REQ05_R12_IMASK1			0x05, 0x12
+#define TM6010_REQ05_R13_IMASK2			0x05, 0x13
+#define TM6010_REQ05_R14_IMASK3			0x05, 0x14
+#define TM6010_REQ05_R15_IMASK4			0x05, 0x15
+#define TM6010_REQ05_R16_IMASK5			0x05, 0x16
+#define TM6010_REQ05_R17_IMASK6			0x05, 0x17
+#define TM6010_REQ05_R18_IMASK7			0x05, 0x18
+#define TM6010_REQ05_R19_ZEROP0			0x05, 0x19
+#define TM6010_REQ05_R1A_ZEROP1			0x05, 0x1a
+#define TM6010_REQ05_R1C_FIFO_EMP0		0x05, 0x1c
+#define TM6010_REQ05_R1D_FIFO_EMP1		0x05, 0x1d
+#define TM6010_REQ05_R20_IRQ_GROUP		0x05, 0x20
+#define TM6010_REQ05_R21_IRQ_SOURCE0		0x05, 0x21
+#define TM6010_REQ05_R22_IRQ_SOURCE1		0x05, 0x22
+#define TM6010_REQ05_R23_IRQ_SOURCE2		0x05, 0x23
+#define TM6010_REQ05_R24_IRQ_SOURCE3		0x05, 0x24
+#define TM6010_REQ05_R25_IRQ_SOURCE4		0x05, 0x25
+#define TM6010_REQ05_R26_IRQ_SOURCE5		0x05, 0x26
+#define TM6010_REQ05_R27_IRQ_SOURCE6		0x05, 0x27
+#define TM6010_REQ05_R28_IRQ_SOURCE7		0x05, 0x28
+#define TM6010_REQ05_R29_SEQ_ERR0		0x05, 0x29
+#define TM6010_REQ05_R2A_SEQ_ERR1		0x05, 0x2a
+#define TM6010_REQ05_R2B_SEQ_ABORT0		0x05, 0x2b
+#define TM6010_REQ05_R2C_SEQ_ABORT1		0x05, 0x2c
+#define TM6010_REQ05_R2D_TX_ZERO0		0x05, 0x2d
+#define TM6010_REQ05_R2E_TX_ZERO1		0x05, 0x2e
+#define TM6010_REQ05_R2F_IDLE_CNT		0x05, 0x2f
+#define TM6010_REQ05_R30_FNO_P1			0x05, 0x30
+#define TM6010_REQ05_R31_FNO_P2			0x05, 0x31
+#define TM6010_REQ05_R32_FNO_P3			0x05, 0x32
+#define TM6010_REQ05_R33_FNO_P4			0x05, 0x33
+#define TM6010_REQ05_R34_FNO_P5			0x05, 0x34
+#define TM6010_REQ05_R35_FNO_P6			0x05, 0x35
+#define TM6010_REQ05_R36_FNO_P7			0x05, 0x36
+#define TM6010_REQ05_R37_FNO_P8			0x05, 0x37
+#define TM6010_REQ05_R38_FNO_P9			0x05, 0x38
+#define TM6010_REQ05_R30_FNO_P10		0x05, 0x39
+#define TM6010_REQ05_R30_FNO_P11		0x05, 0x3a
+#define TM6010_REQ05_R30_FNO_P12		0x05, 0x3b
+#define TM6010_REQ05_R30_FNO_P13		0x05, 0x3c
+#define TM6010_REQ05_R30_FNO_P14		0x05, 0x3d
+#define TM6010_REQ05_R30_FNO_P15		0x05, 0x3e
+#define TM6010_REQ05_R40_IN_MAXPS_LOW1		0x05, 0x40
+#define TM6010_REQ05_R41_IN_MAXPS_HIGH1		0x05, 0x41
+#define TM6010_REQ05_R42_IN_MAXPS_LOW2		0x05, 0x42
+#define TM6010_REQ05_R43_IN_MAXPS_HIGH2		0x05, 0x43
+#define TM6010_REQ05_R44_IN_MAXPS_LOW3		0x05, 0x44
+#define TM6010_REQ05_R45_IN_MAXPS_HIGH3		0x05, 0x45
+#define TM6010_REQ05_R46_IN_MAXPS_LOW4		0x05, 0x46
+#define TM6010_REQ05_R47_IN_MAXPS_HIGH4		0x05, 0x47
+#define TM6010_REQ05_R48_IN_MAXPS_LOW5		0x05, 0x48
+#define TM6010_REQ05_R49_IN_MAXPS_HIGH5		0x05, 0x49
+#define TM6010_REQ05_R4A_IN_MAXPS_LOW6		0x05, 0x4a
+#define TM6010_REQ05_R4B_IN_MAXPS_HIGH6		0x05, 0x4b
+#define TM6010_REQ05_R4C_IN_MAXPS_LOW7		0x05, 0x4c
+#define TM6010_REQ05_R4D_IN_MAXPS_HIGH7		0x05, 0x4d
+#define TM6010_REQ05_R4E_IN_MAXPS_LOW8		0x05, 0x4e
+#define TM6010_REQ05_R4F_IN_MAXPS_HIGH8		0x05, 0x4f
+#define TM6010_REQ05_R50_IN_MAXPS_LOW9		0x05, 0x50
+#define TM6010_REQ05_R51_IN_MAXPS_HIGH9		0x05, 0x51
+#define TM6010_REQ05_R40_IN_MAXPS_LOW10		0x05, 0x52
+#define TM6010_REQ05_R41_IN_MAXPS_HIGH10	0x05, 0x53
+#define TM6010_REQ05_R40_IN_MAXPS_LOW11		0x05, 0x54
+#define TM6010_REQ05_R41_IN_MAXPS_HIGH11	0x05, 0x55
+#define TM6010_REQ05_R40_IN_MAXPS_LOW12		0x05, 0x56
+#define TM6010_REQ05_R41_IN_MAXPS_HIGH12	0x05, 0x57
+#define TM6010_REQ05_R40_IN_MAXPS_LOW13		0x05, 0x58
+#define TM6010_REQ05_R41_IN_MAXPS_HIGH13	0x05, 0x59
+#define TM6010_REQ05_R40_IN_MAXPS_LOW14		0x05, 0x5a
+#define TM6010_REQ05_R41_IN_MAXPS_HIGH14	0x05, 0x5b
+#define TM6010_REQ05_R40_IN_MAXPS_LOW15		0x05, 0x5c
+#define TM6010_REQ05_R41_IN_MAXPS_HIGH15	0x05, 0x5d
+#define TM6010_REQ05_R60_OUT_MAXPS_LOW1		0x05, 0x60
+#define TM6010_REQ05_R61_OUT_MAXPS_HIGH1	0x05, 0x61
+#define TM6010_REQ05_R62_OUT_MAXPS_LOW2		0x05, 0x62
+#define TM6010_REQ05_R63_OUT_MAXPS_HIGH2	0x05, 0x63
+#define TM6010_REQ05_R64_OUT_MAXPS_LOW3		0x05, 0x64
+#define TM6010_REQ05_R65_OUT_MAXPS_HIGH3	0x05, 0x65
+#define TM6010_REQ05_R66_OUT_MAXPS_LOW4		0x05, 0x66
+#define TM6010_REQ05_R67_OUT_MAXPS_HIGH4	0x05, 0x67
+#define TM6010_REQ05_R68_OUT_MAXPS_LOW5		0x05, 0x68
+#define TM6010_REQ05_R69_OUT_MAXPS_HIGH5	0x05, 0x69
+#define TM6010_REQ05_R6A_OUT_MAXPS_LOW6		0x05, 0x6a
+#define TM6010_REQ05_R6B_OUT_MAXPS_HIGH6	0x05, 0x6b
+#define TM6010_REQ05_R6C_OUT_MAXPS_LOW7		0x05, 0x6c
+#define TM6010_REQ05_R6D_OUT_MAXPS_HIGH7	0x05, 0x6d
+#define TM6010_REQ05_R6E_OUT_MAXPS_LOW8		0x05, 0x6e
+#define TM6010_REQ05_R6F_OUT_MAXPS_HIGH8	0x05, 0x6f
+#define TM6010_REQ05_R70_OUT_MAXPS_LOW9		0x05, 0x70
+#define TM6010_REQ05_R71_OUT_MAXPS_HIGH9	0x05, 0x71
+#define TM6010_REQ05_R60_OUT_MAXPS_LOW10	0x05, 0x72
+#define TM6010_REQ05_R61_OUT_MAXPS_HIGH10	0x05, 0x73
+#define TM6010_REQ05_R60_OUT_MAXPS_LOW11	0x05, 0x74
+#define TM6010_REQ05_R61_OUT_MAXPS_HIGH11	0x05, 0x75
+#define TM6010_REQ05_R60_OUT_MAXPS_LOW12	0x05, 0x76
+#define TM6010_REQ05_R61_OUT_MAXPS_HIGH12	0x05, 0x77
+#define TM6010_REQ05_R60_OUT_MAXPS_LOW13	0x05, 0x78
+#define TM6010_REQ05_R61_OUT_MAXPS_HIGH13	0x05, 0x79
+#define TM6010_REQ05_R60_OUT_MAXPS_LOW14	0x05, 0x7a
+#define TM6010_REQ05_R61_OUT_MAXPS_HIGH14	0x05, 0x7b
+#define TM6010_REQ05_R60_OUT_MAXPS_LOW15	0x05, 0x7c
+#define TM6010_REQ05_R61_OUT_MAXPS_HIGH15	0x05, 0x7d
+#define TM6010_REQ05_R80_FIFO0			0x05, 0x80
+#define TM6010_REQ05_R81_FIFO1			0x05, 0x81
+#define TM6010_REQ05_R82_FIFO2			0x05, 0x82
+#define TM6010_REQ05_R83_FIFO3			0x05, 0x83
+#define TM6010_REQ05_R84_FIFO4			0x05, 0x84
+#define TM6010_REQ05_R85_FIFO5			0x05, 0x85
+#define TM6010_REQ05_R86_FIFO6			0x05, 0x86
+#define TM6010_REQ05_R87_FIFO7			0x05, 0x87
+#define TM6010_REQ05_R88_FIFO8			0x05, 0x88
+#define TM6010_REQ05_R89_FIFO9			0x05, 0x89
+#define TM6010_REQ05_R81_FIFO10			0x05, 0x8a
+#define TM6010_REQ05_R81_FIFO11			0x05, 0x8b
+#define TM6010_REQ05_R81_FIFO12			0x05, 0x8c
+#define TM6010_REQ05_R81_FIFO13			0x05, 0x8d
+#define TM6010_REQ05_R81_FIFO14			0x05, 0x8e
+#define TM6010_REQ05_R81_FIFO15			0x05, 0x8f
+#define TM6010_REQ05_R90_CFG_FIFO0		0x05, 0x90
+#define TM6010_REQ05_R91_CFG_FIFO1		0x05, 0x91
+#define TM6010_REQ05_R92_CFG_FIFO2		0x05, 0x92
+#define TM6010_REQ05_R93_CFG_FIFO3		0x05, 0x93
+#define TM6010_REQ05_R94_CFG_FIFO4		0x05, 0x94
+#define TM6010_REQ05_R95_CFG_FIFO5		0x05, 0x95
+#define TM6010_REQ05_R96_CFG_FIFO6		0x05, 0x96
+#define TM6010_REQ05_R97_CFG_FIFO7		0x05, 0x97
+#define TM6010_REQ05_R98_CFG_FIFO8		0x05, 0x98
+#define TM6010_REQ05_R99_CFG_FIFO9		0x05, 0x99
+#define TM6010_REQ05_R91_CFG_FIFO10		0x05, 0x9a
+#define TM6010_REQ05_R91_CFG_FIFO11		0x05, 0x9b
+#define TM6010_REQ05_R91_CFG_FIFO12		0x05, 0x9c
+#define TM6010_REQ05_R91_CFG_FIFO13		0x05, 0x9d
+#define TM6010_REQ05_R91_CFG_FIFO14		0x05, 0x9e
+#define TM6010_REQ05_R91_CFG_FIFO15		0x05, 0x9f
+#define TM6010_REQ05_RA0_CTL_FIFO0		0x05, 0xa0
+#define TM6010_REQ05_RA1_CTL_FIFO1		0x05, 0xa1
+#define TM6010_REQ05_RA2_CTL_FIFO2		0x05, 0xa2
+#define TM6010_REQ05_RA3_CTL_FIFO3		0x05, 0xa3
+#define TM6010_REQ05_RA4_CTL_FIFO4		0x05, 0xa4
+#define TM6010_REQ05_RA5_CTL_FIFO5		0x05, 0xa5
+#define TM6010_REQ05_RA6_CTL_FIFO6		0x05, 0xa6
+#define TM6010_REQ05_RA7_CTL_FIFO7		0x05, 0xa7
+#define TM6010_REQ05_RA8_CTL_FIFO8		0x05, 0xa8
+#define TM6010_REQ05_RA9_CTL_FIFO9		0x05, 0xa9
+#define TM6010_REQ05_RA1_CTL_FIFO10		0x05, 0xaa
+#define TM6010_REQ05_RA1_CTL_FIFO11		0x05, 0xab
+#define TM6010_REQ05_RA1_CTL_FIFO12		0x05, 0xac
+#define TM6010_REQ05_RA1_CTL_FIFO13		0x05, 0xad
+#define TM6010_REQ05_RA1_CTL_FIFO14		0x05, 0xae
+#define TM6010_REQ05_RA1_CTL_FIFO15		0x05, 0xaf
+#define TM6010_REQ05_RB0_BC_LOW_FIFO0		0x05, 0xb0
+#define TM6010_REQ05_RB1_BC_LOW_FIFO1		0x05, 0xb1
+#define TM6010_REQ05_RB2_BC_LOW_FIFO2		0x05, 0xb2
+#define TM6010_REQ05_RB3_BC_LOW_FIFO3		0x05, 0xb3
+#define TM6010_REQ05_RB4_BC_LOW_FIFO4		0x05, 0xb4
+#define TM6010_REQ05_RB5_BC_LOW_FIFO5		0x05, 0xb5
+#define TM6010_REQ05_RB6_BC_LOW_FIFO6		0x05, 0xb6
+#define TM6010_REQ05_RB7_BC_LOW_FIFO7		0x05, 0xb7
+#define TM6010_REQ05_RB8_BC_LOW_FIFO8		0x05, 0xb8
+#define TM6010_REQ05_RB9_BC_LOW_FIFO9		0x05, 0xb9
+#define TM6010_REQ05_RB1_BC_LOW_FIFO10		0x05, 0xba
+#define TM6010_REQ05_RB1_BC_LOW_FIFO11		0x05, 0xbb
+#define TM6010_REQ05_RB1_BC_LOW_FIFO12		0x05, 0xbc
+#define TM6010_REQ05_RB1_BC_LOW_FIFO13		0x05, 0xbd
+#define TM6010_REQ05_RB1_BC_LOW_FIFO14		0x05, 0xbe
+#define TM6010_REQ05_RB1_BC_LOW_FIFO15		0x05, 0xbf
+#define TM6010_REQ05_RC0_DATA_FIFO0		0x05, 0xc0
+#define TM6010_REQ05_RC4_DATA_FIFO1		0x05, 0xc4
+#define TM6010_REQ05_RC8_DATA_FIFO2		0x05, 0xc8
+#define TM6010_REQ05_RCC_DATA_FIFO3		0x05, 0xcc
+#define TM6010_REQ05_RD0_DATA_FIFO4		0x05, 0xd0
+#define TM6010_REQ05_RD4_DATA_FIFO5		0x05, 0xd4
+#define TM6010_REQ05_RD8_DATA_FIFO6		0x05, 0xd8
+#define TM6010_REQ05_RDC_DATA_FIFO7		0x05, 0xdc
+#define TM6010_REQ05_RE0_DATA_FIFO8		0x05, 0xe0
+#define TM6010_REQ05_RE4_DATA_FIFO9		0x05, 0xe4
+#define TM6010_REQ05_RC4_DATA_FIFO10		0x05, 0xe8
+#define TM6010_REQ05_RC4_DATA_FIFO11		0x05, 0xec
+#define TM6010_REQ05_RC4_DATA_FIFO12		0x05, 0xf0
+#define TM6010_REQ05_RC4_DATA_FIFO13		0x05, 0xf4
+#define TM6010_REQ05_RC4_DATA_FIFO14		0x05, 0xf8
+#define TM6010_REQ05_RC4_DATA_FIFO15		0x05, 0xfc
+
+/* Define TM6000/TM6010 Audio decoder registers */
+#define TM6010_REQ08_R00_A_VERSION		0x08, 0x00
+#define TM6010_REQ08_R01_A_INIT			0x08, 0x01
+#define TM6010_REQ08_R02_A_FIX_GAIN_CTRL	0x08, 0x02
+#define TM6010_REQ08_R03_A_AUTO_GAIN_CTRL	0x08, 0x03
+#define TM6010_REQ08_R04_A_SIF_AMP_CTRL		0x08, 0x04
+#define TM6010_REQ08_R05_A_STANDARD_MOD		0x08, 0x05
+#define TM6010_REQ08_R06_A_SOUND_MOD		0x08, 0x06
+#define TM6010_REQ08_R07_A_LEFT_VOL		0x08, 0x07
+#define TM6010_REQ08_R08_A_RIGHT_VOL		0x08, 0x08
+#define TM6010_REQ08_R09_A_MAIN_VOL		0x08, 0x09
+#define TM6010_REQ08_R0A_A_I2S_MOD		0x08, 0x0a
+#define TM6010_REQ08_R0B_A_ASD_THRES1		0x08, 0x0b
+#define TM6010_REQ08_R0C_A_ASD_THRES2		0x08, 0x0c
+#define TM6010_REQ08_R0D_A_AMD_THRES		0x08, 0x0d
+#define TM6010_REQ08_R0E_A_MONO_THRES1		0x08, 0x0e
+#define TM6010_REQ08_R0F_A_MONO_THRES2		0x08, 0x0f
+#define TM6010_REQ08_R10_A_MUTE_THRES1		0x08, 0x10
+#define TM6010_REQ08_R11_A_MUTE_THRES2		0x08, 0x11
+#define TM6010_REQ08_R12_A_AGC_U		0x08, 0x12
+#define TM6010_REQ08_R13_A_AGC_ERR_T		0x08, 0x13
+#define TM6010_REQ08_R14_A_AGC_GAIN_INIT	0x08, 0x14
+#define TM6010_REQ08_R15_A_AGC_STEP_THR		0x08, 0x15
+#define TM6010_REQ08_R16_A_AGC_GAIN_MAX		0x08, 0x16
+#define TM6010_REQ08_R17_A_AGC_GAIN_MIN		0x08, 0x17
+#define TM6010_REQ08_R18_A_TR_CTRL		0x08, 0x18
+#define TM6010_REQ08_R19_A_FH_2FH_GAIN		0x08, 0x19
+#define TM6010_REQ08_R1A_A_NICAM_SER_MAX	0x08, 0x1a
+#define TM6010_REQ08_R1B_A_NICAM_SER_MIN	0x08, 0x1b
+#define TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT	0x08, 0x1e
+#define TM6010_REQ08_R1F_A_TEST_INTF_SEL	0x08, 0x1f
+#define TM6010_REQ08_R20_A_TEST_PIN_SEL		0x08, 0x20
+#define TM6010_REQ08_R21_A_AGC_ERR		0x08, 0x21
+#define TM6010_REQ08_R22_A_AGC_GAIN		0x08, 0x22
+#define TM6010_REQ08_R23_A_NICAM_INFO		0x08, 0x23
+#define TM6010_REQ08_R24_A_SER			0x08, 0x24
+#define TM6010_REQ08_R25_A_C1_AMP		0x08, 0x25
+#define TM6010_REQ08_R26_A_C2_AMP		0x08, 0x26
+#define TM6010_REQ08_R27_A_NOISE_AMP		0x08, 0x27
+#define TM6010_REQ08_R28_A_AUDIO_MODE_RES	0x08, 0x28
+
+/* Define TM6000/TM6010 Video ADC registers */
+#define TM6010_REQ08_RE0_ADC_REF		0x08, 0xe0
+#define TM6010_REQ08_RE1_DAC_CLMP		0x08, 0xe1
+#define TM6010_REQ08_RE2_POWER_DOWN_CTRL1	0x08, 0xe2
+#define TM6010_REQ08_RE3_ADC_IN1_SEL		0x08, 0xe3
+#define TM6010_REQ08_RE4_ADC_IN2_SEL		0x08, 0xe4
+#define TM6010_REQ08_RE5_GAIN_PARAM		0x08, 0xe5
+#define TM6010_REQ08_RE6_POWER_DOWN_CTRL2	0x08, 0xe6
+#define TM6010_REQ08_RE7_REG_GAIN_Y		0x08, 0xe7
+#define TM6010_REQ08_RE8_REG_GAIN_C		0x08, 0xe8
+#define TM6010_REQ08_RE9_BIAS_CTRL		0x08, 0xe9
+#define TM6010_REQ08_REA_BUFF_DRV_CTRL		0x08, 0xea
+#define TM6010_REQ08_REB_SIF_GAIN_CTRL		0x08, 0xeb
+#define TM6010_REQ08_REC_REVERSE_YC_CTRL	0x08, 0xec
+#define TM6010_REQ08_RED_GAIN_SEL		0x08, 0xed
+
+/* Define TM6000/TM6010 Audio ADC registers */
+#define TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG	0x08, 0xf0
+#define TM6010_REQ08_RF1_AADC_POWER_DOWN	0x08, 0xf1
+#define TM6010_REQ08_RF2_LEFT_CHANNEL_VOL	0x08, 0xf2
+#define TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL	0x08, 0xf3
diff --git a/drivers/staging/tm6000/tm6000-stds.c b/drivers/staging/tm6000/tm6000-stds.c
new file mode 100644
index 0000000..b3564f6
--- /dev/null
+++ b/drivers/staging/tm6000/tm6000-stds.c
@@ -0,0 +1,873 @@
+/*
+   tm6000-stds.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+
+   Copyright (C) 2007 Mauro Carvalho Chehab <mchehab@redhat.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation version 2
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include "tm6000.h"
+#include "tm6000-regs.h"
+
+struct tm6000_reg_settings {
+	unsigned char req;
+	unsigned char reg;
+	unsigned char value;
+};
+
+struct tm6000_std_tv_settings {
+	v4l2_std_id id;
+	struct tm6000_reg_settings sif[12];
+	struct tm6000_reg_settings nosif[12];
+	struct tm6000_reg_settings common[25];
+};
+
+struct tm6000_std_settings {
+	v4l2_std_id id;
+	struct tm6000_reg_settings common[37];
+};
+
+static struct tm6000_std_tv_settings tv_stds[] = {
+	{
+		.id = V4L2_STD_PAL_M,
+		.sif = {
+			{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2},
+			{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
+			{TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3},
+			{TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x08},
+			{TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1},
+			{TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0},
+			{TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+			{TM6010_REQ08_RED_GAIN_SEL, 0xe8},
+			{TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x62},
+			{TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe},
+			{TM6010_REQ07_RFE_POWER_DOWN, 0xcb},
+			{0, 0, 0},
+		},
+		.nosif = {
+			{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
+			{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
+			{TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3},
+			{TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f},
+			{TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1},
+			{TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0},
+			{TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+			{TM6010_REQ08_RED_GAIN_SEL, 0xe8},
+			{TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60},
+			{TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc},
+			{TM6010_REQ07_RFE_POWER_DOWN, 0x8b},
+			{0, 0, 0},
+		},
+		.common = {
+			{TM6010_REQ07_R3F_RESET, 0x01},
+			{TM6010_REQ07_R00_VIDEO_CONTROL0, 0x04},
+			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
+			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
+			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
+			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83},
+			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a},
+			{TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0},
+			{TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
+			{TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
+			{TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
+			{TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
+			{TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88},
+			{TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x20},
+			{TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61},
+			{TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c},
+			{TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c},
+			{TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52},
+			{TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F},
+
+			{TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc},
+			{TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+			{TM6010_REQ07_R3F_RESET, 0x00},
+			{0, 0, 0},
+		},
+	}, {
+		.id = V4L2_STD_PAL_Nc,
+		.sif = {
+			{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2},
+			{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
+			{TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3},
+			{TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x08},
+			{TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1},
+			{TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0},
+			{TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+			{TM6010_REQ08_RED_GAIN_SEL, 0xe8},
+			{TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x62},
+			{TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe},
+			{TM6010_REQ07_RFE_POWER_DOWN, 0xcb},
+			{0, 0, 0},
+		},
+		.nosif = {
+			{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
+			{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
+			{TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3},
+			{TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f},
+			{TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1},
+			{TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0},
+			{TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+			{TM6010_REQ08_RED_GAIN_SEL, 0xe8},
+			{TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60},
+			{TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc},
+			{TM6010_REQ07_RFE_POWER_DOWN, 0x8b},
+			{0, 0, 0},
+		},
+		.common = {
+			{TM6010_REQ07_R3F_RESET, 0x01},
+			{TM6010_REQ07_R00_VIDEO_CONTROL0, 0x36},
+			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
+			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
+			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
+			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91},
+			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f},
+			{TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c},
+			{TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
+			{TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
+			{TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
+			{TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
+			{TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c},
+			{TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c},
+			{TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1},
+			{TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c},
+			{TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c},
+			{TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52},
+			{TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F},
+
+			{TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc},
+			{TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+			{TM6010_REQ07_R3F_RESET, 0x00},
+			{0, 0, 0},
+		},
+	}, {
+		.id = V4L2_STD_PAL,
+		.sif = {
+			{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2},
+			{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
+			{TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3},
+			{TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x08},
+			{TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1},
+			{TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0},
+			{TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+			{TM6010_REQ08_RED_GAIN_SEL, 0xe8},
+			{TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x62},
+			{TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe},
+			{TM6010_REQ07_RFE_POWER_DOWN, 0xcb},
+			{0, 0, 0}
+		},
+		.nosif = {
+			{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
+			{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
+			{TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3},
+			{TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f},
+			{TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1},
+			{TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0},
+			{TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+			{TM6010_REQ08_RED_GAIN_SEL, 0xe8},
+			{TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60},
+			{TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc},
+			{TM6010_REQ07_RFE_POWER_DOWN, 0x8b},
+			{0, 0, 0},
+		},
+		.common = {
+			{TM6010_REQ07_R3F_RESET, 0x01},
+			{TM6010_REQ07_R00_VIDEO_CONTROL0, 0x32},
+			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
+			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
+			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25},
+			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5},
+			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63},
+			{TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50},
+			{TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
+			{TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
+			{TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
+			{TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
+			{TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c},
+			{TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c},
+			{TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1},
+			{TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c},
+			{TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c},
+			{TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52},
+			{TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F},
+
+			{TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc},
+			{TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+			{TM6010_REQ07_R3F_RESET, 0x00},
+			{0, 0, 0},
+		},
+	}, {
+		.id = V4L2_STD_SECAM,
+		.sif = {
+			{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2},
+			{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
+			{TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3},
+			{TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x08},
+			{TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1},
+			{TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0},
+			{TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+			{TM6010_REQ08_RED_GAIN_SEL, 0xe8},
+			{TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x62},
+			{TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe},
+			{TM6010_REQ07_RFE_POWER_DOWN, 0xcb},
+			{0, 0, 0},
+		},
+		.nosif = {
+			{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
+			{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
+			{TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3},
+			{TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f},
+			{TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1},
+			{TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0},
+			{TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+			{TM6010_REQ08_RED_GAIN_SEL, 0xe8},
+			{TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60},
+			{TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc},
+			{TM6010_REQ07_RFE_POWER_DOWN, 0x8b},
+			{0, 0, 0},
+		},
+		.common = {
+			{TM6010_REQ07_R3F_RESET, 0x01},
+			{TM6010_REQ07_R00_VIDEO_CONTROL0, 0x38},
+			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
+			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
+			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24},
+			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92},
+			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8},
+			{TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed},
+			{TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
+			{TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
+			{TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
+			{TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
+			{TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c},
+			{TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c},
+			{TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1},
+			{TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c},
+			{TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18},
+			{TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42},
+			{TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xFF},
+
+			{TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+			{TM6010_REQ07_R3F_RESET, 0x00},
+			{0, 0, 0},
+		},
+	}, {
+		.id = V4L2_STD_NTSC,
+		.sif = {
+			{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2},
+			{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
+			{TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3},
+			{TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x08},
+			{TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1},
+			{TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0},
+			{TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+			{TM6010_REQ08_RED_GAIN_SEL, 0xe8},
+			{TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x62},
+			{TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe},
+			{TM6010_REQ07_RFE_POWER_DOWN, 0xcb},
+			{0, 0, 0},
+		},
+		.nosif = {
+			{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
+			{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
+			{TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3},
+			{TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f},
+			{TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1},
+			{TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0},
+			{TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+			{TM6010_REQ08_RED_GAIN_SEL, 0xe8},
+			{TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60},
+			{TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc},
+			{TM6010_REQ07_RFE_POWER_DOWN, 0x8b},
+			{0, 0, 0},
+		},
+		.common = {
+			{TM6010_REQ07_R3F_RESET, 0x01},
+			{TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00},
+			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f},
+			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
+			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
+			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b},
+			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2},
+			{TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9},
+			{TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
+			{TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
+			{TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
+			{TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
+			{TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88},
+			{TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22},
+			{TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61},
+			{TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c},
+			{TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c},
+			{TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42},
+			{TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F},
+
+			{TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd},
+			{TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+			{TM6010_REQ07_R3F_RESET, 0x00},
+			{0, 0, 0},
+		},
+	},
+};
+
+static struct tm6000_std_settings composite_stds[] = {
+	{
+		.id = V4L2_STD_PAL_M,
+		.common = {
+			{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
+			{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4},
+			{TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3},
+			{TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f},
+			{TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1},
+			{TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0},
+			{TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+			{TM6010_REQ08_RED_GAIN_SEL, 0xe8},
+			{TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68},
+			{TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc},
+			{TM6010_REQ07_RFE_POWER_DOWN, 0x8b},
+
+			{TM6010_REQ07_R3F_RESET, 0x01},
+			{TM6010_REQ07_R00_VIDEO_CONTROL0, 0x04},
+			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
+			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
+			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
+			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83},
+			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a},
+			{TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0},
+			{TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
+			{TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
+			{TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
+			{TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
+			{TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88},
+			{TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x20},
+			{TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61},
+			{TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c},
+			{TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c},
+			{TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52},
+			{TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F},
+
+			{TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc},
+			{TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+			{TM6010_REQ07_R3F_RESET, 0x00},
+			{0, 0, 0},
+		},
+	 }, {
+		.id = V4L2_STD_PAL_Nc,
+		.common = {
+			{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
+			{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4},
+			{TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3},
+			{TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f},
+			{TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1},
+			{TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0},
+			{TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+			{TM6010_REQ08_RED_GAIN_SEL, 0xe8},
+			{TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68},
+			{TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc},
+			{TM6010_REQ07_RFE_POWER_DOWN, 0x8b},
+
+			{TM6010_REQ07_R3F_RESET, 0x01},
+			{TM6010_REQ07_R00_VIDEO_CONTROL0, 0x36},
+			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
+			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
+			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
+			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91},
+			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f},
+			{TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c},
+			{TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
+			{TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
+			{TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
+			{TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
+			{TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c},
+			{TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c},
+			{TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1},
+			{TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c},
+			{TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c},
+			{TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52},
+			{TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F},
+
+			{TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc},
+			{TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+			{TM6010_REQ07_R3F_RESET, 0x00},
+			{0, 0, 0},
+		},
+	}, {
+		.id = V4L2_STD_PAL,
+		.common = {
+			{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
+			{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4},
+			{TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3},
+			{TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f},
+			{TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1},
+			{TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0},
+			{TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+			{TM6010_REQ08_RED_GAIN_SEL, 0xe8},
+			{TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68},
+			{TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc},
+			{TM6010_REQ07_RFE_POWER_DOWN, 0x8b},
+
+			{TM6010_REQ07_R3F_RESET, 0x01},
+			{TM6010_REQ07_R00_VIDEO_CONTROL0, 0x32},
+			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
+			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
+			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25},
+			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5},
+			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63},
+			{TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50},
+			{TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
+			{TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
+			{TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
+			{TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
+			{TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c},
+			{TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c},
+			{TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1},
+			{TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c},
+			{TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c},
+			{TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52},
+			{TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F},
+
+			{TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc},
+			{TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+			{TM6010_REQ07_R3F_RESET, 0x00},
+			{0, 0, 0},
+		},
+	 }, {
+		.id = V4L2_STD_SECAM,
+		.common = {
+			{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
+			{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4},
+			{TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3},
+			{TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f},
+			{TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1},
+			{TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0},
+			{TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+			{TM6010_REQ08_RED_GAIN_SEL, 0xe8},
+			{TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68},
+			{TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc},
+			{TM6010_REQ07_RFE_POWER_DOWN, 0x8b},
+
+			{TM6010_REQ07_R3F_RESET, 0x01},
+			{TM6010_REQ07_R00_VIDEO_CONTROL0, 0x38},
+			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
+			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
+			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24},
+			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92},
+			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8},
+			{TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed},
+			{TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
+			{TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
+			{TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
+			{TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
+			{TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c},
+			{TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c},
+			{TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1},
+			{TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c},
+			{TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18},
+			{TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42},
+			{TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xFF},
+
+			{TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+			{TM6010_REQ07_R3F_RESET, 0x00},
+			{0, 0, 0},
+		},
+	}, {
+		.id = V4L2_STD_NTSC,
+		.common = {
+			{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
+			{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4},
+			{TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3},
+			{TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f},
+			{TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1},
+			{TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0},
+			{TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+			{TM6010_REQ08_RED_GAIN_SEL, 0xe8},
+			{TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68},
+			{TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc},
+			{TM6010_REQ07_RFE_POWER_DOWN, 0x8b},
+
+			{TM6010_REQ07_R3F_RESET, 0x01},
+			{TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00},
+			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f},
+			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
+			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
+			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b},
+			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2},
+			{TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9},
+			{TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
+			{TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
+			{TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
+			{TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
+			{TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88},
+			{TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22},
+			{TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61},
+			{TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c},
+			{TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c},
+			{TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42},
+			{TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F},
+
+			{TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd},
+			{TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+			{TM6010_REQ07_R3F_RESET, 0x00},
+			{0, 0, 0},
+		},
+	},
+};
+
+static struct tm6000_std_settings svideo_stds[] = {
+	{
+		.id = V4L2_STD_PAL_M,
+		.common = {
+			{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
+			{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc},
+			{TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8},
+			{TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00},
+			{TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2},
+			{TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0},
+			{TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+			{TM6010_REQ08_RED_GAIN_SEL, 0xe0},
+			{TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68},
+			{TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc},
+			{TM6010_REQ07_RFE_POWER_DOWN, 0x8a},
+
+			{TM6010_REQ07_R3F_RESET, 0x01},
+			{TM6010_REQ07_R00_VIDEO_CONTROL0, 0x05},
+			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
+			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
+			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
+			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83},
+			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a},
+			{TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0},
+			{TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
+			{TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
+			{TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
+			{TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
+			{TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88},
+			{TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22},
+			{TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61},
+			{TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c},
+			{TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c},
+			{TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52},
+			{TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F},
+
+			{TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc},
+			{TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+			{TM6010_REQ07_R3F_RESET, 0x00},
+			{0, 0, 0},
+		},
+	}, {
+		.id = V4L2_STD_PAL_Nc,
+		.common = {
+			{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
+			{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc},
+			{TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8},
+			{TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00},
+			{TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2},
+			{TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0},
+			{TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+			{TM6010_REQ08_RED_GAIN_SEL, 0xe0},
+			{TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68},
+			{TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc},
+			{TM6010_REQ07_RFE_POWER_DOWN, 0x8a},
+
+			{TM6010_REQ07_R3F_RESET, 0x01},
+			{TM6010_REQ07_R00_VIDEO_CONTROL0, 0x37},
+			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
+			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
+			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
+			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91},
+			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f},
+			{TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c},
+			{TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
+			{TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
+			{TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
+			{TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
+			{TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88},
+			{TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22},
+			{TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1},
+			{TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c},
+			{TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c},
+			{TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52},
+			{TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F},
+
+			{TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc},
+			{TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+			{TM6010_REQ07_R3F_RESET, 0x00},
+			{0, 0, 0},
+		},
+	}, {
+		.id = V4L2_STD_PAL,
+		.common = {
+			{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
+			{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc},
+			{TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8},
+			{TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00},
+			{TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2},
+			{TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0},
+			{TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+			{TM6010_REQ08_RED_GAIN_SEL, 0xe0},
+			{TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68},
+			{TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc},
+			{TM6010_REQ07_RFE_POWER_DOWN, 0x8a},
+
+			{TM6010_REQ07_R3F_RESET, 0x01},
+			{TM6010_REQ07_R00_VIDEO_CONTROL0, 0x33},
+			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
+			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
+			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x00},
+			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25},
+			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5},
+			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63},
+			{TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50},
+			{TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
+			{TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
+			{TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
+			{TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
+			{TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c},
+			{TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a},
+			{TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1},
+			{TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c},
+			{TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c},
+			{TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52},
+			{TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F},
+
+			{TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc},
+			{TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+			{TM6010_REQ07_R3F_RESET, 0x00},
+			{0, 0, 0},
+		},
+	 }, {
+		.id = V4L2_STD_SECAM,
+		.common = {
+			{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
+			{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc},
+			{TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8},
+			{TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00},
+			{TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2},
+			{TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0},
+			{TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+			{TM6010_REQ08_RED_GAIN_SEL, 0xe0},
+			{TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68},
+			{TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc},
+			{TM6010_REQ07_RFE_POWER_DOWN, 0x8a},
+
+			{TM6010_REQ07_R3F_RESET, 0x01},
+			{TM6010_REQ07_R00_VIDEO_CONTROL0, 0x39},
+			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
+			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
+			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24},
+			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92},
+			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8},
+			{TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed},
+			{TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
+			{TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
+			{TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
+			{TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
+			{TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c},
+			{TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a},
+			{TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1},
+			{TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c},
+			{TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18},
+			{TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42},
+			{TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xFF},
+
+			{TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+			{TM6010_REQ07_R3F_RESET, 0x00},
+			{0, 0, 0},
+		},
+	}, {
+		.id = V4L2_STD_NTSC,
+		.common = {
+			{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
+			{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc},
+			{TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8},
+			{TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00},
+			{TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2},
+			{TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0},
+			{TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+			{TM6010_REQ08_RED_GAIN_SEL, 0xe0},
+			{TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68},
+			{TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc},
+			{TM6010_REQ07_RFE_POWER_DOWN, 0x8a},
+
+			{TM6010_REQ07_R3F_RESET, 0x01},
+			{TM6010_REQ07_R00_VIDEO_CONTROL0, 0x01},
+			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f},
+			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
+			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x00},
+			{TM6010_REQ07_R17_HLOOP_MAXSTATE, 0x8b},
+			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
+			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b},
+			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2},
+			{TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9},
+			{TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
+			{TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
+			{TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
+			{TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
+			{TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88},
+			{TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22},
+			{TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61},
+			{TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c},
+			{TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c},
+			{TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42},
+			{TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F},
+
+			{TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd},
+			{TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+			{TM6010_REQ07_R3F_RESET, 0x00},
+			{0, 0, 0},
+		},
+	},
+};
+
+void tm6000_get_std_res(struct tm6000_core *dev)
+{
+	/* Currently, those are the only supported resoltions */
+	if (dev->norm & V4L2_STD_525_60) {
+		dev->height = 480;
+	} else {
+		dev->height = 576;
+	}
+	dev->width = 720;
+}
+
+static int tm6000_load_std(struct tm6000_core *dev,
+			   struct tm6000_reg_settings *set, int max_size)
+{
+	int i, rc;
+
+	/* Load board's initialization table */
+	for (i = 0; max_size; i++) {
+		if (!set[i].req)
+			return 0;
+
+		if ((dev->dev_type != TM6010) &&
+		    (set[i].req == REQ_08_SET_GET_AVREG_BIT))
+				continue;
+
+		rc = tm6000_set_reg(dev, set[i].req, set[i].reg, set[i].value);
+		if (rc < 0) {
+			printk(KERN_ERR "Error %i while setting "
+			       "req %d, reg %d to value %d\n",
+			       rc, set[i].req, set[i].reg, set[i].value);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static int tm6000_set_tv(struct tm6000_core *dev, int pos)
+{
+	int rc;
+
+	/* FIXME: This code is for tm6010 - not tested yet - doesn't work with
+	   tm5600
+	 */
+
+	/* FIXME: This is tuner-dependent */
+	int nosif = 0;
+
+	if (nosif) {
+		rc = tm6000_load_std(dev, tv_stds[pos].nosif,
+				     sizeof(tv_stds[pos].nosif));
+	} else {
+		rc = tm6000_load_std(dev, tv_stds[pos].sif,
+				     sizeof(tv_stds[pos].sif));
+	}
+	if (rc < 0)
+		return rc;
+	rc = tm6000_load_std(dev, tv_stds[pos].common,
+			     sizeof(tv_stds[pos].common));
+
+	return rc;
+}
+
+int tm6000_set_standard(struct tm6000_core *dev, v4l2_std_id * norm)
+{
+	int i, rc = 0;
+
+	dev->norm = *norm;
+	tm6000_get_std_res(dev);
+
+	switch (dev->input) {
+	case TM6000_INPUT_TV:
+		for (i = 0; i < ARRAY_SIZE(tv_stds); i++) {
+			if (*norm & tv_stds[i].id) {
+				rc = tm6000_set_tv(dev, i);
+				goto ret;
+			}
+		}
+		return -EINVAL;
+	case TM6000_INPUT_SVIDEO:
+		for (i = 0; i < ARRAY_SIZE(svideo_stds); i++) {
+			if (*norm & svideo_stds[i].id) {
+				rc = tm6000_load_std(dev, svideo_stds[i].common,
+						     sizeof(svideo_stds[i].
+							    common));
+				goto ret;
+			}
+		}
+		return -EINVAL;
+	case TM6000_INPUT_COMPOSITE:
+		for (i = 0; i < ARRAY_SIZE(composite_stds); i++) {
+			if (*norm & composite_stds[i].id) {
+				rc = tm6000_load_std(dev,
+						     composite_stds[i].common,
+						     sizeof(composite_stds[i].
+							    common));
+				goto ret;
+			}
+		}
+		return -EINVAL;
+	}
+
+ret:
+	if (rc < 0)
+		return rc;
+
+	msleep(40);
+
+
+	return 0;
+}
diff --git a/drivers/staging/tm6000/tm6000-usb-isoc.h b/drivers/staging/tm6000/tm6000-usb-isoc.h
new file mode 100644
index 0000000..5a5049a
--- /dev/null
+++ b/drivers/staging/tm6000/tm6000-usb-isoc.h
@@ -0,0 +1,53 @@
+/*
+   tm6000-buf.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+
+   Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation version 2
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/videodev2.h>
+
+#define TM6000_URB_MSG_LEN 180
+
+struct usb_isoc_ctl {
+		/* max packet size of isoc transaction */
+	int				max_pkt_size;
+
+		/* number of allocated urbs */
+	int				num_bufs;
+
+		/* urb for isoc transfers */
+	struct urb			**urb;
+
+		/* transfer buffers for isoc transfer */
+	char				**transfer_buffer;
+
+		/* Last buffer command and region */
+	u8				cmd;
+	int				pos, size, pktsize;
+
+		/* Last field: ODD or EVEN? */
+	int				field;
+
+		/* Stores incomplete commands */
+	u32				tmp_buf;
+	int				tmp_buf_len;
+
+		/* Stores already requested buffers */
+	struct tm6000_buffer    	*buf;
+
+		/* Stores the number of received fields */
+	int				nfields;
+};
diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c
new file mode 100644
index 0000000..f2b7fe4
--- /dev/null
+++ b/drivers/staging/tm6000/tm6000-video.c
@@ -0,0 +1,1557 @@
+/*
+   tm6000-video.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+
+   Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+
+   Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
+	- Fixed module load/unload
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation version 2
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/random.h>
+#include <linux/version.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ioctl.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/highmem.h>
+#include <linux/freezer.h>
+
+#include "tm6000-regs.h"
+#include "tm6000.h"
+
+#define BUFFER_TIMEOUT     msecs_to_jiffies(2000)  /* 2 seconds */
+
+/* Limits minimum and default number of buffers */
+#define TM6000_MIN_BUF 4
+#define TM6000_DEF_BUF 8
+
+#define TM6000_MAX_ISO_PACKETS	40	/* Max number of ISO packets */
+
+/* Declare static vars that will be used as parameters */
+static unsigned int vid_limit = 16;	/* Video memory limit, in Mb */
+static int video_nr = -1;		/* /dev/videoN, -1 for autodetect */
+
+/* Debug level */
+int tm6000_debug;
+
+/* supported controls */
+static struct v4l2_queryctrl tm6000_qctrl[] = {
+	{
+		.id            = V4L2_CID_BRIGHTNESS,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Brightness",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 1,
+		.default_value = 54,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_CONTRAST,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Contrast",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 0x1,
+		.default_value = 119,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_SATURATION,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Saturation",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 0x1,
+		.default_value = 112,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_HUE,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Hue",
+		.minimum       = -128,
+		.maximum       = 127,
+		.step          = 0x1,
+		.default_value = 0,
+		.flags         = 0,
+	}
+};
+
+static int qctl_regs[ARRAY_SIZE(tm6000_qctrl)];
+
+static struct tm6000_fmt format[] = {
+	{
+		.name     = "4:2:2, packed, YVY2",
+		.fourcc   = V4L2_PIX_FMT_YUYV,
+		.depth    = 16,
+	}, {
+		.name     = "4:2:2, packed, UYVY",
+		.fourcc   = V4L2_PIX_FMT_UYVY,
+		.depth    = 16,
+	}, {
+		.name     = "A/V + VBI mux packet",
+		.fourcc   = V4L2_PIX_FMT_TM6000,
+		.depth    = 16,
+	}
+};
+
+/* ------------------------------------------------------------------
+	DMA and thread functions
+   ------------------------------------------------------------------*/
+
+#define norm_maxw(a) 720
+#define norm_maxh(a) 576
+
+#define norm_minw(a) norm_maxw(a)
+#define norm_minh(a) norm_maxh(a)
+
+/*
+ * video-buf generic routine to get the next available buffer
+ */
+static inline void get_next_buf(struct tm6000_dmaqueue *dma_q,
+			       struct tm6000_buffer   **buf)
+{
+	struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+	char *outp;
+
+	if (list_empty(&dma_q->active)) {
+		dprintk(dev, V4L2_DEBUG_QUEUE, "No active queue to serve\n");
+		*buf = NULL;
+		return;
+	}
+
+	*buf = list_entry(dma_q->active.next,
+			struct tm6000_buffer, vb.queue);
+
+	if (!buf)
+		return;
+
+	/* Cleans up buffer - Usefull for testing for frame/URB loss */
+	outp = videobuf_to_vmalloc(&(*buf)->vb);
+//	if (outp)
+//		memset(outp, 0, (*buf)->vb.size);
+
+	return;
+}
+
+/*
+ * Announces that a buffer were filled and request the next
+ */
+static inline void buffer_filled(struct tm6000_core *dev,
+				 struct tm6000_dmaqueue *dma_q,
+				 struct tm6000_buffer *buf)
+{
+	/* Advice that buffer was filled */
+	dprintk(dev, V4L2_DEBUG_ISOC, "[%p/%d] wakeup\n", buf, buf->vb.i);
+	buf->vb.state = VIDEOBUF_DONE;
+	buf->vb.field_count++;
+	do_gettimeofday(&buf->vb.ts);
+
+	list_del(&buf->vb.queue);
+	wake_up(&buf->vb.done);
+}
+
+const char *tm6000_msg_type[] = {
+	"unknown(0)",   /* 0 */
+	"video",        /* 1 */
+	"audio",        /* 2 */
+	"vbi",          /* 3 */
+	"pts",          /* 4 */
+	"err",          /* 5 */
+	"unknown(6)",   /* 6 */
+	"unknown(7)",   /* 7 */
+};
+
+/*
+ * Identify the tm5600/6000 buffer header type and properly handles
+ */
+static int copy_packet(struct urb *urb, u32 header, u8 **ptr, u8 *endp,
+			u8 *out_p, struct tm6000_buffer **buf)
+{
+	struct tm6000_dmaqueue  *dma_q = urb->context;
+	struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+	u8 c;
+	unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0;
+	int rc = 0;
+	/* FIXME: move to tm6000-isoc */
+	static int last_line = -2, start_line = -2, last_field = -2;
+
+	/* FIXME: this is the hardcoded window size
+	 */
+	unsigned int linewidth = (*buf)->vb.width << 1;
+
+	if (!dev->isoc_ctl.cmd) {
+		c = (header >> 24) & 0xff;
+
+		/* split the header fields */
+		size  = (((header & 0x7e) << 1) -1) *4;
+		block = (header >> 7) & 0xf;
+		field = (header >> 11) & 0x1;
+		line  = (header >> 12) & 0x1ff;
+		cmd   = (header >> 21) & 0x7;
+
+		/* Validates header fields */
+		if(size > TM6000_URB_MSG_LEN)
+			size = TM6000_URB_MSG_LEN;
+
+		if (cmd == TM6000_URB_MSG_VIDEO) {
+			if ((block+1)*TM6000_URB_MSG_LEN>linewidth)
+				cmd = TM6000_URB_MSG_ERR;
+
+			/* FIXME: Mounts the image as field0+field1
+			 * It should, instead, check if the user selected
+			 * entrelaced or non-entrelaced mode
+			 */
+			pos = ((line << 1) - field - 1) * linewidth +
+				block * TM6000_URB_MSG_LEN;
+
+			/* Don't allow to write out of the buffer */
+			if (pos+TM6000_URB_MSG_LEN > (*buf)->vb.size) {
+				dprintk(dev, V4L2_DEBUG_ISOC,
+					"ERR: size=%d, num=%d, line=%d, "
+					"field=%d\n",
+					size, block, line, field);
+
+				cmd = TM6000_URB_MSG_ERR;
+			}
+		} else {
+			pos=0;
+		}
+
+		/* Prints debug info */
+		dprintk(dev, V4L2_DEBUG_ISOC, "size=%d, num=%d, "
+				" line=%d, field=%d\n",
+				size, block, line, field);
+
+		if ((last_line!=line)&&(last_line+1!=line) &&
+		    (cmd != TM6000_URB_MSG_ERR) )  {
+			if (cmd != TM6000_URB_MSG_VIDEO)  {
+				dprintk(dev, V4L2_DEBUG_ISOC,  "cmd=%d, "
+					"size=%d, num=%d, line=%d, field=%d\n",
+					cmd, size, block, line, field);
+			}
+			if (start_line<0)
+				start_line=last_line;
+			/* Prints debug info */
+			dprintk(dev, V4L2_DEBUG_ISOC, "lines= %d-%d, "
+					"field=%d\n",
+					start_line, last_line, field);
+
+			if ((start_line<6 && last_line>200) &&
+				(last_field != field) ) {
+
+				dev->isoc_ctl.nfields++;
+				if (dev->isoc_ctl.nfields>=2) {
+					dev->isoc_ctl.nfields=0;
+
+					/* Announces that a new buffer were filled */
+					buffer_filled (dev, dma_q, *buf);
+					dprintk(dev, V4L2_DEBUG_ISOC,
+							"new buffer filled\n");
+					get_next_buf (dma_q, buf);
+					if (!*buf)
+						return rc;
+					out_p = videobuf_to_vmalloc(&((*buf)->vb));
+					if (!out_p)
+						return rc;
+
+					pos = dev->isoc_ctl.pos = 0;
+				}
+			}
+
+			start_line=line;
+			last_field=field;
+		}
+		if (cmd == TM6000_URB_MSG_VIDEO)
+			last_line = line;
+
+		pktsize = TM6000_URB_MSG_LEN;
+	} else {
+		/* Continue the last copy */
+		cmd = dev->isoc_ctl.cmd;
+		size= dev->isoc_ctl.size;
+		pos = dev->isoc_ctl.pos;
+		pktsize = dev->isoc_ctl.pktsize;
+	}
+
+	cpysize = (endp-(*ptr) > size) ? size : endp - *ptr;
+
+	if (cpysize) {
+		/* handles each different URB message */
+		switch(cmd) {
+		case TM6000_URB_MSG_VIDEO:
+			/* Fills video buffer */
+			memcpy(&out_p[pos], *ptr, cpysize);
+			break;
+		case TM6000_URB_MSG_PTS:
+			break;
+		case TM6000_URB_MSG_AUDIO:
+/* Need some code to process audio */
+printk ("%ld: cmd=%s, size=%d\n", jiffies,
+				tm6000_msg_type[cmd],size);
+			break;
+		default:
+			dprintk (dev, V4L2_DEBUG_ISOC, "cmd=%s, size=%d\n",
+						tm6000_msg_type[cmd],size);
+		}
+	}
+	if (cpysize<size) {
+		/* End of URB packet, but cmd processing is not
+		 * complete. Preserve the state for a next packet
+		 */
+		dev->isoc_ctl.pos = pos+cpysize;
+		dev->isoc_ctl.size= size-cpysize;
+		dev->isoc_ctl.cmd = cmd;
+		dev->isoc_ctl.pktsize = pktsize-cpysize;
+		(*ptr)+=cpysize;
+	} else {
+		dev->isoc_ctl.cmd = 0;
+		(*ptr)+=pktsize;
+	}
+
+	return rc;
+}
+
+static int copy_streams(u8 *data, u8 *out_p, unsigned long len,
+			struct urb *urb, struct tm6000_buffer **buf)
+{
+	struct tm6000_dmaqueue  *dma_q = urb->context;
+	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
+	u8 *ptr=data, *endp=data+len;
+	unsigned long header=0;
+	int rc=0;
+
+	for (ptr=data; ptr<endp;) {
+		if (!dev->isoc_ctl.cmd) {
+			u8 *p=(u8 *)&dev->isoc_ctl.tmp_buf;
+			/* FIXME: This seems very complex
+			 * It just recovers up to 3 bytes of the header that
+			 * might be at the previous packet
+			 */
+			if (dev->isoc_ctl.tmp_buf_len) {
+				while (dev->isoc_ctl.tmp_buf_len) {
+					if ( *(ptr+3-dev->isoc_ctl.tmp_buf_len) == 0x47) {
+						break;
+					}
+					p++;
+					dev->isoc_ctl.tmp_buf_len--;
+				}
+				if (dev->isoc_ctl.tmp_buf_len) {
+					memcpy(&header, p,
+						dev->isoc_ctl.tmp_buf_len);
+					memcpy((u8 *)&header +
+						dev->isoc_ctl.tmp_buf_len,
+						ptr,
+						4 - dev->isoc_ctl.tmp_buf_len);
+					ptr += 4 - dev->isoc_ctl.tmp_buf_len;
+					goto HEADER;
+				}
+			}
+			/* Seek for sync */
+			for (;ptr<endp-3;ptr++) {
+				if (*(ptr+3)==0x47)
+					break;
+			}
+
+			if (ptr+3>=endp) {
+				dev->isoc_ctl.tmp_buf_len=endp-ptr;
+				memcpy (&dev->isoc_ctl.tmp_buf,ptr,
+					dev->isoc_ctl.tmp_buf_len);
+				dev->isoc_ctl.cmd=0;
+				return rc;
+			}
+
+			/* Get message header */
+			header=*(unsigned long *)ptr;
+			ptr+=4;
+		}
+HEADER:
+		/* Copy or continue last copy */
+		rc=copy_packet(urb,header,&ptr,endp,out_p,buf);
+		if (rc<0) {
+			buf=NULL;
+			printk(KERN_ERR "tm6000: buffer underrun at %ld\n",
+					jiffies);
+			return rc;
+		}
+		if (!*buf)
+			return 0;
+	}
+
+	return 0;
+}
+/*
+ * Identify the tm5600/6000 buffer header type and properly handles
+ */
+static int copy_multiplexed(u8 *ptr, u8 *out_p, unsigned long len,
+			struct urb *urb, struct tm6000_buffer **buf)
+{
+	struct tm6000_dmaqueue  *dma_q = urb->context;
+	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
+	unsigned int pos=dev->isoc_ctl.pos,cpysize;
+	int rc=1;
+
+	while (len>0) {
+		cpysize=min(len,(*buf)->vb.size-pos);
+//printk("Copying %d bytes (max=%lu) from %p to %p[%u]\n",cpysize,(*buf)->vb.size,ptr,out_p,pos);
+		memcpy(&out_p[pos], ptr, cpysize);
+		pos+=cpysize;
+		ptr+=cpysize;
+		len-=cpysize;
+		if (pos >= (*buf)->vb.size) {
+			pos=0;
+			/* Announces that a new buffer were filled */
+			buffer_filled (dev, dma_q, *buf);
+			dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n");
+			get_next_buf (dma_q, buf);
+			if (!*buf)
+				break;
+			out_p = videobuf_to_vmalloc(&((*buf)->vb));
+			if (!out_p)
+				return rc;
+			pos = 0;
+		}
+	}
+
+	dev->isoc_ctl.pos=pos;
+	return rc;
+}
+
+static void inline print_err_status (struct tm6000_core *dev,
+				     int packet, int status)
+{
+	char *errmsg = "Unknown";
+
+	switch(status) {
+	case -ENOENT:
+		errmsg = "unlinked synchronuously";
+		break;
+	case -ECONNRESET:
+		errmsg = "unlinked asynchronuously";
+		break;
+	case -ENOSR:
+		errmsg = "Buffer error (overrun)";
+		break;
+	case -EPIPE:
+		errmsg = "Stalled (device not responding)";
+		break;
+	case -EOVERFLOW:
+		errmsg = "Babble (bad cable?)";
+		break;
+	case -EPROTO:
+		errmsg = "Bit-stuff error (bad cable?)";
+		break;
+	case -EILSEQ:
+		errmsg = "CRC/Timeout (could be anything)";
+		break;
+	case -ETIME:
+		errmsg = "Device does not respond";
+		break;
+	}
+	if (packet<0) {
+		dprintk(dev, V4L2_DEBUG_QUEUE, "URB status %d [%s].\n",
+			status, errmsg);
+	} else {
+		dprintk(dev, V4L2_DEBUG_QUEUE, "URB packet %d, status %d [%s].\n",
+			packet, status, errmsg);
+	}
+}
+
+
+/*
+ * Controls the isoc copy of each urb packet
+ */
+static inline int tm6000_isoc_copy(struct urb *urb)
+{
+	struct tm6000_dmaqueue  *dma_q = urb->context;
+	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
+	struct tm6000_buffer *buf;
+	int i, len=0, rc=1;
+	int size;
+	char *outp = NULL, *p;
+	unsigned long copied;
+
+	get_next_buf(dma_q, &buf);
+	if (buf)
+		outp = videobuf_to_vmalloc(&buf->vb);
+
+	if (!outp)
+		return 0;
+
+	size = buf->vb.size;
+
+	copied=0;
+
+	if (urb->status<0) {
+		print_err_status (dev,-1,urb->status);
+		return 0;
+	}
+
+	for (i = 0; i < urb->number_of_packets; i++) {
+		int status = urb->iso_frame_desc[i].status;
+
+		if (status<0) {
+			print_err_status (dev,i,status);
+			continue;
+		}
+
+		len=urb->iso_frame_desc[i].actual_length;
+
+//		if (len>=TM6000_URB_MSG_LEN) {
+			p=urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+			if (!urb->iso_frame_desc[i].status) {
+				if ((buf->fmt->fourcc)==V4L2_PIX_FMT_TM6000) {
+					rc=copy_multiplexed(p, outp, len, urb, &buf);
+					if (rc<=0)
+						return rc;
+				} else {
+					copy_streams(p, outp, len, urb, &buf);
+				}
+			}
+			copied += len;
+			if (copied >= size || !buf)
+				break;
+//		}
+	}
+	return rc;
+}
+
+/* ------------------------------------------------------------------
+	URB control
+   ------------------------------------------------------------------*/
+
+/*
+ * IRQ callback, called by URB callback
+ */
+static void tm6000_irq_callback(struct urb *urb)
+{
+	struct tm6000_dmaqueue  *dma_q = urb->context;
+	struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+	int i;
+
+	if (!dev)
+		return;
+
+	spin_lock(&dev->slock);
+	tm6000_isoc_copy(urb);
+	spin_unlock(&dev->slock);
+
+	/* Reset urb buffers */
+	for (i = 0; i < urb->number_of_packets; i++) {
+		urb->iso_frame_desc[i].status = 0;
+		urb->iso_frame_desc[i].actual_length = 0;
+	}
+
+	urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (urb->status)
+		tm6000_err("urb resubmit failed (error=%i)\n",
+			urb->status);
+}
+
+/*
+ * Stop and Deallocate URBs
+ */
+static void tm6000_uninit_isoc(struct tm6000_core *dev)
+{
+	struct urb *urb;
+	int i;
+
+	dev->isoc_ctl.nfields = -1;
+	dev->isoc_ctl.buf = NULL;
+	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+		urb=dev->isoc_ctl.urb[i];
+		if (urb) {
+			usb_kill_urb(urb);
+			usb_unlink_urb(urb);
+			if (dev->isoc_ctl.transfer_buffer[i]) {
+				usb_free_coherent(dev->udev,
+						urb->transfer_buffer_length,
+						dev->isoc_ctl.transfer_buffer[i],
+						urb->transfer_dma);
+			}
+			usb_free_urb(urb);
+			dev->isoc_ctl.urb[i] = NULL;
+		}
+		dev->isoc_ctl.transfer_buffer[i] = NULL;
+	}
+
+	kfree (dev->isoc_ctl.urb);
+	kfree (dev->isoc_ctl.transfer_buffer);
+
+	dev->isoc_ctl.urb=NULL;
+	dev->isoc_ctl.transfer_buffer=NULL;
+	dev->isoc_ctl.num_bufs = 0;
+
+	dev->isoc_ctl.num_bufs=0;
+}
+
+/*
+ * Allocate URBs and start IRQ
+ */
+static int tm6000_prepare_isoc(struct tm6000_core *dev, unsigned int framesize)
+{
+	struct tm6000_dmaqueue *dma_q = &dev->vidq;
+	int i, j, sb_size, pipe, size, max_packets, num_bufs = 5;
+	struct urb *urb;
+
+	/* De-allocates all pending stuff */
+	tm6000_uninit_isoc(dev);
+
+	usb_set_interface(dev->udev,
+			  dev->isoc_in.bInterfaceNumber,
+			  dev->isoc_in.bAlternateSetting);
+
+	pipe = usb_rcvisocpipe(dev->udev,
+			       dev->isoc_in.endp->desc.bEndpointAddress &
+			       USB_ENDPOINT_NUMBER_MASK);
+
+	size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
+
+	if (size > dev->isoc_in.maxsize)
+		size = dev->isoc_in.maxsize;
+
+	dev->isoc_ctl.max_pkt_size = size;
+
+	max_packets = ( framesize + size - 1) / size;
+
+	if (max_packets > TM6000_MAX_ISO_PACKETS)
+		max_packets = TM6000_MAX_ISO_PACKETS;
+
+	sb_size = max_packets * size;
+
+	dev->isoc_ctl.num_bufs = num_bufs;
+
+	dev->isoc_ctl.urb = kmalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
+	if (!dev->isoc_ctl.urb) {
+		tm6000_err("cannot alloc memory for usb buffers\n");
+		return -ENOMEM;
+	}
+
+	dev->isoc_ctl.transfer_buffer = kmalloc(sizeof(void *)*num_bufs,
+				   GFP_KERNEL);
+	if (!dev->isoc_ctl.transfer_buffer) {
+		tm6000_err("cannot allocate memory for usbtransfer\n");
+		kfree(dev->isoc_ctl.urb);
+		return -ENOMEM;
+	}
+
+	dprintk(dev, V4L2_DEBUG_QUEUE, "Allocating %d x %d packets"
+		    " (%d bytes) of %d bytes each to handle %u size\n",
+		    max_packets, num_bufs, sb_size,
+		    dev->isoc_in.maxsize, size);
+
+	/* allocate urbs and transfer buffers */
+	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+		urb = usb_alloc_urb(max_packets, GFP_KERNEL);
+		if (!urb) {
+			tm6000_err("cannot alloc isoc_ctl.urb %i\n", i);
+			tm6000_uninit_isoc(dev);
+			usb_free_urb(urb);
+			return -ENOMEM;
+		}
+		dev->isoc_ctl.urb[i] = urb;
+
+		dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev,
+			sb_size, GFP_KERNEL, &urb->transfer_dma);
+		if (!dev->isoc_ctl.transfer_buffer[i]) {
+			tm6000_err ("unable to allocate %i bytes for transfer"
+					" buffer %i%s\n",
+					sb_size, i,
+					in_interrupt()?" while in int":"");
+			tm6000_uninit_isoc(dev);
+			return -ENOMEM;
+		}
+		memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
+
+		usb_fill_bulk_urb(urb, dev->udev, pipe,
+				  dev->isoc_ctl.transfer_buffer[i], sb_size,
+				  tm6000_irq_callback, dma_q);
+		urb->interval = dev->isoc_in.endp->desc.bInterval;
+		urb->number_of_packets = max_packets;
+		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+
+		for (j = 0; j < max_packets; j++) {
+			urb->iso_frame_desc[j].offset = size * j;
+			urb->iso_frame_desc[j].length = size;
+		}
+	}
+
+	return 0;
+}
+
+static int tm6000_start_thread( struct tm6000_core *dev)
+{
+	struct tm6000_dmaqueue *dma_q = &dev->vidq;
+	int i;
+
+	dma_q->frame=0;
+	dma_q->ini_jiffies=jiffies;
+
+	init_waitqueue_head(&dma_q->wq);
+
+	/* submit urbs and enables IRQ */
+	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+		int rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
+		if (rc) {
+			tm6000_err("submit of urb %i failed (error=%i)\n", i,
+				   rc);
+			tm6000_uninit_isoc(dev);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------
+	Videobuf operations
+   ------------------------------------------------------------------*/
+
+static int
+buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+{
+	struct tm6000_fh *fh = vq->priv_data;
+
+	*size = fh->fmt->depth * fh->width * fh->height >> 3;
+	if (0 == *count)
+		*count = TM6000_DEF_BUF;
+
+	if (*count < TM6000_MIN_BUF) {
+		*count=TM6000_MIN_BUF;
+	}
+
+	while (*size * *count > vid_limit * 1024 * 1024)
+		(*count)--;
+
+	return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct tm6000_buffer *buf)
+{
+	struct tm6000_fh *fh = vq->priv_data;
+	struct tm6000_core   *dev = fh->dev;
+	unsigned long flags;
+
+	if (in_interrupt())
+		BUG();
+
+	/* We used to wait for the buffer to finish here, but this didn't work
+	   because, as we were keeping the state as VIDEOBUF_QUEUED,
+	   videobuf_queue_cancel marked it as finished for us.
+	   (Also, it could wedge forever if the hardware was misconfigured.)
+
+	   This should be safe; by the time we get here, the buffer isn't
+	   queued anymore. If we ever start marking the buffers as
+	   VIDEOBUF_ACTIVE, it won't be, though.
+	*/
+	spin_lock_irqsave(&dev->slock, flags);
+	if (dev->isoc_ctl.buf == buf)
+		dev->isoc_ctl.buf = NULL;
+	spin_unlock_irqrestore(&dev->slock, flags);
+
+	videobuf_vmalloc_free(&buf->vb);
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+						enum v4l2_field field)
+{
+	struct tm6000_fh     *fh  = vq->priv_data;
+	struct tm6000_buffer *buf = container_of(vb,struct tm6000_buffer,vb);
+	struct tm6000_core   *dev = fh->dev;
+	int rc = 0, urb_init = 0;
+
+	BUG_ON(NULL == fh->fmt);
+
+
+	/* FIXME: It assumes depth=2 */
+	/* The only currently supported format is 16 bits/pixel */
+	buf->vb.size = fh->fmt->depth*fh->width*fh->height >> 3;
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+		return -EINVAL;
+
+	if (buf->fmt       != fh->fmt    ||
+	    buf->vb.width  != fh->width  ||
+	    buf->vb.height != fh->height ||
+	    buf->vb.field  != field) {
+		buf->fmt       = fh->fmt;
+		buf->vb.width  = fh->width;
+		buf->vb.height = fh->height;
+		buf->vb.field  = field;
+		buf->vb.state = VIDEOBUF_NEEDS_INIT;
+	}
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		if (0 != (rc = videobuf_iolock(vq, &buf->vb, NULL)))
+			goto fail;
+		urb_init = 1;
+	}
+
+	if (!dev->isoc_ctl.num_bufs)
+		urb_init = 1;
+
+	if (urb_init) {
+		rc = tm6000_prepare_isoc(dev, buf->vb.size);
+		if (rc < 0)
+			goto fail;
+
+		rc = tm6000_start_thread(dev);
+		if (rc < 0)
+			goto fail;
+
+	}
+
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+
+fail:
+	free_buffer(vq, buf);
+	return rc;
+}
+
+static void
+buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct tm6000_buffer    *buf     = container_of(vb,struct tm6000_buffer,vb);
+	struct tm6000_fh        *fh      = vq->priv_data;
+	struct tm6000_core      *dev     = fh->dev;
+	struct tm6000_dmaqueue  *vidq    = &dev->vidq;
+
+	buf->vb.state = VIDEOBUF_QUEUED;
+	list_add_tail(&buf->vb.queue, &vidq->active);
+}
+
+static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct tm6000_buffer   *buf  = container_of(vb,struct tm6000_buffer,vb);
+
+	free_buffer(vq,buf);
+}
+
+static struct videobuf_queue_ops tm6000_video_qops = {
+	.buf_setup      = buffer_setup,
+	.buf_prepare    = buffer_prepare,
+	.buf_queue      = buffer_queue,
+	.buf_release    = buffer_release,
+};
+
+/* ------------------------------------------------------------------
+	IOCTL handling
+   ------------------------------------------------------------------*/
+
+static int res_get(struct tm6000_core *dev, struct tm6000_fh *fh)
+{
+	/* is it free? */
+	mutex_lock(&dev->lock);
+	if (dev->resources) {
+		/* no, someone else uses it */
+		mutex_unlock(&dev->lock);
+		return 0;
+	}
+	/* it's free, grab it */
+	dev->resources =1;
+	dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: get\n");
+	mutex_unlock(&dev->lock);
+	return 1;
+}
+
+static int res_locked(struct tm6000_core *dev)
+{
+	return (dev->resources);
+}
+
+static void res_free(struct tm6000_core *dev, struct tm6000_fh *fh)
+{
+	mutex_lock(&dev->lock);
+	dev->resources = 0;
+	dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: put\n");
+	mutex_unlock(&dev->lock);
+}
+
+/* ------------------------------------------------------------------
+	IOCTL vidioc handling
+   ------------------------------------------------------------------*/
+static int vidioc_querycap (struct file *file, void  *priv,
+					struct v4l2_capability *cap)
+{
+	//	struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
+
+	strlcpy(cap->driver, "tm6000", sizeof(cap->driver));
+	strlcpy(cap->card,"Trident TVMaster TM5600/6000/6010", sizeof(cap->card));
+	//	strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info));
+	cap->version = TM6000_VERSION;
+	cap->capabilities =	V4L2_CAP_VIDEO_CAPTURE |
+				V4L2_CAP_STREAMING     |
+				V4L2_CAP_TUNER	       |
+				V4L2_CAP_READWRITE;
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap (struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	if (unlikely(f->index >= ARRAY_SIZE(format)))
+		return -EINVAL;
+
+	strlcpy(f->description,format[f->index].name,sizeof(f->description));
+	f->pixelformat = format[f->index].fourcc;
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct tm6000_fh  *fh=priv;
+
+	f->fmt.pix.width        = fh->width;
+	f->fmt.pix.height       = fh->height;
+	f->fmt.pix.field        = fh->vb_vidq.field;
+	f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * fh->fmt->depth) >> 3;
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+	return (0);
+}
+
+static struct tm6000_fmt* format_by_fourcc(unsigned int fourcc)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(format); i++)
+		if (format[i].fourcc == fourcc)
+			return format+i;
+	return NULL;
+}
+
+static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
+			struct v4l2_format *f)
+{
+	struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
+	struct tm6000_fmt *fmt;
+	enum v4l2_field field;
+
+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+	if (NULL == fmt) {
+		dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Fourcc format (0x%08x)"
+				" invalid.\n", f->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+
+	field = f->fmt.pix.field;
+
+	if (field == V4L2_FIELD_ANY) {
+//		field=V4L2_FIELD_INTERLACED;
+		field=V4L2_FIELD_SEQ_TB;
+	} else if (V4L2_FIELD_INTERLACED != field) {
+		dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Field type invalid.\n");
+		return -EINVAL;
+	}
+
+	tm6000_get_std_res (dev);
+
+	f->fmt.pix.width  = dev->width;
+	f->fmt.pix.height = dev->height;
+
+	f->fmt.pix.width &= ~0x01;
+
+	f->fmt.pix.field = field;
+
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * fmt->depth) >> 3;
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+	return 0;
+}
+
+/*FIXME: This seems to be generic enough to be at videodev2 */
+static int vidioc_s_fmt_vid_cap (struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct tm6000_fh  *fh=priv;
+	struct tm6000_core *dev = fh->dev;
+	int ret = vidioc_try_fmt_vid_cap(file,fh,f);
+	if (ret < 0)
+		return (ret);
+
+	fh->fmt           = format_by_fourcc(f->fmt.pix.pixelformat);
+	fh->width         = f->fmt.pix.width;
+	fh->height        = f->fmt.pix.height;
+	fh->vb_vidq.field = f->fmt.pix.field;
+	fh->type          = f->type;
+
+	dev->fourcc       = f->fmt.pix.pixelformat;
+
+	tm6000_set_fourcc_format(dev);
+
+	return (0);
+}
+
+static int vidioc_reqbufs (struct file *file, void *priv,
+			   struct v4l2_requestbuffers *p)
+{
+	struct tm6000_fh  *fh=priv;
+
+	return (videobuf_reqbufs(&fh->vb_vidq, p));
+}
+
+static int vidioc_querybuf (struct file *file, void *priv,
+			    struct v4l2_buffer *p)
+{
+	struct tm6000_fh  *fh=priv;
+
+	return (videobuf_querybuf(&fh->vb_vidq, p));
+}
+
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct tm6000_fh  *fh=priv;
+
+	return (videobuf_qbuf(&fh->vb_vidq, p));
+}
+
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct tm6000_fh  *fh=priv;
+
+	return (videobuf_dqbuf(&fh->vb_vidq, p,
+				file->f_flags & O_NONBLOCK));
+}
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+	struct tm6000_fh  *fh=priv;
+
+	return videobuf_cgmbuf (&fh->vb_vidq, mbuf, 8);
+}
+#endif
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct tm6000_fh  *fh=priv;
+	struct tm6000_core *dev    = fh->dev;
+
+	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (i != fh->type)
+		return -EINVAL;
+
+	if (!res_get(dev,fh))
+		return -EBUSY;
+	return (videobuf_streamon(&fh->vb_vidq));
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct tm6000_fh  *fh=priv;
+	struct tm6000_core *dev    = fh->dev;
+
+	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (i != fh->type)
+		return -EINVAL;
+
+	videobuf_streamoff(&fh->vb_vidq);
+	res_free(dev,fh);
+
+	return (0);
+}
+
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *norm)
+{
+	int rc=0;
+	struct tm6000_fh   *fh=priv;
+	struct tm6000_core *dev = fh->dev;
+
+	rc=tm6000_set_standard (dev, norm);
+
+	fh->width  = dev->width;
+	fh->height = dev->height;
+
+	if (rc<0)
+		return rc;
+
+	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
+
+	return 0;
+}
+
+static int vidioc_enum_input (struct file *file, void *priv,
+				struct v4l2_input *inp)
+{
+	switch (inp->index) {
+	case TM6000_INPUT_TV:
+		inp->type = V4L2_INPUT_TYPE_TUNER;
+		strcpy(inp->name,"Television");
+		break;
+	case TM6000_INPUT_COMPOSITE:
+		inp->type = V4L2_INPUT_TYPE_CAMERA;
+		strcpy(inp->name,"Composite");
+		break;
+	case TM6000_INPUT_SVIDEO:
+		inp->type = V4L2_INPUT_TYPE_CAMERA;
+		strcpy(inp->name,"S-Video");
+		break;
+	default:
+		return -EINVAL;
+	}
+	inp->std = TM6000_STD;
+
+	return 0;
+}
+
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
+{
+	struct tm6000_fh   *fh=priv;
+	struct tm6000_core *dev = fh->dev;
+
+	*i=dev->input;
+
+	return 0;
+}
+static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+{
+	struct tm6000_fh   *fh=priv;
+	struct tm6000_core *dev = fh->dev;
+	int rc=0;
+	char buf[1];
+
+	switch (i) {
+	case TM6000_INPUT_TV:
+		dev->input=i;
+		*buf=0;
+		break;
+	case TM6000_INPUT_COMPOSITE:
+	case TM6000_INPUT_SVIDEO:
+		dev->input=i;
+		*buf=1;
+		break;
+	default:
+		return -EINVAL;
+	}
+	rc=tm6000_read_write_usb (dev, USB_DIR_OUT | USB_TYPE_VENDOR,
+			       REQ_03_SET_GET_MCU_PIN, 0x03, 1, buf, 1);
+
+	if (!rc) {
+		dev->input=i;
+		rc=vidioc_s_std (file, priv, &dev->vfd->current_norm);
+	}
+
+	return (rc);
+}
+
+	/* --- controls ---------------------------------------------- */
+static int vidioc_queryctrl (struct file *file, void *priv,
+				struct v4l2_queryctrl *qc)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++)
+		if (qc->id && qc->id == tm6000_qctrl[i].id) {
+			memcpy(qc, &(tm6000_qctrl[i]),
+				sizeof(*qc));
+			return (0);
+		}
+
+	return -EINVAL;
+}
+
+static int vidioc_g_ctrl (struct file *file, void *priv,
+				struct v4l2_control *ctrl)
+{
+	struct tm6000_fh  *fh=priv;
+	struct tm6000_core *dev    = fh->dev;
+	int  val;
+
+	/* FIXME: Probably, those won't work! Maybe we need shadow regs */
+	switch (ctrl->id) {
+	case V4L2_CID_CONTRAST:
+		val = tm6000_get_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0);
+		break;
+	case V4L2_CID_BRIGHTNESS:
+		val = tm6000_get_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0);
+		return 0;
+	case V4L2_CID_SATURATION:
+		val = tm6000_get_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0);
+		return 0;
+	case V4L2_CID_HUE:
+		val = tm6000_get_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, 0);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+
+	if (val<0)
+		return val;
+
+	ctrl->value=val;
+
+	return 0;
+}
+static int vidioc_s_ctrl (struct file *file, void *priv,
+				struct v4l2_control *ctrl)
+{
+	struct tm6000_fh   *fh  =priv;
+	struct tm6000_core *dev = fh->dev;
+	u8  val=ctrl->value;
+
+	switch (ctrl->id) {
+	case V4L2_CID_CONTRAST:
+  tm6000_set_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, val);
+		return 0;
+	case V4L2_CID_BRIGHTNESS:
+  tm6000_set_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, val);
+		return 0;
+	case V4L2_CID_SATURATION:
+  tm6000_set_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, val);
+		return 0;
+	case V4L2_CID_HUE:
+  tm6000_set_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, val);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int vidioc_g_tuner (struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct tm6000_fh   *fh  =priv;
+	struct tm6000_core *dev = fh->dev;
+
+	if (unlikely(UNSET == dev->tuner_type))
+		return -EINVAL;
+	if (0 != t->index)
+		return -EINVAL;
+
+	strcpy(t->name, "Television");
+	t->type       = V4L2_TUNER_ANALOG_TV;
+	t->capability = V4L2_TUNER_CAP_NORM;
+	t->rangehigh  = 0xffffffffUL;
+	t->rxsubchans = V4L2_TUNER_SUB_MONO;
+
+	return 0;
+}
+
+static int vidioc_s_tuner (struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct tm6000_fh   *fh  =priv;
+	struct tm6000_core *dev = fh->dev;
+
+	if (UNSET == dev->tuner_type)
+		return -EINVAL;
+	if (0 != t->index)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int vidioc_g_frequency (struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct tm6000_fh   *fh  =priv;
+	struct tm6000_core *dev = fh->dev;
+
+	if (unlikely(UNSET == dev->tuner_type))
+		return -EINVAL;
+
+	f->type = V4L2_TUNER_ANALOG_TV;
+	f->frequency = dev->freq;
+
+	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f);
+
+	return 0;
+}
+
+static int vidioc_s_frequency (struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct tm6000_fh   *fh  =priv;
+	struct tm6000_core *dev = fh->dev;
+
+	if (unlikely(f->type != V4L2_TUNER_ANALOG_TV))
+		return -EINVAL;
+
+	if (unlikely(UNSET == dev->tuner_type))
+		return -EINVAL;
+	if (unlikely(f->tuner != 0))
+		return -EINVAL;
+
+//	mutex_lock(&dev->lock);
+	dev->freq = f->frequency;
+	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
+//	mutex_unlock(&dev->lock);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------
+	File operations for the device
+   ------------------------------------------------------------------*/
+
+static int tm6000_open(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct tm6000_core *dev = video_drvdata(file);
+	struct tm6000_fh *fh;
+	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	int i,rc;
+
+	printk(KERN_INFO "tm6000: open called (dev=%s)\n",
+		video_device_node_name(vdev));
+
+	dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: open called (dev=%s)\n",
+		video_device_node_name(vdev));
+
+
+	/* If more than one user, mutex should be added */
+	dev->users++;
+
+	dprintk(dev, V4L2_DEBUG_OPEN, "open dev=%s type=%s users=%d\n",
+		video_device_node_name(vdev), v4l2_type_names[type],
+		dev->users);
+
+	/* allocate + initialize per filehandle data */
+	fh = kzalloc(sizeof(*fh),GFP_KERNEL);
+	if (NULL == fh) {
+		dev->users--;
+		return -ENOMEM;
+	}
+
+	file->private_data = fh;
+	fh->dev      = dev;
+
+	fh->type     = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	dev->fourcc  = format[0].fourcc;
+
+	fh->fmt      = format_by_fourcc(dev->fourcc);
+
+	tm6000_get_std_res (dev);
+
+	fh->width    = dev->width;
+	fh->height   = dev->height;
+
+	dprintk(dev, V4L2_DEBUG_OPEN, "Open: fh=0x%08lx, dev=0x%08lx, "
+						"dev->vidq=0x%08lx\n",
+		(unsigned long)fh,(unsigned long)dev,(unsigned long)&dev->vidq);
+	dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty "
+				"queued=%d\n",list_empty(&dev->vidq.queued));
+	dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty "
+				"active=%d\n",list_empty(&dev->vidq.active));
+
+	/* initialize hardware on analog mode */
+	if (dev->mode!=TM6000_MODE_ANALOG) {
+		rc=tm6000_init_analog_mode (dev);
+		if (rc<0)
+			return rc;
+
+		/* Put all controls at a sane state */
+		for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++)
+			qctl_regs[i] =tm6000_qctrl[i].default_value;
+
+		dev->mode=TM6000_MODE_ANALOG;
+	}
+
+	videobuf_queue_vmalloc_init(&fh->vb_vidq, &tm6000_video_qops,
+			NULL, &dev->slock,
+			fh->type,
+			V4L2_FIELD_INTERLACED,
+			sizeof(struct tm6000_buffer),fh);
+
+	return 0;
+}
+
+static ssize_t
+tm6000_read(struct file *file, char __user *data, size_t count, loff_t *pos)
+{
+	struct tm6000_fh        *fh = file->private_data;
+
+	if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		if (res_locked(fh->dev))
+			return -EBUSY;
+
+		return videobuf_read_stream(&fh->vb_vidq, data, count, pos, 0,
+					file->f_flags & O_NONBLOCK);
+	}
+	return 0;
+}
+
+static unsigned int
+tm6000_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct tm6000_fh        *fh = file->private_data;
+	struct tm6000_buffer    *buf;
+
+	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+		return POLLERR;
+
+	if (res_get(fh->dev,fh)) {
+		/* streaming capture */
+		if (list_empty(&fh->vb_vidq.stream))
+			return POLLERR;
+		buf = list_entry(fh->vb_vidq.stream.next,struct tm6000_buffer,vb.stream);
+	} else {
+		/* read() capture */
+		return videobuf_poll_stream(file, &fh->vb_vidq,
+					    wait);
+	}
+	poll_wait(file, &buf->vb.done, wait);
+	if (buf->vb.state == VIDEOBUF_DONE ||
+	    buf->vb.state == VIDEOBUF_ERROR)
+		return POLLIN|POLLRDNORM;
+	return 0;
+}
+
+static int tm6000_release(struct file *file)
+{
+	struct tm6000_fh         *fh = file->private_data;
+	struct tm6000_core      *dev = fh->dev;
+	struct video_device    *vdev = video_devdata(file);
+
+	dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: close called (dev=%s, users=%d)\n",
+		video_device_node_name(vdev), dev->users);
+
+	dev->users--;
+
+	if (!dev->users) {
+		tm6000_uninit_isoc(dev);
+		videobuf_mmap_free(&fh->vb_vidq);
+	}
+
+	kfree (fh);
+
+	return 0;
+}
+
+static int tm6000_mmap(struct file *file, struct vm_area_struct * vma)
+{
+	struct tm6000_fh        *fh = file->private_data;
+	int ret;
+
+	ret=videobuf_mmap_mapper(&fh->vb_vidq, vma);
+
+	return ret;
+}
+
+static struct v4l2_file_operations tm6000_fops = {
+	.owner		= THIS_MODULE,
+	.open           = tm6000_open,
+	.release        = tm6000_release,
+	.ioctl          = video_ioctl2, /* V4L2 ioctl handler */
+	.read           = tm6000_read,
+	.poll		= tm6000_poll,
+	.mmap		= tm6000_mmap,
+};
+
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+	.vidioc_querycap          = vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
+	.vidioc_s_std             = vidioc_s_std,
+	.vidioc_enum_input        = vidioc_enum_input,
+	.vidioc_g_input           = vidioc_g_input,
+	.vidioc_s_input           = vidioc_s_input,
+	.vidioc_queryctrl         = vidioc_queryctrl,
+	.vidioc_g_ctrl            = vidioc_g_ctrl,
+	.vidioc_s_ctrl            = vidioc_s_ctrl,
+	.vidioc_g_tuner           = vidioc_g_tuner,
+	.vidioc_s_tuner           = vidioc_s_tuner,
+	.vidioc_g_frequency       = vidioc_g_frequency,
+	.vidioc_s_frequency       = vidioc_s_frequency,
+	.vidioc_streamon          = vidioc_streamon,
+	.vidioc_streamoff         = vidioc_streamoff,
+	.vidioc_reqbufs           = vidioc_reqbufs,
+	.vidioc_querybuf          = vidioc_querybuf,
+	.vidioc_qbuf              = vidioc_qbuf,
+	.vidioc_dqbuf             = vidioc_dqbuf,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+	.vidiocgmbuf              = vidiocgmbuf,
+#endif
+};
+
+static struct video_device tm6000_template = {
+	.name		= "tm6000",
+	.fops           = &tm6000_fops,
+	.ioctl_ops      = &video_ioctl_ops,
+	.release	= video_device_release,
+	.tvnorms        = TM6000_STD,
+	.current_norm   = V4L2_STD_NTSC_M,
+};
+
+/* -----------------------------------------------------------------
+	Initialization and module stuff
+   ------------------------------------------------------------------*/
+
+int tm6000_v4l2_register(struct tm6000_core *dev)
+{
+	int ret = -1;
+	struct video_device *vfd;
+
+	vfd = video_device_alloc();
+	if(!vfd) {
+		return -ENOMEM;
+	}
+	dev->vfd = vfd;
+
+	/* init video dma queues */
+	INIT_LIST_HEAD(&dev->vidq.active);
+	INIT_LIST_HEAD(&dev->vidq.queued);
+
+	memcpy (dev->vfd, &tm6000_template, sizeof(*(dev->vfd)));
+	dev->vfd->debug=tm6000_debug;
+	vfd->v4l2_dev = &dev->v4l2_dev;
+	video_set_drvdata(vfd, dev);
+
+	ret = video_register_device(dev->vfd, VFL_TYPE_GRABBER, video_nr);
+	printk(KERN_INFO "Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d)\n", ret);
+	return ret;
+}
+
+int tm6000_v4l2_unregister(struct tm6000_core *dev)
+{
+	video_unregister_device(dev->vfd);
+
+	return 0;
+}
+
+int tm6000_v4l2_exit(void)
+{
+	return 0;
+}
+
+module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr,"Allow changing video device number");
+
+module_param_named (debug, tm6000_debug, int, 0444);
+MODULE_PARM_DESC(debug,"activates debug info");
+
+module_param(vid_limit,int,0644);
+MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
+
diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h
new file mode 100644
index 0000000..6812d68
--- /dev/null
+++ b/drivers/staging/tm6000/tm6000.h
@@ -0,0 +1,301 @@
+/*
+   tm6000.h - driver for TM5600/TM6000/TM6010 USB video capture devices
+
+   Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+
+   Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
+	- DVB-T support
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation version 2
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+// Use the tm6000-hack, instead of the proper initialization code
+//#define HACK 1
+
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/videobuf-vmalloc.h>
+#include "tm6000-usb-isoc.h"
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <media/v4l2-device.h>
+
+
+#include <linux/dvb/frontend.h>
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dmxdev.h"
+
+#define TM6000_VERSION KERNEL_VERSION(0, 0, 2)
+
+/* Inputs */
+
+enum tm6000_itype {
+	TM6000_INPUT_TV	= 0,
+	TM6000_INPUT_COMPOSITE,
+	TM6000_INPUT_SVIDEO,
+};
+
+enum tm6000_devtype {
+	TM6000 = 0,
+	TM5600,
+	TM6010,
+};
+
+/* ------------------------------------------------------------------
+	Basic structures
+   ------------------------------------------------------------------*/
+
+struct tm6000_fmt {
+	char  *name;
+	u32   fourcc;          /* v4l2 format id */
+	int   depth;
+};
+
+/* buffer for one video frame */
+struct tm6000_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer vb;
+
+	struct tm6000_fmt      *fmt;
+};
+
+struct tm6000_dmaqueue {
+	struct list_head       active;
+	struct list_head       queued;
+
+	/* thread for generating video stream*/
+	struct task_struct         *kthread;
+	wait_queue_head_t          wq;
+	/* Counters to control fps rate */
+	int                        frame;
+	int                        ini_jiffies;
+};
+
+/* device states */
+enum tm6000_core_state {
+	DEV_INITIALIZED   = 0x01,
+	DEV_DISCONNECTED  = 0x02,
+	DEV_MISCONFIGURED = 0x04,
+};
+
+/* io methods */
+enum tm6000_io_method {
+	IO_NONE,
+	IO_READ,
+	IO_MMAP,
+};
+
+enum tm6000_mode {
+	TM6000_MODE_UNKNOWN=0,
+	TM6000_MODE_ANALOG,
+	TM6000_MODE_DIGITAL,
+};
+
+struct tm6000_gpio {
+	int		tuner_reset;
+	int		tuner_on;
+	int		demod_reset;
+	int		demod_on;
+	int		power_led;
+	int		dvb_led;
+	int		ir;
+};
+
+struct tm6000_capabilities {
+	unsigned int    has_tuner:1;
+	unsigned int    has_tda9874:1;
+	unsigned int    has_dvb:1;
+	unsigned int    has_zl10353:1;
+	unsigned int    has_eeprom:1;
+	unsigned int    has_remote:1;
+};
+
+struct tm6000_dvb {
+	struct dvb_adapter	adapter;
+	struct dvb_demux	demux;
+	struct dvb_frontend	*frontend;
+	struct dmxdev		dmxdev;
+	unsigned int		streams;
+	struct urb 		*bulk_urb;
+	struct mutex		mutex;
+};
+
+struct tm6000_endpoint {
+	struct usb_host_endpoint	*endp;
+	__u8				bInterfaceNumber;
+	__u8				bAlternateSetting;
+	unsigned			maxsize;
+};
+
+struct tm6000_core {
+	/* generic device properties */
+	char				name[30];	/* name (including minor) of the device */
+	int				model;		/* index in the device_data struct */
+	int				devno;		/* marks the number of this device */
+	enum tm6000_devtype		dev_type;	/* type of device */
+
+	v4l2_std_id                     norm;           /* Current norm */
+	int				width,height;	/* Selected resolution */
+
+	enum tm6000_core_state		state;
+
+	/* Device Capabilities*/
+	struct tm6000_capabilities	caps;
+
+	/* Tuner configuration */
+	int				tuner_type;		/* type of the tuner */
+	int				tuner_addr;		/* tuner address */
+
+	struct tm6000_gpio		gpio;
+
+	/* Demodulator configuration */
+	int				demod_addr;	/* demodulator address */
+
+	int				audio_bitrate;
+	/* i2c i/o */
+	struct i2c_adapter		i2c_adap;
+	struct i2c_client		i2c_client;
+
+	/* video for linux */
+	int				users;
+
+	/* various device info */
+	unsigned int			resources;
+	struct video_device		*vfd;
+	struct tm6000_dmaqueue		vidq;
+	struct v4l2_device		v4l2_dev;
+
+	int				input;
+	int				freq;
+	unsigned int			fourcc;
+
+	enum tm6000_mode		mode;
+
+	/* DVB-T support */
+	struct tm6000_dvb		*dvb;
+
+	/* locks */
+	struct mutex			lock;
+
+	/* usb transfer */
+	struct usb_device		*udev;		/* the usb device */
+
+	struct tm6000_endpoint		bulk_in, bulk_out, isoc_in, isoc_out;
+
+	/* scaler!=0 if scaler is active*/
+	int				scaler;
+
+		/* Isoc control struct */
+	struct usb_isoc_ctl          isoc_ctl;
+
+	spinlock_t                   slock;
+};
+
+struct tm6000_fh {
+	struct tm6000_core           *dev;
+
+	/* video capture */
+	struct tm6000_fmt            *fmt;
+	unsigned int                 width,height;
+	struct videobuf_queue        vb_vidq;
+
+	enum v4l2_buf_type           type;
+};
+
+#define TM6000_STD	V4L2_STD_PAL|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|    \
+			V4L2_STD_PAL_M|V4L2_STD_PAL_60|V4L2_STD_NTSC_M| \
+			V4L2_STD_NTSC_M_JP|V4L2_STD_SECAM
+
+/* In tm6000-cards.c */
+
+int tm6000_tuner_callback (void *ptr, int component, int command, int arg);
+int tm6000_xc5000_callback (void *ptr, int component, int command, int arg);
+int tm6000_cards_setup(struct tm6000_core *dev);
+
+/* In tm6000-core.c */
+
+int tm6000_read_write_usb (struct tm6000_core *dev, u8 reqtype, u8 req,
+			   u16 value, u16 index, u8 *buf, u16 len);
+int tm6000_get_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index);
+int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index);
+int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index);
+int tm6000_set_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index);
+int tm6000_init (struct tm6000_core *dev);
+
+int tm6000_init_analog_mode (struct tm6000_core *dev);
+int tm6000_init_digital_mode (struct tm6000_core *dev);
+int tm6000_set_audio_bitrate (struct tm6000_core *dev, int bitrate);
+
+int tm6000_dvb_register(struct tm6000_core *dev);
+void tm6000_dvb_unregister(struct tm6000_core *dev);
+
+int tm6000_v4l2_register(struct tm6000_core *dev);
+int tm6000_v4l2_unregister(struct tm6000_core *dev);
+int tm6000_v4l2_exit(void);
+void tm6000_set_fourcc_format(struct tm6000_core *dev);
+
+/* In tm6000-stds.c */
+void tm6000_get_std_res(struct tm6000_core *dev);
+int tm6000_set_standard (struct tm6000_core *dev, v4l2_std_id *norm);
+
+/* In tm6000-i2c.c */
+int tm6000_i2c_register(struct tm6000_core *dev);
+int tm6000_i2c_unregister(struct tm6000_core *dev);
+
+/* In tm6000-queue.c */
+
+int tm6000_v4l2_mmap(struct file *filp, struct vm_area_struct *vma);
+
+int tm6000_vidioc_streamon(struct file *file, void *priv,
+			   enum v4l2_buf_type i);
+int tm6000_vidioc_streamoff(struct file *file, void *priv,
+			    enum v4l2_buf_type i);
+int tm6000_vidioc_reqbufs (struct file *file, void *priv,
+			   struct v4l2_requestbuffers *rb);
+int tm6000_vidioc_querybuf (struct file *file, void *priv,
+			    struct v4l2_buffer *b);
+int tm6000_vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *b);
+int tm6000_vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *b);
+ssize_t tm6000_v4l2_read(struct file *filp, char __user * buf, size_t count,
+			 loff_t * f_pos);
+unsigned int tm6000_v4l2_poll(struct file *file,
+			      struct poll_table_struct *wait);
+int tm6000_queue_init(struct tm6000_core *dev);
+
+/* In tm6000-alsa.c */
+int tm6000_audio_init(struct tm6000_core *dev, int idx);
+
+
+/* Debug stuff */
+
+extern int tm6000_debug;
+
+#define dprintk(dev, level, fmt, arg...) do {\
+	if (tm6000_debug & level) \
+		printk(KERN_INFO "(%lu) %s %s :"fmt, jiffies, 		\
+			 dev->name, __FUNCTION__ , ##arg); } while (0)
+
+#define V4L2_DEBUG_REG		0x0004
+#define V4L2_DEBUG_I2C		0x0008
+#define V4L2_DEBUG_QUEUE	0x0010
+#define V4L2_DEBUG_ISOC		0x0020
+#define V4L2_DEBUG_RES_LOCK	0x0040	/* Resource locking */
+#define V4L2_DEBUG_OPEN		0x0080	/* video open/close debug */
+
+#define tm6000_err(fmt, arg...) do {\
+	printk(KERN_ERR "tm6000 %s :"fmt, \
+		__FUNCTION__ , ##arg); } while (0)
+
+
diff --git a/include/linux/meye.h b/include/linux/meye.h
index 12010ac..0dd4995 100644
--- a/include/linux/meye.h
+++ b/include/linux/meye.h
@@ -44,17 +44,17 @@
 };
 
 /* query the extended parameters */
-#define MEYEIOC_G_PARAMS	_IOR ('v', BASE_VIDIOCPRIVATE+0, struct meye_params)
+#define MEYEIOC_G_PARAMS	_IOR ('v', BASE_VIDIOC_PRIVATE+0, struct meye_params)
 /* set the extended parameters */
-#define MEYEIOC_S_PARAMS	_IOW ('v', BASE_VIDIOCPRIVATE+1, struct meye_params)
+#define MEYEIOC_S_PARAMS	_IOW ('v', BASE_VIDIOC_PRIVATE+1, struct meye_params)
 /* queue a buffer for mjpeg capture */
-#define MEYEIOC_QBUF_CAPT	_IOW ('v', BASE_VIDIOCPRIVATE+2, int)
+#define MEYEIOC_QBUF_CAPT	_IOW ('v', BASE_VIDIOC_PRIVATE+2, int)
 /* sync a previously queued mjpeg buffer */
-#define MEYEIOC_SYNC		_IOWR('v', BASE_VIDIOCPRIVATE+3, int)
+#define MEYEIOC_SYNC		_IOWR('v', BASE_VIDIOC_PRIVATE+3, int)
 /* get a still uncompressed snapshot */
-#define MEYEIOC_STILLCAPT	_IO  ('v', BASE_VIDIOCPRIVATE+4)
+#define MEYEIOC_STILLCAPT	_IO  ('v', BASE_VIDIOC_PRIVATE+4)
 /* get a jpeg compressed snapshot */
-#define MEYEIOC_STILLJCAPT	_IOR ('v', BASE_VIDIOCPRIVATE+5, int)
+#define MEYEIOC_STILLJCAPT	_IOR ('v', BASE_VIDIOC_PRIVATE+5, int)
 
 /* V4L2 private controls */
 #define V4L2_CID_AGC		V4L2_CID_PRIVATE_BASE
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 3793d16..047f7e6 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -160,16 +160,6 @@
 	V4L2_BUF_TYPE_PRIVATE              = 0x80,
 };
 
-enum v4l2_ctrl_type {
-	V4L2_CTRL_TYPE_INTEGER	     = 1,
-	V4L2_CTRL_TYPE_BOOLEAN	     = 2,
-	V4L2_CTRL_TYPE_MENU	     = 3,
-	V4L2_CTRL_TYPE_BUTTON	     = 4,
-	V4L2_CTRL_TYPE_INTEGER64     = 5,
-	V4L2_CTRL_TYPE_CTRL_CLASS    = 6,
-	V4L2_CTRL_TYPE_STRING        = 7,
-};
-
 enum v4l2_tuner_type {
 	V4L2_TUNER_RADIO	     = 1,
 	V4L2_TUNER_ANALOG_TV	     = 2,
@@ -294,6 +284,8 @@
 
 /* Grey formats */
 #define V4L2_PIX_FMT_GREY    v4l2_fourcc('G', 'R', 'E', 'Y') /*  8  Greyscale     */
+#define V4L2_PIX_FMT_Y4      v4l2_fourcc('Y', '0', '4', ' ') /*  4  Greyscale     */
+#define V4L2_PIX_FMT_Y6      v4l2_fourcc('Y', '0', '6', ' ') /*  6  Greyscale     */
 #define V4L2_PIX_FMT_Y10     v4l2_fourcc('Y', '1', '0', ' ') /* 10  Greyscale     */
 #define V4L2_PIX_FMT_Y16     v4l2_fourcc('Y', '1', '6', ' ') /* 16  Greyscale     */
 
@@ -369,6 +361,7 @@
 #define V4L2_PIX_FMT_OV511    v4l2_fourcc('O', '5', '1', '1') /* ov511 JPEG */
 #define V4L2_PIX_FMT_OV518    v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */
 #define V4L2_PIX_FMT_STV0680  v4l2_fourcc('S', '6', '8', '0') /* stv0680 bayer */
+#define V4L2_PIX_FMT_TM6000   v4l2_fourcc('T', 'M', '6', '0') /* tm5600/tm60x0 */
 
 /*
  *	F O R M A T   E N U M E R A T I O N
@@ -549,6 +542,8 @@
 #define V4L2_BUF_FLAG_KEYFRAME	0x0008	/* Image is a keyframe (I-frame) */
 #define V4L2_BUF_FLAG_PFRAME	0x0010	/* Image is a P-frame */
 #define V4L2_BUF_FLAG_BFRAME	0x0020	/* Image is a B-frame */
+/* Buffer is ready, but the data contained within is corrupted. */
+#define V4L2_BUF_FLAG_ERROR	0x0040
 #define V4L2_BUF_FLAG_TIMECODE	0x0100	/* timecode field is valid */
 #define V4L2_BUF_FLAG_INPUT     0x0200  /* input field is valid */
 
@@ -939,6 +934,16 @@
 #define V4L2_CTRL_ID2CLASS(id)    ((id) & 0x0fff0000UL)
 #define V4L2_CTRL_DRIVER_PRIV(id) (((id) & 0xffff) >= 0x1000)
 
+enum v4l2_ctrl_type {
+	V4L2_CTRL_TYPE_INTEGER	     = 1,
+	V4L2_CTRL_TYPE_BOOLEAN	     = 2,
+	V4L2_CTRL_TYPE_MENU	     = 3,
+	V4L2_CTRL_TYPE_BUTTON	     = 4,
+	V4L2_CTRL_TYPE_INTEGER64     = 5,
+	V4L2_CTRL_TYPE_CTRL_CLASS    = 6,
+	V4L2_CTRL_TYPE_STRING        = 7,
+};
+
 /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
 struct v4l2_queryctrl {
 	__u32		     id;
@@ -1023,14 +1028,24 @@
 	V4L2_COLORFX_NONE	= 0,
 	V4L2_COLORFX_BW		= 1,
 	V4L2_COLORFX_SEPIA	= 2,
+	V4L2_COLORFX_NEGATIVE = 3,
+	V4L2_COLORFX_EMBOSS = 4,
+	V4L2_COLORFX_SKETCH = 5,
+	V4L2_COLORFX_SKY_BLUE = 6,
+	V4L2_COLORFX_GRASS_GREEN = 7,
+	V4L2_COLORFX_SKIN_WHITEN = 8,
+	V4L2_COLORFX_VIVID = 9,
 };
 #define V4L2_CID_AUTOBRIGHTNESS			(V4L2_CID_BASE+32)
 #define V4L2_CID_BAND_STOP_FILTER		(V4L2_CID_BASE+33)
 
 #define V4L2_CID_ROTATE				(V4L2_CID_BASE+34)
 #define V4L2_CID_BG_COLOR			(V4L2_CID_BASE+35)
+
+#define V4L2_CID_CHROMA_GAIN                    (V4L2_CID_BASE+36)
+
 /* last CID + 1 */
-#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+36)
+#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+37)
 
 /*  MPEG-class control IDs defined by V4L2 */
 #define V4L2_CID_MPEG_BASE 			(V4L2_CTRL_CLASS_MPEG | 0x900)
@@ -1276,6 +1291,9 @@
 
 #define V4L2_CID_PRIVACY			(V4L2_CID_CAMERA_CLASS_BASE+16)
 
+#define V4L2_CID_IRIS_ABSOLUTE			(V4L2_CID_CAMERA_CLASS_BASE+17)
+#define V4L2_CID_IRIS_RELATIVE			(V4L2_CID_CAMERA_CLASS_BASE+18)
+
 /* FM Modulator class control IDs */
 #define V4L2_CID_FM_TX_CLASS_BASE		(V4L2_CTRL_CLASS_FM_TX | 0x900)
 #define V4L2_CID_FM_TX_CLASS			(V4L2_CTRL_CLASS_FM_TX | 1)
@@ -1621,6 +1639,38 @@
 };
 
 /*
+ *	E V E N T S
+ */
+
+#define V4L2_EVENT_ALL				0
+#define V4L2_EVENT_VSYNC			1
+#define V4L2_EVENT_EOS				2
+#define V4L2_EVENT_PRIVATE_START		0x08000000
+
+/* Payload for V4L2_EVENT_VSYNC */
+struct v4l2_event_vsync {
+	/* Can be V4L2_FIELD_ANY, _NONE, _TOP or _BOTTOM */
+	__u8 field;
+} __attribute__ ((packed));
+
+struct v4l2_event {
+	__u32				type;
+	union {
+		struct v4l2_event_vsync vsync;
+		__u8			data[64];
+	} u;
+	__u32				pending;
+	__u32				sequence;
+	struct timespec			timestamp;
+	__u32				reserved[9];
+};
+
+struct v4l2_event_subscription {
+	__u32				type;
+	__u32				reserved[7];
+};
+
+/*
  *	A D V A N C E D   D E B U G G I N G
  *
  *	NOTE: EXPERIMENTAL API, NEVER RELY ON THIS IN APPLICATIONS!
@@ -1742,6 +1792,9 @@
 #define	VIDIOC_QUERY_DV_PRESET	_IOR('V',  86, struct v4l2_dv_preset)
 #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)
 
 /* Reminder: when adding new ioctls please add support for them to
    drivers/media/video/v4l2-compat-ioctl32.c as well! */
diff --git a/include/media/ak881x.h b/include/media/ak881x.h
new file mode 100644
index 0000000..b7f2add
--- /dev/null
+++ b/include/media/ak881x.h
@@ -0,0 +1,25 @@
+/*
+ * Header for AK8813 / AK8814 TV-ecoders from Asahi Kasei Microsystems Co., Ltd. (AKM)
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef AK881X_H
+#define AK881X_H
+
+#define AK881X_IF_MODE_MASK	(3 << 0)
+#define AK881X_IF_MODE_BT656	(0 << 0)
+#define AK881X_IF_MODE_MASTER	(1 << 0)
+#define AK881X_IF_MODE_SLAVE	(2 << 0)
+#define AK881X_FIELD		(1 << 2)
+#define AK881X_COMPONENT	(1 << 3)
+
+struct ak881x_pdata {
+	unsigned long flags;
+};
+
+#endif
diff --git a/include/media/davinci/vpfe_capture.h b/include/media/davinci/vpfe_capture.h
index 4314a5f..cc973ed 100644
--- a/include/media/davinci/vpfe_capture.h
+++ b/include/media/davinci/vpfe_capture.h
@@ -94,6 +94,8 @@
 	/* vpfe clock */
 	struct clk *vpssclk;
 	struct clk *slaveclk;
+	/* Function for Clearing the interrupt */
+	void (*clr_intr)(int vdint);
 };
 
 struct vpfe_device {
diff --git a/include/media/ir-common.h b/include/media/ir-common.h
index c662980..528050e 100644
--- a/include/media/ir-common.h
+++ b/include/media/ir-common.h
@@ -50,6 +50,10 @@
 	struct ir_input_state   ir;
 	char                    name[32];
 	char                    phys[32];
+	int			users;
+
+	u32			running:1;
+	struct ir_dev_props	props;
 
 	/* Usual gpio signalling */
 
@@ -79,6 +83,9 @@
 	/* NEC decoding */
 	u32			nec_gpio;
 	struct tasklet_struct   tlet;
+
+	/* IR core raw decoding */
+	u32			raw_decode;
 };
 
 /* Routines from ir-functions.c */
@@ -97,71 +104,4 @@
 void ir_rc5_timer_end(unsigned long data);
 void ir_rc5_timer_keyup(unsigned long data);
 
-/* scancode->keycode map tables from ir-keymaps.c */
-
-extern struct ir_scancode_table ir_codes_empty_table;
-extern struct ir_scancode_table ir_codes_avermedia_table;
-extern struct ir_scancode_table ir_codes_avermedia_dvbt_table;
-extern struct ir_scancode_table ir_codes_avermedia_m135a_table;
-extern struct ir_scancode_table ir_codes_avermedia_cardbus_table;
-extern struct ir_scancode_table ir_codes_apac_viewcomp_table;
-extern struct ir_scancode_table ir_codes_pixelview_table;
-extern struct ir_scancode_table ir_codes_pixelview_new_table;
-extern struct ir_scancode_table ir_codes_nebula_table;
-extern struct ir_scancode_table ir_codes_dntv_live_dvb_t_table;
-extern struct ir_scancode_table ir_codes_iodata_bctv7e_table;
-extern struct ir_scancode_table ir_codes_adstech_dvb_t_pci_table;
-extern struct ir_scancode_table ir_codes_msi_tvanywhere_table;
-extern struct ir_scancode_table ir_codes_cinergy_1400_table;
-extern struct ir_scancode_table ir_codes_avertv_303_table;
-extern struct ir_scancode_table ir_codes_dntv_live_dvbt_pro_table;
-extern struct ir_scancode_table ir_codes_em_terratec_table;
-extern struct ir_scancode_table ir_codes_pinnacle_grey_table;
-extern struct ir_scancode_table ir_codes_flyvideo_table;
-extern struct ir_scancode_table ir_codes_flydvb_table;
-extern struct ir_scancode_table ir_codes_cinergy_table;
-extern struct ir_scancode_table ir_codes_eztv_table;
-extern struct ir_scancode_table ir_codes_avermedia_table;
-extern struct ir_scancode_table ir_codes_videomate_tv_pvr_table;
-extern struct ir_scancode_table ir_codes_manli_table;
-extern struct ir_scancode_table ir_codes_gotview7135_table;
-extern struct ir_scancode_table ir_codes_purpletv_table;
-extern struct ir_scancode_table ir_codes_pctv_sedna_table;
-extern struct ir_scancode_table ir_codes_pv951_table;
-extern struct ir_scancode_table ir_codes_rc5_tv_table;
-extern struct ir_scancode_table ir_codes_winfast_table;
-extern struct ir_scancode_table ir_codes_pinnacle_color_table;
-extern struct ir_scancode_table ir_codes_hauppauge_new_table;
-extern struct ir_scancode_table ir_codes_rc5_hauppauge_new_table;
-extern struct ir_scancode_table ir_codes_npgtech_table;
-extern struct ir_scancode_table ir_codes_norwood_table;
-extern struct ir_scancode_table ir_codes_proteus_2309_table;
-extern struct ir_scancode_table ir_codes_budget_ci_old_table;
-extern struct ir_scancode_table ir_codes_asus_pc39_table;
-extern struct ir_scancode_table ir_codes_encore_enltv_table;
-extern struct ir_scancode_table ir_codes_encore_enltv2_table;
-extern struct ir_scancode_table ir_codes_tt_1500_table;
-extern struct ir_scancode_table ir_codes_fusionhdtv_mce_table;
-extern struct ir_scancode_table ir_codes_behold_table;
-extern struct ir_scancode_table ir_codes_behold_columbus_table;
-extern struct ir_scancode_table ir_codes_pinnacle_pctv_hd_table;
-extern struct ir_scancode_table ir_codes_genius_tvgo_a11mce_table;
-extern struct ir_scancode_table ir_codes_powercolor_real_angel_table;
-extern struct ir_scancode_table ir_codes_avermedia_a16d_table;
-extern struct ir_scancode_table ir_codes_encore_enltv_fm53_table;
-extern struct ir_scancode_table ir_codes_real_audio_220_32_keys_table;
-extern struct ir_scancode_table ir_codes_msi_tvanywhere_plus_table;
-extern struct ir_scancode_table ir_codes_ati_tv_wonder_hd_600_table;
-extern struct ir_scancode_table ir_codes_kworld_plus_tv_analog_table;
-extern struct ir_scancode_table ir_codes_kaiomy_table;
-extern struct ir_scancode_table ir_codes_dm1105_nec_table;
-extern struct ir_scancode_table ir_codes_tevii_nec_table;
-extern struct ir_scancode_table ir_codes_tbs_nec_table;
-extern struct ir_scancode_table ir_codes_evga_indtube_table;
-extern struct ir_scancode_table ir_codes_terratec_cinergy_xs_table;
-extern struct ir_scancode_table ir_codes_videomate_s350_table;
-extern struct ir_scancode_table ir_codes_gadmei_rm008z_table;
-extern struct ir_scancode_table ir_codes_nec_terratec_cinergy_xs_table;
-extern struct ir_scancode_table ir_codes_winfast_usbii_deluxe_table;
-extern struct ir_scancode_table ir_codes_kworld_315u_table;
 #endif
diff --git a/include/media/ir-core.h b/include/media/ir-core.h
index 61c223b..ad1303f 100644
--- a/include/media/ir-core.h
+++ b/include/media/ir-core.h
@@ -1,6 +1,8 @@
 /*
  * Remote Controller core header
  *
+ * Copyright (C) 2009-2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
  * This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation version 2 of the License.
@@ -14,61 +16,133 @@
 #ifndef _IR_CORE
 #define _IR_CORE
 
-#include <linux/input.h>
 #include <linux/spinlock.h>
+#include <linux/kfifo.h>
+#include <linux/time.h>
+#include <linux/timer.h>
+#include <media/rc-map.h>
 
 extern int ir_core_debug;
 #define IR_dprintk(level, fmt, arg...)	if (ir_core_debug >= level) \
 	printk(KERN_DEBUG "%s: " fmt , __func__, ## arg)
 
-#define IR_TYPE_UNKNOWN	0
-#define IR_TYPE_RC5	(1  << 0)	/* Philips RC5 protocol */
-#define IR_TYPE_PD	(1  << 1)	/* Pulse distance encoded IR */
-#define IR_TYPE_NEC	(1  << 2)
-#define IR_TYPE_OTHER	(((u64)1) << 63l)
-
-struct ir_scancode {
-	u16	scancode;
-	u32	keycode;
+enum rc_driver_type {
+	RC_DRIVER_SCANCODE = 0,	/* Driver or hardware generates a scancode */
+	RC_DRIVER_IR_RAW,	/* Needs a Infra-Red pulse/space decoder */
 };
 
-struct ir_scancode_table {
-	struct ir_scancode	*scan;
-	int			size;
-	u64		ir_type;
-	spinlock_t		lock;
-};
-
+/**
+ * struct ir_dev_props - Allow caller drivers to set special properties
+ * @driver_type: specifies if the driver or hardware have already a decoder,
+ *	or if it needs to use the IR raw event decoders to produce a scancode
+ * @allowed_protos: bitmask with the supported IR_TYPE_* protocols
+ * @scanmask: some hardware decoders are not capable of providing the full
+ *	scancode to the application. As this is a hardware limit, we can't do
+ *	anything with it. Yet, as the same keycode table can be used with other
+ *	devices, a mask is provided to allow its usage. Drivers should generally
+ *	leave this field in blank
+ * @priv: driver-specific data, to be used on the callbacks
+ * @change_protocol: allow changing the protocol used on hardware decoders
+ * @open: callback to allow drivers to enable polling/irq when IR input device
+ *	is opened.
+ * @close: callback to allow drivers to disable polling/irq when IR input device
+ *	is opened.
+ */
 struct ir_dev_props {
-	unsigned long allowed_protos;
-	void 		*priv;
-	int (*change_protocol)(void *priv, u64 ir_type);
+	enum rc_driver_type	driver_type;
+	unsigned long		allowed_protos;
+	u32			scanmask;
+	void 			*priv;
+	int			(*change_protocol)(void *priv, u64 ir_type);
+	int			(*open)(void *priv);
+	void			(*close)(void *priv);
 };
 
-
 struct ir_input_dev {
-	struct input_dev		*dev;		/* Input device*/
+	struct device			dev;		/* device */
+	char				*driver_name;	/* Name of the driver module */
 	struct ir_scancode_table	rc_tab;		/* scan/key table */
 	unsigned long			devno;		/* device number */
-	struct attribute_group		attr;		/* IR attributes */
-	struct device			*class_dev;	/* virtual class dev */
 	const struct ir_dev_props	*props;		/* Device properties */
+	struct ir_raw_event_ctrl	*raw;		/* for raw pulse/space events */
+	struct input_dev		*input_dev;	/* the input device associated with this device */
+
+	/* key info - needed by IR keycode handlers */
+	spinlock_t			keylock;	/* protects the below members */
+	bool				keypressed;	/* current state */
+	unsigned long			keyup_jiffies;	/* when should the current keypress be released? */
+	struct timer_list		timer_keyup;	/* timer for releasing a keypress */
+	u32				last_keycode;	/* keycode of last command */
+	u32				last_scancode;	/* scancode of last command */
+	u8				last_toggle;	/* toggle of last command */
 };
+
+enum raw_event_type {
+	IR_SPACE        = (1 << 0),
+	IR_PULSE        = (1 << 1),
+	IR_START_EVENT  = (1 << 2),
+	IR_STOP_EVENT   = (1 << 3),
+};
+
 #define to_ir_input_dev(_attr) container_of(_attr, struct ir_input_dev, attr)
 
-/* Routines from ir-keytable.c */
-
-u32 ir_g_keycode_from_table(struct input_dev *input_dev,
-			    u32 scancode);
-
-int ir_input_register(struct input_dev *dev,
+/* From ir-keytable.c */
+int __ir_input_register(struct input_dev *dev,
 		      const struct ir_scancode_table *ir_codes,
-		      const struct ir_dev_props *props);
+		      const struct ir_dev_props *props,
+		      const char *driver_name);
+
+static inline int ir_input_register(struct input_dev *dev,
+		      const char *map_name,
+		      const struct ir_dev_props *props,
+		      const char *driver_name) {
+	struct ir_scancode_table *ir_codes;
+	struct ir_input_dev *ir_dev;
+	int rc;
+
+	if (!map_name)
+		return -EINVAL;
+
+	ir_codes = get_rc_map(map_name);
+	if (!ir_codes)
+		return -EINVAL;
+
+	rc = __ir_input_register(dev, ir_codes, props, driver_name);
+	if (rc < 0)
+		return -EINVAL;
+
+	ir_dev = input_get_drvdata(dev);
+
+	if (!rc && ir_dev->props && ir_dev->props->change_protocol)
+		rc = ir_dev->props->change_protocol(ir_dev->props->priv,
+						    ir_codes->ir_type);
+
+	return rc;
+}
+
 void ir_input_unregister(struct input_dev *input_dev);
 
-/* Routines from ir-sysfs.c */
+void ir_repeat(struct input_dev *dev);
+void ir_keydown(struct input_dev *dev, int scancode, u8 toggle);
+u32 ir_g_keycode_from_table(struct input_dev *input_dev, u32 scancode);
 
-int ir_register_class(struct input_dev *input_dev);
-void ir_unregister_class(struct input_dev *input_dev);
+/* From ir-raw-event.c */
 
-#endif
+struct ir_raw_event {
+	unsigned                        pulse:1;
+	unsigned                        duration:31;
+};
+
+#define IR_MAX_DURATION                 0x7FFFFFFF      /* a bit more than 2 seconds */
+
+void ir_raw_event_handle(struct input_dev *input_dev);
+int ir_raw_event_store(struct input_dev *input_dev, struct ir_raw_event *ev);
+int ir_raw_event_store_edge(struct input_dev *input_dev, enum raw_event_type type);
+static inline void ir_raw_event_reset(struct input_dev *input_dev)
+{
+	struct ir_raw_event ev = { .pulse = false, .duration = 0 };
+	ir_raw_event_store(input_dev, &ev);
+	ir_raw_event_handle(input_dev);
+}
+
+#endif /* _IR_CORE */
diff --git a/include/media/ir-kbd-i2c.h b/include/media/ir-kbd-i2c.h
index 9142936..0506e45 100644
--- a/include/media/ir-kbd-i2c.h
+++ b/include/media/ir-kbd-i2c.h
@@ -6,7 +6,7 @@
 struct IR_i2c;
 
 struct IR_i2c {
-	struct ir_scancode_table *ir_codes;
+	char		       *ir_codes;
 
 	struct i2c_client      *c;
 	struct input_dev       *input;
@@ -34,9 +34,9 @@
 
 /* Can be passed when instantiating an ir_video i2c device */
 struct IR_i2c_init_data {
-	struct ir_scancode_table *ir_codes;
+	char			*ir_codes;
 	const char             *name;
-	u64          type; /* IR_TYPE_RC5, IR_TYPE_PD, etc */
+	u64          type; /* IR_TYPE_RC5, etc */
 	/*
 	 * Specify either a function pointer or a value indicating one of
 	 * ir_kbd_i2c's internal get_key functions
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
new file mode 100644
index 0000000..5833966
--- /dev/null
+++ b/include/media/rc-map.h
@@ -0,0 +1,121 @@
+/*
+ * rc-map.h - define RC map names used by RC drivers
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/input.h>
+
+#define IR_TYPE_UNKNOWN	0
+#define IR_TYPE_RC5	(1  << 0)	/* Philips RC5 protocol */
+#define IR_TYPE_NEC	(1  << 1)
+#define IR_TYPE_RC6	(1  << 2)	/* Philips RC6 protocol */
+#define IR_TYPE_JVC	(1  << 3)	/* JVC protocol */
+#define IR_TYPE_SONY	(1  << 4)	/* Sony12/15/20 protocol */
+#define IR_TYPE_OTHER	(1u << 31)
+
+struct ir_scancode {
+	u32	scancode;
+	u32	keycode;
+};
+
+struct ir_scancode_table {
+	struct ir_scancode	*scan;
+	unsigned int		size;	/* Max number of entries */
+	unsigned int		len;	/* Used number of entries */
+	unsigned int		alloc;	/* Size of *scan in bytes */
+	u64			ir_type;
+	char			*name;
+	spinlock_t		lock;
+};
+
+struct rc_keymap {
+	struct list_head	 list;
+	struct ir_scancode_table map;
+};
+
+/* Routines from rc-map.c */
+
+int ir_register_map(struct rc_keymap *map);
+void ir_unregister_map(struct rc_keymap *map);
+struct ir_scancode_table *get_rc_map(const char *name);
+void rc_map_init(void);
+
+/* Names of the several keytables defined in-kernel */
+
+#define RC_MAP_ADSTECH_DVB_T_PCI         "rc-adstech-dvb-t-pci"
+#define RC_MAP_APAC_VIEWCOMP             "rc-apac-viewcomp"
+#define RC_MAP_ASUS_PC39                 "rc-asus-pc39"
+#define RC_MAP_ATI_TV_WONDER_HD_600      "rc-ati-tv-wonder-hd-600"
+#define RC_MAP_AVERMEDIA_A16D            "rc-avermedia-a16d"
+#define RC_MAP_AVERMEDIA_CARDBUS         "rc-avermedia-cardbus"
+#define RC_MAP_AVERMEDIA_DVBT            "rc-avermedia-dvbt"
+#define RC_MAP_AVERMEDIA_M135A_RM_JX     "rc-avermedia-m135a-rm-jx"
+#define RC_MAP_AVERMEDIA                 "rc-avermedia"
+#define RC_MAP_AVERTV_303                "rc-avertv-303"
+#define RC_MAP_BEHOLD_COLUMBUS           "rc-behold-columbus"
+#define RC_MAP_BEHOLD                    "rc-behold"
+#define RC_MAP_BUDGET_CI_OLD             "rc-budget-ci-old"
+#define RC_MAP_CINERGY_1400              "rc-cinergy-1400"
+#define RC_MAP_CINERGY                   "rc-cinergy"
+#define RC_MAP_DM1105_NEC                "rc-dm1105-nec"
+#define RC_MAP_DNTV_LIVE_DVBT_PRO        "rc-dntv-live-dvbt-pro"
+#define RC_MAP_DNTV_LIVE_DVB_T           "rc-dntv-live-dvb-t"
+#define RC_MAP_EMPTY                     "rc-empty"
+#define RC_MAP_EM_TERRATEC               "rc-em-terratec"
+#define RC_MAP_ENCORE_ENLTV2             "rc-encore-enltv2"
+#define RC_MAP_ENCORE_ENLTV_FM53         "rc-encore-enltv-fm53"
+#define RC_MAP_ENCORE_ENLTV              "rc-encore-enltv"
+#define RC_MAP_EVGA_INDTUBE              "rc-evga-indtube"
+#define RC_MAP_EZTV                      "rc-eztv"
+#define RC_MAP_FLYDVB                    "rc-flydvb"
+#define RC_MAP_FLYVIDEO                  "rc-flyvideo"
+#define RC_MAP_FUSIONHDTV_MCE            "rc-fusionhdtv-mce"
+#define RC_MAP_GADMEI_RM008Z             "rc-gadmei-rm008z"
+#define RC_MAP_GENIUS_TVGO_A11MCE        "rc-genius-tvgo-a11mce"
+#define RC_MAP_GOTVIEW7135               "rc-gotview7135"
+#define RC_MAP_HAUPPAUGE_NEW             "rc-hauppauge-new"
+#define RC_MAP_IMON_MCE                  "rc-imon-mce"
+#define RC_MAP_IMON_PAD                  "rc-imon-pad"
+#define RC_MAP_IODATA_BCTV7E             "rc-iodata-bctv7e"
+#define RC_MAP_KAIOMY                    "rc-kaiomy"
+#define RC_MAP_KWORLD_315U               "rc-kworld-315u"
+#define RC_MAP_KWORLD_PLUS_TV_ANALOG     "rc-kworld-plus-tv-analog"
+#define RC_MAP_MANLI                     "rc-manli"
+#define RC_MAP_MSI_TVANYWHERE_PLUS       "rc-msi-tvanywhere-plus"
+#define RC_MAP_MSI_TVANYWHERE            "rc-msi-tvanywhere"
+#define RC_MAP_NEBULA                    "rc-nebula"
+#define RC_MAP_NEC_TERRATEC_CINERGY_XS   "rc-nec-terratec-cinergy-xs"
+#define RC_MAP_NORWOOD                   "rc-norwood"
+#define RC_MAP_NPGTECH                   "rc-npgtech"
+#define RC_MAP_PCTV_SEDNA                "rc-pctv-sedna"
+#define RC_MAP_PINNACLE_COLOR            "rc-pinnacle-color"
+#define RC_MAP_PINNACLE_GREY             "rc-pinnacle-grey"
+#define RC_MAP_PINNACLE_PCTV_HD          "rc-pinnacle-pctv-hd"
+#define RC_MAP_PIXELVIEW_NEW             "rc-pixelview-new"
+#define RC_MAP_PIXELVIEW                 "rc-pixelview"
+#define RC_MAP_PIXELVIEW_MK12            "rc-pixelview-mk12"
+#define RC_MAP_POWERCOLOR_REAL_ANGEL     "rc-powercolor-real-angel"
+#define RC_MAP_PROTEUS_2309              "rc-proteus-2309"
+#define RC_MAP_PURPLETV                  "rc-purpletv"
+#define RC_MAP_PV951                     "rc-pv951"
+#define RC_MAP_RC5_HAUPPAUGE_NEW         "rc-rc5-hauppauge-new"
+#define RC_MAP_RC5_TV                    "rc-rc5-tv"
+#define RC_MAP_REAL_AUDIO_220_32_KEYS    "rc-real-audio-220-32-keys"
+#define RC_MAP_TBS_NEC                   "rc-tbs-nec"
+#define RC_MAP_TERRATEC_CINERGY_XS       "rc-terratec-cinergy-xs"
+#define RC_MAP_TEVII_NEC                 "rc-tevii-nec"
+#define RC_MAP_TT_1500                   "rc-tt-1500"
+#define RC_MAP_VIDEOMATE_S350            "rc-videomate-s350"
+#define RC_MAP_VIDEOMATE_TV_PVR          "rc-videomate-tv-pvr"
+#define RC_MAP_WINFAST                   "rc-winfast"
+#define RC_MAP_WINFAST_USBII_DELUXE      "rc-winfast-usbii-deluxe"
+/*
+ * Please, do not just append newer Remote Controller names at the end.
+ * The names should be ordered in alphabetical order
+ */
diff --git a/include/media/sh_vou.h b/include/media/sh_vou.h
new file mode 100644
index 0000000..a3ef302
--- /dev/null
+++ b/include/media/sh_vou.h
@@ -0,0 +1,34 @@
+/*
+ * SuperH Video Output Unit (VOU) driver header
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef SH_VOU_H
+#define SH_VOU_H
+
+#include <linux/i2c.h>
+
+/* Bus flags */
+#define SH_VOU_PCLK_FALLING	(1 << 0)
+#define SH_VOU_HSYNC_LOW	(1 << 1)
+#define SH_VOU_VSYNC_LOW	(1 << 2)
+
+enum sh_vou_bus_fmt {
+	SH_VOU_BUS_8BIT,
+	SH_VOU_BUS_16BIT,
+	SH_VOU_BUS_BT656,
+};
+
+struct sh_vou_pdata {
+	enum sh_vou_bus_fmt bus_fmt;
+	int i2c_adap;
+	struct i2c_board_info *board_info;
+	unsigned long flags;
+	char *module_name;
+};
+
+#endif
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index 9d69f01b..c9a5bbf 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -266,8 +266,8 @@
 		common_flags;
 }
 
-static inline void soc_camera_limit_side(unsigned int *start,
-		unsigned int *length, unsigned int start_min,
+static inline void soc_camera_limit_side(int *start, int *length,
+		unsigned int start_min,
 		unsigned int length_min, unsigned int length_max)
 {
 	if (*length < length_min)
@@ -284,4 +284,12 @@
 extern unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl,
 						   unsigned long flags);
 
+/* This is only temporary here - until v4l2-subdev begins to link to video_device */
+#include <linux/i2c.h>
+static inline struct video_device *soc_camera_i2c_to_vdev(struct i2c_client *client)
+{
+	struct soc_camera_device *icd = client->dev.platform_data;
+	return icd->vdev;
+}
+
 #endif
diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h
index 56abf21..21b4428 100644
--- a/include/media/v4l2-chip-ident.h
+++ b/include/media/v4l2-chip-ident.h
@@ -25,6 +25,10 @@
 #define V4L2_CHIP_IDENT_H_
 
 /* VIDIOC_DBG_G_CHIP_IDENT: identifies the actual chip installed on the board */
+
+/* KEEP THIS LIST ORDERED BY ID!
+   Otherwise it will be hard to see which ranges are already in use when
+   adding support to a new chip family. */
 enum {
 	/* general idents: reserved range 0-49 */
 	V4L2_IDENT_NONE      = 0,       /* No chip matched */
@@ -77,17 +81,14 @@
 	V4L2_IDENT_CX23417 = 417,
 	V4L2_IDENT_CX23418 = 418,
 
-	/* module au0828 */
-	V4L2_IDENT_AU0828 = 828,
-
-	/* module indycam: just ident 2000 */
-	V4L2_IDENT_INDYCAM = 2000,
-
 	/* module bt819: reserved range 810-819 */
 	V4L2_IDENT_BT815A = 815,
 	V4L2_IDENT_BT817A = 817,
 	V4L2_IDENT_BT819A = 819,
 
+	/* module au0828 */
+	V4L2_IDENT_AU0828 = 828,
+
 	/* module bt856: just ident 856 */
 	V4L2_IDENT_BT856 = 856,
 
@@ -99,6 +100,9 @@
 	V4L2_IDENT_KS0127  = 1127,
 	V4L2_IDENT_KS0127B = 1128,
 
+	/* module indycam: just ident 2000 */
+	V4L2_IDENT_INDYCAM = 2000,
+
 	/* module vp27smpx: just ident 2700 */
 	V4L2_IDENT_VP27SMPX = 2700,
 
@@ -162,20 +166,21 @@
 	/* module saa7706h: just ident 7706 */
 	V4L2_IDENT_SAA7706H = 7706,
 
+	/* module mt9v011, just ident 8243 */
+	V4L2_IDENT_MT9V011 = 8243,
+
 	/* module wm8739: just ident 8739 */
 	V4L2_IDENT_WM8739 = 8739,
 
 	/* module wm8775: just ident 8775 */
 	V4L2_IDENT_WM8775 = 8775,
 
-	/* module tda9840: just ident 9840 */
-	V4L2_IDENT_TDA9840 = 9840,
-
 	/* module cafe_ccic, just ident 8801 */
 	V4L2_IDENT_CAFE = 8801,
 
-	/* module mt9v011, just ident 8243 */
-	V4L2_IDENT_MT9V011 = 8243,
+	/* AKM AK8813/AK8814 */
+	V4L2_IDENT_AK8813 = 8813,
+	V4L2_IDENT_AK8814 = 8814,
 
 	/* module cx23885 and cx25840 */
 	V4L2_IDENT_CX23885    = 8850,
@@ -186,6 +191,9 @@
 	V4L2_IDENT_CX23888_AV = 8881, /* Integrated A/V decoder */
 	V4L2_IDENT_CX23888_IR = 8882, /* Integrated infrared controller */
 
+	/* module tda9840: just ident 9840 */
+	V4L2_IDENT_TDA9840 = 9840,
+
 	/* module tw9910: just ident 9910 */
 	V4L2_IDENT_TW9910 = 9910,
 
@@ -198,72 +206,70 @@
 	V4L2_IDENT_CX23101    = 23101,
 	V4L2_IDENT_CX23102    = 23102,
 
-	/* module msp3400: reserved range 34000-34999 and 44000-44999 */
+	/* module msp3400: reserved range 34000-34999 for msp34xx */
 	V4L2_IDENT_MSPX4XX  = 34000, /* generic MSPX4XX identifier, only
 					use internally (tveeprom.c). */
 
 	V4L2_IDENT_MSP3400B = 34002,
-	V4L2_IDENT_MSP3410B = 34102,
-
 	V4L2_IDENT_MSP3400C = 34003,
-	V4L2_IDENT_MSP3410C = 34103,
-
 	V4L2_IDENT_MSP3400D = 34004,
-	V4L2_IDENT_MSP3410D = 34104,
-	V4L2_IDENT_MSP3405D = 34054,
-	V4L2_IDENT_MSP3415D = 34154,
-	V4L2_IDENT_MSP3407D = 34074,
-	V4L2_IDENT_MSP3417D = 34174,
-
 	V4L2_IDENT_MSP3400G = 34007,
-	V4L2_IDENT_MSP3410G = 34107,
-	V4L2_IDENT_MSP3420G = 34207,
-	V4L2_IDENT_MSP3430G = 34307,
-	V4L2_IDENT_MSP3440G = 34407,
-	V4L2_IDENT_MSP3450G = 34507,
-	V4L2_IDENT_MSP3460G = 34607,
-
 	V4L2_IDENT_MSP3401G = 34017,
-	V4L2_IDENT_MSP3411G = 34117,
-	V4L2_IDENT_MSP3421G = 34217,
-	V4L2_IDENT_MSP3431G = 34317,
-	V4L2_IDENT_MSP3441G = 34417,
-	V4L2_IDENT_MSP3451G = 34517,
-	V4L2_IDENT_MSP3461G = 34617,
-
 	V4L2_IDENT_MSP3402G = 34027,
-	V4L2_IDENT_MSP3412G = 34127,
-	V4L2_IDENT_MSP3422G = 34227,
-	V4L2_IDENT_MSP3442G = 34427,
-	V4L2_IDENT_MSP3452G = 34527,
-
+	V4L2_IDENT_MSP3405D = 34054,
 	V4L2_IDENT_MSP3405G = 34057,
-	V4L2_IDENT_MSP3415G = 34157,
-	V4L2_IDENT_MSP3425G = 34257,
-	V4L2_IDENT_MSP3435G = 34357,
-	V4L2_IDENT_MSP3445G = 34457,
-	V4L2_IDENT_MSP3455G = 34557,
-	V4L2_IDENT_MSP3465G = 34657,
-
+	V4L2_IDENT_MSP3407D = 34074,
 	V4L2_IDENT_MSP3407G = 34077,
+
+	V4L2_IDENT_MSP3410B = 34102,
+	V4L2_IDENT_MSP3410C = 34103,
+	V4L2_IDENT_MSP3410D = 34104,
+	V4L2_IDENT_MSP3410G = 34107,
+	V4L2_IDENT_MSP3411G = 34117,
+	V4L2_IDENT_MSP3412G = 34127,
+	V4L2_IDENT_MSP3415D = 34154,
+	V4L2_IDENT_MSP3415G = 34157,
+	V4L2_IDENT_MSP3417D = 34174,
 	V4L2_IDENT_MSP3417G = 34177,
+
+	V4L2_IDENT_MSP3420G = 34207,
+	V4L2_IDENT_MSP3421G = 34217,
+	V4L2_IDENT_MSP3422G = 34227,
+	V4L2_IDENT_MSP3425G = 34257,
 	V4L2_IDENT_MSP3427G = 34277,
+
+	V4L2_IDENT_MSP3430G = 34307,
+	V4L2_IDENT_MSP3431G = 34317,
+	V4L2_IDENT_MSP3435G = 34357,
 	V4L2_IDENT_MSP3437G = 34377,
+
+	V4L2_IDENT_MSP3440G = 34407,
+	V4L2_IDENT_MSP3441G = 34417,
+	V4L2_IDENT_MSP3442G = 34427,
+	V4L2_IDENT_MSP3445G = 34457,
 	V4L2_IDENT_MSP3447G = 34477,
+
+	V4L2_IDENT_MSP3450G = 34507,
+	V4L2_IDENT_MSP3451G = 34517,
+	V4L2_IDENT_MSP3452G = 34527,
+	V4L2_IDENT_MSP3455G = 34557,
 	V4L2_IDENT_MSP3457G = 34577,
+
+	V4L2_IDENT_MSP3460G = 34607,
+	V4L2_IDENT_MSP3461G = 34617,
+	V4L2_IDENT_MSP3465G = 34657,
 	V4L2_IDENT_MSP3467G = 34677,
 
-	/* module msp3400: reserved range 34000-34999 and 44000-44999 */
+	/* module msp3400: reserved range 44000-44999 for msp44xx */
 	V4L2_IDENT_MSP4400G = 44007,
-	V4L2_IDENT_MSP4410G = 44107,
-	V4L2_IDENT_MSP4420G = 44207,
-	V4L2_IDENT_MSP4440G = 44407,
-	V4L2_IDENT_MSP4450G = 44507,
-
 	V4L2_IDENT_MSP4408G = 44087,
+	V4L2_IDENT_MSP4410G = 44107,
 	V4L2_IDENT_MSP4418G = 44187,
+	V4L2_IDENT_MSP4420G = 44207,
 	V4L2_IDENT_MSP4428G = 44287,
+	V4L2_IDENT_MSP4440G = 44407,
 	V4L2_IDENT_MSP4448G = 44487,
+	V4L2_IDENT_MSP4450G = 44507,
 	V4L2_IDENT_MSP4458G = 44587,
 
 	/* Micron CMOS sensor chips: 45000-45099 */
@@ -282,20 +288,27 @@
 	/* HV7131R CMOS sensor: just ident 46000 */
 	V4L2_IDENT_HV7131R		= 46000,
 
+	/* Sharp RJ54N1CB0C, 0xCB0C = 51980 */
+	V4L2_IDENT_RJ54N1CB0C = 51980,
+
+	/* module m52790: just ident 52790 */
+	V4L2_IDENT_M52790 = 52790,
+
 	/* module cs53132a: just ident 53132 */
 	V4L2_IDENT_CS53l32A = 53132,
 
+	/* modules upd61151 MPEG2 encoder: just ident 54000 */
+	V4L2_IDENT_UPD61161 = 54000,
+	/* modules upd61152 MPEG2 encoder with AC3: just ident 54001 */
+	V4L2_IDENT_UPD61162 = 54001,
+
 	/* module upd64031a: just ident 64031 */
 	V4L2_IDENT_UPD64031A = 64031,
 
 	/* module upd64083: just ident 64083 */
 	V4L2_IDENT_UPD64083 = 64083,
 
-	/* module m52790: just ident 52790 */
-	V4L2_IDENT_M52790 = 52790,
-
-	/* Sharp RJ54N1CB0C, 0xCB0C = 51980 */
-	V4L2_IDENT_RJ54N1CB0C = 51980,
+	/* Don't just add new IDs at the end: KEEP THIS LIST ORDERED BY ID! */
 };
 
 #endif
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index 1c7b259..98b3264 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -85,13 +85,13 @@
 struct v4l2_prio_state {
 	atomic_t prios[4];
 };
-int v4l2_prio_init(struct v4l2_prio_state *global);
+void v4l2_prio_init(struct v4l2_prio_state *global);
 int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local,
 		     enum v4l2_priority new);
-int v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local);
-int v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority *local);
+void v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local);
+void v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority local);
 enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global);
-int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local);
+int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority local);
 
 /* ------------------------------------------------------------------------- */
 
@@ -184,6 +184,25 @@
 
 /* ------------------------------------------------------------------------- */
 
+/* SPI Helper functions */
+#if defined(CONFIG_SPI)
+
+#include <linux/spi/spi.h>
+
+struct spi_device;
+
+/* Load an spi module and return an initialized v4l2_subdev struct.
+   The client_type argument is the name of the chip that's on the adapter. */
+struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev,
+		struct spi_master *master, struct spi_board_info *info);
+
+/* Initialize an v4l2_subdev with data from an spi_device struct */
+void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi,
+		const struct v4l2_subdev_ops *ops);
+#endif
+
+/* ------------------------------------------------------------------------- */
+
 /* Note: these remaining ioctls/structs should be removed as well, but they are
    still used in tuner-simple.c (TUNER_SET_CONFIG), cx18/ivtv (RESET) and
    v4l2-int-device.h (v4l2_routing). To remove these ioctls some more cleanup
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index 2dee938..bebe44b 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -32,6 +32,7 @@
    Drivers can clear this flag if they want to block all future
    device access. It is cleared by video_unregister_device. */
 #define V4L2_FL_REGISTERED	(0)
+#define V4L2_FL_USES_V4L2_FH	(1)
 
 struct v4l2_file_operations {
 	struct module *owner;
@@ -77,6 +78,10 @@
 	/* attribute to differentiate multiple indices on one physical device */
 	int index;
 
+	/* V4L2 file handles */
+	spinlock_t		fh_lock; /* Lock for all v4l2_fhs */
+	struct list_head	fh_list; /* List of struct v4l2_fh */
+
 	int debug;			/* Activates debug level*/
 
 	/* Video standard vars */
diff --git a/include/media/v4l2-event.h b/include/media/v4l2-event.h
new file mode 100644
index 0000000..3b86177
--- /dev/null
+++ b/include/media/v4l2-event.h
@@ -0,0 +1,67 @@
+/*
+ * v4l2-event.h
+ *
+ * V4L2 events.
+ *
+ * Copyright (C) 2009--2010 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef V4L2_EVENT_H
+#define V4L2_EVENT_H
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/wait.h>
+
+struct v4l2_fh;
+struct video_device;
+
+struct v4l2_kevent {
+	struct list_head	list;
+	struct v4l2_event	event;
+};
+
+struct v4l2_subscribed_event {
+	struct list_head	list;
+	u32			type;
+};
+
+struct v4l2_events {
+	wait_queue_head_t	wait;
+	struct list_head	subscribed; /* Subscribed events */
+	struct list_head	free; /* Events ready for use */
+	struct list_head	available; /* Dequeueable event */
+	unsigned int		navailable;
+	unsigned int		nallocated; /* Number of allocated events */
+	u32			sequence;
+};
+
+int v4l2_event_init(struct v4l2_fh *fh);
+int v4l2_event_alloc(struct v4l2_fh *fh, unsigned int n);
+void v4l2_event_free(struct v4l2_fh *fh);
+int v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event,
+		       int nonblocking);
+void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev);
+int v4l2_event_pending(struct v4l2_fh *fh);
+int v4l2_event_subscribe(struct v4l2_fh *fh,
+			 struct v4l2_event_subscription *sub);
+int v4l2_event_unsubscribe(struct v4l2_fh *fh,
+			   struct v4l2_event_subscription *sub);
+
+#endif /* V4L2_EVENT_H */
diff --git a/include/media/v4l2-fh.h b/include/media/v4l2-fh.h
new file mode 100644
index 0000000..1d72dde
--- /dev/null
+++ b/include/media/v4l2-fh.h
@@ -0,0 +1,65 @@
+/*
+ * v4l2-fh.h
+ *
+ * V4L2 file handle. Store per file handle data for the V4L2
+ * framework. Using file handles is optional for the drivers.
+ *
+ * Copyright (C) 2009--2010 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef V4L2_FH_H
+#define V4L2_FH_H
+
+#include <linux/list.h>
+
+struct video_device;
+struct v4l2_events;
+
+struct v4l2_fh {
+	struct list_head	list;
+	struct video_device	*vdev;
+	struct v4l2_events      *events; /* events, pending and subscribed */
+};
+
+/*
+ * Initialise the file handle. Parts of the V4L2 framework using the
+ * file handles should be initialised in this function. Must be called
+ * from driver's v4l2_file_operations->open() handler if the driver
+ * uses v4l2_fh.
+ */
+int v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev);
+/*
+ * Add the fh to the list of file handles on a video_device. The file
+ * handle must be initialised first.
+ */
+void v4l2_fh_add(struct v4l2_fh *fh);
+/*
+ * Remove file handle from the list of file handles. Must be called in
+ * v4l2_file_operations->release() handler if the driver uses v4l2_fh.
+ */
+void v4l2_fh_del(struct v4l2_fh *fh);
+/*
+ * Release resources related to a file handle. Parts of the V4L2
+ * framework using the v4l2_fh must release their resources here, too.
+ * Must be called in v4l2_file_operations->release() handler if the
+ * driver uses v4l2_fh.
+ */
+void v4l2_fh_exit(struct v4l2_fh *fh);
+
+#endif /* V4L2_EVENT_H */
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index e8ba0f2..06daa6e 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -21,6 +21,8 @@
 #include <linux/videodev2.h>
 #endif
 
+struct v4l2_fh;
+
 struct v4l2_ioctl_ops {
 	/* ioctl callbacks */
 
@@ -254,6 +256,11 @@
 	int (*vidioc_g_dv_timings) (struct file *file, void *fh,
 				    struct v4l2_dv_timings *timings);
 
+	int (*vidioc_subscribe_event)  (struct v4l2_fh *fh,
+					struct v4l2_event_subscription *sub);
+	int (*vidioc_unsubscribe_event)(struct v4l2_fh *fh,
+					struct v4l2_event_subscription *sub);
+
 	/* For other private ioctls */
 	long (*vidioc_default)	       (struct file *file, void *fh,
 					int cmd, void *arg);
diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h
new file mode 100644
index 0000000..8d149f1
--- /dev/null
+++ b/include/media/v4l2-mem2mem.h
@@ -0,0 +1,201 @@
+/*
+ * Memory-to-memory device framework for Video for Linux 2.
+ *
+ * Helper functions for devices that use memory buffers for both source
+ * and destination.
+ *
+ * Copyright (c) 2009 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <p.osciak@samsung.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version
+ */
+
+#ifndef _MEDIA_V4L2_MEM2MEM_H
+#define _MEDIA_V4L2_MEM2MEM_H
+
+#include <media/videobuf-core.h>
+
+/**
+ * struct v4l2_m2m_ops - mem-to-mem device driver callbacks
+ * @device_run:	required. Begin the actual job (transaction) inside this
+ *		callback.
+ *		The job does NOT have to end before this callback returns
+ *		(and it will be the usual case). When the job finishes,
+ *		v4l2_m2m_job_finish() has to be called.
+ * @job_ready:	optional. Should return 0 if the driver does not have a job
+ *		fully prepared to run yet (i.e. it will not be able to finish a
+ *		transaction without sleeping). If not provided, it will be
+ *		assumed that one source and one destination buffer are all
+ *		that is required for the driver to perform one full transaction.
+ *		This method may not sleep.
+ * @job_abort:	required. Informs the driver that it has to abort the currently
+ *		running transaction as soon as possible (i.e. as soon as it can
+ *		stop the device safely; e.g. in the next interrupt handler),
+ *		even if the transaction would not have been finished by then.
+ *		After the driver performs the necessary steps, it has to call
+ *		v4l2_m2m_job_finish() (as if the transaction ended normally).
+ *		This function does not have to (and will usually not) wait
+ *		until the device enters a state when it can be stopped.
+ */
+struct v4l2_m2m_ops {
+	void (*device_run)(void *priv);
+	int (*job_ready)(void *priv);
+	void (*job_abort)(void *priv);
+};
+
+struct v4l2_m2m_dev;
+
+struct v4l2_m2m_queue_ctx {
+/* private: internal use only */
+	struct videobuf_queue	q;
+
+	/* Queue for buffers ready to be processed as soon as this
+	 * instance receives access to the device */
+	struct list_head	rdy_queue;
+	u8			num_rdy;
+};
+
+struct v4l2_m2m_ctx {
+/* private: internal use only */
+	struct v4l2_m2m_dev		*m2m_dev;
+
+	/* Capture (output to memory) queue context */
+	struct v4l2_m2m_queue_ctx	cap_q_ctx;
+
+	/* Output (input from memory) queue context */
+	struct v4l2_m2m_queue_ctx	out_q_ctx;
+
+	/* For device job queue */
+	struct list_head		queue;
+	unsigned long			job_flags;
+
+	/* Instance private data */
+	void				*priv;
+};
+
+void *v4l2_m2m_get_curr_priv(struct v4l2_m2m_dev *m2m_dev);
+
+struct videobuf_queue *v4l2_m2m_get_vq(struct v4l2_m2m_ctx *m2m_ctx,
+				       enum v4l2_buf_type type);
+
+void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev,
+			 struct v4l2_m2m_ctx *m2m_ctx);
+
+int v4l2_m2m_reqbufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+		     struct v4l2_requestbuffers *reqbufs);
+
+int v4l2_m2m_querybuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+		      struct v4l2_buffer *buf);
+
+int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+		  struct v4l2_buffer *buf);
+int v4l2_m2m_dqbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+		   struct v4l2_buffer *buf);
+
+int v4l2_m2m_streamon(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+		      enum v4l2_buf_type type);
+int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+		       enum v4l2_buf_type type);
+
+unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+			   struct poll_table_struct *wait);
+
+int v4l2_m2m_mmap(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+		  struct vm_area_struct *vma);
+
+struct v4l2_m2m_dev *v4l2_m2m_init(struct v4l2_m2m_ops *m2m_ops);
+void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev);
+
+struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(void *priv, struct v4l2_m2m_dev *m2m_dev,
+			void (*vq_init)(void *priv, struct videobuf_queue *,
+					enum v4l2_buf_type));
+void v4l2_m2m_ctx_release(struct v4l2_m2m_ctx *m2m_ctx);
+
+void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, struct videobuf_queue *vq,
+			struct videobuf_buffer *vb);
+
+/**
+ * v4l2_m2m_num_src_bufs_ready() - return the number of source buffers ready for
+ * use
+ */
+static inline
+unsigned int v4l2_m2m_num_src_bufs_ready(struct v4l2_m2m_ctx *m2m_ctx)
+{
+	return m2m_ctx->cap_q_ctx.num_rdy;
+}
+
+/**
+ * v4l2_m2m_num_src_bufs_ready() - return the number of destination buffers
+ * ready for use
+ */
+static inline
+unsigned int v4l2_m2m_num_dst_bufs_ready(struct v4l2_m2m_ctx *m2m_ctx)
+{
+	return m2m_ctx->out_q_ctx.num_rdy;
+}
+
+void *v4l2_m2m_next_buf(struct v4l2_m2m_ctx *m2m_ctx, enum v4l2_buf_type type);
+
+/**
+ * v4l2_m2m_next_src_buf() - return next source buffer from the list of ready
+ * buffers
+ */
+static inline void *v4l2_m2m_next_src_buf(struct v4l2_m2m_ctx *m2m_ctx)
+{
+	return v4l2_m2m_next_buf(m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+}
+
+/**
+ * v4l2_m2m_next_dst_buf() - return next destination buffer from the list of
+ * ready buffers
+ */
+static inline void *v4l2_m2m_next_dst_buf(struct v4l2_m2m_ctx *m2m_ctx)
+{
+	return v4l2_m2m_next_buf(m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+}
+
+/**
+ * v4l2_m2m_get_src_vq() - return videobuf_queue for source buffers
+ */
+static inline
+struct videobuf_queue *v4l2_m2m_get_src_vq(struct v4l2_m2m_ctx *m2m_ctx)
+{
+	return v4l2_m2m_get_vq(m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+}
+
+/**
+ * v4l2_m2m_get_dst_vq() - return videobuf_queue for destination buffers
+ */
+static inline
+struct videobuf_queue *v4l2_m2m_get_dst_vq(struct v4l2_m2m_ctx *m2m_ctx)
+{
+	return v4l2_m2m_get_vq(m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+}
+
+void *v4l2_m2m_buf_remove(struct v4l2_m2m_ctx *m2m_ctx,
+			  enum v4l2_buf_type type);
+
+/**
+ * v4l2_m2m_src_buf_remove() - take off a source buffer from the list of ready
+ * buffers and return it
+ */
+static inline void *v4l2_m2m_src_buf_remove(struct v4l2_m2m_ctx *m2m_ctx)
+{
+	return v4l2_m2m_buf_remove(m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+}
+
+/**
+ * v4l2_m2m_dst_buf_remove() - take off a destination buffer from the list of
+ * ready buffers and return it
+ */
+static inline void *v4l2_m2m_dst_buf_remove(struct v4l2_m2m_ctx *m2m_ctx)
+{
+	return v4l2_m2m_buf_remove(m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+}
+
+#endif /* _MEDIA_V4L2_MEM2MEM_H */
+
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 2bcdca0..a888893 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -184,28 +184,6 @@
 };
 
 /*
-   decode_vbi_line: video decoders that support sliced VBI need to implement
-	this ioctl. Field p of the v4l2_sliced_vbi_line struct is set to the
-	start of the VBI data that was generated by the decoder. The driver
-	then parses the sliced VBI data and sets the other fields in the
-	struct accordingly. The pointer p is updated to point to the start of
-	the payload which can be copied verbatim into the data field of the
-	v4l2_sliced_vbi_data struct. If no valid VBI data was found, then the
-	type field is set to 0 on return.
-
-   s_vbi_data: used to generate VBI signals on a video signal.
-	v4l2_sliced_vbi_data is filled with the data packets that should be
-	output. Note that if you set the line field to 0, then that VBI signal
-	is disabled. If no valid VBI data was found, then the type field is
-	set to 0 on return.
-
-   g_vbi_data: used to obtain the sliced VBI packet from a readback register.
-	Not all video decoders support this. If no data is available because
-	the readback register contains invalid or erroneous data -EIO is
-	returned. Note that you must fill in the 'id' member and the 'field'
-	member (to determine whether CC data from the first or second field
-	should be obtained).
-
    s_std_output: set v4l2_std_id for video OUTPUT devices. This is ignored by
 	video input devices.
 
@@ -243,10 +221,6 @@
 struct v4l2_subdev_video_ops {
 	int (*s_routing)(struct v4l2_subdev *sd, u32 input, u32 output, u32 config);
 	int (*s_crystal_freq)(struct v4l2_subdev *sd, u32 freq, u32 flags);
-	int (*decode_vbi_line)(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi_line);
-	int (*s_vbi_data)(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *vbi_data);
-	int (*g_vbi_data)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_data *vbi_data);
-	int (*g_sliced_vbi_cap)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_cap *cap);
 	int (*s_std_output)(struct v4l2_subdev *sd, v4l2_std_id std);
 	int (*querystd)(struct v4l2_subdev *sd, v4l2_std_id *std);
 	int (*g_input_status)(struct v4l2_subdev *sd, u32 *status);
@@ -262,6 +236,8 @@
 	int (*s_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param);
 	int (*enum_framesizes)(struct v4l2_subdev *sd, struct v4l2_frmsizeenum *fsize);
 	int (*enum_frameintervals)(struct v4l2_subdev *sd, struct v4l2_frmivalenum *fival);
+	int (*enum_dv_presets) (struct v4l2_subdev *sd,
+			struct v4l2_dv_enum_preset *preset);
 	int (*s_dv_preset)(struct v4l2_subdev *sd,
 			struct v4l2_dv_preset *preset);
 	int (*query_dv_preset)(struct v4l2_subdev *sd,
@@ -280,6 +256,45 @@
 			  struct v4l2_mbus_framefmt *fmt);
 };
 
+/*
+   decode_vbi_line: video decoders that support sliced VBI need to implement
+	this ioctl. Field p of the v4l2_sliced_vbi_line struct is set to the
+	start of the VBI data that was generated by the decoder. The driver
+	then parses the sliced VBI data and sets the other fields in the
+	struct accordingly. The pointer p is updated to point to the start of
+	the payload which can be copied verbatim into the data field of the
+	v4l2_sliced_vbi_data struct. If no valid VBI data was found, then the
+	type field is set to 0 on return.
+
+   s_vbi_data: used to generate VBI signals on a video signal.
+	v4l2_sliced_vbi_data is filled with the data packets that should be
+	output. Note that if you set the line field to 0, then that VBI signal
+	is disabled. If no valid VBI data was found, then the type field is
+	set to 0 on return.
+
+   g_vbi_data: used to obtain the sliced VBI packet from a readback register.
+	Not all video decoders support this. If no data is available because
+	the readback register contains invalid or erroneous data -EIO is
+	returned. Note that you must fill in the 'id' member and the 'field'
+	member (to determine whether CC data from the first or second field
+	should be obtained).
+
+   s_raw_fmt: setup the video encoder/decoder for raw VBI.
+
+   g_sliced_fmt: retrieve the current sliced VBI settings.
+
+   s_sliced_fmt: setup the sliced VBI settings.
+ */
+struct v4l2_subdev_vbi_ops {
+	int (*decode_vbi_line)(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi_line);
+	int (*s_vbi_data)(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *vbi_data);
+	int (*g_vbi_data)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_data *vbi_data);
+	int (*g_sliced_vbi_cap)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_cap *cap);
+	int (*s_raw_fmt)(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt);
+	int (*g_sliced_fmt)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt);
+	int (*s_sliced_fmt)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt);
+};
+
 /**
  * struct v4l2_subdev_sensor_ops - v4l2-subdev sensor operations
  * @g_skip_top_lines: number of lines at the top of the image to be skipped.
@@ -379,6 +394,7 @@
 	const struct v4l2_subdev_tuner_ops	*tuner;
 	const struct v4l2_subdev_audio_ops	*audio;
 	const struct v4l2_subdev_video_ops	*video;
+	const struct v4l2_subdev_vbi_ops	*vbi;
 	const struct v4l2_subdev_ir_ops		*ir;
 	const struct v4l2_subdev_sensor_ops	*sensor;
 };
@@ -387,6 +403,8 @@
 
 /* Set this flag if this subdev is a i2c device. */
 #define V4L2_SUBDEV_FL_IS_I2C (1U << 0)
+/* Set this flag if this subdev is a spi device. */
+#define V4L2_SUBDEV_FL_IS_SPI (1U << 1)
 
 /* Each instance of a subdev driver should create this struct, either
    stand-alone or embedded in a larger struct.
diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h
index 316fdcc..f91a736 100644
--- a/include/media/videobuf-core.h
+++ b/include/media/videobuf-core.h
@@ -127,30 +127,16 @@
 struct videobuf_qtype_ops {
 	u32                     magic;
 
-	void *(*alloc)		(size_t size);
-	void *(*vmalloc)	(struct videobuf_buffer *buf);
-	int (*iolock)		(struct videobuf_queue* q,
+	struct videobuf_buffer *(*alloc)(size_t size);
+	void *(*vaddr)		(struct videobuf_buffer *buf);
+	int (*iolock)		(struct videobuf_queue *q,
 				 struct videobuf_buffer *vb,
 				 struct v4l2_framebuffer *fbuf);
-	int (*mmap)		(struct videobuf_queue *q,
-				 unsigned int *count,
-				 unsigned int *size,
-				 enum v4l2_memory memory);
-	int (*sync)		(struct videobuf_queue* q,
+	int (*sync)		(struct videobuf_queue *q,
 				 struct videobuf_buffer *buf);
-	int (*video_copy_to_user)(struct videobuf_queue *q,
-				 char __user *data,
-				 size_t count,
-				 int nonblocking);
-	int (*copy_stream)	(struct videobuf_queue *q,
-				 char __user *data,
-				 size_t count,
-				 size_t pos,
-				 int vbihack,
-				 int nonblocking);
-	int (*mmap_free)	(struct videobuf_queue *q);
 	int (*mmap_mapper)	(struct videobuf_queue *q,
-				struct vm_area_struct *vma);
+				 struct videobuf_buffer *buf,
+				 struct vm_area_struct *vma);
 };
 
 struct videobuf_queue {
@@ -171,7 +157,6 @@
 
 	unsigned int               streaming:1;
 	unsigned int               reading:1;
-	unsigned int		   is_mmapped:1;
 
 	/* capture via mmap() + ioctl(QBUF/DQBUF) */
 	struct list_head           stream;
@@ -185,14 +170,14 @@
 };
 
 int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr);
-int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb,
+int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb,
 		struct v4l2_framebuffer *fbuf);
 
-void *videobuf_alloc(struct videobuf_queue* q);
+struct videobuf_buffer *videobuf_alloc(struct videobuf_queue *q);
 
 /* Used on videobuf-dvb */
-void *videobuf_queue_to_vmalloc (struct videobuf_queue* q,
-				 struct videobuf_buffer *buf);
+void *videobuf_queue_to_vaddr(struct videobuf_queue *q,
+			      struct videobuf_buffer *buf);
 
 void videobuf_queue_core_init(struct videobuf_queue *q,
 			 const struct videobuf_queue_ops *ops,
diff --git a/include/media/videobuf-dma-sg.h b/include/media/videobuf-dma-sg.h
index 53e72f7..a195f3b 100644
--- a/include/media/videobuf-dma-sg.h
+++ b/include/media/videobuf-dma-sg.h
@@ -17,6 +17,8 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2
  */
+#ifndef _VIDEOBUF_DMA_SG_H
+#define _VIDEOBUF_DMA_SG_H
 
 #include <media/videobuf-core.h>
 
@@ -27,14 +29,14 @@
  * block (NULL on errors).  Memory for the scatterlist is allocated
  * using kmalloc.  The caller must free the memory.
  */
-struct scatterlist* videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages);
+struct scatterlist *videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages);
 
 /*
  * Return a scatterlist for a an array of userpages (NULL on errors).
  * Memory for the scatterlist is allocated using kmalloc.  The caller
  * must free the memory.
  */
-struct scatterlist* videobuf_pages_to_sg(struct page **pages, int nr_pages,
+struct scatterlist *videobuf_pages_to_sg(struct page **pages, int nr_pages,
 					 int offset);
 
 /* --------------------------------------------------------------------- */
@@ -78,8 +80,7 @@
 	int                 direction;
 };
 
-struct videobuf_dma_sg_memory
-{
+struct videobuf_dma_sg_memory {
 	u32                 magic;
 
 	/* for mmap'ed buffers */
@@ -95,14 +96,13 @@
 			      dma_addr_t addr, int nr_pages);
 int videobuf_dma_free(struct videobuf_dmabuf *dma);
 
-int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma);
-int videobuf_dma_sync(struct videobuf_queue* q,struct videobuf_dmabuf *dma);
-int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma);
-struct videobuf_dmabuf *videobuf_to_dma (struct videobuf_buffer *buf);
+int videobuf_dma_map(struct videobuf_queue *q, struct videobuf_dmabuf *dma);
+int videobuf_dma_unmap(struct videobuf_queue *q, struct videobuf_dmabuf *dma);
+struct videobuf_dmabuf *videobuf_to_dma(struct videobuf_buffer *buf);
 
 void *videobuf_sg_alloc(size_t size);
 
-void videobuf_queue_sg_init(struct videobuf_queue* q,
+void videobuf_queue_sg_init(struct videobuf_queue *q,
 			 const struct videobuf_queue_ops *ops,
 			 struct device *dev,
 			 spinlock_t *irqlock,
@@ -111,9 +111,11 @@
 			 unsigned int msize,
 			 void *priv);
 
-	/*FIXME: these variants are used only on *-alsa code, where videobuf is
-	 * used without queue
-	 */
+/*FIXME: these variants are used only on *-alsa code, where videobuf is
+ * used without queue
+ */
 int videobuf_sg_dma_map(struct device *dev, struct videobuf_dmabuf *dma);
 int videobuf_sg_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma);
 
+#endif /* _VIDEOBUF_DMA_SG_H */
+
diff --git a/include/media/videobuf-vmalloc.h b/include/media/videobuf-vmalloc.h
index 4b419a257..851eb1a 100644
--- a/include/media/videobuf-vmalloc.h
+++ b/include/media/videobuf-vmalloc.h
@@ -19,17 +19,17 @@
 
 /* --------------------------------------------------------------------- */
 
-struct videobuf_vmalloc_memory
-{
+struct videobuf_vmalloc_memory {
 	u32                 magic;
 
 	void                *vmalloc;
 
-	/* remap_vmalloc_range seems to need to run after mmap() on some cases */
+	/* remap_vmalloc_range seems to need to run
+	 * after mmap() on some cases */
 	struct vm_area_struct *vma;
 };
 
-void videobuf_queue_vmalloc_init(struct videobuf_queue* q,
+void videobuf_queue_vmalloc_init(struct videobuf_queue *q,
 			 const struct videobuf_queue_ops *ops,
 			 struct device *dev,
 			 spinlock_t *irqlock,
@@ -38,8 +38,8 @@
 			 unsigned int msize,
 			 void *priv);
 
-void *videobuf_to_vmalloc (struct videobuf_buffer *buf);
+void *videobuf_to_vmalloc(struct videobuf_buffer *buf);
 
-void videobuf_vmalloc_free (struct videobuf_buffer *buf);
+void videobuf_vmalloc_free(struct videobuf_buffer *buf);
 
 #endif