Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 24 May 2011 04:12:49 +0000 (21:12 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 24 May 2011 04:12:49 +0000 (21:12 -0700)
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (247 commits)
  [media] gspca - sunplus: Fix some warnings and simplify code
  [media] gspca: Fix some warnings tied to 'no debug'
  [media] gspca: Unset debug by default
  [media] gspca - cpia1: Remove a bad conditional compilation instruction
  [media] gspca - main: Remove USB traces
  [media] gspca - main: Version change to 2.13
  [media] gspca - stk014 / t613: Accept the index 0 in querymenu
  [media] gspca - kinect: Remove __devinitdata
  [media] gspca - cpia1: Fix some warnings
  [media] video/Kconfig: Fix mis-classified devices
  [media] support for medion dvb stick 1660:1921
  [media] tm6000: fix uninitialized field, change prink to dprintk
  [media] cx231xx: Add support for Iconbit U100
  [media] saa7134 add new TV cards
  [media] Use a more consistent value for RC repeat period
  [media] cx18: Move spinlock and vb_type initialisation into stream_init
  [media] tm6000: remove tm6010 sif audio start and stop
  [media] tm6000: remove unused exports
  [media] tm6000: add pts logging
  [media] tm6000: change from ioctl to unlocked_ioctl
  ...

228 files changed:
Documentation/DocBook/.gitignore
Documentation/DocBook/dvb/dvbapi.xml
Documentation/DocBook/dvb/dvbproperty.xml
Documentation/DocBook/dvb/frontend.h.xml
Documentation/DocBook/media-entities.tmpl
Documentation/DocBook/v4l/pixfmt-m420.xml [new file with mode: 0644]
Documentation/DocBook/v4l/pixfmt-y10b.xml [new file with mode: 0644]
Documentation/DocBook/v4l/pixfmt.xml
Documentation/DocBook/v4l/subdev-formats.xml
Documentation/DocBook/v4l/videodev2.h.xml
Documentation/feature-removal-schedule.txt
Documentation/ioctl/ioctl-number.txt
Documentation/video4linux/CARDLIST.em28xx
Documentation/video4linux/Zoran
Documentation/video4linux/gspca.txt
Documentation/video4linux/uvcvideo.txt [new file with mode: 0644]
drivers/media/common/saa7146_core.c
drivers/media/common/tuners/Kconfig
drivers/media/common/tuners/Makefile
drivers/media/common/tuners/mxl5005s.c
drivers/media/common/tuners/tda18212.c [new file with mode: 0644]
drivers/media/common/tuners/tda18212.h [new file with mode: 0644]
drivers/media/common/tuners/tda18212_priv.h [new file with mode: 0644]
drivers/media/common/tuners/tda18271-fe.c
drivers/media/common/tuners/xc5000.c
drivers/media/dvb/b2c2/flexcop-pci.c
drivers/media/dvb/bt8xx/bt878.c
drivers/media/dvb/dvb-core/dvb_demux.c
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvb_frontend.h
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/a800.c
drivers/media/dvb/dvb-usb/anysee.c
drivers/media/dvb/dvb-usb/anysee.h
drivers/media/dvb/dvb-usb/au6610.c
drivers/media/dvb/dvb-usb/ce6230.c
drivers/media/dvb/dvb-usb/dib0700.h
drivers/media/dvb/dvb-usb/dib0700_core.c
drivers/media/dvb/dvb-usb/dib0700_devices.c
drivers/media/dvb/dvb-usb/dibusb-common.c
drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dw2102.c
drivers/media/dvb/dvb-usb/ec168.c
drivers/media/dvb/dvb-usb/friio.c
drivers/media/dvb/dvb-usb/lmedm04.c
drivers/media/dvb/dvb-usb/lmedm04.h
drivers/media/dvb/dvb-usb/m920x.c
drivers/media/dvb/dvb-usb/nova-t-usb2.c
drivers/media/dvb/dvb-usb/opera1.c
drivers/media/dvb/dvb-usb/vp702x-fe.c
drivers/media/dvb/dvb-usb/vp702x.c
drivers/media/dvb/dvb-usb/vp702x.h
drivers/media/dvb/dvb-usb/vp7045.c
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/bsbe1-d01a.h [new file with mode: 0644]
drivers/media/dvb/frontends/bsru6.h
drivers/media/dvb/frontends/cx24116.c
drivers/media/dvb/frontends/cx24116.h
drivers/media/dvb/frontends/cxd2820r.h [new file with mode: 0644]
drivers/media/dvb/frontends/cxd2820r_c.c [new file with mode: 0644]
drivers/media/dvb/frontends/cxd2820r_core.c [new file with mode: 0644]
drivers/media/dvb/frontends/cxd2820r_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/cxd2820r_t.c [new file with mode: 0644]
drivers/media/dvb/frontends/cxd2820r_t2.c [new file with mode: 0644]
drivers/media/dvb/frontends/dib0070.c
drivers/media/dvb/frontends/dib0090.c
drivers/media/dvb/frontends/dib7000m.c
drivers/media/dvb/frontends/dib7000p.c
drivers/media/dvb/frontends/dib8000.c
drivers/media/dvb/frontends/dib9000.c
drivers/media/dvb/frontends/dibx000_common.c
drivers/media/dvb/frontends/dibx000_common.h
drivers/media/dvb/frontends/drx397xD.c [deleted file]
drivers/media/dvb/frontends/drx397xD.h [deleted file]
drivers/media/dvb/frontends/drx397xD_fw.h [deleted file]
drivers/media/dvb/frontends/drxd.h [new file with mode: 0644]
drivers/media/dvb/frontends/drxd_firm.c [new file with mode: 0644]
drivers/media/dvb/frontends/drxd_firm.h [new file with mode: 0644]
drivers/media/dvb/frontends/drxd_hard.c [new file with mode: 0644]
drivers/media/dvb/frontends/drxd_map_firm.h [new file with mode: 0644]
drivers/media/dvb/frontends/eds1547.h
drivers/media/dvb/frontends/ix2505v.c
drivers/media/dvb/frontends/stv0288.c
drivers/media/dvb/frontends/stv0299.c
drivers/media/dvb/frontends/z0194a.h
drivers/media/dvb/mantis/hopper_cards.c
drivers/media/dvb/mantis/mantis_cards.c
drivers/media/dvb/mantis/mantis_pci.c
drivers/media/dvb/mantis/mantis_vp1033.c
drivers/media/dvb/pt1/pt1.c
drivers/media/dvb/siano/smsusb.c
drivers/media/dvb/ttpci/Kconfig
drivers/media/dvb/ttpci/budget-ci.c
drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
drivers/media/radio/si470x/radio-si470x-common.c
drivers/media/radio/si470x/radio-si470x-i2c.c
drivers/media/radio/si470x/radio-si470x.h
drivers/media/radio/wl128x/fmdrv.h
drivers/media/rc/Kconfig
drivers/media/rc/Makefile
drivers/media/rc/imon.c
drivers/media/rc/ite-cir.c
drivers/media/rc/keymaps/Makefile
drivers/media/rc/keymaps/rc-avermedia-cardbus.c
drivers/media/rc/keymaps/rc-imon-mce.c
drivers/media/rc/keymaps/rc-imon-pad.c
drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c
drivers/media/rc/keymaps/rc-rc6-mce.c
drivers/media/rc/keymaps/rc-tivo.c [new file with mode: 0644]
drivers/media/rc/keymaps/rc-winfast.c
drivers/media/rc/mceusb.c
drivers/media/rc/nuvoton-cir.c
drivers/media/rc/nuvoton-cir.h
drivers/media/rc/rc-loopback.c
drivers/media/rc/rc-main.c
drivers/media/rc/redrat3.c [new file with mode: 0644]
drivers/media/rc/winbond-cir.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cx18/Kconfig
drivers/media/video/cx18/cx18-cards.c
drivers/media/video/cx18/cx18-cards.h
drivers/media/video/cx18/cx18-driver.c
drivers/media/video/cx18/cx18-driver.h
drivers/media/video/cx18/cx18-fileops.c
drivers/media/video/cx18/cx18-fileops.h
drivers/media/video/cx18/cx18-ioctl.c
drivers/media/video/cx18/cx18-mailbox.c
drivers/media/video/cx18/cx18-streams.c
drivers/media/video/cx18/cx18-version.h
drivers/media/video/cx18/cx23418.h
drivers/media/video/cx231xx/cx231xx-cards.c
drivers/media/video/cx231xx/cx231xx-dvb.c
drivers/media/video/cx231xx/cx231xx.h
drivers/media/video/cx23885/cx23885-cards.c
drivers/media/video/cx23885/cx23885-core.c
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-mpeg.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88.h
drivers/media/video/em28xx/Kconfig
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx-dvb.c
drivers/media/video/em28xx/em28xx-i2c.c
drivers/media/video/em28xx/em28xx-reg.h
drivers/media/video/em28xx/em28xx.h
drivers/media/video/fsl-viu.c
drivers/media/video/gspca/Kconfig
drivers/media/video/gspca/Makefile
drivers/media/video/gspca/cpia1.c
drivers/media/video/gspca/gl860/gl860.c
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/gspca.h
drivers/media/video/gspca/jeilinj.c
drivers/media/video/gspca/kinect.c [new file with mode: 0644]
drivers/media/video/gspca/spca508.c
drivers/media/video/gspca/stk014.c
drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
drivers/media/video/gspca/sunplus.c
drivers/media/video/gspca/t613.c
drivers/media/video/gspca/zc3xx.c
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/mt9m111.c
drivers/media/video/mt9v022.c
drivers/media/video/mt9v032.c [new file with mode: 0644]
drivers/media/video/mx3_camera.c
drivers/media/video/omap1_camera.c
drivers/media/video/pvrusb2/pvrusb2-std.c
drivers/media/video/pwc/pwc-if.c
drivers/media/video/pwc/pwc-v4l.c
drivers/media/video/pxa_camera.c
drivers/media/video/s2255drv.c
drivers/media/video/s5p-fimc/Makefile
drivers/media/video/s5p-fimc/mipi-csis.c [new file with mode: 0644]
drivers/media/video/s5p-fimc/mipi-csis.h [new file with mode: 0644]
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/saa7164/saa7164-core.c
drivers/media/video/sh_mobile_ceu_camera.c
drivers/media/video/soc_camera.c
drivers/media/video/soc_mediabus.c
drivers/media/video/tveeprom.c
drivers/media/video/usbvision/usbvision-cards.c
drivers/media/video/usbvision/usbvision-cards.h
drivers/media/video/usbvision/usbvision-core.c
drivers/media/video/usbvision/usbvision-i2c.c
drivers/media/video/usbvision/usbvision-video.c
drivers/media/video/usbvision/usbvision.h
drivers/media/video/uvc/uvc_ctrl.c
drivers/media/video/uvc/uvc_driver.c
drivers/media/video/uvc/uvc_queue.c
drivers/media/video/uvc/uvc_v4l2.c
drivers/media/video/uvc/uvcvideo.h
drivers/media/video/v4l2-dev.c
drivers/media/video/via-camera.c
drivers/media/video/zoran/zoran_card.c
drivers/staging/lirc/lirc_sasem.c
drivers/staging/tm6000/CARDLIST [new file with mode: 0644]
drivers/staging/tm6000/tm6000-alsa.c
drivers/staging/tm6000/tm6000-cards.c
drivers/staging/tm6000/tm6000-core.c
drivers/staging/tm6000/tm6000-i2c.c
drivers/staging/tm6000/tm6000-stds.c
drivers/staging/tm6000/tm6000-usb-isoc.h
drivers/staging/tm6000/tm6000-video.c
drivers/staging/tm6000/tm6000.h
include/linux/Kbuild
include/linux/dvb/frontend.h
include/linux/dvb/version.h
include/linux/uvcvideo.h [new file with mode: 0644]
include/linux/v4l2-mediabus.h
include/linux/videodev2.h
include/media/mt9v032.h [new file with mode: 0644]
include/media/rc-core.h
include/media/rc-map.h
include/media/soc_camera.h
include/media/soc_camera_platform.h
include/media/soc_mediabus.h
include/media/v4l2-dev.h

index ad8678d..9fad86c 100644 (file)
 
 <revhistory>
 <!-- Put document revisions here, newest first. -->
+<revision>
+       <revnumber>2.0.4</revnumber>
+       <date>2011-05-06</date>
+       <authorinitials>mcc</authorinitials>
+       <revremark>
+               Add more information about DVB APIv5, better describing the frontend GET/SET props ioctl's.
+       </revremark>
+</revision>
 <revision>
        <revnumber>2.0.3</revnumber>
        <date>2010-07-03</date>
index 97f397e..52d5e3c 100644 (file)
@@ -1,6 +1,327 @@
-<section id="FE_GET_PROPERTY">
+<section id="FE_GET_SET_PROPERTY">
 <title>FE_GET_PROPERTY/FE_SET_PROPERTY</title>
 
+<programlisting>
+/* Reserved fields should be set to 0 */
+struct dtv_property {
+       __u32 cmd;
+       union {
+               __u32 data;
+               struct {
+                       __u8 data[32];
+                       __u32 len;
+                       __u32 reserved1[3];
+                       void *reserved2;
+               } buffer;
+       } u;
+       int result;
+} __attribute__ ((packed));
+
+/* num of properties cannot exceed DTV_IOCTL_MAX_MSGS per ioctl */
+#define DTV_IOCTL_MAX_MSGS 64
+
+struct dtv_properties {
+       __u32 num;
+       struct dtv_property *props;
+};
+</programlisting>
+
+<section id="FE_GET_PROPERTY">
+<title>FE_GET_PROPERTY</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call returns one or more frontend properties. This call only
+ requires read-only access to the device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>,
+ dtv_properties &#x22C6;props);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int num</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct dtv_property *props</para>
+</entry><entry
+ align="char">
+<para>Points to the location where the front-end property commands are stored.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>ERRORS</para>
+<informaltable><tgroup cols="2"><tbody><row>
+  <entry align="char"><para>EINVAL</para></entry>
+  <entry align="char"><para>Invalid parameter(s) received or number of parameters out of the range.</para></entry>
+ </row><row>
+  <entry align="char"><para>ENOMEM</para></entry>
+  <entry align="char"><para>Out of memory.</para></entry>
+ </row><row>
+  <entry align="char"><para>EFAULT</para></entry>
+  <entry align="char"><para>Failure while copying data from/to userspace.</para></entry>
+ </row><row>
+  <entry align="char"><para>EOPNOTSUPP</para></entry>
+  <entry align="char"><para>Property type not supported.</para></entry>
+ </row></tbody></tgroup></informaltable>
+</section>
+
+<section id="FE_SET_PROPERTY">
+<title>FE_SET_PROPERTY</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call sets one or more frontend properties. This call only
+ requires read-only access to the device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = <link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link>,
+ dtv_properties &#x22C6;props);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int num</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct dtv_property *props</para>
+</entry><entry
+ align="char">
+<para>Points to the location where the front-end property commands are stored.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>ERRORS
+</para>
+<informaltable><tgroup cols="2"><tbody><row>
+  <entry align="char"><para>EINVAL</para></entry>
+  <entry align="char"><para>Invalid parameter(s) received or number of parameters out of the range.</para></entry>
+ </row><row>
+  <entry align="char"><para>ENOMEM</para></entry>
+  <entry align="char"><para>Out of memory.</para></entry>
+ </row><row>
+  <entry align="char"><para>EFAULT</para></entry>
+  <entry align="char"><para>Failure while copying data from/to userspace.</para></entry>
+ </row><row>
+  <entry align="char"><para>EOPNOTSUPP</para></entry>
+  <entry align="char"><para>Property type not supported.</para></entry>
+ </row></tbody></tgroup></informaltable>
+</section>
+
+<para>
+On <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>/<link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link>,
+the actual action is determined by the dtv_property cmd/data pairs. With one single ioctl, is possible to
+get/set up to 64 properties. The actual meaning of each property is described on the next sections.
+</para>
+
+<para>The Available frontend property types are:</para>
+<programlisting>
+#define DTV_UNDEFINED          0
+#define DTV_TUNE               1
+#define DTV_CLEAR              2
+#define DTV_FREQUENCY          3
+#define DTV_MODULATION         4
+#define DTV_BANDWIDTH_HZ       5
+#define DTV_INVERSION          6
+#define DTV_DISEQC_MASTER      7
+#define DTV_SYMBOL_RATE                8
+#define DTV_INNER_FEC          9
+#define DTV_VOLTAGE            10
+#define DTV_TONE               11
+#define DTV_PILOT              12
+#define DTV_ROLLOFF            13
+#define DTV_DISEQC_SLAVE_REPLY 14
+#define DTV_FE_CAPABILITY_COUNT        15
+#define DTV_FE_CAPABILITY      16
+#define DTV_DELIVERY_SYSTEM    17
+#define DTV_ISDBT_PARTIAL_RECEPTION    18
+#define DTV_ISDBT_SOUND_BROADCASTING   19
+#define DTV_ISDBT_SB_SUBCHANNEL_ID     20
+#define DTV_ISDBT_SB_SEGMENT_IDX       21
+#define DTV_ISDBT_SB_SEGMENT_COUNT     22
+#define DTV_ISDBT_LAYERA_FEC                   23
+#define DTV_ISDBT_LAYERA_MODULATION            24
+#define DTV_ISDBT_LAYERA_SEGMENT_COUNT         25
+#define DTV_ISDBT_LAYERA_TIME_INTERLEAVING     26
+#define DTV_ISDBT_LAYERB_FEC                   27
+#define DTV_ISDBT_LAYERB_MODULATION            28
+#define DTV_ISDBT_LAYERB_SEGMENT_COUNT         29
+#define DTV_ISDBT_LAYERB_TIME_INTERLEAVING     30
+#define DTV_ISDBT_LAYERC_FEC                   31
+#define DTV_ISDBT_LAYERC_MODULATION            32
+#define DTV_ISDBT_LAYERC_SEGMENT_COUNT         33
+#define DTV_ISDBT_LAYERC_TIME_INTERLEAVING     34
+#define DTV_API_VERSION                35
+#define DTV_CODE_RATE_HP       36
+#define DTV_CODE_RATE_LP       37
+#define DTV_GUARD_INTERVAL     38
+#define DTV_TRANSMISSION_MODE  39
+#define DTV_HIERARCHY          40
+#define DTV_ISDBT_LAYER_ENABLED        41
+#define DTV_ISDBS_TS_ID                42
+</programlisting>
+
+<section id="fe_property_common">
+       <title>Parameters that are common to all Digital TV standards</title>
+       <section id="DTV_FREQUENCY">
+               <title><constant>DTV_FREQUENCY</constant></title>
+
+               <para>Central frequency of the channel, in HZ.</para>
+
+               <para>Notes:</para>
+               <para>1)For ISDB-T, the channels are usually transmitted with an offset of 143kHz.
+                       E.g. a valid frequncy could be 474143 kHz. The stepping is bound to the bandwidth of
+                       the channel which is 6MHz.</para>
+
+               <para>2)As in ISDB-Tsb the channel consists of only one or three segments the
+                       frequency step is 429kHz, 3*429 respectively. As for ISDB-T the
+                       central frequency of the channel is expected.</para>
+       </section>
+
+       <section id="DTV_BANDWIDTH_HZ">
+               <title><constant>DTV_BANDWIDTH_HZ</constant></title>
+
+               <para>Bandwidth for the channel, in HZ.</para>
+
+               <para>Possible values:
+                       <constant>1712000</constant>,
+                       <constant>5000000</constant>,
+                       <constant>6000000</constant>,
+                       <constant>7000000</constant>,
+                       <constant>8000000</constant>,
+                       <constant>10000000</constant>.
+               </para>
+
+               <para>Notes:</para>
+
+               <para>1) For ISDB-T it should be always 6000000Hz (6MHz)</para>
+               <para>2) For ISDB-Tsb it can vary depending on the number of connected segments</para>
+               <para>3) Bandwidth doesn't apply for DVB-C transmissions, as the bandwidth
+                        for DVB-C depends on the symbol rate</para>
+               <para>4) Bandwidth in ISDB-T is fixed (6MHz) or can be easily derived from
+                       other parameters (DTV_ISDBT_SB_SEGMENT_IDX,
+                       DTV_ISDBT_SB_SEGMENT_COUNT).</para>
+               <para>5) DVB-T supports 6, 7 and 8MHz.</para>
+               <para>6) In addition, DVB-T2 supports 1.172, 5 and 10MHz.</para>
+       </section>
+
+       <section id="DTV_DELIVERY_SYSTEM">
+               <title><constant>DTV_DELIVERY_SYSTEM</constant></title>
+
+               <para>Specifies the type of Delivery system</para>
+
+               <para>Possible values: </para>
+<programlisting>
+typedef enum fe_delivery_system {
+       SYS_UNDEFINED,
+       SYS_DVBC_ANNEX_AC,
+       SYS_DVBC_ANNEX_B,
+       SYS_DVBT,
+       SYS_DSS,
+       SYS_DVBS,
+       SYS_DVBS2,
+       SYS_DVBH,
+       SYS_ISDBT,
+       SYS_ISDBS,
+       SYS_ISDBC,
+       SYS_ATSC,
+       SYS_ATSCMH,
+       SYS_DMBTH,
+       SYS_CMMB,
+       SYS_DAB,
+       SYS_DVBT2,
+} fe_delivery_system_t;
+</programlisting>
+
+       </section>
+
+       <section id="DTV_TRANSMISSION_MODE">
+               <title><constant>DTV_TRANSMISSION_MODE</constant></title>
+
+               <para>Specifies the number of carriers used by the standard</para>
+
+               <para>Possible values are:</para>
+<programlisting>
+typedef enum fe_transmit_mode {
+       TRANSMISSION_MODE_2K,
+       TRANSMISSION_MODE_8K,
+       TRANSMISSION_MODE_AUTO,
+       TRANSMISSION_MODE_4K,
+       TRANSMISSION_MODE_1K,
+       TRANSMISSION_MODE_16K,
+       TRANSMISSION_MODE_32K,
+} fe_transmit_mode_t;
+</programlisting>
+
+               <para>Notes:</para>
+               <para>1) ISDB-T supports three carrier/symbol-size: 8K, 4K, 2K. It is called
+                       'mode' in the standard: Mode 1 is 2K, mode 2 is 4K, mode 3 is 8K</para>
+
+               <para>2) If <constant>DTV_TRANSMISSION_MODE</constant> is set the <constant>TRANSMISSION_MODE_AUTO</constant> the
+                       hardware will try to find the correct FFT-size (if capable) and will
+                       use TMCC to fill in the missing parameters.</para>
+               <para>3) DVB-T specifies 2K and 8K as valid sizes.</para>
+               <para>4) DVB-T2 specifies 1K, 2K, 4K, 8K, 16K and 32K.</para>
+       </section>
+
+       <section id="DTV_GUARD_INTERVAL">
+               <title><constant>DTV_GUARD_INTERVAL</constant></title>
+
+               <para>Possible values are:</para>
+<programlisting>
+typedef enum fe_guard_interval {
+       GUARD_INTERVAL_1_32,
+       GUARD_INTERVAL_1_16,
+       GUARD_INTERVAL_1_8,
+       GUARD_INTERVAL_1_4,
+       GUARD_INTERVAL_AUTO,
+       GUARD_INTERVAL_1_128,
+       GUARD_INTERVAL_19_128,
+       GUARD_INTERVAL_19_256,
+} fe_guard_interval_t;
+</programlisting>
+
+               <para>Notes:</para>
+               <para>1) If <constant>DTV_GUARD_INTERVAL</constant> is set the <constant>GUARD_INTERVAL_AUTO</constant> the hardware will
+                       try to find the correct guard interval (if capable) and will use TMCC to fill
+                       in the missing parameters.</para>
+               <para>2) Intervals 1/128, 19/128 and 19/256 are used only for DVB-T2 at present</para>
+       </section>
+</section>
+
 <section id="isdbt">
        <title>ISDB-T frontend</title>
        <para>This section describes shortly what are the possible parameters in the Linux
 
        <para>Parameters used by ISDB-T and ISDB-Tsb.</para>
 
-       <section id="isdbt-parms">
-               <title>Parameters that are common with DVB-T and ATSC</title>
-
-               <section id="isdbt-freq">
-                       <title><constant>DTV_FREQUENCY</constant></title>
-
-                       <para>Central frequency of the channel.</para>
-
-                       <para>For ISDB-T the channels are usually transmitted with an offset of 143kHz. E.g. a
-                               valid frequncy could be 474143 kHz. The stepping is bound to the bandwidth of
-                               the channel which is 6MHz.</para>
-
-                       <para>As in ISDB-Tsb the channel consists of only one or three segments the
-                               frequency step is 429kHz, 3*429 respectively. As for ISDB-T the
-                               central frequency of the channel is expected.</para>
-               </section>
-
-               <section id="isdbt-bw">
-                       <title><constant>DTV_BANDWIDTH_HZ</constant> (optional)</title>
-
-                       <para>Possible values:</para>
-
-                       <para>For ISDB-T it should be always 6000000Hz (6MHz)</para>
-                       <para>For ISDB-Tsb it can vary depending on the number of connected segments</para>
-
-                       <para>Note: Hardware specific values might be given here, but standard
-                               applications should not bother to set a value to this field as
-                               standard demods are ignoring it anyway.</para>
-
-                       <para>Bandwidth in ISDB-T is fixed (6MHz) or can be easily derived from
-                               other parameters (DTV_ISDBT_SB_SEGMENT_IDX,
-                               DTV_ISDBT_SB_SEGMENT_COUNT).</para>
-               </section>
-
-               <section id="isdbt-delivery-sys">
-                       <title><constant>DTV_DELIVERY_SYSTEM</constant></title>
-
-                       <para>Possible values: <constant>SYS_ISDBT</constant></para>
-               </section>
-
-               <section id="isdbt-tx-mode">
-                       <title><constant>DTV_TRANSMISSION_MODE</constant></title>
-
-                       <para>ISDB-T supports three carrier/symbol-size: 8K, 4K, 2K. It is called
-                               'mode' in the standard: Mode 1 is 2K, mode 2 is 4K, mode 3 is 8K</para>
-
-                       <para>Possible values: <constant>TRANSMISSION_MODE_2K</constant>, <constant>TRANSMISSION_MODE_8K</constant>,
-                               <constant>TRANSMISSION_MODE_AUTO</constant>, <constant>TRANSMISSION_MODE_4K</constant></para>
-
-                       <para>If <constant>DTV_TRANSMISSION_MODE</constant> is set the <constant>TRANSMISSION_MODE_AUTO</constant> the
-                               hardware will try to find the correct FFT-size (if capable) and will
-                               use TMCC to fill in the missing parameters.</para>
-
-                       <para><constant>TRANSMISSION_MODE_4K</constant> is added at the same time as the other new parameters.</para>
-               </section>
-
-               <section id="isdbt-guard-interval">
-                       <title><constant>DTV_GUARD_INTERVAL</constant></title>
-
-                       <para>Possible values: <constant>GUARD_INTERVAL_1_32</constant>, <constant>GUARD_INTERVAL_1_16</constant>, <constant>GUARD_INTERVAL_1_8</constant>,
-                               <constant>GUARD_INTERVAL_1_4</constant>, <constant>GUARD_INTERVAL_AUTO</constant></para>
-
-                       <para>If <constant>DTV_GUARD_INTERVAL</constant> is set the <constant>GUARD_INTERVAL_AUTO</constant> the hardware will
-                               try to find the correct guard interval (if capable) and will use TMCC to fill
-                               in the missing parameters.</para>
-               </section>
-       </section>
        <section id="isdbt-new-parms">
                <title>ISDB-T only parameters</title>
 
                        </section>
                </section>
        </section>
+       <section id="dvbt2-params">
+               <title>DVB-T2 parameters</title>
+               
+               <para>This section covers parameters that apply only to the DVB-T2 delivery method. DVB-T2
+                       support is currently in the early stages development so expect this section to grow
+                       and become more detailed with time.</para>
+
+               <section id="dvbt2-plp-id">
+                       <title><constant>DTV_DVBT2_PLP_ID</constant></title>
+
+                       <para>DVB-T2 supports Physical Layer Pipes (PLP) to allow transmission of
+                               many data types via a single multiplex. The API will soon support this
+                               at which point this section will be expanded.</para>
+               </section>
+       </section>
 </section>
 </section>
index d08e0d4..d792f78 100644 (file)
@@ -176,14 +176,20 @@ typedef enum fe_transmit_mode {
         TRANSMISSION_MODE_2K,
         TRANSMISSION_MODE_8K,
         TRANSMISSION_MODE_AUTO,
-        TRANSMISSION_MODE_4K
+        TRANSMISSION_MODE_4K,
+        TRANSMISSION_MODE_1K,
+        TRANSMISSION_MODE_16K,
+        TRANSMISSION_MODE_32K,
 } fe_transmit_mode_t;
 
 typedef enum fe_bandwidth {
         BANDWIDTH_8_MHZ,
         BANDWIDTH_7_MHZ,
         BANDWIDTH_6_MHZ,
-        BANDWIDTH_AUTO
+        BANDWIDTH_AUTO,
+        BANDWIDTH_5_MHZ,
+        BANDWIDTH_10_MHZ,
+        BANDWIDTH_1_712_MHZ,
 } fe_bandwidth_t;
 
 
@@ -192,7 +198,10 @@ typedef enum fe_guard_interval {
         GUARD_INTERVAL_1_16,
         GUARD_INTERVAL_1_8,
         GUARD_INTERVAL_1_4,
-        GUARD_INTERVAL_AUTO
+        GUARD_INTERVAL_AUTO,
+        GUARD_INTERVAL_1_128,
+        GUARD_INTERVAL_19_128,
+        GUARD_INTERVAL_19_256,
 } fe_guard_interval_t;
 
 
@@ -306,7 +315,9 @@ struct dvb_frontend_event {
 
 #define DTV_ISDBS_TS_ID         42
 
-#define DTV_MAX_COMMAND                         DTV_ISDBS_TS_ID
+#define DTV_DVBT2_PLP_ID       43
+
+#define DTV_MAX_COMMAND                         DTV_DVBT2_PLP_ID
 
 typedef enum fe_pilot {
         PILOT_ON,
@@ -338,6 +349,7 @@ typedef enum fe_delivery_system {
         SYS_DMBTH,
         SYS_CMMB,
         SYS_DAB,
+        SYS_DVBT2,
 } fe_delivery_system_t;
 
 struct dtv_cmds_h {
index fea63b4..c8abb23 100644 (file)
 <!ENTITY sub-write SYSTEM "v4l/func-write.xml">
 <!ENTITY sub-io SYSTEM "v4l/io.xml">
 <!ENTITY sub-grey SYSTEM "v4l/pixfmt-grey.xml">
+<!ENTITY sub-m420 SYSTEM "v4l/pixfmt-m420.xml">
 <!ENTITY sub-nv12 SYSTEM "v4l/pixfmt-nv12.xml">
 <!ENTITY sub-nv12m SYSTEM "v4l/pixfmt-nv12m.xml">
 <!ENTITY sub-nv12mt SYSTEM "v4l/pixfmt-nv12mt.xml">
 <!ENTITY sub-srggb8 SYSTEM "v4l/pixfmt-srggb8.xml">
 <!ENTITY sub-y10 SYSTEM "v4l/pixfmt-y10.xml">
 <!ENTITY sub-y12 SYSTEM "v4l/pixfmt-y12.xml">
+<!ENTITY sub-y10b SYSTEM "v4l/pixfmt-y10b.xml">
 <!ENTITY sub-pixfmt SYSTEM "v4l/pixfmt.xml">
 <!ENTITY sub-cropcap SYSTEM "v4l/vidioc-cropcap.xml">
 <!ENTITY sub-dbg-g-register SYSTEM "v4l/vidioc-dbg-g-register.xml">
diff --git a/Documentation/DocBook/v4l/pixfmt-m420.xml b/Documentation/DocBook/v4l/pixfmt-m420.xml
new file mode 100644 (file)
index 0000000..ce4bc01
--- /dev/null
@@ -0,0 +1,147 @@
+    <refentry id="V4L2-PIX-FMT-M420">
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_M420 ('M420')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname><constant>V4L2_PIX_FMT_M420</constant></refname>
+       <refpurpose>Format with &frac12; horizontal and vertical chroma
+       resolution, also known as YUV 4:2:0. Hybrid plane line-interleaved
+       layout.</refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>M420 is a YUV format with &frac12; horizontal and vertical chroma
+       subsampling (YUV 4:2:0). Pixels are organized as interleaved luma and
+       chroma planes. Two lines of luma data are followed by one line of chroma
+       data.</para>
+       <para>The luma plane has one byte per pixel. The chroma plane contains
+       interleaved CbCr pixels subsampled by &frac12; in the horizontal and
+       vertical directions. Each CbCr pair belongs to four pixels. For example,
+Cb<subscript>0</subscript>/Cr<subscript>0</subscript> belongs to
+Y'<subscript>00</subscript>, Y'<subscript>01</subscript>,
+Y'<subscript>10</subscript>, Y'<subscript>11</subscript>.</para>
+
+       <para>All line lengths are identical: if the Y lines include pad bytes
+       so do the CbCr lines.</para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_M420</constant> 4 &times; 4
+pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+               <informaltable frame="none">
+               <tgroup cols="5" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start&nbsp;+&nbsp;0:</entry>
+                     <entry>Y'<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>01</subscript></entry>
+                     <entry>Y'<subscript>02</subscript></entry>
+                     <entry>Y'<subscript>03</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;4:</entry>
+                     <entry>Y'<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>11</subscript></entry>
+                     <entry>Y'<subscript>12</subscript></entry>
+                     <entry>Y'<subscript>13</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;8:</entry>
+                     <entry>Cb<subscript>00</subscript></entry>
+                     <entry>Cr<subscript>00</subscript></entry>
+                     <entry>Cb<subscript>01</subscript></entry>
+                     <entry>Cr<subscript>01</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;16:</entry>
+                     <entry>Y'<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>21</subscript></entry>
+                     <entry>Y'<subscript>22</subscript></entry>
+                     <entry>Y'<subscript>23</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;20:</entry>
+                     <entry>Y'<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>31</subscript></entry>
+                     <entry>Y'<subscript>32</subscript></entry>
+                     <entry>Y'<subscript>33</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;24:</entry>
+                     <entry>Cb<subscript>10</subscript></entry>
+                     <entry>Cr<subscript>10</subscript></entry>
+                     <entry>Cb<subscript>11</subscript></entry>
+                     <entry>Cr<subscript>11</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+
+         <formalpara>
+           <title>Color Sample Location.</title>
+           <para>
+               <informaltable frame="none">
+               <tgroup cols="7" align="center">
+                 <tbody valign="top">
+                   <row>
+                     <entry></entry>
+                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
+                     <entry>2</entry><entry></entry><entry>3</entry>
+                   </row>
+                   <row>
+                     <entry>0</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry>
+                   </row>
+                   <row>
+                     <entry>1</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                   </row>
+                   <row>
+                     <entry>2</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry>
+                   </row>
+                   <row>
+                     <entry>3</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-y10b.xml b/Documentation/DocBook/v4l/pixfmt-y10b.xml
new file mode 100644 (file)
index 0000000..adb0ad8
--- /dev/null
@@ -0,0 +1,43 @@
+<refentry id="V4L2-PIX-FMT-Y10BPACK">
+  <refmeta>
+    <refentrytitle>V4L2_PIX_FMT_Y10BPACK ('Y10B')</refentrytitle>
+    &manvol;
+  </refmeta>
+  <refnamediv>
+    <refname><constant>V4L2_PIX_FMT_Y10BPACK</constant></refname>
+    <refpurpose>Grey-scale image as a bit-packed array</refpurpose>
+  </refnamediv>
+  <refsect1>
+    <title>Description</title>
+
+    <para>This is a packed grey-scale image format with a depth of 10 bits per
+      pixel. Pixels are stored in a bit-packed array of 10bit bits per pixel,
+      with no padding between them and with the most significant bits coming
+      first from the left.</para>
+
+    <example>
+      <title><constant>V4L2_PIX_FMT_Y10BPACK</constant> 4 pixel data stream taking 5 bytes</title>
+
+      <formalpara>
+       <title>Bit-packed representation</title>
+       <para>pixels cross the byte boundary and have a ratio of 5 bytes for each 4
+          pixels.
+         <informaltable frame="all">
+           <tgroup cols="5" align="center">
+             <colspec align="left" colwidth="2*" />
+             <tbody valign="top">
+               <row>
+                 <entry>Y'<subscript>00[9:2]</subscript></entry>
+                 <entry>Y'<subscript>00[1:0]</subscript>Y'<subscript>01[9:4]</subscript></entry>
+                 <entry>Y'<subscript>01[3:0]</subscript>Y'<subscript>02[9:6]</subscript></entry>
+                 <entry>Y'<subscript>02[5:0]</subscript>Y'<subscript>03[9:8]</subscript></entry>
+                 <entry>Y'<subscript>03[7:0]</subscript></entry>
+               </row>
+             </tbody>
+           </tgroup>
+         </informaltable>
+       </para>
+      </formalpara>
+    </example>
+  </refsect1>
+</refentry>
index 40af4be..dbfe3b0 100644 (file)
@@ -697,6 +697,7 @@ information.</para>
     &sub-grey;
     &sub-y10;
     &sub-y12;
+    &sub-y10b;
     &sub-y16;
     &sub-yuyv;
     &sub-uyvy;
@@ -712,6 +713,7 @@ information.</para>
     &sub-nv12m;
     &sub-nv12mt;
     &sub-nv16;
+    &sub-m420;
   </section>
 
   <section>
index d7ccd25..a26b10c 100644 (file)
        </tgroup>
       </table>
     </section>
+
+    <section>
+      <title>JPEG Compressed Formats</title>
+
+      <para>Those data formats consist of an ordered sequence of 8-bit bytes
+       obtained from JPEG compression process. Additionally to the
+       <constant>_JPEG</constant> prefix the format code is made of
+       the following information.
+       <itemizedlist>
+         <listitem>The number of bus samples per entropy encoded byte.</listitem>
+         <listitem>The bus width.</listitem>
+       </itemizedlist>
+
+       <para>For instance, for a JPEG baseline process and an 8-bit bus width
+         the format will be named <constant>V4L2_MBUS_FMT_JPEG_1X8</constant>.
+       </para>
+      </para>
+
+      <para>The following table lists existing JPEG compressed formats.</para>
+
+      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-jpeg">
+       <title>JPEG Formats</title>
+       <tgroup cols="3">
+         <colspec colname="id" align="left" />
+         <colspec colname="code" align="left"/>
+         <colspec colname="remarks" align="left"/>
+         <thead>
+           <row>
+             <entry>Identifier</entry>
+             <entry>Code</entry>
+             <entry>Remarks</entry>
+           </row>
+         </thead>
+         <tbody valign="top">
+           <row id="V4L2-MBUS-FMT-JPEG-1X8">
+             <entry>V4L2_MBUS_FMT_JPEG_1X8</entry>
+             <entry>0x4001</entry>
+             <entry>Besides of its usage for the parallel bus this format is
+               recommended for transmission of JPEG data over MIPI CSI bus
+               using the User Defined 8-bit Data types.
+             </entry>
+           </row>
+         </tbody>
+       </tgroup>
+      </table>
+    </section>
   </section>
 </section>
index 2b796a2..c50536a 100644 (file)
@@ -311,6 +311,9 @@ struct <link linkend="v4l2-pix-format">v4l2_pix_format</link> {
 #define <link linkend="V4L2-PIX-FMT-Y10">V4L2_PIX_FMT_Y10</link>     v4l2_fourcc('Y', '1', '0', ' ') /* 10  Greyscale     */
 #define <link linkend="V4L2-PIX-FMT-Y16">V4L2_PIX_FMT_Y16</link>     v4l2_fourcc('Y', '1', '6', ' ') /* 16  Greyscale     */
 
+/* Grey bit-packed formats */
+#define <link linkend="V4L2-PIX-FMT-Y10BPACK">V4L2_PIX_FMT_Y10BPACK</link>    v4l2_fourcc('Y', '1', '0', 'B') /* 10  Greyscale bit-packed */
+
 /* Palette formats */
 #define <link linkend="V4L2-PIX-FMT-PAL8">V4L2_PIX_FMT_PAL8</link>    v4l2_fourcc('P', 'A', 'L', '8') /*  8  8-bit palette */
 
@@ -333,6 +336,7 @@ struct <link linkend="v4l2-pix-format">v4l2_pix_format</link> {
 #define <link linkend="V4L2-PIX-FMT-YUV420">V4L2_PIX_FMT_YUV420</link>  v4l2_fourcc('Y', 'U', '1', '2') /* 12  YUV 4:2:0     */
 #define <link linkend="V4L2-PIX-FMT-HI240">V4L2_PIX_FMT_HI240</link>   v4l2_fourcc('H', 'I', '2', '4') /*  8  8-bit color   */
 #define <link linkend="V4L2-PIX-FMT-HM12">V4L2_PIX_FMT_HM12</link>    v4l2_fourcc('H', 'M', '1', '2') /*  8  YUV 4:2:0 16x16 macroblocks */
+#define <link linkend="V4L2-PIX-FMT-M420">V4L2_PIX_FMT_M420</link>    v4l2_fourcc('M', '4', '2', '0') /* 12  YUV 4:2:0 2 lines y, 1 line uv interleaved */
 
 /* two planes -- one Y, one Cr + Cb interleaved  */
 #define <link linkend="V4L2-PIX-FMT-NV12">V4L2_PIX_FMT_NV12</link>    v4l2_fourcc('N', 'V', '1', '2') /* 12  Y/CbCr 4:2:0  */
index 19132ca..95788ad 100644 (file)
@@ -551,3 +551,26 @@ Why:       These legacy callbacks should no longer be used as i2c-core offers
 Who:   Jean Delvare <khali@linux-fr.org>
 
 ----------------------------
+
+What:  Support for UVCIOC_CTRL_ADD in the uvcvideo driver
+When:  2.6.42
+Why:   The information passed to the driver by this ioctl is now queried
+       dynamically from the device.
+Who:   Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+
+----------------------------
+
+What:  Support for UVCIOC_CTRL_MAP_OLD in the uvcvideo driver
+When:  2.6.42
+Why:   Used only by applications compiled against older driver versions.
+       Superseded by UVCIOC_CTRL_MAP which supports V4L2 menu controls.
+Who:   Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+
+----------------------------
+
+What:  Support for UVCIOC_CTRL_GET and UVCIOC_CTRL_SET in the uvcvideo driver
+When:  2.6.42
+Why:   Superseded by the UVCIOC_CTRL_QUERY ioctl.
+Who:   Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+
+----------------------------
index a0a5d82..2d1ad12 100644 (file)
@@ -166,7 +166,6 @@ Code  Seq#(hex)     Include File            Comments
 'T'    all     arch/x86/include/asm/ioctls.h   conflict!
 'T'    C0-DF   linux/if_tun.h          conflict!
 'U'    all     sound/asound.h          conflict!
-'U'    00-0F   drivers/media/video/uvc/uvcvideo.h      conflict!
 'U'    00-CF   linux/uinput.h          conflict!
 'U'    00-EF   linux/usbdevice_fs.h
 'U'    C0-CF   drivers/bluetooth/hci_uart.h
@@ -259,6 +258,7 @@ Code  Seq#(hex)     Include File            Comments
 't'    80-8F   linux/isdn_ppp.h
 't'    90      linux/toshiba.h
 'u'    00-1F   linux/smb_fs.h          gone
+'u'    20-3F   linux/uvcvideo.h        USB video class host driver
 'v'    00-1F   linux/ext2_fs.h         conflict!
 'v'    00-1F   linux/fs.h              conflict!
 'v'    00-0F   linux/sonypi.h          conflict!
index 31b4857..9aae449 100644 (file)
@@ -54,7 +54,7 @@
  53 -> Pinnacle Hybrid Pro                      (em2881)
  54 -> Kworld VS-DVB-T 323UR                    (em2882)        [eb1a:e323]
  55 -> Terratec Cinnergy Hybrid T USB XS (em2882) (em2882)        [0ccd:005e,0ccd:0042]
- 56 -> Pinnacle Hybrid Pro (2)                  (em2882)        [2304:0226]
+ 56 -> Pinnacle Hybrid Pro (330e)               (em2882)        [2304:0226]
  57 -> Kworld PlusTV HD Hybrid 330              (em2883)        [eb1a:a316]
  58 -> Compro VideoMate ForYou/Stereo           (em2820/em2840) [185b:2041]
  60 -> Hauppauge WinTV HVR 850                  (em2883)        [2040:651f]
index c40e3ba..9ed629d 100644 (file)
@@ -130,7 +130,6 @@ Card number: 4
 
 Note: No module for the mse3000 is available yet
 Note: No module for the vpx3224 is available yet
-Note: use encoder=X or decoder=X for non-default i2c chips
 
 ===========================
 
index 5c542e6..5bfa9a7 100644 (file)
@@ -275,6 +275,7 @@ pac7302             093a:2629       Genious iSlim 300
 pac7302                093a:262a       Webcam 300k
 pac7302                093a:262c       Philips SPC 230 NC
 jeilinj                0979:0280       Sakar 57379
+jeilinj                0979:0280       Sportscam DV15
 zc3xx          0ac8:0302       Z-star Vimicro zc0302
 vc032x         0ac8:0321       Vimicro generic vc0321
 vc032x         0ac8:0323       Vimicro Vc0323
diff --git a/Documentation/video4linux/uvcvideo.txt b/Documentation/video4linux/uvcvideo.txt
new file mode 100644 (file)
index 0000000..848d620
--- /dev/null
@@ -0,0 +1,239 @@
+Linux USB Video Class (UVC) driver
+==================================
+
+This file documents some driver-specific aspects of the UVC driver, such as
+driver-specific ioctls and implementation notes.
+
+Questions and remarks can be sent to the Linux UVC development mailing list at
+linux-uvc-devel@lists.berlios.de.
+
+
+Extension Unit (XU) support
+---------------------------
+
+1. Introduction
+
+The UVC specification allows for vendor-specific extensions through extension
+units (XUs). The Linux UVC driver supports extension unit controls (XU controls)
+through two separate mechanisms:
+
+  - through mappings of XU controls to V4L2 controls
+  - through a driver-specific ioctl interface
+
+The first one allows generic V4L2 applications to use XU controls by mapping
+certain XU controls onto V4L2 controls, which then show up during ordinary
+control enumeration.
+
+The second mechanism requires uvcvideo-specific knowledge for the application to
+access XU controls but exposes the entire UVC XU concept to user space for
+maximum flexibility.
+
+Both mechanisms complement each other and are described in more detail below.
+
+
+2. Control mappings
+
+The UVC driver provides an API for user space applications to define so-called
+control mappings at runtime. These allow for individual XU controls or byte
+ranges thereof to be mapped to new V4L2 controls. Such controls appear and
+function exactly like normal V4L2 controls (i.e. the stock controls, such as
+brightness, contrast, etc.). However, reading or writing of such a V4L2 controls
+triggers a read or write of the associated XU control.
+
+The ioctl used to create these control mappings is called UVCIOC_CTRL_MAP.
+Previous driver versions (before 0.2.0) required another ioctl to be used
+beforehand (UVCIOC_CTRL_ADD) to pass XU control information to the UVC driver.
+This is no longer necessary as newer uvcvideo versions query the information
+directly from the device.
+
+For details on the UVCIOC_CTRL_MAP ioctl please refer to the section titled
+"IOCTL reference" below.
+
+
+3. Driver specific XU control interface
+
+For applications that need to access XU controls directly, e.g. for testing
+purposes, firmware upload, or accessing binary controls, a second mechanism to
+access XU controls is provided in the form of a driver-specific ioctl, namely
+UVCIOC_CTRL_QUERY.
+
+A call to this ioctl allows applications to send queries to the UVC driver that
+directly map to the low-level UVC control requests.
+
+In order to make such a request the UVC unit ID of the control's extension unit
+and the control selector need to be known. This information either needs to be
+hardcoded in the application or queried using other ways such as by parsing the
+UVC descriptor or, if available, using the media controller API to enumerate a
+device's entities.
+
+Unless the control size is already known it is necessary to first make a
+UVC_GET_LEN requests in order to be able to allocate a sufficiently large buffer
+and set the buffer size to the correct value. Similarly, to find out whether
+UVC_GET_CUR or UVC_SET_CUR are valid requests for a given control, a
+UVC_GET_INFO request should be made. The bits 0 (GET supported) and 1 (SET
+supported) of the resulting byte indicate which requests are valid.
+
+With the addition of the UVCIOC_CTRL_QUERY ioctl the UVCIOC_CTRL_GET and
+UVCIOC_CTRL_SET ioctls have become obsolete since their functionality is a
+subset of the former ioctl. For the time being they are still supported but
+application developers are encouraged to use UVCIOC_CTRL_QUERY instead.
+
+For details on the UVCIOC_CTRL_QUERY ioctl please refer to the section titled
+"IOCTL reference" below.
+
+
+4. Security
+
+The API doesn't currently provide a fine-grained access control facility. The
+UVCIOC_CTRL_ADD and UVCIOC_CTRL_MAP ioctls require super user permissions.
+
+Suggestions on how to improve this are welcome.
+
+
+5. Debugging
+
+In order to debug problems related to XU controls or controls in general it is
+recommended to enable the UVC_TRACE_CONTROL bit in the module parameter 'trace'.
+This causes extra output to be written into the system log.
+
+
+6. IOCTL reference
+
+---- UVCIOC_CTRL_MAP - Map a UVC control to a V4L2 control ----
+
+Argument: struct uvc_xu_control_mapping
+
+Description:
+       This ioctl creates a mapping between a UVC control or part of a UVC
+       control and a V4L2 control. Once mappings are defined, userspace
+       applications can access vendor-defined UVC control through the V4L2
+       control API.
+
+       To create a mapping, applications fill the uvc_xu_control_mapping
+       structure with information about an existing UVC control defined with
+       UVCIOC_CTRL_ADD and a new V4L2 control.
+
+       A UVC control can be mapped to several V4L2 controls. For instance,
+       a UVC pan/tilt control could be mapped to separate pan and tilt V4L2
+       controls. The UVC control is divided into non overlapping fields using
+       the 'size' and 'offset' fields and are then independantly mapped to
+       V4L2 control.
+
+       For signed integer V4L2 controls the data_type field should be set to
+       UVC_CTRL_DATA_TYPE_SIGNED. Other values are currently ignored.
+
+Return value:
+       On success 0 is returned. On error -1 is returned and errno is set
+       appropriately.
+
+       ENOMEM
+               Not enough memory to perform the operation.
+       EPERM
+               Insufficient privileges (super user privileges are required).
+       EINVAL
+               No such UVC control.
+       EOVERFLOW
+               The requested offset and size would overflow the UVC control.
+       EEXIST
+               Mapping already exists.
+
+Data types:
+       * struct uvc_xu_control_mapping
+
+       __u32   id              V4L2 control identifier
+       __u8    name[32]        V4L2 control name
+       __u8    entity[16]      UVC extension unit GUID
+       __u8    selector        UVC control selector
+       __u8    size            V4L2 control size (in bits)
+       __u8    offset          V4L2 control offset (in bits)
+       enum v4l2_ctrl_type
+               v4l2_type       V4L2 control type
+       enum uvc_control_data_type
+               data_type       UVC control data type
+       struct uvc_menu_info
+               *menu_info      Array of menu entries (for menu controls only)
+       __u32   menu_count      Number of menu entries (for menu controls only)
+
+       * struct uvc_menu_info
+
+       __u32   value           Menu entry value used by the device
+       __u8    name[32]        Menu entry name
+
+
+       * enum uvc_control_data_type
+
+       UVC_CTRL_DATA_TYPE_RAW          Raw control (byte array)
+       UVC_CTRL_DATA_TYPE_SIGNED       Signed integer
+       UVC_CTRL_DATA_TYPE_UNSIGNED     Unsigned integer
+       UVC_CTRL_DATA_TYPE_BOOLEAN      Boolean
+       UVC_CTRL_DATA_TYPE_ENUM         Enumeration
+       UVC_CTRL_DATA_TYPE_BITMASK      Bitmask
+
+
+---- UVCIOC_CTRL_QUERY - Query a UVC XU control ----
+
+Argument: struct uvc_xu_control_query
+
+Description:
+       This ioctl queries a UVC XU control identified by its extension unit ID
+       and control selector.
+
+       There are a number of different queries available that closely
+       correspond to the low-level control requests described in the UVC
+       specification. These requests are:
+
+       UVC_GET_CUR
+               Obtain the current value of the control.
+       UVC_GET_MIN
+               Obtain the minimum value of the control.
+       UVC_GET_MAX
+               Obtain the maximum value of the control.
+       UVC_GET_DEF
+               Obtain the default value of the control.
+       UVC_GET_RES
+               Query the resolution of the control, i.e. the step size of the
+               allowed control values.
+       UVC_GET_LEN
+               Query the size of the control in bytes.
+       UVC_GET_INFO
+               Query the control information bitmap, which indicates whether
+               get/set requests are supported.
+       UVC_SET_CUR
+               Update the value of the control.
+
+       Applications must set the 'size' field to the correct length for the
+       control. Exceptions are the UVC_GET_LEN and UVC_GET_INFO queries, for
+       which the size must be set to 2 and 1, respectively. The 'data' field
+       must point to a valid writable buffer big enough to hold the indicated
+       number of data bytes.
+
+       Data is copied directly from the device without any driver-side
+       processing. Applications are responsible for data buffer formatting,
+       including little-endian/big-endian conversion. This is particularly
+       important for the result of the UVC_GET_LEN requests, which is always
+       returned as a little-endian 16-bit integer by the device.
+
+Return value:
+       On success 0 is returned. On error -1 is returned and errno is set
+       appropriately.
+
+       ENOENT
+               The device does not support the given control or the specified
+               extension unit could not be found.
+       ENOBUFS
+               The specified buffer size is incorrect (too big or too small).
+       EINVAL
+               An invalid request code was passed.
+       EBADRQC
+               The given request is not supported by the given control.
+       EFAULT
+               The data pointer references an inaccessible memory area.
+
+Data types:
+       * struct uvc_xu_control_query
+
+       __u8    unit            Extension unit ID
+       __u8    selector        Control selector
+       __u8    query           Request code to send to the device
+       __u16   size            Control data size (in bytes)
+       __u8    *data           Control value
index 9f47e38..9af2140 100644 (file)
@@ -378,12 +378,7 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
        dev->pci = pci;
 
        /* get chip-revision; this is needed to enable bug-fixes */
-       err = pci_read_config_dword(pci, PCI_CLASS_REVISION, &dev->revision);
-       if (err < 0) {
-               ERR(("pci_read_config_dword() failed.\n"));
-               goto err_disable;
-       }
-       dev->revision &= 0xf;
+       dev->revision = pci->revision;
 
        /* remap the memory from virtual to physical address */
 
index 6fc79f1..22d3ca3 100644 (file)
@@ -186,4 +186,12 @@ config MEDIA_TUNER_TDA18218
        default m if MEDIA_TUNER_CUSTOMISE
        help
          NXP TDA18218 silicon tuner driver.
+
+config MEDIA_TUNER_TDA18212
+       tristate "NXP TDA18212 silicon tuner"
+       depends on VIDEO_MEDIA && I2C
+       default m if MEDIA_TUNER_CUSTOMISE
+       help
+         NXP TDA18212 silicon tuner driver.
+
 endmenu
index 96da03d..2cb4f53 100644 (file)
@@ -25,6 +25,7 @@ obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o
 obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o
 obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o
 obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
+obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
 EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
index 0d6e094..56fe75c 100644 (file)
@@ -4024,6 +4024,8 @@ static int mxl5005s_set_params(struct dvb_frontend *fe,
                        case BANDWIDTH_8_MHZ:
                                req_bw  = MXL5005S_BANDWIDTH_8MHZ;
                                break;
+                       default:
+                               return -EINVAL;
                        }
                }
 
diff --git a/drivers/media/common/tuners/tda18212.c b/drivers/media/common/tuners/tda18212.c
new file mode 100644 (file)
index 0000000..1f1db20
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * NXP TDA18212HN silicon tuner driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "tda18212_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+/* write multiple registers */
+static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
+       int len)
+{
+       int ret;
+       u8 buf[len+1];
+       struct i2c_msg msg[1] = {
+               {
+                       .addr = priv->cfg->i2c_address,
+                       .flags = 0,
+                       .len = sizeof(buf),
+                       .buf = buf,
+               }
+       };
+
+       buf[0] = reg;
+       memcpy(&buf[1], val, len);
+
+       ret = i2c_transfer(priv->i2c, msg, 1);
+       if (ret == 1) {
+               ret = 0;
+       } else {
+               warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
+               ret = -EREMOTEIO;
+       }
+       return ret;
+}
+
+/* read multiple registers */
+static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
+       int len)
+{
+       int ret;
+       u8 buf[len];
+       struct i2c_msg msg[2] = {
+               {
+                       .addr = priv->cfg->i2c_address,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = &reg,
+               }, {
+                       .addr = priv->cfg->i2c_address,
+                       .flags = I2C_M_RD,
+                       .len = sizeof(buf),
+                       .buf = buf,
+               }
+       };
+
+       ret = i2c_transfer(priv->i2c, msg, 2);
+       if (ret == 2) {
+               memcpy(val, buf, len);
+               ret = 0;
+       } else {
+               warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
+               ret = -EREMOTEIO;
+       }
+
+       return ret;
+}
+
+/* write single register */
+static int tda18212_wr_reg(struct tda18212_priv *priv, u8 reg, u8 val)
+{
+       return tda18212_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register */
+static int tda18212_rd_reg(struct tda18212_priv *priv, u8 reg, u8 *val)
+{
+       return tda18212_rd_regs(priv, reg, val, 1);
+}
+
+#if 0 /* keep, useful when developing driver */
+static void tda18212_dump_regs(struct tda18212_priv *priv)
+{
+       int i;
+       u8 buf[256];
+
+       #define TDA18212_RD_LEN 32
+       for (i = 0; i < sizeof(buf); i += TDA18212_RD_LEN)
+               tda18212_rd_regs(priv, i, &buf[i], TDA18212_RD_LEN);
+
+       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 32, 1, buf,
+               sizeof(buf), true);
+
+       return;
+}
+#endif
+
+static int tda18212_set_params(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *p)
+{
+       struct tda18212_priv *priv = fe->tuner_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int ret, i;
+       u32 if_khz;
+       u8 buf[9];
+       static const u8 bw_params[][3] = {
+               /*  0f    13    23 */
+               { 0xb3, 0x20, 0x03 }, /* DVB-T 6 MHz */
+               { 0xb3, 0x31, 0x01 }, /* DVB-T 7 MHz */
+               { 0xb3, 0x22, 0x01 }, /* DVB-T 8 MHz */
+               { 0x92, 0x53, 0x03 }, /* DVB-C */
+       };
+
+       dbg("%s: delsys=%d RF=%d BW=%d", __func__,
+               c->delivery_system, c->frequency, c->bandwidth_hz);
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+       switch (c->delivery_system) {
+       case SYS_DVBT:
+               switch (c->bandwidth_hz) {
+               case 6000000:
+                       if_khz = priv->cfg->if_dvbt_6;
+                       i = 0;
+                       break;
+               case 7000000:
+                       if_khz = priv->cfg->if_dvbt_7;
+                       i = 1;
+                       break;
+               case 8000000:
+                       if_khz = priv->cfg->if_dvbt_8;
+                       i = 2;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       goto error;
+               }
+               break;
+       case SYS_DVBC_ANNEX_AC:
+               if_khz = priv->cfg->if_dvbc;
+               i = 3;
+               break;
+       default:
+               ret = -EINVAL;
+               goto error;
+       }
+
+       ret = tda18212_wr_reg(priv, 0x23, bw_params[i][2]);
+       if (ret)
+               goto error;
+
+       ret = tda18212_wr_reg(priv, 0x06, 0x00);
+       if (ret)
+               goto error;
+
+       ret = tda18212_wr_reg(priv, 0x0f, bw_params[i][0]);
+       if (ret)
+               goto error;
+
+       buf[0] = 0x02;
+       buf[1] = bw_params[i][1];
+       buf[2] = 0x03; /* default value */
+       buf[3] = if_khz / 50;
+       buf[4] = ((c->frequency / 1000) >> 16) & 0xff;
+       buf[5] = ((c->frequency / 1000) >>  8) & 0xff;
+       buf[6] = ((c->frequency / 1000) >>  0) & 0xff;
+       buf[7] = 0xc1;
+       buf[8] = 0x01;
+       ret = tda18212_wr_regs(priv, 0x12, buf, sizeof(buf));
+       if (ret)
+               goto error;
+
+exit:
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+       return ret;
+
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       goto exit;
+}
+
+static int tda18212_release(struct dvb_frontend *fe)
+{
+       kfree(fe->tuner_priv);
+       fe->tuner_priv = NULL;
+       return 0;
+}
+
+static const struct dvb_tuner_ops tda18212_tuner_ops = {
+       .info = {
+               .name           = "NXP TDA18212",
+
+               .frequency_min  =  48000000,
+               .frequency_max  = 864000000,
+               .frequency_step =      1000,
+       },
+
+       .release       = tda18212_release,
+
+       .set_params    = tda18212_set_params,
+};
+
+struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
+       struct i2c_adapter *i2c, struct tda18212_config *cfg)
+{
+       struct tda18212_priv *priv = NULL;
+       int ret;
+       u8 val;
+
+       priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return NULL;
+
+       priv->cfg = cfg;
+       priv->i2c = i2c;
+       fe->tuner_priv = priv;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+       /* check if the tuner is there */
+       ret = tda18212_rd_reg(priv, 0x00, &val);
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+       dbg("%s: ret:%d chip ID:%02x", __func__, ret, val);
+       if (ret || val != 0xc7) {
+               kfree(priv);
+               return NULL;
+       }
+
+       info("NXP TDA18212HN successfully identified.");
+
+       memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops,
+               sizeof(struct dvb_tuner_ops));
+
+       return fe;
+}
+EXPORT_SYMBOL(tda18212_attach);
+
+MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/tda18212.h b/drivers/media/common/tuners/tda18212.h
new file mode 100644 (file)
index 0000000..83b497f
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * NXP TDA18212HN silicon tuner driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef TDA18212_H
+#define TDA18212_H
+
+#include "dvb_frontend.h"
+
+struct tda18212_config {
+       u8 i2c_address;
+
+       u16 if_dvbt_6;
+       u16 if_dvbt_7;
+       u16 if_dvbt_8;
+       u16 if_dvbc;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_TDA18212) || \
+       (defined(CONFIG_MEDIA_TUNER_TDA18212_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
+       struct i2c_adapter *i2c, struct tda18212_config *cfg);
+#else
+static inline struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
+       struct i2c_adapter *i2c, struct tda18212_config *cfg)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/common/tuners/tda18212_priv.h b/drivers/media/common/tuners/tda18212_priv.h
new file mode 100644 (file)
index 0000000..9adff93
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * NXP TDA18212HN silicon tuner driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef TDA18212_PRIV_H
+#define TDA18212_PRIV_H
+
+#include "tda18212.h"
+
+#define LOG_PREFIX "tda18212"
+
+#undef dbg
+#define dbg(f, arg...) \
+       if (debug) \
+               printk(KERN_INFO   LOG_PREFIX": " f "\n" , ## arg)
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+struct tda18212_priv {
+       struct tda18212_config *cfg;
+       struct i2c_adapter *i2c;
+};
+
+#endif
index d884f5e..57022e8 100644 (file)
@@ -976,6 +976,10 @@ static int tda18271_set_params(struct dvb_frontend *fe,
                        tda_warn("bandwidth not set!\n");
                        return -EINVAL;
                }
+       } else if (fe->ops.info.type == FE_QAM) {
+               /* DVB-C */
+               map = &std_map->qam_8;
+               bw = 8000000;
        } else {
                tda_warn("modulation type not supported!\n");
                return -EINVAL;
index 1e28f7d..aa1b2e8 100644 (file)
@@ -628,6 +628,15 @@ static void xc_debug_dump(struct xc5000_priv *priv)
        dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
 }
 
+/*
+ * As defined on EN 300 429, the DVB-C roll-off factor is 0.15.
+ * So, the amount of the needed bandwith is given by:
+ *     Bw = Symbol_rate * (1 + 0.15)
+ * As such, the maximum symbol rate supported by 6 MHz is given by:
+ *     max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds
+ */
+#define MAX_SYMBOL_RATE_6MHz   5217391
+
 static int xc5000_set_params(struct dvb_frontend *fe,
        struct dvb_frontend_parameters *params)
 {
@@ -688,21 +697,32 @@ static int xc5000_set_params(struct dvb_frontend *fe,
                }
                priv->rf_mode = XC_RF_MODE_AIR;
        } else if (fe->ops.info.type == FE_QAM) {
-               dprintk(1, "%s() QAM\n", __func__);
                switch (params->u.qam.modulation) {
+               case QAM_256:
+               case QAM_AUTO:
                case QAM_16:
                case QAM_32:
                case QAM_64:
                case QAM_128:
-               case QAM_256:
-               case QAM_AUTO:
                        dprintk(1, "%s() QAM modulation\n", __func__);
-                       priv->bandwidth = BANDWIDTH_8_MHZ;
-                       priv->video_standard = DTV7_8;
-                       priv->freq_hz = params->frequency - 2750000;
                        priv->rf_mode = XC_RF_MODE_CABLE;
+                       /*
+                        * Using a 8MHz bandwidth sometimes fail
+                        * with 6MHz-spaced channels, due to inter-carrier
+                        * interference. So, use DTV6 firmware
+                        */
+                       if (params->u.qam.symbol_rate <= MAX_SYMBOL_RATE_6MHz) {
+                               priv->bandwidth = BANDWIDTH_6_MHZ;
+                               priv->video_standard = DTV6;
+                               priv->freq_hz = params->frequency - 1750000;
+                       } else {
+                               priv->bandwidth = BANDWIDTH_8_MHZ;
+                               priv->video_standard = DTV7_8;
+                               priv->freq_hz = params->frequency - 2750000;
+                       }
                        break;
                default:
+                       dprintk(1, "%s() Unsupported QAM type\n", __func__);
                        return -EINVAL;
                }
        } else {
index 03f96d6..44f8fb5 100644 (file)
@@ -290,10 +290,8 @@ static void flexcop_pci_dma_exit(struct flexcop_pci *fc_pci)
 static int flexcop_pci_init(struct flexcop_pci *fc_pci)
 {
        int ret;
-       u8 card_rev;
 
-       pci_read_config_byte(fc_pci->pdev, PCI_CLASS_REVISION, &card_rev);
-       info("card revision %x", card_rev);
+       info("card revision %x", fc_pci->pdev->revision);
 
        if ((ret = pci_enable_device(fc_pci->pdev)) != 0)
                return ret;
index 99d6209..b34fa95 100644 (file)
@@ -460,7 +460,7 @@ static int __devinit bt878_probe(struct pci_dev *dev,
                goto fail0;
        }
 
-       pci_read_config_byte(dev, PCI_CLASS_REVISION, &bt->revision);
+       bt->revision = dev->revision;
        pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
 
 
index 4a88a3e..faa3671 100644 (file)
@@ -478,97 +478,94 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
 
 EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
 
-void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
+static inline int find_next_packet(const u8 *buf, int pos, size_t count,
+                                  const int pktsize)
 {
-       int p = 0, i, j;
+       int start = pos, lost;
 
-       spin_lock(&demux->lock);
-
-       if (demux->tsbufp) {
-               i = demux->tsbufp;
-               j = 188 - i;
-               if (count < j) {
-                       memcpy(&demux->tsbuf[i], buf, count);
-                       demux->tsbufp += count;
-                       goto bailout;
-               }
-               memcpy(&demux->tsbuf[i], buf, j);
-               if (demux->tsbuf[0] == 0x47)
-                       dvb_dmx_swfilter_packet(demux, demux->tsbuf);
-               demux->tsbufp = 0;
-               p += j;
+       while (pos < count) {
+               if (buf[pos] == 0x47 ||
+                   (pktsize == 204 && buf[pos] == 0xB8))
+                       break;
+               pos++;
        }
 
-       while (p < count) {
-               if (buf[p] == 0x47) {
-                       if (count - p >= 188) {
-                               dvb_dmx_swfilter_packet(demux, &buf[p]);
-                               p += 188;
-                       } else {
-                               i = count - p;
-                               memcpy(demux->tsbuf, &buf[p], i);
-                               demux->tsbufp = i;
-                               goto bailout;
-                       }
-               } else
-                       p++;
+       lost = pos - start;
+       if (lost) {
+               /* This garbage is part of a valid packet? */
+               int backtrack = pos - pktsize;
+               if (backtrack >= 0 && (buf[backtrack] == 0x47 ||
+                   (pktsize == 204 && buf[backtrack] == 0xB8)))
+                       return backtrack;
        }
 
-bailout:
-       spin_unlock(&demux->lock);
+       return pos;
 }
 
-EXPORT_SYMBOL(dvb_dmx_swfilter);
-
-void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
+/* Filter all pktsize= 188 or 204 sized packets and skip garbage. */
+static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
+               size_t count, const int pktsize)
 {
        int p = 0, i, j;
-       u8 tmppack[188];
+       const u8 *q;
 
        spin_lock(&demux->lock);
 
-       if (demux->tsbufp) {
+       if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */
                i = demux->tsbufp;
-               j = 204 - i;
+               j = pktsize - i;
                if (count < j) {
                        memcpy(&demux->tsbuf[i], buf, count);
                        demux->tsbufp += count;
                        goto bailout;
                }
                memcpy(&demux->tsbuf[i], buf, j);
-               if ((demux->tsbuf[0] == 0x47) || (demux->tsbuf[0] == 0xB8)) {
-                       memcpy(tmppack, demux->tsbuf, 188);
-                       if (tmppack[0] == 0xB8)
-                               tmppack[0] = 0x47;
-                       dvb_dmx_swfilter_packet(demux, tmppack);
-               }
+               if (demux->tsbuf[0] == 0x47) /* double check */
+                       dvb_dmx_swfilter_packet(demux, demux->tsbuf);
                demux->tsbufp = 0;
                p += j;
        }
 
-       while (p < count) {
-               if ((buf[p] == 0x47) || (buf[p] == 0xB8)) {
-                       if (count - p >= 204) {
-                               memcpy(tmppack, &buf[p], 188);
-                               if (tmppack[0] == 0xB8)
-                                       tmppack[0] = 0x47;
-                               dvb_dmx_swfilter_packet(demux, tmppack);
-                               p += 204;
-                       } else {
-                               i = count - p;
-                               memcpy(demux->tsbuf, &buf[p], i);
-                               demux->tsbufp = i;
-                               goto bailout;
-                       }
-               } else {
-                       p++;
+       while (1) {
+               p = find_next_packet(buf, p, count, pktsize);
+               if (p >= count)
+                       break;
+               if (count - p < pktsize)
+                       break;
+
+               q = &buf[p];
+
+               if (pktsize == 204 && (*q == 0xB8)) {
+                       memcpy(demux->tsbuf, q, 188);
+                       demux->tsbuf[0] = 0x47;
+                       q = demux->tsbuf;
                }
+               dvb_dmx_swfilter_packet(demux, q);
+               p += pktsize;
+       }
+
+       i = count - p;
+       if (i) {
+               memcpy(demux->tsbuf, &buf[p], i);
+               demux->tsbufp = i;
+               if (pktsize == 204 && demux->tsbuf[0] == 0xB8)
+                       demux->tsbuf[0] = 0x47;
        }
 
 bailout:
        spin_unlock(&demux->lock);
 }
 
+void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
+{
+       _dvb_dmx_swfilter(demux, buf, count, 188);
+}
+EXPORT_SYMBOL(dvb_dmx_swfilter);
+
+void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
+{
+       _dvb_dmx_swfilter(demux, buf, count, 204);
+}
 EXPORT_SYMBOL(dvb_dmx_swfilter_204);
 
 static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux)
index 31e2c0d..9827804 100644 (file)
@@ -105,7 +105,8 @@ struct dvb_frontend_private {
 
        /* thread/frontend values */
        struct dvb_device *dvbdev;
-       struct dvb_frontend_parameters parameters;
+       struct dvb_frontend_parameters parameters_in;
+       struct dvb_frontend_parameters parameters_out;
        struct dvb_fe_events events;
        struct semaphore sem;
        struct list_head list_head;
@@ -160,12 +161,11 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
 
        e = &events->events[events->eventw];
 
-       memcpy (&e->parameters, &fepriv->parameters,
-               sizeof (struct dvb_frontend_parameters));
-
        if (status & FE_HAS_LOCK)
                if (fe->ops.get_frontend)
-                       fe->ops.get_frontend(fe, &e->parameters);
+                       fe->ops.get_frontend(fe, &fepriv->parameters_out);
+
+       e->parameters = fepriv->parameters_out;
 
        events->eventw = wp;
 
@@ -277,12 +277,12 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
        int ready = 0;
        int fe_set_err = 0;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       int original_inversion = fepriv->parameters.inversion;
-       u32 original_frequency = fepriv->parameters.frequency;
+       int original_inversion = fepriv->parameters_in.inversion;
+       u32 original_frequency = fepriv->parameters_in.frequency;
 
        /* are we using autoinversion? */
        autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
-                        (fepriv->parameters.inversion == INVERSION_AUTO));
+                        (fepriv->parameters_in.inversion == INVERSION_AUTO));
 
        /* setup parameters correctly */
        while(!ready) {
@@ -348,18 +348,19 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
                fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step);
 
        /* set the frontend itself */
-       fepriv->parameters.frequency += fepriv->lnb_drift;
+       fepriv->parameters_in.frequency += fepriv->lnb_drift;
        if (autoinversion)
-               fepriv->parameters.inversion = fepriv->inversion;
+               fepriv->parameters_in.inversion = fepriv->inversion;
        if (fe->ops.set_frontend)
-               fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters);
+               fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters_in);
+       fepriv->parameters_out = fepriv->parameters_in;
        if (fe_set_err < 0) {
                fepriv->state = FESTATE_ERROR;
                return fe_set_err;
        }
 
-       fepriv->parameters.frequency = original_frequency;
-       fepriv->parameters.inversion = original_inversion;
+       fepriv->parameters_in.frequency = original_frequency;
+       fepriv->parameters_in.inversion = original_inversion;
 
        fepriv->auto_sub_step++;
        return 0;
@@ -383,7 +384,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
                if (fepriv->state & FESTATE_RETUNE) {
                        if (fe->ops.set_frontend)
                                retval = fe->ops.set_frontend(fe,
-                                                       &fepriv->parameters);
+                                                       &fepriv->parameters_in);
+                       fepriv->parameters_out = fepriv->parameters_in;
                        if (retval < 0)
                                fepriv->state = FESTATE_ERROR;
                        else
@@ -413,8 +415,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
 
                /* if we're tuned, then we have determined the correct inversion */
                if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
-                   (fepriv->parameters.inversion == INVERSION_AUTO)) {
-                       fepriv->parameters.inversion = fepriv->inversion;
+                   (fepriv->parameters_in.inversion == INVERSION_AUTO)) {
+                       fepriv->parameters_in.inversion = fepriv->inversion;
                }
                return;
        }
@@ -594,12 +596,14 @@ restart:
 
                                if (fepriv->state & FESTATE_RETUNE) {
                                        dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);
-                                       params = &fepriv->parameters;
+                                       params = &fepriv->parameters_in;
                                        fepriv->state = FESTATE_TUNED;
                                }
 
                                if (fe->ops.tune)
                                        fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
+                               if (params)
+                                       fepriv->parameters_out = *params;
 
                                if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) {
                                        dprintk("%s: state changed, adding current state\n", __func__);
@@ -612,11 +616,9 @@ restart:
                                dvb_frontend_swzigzag(fe);
                                break;
                        case DVBFE_ALGO_CUSTOM:
-                               params = NULL; /* have we been asked to RETUNE ?        */
                                dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state);
                                if (fepriv->state & FESTATE_RETUNE) {
                                        dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__);
-                                       params = &fepriv->parameters;
                                        fepriv->state = FESTATE_TUNED;
                                }
                                /* Case where we are going to search for a carrier
@@ -625,7 +627,7 @@ restart:
                                 */
                                if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) {
                                        if (fe->ops.search) {
-                                               fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters);
+                                               fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters_in);
                                                /* We did do a search as was requested, the flags are
                                                 * now unset as well and has the flags wrt to search.
                                                 */
@@ -636,11 +638,12 @@ restart:
                                /* Track the carrier if the search was successful */
                                if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) {
                                        if (fe->ops.track)
-                                               fe->ops.track(fe, &fepriv->parameters);
+                                               fe->ops.track(fe, &fepriv->parameters_in);
                                } else {
                                        fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
                                        fepriv->delay = HZ / 2;
                                }
+                               fepriv->parameters_out = fepriv->parameters_in;
                                fe->ops.read_status(fe, &s);
                                if (s != fepriv->status) {
                                        dvb_frontend_add_event(fe, s); /* update event list */
@@ -860,34 +863,34 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
 
 static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int i;
 
-       memset(&(fe->dtv_property_cache), 0,
-                       sizeof(struct dtv_frontend_properties));
-
-       fe->dtv_property_cache.state = DTV_CLEAR;
-       fe->dtv_property_cache.delivery_system = SYS_UNDEFINED;
-       fe->dtv_property_cache.inversion = INVERSION_AUTO;
-       fe->dtv_property_cache.fec_inner = FEC_AUTO;
-       fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO;
-       fe->dtv_property_cache.bandwidth_hz = BANDWIDTH_AUTO;
-       fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO;
-       fe->dtv_property_cache.hierarchy = HIERARCHY_AUTO;
-       fe->dtv_property_cache.symbol_rate = QAM_AUTO;
-       fe->dtv_property_cache.code_rate_HP = FEC_AUTO;
-       fe->dtv_property_cache.code_rate_LP = FEC_AUTO;
-
-       fe->dtv_property_cache.isdbt_partial_reception = -1;
-       fe->dtv_property_cache.isdbt_sb_mode = -1;
-       fe->dtv_property_cache.isdbt_sb_subchannel = -1;
-       fe->dtv_property_cache.isdbt_sb_segment_idx = -1;
-       fe->dtv_property_cache.isdbt_sb_segment_count = -1;
-       fe->dtv_property_cache.isdbt_layer_enabled = 0x7;
+       memset(c, 0, sizeof(struct dtv_frontend_properties));
+
+       c->state = DTV_CLEAR;
+       c->delivery_system = SYS_UNDEFINED;
+       c->inversion = INVERSION_AUTO;
+       c->fec_inner = FEC_AUTO;
+       c->transmission_mode = TRANSMISSION_MODE_AUTO;
+       c->bandwidth_hz = BANDWIDTH_AUTO;
+       c->guard_interval = GUARD_INTERVAL_AUTO;
+       c->hierarchy = HIERARCHY_AUTO;
+       c->symbol_rate = QAM_AUTO;
+       c->code_rate_HP = FEC_AUTO;
+       c->code_rate_LP = FEC_AUTO;
+
+       c->isdbt_partial_reception = -1;
+       c->isdbt_sb_mode = -1;
+       c->isdbt_sb_subchannel = -1;
+       c->isdbt_sb_segment_idx = -1;
+       c->isdbt_sb_segment_count = -1;
+       c->isdbt_layer_enabled = 0x7;
        for (i = 0; i < 3; i++) {
-               fe->dtv_property_cache.layer[i].fec = FEC_AUTO;
-               fe->dtv_property_cache.layer[i].modulation = QAM_AUTO;
-               fe->dtv_property_cache.layer[i].interleaving = -1;
-               fe->dtv_property_cache.layer[i].segment_count = -1;
+               c->layer[i].fec = FEC_AUTO;
+               c->layer[i].modulation = QAM_AUTO;
+               c->layer[i].interleaving = -1;
+               c->layer[i].segment_count = -1;
        }
 
        return 0;
@@ -1020,10 +1023,9 @@ static int is_legacy_delivery_system(fe_delivery_system_t s)
  * it's being used for the legacy or new API, reducing code and complexity.
  */
 static void dtv_property_cache_sync(struct dvb_frontend *fe,
-                                   struct dvb_frontend_parameters *p)
+                                   struct dtv_frontend_properties *c,
+                                   const struct dvb_frontend_parameters *p)
 {
-       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-
        c->frequency = p->frequency;
        c->inversion = p->inversion;
 
@@ -1074,9 +1076,9 @@ static void dtv_property_cache_sync(struct dvb_frontend *fe,
  */
 static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
 {
-       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       struct dvb_frontend_parameters *p = &fepriv->parameters;
+       struct dvb_frontend_parameters *p = &fepriv->parameters_in;
 
        p->frequency = c->frequency;
        p->inversion = c->inversion;
@@ -1086,14 +1088,12 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
                dprintk("%s() Preparing QPSK req\n", __func__);
                p->u.qpsk.symbol_rate = c->symbol_rate;
                p->u.qpsk.fec_inner = c->fec_inner;
-               c->delivery_system = SYS_DVBS;
                break;
        case FE_QAM:
                dprintk("%s() Preparing QAM req\n", __func__);
                p->u.qam.symbol_rate = c->symbol_rate;
                p->u.qam.fec_inner = c->fec_inner;
                p->u.qam.modulation = c->modulation;
-               c->delivery_system = SYS_DVBC_ANNEX_AC;
                break;
        case FE_OFDM:
                dprintk("%s() Preparing OFDM req\n", __func__);
@@ -1111,15 +1111,10 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
                p->u.ofdm.transmission_mode = c->transmission_mode;
                p->u.ofdm.guard_interval = c->guard_interval;
                p->u.ofdm.hierarchy_information = c->hierarchy;
-               c->delivery_system = SYS_DVBT;
                break;
        case FE_ATSC:
                dprintk("%s() Preparing VSB req\n", __func__);
                p->u.vsb.modulation = c->modulation;
-               if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
-                       c->delivery_system = SYS_ATSC;
-               else
-                       c->delivery_system = SYS_DVBC_ANNEX_B;
                break;
        }
 }
@@ -1129,9 +1124,9 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
  */
 static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
 {
-       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       struct dvb_frontend_parameters *p = &fepriv->parameters;
+       struct dvb_frontend_parameters *p = &fepriv->parameters_in;
 
        p->frequency = c->frequency;
        p->inversion = c->inversion;
@@ -1148,10 +1143,9 @@ static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
                break;
        }
 
-       if(c->delivery_system == SYS_ISDBT) {
-               /* Fake out a generic DVB-T request so we pass validation in the ioctl */
-               p->frequency = c->frequency;
-               p->inversion = c->inversion;
+       /* Fake out a generic DVB-T request so we pass validation in the ioctl */
+       if ((c->delivery_system == SYS_ISDBT) ||
+           (c->delivery_system == SYS_DVBT2)) {
                p->u.ofdm.constellation = QAM_AUTO;
                p->u.ofdm.code_rate_HP = FEC_AUTO;
                p->u.ofdm.code_rate_LP = FEC_AUTO;
@@ -1171,7 +1165,7 @@ static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
 
 static void dtv_property_cache_submit(struct dvb_frontend *fe)
 {
-       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 
        /* For legacy delivery systems we don't need the delivery_system to
         * be specified, but we populate the older structures from the cache
@@ -1204,133 +1198,149 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
                                    struct dtv_property *tvp,
                                    struct file *file)
 {
-       int r = 0;
-
-       /* Allow the frontend to validate incoming properties */
-       if (fe->ops.get_property)
-               r = fe->ops.get_property(fe, tvp);
+       const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct dtv_frontend_properties cdetected;
+       int r;
 
-       if (r < 0)
-               return r;
+       /*
+        * If the driver implements a get_frontend function, then convert
+        * detected parameters to S2API properties.
+        */
+       if (fe->ops.get_frontend) {
+               cdetected = *c;
+               dtv_property_cache_sync(fe, &cdetected, &fepriv->parameters_out);
+               c = &cdetected;
+       }
 
        switch(tvp->cmd) {
        case DTV_FREQUENCY:
-               tvp->u.data = fe->dtv_property_cache.frequency;
+               tvp->u.data = c->frequency;
                break;
        case DTV_MODULATION:
-               tvp->u.data = fe->dtv_property_cache.modulation;
+               tvp->u.data = c->modulation;
                break;
        case DTV_BANDWIDTH_HZ:
-               tvp->u.data = fe->dtv_property_cache.bandwidth_hz;
+               tvp->u.data = c->bandwidth_hz;
                break;
        case DTV_INVERSION:
-               tvp->u.data = fe->dtv_property_cache.inversion;
+               tvp->u.data = c->inversion;
                break;
        case DTV_SYMBOL_RATE:
-               tvp->u.data = fe->dtv_property_cache.symbol_rate;
+               tvp->u.data = c->symbol_rate;
                break;
        case DTV_INNER_FEC:
-               tvp->u.data = fe->dtv_property_cache.fec_inner;
+               tvp->u.data = c->fec_inner;
                break;
        case DTV_PILOT:
-               tvp->u.data = fe->dtv_property_cache.pilot;
+               tvp->u.data = c->pilot;
                break;
        case DTV_ROLLOFF:
-               tvp->u.data = fe->dtv_property_cache.rolloff;
+               tvp->u.data = c->rolloff;
                break;
        case DTV_DELIVERY_SYSTEM:
-               tvp->u.data = fe->dtv_property_cache.delivery_system;
+               tvp->u.data = c->delivery_system;
                break;
        case DTV_VOLTAGE:
-               tvp->u.data = fe->dtv_property_cache.voltage;
+               tvp->u.data = c->voltage;
                break;
        case DTV_TONE:
-               tvp->u.data = fe->dtv_property_cache.sectone;
+               tvp->u.data = c->sectone;
                break;
        case DTV_API_VERSION:
                tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR;
                break;
        case DTV_CODE_RATE_HP:
-               tvp->u.data = fe->dtv_property_cache.code_rate_HP;
+               tvp->u.data = c->code_rate_HP;
                break;
        case DTV_CODE_RATE_LP:
-               tvp->u.data = fe->dtv_property_cache.code_rate_LP;
+               tvp->u.data = c->code_rate_LP;
                break;
        case DTV_GUARD_INTERVAL:
-               tvp->u.data = fe->dtv_property_cache.guard_interval;
+               tvp->u.data = c->guard_interval;
                break;
        case DTV_TRANSMISSION_MODE:
-               tvp->u.data = fe->dtv_property_cache.transmission_mode;
+               tvp->u.data = c->transmission_mode;
                break;
        case DTV_HIERARCHY:
-               tvp->u.data = fe->dtv_property_cache.hierarchy;
+               tvp->u.data = c->hierarchy;
                break;
 
        /* ISDB-T Support here */
        case DTV_ISDBT_PARTIAL_RECEPTION:
-               tvp->u.data = fe->dtv_property_cache.isdbt_partial_reception;
+               tvp->u.data = c->isdbt_partial_reception;
                break;
        case DTV_ISDBT_SOUND_BROADCASTING:
-               tvp->u.data = fe->dtv_property_cache.isdbt_sb_mode;
+               tvp->u.data = c->isdbt_sb_mode;
                break;
        case DTV_ISDBT_SB_SUBCHANNEL_ID:
-               tvp->u.data = fe->dtv_property_cache.isdbt_sb_subchannel;
+               tvp->u.data = c->isdbt_sb_subchannel;
                break;
        case DTV_ISDBT_SB_SEGMENT_IDX:
-               tvp->u.data = fe->dtv_property_cache.isdbt_sb_segment_idx;
+               tvp->u.data = c->isdbt_sb_segment_idx;
                break;
        case DTV_ISDBT_SB_SEGMENT_COUNT:
-               tvp->u.data = fe->dtv_property_cache.isdbt_sb_segment_count;
+               tvp->u.data = c->isdbt_sb_segment_count;
                break;
        case DTV_ISDBT_LAYER_ENABLED:
-               tvp->u.data = fe->dtv_property_cache.isdbt_layer_enabled;
+               tvp->u.data = c->isdbt_layer_enabled;
                break;
        case DTV_ISDBT_LAYERA_FEC:
-               tvp->u.data = fe->dtv_property_cache.layer[0].fec;
+               tvp->u.data = c->layer[0].fec;
                break;
        case DTV_ISDBT_LAYERA_MODULATION:
-               tvp->u.data = fe->dtv_property_cache.layer[0].modulation;
+               tvp->u.data = c->layer[0].modulation;
                break;
        case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
-               tvp->u.data = fe->dtv_property_cache.layer[0].segment_count;
+               tvp->u.data = c->layer[0].segment_count;
                break;
        case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
-               tvp->u.data = fe->dtv_property_cache.layer[0].interleaving;
+               tvp->u.data = c->layer[0].interleaving;
                break;
        case DTV_ISDBT_LAYERB_FEC:
-               tvp->u.data = fe->dtv_property_cache.layer[1].fec;
+               tvp->u.data = c->layer[1].fec;
                break;
        case DTV_ISDBT_LAYERB_MODULATION:
-               tvp->u.data = fe->dtv_property_cache.layer[1].modulation;
+               tvp->u.data = c->layer[1].modulation;
                break;
        case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
-               tvp->u.data = fe->dtv_property_cache.layer[1].segment_count;
+               tvp->u.data = c->layer[1].segment_count;
                break;
        case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
-               tvp->u.data = fe->dtv_property_cache.layer[1].interleaving;
+               tvp->u.data = c->layer[1].interleaving;
                break;
        case DTV_ISDBT_LAYERC_FEC:
-               tvp->u.data = fe->dtv_property_cache.layer[2].fec;
+               tvp->u.data = c->layer[2].fec;
                break;
        case DTV_ISDBT_LAYERC_MODULATION:
-               tvp->u.data = fe->dtv_property_cache.layer[2].modulation;
+               tvp->u.data = c->layer[2].modulation;
                break;
        case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
-               tvp->u.data = fe->dtv_property_cache.layer[2].segment_count;
+               tvp->u.data = c->layer[2].segment_count;
                break;
        case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
-               tvp->u.data = fe->dtv_property_cache.layer[2].interleaving;
+               tvp->u.data = c->layer[2].interleaving;
                break;
        case DTV_ISDBS_TS_ID:
-               tvp->u.data = fe->dtv_property_cache.isdbs_ts_id;
+               tvp->u.data = c->isdbs_ts_id;
+               break;
+       case DTV_DVBT2_PLP_ID:
+               tvp->u.data = c->dvbt2_plp_id;
                break;
        default:
-               r = -1;
+               return -EINVAL;
+       }
+
+       /* Allow the frontend to override outgoing properties */
+       if (fe->ops.get_property) {
+               r = fe->ops.get_property(fe, tvp);
+               if (r < 0)
+                       return r;
        }
 
        dtv_property_dump(tvp);
 
-       return r;
+       return 0;
 }
 
 static int dtv_property_process_set(struct dvb_frontend *fe,
@@ -1338,15 +1348,16 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
                                    struct file *file)
 {
        int r = 0;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
        dtv_property_dump(tvp);
 
        /* Allow the frontend to validate incoming properties */
-       if (fe->ops.set_property)
+       if (fe->ops.set_property) {
                r = fe->ops.set_property(fe, tvp);
-
-       if (r < 0)
-               return r;
+               if (r < 0)
+                       return r;
+       }
 
        switch(tvp->cmd) {
        case DTV_CLEAR:
@@ -1361,126 +1372,129 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
                 * tunerequest so we can pass validation in the FE_SET_FRONTEND
                 * ioctl.
                 */
-               fe->dtv_property_cache.state = tvp->cmd;
+               c->state = tvp->cmd;
                dprintk("%s() Finalised property cache\n", __func__);
                dtv_property_cache_submit(fe);
 
-               r |= dvb_frontend_ioctl_legacy(file, FE_SET_FRONTEND,
-                       &fepriv->parameters);
+               r = dvb_frontend_ioctl_legacy(file, FE_SET_FRONTEND,
+                       &fepriv->parameters_in);
                break;
        case DTV_FREQUENCY:
-               fe->dtv_property_cache.frequency = tvp->u.data;
+               c->frequency = tvp->u.data;
                break;
        case DTV_MODULATION:
-               fe->dtv_property_cache.modulation = tvp->u.data;
+               c->modulation = tvp->u.data;
                break;
        case DTV_BANDWIDTH_HZ:
-               fe->dtv_property_cache.bandwidth_hz = tvp->u.data;
+               c->bandwidth_hz = tvp->u.data;
                break;
        case DTV_INVERSION:
-               fe->dtv_property_cache.inversion = tvp->u.data;
+               c->inversion = tvp->u.data;
                break;
        case DTV_SYMBOL_RATE:
-               fe->dtv_property_cache.symbol_rate = tvp->u.data;
+               c->symbol_rate = tvp->u.data;
                break;
        case DTV_INNER_FEC:
-               fe->dtv_property_cache.fec_inner = tvp->u.data;
+               c->fec_inner = tvp->u.data;
                break;
        case DTV_PILOT:
-               fe->dtv_property_cache.pilot = tvp->u.data;
+               c->pilot = tvp->u.data;
                break;
        case DTV_ROLLOFF:
-               fe->dtv_property_cache.rolloff = tvp->u.data;
+               c->rolloff = tvp->u.data;
                break;
        case DTV_DELIVERY_SYSTEM:
-               fe->dtv_property_cache.delivery_system = tvp->u.data;
+               c->delivery_system = tvp->u.data;
                break;
        case DTV_VOLTAGE:
-               fe->dtv_property_cache.voltage = tvp->u.data;
+               c->voltage = tvp->u.data;
                r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE,
-                       (void *)fe->dtv_property_cache.voltage);
+                       (void *)c->voltage);
                break;
        case DTV_TONE:
-               fe->dtv_property_cache.sectone = tvp->u.data;
+               c->sectone = tvp->u.data;
                r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE,
-                       (void *)fe->dtv_property_cache.sectone);
+                       (void *)c->sectone);
                break;
        case DTV_CODE_RATE_HP:
-               fe->dtv_property_cache.code_rate_HP = tvp->u.data;
+               c->code_rate_HP = tvp->u.data;
                break;
        case DTV_CODE_RATE_LP:
-               fe->dtv_property_cache.code_rate_LP = tvp->u.data;
+               c->code_rate_LP = tvp->u.data;
                break;
        case DTV_GUARD_INTERVAL:
-               fe->dtv_property_cache.guard_interval = tvp->u.data;
+               c->guard_interval = tvp->u.data;
                break;
        case DTV_TRANSMISSION_MODE:
-               fe->dtv_property_cache.transmission_mode = tvp->u.data;
+               c->transmission_mode = tvp->u.data;
                break;
        case DTV_HIERARCHY:
-               fe->dtv_property_cache.hierarchy = tvp->u.data;
+               c->hierarchy = tvp->u.data;
                break;
 
        /* ISDB-T Support here */
        case DTV_ISDBT_PARTIAL_RECEPTION:
-               fe->dtv_property_cache.isdbt_partial_reception = tvp->u.data;
+               c->isdbt_partial_reception = tvp->u.data;
                break;
        case DTV_ISDBT_SOUND_BROADCASTING:
-               fe->dtv_property_cache.isdbt_sb_mode = tvp->u.data;
+               c->isdbt_sb_mode = tvp->u.data;
                break;
        case DTV_ISDBT_SB_SUBCHANNEL_ID:
-               fe->dtv_property_cache.isdbt_sb_subchannel = tvp->u.data;
+               c->isdbt_sb_subchannel = tvp->u.data;
                break;
        case DTV_ISDBT_SB_SEGMENT_IDX:
-               fe->dtv_property_cache.isdbt_sb_segment_idx = tvp->u.data;
+               c->isdbt_sb_segment_idx = tvp->u.data;
                break;
        case DTV_ISDBT_SB_SEGMENT_COUNT:
-               fe->dtv_property_cache.isdbt_sb_segment_count = tvp->u.data;
+               c->isdbt_sb_segment_count = tvp->u.data;
                break;
        case DTV_ISDBT_LAYER_ENABLED:
-               fe->dtv_property_cache.isdbt_layer_enabled = tvp->u.data;
+               c->isdbt_layer_enabled = tvp->u.data;
                break;
        case DTV_ISDBT_LAYERA_FEC:
-               fe->dtv_property_cache.layer[0].fec = tvp->u.data;
+               c->layer[0].fec = tvp->u.data;
                break;
        case DTV_ISDBT_LAYERA_MODULATION:
-               fe->dtv_property_cache.layer[0].modulation = tvp->u.data;
+               c->layer[0].modulation = tvp->u.data;
                break;
        case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
-               fe->dtv_property_cache.layer[0].segment_count = tvp->u.data;
+               c->layer[0].segment_count = tvp->u.data;
                break;
        case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
-               fe->dtv_property_cache.layer[0].interleaving = tvp->u.data;
+               c->layer[0].interleaving = tvp->u.data;
                break;
        case DTV_ISDBT_LAYERB_FEC:
-               fe->dtv_property_cache.layer[1].fec = tvp->u.data;
+               c->layer[1].fec = tvp->u.data;
                break;
        case DTV_ISDBT_LAYERB_MODULATION:
-               fe->dtv_property_cache.layer[1].modulation = tvp->u.data;
+               c->layer[1].modulation = tvp->u.data;
                break;
        case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
-               fe->dtv_property_cache.layer[1].segment_count = tvp->u.data;
+               c->layer[1].segment_count = tvp->u.data;
                break;
        case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
-               fe->dtv_property_cache.layer[1].interleaving = tvp->u.data;
+               c->layer[1].interleaving = tvp->u.data;
                break;
        case DTV_ISDBT_LAYERC_FEC:
-               fe->dtv_property_cache.layer[2].fec = tvp->u.data;
+               c->layer[2].fec = tvp->u.data;
                break;
        case DTV_ISDBT_LAYERC_MODULATION:
-               fe->dtv_property_cache.layer[2].modulation = tvp->u.data;
+               c->layer[2].modulation = tvp->u.data;
                break;
        case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
-               fe->dtv_property_cache.layer[2].segment_count = tvp->u.data;
+               c->layer[2].segment_count = tvp->u.data;
                break;
        case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
-               fe->dtv_property_cache.layer[2].interleaving = tvp->u.data;
+               c->layer[2].interleaving = tvp->u.data;
                break;
        case DTV_ISDBS_TS_ID:
-               fe->dtv_property_cache.isdbs_ts_id = tvp->u.data;
+               c->isdbs_ts_id = tvp->u.data;
+               break;
+       case DTV_DVBT2_PLP_ID:
+               c->dvbt2_plp_id = tvp->u.data;
                break;
        default:
-               r = -1;
+               return -EINVAL;
        }
 
        return r;
@@ -1491,6 +1505,7 @@ static int dvb_frontend_ioctl(struct file *file,
 {
        struct dvb_device *dvbdev = file->private_data;
        struct dvb_frontend *fe = dvbdev->priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
        int err = -EOPNOTSUPP;
 
@@ -1510,7 +1525,7 @@ static int dvb_frontend_ioctl(struct file *file,
        if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))
                err = dvb_frontend_ioctl_properties(file, cmd, parg);
        else {
-               fe->dtv_property_cache.state = DTV_UNDEFINED;
+               c->state = DTV_UNDEFINED;
                err = dvb_frontend_ioctl_legacy(file, cmd, parg);
        }
 
@@ -1523,6 +1538,7 @@ static int dvb_frontend_ioctl_properties(struct file *file,
 {
        struct dvb_device *dvbdev = file->private_data;
        struct dvb_frontend *fe = dvbdev->priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int err = 0;
 
        struct dtv_properties *tvps = NULL;
@@ -1554,11 +1570,13 @@ static int dvb_frontend_ioctl_properties(struct file *file,
                }
 
                for (i = 0; i < tvps->num; i++) {
-                       (tvp + i)->result = dtv_property_process_set(fe, tvp + i, file);
-                       err |= (tvp + i)->result;
+                       err = dtv_property_process_set(fe, tvp + i, file);
+                       if (err < 0)
+                               goto out;
+                       (tvp + i)->result = err;
                }
 
-               if(fe->dtv_property_cache.state == DTV_TUNE)
+               if (c->state == DTV_TUNE)
                        dprintk("%s() Property cache is full, tuning\n", __func__);
 
        } else
@@ -1586,8 +1604,10 @@ static int dvb_frontend_ioctl_properties(struct file *file,
                }
 
                for (i = 0; i < tvps->num; i++) {
-                       (tvp + i)->result = dtv_property_process_get(fe, tvp + i, file);
-                       err |= (tvp + i)->result;
+                       err = dtv_property_process_get(fe, tvp + i, file);
+                       if (err < 0)
+                               goto out;
+                       (tvp + i)->result = err;
                }
 
                if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {
@@ -1787,10 +1807,11 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
                break;
 
        case FE_SET_FRONTEND: {
+               struct dtv_frontend_properties *c = &fe->dtv_property_cache;
                struct dvb_frontend_tune_settings fetunesettings;
 
-               if(fe->dtv_property_cache.state == DTV_TUNE) {
-                       if (dvb_frontend_check_parameters(fe, &fepriv->parameters) < 0) {
+               if (c->state == DTV_TUNE) {
+                       if (dvb_frontend_check_parameters(fe, &fepriv->parameters_in) < 0) {
                                err = -EINVAL;
                                break;
                        }
@@ -1800,9 +1821,9 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
                                break;
                        }
 
-                       memcpy (&fepriv->parameters, parg,
+                       memcpy (&fepriv->parameters_in, parg,
                                sizeof (struct dvb_frontend_parameters));
-                       dtv_property_cache_sync(fe, &fepriv->parameters);
+                       dtv_property_cache_sync(fe, c, &fepriv->parameters_in);
                }
 
                memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
@@ -1811,15 +1832,15 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
 
                /* force auto frequency inversion if requested */
                if (dvb_force_auto_inversion) {
-                       fepriv->parameters.inversion = INVERSION_AUTO;
+                       fepriv->parameters_in.inversion = INVERSION_AUTO;
                        fetunesettings.parameters.inversion = INVERSION_AUTO;
                }
                if (fe->ops.info.type == FE_OFDM) {
                        /* without hierarchical coding code_rate_LP is irrelevant,
                         * so we tolerate the otherwise invalid FEC_NONE setting */
-                       if (fepriv->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
-                           fepriv->parameters.u.ofdm.code_rate_LP == FEC_NONE)
-                               fepriv->parameters.u.ofdm.code_rate_LP = FEC_AUTO;
+                       if (fepriv->parameters_in.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
+                           fepriv->parameters_in.u.ofdm.code_rate_LP == FEC_NONE)
+                               fepriv->parameters_in.u.ofdm.code_rate_LP = FEC_AUTO;
                }
 
                /* get frontend-specific tuning settings */
@@ -1832,8 +1853,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
                        switch(fe->ops.info.type) {
                        case FE_QPSK:
                                fepriv->min_delay = HZ/20;
-                               fepriv->step_size = fepriv->parameters.u.qpsk.symbol_rate / 16000;
-                               fepriv->max_drift = fepriv->parameters.u.qpsk.symbol_rate / 2000;
+                               fepriv->step_size = fepriv->parameters_in.u.qpsk.symbol_rate / 16000;
+                               fepriv->max_drift = fepriv->parameters_in.u.qpsk.symbol_rate / 2000;
                                break;
 
                        case FE_QAM:
@@ -1875,8 +1896,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
 
        case FE_GET_FRONTEND:
                if (fe->ops.get_frontend) {
-                       memcpy (parg, &fepriv->parameters, sizeof (struct dvb_frontend_parameters));
-                       err = fe->ops.get_frontend(fe, (struct dvb_frontend_parameters*) parg);
+                       err = fe->ops.get_frontend(fe, &fepriv->parameters_out);
+                       memcpy(parg, &fepriv->parameters_out, sizeof(struct dvb_frontend_parameters));
                }
                break;
 
index 3b86050..5590eb6 100644 (file)
@@ -358,6 +358,9 @@ struct dtv_frontend_properties {
 
        /* ISDB-T specifics */
        u32                     isdbs_ts_id;
+
+       /* DVB-T2 specifics */
+       u32                     dvbt2_plp_id;
 };
 
 struct dvb_frontend {
index c545039..e85304c 100644 (file)
@@ -292,6 +292,11 @@ config DVB_USB_ANYSEE
        select DVB_MT352 if !DVB_FE_CUSTOMISE
        select DVB_ZL10353 if !DVB_FE_CUSTOMISE
        select DVB_TDA10023 if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_TDA18212 if !MEDIA_TUNER_CUSTOMISE
+       select DVB_CX24116 if !DVB_FE_CUSTOMISE
+       select DVB_STV0900 if !DVB_FE_CUSTOMISE
+       select DVB_STV6110 if !DVB_FE_CUSTOMISE
+       select DVB_ISL6423 if !DVB_FE_CUSTOMISE
        help
          Say Y here to support the Anysee E30, Anysee E30 Plus or
          Anysee E30 C Plus DVB USB2.0 receiver.
index f8e9bf1..b95a95e 100644 (file)
@@ -78,17 +78,26 @@ static struct rc_map_table rc_map_a800_table[] = {
 
 static int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
-       u8 key[5];
+       int ret;
+       u8 *key = kmalloc(5, GFP_KERNEL);
+       if (!key)
+               return -ENOMEM;
+
        if (usb_control_msg(d->udev,usb_rcvctrlpipe(d->udev,0),
                                0x04, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, key, 5,
-                               2000) != 5)
-               return -ENODEV;
+                               2000) != 5) {
+               ret = -ENODEV;
+               goto out;
+       }
 
        /* call the universal NEC remote processor, to find out the key's state and event */
        dvb_usb_nec_rc_key_to_event(d,key,event,state);
        if (key[0] != 0)
                deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
-       return 0;
+       ret = 0;
+out:
+       kfree(key);
+       return ret;
 }
 
 /* USB Driver stuff */
index 6b402e9..4dc1ca3 100644 (file)
 #include "mt352.h"
 #include "mt352_priv.h"
 #include "zl10353.h"
+#include "tda18212.h"
+#include "cx24116.h"
+#include "stv0900.h"
+#include "stv6110.h"
+#include "isl6423.h"
 
 /* debug */
 static int dvb_usb_anysee_debug;
@@ -105,6 +110,27 @@ static int anysee_write_reg(struct dvb_usb_device *d, u16 reg, u8 val)
        return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
 }
 
+/* write single register with mask */
+static int anysee_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val,
+       u8 mask)
+{
+       int ret;
+       u8 tmp;
+
+       /* no need for read if whole reg is written */
+       if (mask != 0xff) {
+               ret = anysee_read_reg(d, reg, &tmp);
+               if (ret)
+                       return ret;
+
+               val &= mask;
+               tmp &= ~mask;
+               val |= tmp;
+       }
+
+       return anysee_write_reg(d, reg, val);
+}
+
 static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id)
 {
        u8 buf[] = {CMD_GET_HW_INFO};
@@ -162,18 +188,18 @@ static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
                if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
                        u8 buf[6];
                        buf[0] = CMD_I2C_READ;
-                       buf[1] = msg[i].addr + 1;
+                       buf[1] = (msg[i].addr << 1) | 0x01;
                        buf[2] = msg[i].buf[0];
-                       buf[3] = 0x00;
-                       buf[4] = 0x00;
-                       buf[5] = 0x01;
+                       buf[3] = msg[i].buf[1];
+                       buf[4] = msg[i].len-1;
+                       buf[5] = msg[i+1].len;
                        ret = anysee_ctrl_msg(d, buf, sizeof(buf), msg[i+1].buf,
                                msg[i+1].len);
                        inc = 2;
                } else {
                        u8 buf[4+msg[i].len];
                        buf[0] = CMD_I2C_WRITE;
-                       buf[1] = msg[i].addr;
+                       buf[1] = (msg[i].addr << 1);
                        buf[2] = msg[i].len;
                        buf[3] = 0x01;
                        memcpy(&buf[4], msg[i].buf, msg[i].len);
@@ -224,7 +250,7 @@ static int anysee_mt352_demod_init(struct dvb_frontend *fe)
 
 /* Callbacks for DVB USB */
 static struct tda10023_config anysee_tda10023_config = {
-       .demod_address = 0x1a,
+       .demod_address = (0x1a >> 1),
        .invert = 0,
        .xtal   = 16000000,
        .pll_m  = 11,
@@ -235,143 +261,539 @@ static struct tda10023_config anysee_tda10023_config = {
 };
 
 static struct mt352_config anysee_mt352_config = {
-       .demod_address = 0x1e,
+       .demod_address = (0x1e >> 1),
        .demod_init    = anysee_mt352_demod_init,
 };
 
 static struct zl10353_config anysee_zl10353_config = {
-       .demod_address = 0x1e,
+       .demod_address = (0x1e >> 1),
        .parallel_ts = 1,
 };
 
+static struct zl10353_config anysee_zl10353_tda18212_config2 = {
+       .demod_address = (0x1e >> 1),
+       .parallel_ts = 1,
+       .disable_i2c_gate_ctrl = 1,
+       .no_tuner = 1,
+       .if2 = 41500,
+};
+
+static struct zl10353_config anysee_zl10353_tda18212_config = {
+       .demod_address = (0x18 >> 1),
+       .parallel_ts = 1,
+       .disable_i2c_gate_ctrl = 1,
+       .no_tuner = 1,
+       .if2 = 41500,
+};
+
+static struct tda10023_config anysee_tda10023_tda18212_config = {
+       .demod_address = (0x1a >> 1),
+       .xtal   = 16000000,
+       .pll_m  = 12,
+       .pll_p  = 3,
+       .pll_n  = 1,
+       .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C,
+       .deltaf = 0xba02,
+};
+
+static struct tda18212_config anysee_tda18212_config = {
+       .i2c_address = (0xc0 >> 1),
+       .if_dvbt_6 = 4150,
+       .if_dvbt_7 = 4150,
+       .if_dvbt_8 = 4150,
+       .if_dvbc = 5000,
+};
+
+static struct cx24116_config anysee_cx24116_config = {
+       .demod_address = (0xaa >> 1),
+       .mpg_clk_pos_pol = 0x00,
+       .i2c_wr_max = 48,
+};
+
+static struct stv0900_config anysee_stv0900_config = {
+       .demod_address = (0xd0 >> 1),
+       .demod_mode = 0,
+       .xtal = 8000000,
+       .clkmode = 3,
+       .diseqc_mode = 2,
+       .tun1_maddress = 0,
+       .tun1_adc = 1, /* 1 Vpp */
+       .path1_mode = 3,
+};
+
+static struct stv6110_config anysee_stv6110_config = {
+       .i2c_address = (0xc0 >> 1),
+       .mclk = 16000000,
+       .clk_div = 1,
+};
+
+static struct isl6423_config anysee_isl6423_config = {
+       .current_max = SEC_CURRENT_800m,
+       .curlim  = SEC_CURRENT_LIM_OFF,
+       .mod_extern = 1,
+       .addr = (0x10 >> 1),
+};
+
+/*
+ * New USB device strings: Mfr=1, Product=2, SerialNumber=0
+ * Manufacturer: AMT.CO.KR
+ *
+ * E30 VID=04b4 PID=861f HW=2 FW=2.1 Product=????????
+ * PCB: ?
+ * parts: DNOS404ZH102A(MT352, DTT7579(?))
+ *
+ * E30 VID=04b4 PID=861f HW=2 FW=2.1 Product=????????
+ * PCB: ?
+ * parts: DNOS404ZH103A(ZL10353, DTT7579(?))
+ *
+ * E30 Plus VID=04b4 PID=861f HW=6 FW=1.0 "anysee"
+ * PCB: 507CD (rev1.1)
+ * parts: DNOS404ZH103A(ZL10353, DTT7579(?)), CST56I01
+ * OEA=80 OEB=00 OEC=00 OED=ff OEF=fe
+ * IOA=4f IOB=ff IOC=00 IOD=06 IOF=01
+ * IOD[0] ZL10353 1=enabled
+ * IOA[7] TS 0=enabled
+ * tuner is not behind ZL10353 I2C-gate (no care if gate disabled or not)
+ *
+ * E30 C Plus VID=04b4 PID=861f HW=10 FW=1.0 "anysee-DC(LP)"
+ * PCB: 507DC (rev0.2)
+ * parts: TDA10023, DTOS403IH102B TM, CST56I01
+ * OEA=80 OEB=00 OEC=00 OED=ff OEF=fe
+ * IOA=4f IOB=ff IOC=00 IOD=26 IOF=01
+ * IOD[0] TDA10023 1=enabled
+ *
+ * E30 S2 Plus VID=04b4 PID=861f HW=11 FW=0.1 "anysee-S2(LP)"
+ * PCB: 507SI (rev2.1)
+ * parts: BS2N10WCC01(CX24116, CX24118), ISL6423, TDA8024
+ * OEA=80 OEB=00 OEC=ff OED=ff OEF=fe
+ * IOA=4d IOB=ff IOC=00 IOD=26 IOF=01
+ * IOD[0] CX24116 1=enabled
+ *
+ * E30 C Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)"
+ * PCB: 507FA (rev0.4)
+ * parts: TDA10023, DTOS403IH102B TM, TDA8024
+ * OEA=80 OEB=00 OEC=ff OED=ff OEF=ff
+ * IOA=4d IOB=ff IOC=00 IOD=00 IOF=c0
+ * IOD[5] TDA10023 1=enabled
+ * IOE[0] tuner 1=enabled
+ *
+ * E30 Combo Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)"
+ * PCB: 507FA (rev1.1)
+ * parts: ZL10353, TDA10023, DTOS403IH102B TM, TDA8024
+ * OEA=80 OEB=00 OEC=ff OED=ff OEF=ff
+ * IOA=4d IOB=ff IOC=00 IOD=00 IOF=c0
+ * DVB-C:
+ * IOD[5] TDA10023 1=enabled
+ * IOE[0] tuner 1=enabled
+ * DVB-T:
+ * IOD[0] ZL10353 1=enabled
+ * IOE[0] tuner 0=enabled
+ * tuner is behind ZL10353 I2C-gate
+ *
+ * E7 TC VID=1c73 PID=861f HW=18 FW=0.7 AMTCI=0.5 "anysee-E7TC(LP)"
+ * PCB: 508TC (rev0.6)
+ * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212)
+ * OEA=80 OEB=00 OEC=03 OED=f7 OEF=ff
+ * IOA=4d IOB=00 IOC=cc IOD=48 IOF=e4
+ * IOA[7] TS 1=enabled
+ * IOE[4] TDA18212 1=enabled
+ * DVB-C:
+ * IOD[6] ZL10353 0=disabled
+ * IOD[5] TDA10023 1=enabled
+ * IOE[0] IF 1=enabled
+ * DVB-T:
+ * IOD[5] TDA10023 0=disabled
+ * IOD[6] ZL10353 1=enabled
+ * IOE[0] IF 0=enabled
+ *
+ * E7 S2 VID=1c73 PID=861f HW=19 FW=0.4 AMTCI=0.5 "anysee-E7S2(LP)"
+ * PCB: 508S2 (rev0.7)
+ * parts: DNBU10512IST(STV0903, STV6110), ISL6423
+ * OEA=80 OEB=00 OEC=03 OED=f7 OEF=ff
+ * IOA=4d IOB=00 IOC=c4 IOD=08 IOF=e4
+ * IOA[7] TS 1=enabled
+ * IOE[5] STV0903 1=enabled
+ *
+ */
+
 static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
 {
        int ret;
        struct anysee_state *state = adap->dev->priv;
        u8 hw_info[3];
-       u8 io_d; /* IO port D */
+       u8 tmp;
+       struct i2c_msg msg[2] = {
+               {
+                       .addr = anysee_tda18212_config.i2c_address,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = "\x00",
+               }, {
+                       .addr = anysee_tda18212_config.i2c_address,
+                       .flags = I2C_M_RD,
+                       .len = 1,
+                       .buf = &tmp,
+               }
+       };
 
-       /* check which hardware we have
-          We must do this call two times to get reliable values (hw bug). */
+       /* Check which hardware we have.
+        * We must do this call two times to get reliable values (hw bug).
+        */
        ret = anysee_get_hw_info(adap->dev, hw_info);
        if (ret)
-               return ret;
+               goto error;
+
        ret = anysee_get_hw_info(adap->dev, hw_info);
        if (ret)
-               return ret;
+               goto error;
 
        /* Meaning of these info bytes are guessed. */
-       info("firmware version:%d.%d.%d hardware id:%d",
-               0, hw_info[1], hw_info[2], hw_info[0]);
+       info("firmware version:%d.%d hardware id:%d",
+               hw_info[1], hw_info[2], hw_info[0]);
 
-       ret = anysee_read_reg(adap->dev, 0xb0, &io_d); /* IO port D */
-       if (ret)
-               return ret;
-       deb_info("%s: IO port D:%02x\n", __func__, io_d);
-
-       /* Select demod using trial and error method. */
-
-       /* Try to attach demodulator in following order:
-             model      demod     hw  firmware
-          1. E30        MT352     02  0.2.1
-          2. E30        ZL10353   02  0.2.1
-          3. E30 Combo  ZL10353   0f  0.1.2    DVB-T/C combo
-          4. E30 Plus   ZL10353   06  0.1.0
-          5. E30C Plus  TDA10023  0a  0.1.0    rev 0.2
-             E30C Plus  TDA10023  0f  0.1.2    rev 0.4
-             E30 Combo  TDA10023  0f  0.1.2    DVB-T/C combo
-       */
-
-       /* Zarlink MT352 DVB-T demod inside of Samsung DNOS404ZH102A NIM */
-       adap->fe = dvb_attach(mt352_attach, &anysee_mt352_config,
-                             &adap->dev->i2c_adap);
-       if (adap->fe != NULL) {
-               state->tuner = DVB_PLL_THOMSON_DTT7579;
-               return 0;
-       }
+       state->hw = hw_info[0];
 
-       /* Zarlink ZL10353 DVB-T demod inside of Samsung DNOS404ZH103A NIM */
-       adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
-                             &adap->dev->i2c_adap);
-       if (adap->fe != NULL) {
-               state->tuner = DVB_PLL_THOMSON_DTT7579;
-               return 0;
-       }
+       switch (state->hw) {
+       case ANYSEE_HW_02: /* 2 */
+               /* E30 */
+
+               /* attach demod */
+               adap->fe = dvb_attach(mt352_attach, &anysee_mt352_config,
+                       &adap->dev->i2c_adap);
+               if (adap->fe)
+                       break;
+
+               /* attach demod */
+               adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
+                       &adap->dev->i2c_adap);
+
+               break;
+       case ANYSEE_HW_507CD: /* 6 */
+               /* E30 Plus */
 
-       /* for E30 Combo Plus DVB-T demodulator */
-       if (dvb_usb_anysee_delsys) {
-               ret = anysee_write_reg(adap->dev, 0xb0, 0x01);
+               /* enable DVB-T demod on IOD[0] */
+               ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01);
                if (ret)
-                       return ret;
+                       goto error;
+
+               /* enable transport stream on IOA[7] */
+               ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (0 << 7), 0x80);
+               if (ret)
+                       goto error;
 
-               /* Zarlink ZL10353 DVB-T demod */
+               /* attach demod */
                adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
-                                     &adap->dev->i2c_adap);
-               if (adap->fe != NULL) {
-                       state->tuner = DVB_PLL_SAMSUNG_DTOS403IH102A;
-                       return 0;
+                       &adap->dev->i2c_adap);
+
+               break;
+       case ANYSEE_HW_507DC: /* 10 */
+               /* E30 C Plus */
+
+               /* enable DVB-C demod on IOD[0] */
+               ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01);
+               if (ret)
+                       goto error;
+
+               /* attach demod */
+               adap->fe = dvb_attach(tda10023_attach, &anysee_tda10023_config,
+                       &adap->dev->i2c_adap, 0x48);
+
+               break;
+       case ANYSEE_HW_507SI: /* 11 */
+               /* E30 S2 Plus */
+
+               /* enable DVB-S/S2 demod on IOD[0] */
+               ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01);
+               if (ret)
+                       goto error;
+
+               /* attach demod */
+               adap->fe = dvb_attach(cx24116_attach, &anysee_cx24116_config,
+                       &adap->dev->i2c_adap);
+
+               break;
+       case ANYSEE_HW_507FA: /* 15 */
+               /* E30 Combo Plus */
+               /* E30 C Plus */
+
+               /* enable tuner on IOE[4] */
+               ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10);
+               if (ret)
+                       goto error;
+
+               /* probe TDA18212 */
+               tmp = 0;
+               ret = i2c_transfer(&adap->dev->i2c_adap, msg, 2);
+               if (ret == 2 && tmp == 0xc7)
+                       deb_info("%s: TDA18212 found\n", __func__);
+               else
+                       tmp = 0;
+
+               /* disable tuner on IOE[4] */
+               ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 4), 0x10);
+               if (ret)
+                       goto error;
+
+               if (dvb_usb_anysee_delsys) {
+                       /* disable DVB-C demod on IOD[5] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
+                               0x20);
+                       if (ret)
+                               goto error;
+
+                       /* enable DVB-T demod on IOD[0] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0),
+                               0x01);
+                       if (ret)
+                               goto error;
+
+                       /* attach demod */
+                       if (tmp == 0xc7) {
+                               /* TDA18212 config */
+                               adap->fe = dvb_attach(zl10353_attach,
+                                       &anysee_zl10353_tda18212_config2,
+                                       &adap->dev->i2c_adap);
+                       } else {
+                               /* PLL config */
+                               adap->fe = dvb_attach(zl10353_attach,
+                                       &anysee_zl10353_config,
+                                       &adap->dev->i2c_adap);
+                       }
+               } else {
+                       /* disable DVB-T demod on IOD[0] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0),
+                               0x01);
+                       if (ret)
+                               goto error;
+
+                       /* enable DVB-C demod on IOD[5] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
+                               0x20);
+                       if (ret)
+                               goto error;
+
+                       /* attach demod */
+                       if (tmp == 0xc7) {
+                               /* TDA18212 config */
+                               adap->fe = dvb_attach(tda10023_attach,
+                                       &anysee_tda10023_tda18212_config,
+                                       &adap->dev->i2c_adap, 0x48);
+                       } else {
+                               /* PLL config */
+                               adap->fe = dvb_attach(tda10023_attach,
+                                       &anysee_tda10023_config,
+                                       &adap->dev->i2c_adap, 0x48);
+                       }
                }
-       }
 
-       /* connect demod on IO port D for TDA10023 & ZL10353 */
-       ret = anysee_write_reg(adap->dev, 0xb0, 0x25);
-       if (ret)
-               return ret;
+               break;
+       case ANYSEE_HW_508TC: /* 18 */
+               /* E7 TC */
 
-       /* Zarlink ZL10353 DVB-T demod inside of Samsung DNOS404ZH103A NIM */
-       adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
-                             &adap->dev->i2c_adap);
-       if (adap->fe != NULL) {
-               state->tuner = DVB_PLL_THOMSON_DTT7579;
-               return 0;
-       }
+               /* enable transport stream on IOA[7] */
+               ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80);
+               if (ret)
+                       goto error;
+
+               if (dvb_usb_anysee_delsys) {
+                       /* disable DVB-C demod on IOD[5] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
+                               0x20);
+                       if (ret)
+                               goto error;
+
+                       /* enable DVB-T demod on IOD[6] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6),
+                               0x40);
+                       if (ret)
+                               goto error;
+
+                       /* enable IF route on IOE[0] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0),
+                               0x01);
+                       if (ret)
+                               goto error;
+
+                       /* attach demod */
+                       adap->fe = dvb_attach(zl10353_attach,
+                               &anysee_zl10353_tda18212_config,
+                               &adap->dev->i2c_adap);
+               } else {
+                       /* disable DVB-T demod on IOD[6] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6),
+                               0x40);
+                       if (ret)
+                               goto error;
+
+                       /* enable DVB-C demod on IOD[5] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
+                               0x20);
+                       if (ret)
+                               goto error;
+
+                       /* enable IF route on IOE[0] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0),
+                               0x01);
+                       if (ret)
+                               goto error;
+
+                       /* attach demod */
+                       adap->fe = dvb_attach(tda10023_attach,
+                               &anysee_tda10023_tda18212_config,
+                               &adap->dev->i2c_adap, 0x48);
+               }
 
-       /* IO port E - E30C rev 0.4 board requires this */
-       ret = anysee_write_reg(adap->dev, 0xb1, 0xa7);
-       if (ret)
-               return ret;
+               break;
+       case ANYSEE_HW_508S2: /* 19 */
+               /* E7 S2 */
 
-       /* Philips TDA10023 DVB-C demod */
-       adap->fe = dvb_attach(tda10023_attach, &anysee_tda10023_config,
-                             &adap->dev->i2c_adap, 0x48);
-       if (adap->fe != NULL) {
-               state->tuner = DVB_PLL_SAMSUNG_DTOS403IH102A;
-               return 0;
-       }
+               /* enable transport stream on IOA[7] */
+               ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80);
+               if (ret)
+                       goto error;
 
-       /* return IO port D to init value for safe */
-       ret = anysee_write_reg(adap->dev, 0xb0, io_d);
-       if (ret)
-               return ret;
+               /* enable DVB-S/S2 demod on IOE[5] */
+               ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20);
+               if (ret)
+                       goto error;
+
+               /* attach demod */
+               adap->fe = dvb_attach(stv0900_attach, &anysee_stv0900_config,
+                       &adap->dev->i2c_adap, 0);
 
-       err("Unknown Anysee version: %02x %02x %02x. "\
-           "Please report the <linux-dvb@linuxtv.org>.",
-           hw_info[0], hw_info[1], hw_info[2]);
+               break;
+       }
 
-       return -ENODEV;
+       if (!adap->fe) {
+               /* we have no frontend :-( */
+               ret = -ENODEV;
+               err("Unsupported Anysee version. " \
+                       "Please report the <linux-media@vger.kernel.org>.");
+       }
+error:
+       return ret;
 }
 
 static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
 {
        struct anysee_state *state = adap->dev->priv;
+       struct dvb_frontend *fe;
+       int ret;
        deb_info("%s:\n", __func__);
 
-       switch (state->tuner) {
-       case DVB_PLL_THOMSON_DTT7579:
-               /* Thomson dtt7579 (not sure) PLL inside of:
-                  Samsung DNOS404ZH102A NIM
-                  Samsung DNOS404ZH103A NIM */
-               dvb_attach(dvb_pll_attach, adap->fe, 0x61,
-                          NULL, DVB_PLL_THOMSON_DTT7579);
+       switch (state->hw) {
+       case ANYSEE_HW_02: /* 2 */
+               /* E30 */
+
+               /* attach tuner */
+               fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc2 >> 1),
+                       NULL, DVB_PLL_THOMSON_DTT7579);
+
+               break;
+       case ANYSEE_HW_507CD: /* 6 */
+               /* E30 Plus */
+
+               /* attach tuner */
+               fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc2 >> 1),
+                       &adap->dev->i2c_adap, DVB_PLL_THOMSON_DTT7579);
+
+               break;
+       case ANYSEE_HW_507DC: /* 10 */
+               /* E30 C Plus */
+
+               /* attach tuner */
+               fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc0 >> 1),
+                       &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
+
+               break;
+       case ANYSEE_HW_507SI: /* 11 */
+               /* E30 S2 Plus */
+
+               /* attach LNB controller */
+               fe = dvb_attach(isl6423_attach, adap->fe, &adap->dev->i2c_adap,
+                       &anysee_isl6423_config);
+
+               break;
+       case ANYSEE_HW_507FA: /* 15 */
+               /* E30 Combo Plus */
+               /* E30 C Plus */
+
+               if (dvb_usb_anysee_delsys) {
+                       /* enable DVB-T tuner on IOE[0] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0),
+                               0x01);
+                       if (ret)
+                               goto error;
+               } else {
+                       /* enable DVB-C tuner on IOE[0] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0),
+                               0x01);
+                       if (ret)
+                               goto error;
+               }
+
+               /* Try first attach TDA18212 silicon tuner on IOE[4], if that
+                * fails attach old simple PLL. */
+
+               /* enable tuner on IOE[4] */
+               ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10);
+               if (ret)
+                       goto error;
+
+               /* attach tuner */
+               fe = dvb_attach(tda18212_attach, adap->fe, &adap->dev->i2c_adap,
+                       &anysee_tda18212_config);
+               if (fe)
+                       break;
+
+               /* disable tuner on IOE[4] */
+               ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 4), 0x10);
+               if (ret)
+                       goto error;
+
+               /* attach tuner */
+               fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc0 >> 1),
+                       &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
+
                break;
-       case DVB_PLL_SAMSUNG_DTOS403IH102A:
-               /* Unknown PLL inside of Samsung DTOS403IH102A tuner module */
-               dvb_attach(dvb_pll_attach, adap->fe, 0xc0,
-                          &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
+       case ANYSEE_HW_508TC: /* 18 */
+               /* E7 TC */
+
+               /* enable tuner on IOE[4] */
+               ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10);
+               if (ret)
+                       goto error;
+
+               /* attach tuner */
+               fe = dvb_attach(tda18212_attach, adap->fe, &adap->dev->i2c_adap,
+                       &anysee_tda18212_config);
+
                break;
+       case ANYSEE_HW_508S2: /* 19 */
+               /* E7 S2 */
+
+               /* attach tuner */
+               fe = dvb_attach(stv6110_attach, adap->fe,
+                       &anysee_stv6110_config, &adap->dev->i2c_adap);
+
+               if (fe) {
+                       /* attach LNB controller */
+                       fe = dvb_attach(isl6423_attach, adap->fe,
+                               &adap->dev->i2c_adap, &anysee_isl6423_config);
+               }
+
+               break;
+       default:
+               fe = NULL;
        }
 
-       return 0;
+       if (fe)
+               ret = 0;
+       else
+               ret = -ENODEV;
+
+error:
+       return ret;
 }
 
 static int anysee_rc_query(struct dvb_usb_device *d)
index 7ca01ff..a7673aa 100644 (file)
@@ -57,10 +57,29 @@ enum cmd {
 };
 
 struct anysee_state {
-       u8 tuner;
+       u8 hw; /* PCB ID */
        u8 seq;
 };
 
+#define ANYSEE_HW_02     2 /* E30 */
+#define ANYSEE_HW_507CD  6 /* E30 Plus */
+#define ANYSEE_HW_507DC 10 /* E30 C Plus */
+#define ANYSEE_HW_507SI 11 /* E30 S2 Plus */
+#define ANYSEE_HW_507FA 15 /* E30 Combo Plus / E30 C Plus */
+#define ANYSEE_HW_508TC 18 /* E7 TC */
+#define ANYSEE_HW_508S2 19 /* E7 S2 */
+
+#define REG_IOA       0x80 /* Port A (bit addressable) */
+#define REG_IOB       0x90 /* Port B (bit addressable) */
+#define REG_IOC       0xa0 /* Port C (bit addressable) */
+#define REG_IOD       0xb0 /* Port D (bit addressable) */
+#define REG_IOE       0xb1 /* Port E (NOT bit addressable) */
+#define REG_OEA       0xb2 /* Port A Output Enable */
+#define REG_OEB       0xb3 /* Port B Output Enable */
+#define REG_OEC       0xb4 /* Port C Output Enable */
+#define REG_OED       0xb5 /* Port D Output Enable */
+#define REG_OEE       0xb6 /* Port E Output Enable */
+
 #endif
 
 /***************************************************************************
@@ -136,7 +155,7 @@ General reply packet(s) are always used if not own reply defined.
 ----------------------------------------------------------------------------
 |    04 | 0x00
 ----------------------------------------------------------------------------
-|    05 | 0x01
+|    05 | data length
 ----------------------------------------------------------------------------
 | 06-59 | don't care
 ----------------------------------------------------------------------------
index eb34cc3..2351077 100644 (file)
@@ -33,8 +33,16 @@ static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
 {
        int ret;
        u16 index;
-       u8 usb_buf[6]; /* enough for all known requests,
-                         read returns 5 and write 6 bytes */
+       u8 *usb_buf;
+
+       /*
+        * allocate enough for all known requests,
+        * read returns 5 and write 6 bytes
+        */
+       usb_buf = kmalloc(6, GFP_KERNEL);
+       if (!usb_buf)
+               return -ENOMEM;
+
        switch (wlen) {
        case 1:
                index = wbuf[0] << 8;
@@ -45,14 +53,15 @@ static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
                break;
        default:
                warn("wlen = %x, aborting.", wlen);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto error;
        }
 
        ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,
                              USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index,
-                             usb_buf, sizeof(usb_buf), AU6610_USB_TIMEOUT);
+                             usb_buf, 6, AU6610_USB_TIMEOUT);
        if (ret < 0)
-               return ret;
+               goto error;
 
        switch (operation) {
        case AU6610_REQ_I2C_READ:
@@ -60,7 +69,8 @@ static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
                /* requested value is always 5th byte in buffer */
                rbuf[0] = usb_buf[4];
        }
-
+error:
+       kfree(usb_buf);
        return ret;
 }
 
index 3df2045..6d1a304 100644 (file)
@@ -39,7 +39,7 @@ static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)
        u8 requesttype;
        u16 value;
        u16 index;
-       u8 buf[req->data_len];
+       u8 *buf;
 
        request = req->cmd;
        value = req->value;
@@ -62,6 +62,12 @@ static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)
                goto error;
        }
 
+       buf = kmalloc(req->data_len, GFP_KERNEL);
+       if (!buf) {
+               ret = -ENOMEM;
+               goto error;
+       }
+
        if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
                /* write */
                memcpy(buf, req->data, req->data_len);
@@ -74,7 +80,7 @@ static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)
        msleep(1); /* avoid I2C errors */
 
        ret = usb_control_msg(udev, pipe, request, requesttype, value, index,
-                               buf, sizeof(buf), CE6230_USB_TIMEOUT);
+                               buf, req->data_len, CE6230_USB_TIMEOUT);
 
        ce6230_debug_dump(request, requesttype, value, index, buf,
                req->data_len, deb_xfer);
@@ -88,6 +94,7 @@ static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)
        if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
                memcpy(req->data, buf, req->data_len);
 
+       kfree(buf);
 error:
        return ret;
 }
index b2a87f2..9bd6d51 100644 (file)
@@ -46,8 +46,9 @@ struct dib0700_state {
        u8 is_dib7000pc;
        u8 fw_use_new_i2c_api;
        u8 disable_streaming_master_mode;
-    u32 fw_version;
-    u32 nb_packet_buffer_size;
+       u32 fw_version;
+       u32 nb_packet_buffer_size;
+       u8 buf[255];
 };
 
 extern int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
index b79af68..5eb91b4 100644 (file)
@@ -27,19 +27,25 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
                        u32 *romversion, u32 *ramversion, u32 *fwtype)
 {
-       u8 b[16];
-       int ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
+       struct dib0700_state *st = d->priv;
+       int ret;
+
+       ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
                                  REQUEST_GET_VERSION,
                                  USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
-                                 b, sizeof(b), USB_CTRL_GET_TIMEOUT);
+                                 st->buf, 16, USB_CTRL_GET_TIMEOUT);
        if (hwversion != NULL)
-               *hwversion  = (b[0] << 24)  | (b[1] << 16)  | (b[2] << 8)  | b[3];
+               *hwversion  = (st->buf[0] << 24)  | (st->buf[1] << 16)  |
+                       (st->buf[2] << 8)  | st->buf[3];
        if (romversion != NULL)
-               *romversion = (b[4] << 24)  | (b[5] << 16)  | (b[6] << 8)  | b[7];
+               *romversion = (st->buf[4] << 24)  | (st->buf[5] << 16)  |
+                       (st->buf[6] << 8)  | st->buf[7];
        if (ramversion != NULL)
-               *ramversion = (b[8] << 24)  | (b[9] << 16)  | (b[10] << 8) | b[11];
+               *ramversion = (st->buf[8] << 24)  | (st->buf[9] << 16)  |
+                       (st->buf[10] << 8) | st->buf[11];
        if (fwtype != NULL)
-               *fwtype     = (b[12] << 24) | (b[13] << 16) | (b[14] << 8) | b[15];
+               *fwtype     = (st->buf[12] << 24) | (st->buf[13] << 16) |
+                       (st->buf[14] << 8) | st->buf[15];
        return ret;
 }
 
@@ -101,24 +107,31 @@ int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen
 
 int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val)
 {
-       u8 buf[3] = { REQUEST_SET_GPIO, gpio, ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6) };
-       return dib0700_ctrl_wr(d, buf, sizeof(buf));
+       struct dib0700_state *st = d->priv;
+       s16 ret;
+
+       st->buf[0] = REQUEST_SET_GPIO;
+       st->buf[1] = gpio;
+       st->buf[2] = ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6);
+
+       ret = dib0700_ctrl_wr(d, st->buf, 3);
+
+       return ret;
 }
 
 static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets)
 {
        struct dib0700_state *st = d->priv;
-       u8 b[3];
        int ret;
 
        if (st->fw_version >= 0x10201) {
-               b[0] = REQUEST_SET_USB_XFER_LEN;
-               b[1] = (nb_ts_packets >> 8) & 0xff;
-               b[2] = nb_ts_packets & 0xff;
+               st->buf[0] = REQUEST_SET_USB_XFER_LEN;
+               st->buf[1] = (nb_ts_packets >> 8) & 0xff;
+               st->buf[2] = nb_ts_packets & 0xff;
 
                deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
 
-               ret = dib0700_ctrl_wr(d, b, sizeof(b));
+               ret = dib0700_ctrl_wr(d, st->buf, 3);
        } else {
                deb_info("this firmware does not allow to change the USB xfer len\n");
                ret = -EIO;
@@ -137,11 +150,11 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
           properly support i2c read calls not preceded by a write */
 
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       struct dib0700_state *st = d->priv;
        uint8_t bus_mode = 1;  /* 0=eeprom bus, 1=frontend bus */
        uint8_t gen_mode = 0; /* 0=master i2c, 1=gpio i2c */
        uint8_t en_start = 0;
        uint8_t en_stop = 0;
-       uint8_t buf[255]; /* TBV: malloc ? */
        int result, i;
 
        /* Ensure nobody else hits the i2c bus while we're sending our
@@ -195,24 +208,24 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
 
                } else {
                        /* Write request */
-                       buf[0] = REQUEST_NEW_I2C_WRITE;
-                       buf[1] = msg[i].addr << 1;
-                       buf[2] = (en_start << 7) | (en_stop << 6) |
+                       st->buf[0] = REQUEST_NEW_I2C_WRITE;
+                       st->buf[1] = msg[i].addr << 1;
+                       st->buf[2] = (en_start << 7) | (en_stop << 6) |
                                (msg[i].len & 0x3F);
                        /* I2C ctrl + FE bus; */
-                       buf[3] = ((gen_mode << 6) & 0xC0) |
+                       st->buf[3] = ((gen_mode << 6) & 0xC0) |
                                 ((bus_mode << 4) & 0x30);
                        /* The Actual i2c payload */
-                       memcpy(&buf[4], msg[i].buf, msg[i].len);
+                       memcpy(&st->buf[4], msg[i].buf, msg[i].len);
 
                        deb_data(">>> ");
-                       debug_dump(buf, msg[i].len + 4, deb_data);
+                       debug_dump(st->buf, msg[i].len + 4, deb_data);
 
                        result = usb_control_msg(d->udev,
                                                 usb_sndctrlpipe(d->udev, 0),
                                                 REQUEST_NEW_I2C_WRITE,
                                                 USB_TYPE_VENDOR | USB_DIR_OUT,
-                                                0, 0, buf, msg[i].len + 4,
+                                                0, 0, st->buf, msg[i].len + 4,
                                                 USB_CTRL_GET_TIMEOUT);
                        if (result < 0) {
                                deb_info("i2c write error (status = %d)\n", result);
@@ -231,27 +244,29 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
                                   struct i2c_msg *msg, int num)
 {
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       struct dib0700_state *st = d->priv;
        int i,len;
-       u8 buf[255];
 
        if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
                return -EAGAIN;
 
        for (i = 0; i < num; i++) {
                /* fill in the address */
-               buf[1] = msg[i].addr << 1;
+               st->buf[1] = msg[i].addr << 1;
                /* fill the buffer */
-               memcpy(&buf[2], msg[i].buf, msg[i].len);
+               memcpy(&st->buf[2], msg[i].buf, msg[i].len);
 
                /* write/read request */
                if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
-                       buf[0] = REQUEST_I2C_READ;
-                       buf[1] |= 1;
+                       st->buf[0] = REQUEST_I2C_READ;
+                       st->buf[1] |= 1;
 
                        /* special thing in the current firmware: when length is zero the read-failed */
-                       if ((len = dib0700_ctrl_rd(d, buf, msg[i].len + 2, msg[i+1].buf, msg[i+1].len)) <= 0) {
+                       len = dib0700_ctrl_rd(d, st->buf, msg[i].len + 2,
+                                       msg[i+1].buf, msg[i+1].len);
+                       if (len <= 0) {
                                deb_info("I2C read failed on address 0x%02x\n",
-                                        msg[i].addr);
+                                               msg[i].addr);
                                break;
                        }
 
@@ -259,13 +274,13 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
 
                        i++;
                } else {
-                       buf[0] = REQUEST_I2C_WRITE;
-                       if (dib0700_ctrl_wr(d, buf, msg[i].len + 2) < 0)
+                       st->buf[0] = REQUEST_I2C_WRITE;
+                       if (dib0700_ctrl_wr(d, st->buf, msg[i].len + 2) < 0)
                                break;
                }
        }
-
        mutex_unlock(&d->i2c_mutex);
+
        return i;
 }
 
@@ -297,15 +312,23 @@ struct i2c_algorithm dib0700_i2c_algo = {
 int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
                        struct dvb_usb_device_description **desc, int *cold)
 {
-       u8 b[16];
-       s16 ret = usb_control_msg(udev, usb_rcvctrlpipe(udev,0),
+       s16 ret;
+       u8 *b;
+
+       b = kmalloc(16, GFP_KERNEL);
+       if (!b)
+               return  -ENOMEM;
+
+
+       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
                REQUEST_GET_VERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, b, 16, USB_CTRL_GET_TIMEOUT);
 
        deb_info("FW GET_VERSION length: %d\n",ret);
 
        *cold = ret <= 0;
-
        deb_info("cold: %d\n", *cold);
+
+       kfree(b);
        return 0;
 }
 
@@ -313,43 +336,50 @@ static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll,
        u8 pll_src, u8 pll_range, u8 clock_gpio3, u16 pll_prediv,
        u16 pll_loopdiv, u16 free_div, u16 dsuScaler)
 {
-       u8 b[10];
-       b[0] = REQUEST_SET_CLOCK;
-       b[1] = (en_pll << 7) | (pll_src << 6) | (pll_range << 5) | (clock_gpio3 << 4);
-       b[2] = (pll_prediv >> 8)  & 0xff; // MSB
-       b[3] =  pll_prediv        & 0xff; // LSB
-       b[4] = (pll_loopdiv >> 8) & 0xff; // MSB
-       b[5] =  pll_loopdiv       & 0xff; // LSB
-       b[6] = (free_div >> 8)    & 0xff; // MSB
-       b[7] =  free_div          & 0xff; // LSB
-       b[8] = (dsuScaler >> 8)   & 0xff; // MSB
-       b[9] =  dsuScaler         & 0xff; // LSB
-
-       return dib0700_ctrl_wr(d, b, 10);
+       struct dib0700_state *st = d->priv;
+       s16 ret;
+
+       st->buf[0] = REQUEST_SET_CLOCK;
+       st->buf[1] = (en_pll << 7) | (pll_src << 6) |
+               (pll_range << 5) | (clock_gpio3 << 4);
+       st->buf[2] = (pll_prediv >> 8)  & 0xff; /* MSB */
+       st->buf[3] =  pll_prediv        & 0xff; /* LSB */
+       st->buf[4] = (pll_loopdiv >> 8) & 0xff; /* MSB */
+       st->buf[5] =  pll_loopdiv       & 0xff; /* LSB */
+       st->buf[6] = (free_div >> 8)    & 0xff; /* MSB */
+       st->buf[7] =  free_div          & 0xff; /* LSB */
+       st->buf[8] = (dsuScaler >> 8)   & 0xff; /* MSB */
+       st->buf[9] =  dsuScaler         & 0xff; /* LSB */
+
+       ret = dib0700_ctrl_wr(d, st->buf, 10);
+
+       return ret;
 }
 
 int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz)
 {
+       struct dib0700_state *st = d->priv;
        u16 divider;
-       u8 b[8];
 
        if (scl_kHz == 0)
                return -EINVAL;
 
-       b[0] = REQUEST_SET_I2C_PARAM;
+       st->buf[0] = REQUEST_SET_I2C_PARAM;
        divider = (u16) (30000 / scl_kHz);
-       b[2] = (u8) (divider >> 8);
-       b[3] = (u8) (divider & 0xff);
+       st->buf[1] = 0;
+       st->buf[2] = (u8) (divider >> 8);
+       st->buf[3] = (u8) (divider & 0xff);
        divider = (u16) (72000 / scl_kHz);
-       b[4] = (u8) (divider >> 8);
-       b[5] = (u8) (divider & 0xff);
+       st->buf[4] = (u8) (divider >> 8);
+       st->buf[5] = (u8) (divider & 0xff);
        divider = (u16) (72000 / scl_kHz); /* clock: 72MHz */
-       b[6] = (u8) (divider >> 8);
-       b[7] = (u8) (divider & 0xff);
+       st->buf[6] = (u8) (divider >> 8);
+       st->buf[7] = (u8) (divider & 0xff);
 
        deb_info("setting I2C speed: %04x %04x %04x (%d kHz).",
-               (b[2] << 8) | (b[3]), (b[4] << 8) | b[5], (b[6] << 8) | b[7], scl_kHz);
-       return dib0700_ctrl_wr(d, b, 8);
+               (st->buf[2] << 8) | (st->buf[3]), (st->buf[4] << 8) |
+               st->buf[5], (st->buf[6] << 8) | st->buf[7], scl_kHz);
+       return dib0700_ctrl_wr(d, st->buf, 8);
 }
 
 
@@ -364,32 +394,45 @@ int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3)
 
 static int dib0700_jumpram(struct usb_device *udev, u32 address)
 {
-       int ret, actlen;
-       u8 buf[8] = { REQUEST_JUMPRAM, 0, 0, 0,
-               (address >> 24) & 0xff,
-               (address >> 16) & 0xff,
-               (address >> 8)  & 0xff,
-                address        & 0xff };
+       int ret = 0, actlen;
+       u8 *buf;
+
+       buf = kmalloc(8, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       buf[0] = REQUEST_JUMPRAM;
+       buf[1] = 0;
+       buf[2] = 0;
+       buf[3] = 0;
+       buf[4] = (address >> 24) & 0xff;
+       buf[5] = (address >> 16) & 0xff;
+       buf[6] = (address >> 8)  & 0xff;
+       buf[7] =  address        & 0xff;
 
        if ((ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x01),buf,8,&actlen,1000)) < 0) {
                deb_fw("jumpram to 0x%x failed\n",address);
-               return ret;
+               goto out;
        }
        if (actlen != 8) {
                deb_fw("jumpram to 0x%x failed\n",address);
-               return -EIO;
+               ret = -EIO;
+               goto out;
        }
-       return 0;
+out:
+       kfree(buf);
+       return ret;
 }
 
 int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw)
 {
        struct hexline hx;
        int pos = 0, ret, act_len, i, adap_num;
-       u8 b[16];
+       u8 *buf;
        u32 fw_version;
 
-       u8 buf[260];
+       buf = kmalloc(260, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
 
        while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) {
                deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n",
@@ -411,7 +454,7 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw
 
                if (ret < 0) {
                        err("firmware download failed at %d with %d",pos,ret);
-                       return ret;
+                       goto out;
                }
        }
 
@@ -432,8 +475,8 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw
        usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
                                  REQUEST_GET_VERSION,
                                  USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
-                                 b, sizeof(b), USB_CTRL_GET_TIMEOUT);
-       fw_version = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11];
+                                 buf, 16, USB_CTRL_GET_TIMEOUT);
+       fw_version = (buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | buf[11];
 
        /* set the buffer size - DVB-USB is allocating URB buffers
         * only after the firwmare download was successful */
@@ -451,14 +494,14 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw
                        }
                }
        }
-
+out:
+       kfree(buf);
        return ret;
 }
 
 int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
        struct dib0700_state *st = adap->dev->priv;
-       u8 b[4];
        int ret;
 
        if ((onoff != 0) && (st->fw_version >= 0x10201)) {
@@ -472,15 +515,17 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
                }
        }
 
-       b[0] = REQUEST_ENABLE_VIDEO;
-       b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */
+       st->buf[0] = REQUEST_ENABLE_VIDEO;
+       /* this bit gives a kind of command,
+        * rather than enabling something or not */
+       st->buf[1] = (onoff << 4) | 0x00;
 
        if (st->disable_streaming_master_mode == 1)
-               b[2] = 0x00;
+               st->buf[2] = 0x00;
        else
-               b[2] = 0x01 << 4; /* Master mode */
+               st->buf[2] = 0x01 << 4; /* Master mode */
 
-       b[3] = 0x00;
+       st->buf[3] = 0x00;
 
        deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id);
 
@@ -499,20 +544,23 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
                        st->channel_state |=    1 << (3-adap->stream.props.endpoint);
        }
 
-       b[2] |= st->channel_state;
+       st->buf[2] |= st->channel_state;
 
-       deb_info("data for streaming: %x %x\n", b[1], b[2]);
+       deb_info("data for streaming: %x %x\n", st->buf[1], st->buf[2]);
 
-       return dib0700_ctrl_wr(adap->dev, b, 4);
+       return dib0700_ctrl_wr(adap->dev, st->buf, 4);
 }
 
 int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
 {
        struct dvb_usb_device *d = rc->priv;
        struct dib0700_state *st = d->priv;
-       u8 rc_setup[3] = { REQUEST_SET_RC, 0, 0 };
        int new_proto, ret;
 
+       st->buf[0] = REQUEST_SET_RC;
+       st->buf[1] = 0;
+       st->buf[2] = 0;
+
        /* Set the IR mode */
        if (rc_type == RC_TYPE_RC5)
                new_proto = 1;
@@ -526,9 +574,9 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
        } else
                return -EINVAL;
 
-       rc_setup[1] = new_proto;
+       st->buf[1] = new_proto;
 
-       ret = dib0700_ctrl_wr(d, rc_setup, sizeof(rc_setup));
+       ret = dib0700_ctrl_wr(d, st->buf, 3);
        if (ret < 0) {
                err("ir protocol setup failed");
                return ret;
@@ -561,7 +609,6 @@ struct dib0700_rc_response {
 static void dib0700_rc_urb_completion(struct urb *purb)
 {
        struct dvb_usb_device *d = purb->context;
-       struct dib0700_state *st;
        struct dib0700_rc_response *poll_reply;
        u32 uninitialized_var(keycode);
        u8 toggle;
@@ -576,7 +623,6 @@ static void dib0700_rc_urb_completion(struct urb *purb)
                return;
        }
 
-       st = d->priv;
        poll_reply = purb->transfer_buffer;
 
        if (purb->status < 0) {
index 65214af..c519ad5 100644 (file)
@@ -2439,7 +2439,6 @@ static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap)
 
        dib0700_set_i2c_speed(adap->dev, 340);
        adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]);
-
        if (adap->fe == NULL)
                return -ENODEV;
 
@@ -2802,6 +2801,7 @@ struct usb_device_id dib0700_usb_id_table[] = {
        { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_NIM7090) },
        { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_TFE7090PVR) },
        { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2) },
+/* 75 */{ USB_DEVICE(USB_VID_MEDION,    USB_PID_CREATIX_CTX1921) },
        { 0 }           /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -3411,7 +3411,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
-               .num_device_descs = 3,
+               .num_device_descs = 4,
                .devices = {
                        {   "DiBcom STK7770P reference design",
                                { &dib0700_usb_id_table[59], NULL },
@@ -3427,6 +3427,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { &dib0700_usb_id_table[74], NULL },
                                { NULL },
                        },
+                       {   "Medion CTX1921 DVB-T USB",
+                               { &dib0700_usb_id_table[75], NULL },
+                               { NULL },
+                       },
                },
 
                .rc.core = {
index 956f7ae..4c2a689 100644 (file)
@@ -408,7 +408,7 @@ struct rc_map_table rc_map_dibusb_table[] = {
 
        { 0x8008, KEY_DVD },
        { 0x8009, KEY_AUDIO },
-       { 0x800a, KEY_MEDIA },      /* Pictures */
+       { 0x800a, KEY_IMAGES },      /* Pictures */
        { 0x800b, KEY_VIDEO },
 
        { 0x800c, KEY_BACK },
index df1ec3e..b3cb626 100644 (file)
@@ -12,7 +12,7 @@
 static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
 {
        struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
-       int newfeedcount,ret;
+       int newfeedcount, ret;
 
        if (adap == NULL)
                return -ENODEV;
@@ -24,9 +24,13 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
                deb_ts("stop feeding\n");
                usb_urb_kill(&adap->stream);
 
-               if (adap->props.streaming_ctrl != NULL)
-                       if ((ret = adap->props.streaming_ctrl(adap,0)))
+               if (adap->props.streaming_ctrl != NULL) {
+                       ret = adap->props.streaming_ctrl(adap, 0);
+                       if (ret < 0) {
                                err("error while stopping stream.");
+                               return ret;
+                       }
+               }
        }
 
        adap->feedcount = newfeedcount;
@@ -49,17 +53,24 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
 
                deb_ts("controlling pid parser\n");
                if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER &&
-                       adap->props.caps & DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
-                       adap->props.pid_filter_ctrl != NULL)
-                       if (adap->props.pid_filter_ctrl(adap,adap->pid_filtering) < 0)
+                       adap->props.caps &
+                       DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
+                       adap->props.pid_filter_ctrl != NULL) {
+                       ret = adap->props.pid_filter_ctrl(adap,
+                               adap->pid_filtering);
+                       if (ret < 0) {
                                err("could not handle pid_parser");
-
+                               return ret;
+                       }
+               }
                deb_ts("start feeding\n");
-               if (adap->props.streaming_ctrl != NULL)
-                       if (adap->props.streaming_ctrl(adap,1)) {
+               if (adap->props.streaming_ctrl != NULL) {
+                       ret = adap->props.streaming_ctrl(adap, 1);
+                       if (ret < 0) {
                                err("error while enabling fifo.");
-                               return -ENODEV;
+                               return ret;
                        }
+               }
 
        }
        return 0;
index 3a8b744..21b1549 100644 (file)
@@ -91,6 +91,7 @@
 #define USB_PID_COMPRO_VIDEOMATE_U500_PC               0x1e80
 #define USB_PID_CONCEPTRONIC_CTVDIGRCU                 0xe397
 #define USB_PID_CONEXANT_D680_DMB                      0x86d6
+#define USB_PID_CREATIX_CTX1921                                0x1921
 #define USB_PID_DIBCOM_HOOK_DEFAULT                    0x0064
 #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM             0x0065
 #define USB_PID_DIBCOM_MOD3000_COLD                    0x0bb8
index d312323..058b231 100644 (file)
@@ -121,12 +121,16 @@ static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
                        u16 index, u8 * data, u16 len, int flags)
 {
        int ret;
-       u8 u8buf[len];
-
+       u8 *u8buf;
        unsigned int pipe = (flags == DW210X_READ_MSG) ?
                                usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0);
        u8 request_type = (flags == DW210X_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
 
+       u8buf = kmalloc(len, GFP_KERNEL);
+       if (!u8buf)
+               return -ENOMEM;
+
+
        if (flags == DW210X_WRITE_MSG)
                memcpy(u8buf, data, len);
        ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR,
@@ -134,6 +138,8 @@ static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
 
        if (flags == DW210X_READ_MSG)
                memcpy(data, u8buf, len);
+
+       kfree(u8buf);
        return ret;
 }
 
index 52f5d4f..1ba3e5d 100644 (file)
@@ -36,7 +36,9 @@ static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req)
        int ret;
        unsigned int pipe;
        u8 request, requesttype;
-       u8 buf[req->size];
+       u8 *buf;
+
+
 
        switch (req->cmd) {
        case DOWNLOAD_FIRMWARE:
@@ -72,6 +74,12 @@ static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req)
                goto error;
        }
 
+       buf = kmalloc(req->size, GFP_KERNEL);
+       if (!buf) {
+               ret = -ENOMEM;
+               goto error;
+       }
+
        if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
                /* write */
                memcpy(buf, req->data, req->size);
@@ -84,13 +92,13 @@ static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req)
        msleep(1); /* avoid I2C errors */
 
        ret = usb_control_msg(udev, pipe, request, requesttype, req->value,
-               req->index, buf, sizeof(buf), EC168_USB_TIMEOUT);
+               req->index, buf, req->size, EC168_USB_TIMEOUT);
 
        ec168_debug_dump(request, requesttype, req->value, req->index, buf,
                req->size, deb_xfer);
 
        if (ret < 0)
-               goto error;
+               goto err_dealloc;
        else
                ret = 0;
 
@@ -98,7 +106,11 @@ static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req)
        if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
                memcpy(req->data, buf, req->size);
 
+       kfree(buf);
        return ret;
+
+err_dealloc:
+       kfree(buf);
 error:
        deb_info("%s: failed:%d\n", __func__, ret);
        return ret;
index 14a65b4..76159ae 100644 (file)
@@ -142,17 +142,20 @@ static u32 gl861_i2c_func(struct i2c_adapter *adapter)
        return I2C_FUNC_I2C;
 }
 
-
 static int friio_ext_ctl(struct dvb_usb_adapter *adap,
                         u32 sat_color, int lnb_on)
 {
        int i;
        int ret;
        struct i2c_msg msg;
-       u8 buf[2];
+       u8 *buf;
        u32 mask;
        u8 lnb = (lnb_on) ? FRIIO_CTL_LNB : 0;
 
+       buf = kmalloc(2, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
        msg.addr = 0x00;
        msg.flags = 0;
        msg.len = 2;
@@ -189,6 +192,7 @@ static int friio_ext_ctl(struct dvb_usb_adapter *adap,
        buf[1] |= FRIIO_CTL_CLK;
        ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
 
+       kfree(buf);
        return (ret == 70);
 }
 
@@ -219,11 +223,20 @@ static int friio_initialize(struct dvb_usb_device *d)
        int ret;
        int i;
        int retry = 0;
-       u8 rbuf[2];
-       u8 wbuf[3];
+       u8 *rbuf, *wbuf;
 
        deb_info("%s called.\n", __func__);
 
+       wbuf = kmalloc(3, GFP_KERNEL);
+       if (!wbuf)
+               return -ENOMEM;
+
+       rbuf = kmalloc(2, GFP_KERNEL);
+       if (!rbuf) {
+               kfree(wbuf);
+               return -ENOMEM;
+       }
+
        /* use gl861_i2c_msg instead of gl861_i2c_xfer(), */
        /* because the i2c device is not set up yet. */
        wbuf[0] = 0x11;
@@ -358,6 +371,8 @@ restart:
        return 0;
 
 error:
+       kfree(wbuf);
+       kfree(rbuf);
        deb_info("%s:ret == %d\n", __func__, ret);
        return -EIO;
 }
index f2db012..f36f471 100644 (file)
@@ -62,8 +62,6 @@
  *     LME2510: SHARP:BS2F7HZ0194(MV0194) cannot cold reset and share system
  * with other tuners. After a cold reset streaming will not start.
  *
- *     PID functions have been removed from this driver version due to
- * problems with different firmware and application versions.
  */
 #define DVB_USB_LOG_PREFIX "LME2510(C)"
 #include <linux/usb.h>
@@ -104,6 +102,10 @@ static int dvb_usb_lme2510_firmware;
 module_param_named(firmware, dvb_usb_lme2510_firmware, int, 0644);
 MODULE_PARM_DESC(firmware, "set default firmware 0=Sharp7395 1=LG");
 
+static int pid_filter;
+module_param_named(pid, pid_filter, int, 0644);
+MODULE_PARM_DESC(pid, "set default 0=on 1=off");
+
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
@@ -125,6 +127,7 @@ struct lme2510_state {
        u8 i2c_tuner_gate_r;
        u8 i2c_tuner_addr;
        u8 stream_on;
+       u8 pid_size;
        void *buffer;
        struct urb *lme_urb;
        void *usb_buffer;
@@ -167,14 +170,14 @@ static int lme2510_usb_talk(struct dvb_usb_device *d,
        }
        buff = st->usb_buffer;
 
-       /* the read/write capped at 512 */
-       memcpy(buff, wbuf, (wlen > 512) ? 512 : wlen);
-
        ret = mutex_lock_interruptible(&d->usb_mutex);
 
        if (ret < 0)
                return -EAGAIN;
 
+       /* the read/write capped at 512 */
+       memcpy(buff, wbuf, (wlen > 512) ? 512 : wlen);
+
        ret |= usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, 0x01));
 
        ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01);
@@ -216,6 +219,37 @@ static int lme2510_remote_keypress(struct dvb_usb_adapter *adap, u32 keypress)
        return 0;
 }
 
+static int lme2510_enable_pid(struct dvb_usb_device *d, u8 index, u16 pid_out)
+{
+       struct lme2510_state *st = d->priv;
+       static u8 pid_buff[] = LME_ZERO_PID;
+       static u8 rbuf[1];
+       u8 pid_no = index * 2;
+       u8 pid_len = pid_no + 2;
+       int ret = 0;
+       deb_info(1, "PID Setting Pid %04x", pid_out);
+
+       if (st->pid_size == 0)
+               ret |= lme2510_stream_restart(d);
+
+       pid_buff[2] = pid_no;
+       pid_buff[3] = (u8)pid_out & 0xff;
+       pid_buff[4] = pid_no + 1;
+       pid_buff[5] = (u8)(pid_out >> 8);
+
+       if (pid_len > st->pid_size)
+               st->pid_size = pid_len;
+       pid_buff[7] = 0x80 + st->pid_size;
+
+       ret |= lme2510_usb_talk(d, pid_buff ,
+               sizeof(pid_buff) , rbuf, sizeof(rbuf));
+
+       if (st->stream_on)
+               ret |= lme2510_stream_restart(d);
+
+       return ret;
+}
+
 static void lme2510_int_response(struct urb *lme_urb)
 {
        struct dvb_usb_adapter *adap = lme_urb->context;
@@ -326,16 +360,68 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap)
        return 0;
 }
 
+static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+       struct lme2510_state *st = adap->dev->priv;
+       static u8 clear_pid_reg[] = LME_CLEAR_PID;
+       static u8 rbuf[1];
+       int ret;
+
+       deb_info(1, "PID Clearing Filter");
+
+       ret = mutex_lock_interruptible(&adap->dev->i2c_mutex);
+       if (ret < 0)
+               return -EAGAIN;
+
+       if (!onoff)
+               ret |= lme2510_usb_talk(adap->dev, clear_pid_reg,
+                       sizeof(clear_pid_reg), rbuf, sizeof(rbuf));
+
+       st->pid_size = 0;
+
+       mutex_unlock(&adap->dev->i2c_mutex);
+
+       return 0;
+}
+
+static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
+       int onoff)
+{
+       int ret = 0;
+
+       deb_info(3, "%s PID=%04x Index=%04x onoff=%02x", __func__,
+               pid, index, onoff);
+
+       if (onoff)
+               if (!pid_filter) {
+                       ret = mutex_lock_interruptible(&adap->dev->i2c_mutex);
+                       if (ret < 0)
+                               return -EAGAIN;
+                       ret |= lme2510_enable_pid(adap->dev, index, pid);
+                       mutex_unlock(&adap->dev->i2c_mutex);
+       }
+
+
+       return ret;
+}
+
+
 static int lme2510_return_status(struct usb_device *dev)
 {
        int ret = 0;
-       u8 data[10] = {0};
+       u8 *data;
+
+       data = kzalloc(10, GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
        ret |= usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
                        0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200);
        info("Firmware Status: %x (%x)", ret , data[2]);
 
-       return (ret < 0) ? -ENODEV : data[2];
+       ret = (ret < 0) ? -ENODEV : data[2];
+       kfree(data);
+       return ret;
 }
 
 static int lme2510_msg(struct dvb_usb_device *d,
@@ -591,9 +677,10 @@ static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
        else {
                deb_info(1, "STM Steam Off");
                /* mutex is here only to avoid collision with I2C */
-               ret = mutex_lock_interruptible(&adap->dev->i2c_mutex);
+               if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
+                       return -EAGAIN;
 
-               ret |= lme2510_usb_talk(adap->dev, clear_reg_3,
+               ret = lme2510_usb_talk(adap->dev, clear_reg_3,
                                sizeof(clear_reg_3), rbuf, rlen);
                st->stream_on = 0;
                st->i2c_talk_onoff = 1;
@@ -655,7 +742,7 @@ static int lme2510_download_firmware(struct usb_device *dev,
                                        const struct firmware *fw)
 {
        int ret = 0;
-       u8 data[512] = {0};
+       u8 *data;
        u16 j, wlen, len_in, start, end;
        u8 packet_size, dlen, i;
        u8 *fw_data;
@@ -663,6 +750,11 @@ static int lme2510_download_firmware(struct usb_device *dev,
        packet_size = 0x31;
        len_in = 1;
 
+       data = kzalloc(512, GFP_KERNEL);
+       if (!data) {
+               info("FRM Could not start Firmware Download (Buffer allocation failed)");
+               return -ENOMEM;
+       }
 
        info("FRM Starting Firmware Download");
 
@@ -678,15 +770,15 @@ static int lme2510_download_firmware(struct usb_device *dev,
                                data[0] = i | 0x80;
                                dlen = (u8)(end - j)-1;
                        }
-               data[1] = dlen;
-               memcpy(&data[2], fw_data, dlen+1);
-               wlen = (u8) dlen + 4;
-               data[wlen-1] = check_sum(fw_data, dlen+1);
-               deb_info(1, "Data S=%02x:E=%02x CS= %02x", data[3],
+                       data[1] = dlen;
+                       memcpy(&data[2], fw_data, dlen+1);
+                       wlen = (u8) dlen + 4;
+                       data[wlen-1] = check_sum(fw_data, dlen+1);
+                       deb_info(1, "Data S=%02x:E=%02x CS= %02x", data[3],
                                data[dlen+2], data[dlen+3]);
-               ret |= lme2510_bulk_write(dev, data,  wlen, 1);
-               ret |= lme2510_bulk_read(dev, data, len_in , 1);
-               ret |= (data[0] == 0x88) ? 0 : -1;
+                       ret |= lme2510_bulk_write(dev, data,  wlen, 1);
+                       ret |= lme2510_bulk_read(dev, data, len_in , 1);
+                       ret |= (data[0] == 0x88) ? 0 : -1;
                }
        }
 
@@ -706,7 +798,7 @@ static int lme2510_download_firmware(struct usb_device *dev,
        else
                info("FRM Firmware Download Completed - Resetting Device");
 
-
+       kfree(data);
        return (ret < 0) ? -ENODEV : 0;
 }
 
@@ -747,7 +839,7 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
                        fw_lme = fw_s0194;
                        ret = request_firmware(&fw, fw_lme, &udev->dev);
                        if (ret == 0) {
-                               cold = 0;/*lme2510-s0194 cannot cold reset*/
+                               cold = 0;
                                break;
                        }
                        dvb_usb_lme2510_firmware = TUNER_LG;
@@ -769,8 +861,10 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
                case TUNER_S7395:
                        fw_lme = fw_c_s7395;
                        ret = request_firmware(&fw, fw_lme, &udev->dev);
-                       if (ret == 0)
+                       if (ret == 0) {
+                               cold = 0;
                                break;
+                       }
                        dvb_usb_lme2510_firmware = TUNER_LG;
                case TUNER_LG:
                        fw_lme = fw_c_lg;
@@ -796,14 +890,14 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
                ret = lme2510_download_firmware(udev, fw);
        }
 
+       release_firmware(fw);
+
        if (cold) {
                info("FRM Changing to %s firmware", fw_lme);
                lme_coldreset(udev);
                return -ENODEV;
        }
 
-       release_firmware(fw);
-
        return ret;
 }
 
@@ -1017,12 +1111,13 @@ static int lme2510_powerup(struct dvb_usb_device *d, int onoff)
        static u8 rbuf[1];
        int ret, len = 3, rlen = 1;
 
-       ret = mutex_lock_interruptible(&d->i2c_mutex);
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
 
        if (onoff)
-               ret |= lme2510_usb_talk(d, lnb_on, len, rbuf, rlen);
+               ret = lme2510_usb_talk(d, lnb_on, len, rbuf, rlen);
        else
-               ret |= lme2510_usb_talk(d, lnb_off, len, rbuf, rlen);
+               ret = lme2510_usb_talk(d, lnb_off, len, rbuf, rlen);
 
        st->i2c_talk_onoff = 1;
 
@@ -1086,7 +1181,13 @@ static struct dvb_usb_device_properties lme2510_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+                       .caps = DVB_USB_ADAP_HAS_PID_FILTER|
+                               DVB_USB_ADAP_NEED_PID_FILTERING|
+                               DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                        .streaming_ctrl   = lme2510_streaming_ctrl,
+                       .pid_filter_count = 15,
+                       .pid_filter = lme2510_pid_filter,
+                       .pid_filter_ctrl  = lme2510_pid_filter_ctrl,
                        .frontend_attach  = dm04_lme2510_frontend_attach,
                        .tuner_attach = dm04_lme2510_tuner,
                        /* parameter for the MPEG2-data transfer */
@@ -1122,7 +1223,13 @@ static struct dvb_usb_device_properties lme2510c_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+                       .caps = DVB_USB_ADAP_HAS_PID_FILTER|
+                               DVB_USB_ADAP_NEED_PID_FILTERING|
+                               DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                        .streaming_ctrl   = lme2510_streaming_ctrl,
+                       .pid_filter_count = 15,
+                       .pid_filter = lme2510_pid_filter,
+                       .pid_filter_ctrl  = lme2510_pid_filter_ctrl,
                        .frontend_attach  = dm04_lme2510_frontend_attach,
                        .tuner_attach = dm04_lme2510_tuner,
                        /* parameter for the MPEG2-data transfer */
@@ -1151,7 +1258,7 @@ static struct dvb_usb_device_properties lme2510c_properties = {
        }
 };
 
-void *lme2510_exit_int(struct dvb_usb_device *d)
+static void *lme2510_exit_int(struct dvb_usb_device *d)
 {
        struct lme2510_state *st = d->priv;
        struct dvb_usb_adapter *adap = &d->adapter[0];
@@ -1178,7 +1285,7 @@ void *lme2510_exit_int(struct dvb_usb_device *d)
        return buffer;
 }
 
-void lme2510_exit(struct usb_interface *intf)
+static void lme2510_exit(struct usb_interface *intf)
 {
        struct dvb_usb_device *d = usb_get_intfdata(intf);
        void *usb_buffer;
@@ -1220,5 +1327,5 @@ module_exit(lme2510_module_exit);
 
 MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
 MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0");
-MODULE_VERSION("1.80");
+MODULE_VERSION("1.86");
 MODULE_LICENSE("GPL");
index e6af16c..ab21e2e 100644 (file)
@@ -40,6 +40,7 @@
 */
 #define LME_ST_ON_W    {0x06, 0x00}
 #define LME_CLEAR_PID   {0x03, 0x02, 0x20, 0xa0}
+#define LME_ZERO_PID   {0x03, 0x06, 0x00, 0x00, 0x01, 0x00, 0x20, 0x9c}
 
 /*  LNB Voltage
  *  07 XX XX
@@ -108,14 +109,14 @@ static u8 s7395_inittab[] = {
        0x3d, 0x30,
        0x40, 0x63,
        0x41, 0x04,
-       0x42, 0x60,
+       0x42, 0x20,
        0x43, 0x00,
        0x44, 0x00,
        0x45, 0x00,
        0x46, 0x00,
        0x47, 0x00,
        0x4a, 0x00,
-       0x50, 0x12,
+       0x50, 0x10,
        0x51, 0x36,
        0x52, 0x21,
        0x53, 0x94,
index da9dc91..9456792 100644 (file)
@@ -134,13 +134,17 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
        struct m920x_state *m = d->priv;
        int i, ret = 0;
-       u8 rc_state[2];
+       u8 *rc_state;
+
+       rc_state = kmalloc(2, GFP_KERNEL);
+       if (!rc_state)
+               return -ENOMEM;
 
        if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_STATE, rc_state, 1)) != 0)
-               goto unlock;
+               goto out;
 
        if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0)
-               goto unlock;
+               goto out;
 
        for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
                if (rc5_data(&d->props.rc.legacy.rc_map_table[i]) == rc_state[1]) {
@@ -149,7 +153,7 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
                        switch(rc_state[0]) {
                        case 0x80:
                                *state = REMOTE_NO_KEY_PRESSED;
-                               goto unlock;
+                               goto out;
 
                        case 0x88: /* framing error or "invalid code" */
                        case 0x99:
@@ -157,7 +161,7 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
                        case 0xd8:
                                *state = REMOTE_NO_KEY_PRESSED;
                                m->rep_count = 0;
-                               goto unlock;
+                               goto out;
 
                        case 0x93:
                        case 0x92:
@@ -165,7 +169,7 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
                        case 0x82:
                                m->rep_count = 0;
                                *state = REMOTE_KEY_PRESSED;
-                               goto unlock;
+                               goto out;
 
                        case 0x91:
                        case 0x81: /* pinnacle PCTV310e */
@@ -174,12 +178,12 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
                                        *state = REMOTE_KEY_REPEAT;
                                else
                                        *state = REMOTE_NO_KEY_PRESSED;
-                               goto unlock;
+                               goto out;
 
                        default:
                                deb("Unexpected rc state %02x\n", rc_state[0]);
                                *state = REMOTE_NO_KEY_PRESSED;
-                               goto unlock;
+                               goto out;
                        }
                }
 
@@ -188,8 +192,8 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 
        *state = REMOTE_NO_KEY_PRESSED;
 
unlock:
-
out:
+       kfree(rc_state);
        return ret;
 }
 
@@ -339,13 +343,19 @@ static int m920x_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, in
 static int m920x_firmware_download(struct usb_device *udev, const struct firmware *fw)
 {
        u16 value, index, size;
-       u8 read[4], *buff;
+       u8 *read, *buff;
        int i, pass, ret = 0;
 
        buff = kmalloc(65536, GFP_KERNEL);
        if (buff == NULL)
                return -ENOMEM;
 
+       read = kmalloc(4, GFP_KERNEL);
+       if (!read) {
+               kfree(buff);
+               return -ENOMEM;
+       }
+
        if ((ret = m920x_read(udev, M9206_FILTER, 0x0, 0x8000, read, 4)) != 0)
                goto done;
        deb("%x %x %x %x\n", read[0], read[1], read[2], read[3]);
@@ -396,6 +406,7 @@ static int m920x_firmware_download(struct usb_device *udev, const struct firmwar
        deb("firmware uploaded!\n");
 
  done:
+       kfree(read);
        kfree(buff);
 
        return ret;
@@ -632,9 +643,9 @@ static struct rc_map_table rc_map_pinnacle310e_table[] = {
        { 0x16, KEY_POWER },
        { 0x17, KEY_FAVORITES },
        { 0x0f, KEY_TEXT },
-       { 0x48, KEY_MEDIA },            /* preview */
+       { 0x48, KEY_PROGRAM },          /* preview */
        { 0x1c, KEY_EPG },
-       { 0x04, KEY_LIST },                     /* record list */
+       { 0x04, KEY_LIST },             /* record list */
        { 0x03, KEY_1 },
        { 0x01, KEY_2 },
        { 0x06, KEY_3 },
@@ -674,14 +685,14 @@ static struct rc_map_table rc_map_pinnacle310e_table[] = {
        { 0x0e, KEY_MUTE },
 /*     { 0x49, KEY_LR },       */              /* L/R */
        { 0x07, KEY_SLEEP },            /* Hibernate */
-       { 0x08, KEY_MEDIA },            /* A/V */
-       { 0x0e, KEY_MENU },                     /* Recall */
+       { 0x08, KEY_VIDEO },            /* A/V */
+       { 0x0e, KEY_MENU },             /* Recall */
        { 0x45, KEY_ZOOMIN },
        { 0x46, KEY_ZOOMOUT },
-       { 0x18, KEY_TV },                       /* Red */
-       { 0x53, KEY_VCR },                      /* Green */
-       { 0x5e, KEY_SAT },                      /* Yellow */
-       { 0x5f, KEY_PLAYER },           /* Blue */
+       { 0x18, KEY_RED },              /* Red */
+       { 0x53, KEY_GREEN },            /* Green */
+       { 0x5e, KEY_YELLOW },           /* Yellow */
+       { 0x5f, KEY_BLUE },             /* Blue */
 };
 
 /* DVB USB Driver stuff */
index 9d3cd2d..bc350e9 100644 (file)
@@ -47,7 +47,7 @@ static struct rc_map_table rc_map_haupp_table[] = {
        { 0x1e17, KEY_RIGHT },
        { 0x1e18, KEY_VIDEO },
        { 0x1e19, KEY_AUDIO },
-       { 0x1e1a, KEY_MEDIA },
+       { 0x1e1a, KEY_IMAGES },
        { 0x1e1b, KEY_EPG },
        { 0x1e1c, KEY_TV },
        { 0x1e1e, KEY_NEXT },
index 7e569f4..2e4fab7 100644 (file)
@@ -53,27 +53,36 @@ static int opera1_xilinx_rw(struct usb_device *dev, u8 request, u16 value,
                            u8 * data, u16 len, int flags)
 {
        int ret;
-       u8 r;
-       u8 u8buf[len];
-
+       u8 tmp;
+       u8 *buf;
        unsigned int pipe = (flags == OPERA_READ_MSG) ?
                usb_rcvctrlpipe(dev,0) : usb_sndctrlpipe(dev, 0);
        u8 request_type = (flags == OPERA_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
 
+       buf = kmalloc(len, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
        if (flags == OPERA_WRITE_MSG)
-               memcpy(u8buf, data, len);
-       ret =
-               usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR,
-                       value, 0x0, u8buf, len, 2000);
+               memcpy(buf, data, len);
+       ret = usb_control_msg(dev, pipe, request,
+                       request_type | USB_TYPE_VENDOR, value, 0x0,
+                       buf, len, 2000);
 
        if (request == OPERA_TUNER_REQ) {
+               tmp = buf[0];
                if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-                               OPERA_TUNER_REQ, USB_DIR_IN | USB_TYPE_VENDOR,
-                               0x01, 0x0, &r, 1, 2000)<1 || r!=0x08)
-                                       return 0;
+                           OPERA_TUNER_REQ, USB_DIR_IN | USB_TYPE_VENDOR,
+                           0x01, 0x0, buf, 1, 2000) < 1 || buf[0] != 0x08) {
+                       ret = 0;
+                       goto out;
+               }
+               buf[0] = tmp;
        }
        if (flags == OPERA_READ_MSG)
-               memcpy(data, u8buf, len);
+               memcpy(data, buf, len);
+out:
+       kfree(buf);
        return ret;
 }
 
@@ -189,7 +198,7 @@ static int opera1_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate,
 static u8 opera1_inittab[] = {
        0x00, 0xa1,
        0x01, 0x15,
-       0x02, 0x00,
+       0x02, 0x30,
        0x03, 0x00,
        0x04, 0x7d,
        0x05, 0x05,
index ccc7e44..2bb8d4c 100644 (file)
@@ -41,14 +41,23 @@ struct vp702x_fe_state {
 
 static int vp702x_fe_refresh_state(struct vp702x_fe_state *st)
 {
-       u8 buf[10];
-       if (time_after(jiffies,st->next_status_check)) {
-               vp702x_usb_in_op(st->d,READ_STATUS,0,0,buf,10);
+       struct vp702x_device_state *dst = st->d->priv;
+       u8 *buf;
 
+       if (time_after(jiffies, st->next_status_check)) {
+               mutex_lock(&dst->buf_mutex);
+               buf = dst->buf;
+
+               vp702x_usb_in_op(st->d, READ_STATUS, 0, 0, buf, 10);
                st->lock = buf[4];
-               vp702x_usb_in_op(st->d,READ_TUNER_REG_REQ,0x11,0,&st->snr,1);
-               vp702x_usb_in_op(st->d,READ_TUNER_REG_REQ,0x15,0,&st->sig,1);
 
+               vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x11, 0, buf, 1);
+               st->snr = buf[0];
+
+               vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x15, 0, buf, 1);
+               st->sig = buf[0];
+
+               mutex_unlock(&dst->buf_mutex);
                st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
        }
        return 0;
@@ -130,11 +139,17 @@ static int vp702x_fe_set_frontend(struct dvb_frontend* fe,
                                  struct dvb_frontend_parameters *fep)
 {
        struct vp702x_fe_state *st = fe->demodulator_priv;
+       struct vp702x_device_state *dst = st->d->priv;
        u32 freq = fep->frequency/1000;
        /*CalFrequency*/
 /*     u16 frequencyRef[16] = { 2, 4, 8, 16, 32, 64, 128, 256, 24, 5, 10, 20, 40, 80, 160, 320 }; */
        u64 sr;
-       u8 cmd[8] = { 0 },ibuf[10];
+       u8 *cmd;
+
+       mutex_lock(&dst->buf_mutex);
+
+       cmd = dst->buf;
+       memset(cmd, 0, 10);
 
        cmd[0] = (freq >> 8) & 0x7f;
        cmd[1] =  freq       & 0xff;
@@ -170,13 +185,15 @@ static int vp702x_fe_set_frontend(struct dvb_frontend* fe,
        st->status_check_interval = 250;
        st->next_status_check = jiffies;
 
-       vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100);
+       vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100);
 
-       if (ibuf[2] == 0 && ibuf[3] == 0)
+       if (cmd[2] == 0 && cmd[3] == 0)
                deb_fe("tuning failed.\n");
        else
                deb_fe("tuning succeeded.\n");
 
+       mutex_unlock(&dst->buf_mutex);
+
        return 0;
 }
 
@@ -204,27 +221,32 @@ static int vp702x_fe_get_frontend(struct dvb_frontend* fe,
 static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe,
                                    struct dvb_diseqc_master_cmd *m)
 {
+       u8 *cmd;
        struct vp702x_fe_state *st = fe->demodulator_priv;
-       u8 cmd[8],ibuf[10];
-       memset(cmd,0,8);
+       struct vp702x_device_state *dst = st->d->priv;
 
        deb_fe("%s\n",__func__);
 
        if (m->msg_len > 4)
                return -EINVAL;
 
+       mutex_lock(&dst->buf_mutex);
+
+       cmd = dst->buf;
        cmd[1] = SET_DISEQC_CMD;
        cmd[2] = m->msg_len;
        memcpy(&cmd[3], m->msg, m->msg_len);
-       cmd[7] = vp702x_chksum(cmd,0,7);
+       cmd[7] = vp702x_chksum(cmd, 0, 7);
 
-       vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100);
+       vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100);
 
-       if (ibuf[2] == 0 && ibuf[3] == 0)
+       if (cmd[2] == 0 && cmd[3] == 0)
                deb_fe("diseqc cmd failed.\n");
        else
                deb_fe("diseqc cmd succeeded.\n");
 
+       mutex_unlock(&dst->buf_mutex);
+
        return 0;
 }
 
@@ -237,7 +259,9 @@ static int vp702x_fe_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd
 static int vp702x_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
 {
        struct vp702x_fe_state *st = fe->demodulator_priv;
-       u8 ibuf[10];
+       struct vp702x_device_state *dst = st->d->priv;
+       u8 *buf;
+
        deb_fe("%s\n",__func__);
 
        st->tone_mode = tone;
@@ -247,14 +271,21 @@ static int vp702x_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
        else
                st->lnb_buf[2] = 0x00;
 
-       st->lnb_buf[7] = vp702x_chksum(st->lnb_buf,0,7);
+       st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7);
+
+       mutex_lock(&dst->buf_mutex);
+
+       buf = dst->buf;
+       memcpy(buf, st->lnb_buf, 8);
 
-       vp702x_usb_inout_op(st->d,st->lnb_buf,8,ibuf,10,100);
-       if (ibuf[2] == 0 && ibuf[3] == 0)
+       vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100);
+       if (buf[2] == 0 && buf[3] == 0)
                deb_fe("set_tone cmd failed.\n");
        else
                deb_fe("set_tone cmd succeeded.\n");
 
+       mutex_unlock(&dst->buf_mutex);
+
        return 0;
 }
 
@@ -262,7 +293,8 @@ static int vp702x_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t
                voltage)
 {
        struct vp702x_fe_state *st = fe->demodulator_priv;
-       u8 ibuf[10];
+       struct vp702x_device_state *dst = st->d->priv;
+       u8 *buf;
        deb_fe("%s\n",__func__);
 
        st->voltage = voltage;
@@ -272,14 +304,20 @@ static int vp702x_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t
        else
                st->lnb_buf[4] = 0x00;
 
-       st->lnb_buf[7] = vp702x_chksum(st->lnb_buf,0,7);
+       st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7);
+
+       mutex_lock(&dst->buf_mutex);
+
+       buf = dst->buf;
+       memcpy(buf, st->lnb_buf, 8);
 
-       vp702x_usb_inout_op(st->d,st->lnb_buf,8,ibuf,10,100);
-       if (ibuf[2] == 0 && ibuf[3] == 0)
+       vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100);
+       if (buf[2] == 0 && buf[3] == 0)
                deb_fe("set_voltage cmd failed.\n");
        else
                deb_fe("set_voltage cmd succeeded.\n");
 
+       mutex_unlock(&dst->buf_mutex);
        return 0;
 }
 
index 7890e75..54355f8 100644 (file)
@@ -15,6 +15,7 @@
  * see Documentation/dvb/README.dvb-usb for more information
  */
 #include "vp702x.h"
+#include <linux/mutex.h>
 
 /* debug */
 int dvb_usb_vp702x_debug;
@@ -23,27 +24,23 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DV
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
-struct vp702x_state {
+struct vp702x_adapter_state {
        int pid_filter_count;
        int pid_filter_can_bypass;
        u8  pid_filter_state;
 };
 
-struct vp702x_device_state {
-       u8 power_state;
-};
-
-/* check for mutex FIXME */
-int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
+static int vp702x_usb_in_op_unlocked(struct dvb_usb_device *d, u8 req,
+                                    u16 value, u16 index, u8 *b, int blen)
 {
-       int ret = -1;
+       int ret;
 
-               ret = usb_control_msg(d->udev,
-                       usb_rcvctrlpipe(d->udev,0),
-                       req,
-                       USB_TYPE_VENDOR | USB_DIR_IN,
-                       value,index,b,blen,
-                       2000);
+       ret = usb_control_msg(d->udev,
+               usb_rcvctrlpipe(d->udev, 0),
+               req,
+               USB_TYPE_VENDOR | USB_DIR_IN,
+               value, index, b, blen,
+               2000);
 
        if (ret < 0) {
                warn("usb in operation failed. (%d)", ret);
@@ -58,8 +55,20 @@ int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8
        return ret;
 }
 
-static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
-                            u16 index, u8 *b, int blen)
+int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value,
+                           u16 index, u8 *b, int blen)
+{
+       int ret;
+
+       mutex_lock(&d->usb_mutex);
+       ret = vp702x_usb_in_op_unlocked(d, req, value, index, b, blen);
+       mutex_unlock(&d->usb_mutex);
+
+       return ret;
+}
+
+int vp702x_usb_out_op_unlocked(struct dvb_usb_device *d, u8 req, u16 value,
+                                     u16 index, u8 *b, int blen)
 {
        int ret;
        deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
@@ -77,6 +86,18 @@ static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
                return 0;
 }
 
+int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+                            u16 index, u8 *b, int blen)
+{
+       int ret;
+
+       mutex_lock(&d->usb_mutex);
+       ret = vp702x_usb_out_op_unlocked(d, req, value, index, b, blen);
+       mutex_unlock(&d->usb_mutex);
+
+       return ret;
+}
+
 int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec)
 {
        int ret;
@@ -84,50 +105,93 @@ int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int il
        if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
                return ret;
 
-       ret = vp702x_usb_out_op(d,REQUEST_OUT,0,0,o,olen);
+       ret = vp702x_usb_out_op_unlocked(d, REQUEST_OUT, 0, 0, o, olen);
        msleep(msec);
-       ret = vp702x_usb_in_op(d,REQUEST_IN,0,0,i,ilen);
+       ret = vp702x_usb_in_op_unlocked(d, REQUEST_IN, 0, 0, i, ilen);
 
        mutex_unlock(&d->usb_mutex);
-
        return ret;
 }
 
 static int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o,
                                int olen, u8 *i, int ilen, int msec)
 {
-       u8 bout[olen+2];
-       u8 bin[ilen+1];
+       struct vp702x_device_state *st = d->priv;
        int ret = 0;
+       u8 *buf;
+       int buflen = max(olen + 2, ilen + 1);
+
+       ret = mutex_lock_interruptible(&st->buf_mutex);
+       if (ret < 0)
+               return ret;
+
+       if (buflen > st->buf_len) {
+               buf = kmalloc(buflen, GFP_KERNEL);
+               if (!buf) {
+                       mutex_unlock(&st->buf_mutex);
+                       return -ENOMEM;
+               }
+               info("successfully reallocated a bigger buffer");
+               kfree(st->buf);
+               st->buf = buf;
+               st->buf_len = buflen;
+       } else {
+               buf = st->buf;
+       }
 
-       bout[0] = 0x00;
-       bout[1] = cmd;
-       memcpy(&bout[2],o,olen);
+       buf[0] = 0x00;
+       buf[1] = cmd;
+       memcpy(&buf[2], o, olen);
 
-       ret = vp702x_usb_inout_op(d, bout, olen+2, bin, ilen+1,msec);
+       ret = vp702x_usb_inout_op(d, buf, olen+2, buf, ilen+1, msec);
 
        if (ret == 0)
-               memcpy(i,&bin[1],ilen);
+               memcpy(i, &buf[1], ilen);
+       mutex_unlock(&st->buf_mutex);
 
        return ret;
 }
 
 static int vp702x_set_pld_mode(struct dvb_usb_adapter *adap, u8 bypass)
 {
-       u8 buf[16] = { 0 };
-       return vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e, 0, buf, 16);
+       int ret;
+       struct vp702x_device_state *st = adap->dev->priv;
+       u8 *buf;
+
+       mutex_lock(&st->buf_mutex);
+
+       buf = st->buf;
+       memset(buf, 0, 16);
+
+       ret = vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e,
+                       0, buf, 16);
+       mutex_unlock(&st->buf_mutex);
+       return ret;
 }
 
 static int vp702x_set_pld_state(struct dvb_usb_adapter *adap, u8 state)
 {
-       u8 buf[16] = { 0 };
-       return vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f, 0, buf, 16);
+       int ret;
+       struct vp702x_device_state *st = adap->dev->priv;
+       u8 *buf;
+
+       mutex_lock(&st->buf_mutex);
+
+       buf = st->buf;
+       memset(buf, 0, 16);
+       ret = vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f,
+                       0, buf, 16);
+
+       mutex_unlock(&st->buf_mutex);
+
+       return ret;
 }
 
 static int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onoff)
 {
-       struct vp702x_state *st = adap->priv;
-       u8 buf[16] = { 0 };
+       struct vp702x_adapter_state *st = adap->priv;
+       struct vp702x_device_state *dst = adap->dev->priv;
+       u8 *buf;
 
        if (onoff)
                st->pid_filter_state |=  (1 << id);
@@ -139,32 +203,45 @@ static int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onof
        id = 0x10 + id*2;
 
        vp702x_set_pld_state(adap, st->pid_filter_state);
+
+       mutex_lock(&dst->buf_mutex);
+
+       buf = dst->buf;
+       memset(buf, 0, 16);
        vp702x_usb_in_op(adap->dev, 0xe0, (((pid >> 8) & 0xff) << 8) | (id), 0, buf, 16);
        vp702x_usb_in_op(adap->dev, 0xe0, (((pid     ) & 0xff) << 8) | (id+1), 0, buf, 16);
+
+       mutex_unlock(&dst->buf_mutex);
+
        return 0;
 }
 
 
 static int vp702x_init_pid_filter(struct dvb_usb_adapter *adap)
 {
-       struct vp702x_state *st = adap->priv;
+       struct vp702x_adapter_state *st = adap->priv;
+       struct vp702x_device_state *dst = adap->dev->priv;
        int i;
-       u8 b[10] = { 0 };
+       u8 *b;
 
        st->pid_filter_count = 8;
        st->pid_filter_can_bypass = 1;
        st->pid_filter_state = 0x00;
 
-       vp702x_set_pld_mode(adap, 1); // bypass
+       vp702x_set_pld_mode(adap, 1); /* bypass */
 
        for (i = 0; i < st->pid_filter_count; i++)
                vp702x_set_pid(adap, 0xffff, i, 1);
 
+       mutex_lock(&dst->buf_mutex);
+       b = dst->buf;
+       memset(b, 0, 10);
        vp702x_usb_in_op(adap->dev, 0xb5, 3, 0, b, 10);
        vp702x_usb_in_op(adap->dev, 0xb5, 0, 0, b, 10);
        vp702x_usb_in_op(adap->dev, 0xb5, 1, 0, b, 10);
+       mutex_unlock(&dst->buf_mutex);
+       /*vp702x_set_pld_mode(d, 0); // filter */
 
-       //vp702x_set_pld_mode(d, 0); // filter
        return 0;
 }
 
@@ -182,18 +259,23 @@ static struct rc_map_table rc_map_vp702x_table[] = {
 /* remote control stuff (does not work with my box) */
 static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
-       u8 key[10];
+       u8 *key;
        int i;
 
 /* remove the following return to enabled remote querying */
        return 0;
 
+       key = kmalloc(10, GFP_KERNEL);
+       if (!key)
+               return -ENOMEM;
+
        vp702x_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10);
 
        deb_rc("remote query key: %x %d\n",key[1],key[1]);
 
        if (key[1] == 0x44) {
                *state = REMOTE_NO_KEY_PRESSED;
+               kfree(key);
                return 0;
        }
 
@@ -203,15 +285,23 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
                        *event = rc_map_vp702x_table[i].keycode;
                        break;
                }
+       kfree(key);
        return 0;
 }
 
 
 static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
 {
-       u8 i;
+       u8 i, *buf;
+       struct vp702x_device_state *st = d->priv;
+
+       mutex_lock(&st->buf_mutex);
+       buf = st->buf;
        for (i = 6; i < 12; i++)
-               vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &mac[i - 6], 1);
+               vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &buf[i - 6], 1);
+
+       memcpy(mac, buf, 6);
+       mutex_unlock(&st->buf_mutex);
        return 0;
 }
 
@@ -221,7 +311,8 @@ static int vp702x_frontend_attach(struct dvb_usb_adapter *adap)
 
        vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
 
-       if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0, buf, 10, 10))
+       if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0,
+                                  buf, 10, 10))
                return -EIO;
 
        buf[9] = '\0';
@@ -240,8 +331,38 @@ static struct dvb_usb_device_properties vp702x_properties;
 static int vp702x_usb_probe(struct usb_interface *intf,
                const struct usb_device_id *id)
 {
-       return dvb_usb_device_init(intf, &vp702x_properties,
-                                  THIS_MODULE, NULL, adapter_nr);
+       struct dvb_usb_device *d;
+       struct vp702x_device_state *st;
+       int ret;
+
+       ret = dvb_usb_device_init(intf, &vp702x_properties,
+                                  THIS_MODULE, &d, adapter_nr);
+       if (ret)
+               goto out;
+
+       st = d->priv;
+       st->buf_len = 16;
+       st->buf = kmalloc(st->buf_len, GFP_KERNEL);
+       if (!st->buf) {
+               ret = -ENOMEM;
+               dvb_usb_device_exit(intf);
+               goto out;
+       }
+       mutex_init(&st->buf_mutex);
+
+out:
+       return ret;
+
+}
+
+static void vp702x_usb_disconnect(struct usb_interface *intf)
+{
+       struct dvb_usb_device *d = usb_get_intfdata(intf);
+       struct vp702x_device_state *st = d->priv;
+       mutex_lock(&st->buf_mutex);
+       kfree(st->buf);
+       mutex_unlock(&st->buf_mutex);
+       dvb_usb_device_exit(intf);
 }
 
 static struct usb_device_id vp702x_usb_table [] = {
@@ -278,7 +399,7 @@ static struct dvb_usb_device_properties vp702x_properties = {
                                        }
                                }
                        },
-                       .size_of_priv     = sizeof(struct vp702x_state),
+                       .size_of_priv     = sizeof(struct vp702x_adapter_state),
                }
        },
        .read_mac_address = vp702x_read_mac_addr,
@@ -307,9 +428,9 @@ static struct dvb_usb_device_properties vp702x_properties = {
 /* usb specific object needed to register this driver with the usb subsystem */
 static struct usb_driver vp702x_usb_driver = {
        .name           = "dvb_usb_vp702x",
-       .probe          = vp702x_usb_probe,
-       .disconnect = dvb_usb_device_exit,
-       .id_table       = vp702x_usb_table,
+       .probe          = vp702x_usb_probe,
+       .disconnect     = vp702x_usb_disconnect,
+       .id_table       = vp702x_usb_table,
 };
 
 /* module stuff */
index c2f97f9..20b9005 100644 (file)
@@ -98,6 +98,13 @@ extern int dvb_usb_vp702x_debug;
 #define RESET_TUNER            0xBE
 /* IN  i: 0, v: 0, no extra buffer */
 
+struct vp702x_device_state {
+       struct mutex buf_mutex;
+       int buf_len;
+       u8 *buf;
+};
+
+
 extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d);
 
 extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec);
index ab0ab3c..3db89e3 100644 (file)
@@ -28,9 +28,9 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec)
 {
        int ret = 0;
-       u8 inbuf[12] = { 0 }, outbuf[20] = { 0 };
+       u8 *buf = d->priv;
 
-       outbuf[0] = cmd;
+       buf[0] = cmd;
 
        if (outlen > 19)
                outlen = 19;
@@ -38,19 +38,21 @@ int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in,
        if (inlen > 11)
                inlen = 11;
 
+       ret = mutex_lock_interruptible(&d->usb_mutex);
+       if (ret)
+               return ret;
+
        if (out != NULL && outlen > 0)
-               memcpy(&outbuf[1], out, outlen);
+               memcpy(&buf[1], out, outlen);
 
        deb_xfer("out buffer: ");
-       debug_dump(outbuf,outlen+1,deb_xfer);
+       debug_dump(buf, outlen+1, deb_xfer);
 
-       if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
-               return ret;
 
        if (usb_control_msg(d->udev,
                        usb_sndctrlpipe(d->udev,0),
                        TH_COMMAND_OUT, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0,
-                       outbuf, 20, 2000) != 20) {
+                       buf, 20, 2000) != 20) {
                err("USB control message 'out' went wrong.");
                ret = -EIO;
                goto unlock;
@@ -61,17 +63,17 @@ int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in,
        if (usb_control_msg(d->udev,
                        usb_rcvctrlpipe(d->udev,0),
                        TH_COMMAND_IN, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
-                       inbuf, 12, 2000) != 12) {
+                       buf, 12, 2000) != 12) {
                err("USB control message 'in' went wrong.");
                ret = -EIO;
                goto unlock;
        }
 
        deb_xfer("in buffer: ");
-       debug_dump(inbuf,12,deb_xfer);
+       debug_dump(buf, 12, deb_xfer);
 
        if (in != NULL && inlen > 0)
-               memcpy(in,&inbuf[1],inlen);
+               memcpy(in, &buf[1], inlen);
 
 unlock:
        mutex_unlock(&d->usb_mutex);
@@ -222,8 +224,26 @@ static struct dvb_usb_device_properties vp7045_properties;
 static int vp7045_usb_probe(struct usb_interface *intf,
                const struct usb_device_id *id)
 {
-       return dvb_usb_device_init(intf, &vp7045_properties,
-                                  THIS_MODULE, NULL, adapter_nr);
+       struct dvb_usb_device *d;
+       int ret = dvb_usb_device_init(intf, &vp7045_properties,
+                                  THIS_MODULE, &d, adapter_nr);
+       if (ret)
+               return ret;
+
+       d->priv = kmalloc(20, GFP_KERNEL);
+       if (!d->priv) {
+               dvb_usb_device_exit(intf);
+               return -ENOMEM;
+       }
+
+       return ret;
+}
+
+static void vp7045_usb_disconnect(struct usb_interface *intf)
+{
+       struct dvb_usb_device *d = usb_get_intfdata(intf);
+       kfree(d->priv);
+       dvb_usb_device_exit(intf);
 }
 
 static struct usb_device_id vp7045_usb_table [] = {
@@ -238,6 +258,7 @@ MODULE_DEVICE_TABLE(usb, vp7045_usb_table);
 static struct dvb_usb_device_properties vp7045_properties = {
        .usb_ctrl = CYPRESS_FX2,
        .firmware = "dvb-usb-vp7045-01.fw",
+       .size_of_priv = sizeof(u8 *),
 
        .num_adapters = 1,
        .adapter = {
@@ -284,7 +305,7 @@ static struct dvb_usb_device_properties vp7045_properties = {
 static struct usb_driver vp7045_usb_driver = {
        .name           = "dvb_usb_vp7045",
        .probe          = vp7045_usb_probe,
-       .disconnect = dvb_usb_device_exit,
+       .disconnect     = vp7045_usb_disconnect,
        .id_table       = vp7045_usb_table,
 };
 
index 83093d1..44b816f 100644 (file)
@@ -263,18 +263,16 @@ config DVB_S5H1432
        help
          A DVB-T tuner module. Say Y when you want to support this frontend.
 
-config DVB_DRX397XD
-       tristate "Micronas DRX3975D/DRX3977D based"
+config DVB_DRXD
+       tristate "Micronas DRXD driver"
        depends on DVB_CORE && I2C
        default m if DVB_FE_CUSTOMISE
        help
          A DVB-T tuner module. Say Y when you want to support this frontend.
 
-         TODO:
-         This driver needs external firmware. Please use the command
-         "<kerneldir>/Documentation/dvb/get_dvb_firmware drx397xD" to
-         download/extract them, and then copy them to /usr/lib/hotplug/firmware
-         or /lib/firmware (depending on configuration of firmware hotplug).
+         Note: this driver was based on vendor driver reference code (released
+         under the GPL) as opposed to the existing drx397xd driver, which
+         was written via reverse engineering.
 
 config DVB_L64781
        tristate "LSI L64781"
@@ -385,6 +383,13 @@ config DVB_STV0367
        help
          A DVB-T/C tuner module. Say Y when you want to support this frontend.
 
+config DVB_CXD2820R
+       tristate "Sony CXD2820R"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         Say Y when you want to support this frontend.
+
 comment "DVB-C (cable) frontends"
        depends on DVB_CORE
 
index 3b0c4bd..2f3a6f7 100644 (file)
@@ -8,6 +8,8 @@ EXTRA_CFLAGS += -Idrivers/media/common/tuners/
 stb0899-objs = stb0899_drv.o stb0899_algo.o
 stv0900-objs = stv0900_core.o stv0900_sw.o
 au8522-objs = au8522_dig.o au8522_decoder.o
+drxd-objs = drxd_firm.o drxd_hard.o
+cxd2820r-objs = cxd2820r_core.o cxd2820r_c.o cxd2820r_t.o cxd2820r_t2.o
 
 obj-$(CONFIG_DVB_PLL) += dvb-pll.o
 obj-$(CONFIG_DVB_STV0299) += stv0299.o
@@ -36,7 +38,7 @@ obj-$(CONFIG_DVB_ZL10036) += zl10036.o
 obj-$(CONFIG_DVB_ZL10039) += zl10039.o
 obj-$(CONFIG_DVB_ZL10353) += zl10353.o
 obj-$(CONFIG_DVB_CX22702) += cx22702.o
-obj-$(CONFIG_DVB_DRX397XD) += drx397xD.o
+obj-$(CONFIG_DVB_DRXD) += drxd.o
 obj-$(CONFIG_DVB_TDA10021) += tda10021.o
 obj-$(CONFIG_DVB_TDA10023) += tda10023.o
 obj-$(CONFIG_DVB_STV0297) += stv0297.o
@@ -85,3 +87,5 @@ obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
 obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o
 obj-$(CONFIG_DVB_IX2505V) += ix2505v.o
 obj-$(CONFIG_DVB_STV0367) += stv0367.o
+obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o
+
diff --git a/drivers/media/dvb/frontends/bsbe1-d01a.h b/drivers/media/dvb/frontends/bsbe1-d01a.h
new file mode 100644 (file)
index 0000000..7ed3c42
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * bsbe1-d01a.h - ALPS BSBE1-D01A tuner support
+ *
+ * Copyright (C) 2011 Oliver Endriss <o.endriss@gmx.de>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef BSBE1_D01A_H
+#define BSBE1_D01A_H
+
+#include "stb6000.h"
+#include "stv0288.h"
+
+static u8 stv0288_bsbe1_d01a_inittab[] = {
+       0x01, 0x15,
+       0x02, 0x20,
+       0x09, 0x0,
+       0x0a, 0x4,
+       0x0b, 0x0,
+       0x0c, 0x0,
+       0x0d, 0x0,
+       0x0e, 0xd4,
+       0x0f, 0x30,
+       0x11, 0x80,
+       0x12, 0x03,
+       0x13, 0x48,
+       0x14, 0x84,
+       0x15, 0x45,
+       0x16, 0xb7,
+       0x17, 0x9c,
+       0x18, 0x0,
+       0x19, 0xa6,
+       0x1a, 0x88,
+       0x1b, 0x8f,
+       0x1c, 0xf0,
+       0x20, 0x0b,
+       0x21, 0x54,
+       0x22, 0x0,
+       0x23, 0x0,
+       0x2b, 0xff,
+       0x2c, 0xf7,
+       0x30, 0x0,
+       0x31, 0x1e,
+       0x32, 0x14,
+       0x33, 0x0f,
+       0x34, 0x09,
+       0x35, 0x0c,
+       0x36, 0x05,
+       0x37, 0x2f,
+       0x38, 0x16,
+       0x39, 0xbd,
+       0x3a, 0x03,
+       0x3b, 0x13,
+       0x3c, 0x11,
+       0x3d, 0x30,
+       0x40, 0x63,
+       0x41, 0x04,
+       0x42, 0x60,
+       0x43, 0x00,
+       0x44, 0x00,
+       0x45, 0x00,
+       0x46, 0x00,
+       0x47, 0x00,
+       0x4a, 0x00,
+       0x50, 0x10,
+       0x51, 0x36,
+       0x52, 0x09,
+       0x53, 0x94,
+       0x54, 0x62,
+       0x55, 0x29,
+       0x56, 0x64,
+       0x57, 0x2b,
+       0x58, 0x54,
+       0x59, 0x86,
+       0x5a, 0x0,
+       0x5b, 0x9b,
+       0x5c, 0x08,
+       0x5d, 0x7f,
+       0x5e, 0x0,
+       0x5f, 0xff,
+       0x70, 0x0,
+       0x71, 0x0,
+       0x72, 0x0,
+       0x74, 0x0,
+       0x75, 0x0,
+       0x76, 0x0,
+       0x81, 0x0,
+       0x82, 0x3f,
+       0x83, 0x3f,
+       0x84, 0x0,
+       0x85, 0x0,
+       0x88, 0x0,
+       0x89, 0x0,
+       0x8a, 0x0,
+       0x8b, 0x0,
+       0x8c, 0x0,
+       0x90, 0x0,
+       0x91, 0x0,
+       0x92, 0x0,
+       0x93, 0x0,
+       0x94, 0x1c,
+       0x97, 0x0,
+       0xa0, 0x48,
+       0xa1, 0x0,
+       0xb0, 0xb8,
+       0xb1, 0x3a,
+       0xb2, 0x10,
+       0xb3, 0x82,
+       0xb4, 0x80,
+       0xb5, 0x82,
+       0xb6, 0x82,
+       0xb7, 0x82,
+       0xb8, 0x20,
+       0xb9, 0x0,
+       0xf0, 0x0,
+       0xf1, 0x0,
+       0xf2, 0xc0,
+       0xff, 0xff,
+};
+
+static struct stv0288_config stv0288_bsbe1_d01a_config = {
+       .demod_address = 0x68,
+       .min_delay_ms = 100,
+       .inittab = stv0288_bsbe1_d01a_inittab,
+};
+
+#endif
index 45a6dfd..c480c83 100644 (file)
@@ -27,7 +27,7 @@
 
 static u8 alps_bsru6_inittab[] = {
        0x01, 0x15,
-       0x02, 0x00,
+       0x02, 0x30,
        0x03, 0x00,
        0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
        0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
index 2410d8b..95c6465 100644 (file)
@@ -137,7 +137,7 @@ MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, "\
 /* SNR measurements */
 static int esno_snr;
 module_param(esno_snr, int, 0644);
-MODULE_PARM_DESC(debug, "SNR return units, 0=PERCENTAGE 0-100, "\
+MODULE_PARM_DESC(esno_snr, "SNR return units, 0=PERCENTAGE 0-100, "\
        "1=ESNO(db * 10) (default:0)");
 
 enum cmds {
@@ -566,7 +566,7 @@ static int cx24116_load_firmware(struct dvb_frontend *fe,
 {
        struct cx24116_state *state = fe->demodulator_priv;
        struct cx24116_cmd cmd;
-       int i, ret;
+       int i, ret, len, max, remaining;
        unsigned char vers[4];
 
        dprintk("%s\n", __func__);
@@ -603,8 +603,21 @@ static int cx24116_load_firmware(struct dvb_frontend *fe,
        cx24116_writereg(state, 0xF5, 0x00);
        cx24116_writereg(state, 0xF6, 0x00);
 
-       /* write the entire firmware as one transaction */
-       cx24116_writeregN(state, 0xF7, fw->data, fw->size);
+       /* Split firmware to the max I2C write len and write.
+        * Writes whole firmware as one write when i2c_wr_max is set to 0. */
+       if (state->config->i2c_wr_max)
+               max = state->config->i2c_wr_max;
+       else
+               max = INT_MAX; /* enough for 32k firmware */
+
+       for (remaining = fw->size; remaining > 0; remaining -= max - 1) {
+               len = remaining;
+               if (len > max - 1)
+                       len = max - 1;
+
+               cx24116_writeregN(state, 0xF7, &fw->data[fw->size - remaining],
+                       len);
+       }
 
        cx24116_writereg(state, 0xF4, 0x10);
        cx24116_writereg(state, 0xF0, 0x00);
index b1b76b4..7d90ab9 100644 (file)
@@ -35,6 +35,9 @@ struct cx24116_config {
 
        /* Need to set MPEG parameters */
        u8 mpg_clk_pos_pol:0x02;
+
+       /* max bytes I2C provider can write at once */
+       u16 i2c_wr_max;
 };
 
 #if defined(CONFIG_DVB_CX24116) || \
diff --git a/drivers/media/dvb/frontends/cxd2820r.h b/drivers/media/dvb/frontends/cxd2820r.h
new file mode 100644 (file)
index 0000000..ad17845
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Sony CXD2820R demodulator driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#ifndef CXD2820R_H
+#define CXD2820R_H
+
+#include <linux/dvb/frontend.h>
+
+#define CXD2820R_GPIO_D (0 << 0) /* disable */
+#define CXD2820R_GPIO_E (1 << 0) /* enable */
+#define CXD2820R_GPIO_O (0 << 1) /* output */
+#define CXD2820R_GPIO_I (1 << 1) /* input */
+#define CXD2820R_GPIO_L (0 << 2) /* output low */
+#define CXD2820R_GPIO_H (1 << 2) /* output high */
+
+#define CXD2820R_TS_SERIAL        0x08
+#define CXD2820R_TS_SERIAL_MSB    0x28
+#define CXD2820R_TS_PARALLEL      0x30
+#define CXD2820R_TS_PARALLEL_MSB  0x70
+
+struct cxd2820r_config {
+       /* Demodulator I2C address.
+        * Driver determines DVB-C slave I2C address automatically from master
+        * address.
+        * Default: none, must set
+        * Values: 0x6c, 0x6d
+        */
+       u8 i2c_address;
+
+       /* TS output mode.
+        * Default: none, must set.
+        * Values:
+        */
+       u8 ts_mode;
+
+       /* IF AGC polarity.
+        * Default: 0
+        * Values: 0, 1
+        */
+       int if_agc_polarity:1;
+
+       /* Spectrum inversion.
+        * Default: 0
+        * Values: 0, 1
+        */
+       int spec_inv:1;
+
+       /* IFs for all used modes.
+        * Default: none, must set
+        * Values: <kHz>
+        */
+       u16 if_dvbt_6;
+       u16 if_dvbt_7;
+       u16 if_dvbt_8;
+       u16 if_dvbt2_5;
+       u16 if_dvbt2_6;
+       u16 if_dvbt2_7;
+       u16 if_dvbt2_8;
+       u16 if_dvbc;
+
+       /* GPIOs for all used modes.
+        * Default: none, disabled
+        * Values: <see above>
+        */
+       u8 gpio_dvbt[3];
+       u8 gpio_dvbt2[3];
+       u8 gpio_dvbc[3];
+};
+
+
+#if defined(CONFIG_DVB_CXD2820R) || \
+       (defined(CONFIG_DVB_CXD2820R_MODULE) && defined(MODULE))
+extern struct dvb_frontend *cxd2820r_attach(
+       const struct cxd2820r_config *config,
+       struct i2c_adapter *i2c,
+       struct dvb_frontend *fe
+);
+extern struct i2c_adapter *cxd2820r_get_tuner_i2c_adapter(
+       struct dvb_frontend *fe
+);
+#else
+static inline struct dvb_frontend *cxd2820r_attach(
+       const struct cxd2820r_config *config,
+       struct i2c_adapter *i2c,
+       struct dvb_frontend *fe
+)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+static inline struct i2c_adapter *cxd2820r_get_tuner_i2c_adapter(
+       struct dvb_frontend *fe
+)
+{
+       return NULL;
+}
+
+#endif
+
+#endif /* CXD2820R_H */
diff --git a/drivers/media/dvb/frontends/cxd2820r_c.c b/drivers/media/dvb/frontends/cxd2820r_c.c
new file mode 100644 (file)
index 0000000..3c07d40
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * Sony CXD2820R demodulator driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#include "cxd2820r_priv.h"
+
+int cxd2820r_set_frontend_c(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *params)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int ret, i;
+       u8 buf[2];
+       u16 if_ctl;
+       u64 num;
+       struct reg_val_mask tab[] = {
+               { 0x00080, 0x01, 0xff },
+               { 0x00081, 0x05, 0xff },
+               { 0x00085, 0x07, 0xff },
+               { 0x00088, 0x01, 0xff },
+
+               { 0x00082, 0x20, 0x60 },
+               { 0x1016a, 0x48, 0xff },
+               { 0x100a5, 0x00, 0x01 },
+               { 0x10020, 0x06, 0x07 },
+               { 0x10059, 0x50, 0xff },
+               { 0x10087, 0x0c, 0x3c },
+               { 0x1008b, 0x07, 0xff },
+               { 0x1001f, priv->cfg.if_agc_polarity << 7, 0x80 },
+               { 0x10070, priv->cfg.ts_mode, 0xff },
+       };
+
+       dbg("%s: RF=%d SR=%d", __func__, c->frequency, c->symbol_rate);
+
+       /* update GPIOs */
+       ret = cxd2820r_gpio(fe);
+       if (ret)
+               goto error;
+
+       /* program tuner */
+       if (fe->ops.tuner_ops.set_params)
+               fe->ops.tuner_ops.set_params(fe, params);
+
+       if (priv->delivery_system !=  SYS_DVBC_ANNEX_AC) {
+               for (i = 0; i < ARRAY_SIZE(tab); i++) {
+                       ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,
+                               tab[i].val, tab[i].mask);
+                       if (ret)
+                               goto error;
+               }
+       }
+
+       priv->delivery_system = SYS_DVBC_ANNEX_AC;
+       priv->ber_running = 0; /* tune stops BER counter */
+
+       num = priv->cfg.if_dvbc;
+       num *= 0x4000;
+       if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
+       buf[0] = (if_ctl >> 8) & 0x3f;
+       buf[1] = (if_ctl >> 0) & 0xff;
+
+       ret = cxd2820r_wr_regs(priv, 0x10042, buf, 2);
+       if (ret)
+               goto error;
+
+       ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08);
+       if (ret)
+               goto error;
+
+       ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01);
+       if (ret)
+               goto error;
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+int cxd2820r_get_frontend_c(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *p)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int ret;
+       u8 buf[2];
+
+       ret = cxd2820r_rd_regs(priv, 0x1001a, buf, 2);
+       if (ret)
+               goto error;
+
+       c->symbol_rate = 2500 * ((buf[0] & 0x0f) << 8 | buf[1]);
+
+       ret = cxd2820r_rd_reg(priv, 0x10019, &buf[0]);
+       if (ret)
+               goto error;
+
+       switch ((buf[0] >> 0) & 0x03) {
+       case 0:
+               c->modulation = QAM_16;
+               break;
+       case 1:
+               c->modulation = QAM_32;
+               break;
+       case 2:
+               c->modulation = QAM_64;
+               break;
+       case 3:
+               c->modulation = QAM_128;
+               break;
+       case 4:
+               c->modulation = QAM_256;
+               break;
+       }
+
+       switch ((buf[0] >> 7) & 0x01) {
+       case 0:
+               c->inversion = INVERSION_OFF;
+               break;
+       case 1:
+               c->inversion = INVERSION_ON;
+               break;
+       }
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+int cxd2820r_read_ber_c(struct dvb_frontend *fe, u32 *ber)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+       u8 buf[3], start_ber = 0;
+       *ber = 0;
+
+       if (priv->ber_running) {
+               ret = cxd2820r_rd_regs(priv, 0x10076, buf, sizeof(buf));
+               if (ret)
+                       goto error;
+
+               if ((buf[2] >> 7) & 0x01 || (buf[2] >> 4) & 0x01) {
+                       *ber = (buf[2] & 0x0f) << 16 | buf[1] << 8 | buf[0];
+                       start_ber = 1;
+               }
+       } else {
+               priv->ber_running = 1;
+               start_ber = 1;
+       }
+
+       if (start_ber) {
+               /* (re)start BER */
+               ret = cxd2820r_wr_reg(priv, 0x10079, 0x01);
+               if (ret)
+                       goto error;
+       }
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+int cxd2820r_read_signal_strength_c(struct dvb_frontend *fe,
+       u16 *strength)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+       u8 buf[2];
+       u16 tmp;
+
+       ret = cxd2820r_rd_regs(priv, 0x10049, buf, sizeof(buf));
+       if (ret)
+               goto error;
+
+       tmp = (buf[0] & 0x03) << 8 | buf[1];
+       tmp = (~tmp & 0x03ff);
+
+       if (tmp == 512)
+               /* ~no signal */
+               tmp = 0;
+       else if (tmp > 350)
+               tmp = 350;
+
+       /* scale value to 0x0000-0xffff */
+       *strength = tmp * 0xffff / (350-0);
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+int cxd2820r_read_snr_c(struct dvb_frontend *fe, u16 *snr)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+       u8 tmp;
+       unsigned int A, B;
+       /* report SNR in dB * 10 */
+
+       ret = cxd2820r_rd_reg(priv, 0x10019, &tmp);
+       if (ret)
+               goto error;
+
+       if (((tmp >> 0) & 0x03) % 2) {
+               A = 875;
+               B = 650;
+       } else {
+               A = 950;
+               B = 760;
+       }
+
+       ret = cxd2820r_rd_reg(priv, 0x1004d, &tmp);
+       if (ret)
+               goto error;
+
+       #define CXD2820R_LOG2_E_24 24204406 /* log2(e) << 24 */
+       if (tmp)
+               *snr = A * (intlog2(B / tmp) >> 5) / (CXD2820R_LOG2_E_24 >> 5)
+                       / 10;
+       else
+               *snr = 0;
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+int cxd2820r_read_ucblocks_c(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       *ucblocks = 0;
+       /* no way to read ? */
+       return 0;
+}
+
+int cxd2820r_read_status_c(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+       u8 buf[2];
+       *status = 0;
+
+       ret = cxd2820r_rd_regs(priv, 0x10088, buf, sizeof(buf));
+       if (ret)
+               goto error;
+
+       if (((buf[0] >> 0) & 0x01) == 1) {
+               *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+                       FE_HAS_VITERBI | FE_HAS_SYNC;
+
+               if (((buf[1] >> 3) & 0x01) == 1) {
+                       *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+                               FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+               }
+       }
+
+       dbg("%s: lock=%02x %02x", __func__, buf[0], buf[1]);
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+int cxd2820r_init_c(struct dvb_frontend *fe)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+
+       ret = cxd2820r_wr_reg(priv, 0x00085, 0x07);
+       if (ret)
+               goto error;
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+int cxd2820r_sleep_c(struct dvb_frontend *fe)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret, i;
+       struct reg_val_mask tab[] = {
+               { 0x000ff, 0x1f, 0xff },
+               { 0x00085, 0x00, 0xff },
+               { 0x00088, 0x01, 0xff },
+               { 0x00081, 0x00, 0xff },
+               { 0x00080, 0x00, 0xff },
+       };
+
+       dbg("%s", __func__);
+
+       priv->delivery_system = SYS_UNDEFINED;
+
+       for (i = 0; i < ARRAY_SIZE(tab); i++) {
+               ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val,
+                       tab[i].mask);
+               if (ret)
+                       goto error;
+       }
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe,
+       struct dvb_frontend_tune_settings *s)
+{
+       s->min_delay_ms = 500;
+       s->step_size = 0; /* no zigzag */
+       s->max_drift = 0;
+
+       return 0;
+}
+
diff --git a/drivers/media/dvb/frontends/cxd2820r_core.c b/drivers/media/dvb/frontends/cxd2820r_core.c
new file mode 100644 (file)
index 0000000..0779f69
--- /dev/null
@@ -0,0 +1,915 @@
+/*
+ * Sony CXD2820R demodulator driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#include "cxd2820r_priv.h"
+
+int cxd2820r_debug;
+module_param_named(debug, cxd2820r_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+/* write multiple registers */
+static int cxd2820r_wr_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg,
+       u8 *val, int len)
+{
+       int ret;
+       u8 buf[len+1];
+       struct i2c_msg msg[1] = {
+               {
+                       .addr = i2c,
+                       .flags = 0,
+                       .len = sizeof(buf),
+                       .buf = buf,
+               }
+       };
+
+       buf[0] = reg;
+       memcpy(&buf[1], val, len);
+
+       ret = i2c_transfer(priv->i2c, msg, 1);
+       if (ret == 1) {
+               ret = 0;
+       } else {
+               warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
+               ret = -EREMOTEIO;
+       }
+       return ret;
+}
+
+/* read multiple registers */
+static int cxd2820r_rd_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg,
+       u8 *val, int len)
+{
+       int ret;
+       u8 buf[len];
+       struct i2c_msg msg[2] = {
+               {
+                       .addr = i2c,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = &reg,
+               }, {
+                       .addr = i2c,
+                       .flags = I2C_M_RD,
+                       .len = sizeof(buf),
+                       .buf = buf,
+               }
+       };
+
+       ret = i2c_transfer(priv->i2c, msg, 2);
+       if (ret == 2) {
+               memcpy(val, buf, len);
+               ret = 0;
+       } else {
+               warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
+               ret = -EREMOTEIO;
+       }
+
+       return ret;
+}
+
+/* write multiple registers */
+int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
+       int len)
+{
+       int ret;
+       u8 i2c_addr;
+       u8 reg = (reginfo >> 0) & 0xff;
+       u8 bank = (reginfo >> 8) & 0xff;
+       u8 i2c = (reginfo >> 16) & 0x01;
+
+       /* select I2C */
+       if (i2c)
+               i2c_addr = priv->cfg.i2c_address | (1 << 1); /* DVB-C */
+       else
+               i2c_addr = priv->cfg.i2c_address; /* DVB-T/T2 */
+
+       /* switch bank if needed */
+       if (bank != priv->bank[i2c]) {
+               ret = cxd2820r_wr_regs_i2c(priv, i2c_addr, 0x00, &bank, 1);
+               if (ret)
+                       return ret;
+               priv->bank[i2c] = bank;
+       }
+       return cxd2820r_wr_regs_i2c(priv, i2c_addr, reg, val, len);
+}
+
+/* read multiple registers */
+int cxd2820r_rd_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
+       int len)
+{
+       int ret;
+       u8 i2c_addr;
+       u8 reg = (reginfo >> 0) & 0xff;
+       u8 bank = (reginfo >> 8) & 0xff;
+       u8 i2c = (reginfo >> 16) & 0x01;
+
+       /* select I2C */
+       if (i2c)
+               i2c_addr = priv->cfg.i2c_address | (1 << 1); /* DVB-C */
+       else
+               i2c_addr = priv->cfg.i2c_address; /* DVB-T/T2 */
+
+       /* switch bank if needed */
+       if (bank != priv->bank[i2c]) {
+               ret = cxd2820r_wr_regs_i2c(priv, i2c_addr, 0x00, &bank, 1);
+               if (ret)
+                       return ret;
+               priv->bank[i2c] = bank;
+       }
+       return cxd2820r_rd_regs_i2c(priv, i2c_addr, reg, val, len);
+}
+
+/* write single register */
+int cxd2820r_wr_reg(struct cxd2820r_priv *priv, u32 reg, u8 val)
+{
+       return cxd2820r_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register */
+int cxd2820r_rd_reg(struct cxd2820r_priv *priv, u32 reg, u8 *val)
+{
+       return cxd2820r_rd_regs(priv, reg, val, 1);
+}
+
+/* write single register with mask */
+int cxd2820r_wr_reg_mask(struct cxd2820r_priv *priv, u32 reg, u8 val,
+       u8 mask)
+{
+       int ret;
+       u8 tmp;
+
+       /* no need for read if whole reg is written */
+       if (mask != 0xff) {
+               ret = cxd2820r_rd_reg(priv, reg, &tmp);
+               if (ret)
+                       return ret;
+
+               val &= mask;
+               tmp &= ~mask;
+               val |= tmp;
+       }
+
+       return cxd2820r_wr_reg(priv, reg, val);
+}
+
+int cxd2820r_gpio(struct dvb_frontend *fe)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret, i;
+       u8 *gpio, tmp0, tmp1;
+       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+       switch (fe->dtv_property_cache.delivery_system) {
+       case SYS_DVBT:
+               gpio = priv->cfg.gpio_dvbt;
+               break;
+       case SYS_DVBT2:
+               gpio = priv->cfg.gpio_dvbt2;
+               break;
+       case SYS_DVBC_ANNEX_AC:
+               gpio = priv->cfg.gpio_dvbc;
+               break;
+       default:
+               ret = -EINVAL;
+               goto error;
+       }
+
+       /* update GPIOs only when needed */
+       if (!memcmp(gpio, priv->gpio, sizeof(priv->gpio)))
+               return 0;
+
+       tmp0 = 0x00;
+       tmp1 = 0x00;
+       for (i = 0; i < sizeof(priv->gpio); i++) {
+               /* enable / disable */
+               if (gpio[i] & CXD2820R_GPIO_E)
+                       tmp0 |= (2 << 6) >> (2 * i);
+               else
+                       tmp0 |= (1 << 6) >> (2 * i);
+
+               /* input / output */
+               if (gpio[i] & CXD2820R_GPIO_I)
+                       tmp1 |= (1 << (3 + i));
+               else
+                       tmp1 |= (0 << (3 + i));
+
+               /* high / low */
+               if (gpio[i] & CXD2820R_GPIO_H)
+                       tmp1 |= (1 << (0 + i));
+               else
+                       tmp1 |= (0 << (0 + i));
+
+               dbg("%s: GPIO i=%d %02x %02x", __func__, i, tmp0, tmp1);
+       }
+
+       dbg("%s: wr gpio=%02x %02x", __func__, tmp0, tmp1);
+
+       /* write bits [7:2] */
+       ret = cxd2820r_wr_reg_mask(priv, 0x00089, tmp0, 0xfc);
+       if (ret)
+               goto error;
+
+       /* write bits [5:0] */
+       ret = cxd2820r_wr_reg_mask(priv, 0x0008e, tmp1, 0x3f);
+       if (ret)
+               goto error;
+
+       memcpy(priv->gpio, gpio, sizeof(priv->gpio));
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+/* lock FE */
+static int cxd2820r_lock(struct cxd2820r_priv *priv, int active_fe)
+{
+       int ret = 0;
+       dbg("%s: active_fe=%d", __func__, active_fe);
+
+       mutex_lock(&priv->fe_lock);
+
+       /* -1=NONE, 0=DVB-T/T2, 1=DVB-C */
+       if (priv->active_fe == active_fe)
+               ;
+       else if (priv->active_fe == -1)
+               priv->active_fe = active_fe;
+       else
+               ret = -EBUSY;
+
+       mutex_unlock(&priv->fe_lock);
+
+       return ret;
+}
+
+/* unlock FE */
+static void cxd2820r_unlock(struct cxd2820r_priv *priv, int active_fe)
+{
+       dbg("%s: active_fe=%d", __func__, active_fe);
+
+       mutex_lock(&priv->fe_lock);
+
+       /* -1=NONE, 0=DVB-T/T2, 1=DVB-C */
+       if (priv->active_fe == active_fe)
+               priv->active_fe = -1;
+
+       mutex_unlock(&priv->fe_lock);
+
+       return;
+}
+
+/* 64 bit div with round closest, like DIV_ROUND_CLOSEST but 64 bit */
+u32 cxd2820r_div_u64_round_closest(u64 dividend, u32 divisor)
+{
+       return div_u64(dividend + (divisor / 2), divisor);
+}
+
+static int cxd2820r_set_frontend(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *p)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int ret;
+       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+       if (fe->ops.info.type == FE_OFDM) {
+               /* DVB-T/T2 */
+               ret = cxd2820r_lock(priv, 0);
+               if (ret)
+                       return ret;
+
+               switch (priv->delivery_system) {
+               case SYS_UNDEFINED:
+                       if (c->delivery_system == SYS_DVBT) {
+                               /* SLEEP => DVB-T */
+                               ret = cxd2820r_set_frontend_t(fe, p);
+                       } else {
+                               /* SLEEP => DVB-T2 */
+                               ret = cxd2820r_set_frontend_t2(fe, p);
+                       }
+                       break;
+               case SYS_DVBT:
+                       if (c->delivery_system == SYS_DVBT) {
+                               /* DVB-T => DVB-T */
+                               ret = cxd2820r_set_frontend_t(fe, p);
+                       } else if (c->delivery_system == SYS_DVBT2) {
+                               /* DVB-T => DVB-T2 */
+                               ret = cxd2820r_sleep_t(fe);
+                               ret = cxd2820r_set_frontend_t2(fe, p);
+                       }
+                       break;
+               case SYS_DVBT2:
+                       if (c->delivery_system == SYS_DVBT2) {
+                               /* DVB-T2 => DVB-T2 */
+                               ret = cxd2820r_set_frontend_t2(fe, p);
+                       } else if (c->delivery_system == SYS_DVBT) {
+                               /* DVB-T2 => DVB-T */
+                               ret = cxd2820r_sleep_t2(fe);
+                               ret = cxd2820r_set_frontend_t(fe, p);
+                       }
+                       break;
+               default:
+                       dbg("%s: error state=%d", __func__,
+                               priv->delivery_system);
+                       ret = -EINVAL;
+               }
+       } else {
+               /* DVB-C */
+               ret = cxd2820r_lock(priv, 1);
+               if (ret)
+                       return ret;
+
+               ret = cxd2820r_set_frontend_c(fe, p);
+       }
+
+       return ret;
+}
+
+static int cxd2820r_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+       if (fe->ops.info.type == FE_OFDM) {
+               /* DVB-T/T2 */
+               ret = cxd2820r_lock(priv, 0);
+               if (ret)
+                       return ret;
+
+               switch (fe->dtv_property_cache.delivery_system) {
+               case SYS_DVBT:
+                       ret = cxd2820r_read_status_t(fe, status);
+                       break;
+               case SYS_DVBT2:
+                       ret = cxd2820r_read_status_t2(fe, status);
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+       } else {
+               /* DVB-C */
+               ret = cxd2820r_lock(priv, 1);
+               if (ret)
+                       return ret;
+
+               ret = cxd2820r_read_status_c(fe, status);
+       }
+
+       return ret;
+}
+
+static int cxd2820r_get_frontend(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *p)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+       if (fe->ops.info.type == FE_OFDM) {
+               /* DVB-T/T2 */
+               ret = cxd2820r_lock(priv, 0);
+               if (ret)
+                       return ret;
+
+               switch (fe->dtv_property_cache.delivery_system) {
+               case SYS_DVBT:
+                       ret = cxd2820r_get_frontend_t(fe, p);
+                       break;
+               case SYS_DVBT2:
+                       ret = cxd2820r_get_frontend_t2(fe, p);
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+       } else {
+               /* DVB-C */
+               ret = cxd2820r_lock(priv, 1);
+               if (ret)
+                       return ret;
+
+               ret = cxd2820r_get_frontend_c(fe, p);
+       }
+
+       return ret;
+}
+
+static int cxd2820r_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+       if (fe->ops.info.type == FE_OFDM) {
+               /* DVB-T/T2 */
+               ret = cxd2820r_lock(priv, 0);
+               if (ret)
+                       return ret;
+
+               switch (fe->dtv_property_cache.delivery_system) {
+               case SYS_DVBT:
+                       ret = cxd2820r_read_ber_t(fe, ber);
+                       break;
+               case SYS_DVBT2:
+                       ret = cxd2820r_read_ber_t2(fe, ber);
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+       } else {
+               /* DVB-C */
+               ret = cxd2820r_lock(priv, 1);
+               if (ret)
+                       return ret;
+
+               ret = cxd2820r_read_ber_c(fe, ber);
+       }
+
+       return ret;
+}
+
+static int cxd2820r_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+       if (fe->ops.info.type == FE_OFDM) {
+               /* DVB-T/T2 */
+               ret = cxd2820r_lock(priv, 0);
+               if (ret)
+                       return ret;
+
+               switch (fe->dtv_property_cache.delivery_system) {
+               case SYS_DVBT:
+                       ret = cxd2820r_read_signal_strength_t(fe, strength);
+                       break;
+               case SYS_DVBT2:
+                       ret = cxd2820r_read_signal_strength_t2(fe, strength);
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+       } else {
+               /* DVB-C */
+               ret = cxd2820r_lock(priv, 1);
+               if (ret)
+                       return ret;
+
+               ret = cxd2820r_read_signal_strength_c(fe, strength);
+       }
+
+       return ret;
+}
+
+static int cxd2820r_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+       if (fe->ops.info.type == FE_OFDM) {
+               /* DVB-T/T2 */
+               ret = cxd2820r_lock(priv, 0);
+               if (ret)
+                       return ret;
+
+               switch (fe->dtv_property_cache.delivery_system) {
+               case SYS_DVBT:
+                       ret = cxd2820r_read_snr_t(fe, snr);
+                       break;
+               case SYS_DVBT2:
+                       ret = cxd2820r_read_snr_t2(fe, snr);
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+       } else {
+               /* DVB-C */
+               ret = cxd2820r_lock(priv, 1);
+               if (ret)
+                       return ret;
+
+               ret = cxd2820r_read_snr_c(fe, snr);
+       }
+
+       return ret;
+}
+
+static int cxd2820r_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+       if (fe->ops.info.type == FE_OFDM) {
+               /* DVB-T/T2 */
+               ret = cxd2820r_lock(priv, 0);
+               if (ret)
+                       return ret;
+
+               switch (fe->dtv_property_cache.delivery_system) {
+               case SYS_DVBT:
+                       ret = cxd2820r_read_ucblocks_t(fe, ucblocks);
+                       break;
+               case SYS_DVBT2:
+                       ret = cxd2820r_read_ucblocks_t2(fe, ucblocks);
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+       } else {
+               /* DVB-C */
+               ret = cxd2820r_lock(priv, 1);
+               if (ret)
+                       return ret;
+
+               ret = cxd2820r_read_ucblocks_c(fe, ucblocks);
+       }
+
+       return ret;
+}
+
+static int cxd2820r_init(struct dvb_frontend *fe)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+       priv->delivery_system = SYS_UNDEFINED;
+       /* delivery system is unknown at that (init) phase */
+
+       if (fe->ops.info.type == FE_OFDM) {
+               /* DVB-T/T2 */
+               ret = cxd2820r_lock(priv, 0);
+               if (ret)
+                       return ret;
+
+               ret = cxd2820r_init_t(fe);
+       } else {
+               /* DVB-C */
+               ret = cxd2820r_lock(priv, 1);
+               if (ret)
+                       return ret;
+
+               ret = cxd2820r_init_c(fe);
+       }
+
+       return ret;
+}
+
+static int cxd2820r_sleep(struct dvb_frontend *fe)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+       if (fe->ops.info.type == FE_OFDM) {
+               /* DVB-T/T2 */
+               ret = cxd2820r_lock(priv, 0);
+               if (ret)
+                       return ret;
+
+               switch (fe->dtv_property_cache.delivery_system) {
+               case SYS_DVBT:
+                       ret = cxd2820r_sleep_t(fe);
+                       break;
+               case SYS_DVBT2:
+                       ret = cxd2820r_sleep_t2(fe);
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+
+               cxd2820r_unlock(priv, 0);
+       } else {
+               /* DVB-C */
+               ret = cxd2820r_lock(priv, 1);
+               if (ret)
+                       return ret;
+
+               ret = cxd2820r_sleep_c(fe);
+
+               cxd2820r_unlock(priv, 1);
+       }
+
+       return ret;
+}
+
+static int cxd2820r_get_tune_settings(struct dvb_frontend *fe,
+       struct dvb_frontend_tune_settings *s)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+       if (fe->ops.info.type == FE_OFDM) {
+               /* DVB-T/T2 */
+               ret = cxd2820r_lock(priv, 0);
+               if (ret)
+                       return ret;
+
+               switch (fe->dtv_property_cache.delivery_system) {
+               case SYS_DVBT:
+                       ret = cxd2820r_get_tune_settings_t(fe, s);
+                       break;
+               case SYS_DVBT2:
+                       ret = cxd2820r_get_tune_settings_t2(fe, s);
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+       } else {
+               /* DVB-C */
+               ret = cxd2820r_lock(priv, 1);
+               if (ret)
+                       return ret;
+
+               ret = cxd2820r_get_tune_settings_c(fe, s);
+       }
+
+       return ret;
+}
+
+static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *p)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int ret, i;
+       fe_status_t status = 0;
+       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+       /* switch between DVB-T and DVB-T2 when tune fails */
+       if (priv->last_tune_failed) {
+               if (priv->delivery_system == SYS_DVBT)
+                       c->delivery_system = SYS_DVBT2;
+               else
+                       c->delivery_system = SYS_DVBT;
+       }
+
+       /* set frontend */
+       ret = cxd2820r_set_frontend(fe, p);
+       if (ret)
+               goto error;
+
+
+       /* frontend lock wait loop count */
+       switch (priv->delivery_system) {
+       case SYS_DVBT:
+               i = 20;
+               break;
+       case SYS_DVBT2:
+               i = 40;
+               break;
+       case SYS_UNDEFINED:
+       default:
+               i = 0;
+               break;
+       }
+
+       /* wait frontend lock */
+       for (; i > 0; i--) {
+               dbg("%s: LOOP=%d", __func__, i);
+               msleep(50);
+               ret = cxd2820r_read_status(fe, &status);
+               if (ret)
+                       goto error;
+
+               if (status & FE_HAS_SIGNAL)
+                       break;
+       }
+
+       /* check if we have a valid signal */
+       if (status) {
+               priv->last_tune_failed = 0;
+               return DVBFE_ALGO_SEARCH_SUCCESS;
+       } else {
+               priv->last_tune_failed = 1;
+               return DVBFE_ALGO_SEARCH_AGAIN;
+       }
+
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return DVBFE_ALGO_SEARCH_ERROR;
+}
+
+static int cxd2820r_get_frontend_algo(struct dvb_frontend *fe)
+{
+       return DVBFE_ALGO_CUSTOM;
+}
+
+static void cxd2820r_release(struct dvb_frontend *fe)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       dbg("%s", __func__);
+
+       if (fe->ops.info.type == FE_OFDM) {
+               i2c_del_adapter(&priv->tuner_i2c_adapter);
+               kfree(priv);
+       }
+
+       return;
+}
+
+static u32 cxd2820r_tuner_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static int cxd2820r_tuner_i2c_xfer(struct i2c_adapter *i2c_adap,
+       struct i2c_msg msg[], int num)
+{
+       struct cxd2820r_priv *priv = i2c_get_adapdata(i2c_adap);
+       u8 obuf[msg[0].len + 2];
+       struct i2c_msg msg2[2] = {
+               {
+                       .addr = priv->cfg.i2c_address,
+                       .flags = 0,
+                       .len = sizeof(obuf),
+                       .buf = obuf,
+               }, {
+                       .addr = priv->cfg.i2c_address,
+                       .flags = I2C_M_RD,
+                       .len = msg[1].len,
+                       .buf = msg[1].buf,
+               }
+       };
+
+       obuf[0] = 0x09;
+       obuf[1] = (msg[0].addr << 1);
+       if (num == 2) { /* I2C read */
+               obuf[1] = (msg[0].addr << 1) | I2C_M_RD; /* I2C RD flag */
+               msg2[0].len = sizeof(obuf) - 1; /* maybe HW bug ? */
+       }
+       memcpy(&obuf[2], msg[0].buf, msg[0].len);
+
+       return i2c_transfer(priv->i2c, msg2, num);
+}
+
+static struct i2c_algorithm cxd2820r_tuner_i2c_algo = {
+       .master_xfer   = cxd2820r_tuner_i2c_xfer,
+       .functionality = cxd2820r_tuner_i2c_func,
+};
+
+struct i2c_adapter *cxd2820r_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       return &priv->tuner_i2c_adapter;
+}
+EXPORT_SYMBOL(cxd2820r_get_tuner_i2c_adapter);
+
+static struct dvb_frontend_ops cxd2820r_ops[2];
+
+struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg,
+       struct i2c_adapter *i2c, struct dvb_frontend *fe)
+{
+       int ret;
+       struct cxd2820r_priv *priv = NULL;
+       u8 tmp;
+
+       if (fe == NULL) {
+               /* FE0 */
+               /* allocate memory for the internal priv */
+               priv = kzalloc(sizeof(struct cxd2820r_priv), GFP_KERNEL);
+               if (priv == NULL)
+                       goto error;
+
+               /* setup the priv */
+               priv->i2c = i2c;
+               memcpy(&priv->cfg, cfg, sizeof(struct cxd2820r_config));
+               mutex_init(&priv->fe_lock);
+
+               priv->active_fe = -1; /* NONE */
+
+               /* check if the demod is there */
+               priv->bank[0] = priv->bank[1] = 0xff;
+               ret = cxd2820r_rd_reg(priv, 0x000fd, &tmp);
+               dbg("%s: chip id=%02x", __func__, tmp);
+               if (ret || tmp != 0xe1)
+                       goto error;
+
+               /* create frontends */
+               memcpy(&priv->fe[0].ops, &cxd2820r_ops[0],
+                       sizeof(struct dvb_frontend_ops));
+               memcpy(&priv->fe[1].ops, &cxd2820r_ops[1],
+                       sizeof(struct dvb_frontend_ops));
+
+               priv->fe[0].demodulator_priv = priv;
+               priv->fe[1].demodulator_priv = priv;
+
+               /* create tuner i2c adapter */
+               strlcpy(priv->tuner_i2c_adapter.name,
+                       "CXD2820R tuner I2C adapter",
+                       sizeof(priv->tuner_i2c_adapter.name));
+               priv->tuner_i2c_adapter.algo = &cxd2820r_tuner_i2c_algo;
+               priv->tuner_i2c_adapter.algo_data = NULL;
+               i2c_set_adapdata(&priv->tuner_i2c_adapter, priv);
+               if (i2c_add_adapter(&priv->tuner_i2c_adapter) < 0) {
+                       err("tuner I2C bus could not be initialized");
+                       goto error;
+               }
+
+               return &priv->fe[0];
+
+       } else {
+               /* FE1: FE0 given as pointer, just return FE1 we have
+                * already created */
+               priv = fe->demodulator_priv;
+               return &priv->fe[1];
+       }
+
+error:
+       kfree(priv);
+       return NULL;
+}
+EXPORT_SYMBOL(cxd2820r_attach);
+
+static struct dvb_frontend_ops cxd2820r_ops[2] = {
+       {
+               /* DVB-T/T2 */
+               .info = {
+                       .name = "Sony CXD2820R (DVB-T/T2)",
+                       .type = FE_OFDM,
+                       .caps =
+                               FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+                               FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 |
+                               FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                               FE_CAN_QPSK | FE_CAN_QAM_16 |
+                               FE_CAN_QAM_64 | FE_CAN_QAM_256 |
+                               FE_CAN_QAM_AUTO |
+                               FE_CAN_TRANSMISSION_MODE_AUTO |
+                               FE_CAN_GUARD_INTERVAL_AUTO |
+                               FE_CAN_HIERARCHY_AUTO |
+                               FE_CAN_MUTE_TS |
+                               FE_CAN_2G_MODULATION
+               },
+
+               .release = cxd2820r_release,
+               .init = cxd2820r_init,
+               .sleep = cxd2820r_sleep,
+
+               .get_tune_settings = cxd2820r_get_tune_settings,
+
+               .get_frontend = cxd2820r_get_frontend,
+
+               .get_frontend_algo = cxd2820r_get_frontend_algo,
+               .search = cxd2820r_search,
+
+               .read_status = cxd2820r_read_status,
+               .read_snr = cxd2820r_read_snr,
+               .read_ber = cxd2820r_read_ber,
+               .read_ucblocks = cxd2820r_read_ucblocks,
+               .read_signal_strength = cxd2820r_read_signal_strength,
+       },
+       {
+               /* DVB-C */
+               .info = {
+                       .name = "Sony CXD2820R (DVB-C)",
+                       .type = FE_QAM,
+                       .caps =
+                               FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
+                               FE_CAN_QAM_128 | FE_CAN_QAM_256 |
+                               FE_CAN_FEC_AUTO
+               },
+
+               .release = cxd2820r_release,
+               .init = cxd2820r_init,
+               .sleep = cxd2820r_sleep,
+
+               .get_tune_settings = cxd2820r_get_tune_settings,
+
+               .set_frontend = cxd2820r_set_frontend,
+               .get_frontend = cxd2820r_get_frontend,
+
+               .read_status = cxd2820r_read_status,
+               .read_snr = cxd2820r_read_snr,
+               .read_ber = cxd2820r_read_ber,
+               .read_ucblocks = cxd2820r_read_ucblocks,
+               .read_signal_strength = cxd2820r_read_signal_strength,
+       },
+};
+
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Sony CXD2820R demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/cxd2820r_priv.h b/drivers/media/dvb/frontends/cxd2820r_priv.h
new file mode 100644 (file)
index 0000000..25adbee
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Sony CXD2820R demodulator driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#ifndef CXD2820R_PRIV_H
+#define CXD2820R_PRIV_H
+
+#include <linux/dvb/version.h>
+#include "dvb_frontend.h"
+#include "dvb_math.h"
+#include "cxd2820r.h"
+
+#define LOG_PREFIX "cxd2820r"
+
+#undef dbg
+#define dbg(f, arg...) \
+       if (cxd2820r_debug) \
+               printk(KERN_INFO   LOG_PREFIX": " f "\n" , ## arg)
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+struct reg_val_mask {
+       u32 reg;
+       u8  val;
+       u8  mask;
+};
+
+struct cxd2820r_priv {
+       struct i2c_adapter *i2c;
+       struct dvb_frontend fe[2];
+       struct cxd2820r_config cfg;
+       struct i2c_adapter tuner_i2c_adapter;
+
+       struct mutex fe_lock; /* FE lock */
+       int active_fe:2; /* FE lock, -1=NONE, 0=DVB-T/T2, 1=DVB-C */
+
+       int ber_running:1;
+
+       u8 bank[2];
+       u8 gpio[3];
+
+       fe_delivery_system_t delivery_system;
+       int last_tune_failed:1; /* for switch between T and T2 tune */
+};
+
+/* cxd2820r_core.c */
+
+extern int cxd2820r_debug;
+
+int cxd2820r_gpio(struct dvb_frontend *fe);
+
+int cxd2820r_wr_reg_mask(struct cxd2820r_priv *priv, u32 reg, u8 val,
+       u8 mask);
+
+int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
+       int len);
+
+u32 cxd2820r_div_u64_round_closest(u64 dividend, u32 divisor);
+
+int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
+       int len);
+
+int cxd2820r_rd_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
+       int len);
+
+int cxd2820r_wr_reg(struct cxd2820r_priv *priv, u32 reg, u8 val);
+
+int cxd2820r_rd_reg(struct cxd2820r_priv *priv, u32 reg, u8 *val);
+
+/* cxd2820r_c.c */
+
+int cxd2820r_get_frontend_c(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *p);
+
+int cxd2820r_set_frontend_c(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *params);
+
+int cxd2820r_read_status_c(struct dvb_frontend *fe, fe_status_t *status);
+
+int cxd2820r_read_ber_c(struct dvb_frontend *fe, u32 *ber);
+
+int cxd2820r_read_signal_strength_c(struct dvb_frontend *fe, u16 *strength);
+
+int cxd2820r_read_snr_c(struct dvb_frontend *fe, u16 *snr);
+
+int cxd2820r_read_ucblocks_c(struct dvb_frontend *fe, u32 *ucblocks);
+
+int cxd2820r_init_c(struct dvb_frontend *fe);
+
+int cxd2820r_sleep_c(struct dvb_frontend *fe);
+
+int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe,
+       struct dvb_frontend_tune_settings *s);
+
+/* cxd2820r_t.c */
+
+int cxd2820r_get_frontend_t(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *p);
+
+int cxd2820r_set_frontend_t(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *params);
+
+int cxd2820r_read_status_t(struct dvb_frontend *fe, fe_status_t *status);
+
+int cxd2820r_read_ber_t(struct dvb_frontend *fe, u32 *ber);
+
+int cxd2820r_read_signal_strength_t(struct dvb_frontend *fe, u16 *strength);
+
+int cxd2820r_read_snr_t(struct dvb_frontend *fe, u16 *snr);
+
+int cxd2820r_read_ucblocks_t(struct dvb_frontend *fe, u32 *ucblocks);
+
+int cxd2820r_init_t(struct dvb_frontend *fe);
+
+int cxd2820r_sleep_t(struct dvb_frontend *fe);
+
+int cxd2820r_get_tune_settings_t(struct dvb_frontend *fe,
+       struct dvb_frontend_tune_settings *s);
+
+/* cxd2820r_t2.c */
+
+int cxd2820r_get_frontend_t2(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *p);
+
+int cxd2820r_set_frontend_t2(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *params);
+
+int cxd2820r_read_status_t2(struct dvb_frontend *fe, fe_status_t *status);
+
+int cxd2820r_read_ber_t2(struct dvb_frontend *fe, u32 *ber);
+
+int cxd2820r_read_signal_strength_t2(struct dvb_frontend *fe, u16 *strength);
+
+int cxd2820r_read_snr_t2(struct dvb_frontend *fe, u16 *snr);
+
+int cxd2820r_read_ucblocks_t2(struct dvb_frontend *fe, u32 *ucblocks);
+
+int cxd2820r_init_t2(struct dvb_frontend *fe);
+
+int cxd2820r_sleep_t2(struct dvb_frontend *fe);
+
+int cxd2820r_get_tune_settings_t2(struct dvb_frontend *fe,
+       struct dvb_frontend_tune_settings *s);
+
+#endif /* CXD2820R_PRIV_H */
diff --git a/drivers/media/dvb/frontends/cxd2820r_t.c b/drivers/media/dvb/frontends/cxd2820r_t.c
new file mode 100644 (file)
index 0000000..6582564
--- /dev/null
@@ -0,0 +1,449 @@
+/*
+ * Sony CXD2820R demodulator driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#include "cxd2820r_priv.h"
+
+int cxd2820r_set_frontend_t(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *p)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int ret, i;
+       u32 if_khz, if_ctl;
+       u64 num;
+       u8 buf[3], bw_param;
+       u8 bw_params1[][5] = {
+               { 0x17, 0xea, 0xaa, 0xaa, 0xaa }, /* 6 MHz */
+               { 0x14, 0x80, 0x00, 0x00, 0x00 }, /* 7 MHz */
+               { 0x11, 0xf0, 0x00, 0x00, 0x00 }, /* 8 MHz */
+       };
+       u8 bw_params2[][2] = {
+               { 0x1f, 0xdc }, /* 6 MHz */
+               { 0x12, 0xf8 }, /* 7 MHz */
+               { 0x01, 0xe0 }, /* 8 MHz */
+       };
+       struct reg_val_mask tab[] = {
+               { 0x00080, 0x00, 0xff },
+               { 0x00081, 0x03, 0xff },
+               { 0x00085, 0x07, 0xff },
+               { 0x00088, 0x01, 0xff },
+
+               { 0x00070, priv->cfg.ts_mode, 0xff },
+               { 0x000cb, priv->cfg.if_agc_polarity << 6, 0x40 },
+               { 0x000a5, 0x00, 0x01 },
+               { 0x00082, 0x20, 0x60 },
+               { 0x000c2, 0xc3, 0xff },
+               { 0x0016a, 0x50, 0xff },
+               { 0x00427, 0x41, 0xff },
+       };
+
+       dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz);
+
+       /* update GPIOs */
+       ret = cxd2820r_gpio(fe);
+       if (ret)
+               goto error;
+
+       /* program tuner */
+       if (fe->ops.tuner_ops.set_params)
+               fe->ops.tuner_ops.set_params(fe, p);
+
+       if (priv->delivery_system != SYS_DVBT) {
+               for (i = 0; i < ARRAY_SIZE(tab); i++) {
+                       ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,
+                               tab[i].val, tab[i].mask);
+                       if (ret)
+                               goto error;
+               }
+       }
+
+       priv->delivery_system = SYS_DVBT;
+       priv->ber_running = 0; /* tune stops BER counter */
+
+       switch (c->bandwidth_hz) {
+       case 6000000:
+               if_khz = priv->cfg.if_dvbt_6;
+               i = 0;
+               bw_param = 2;
+               break;
+       case 7000000:
+               if_khz = priv->cfg.if_dvbt_7;
+               i = 1;
+               bw_param = 1;
+               break;
+       case 8000000:
+               if_khz = priv->cfg.if_dvbt_8;
+               i = 2;
+               bw_param = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       num = if_khz;
+       num *= 0x1000000;
+       if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
+       buf[0] = ((if_ctl >> 16) & 0xff);
+       buf[1] = ((if_ctl >>  8) & 0xff);
+       buf[2] = ((if_ctl >>  0) & 0xff);
+
+       ret = cxd2820r_wr_regs(priv, 0x000b6, buf, 3);
+       if (ret)
+               goto error;
+
+       ret = cxd2820r_wr_regs(priv, 0x0009f, bw_params1[i], 5);
+       if (ret)
+               goto error;
+
+       ret = cxd2820r_wr_reg_mask(priv, 0x000d7, bw_param << 6, 0xc0);
+       if (ret)
+               goto error;
+
+       ret = cxd2820r_wr_regs(priv, 0x000d9, bw_params2[i], 2);
+       if (ret)
+               goto error;
+
+       ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08);
+       if (ret)
+               goto error;
+
+       ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01);
+       if (ret)
+               goto error;
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+int cxd2820r_get_frontend_t(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *p)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int ret;
+       u8 buf[2];
+
+       ret = cxd2820r_rd_regs(priv, 0x0002f, buf, sizeof(buf));
+       if (ret)
+               goto error;
+
+       switch ((buf[0] >> 6) & 0x03) {
+       case 0:
+               c->modulation = QPSK;
+               break;
+       case 1:
+               c->modulation = QAM_16;
+               break;
+       case 2:
+               c->modulation = QAM_64;
+               break;
+       }
+
+       switch ((buf[1] >> 1) & 0x03) {
+       case 0:
+               c->transmission_mode = TRANSMISSION_MODE_2K;
+               break;
+       case 1:
+               c->transmission_mode = TRANSMISSION_MODE_8K;
+               break;
+       }
+
+       switch ((buf[1] >> 3) & 0x03) {
+       case 0:
+               c->guard_interval = GUARD_INTERVAL_1_32;
+               break;
+       case 1:
+               c->guard_interval = GUARD_INTERVAL_1_16;
+               break;
+       case 2:
+               c->guard_interval = GUARD_INTERVAL_1_8;
+               break;
+       case 3:
+               c->guard_interval = GUARD_INTERVAL_1_4;
+               break;
+       }
+
+       switch ((buf[0] >> 3) & 0x07) {
+       case 0:
+               c->hierarchy = HIERARCHY_NONE;
+               break;
+       case 1:
+               c->hierarchy = HIERARCHY_1;
+               break;
+       case 2:
+               c->hierarchy = HIERARCHY_2;
+               break;
+       case 3:
+               c->hierarchy = HIERARCHY_4;
+               break;
+       }
+
+       switch ((buf[0] >> 0) & 0x07) {
+       case 0:
+               c->code_rate_HP = FEC_1_2;
+               break;
+       case 1:
+               c->code_rate_HP = FEC_2_3;
+               break;
+       case 2:
+               c->code_rate_HP = FEC_3_4;
+               break;
+       case 3:
+               c->code_rate_HP = FEC_5_6;
+               break;
+       case 4:
+               c->code_rate_HP = FEC_7_8;
+               break;
+       }
+
+       switch ((buf[1] >> 5) & 0x07) {
+       case 0:
+               c->code_rate_LP = FEC_1_2;
+               break;
+       case 1:
+               c->code_rate_LP = FEC_2_3;
+               break;
+       case 2:
+               c->code_rate_LP = FEC_3_4;
+               break;
+       case 3:
+               c->code_rate_LP = FEC_5_6;
+               break;
+       case 4:
+               c->code_rate_LP = FEC_7_8;
+               break;
+       }
+
+       ret = cxd2820r_rd_reg(priv, 0x007c6, &buf[0]);
+       if (ret)
+               goto error;
+
+       switch ((buf[0] >> 0) & 0x01) {
+       case 0:
+               c->inversion = INVERSION_OFF;
+               break;
+       case 1:
+               c->inversion = INVERSION_ON;
+               break;
+       }
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+int cxd2820r_read_ber_t(struct dvb_frontend *fe, u32 *ber)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+       u8 buf[3], start_ber = 0;
+       *ber = 0;
+
+       if (priv->ber_running) {
+               ret = cxd2820r_rd_regs(priv, 0x00076, buf, sizeof(buf));
+               if (ret)
+                       goto error;
+
+               if ((buf[2] >> 7) & 0x01 || (buf[2] >> 4) & 0x01) {
+                       *ber = (buf[2] & 0x0f) << 16 | buf[1] << 8 | buf[0];
+                       start_ber = 1;
+               }
+       } else {
+               priv->ber_running = 1;
+               start_ber = 1;
+       }
+
+       if (start_ber) {
+               /* (re)start BER */
+               ret = cxd2820r_wr_reg(priv, 0x00079, 0x01);
+               if (ret)
+                       goto error;
+       }
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+int cxd2820r_read_signal_strength_t(struct dvb_frontend *fe,
+       u16 *strength)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+       u8 buf[2];
+       u16 tmp;
+
+       ret = cxd2820r_rd_regs(priv, 0x00026, buf, sizeof(buf));
+       if (ret)
+               goto error;
+
+       tmp = (buf[0] & 0x0f) << 8 | buf[1];
+       tmp = ~tmp & 0x0fff;
+
+       /* scale value to 0x0000-0xffff from 0x0000-0x0fff */
+       *strength = tmp * 0xffff / 0x0fff;
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+int cxd2820r_read_snr_t(struct dvb_frontend *fe, u16 *snr)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+       u8 buf[2];
+       u16 tmp;
+       /* report SNR in dB * 10 */
+
+       ret = cxd2820r_rd_regs(priv, 0x00028, buf, sizeof(buf));
+       if (ret)
+               goto error;
+
+       tmp = (buf[0] & 0x1f) << 8 | buf[1];
+       #define CXD2820R_LOG10_8_24 15151336 /* log10(8) << 24 */
+       if (tmp)
+               *snr = (intlog10(tmp) - CXD2820R_LOG10_8_24) / ((1 << 24)
+                       / 100);
+       else
+               *snr = 0;
+
+       dbg("%s: dBx10=%d val=%04x", __func__, *snr, tmp);
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+int cxd2820r_read_ucblocks_t(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       *ucblocks = 0;
+       /* no way to read ? */
+       return 0;
+}
+
+int cxd2820r_read_status_t(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+       u8 buf[4];
+       *status = 0;
+
+       ret = cxd2820r_rd_reg(priv, 0x00010, &buf[0]);
+       if (ret)
+               goto error;
+
+       if ((buf[0] & 0x07) == 6) {
+               ret = cxd2820r_rd_reg(priv, 0x00073, &buf[1]);
+               if (ret)
+                       goto error;
+
+               if (((buf[1] >> 3) & 0x01) == 1) {
+                       *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+                               FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+               } else {
+                       *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+                               FE_HAS_VITERBI | FE_HAS_SYNC;
+               }
+       } else {
+               ret = cxd2820r_rd_reg(priv, 0x00014, &buf[2]);
+               if (ret)
+                       goto error;
+
+               if ((buf[2] & 0x0f) >= 4) {
+                       ret = cxd2820r_rd_reg(priv, 0x00a14, &buf[3]);
+                       if (ret)
+                               goto error;
+
+                       if (((buf[3] >> 4) & 0x01) == 1)
+                               *status |= FE_HAS_SIGNAL;
+               }
+       }
+
+       dbg("%s: lock=%02x %02x %02x %02x", __func__,
+               buf[0], buf[1], buf[2], buf[3]);
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+int cxd2820r_init_t(struct dvb_frontend *fe)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+
+       ret = cxd2820r_wr_reg(priv, 0x00085, 0x07);
+       if (ret)
+               goto error;
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+int cxd2820r_sleep_t(struct dvb_frontend *fe)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret, i;
+       struct reg_val_mask tab[] = {
+               { 0x000ff, 0x1f, 0xff },
+               { 0x00085, 0x00, 0xff },
+               { 0x00088, 0x01, 0xff },
+               { 0x00081, 0x00, 0xff },
+               { 0x00080, 0x00, 0xff },
+       };
+
+       dbg("%s", __func__);
+
+       priv->delivery_system = SYS_UNDEFINED;
+
+       for (i = 0; i < ARRAY_SIZE(tab); i++) {
+               ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val,
+                       tab[i].mask);
+               if (ret)
+                       goto error;
+       }
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+int cxd2820r_get_tune_settings_t(struct dvb_frontend *fe,
+       struct dvb_frontend_tune_settings *s)
+{
+       s->min_delay_ms = 500;
+       s->step_size = fe->ops.info.frequency_stepsize * 2;
+       s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
+
+       return 0;
+}
+
diff --git a/drivers/media/dvb/frontends/cxd2820r_t2.c b/drivers/media/dvb/frontends/cxd2820r_t2.c
new file mode 100644 (file)
index 0000000..c47b35c
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ * Sony CXD2820R demodulator driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#include "cxd2820r_priv.h"
+
+int cxd2820r_set_frontend_t2(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *params)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int ret, i;
+       u32 if_khz, if_ctl;
+       u64 num;
+       u8 buf[3], bw_param;
+       u8 bw_params1[][5] = {
+               { 0x1c, 0xb3, 0x33, 0x33, 0x33 }, /* 5 MHz */
+               { 0x17, 0xea, 0xaa, 0xaa, 0xaa }, /* 6 MHz */
+               { 0x14, 0x80, 0x00, 0x00, 0x00 }, /* 7 MHz */
+               { 0x11, 0xf0, 0x00, 0x00, 0x00 }, /* 8 MHz */
+       };
+       struct reg_val_mask tab[] = {
+               { 0x00080, 0x02, 0xff },
+               { 0x00081, 0x20, 0xff },
+               { 0x00085, 0x07, 0xff },
+               { 0x00088, 0x01, 0xff },
+               { 0x02069, 0x01, 0xff },
+
+               { 0x0207f, 0x2a, 0xff },
+               { 0x02082, 0x0a, 0xff },
+               { 0x02083, 0x0a, 0xff },
+               { 0x020cb, priv->cfg.if_agc_polarity << 6, 0x40 },
+               { 0x02070, priv->cfg.ts_mode, 0xff },
+               { 0x020b5, priv->cfg.spec_inv << 4, 0x10 },
+               { 0x02567, 0x07, 0x0f },
+               { 0x02569, 0x03, 0x03 },
+               { 0x02595, 0x1a, 0xff },
+               { 0x02596, 0x50, 0xff },
+               { 0x02a8c, 0x00, 0xff },
+               { 0x02a8d, 0x34, 0xff },
+               { 0x02a45, 0x06, 0x07 },
+               { 0x03f10, 0x0d, 0xff },
+               { 0x03f11, 0x02, 0xff },
+               { 0x03f12, 0x01, 0xff },
+               { 0x03f23, 0x2c, 0xff },
+               { 0x03f51, 0x13, 0xff },
+               { 0x03f52, 0x01, 0xff },
+               { 0x03f53, 0x00, 0xff },
+               { 0x027e6, 0x14, 0xff },
+               { 0x02786, 0x02, 0x07 },
+               { 0x02787, 0x40, 0xe0 },
+               { 0x027ef, 0x10, 0x18 },
+       };
+
+       dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz);
+
+       /* update GPIOs */
+       ret = cxd2820r_gpio(fe);
+       if (ret)
+               goto error;
+
+       /* program tuner */
+       if (fe->ops.tuner_ops.set_params)
+               fe->ops.tuner_ops.set_params(fe, params);
+
+       if (priv->delivery_system != SYS_DVBT2) {
+               for (i = 0; i < ARRAY_SIZE(tab); i++) {
+                       ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,
+                               tab[i].val, tab[i].mask);
+                       if (ret)
+                               goto error;
+               }
+       }
+
+       priv->delivery_system = SYS_DVBT2;
+
+       switch (c->bandwidth_hz) {
+       case 5000000:
+               if_khz = priv->cfg.if_dvbt2_5;
+               i = 0;
+               bw_param = 3;
+               break;
+       case 6000000:
+               if_khz = priv->cfg.if_dvbt2_6;
+               i = 1;
+               bw_param = 2;
+               break;
+       case 7000000:
+               if_khz = priv->cfg.if_dvbt2_7;
+               i = 2;
+               bw_param = 1;
+               break;
+       case 8000000:
+               if_khz = priv->cfg.if_dvbt2_8;
+               i = 3;
+               bw_param = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       num = if_khz;
+       num *= 0x1000000;
+       if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
+       buf[0] = ((if_ctl >> 16) & 0xff);
+       buf[1] = ((if_ctl >>  8) & 0xff);
+       buf[2] = ((if_ctl >>  0) & 0xff);
+
+       ret = cxd2820r_wr_regs(priv, 0x020b6, buf, 3);
+       if (ret)
+               goto error;
+
+       ret = cxd2820r_wr_regs(priv, 0x0209f, bw_params1[i], 5);
+       if (ret)
+               goto error;
+
+       ret = cxd2820r_wr_reg_mask(priv, 0x020d7, bw_param << 6, 0xc0);
+       if (ret)
+               goto error;
+
+       ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08);
+       if (ret)
+               goto error;
+
+       ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01);
+       if (ret)
+               goto error;
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+
+}
+
+int cxd2820r_get_frontend_t2(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *p)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int ret;
+       u8 buf[2];
+
+       ret = cxd2820r_rd_regs(priv, 0x0205c, buf, 2);
+       if (ret)
+               goto error;
+
+       switch ((buf[0] >> 0) & 0x07) {
+       case 0:
+               c->transmission_mode = TRANSMISSION_MODE_2K;
+               break;
+       case 1:
+               c->transmission_mode = TRANSMISSION_MODE_8K;
+               break;
+       case 2:
+               c->transmission_mode = TRANSMISSION_MODE_4K;
+               break;
+       case 3:
+               c->transmission_mode = TRANSMISSION_MODE_1K;
+               break;
+       case 4:
+               c->transmission_mode = TRANSMISSION_MODE_16K;
+               break;
+       case 5:
+               c->transmission_mode = TRANSMISSION_MODE_32K;
+               break;
+       }
+
+       switch ((buf[1] >> 4) & 0x07) {
+       case 0:
+               c->guard_interval = GUARD_INTERVAL_1_32;
+               break;
+       case 1:
+               c->guard_interval = GUARD_INTERVAL_1_16;
+               break;
+       case 2:
+               c->guard_interval = GUARD_INTERVAL_1_8;
+               break;
+       case 3:
+               c->guard_interval = GUARD_INTERVAL_1_4;
+               break;
+       case 4:
+               c->guard_interval = GUARD_INTERVAL_1_128;
+               break;
+       case 5:
+               c->guard_interval = GUARD_INTERVAL_19_128;
+               break;
+       case 6:
+               c->guard_interval = GUARD_INTERVAL_19_256;
+               break;
+       }
+
+       ret = cxd2820r_rd_regs(priv, 0x0225b, buf, 2);
+       if (ret)
+               goto error;
+
+       switch ((buf[0] >> 0) & 0x07) {
+       case 0:
+               c->fec_inner = FEC_1_2;
+               break;
+       case 1:
+               c->fec_inner = FEC_3_5;
+               break;
+       case 2:
+               c->fec_inner = FEC_2_3;
+               break;
+       case 3:
+               c->fec_inner = FEC_3_4;
+               break;
+       case 4:
+               c->fec_inner = FEC_4_5;
+               break;
+       case 5:
+               c->fec_inner = FEC_5_6;
+               break;
+       }
+
+       switch ((buf[1] >> 0) & 0x07) {
+       case 0:
+               c->modulation = QPSK;
+               break;
+       case 1:
+               c->modulation = QAM_16;
+               break;
+       case 2:
+               c->modulation = QAM_64;
+               break;
+       case 3:
+               c->modulation = QAM_256;
+               break;
+       }
+
+       ret = cxd2820r_rd_reg(priv, 0x020b5, &buf[0]);
+       if (ret)
+               goto error;
+
+       switch ((buf[0] >> 4) & 0x01) {
+       case 0:
+               c->inversion = INVERSION_OFF;
+               break;
+       case 1:
+               c->inversion = INVERSION_ON;
+               break;
+       }
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+int cxd2820r_read_status_t2(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+       u8 buf[1];
+       *status = 0;
+
+       ret = cxd2820r_rd_reg(priv, 0x02010 , &buf[0]);
+       if (ret)
+               goto error;
+
+       if ((buf[0] & 0x07) == 6) {
+               if (((buf[0] >> 5) & 0x01) == 1) {
+                       *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+                               FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+               } else {
+                       *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+                               FE_HAS_VITERBI | FE_HAS_SYNC;
+               }
+       }
+
+       dbg("%s: lock=%02x", __func__, buf[0]);
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+int cxd2820r_read_ber_t2(struct dvb_frontend *fe, u32 *ber)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+       u8 buf[4];
+       unsigned int errbits;
+       *ber = 0;
+       /* FIXME: correct calculation */
+
+       ret = cxd2820r_rd_regs(priv, 0x02039, buf, sizeof(buf));
+       if (ret)
+               goto error;
+
+       if ((buf[0] >> 4) & 0x01) {
+               errbits = (buf[0] & 0x0f) << 24 | buf[1] << 16 |
+                       buf[2] << 8 | buf[3];
+
+               if (errbits)
+                       *ber = errbits * 64 / 16588800;
+       }
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+int cxd2820r_read_signal_strength_t2(struct dvb_frontend *fe,
+       u16 *strength)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+       u8 buf[2];
+       u16 tmp;
+
+       ret = cxd2820r_rd_regs(priv, 0x02026, buf, sizeof(buf));
+       if (ret)
+               goto error;
+
+       tmp = (buf[0] & 0x0f) << 8 | buf[1];
+       tmp = ~tmp & 0x0fff;
+
+       /* scale value to 0x0000-0xffff from 0x0000-0x0fff */
+       *strength = tmp * 0xffff / 0x0fff;
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+int cxd2820r_read_snr_t2(struct dvb_frontend *fe, u16 *snr)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret;
+       u8 buf[2];
+       u16 tmp;
+       /* report SNR in dB * 10 */
+
+       ret = cxd2820r_rd_regs(priv, 0x02028, buf, sizeof(buf));
+       if (ret)
+               goto error;
+
+       tmp = (buf[0] & 0x0f) << 8 | buf[1];
+       #define CXD2820R_LOG10_8_24 15151336 /* log10(8) << 24 */
+       if (tmp)
+               *snr = (intlog10(tmp) - CXD2820R_LOG10_8_24) / ((1 << 24)
+                       / 100);
+       else
+               *snr = 0;
+
+       dbg("%s: dBx10=%d val=%04x", __func__, *snr, tmp);
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+int cxd2820r_read_ucblocks_t2(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       *ucblocks = 0;
+       /* no way to read ? */
+       return 0;
+}
+
+int cxd2820r_sleep_t2(struct dvb_frontend *fe)
+{
+       struct cxd2820r_priv *priv = fe->demodulator_priv;
+       int ret, i;
+       struct reg_val_mask tab[] = {
+               { 0x000ff, 0x1f, 0xff },
+               { 0x00085, 0x00, 0xff },
+               { 0x00088, 0x01, 0xff },
+               { 0x02069, 0x00, 0xff },
+               { 0x00081, 0x00, 0xff },
+               { 0x00080, 0x00, 0xff },
+       };
+
+       dbg("%s", __func__);
+
+       for (i = 0; i < ARRAY_SIZE(tab); i++) {
+               ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val,
+                       tab[i].mask);
+               if (ret)
+                       goto error;
+       }
+
+       priv->delivery_system = SYS_UNDEFINED;
+
+       return ret;
+error:
+       dbg("%s: failed:%d", __func__, ret);
+       return ret;
+}
+
+int cxd2820r_get_tune_settings_t2(struct dvb_frontend *fe,
+       struct dvb_frontend_tune_settings *s)
+{
+       s->min_delay_ms = 1500;
+       s->step_size = fe->ops.info.frequency_stepsize * 2;
+       s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
+
+       return 0;
+}
+
index d4e466a..1d47d4d 100644 (file)
@@ -73,27 +73,47 @@ struct dib0070_state {
 
     u8  wbd_gain_current;
        u16 wbd_offset_3_3[2];
+
+       /* for the I2C transfer */
+       struct i2c_msg msg[2];
+       u8 i2c_write_buffer[3];
+       u8 i2c_read_buffer[2];
 };
 
 static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg)
 {
-       u8 b[2];
-       struct i2c_msg msg[2] = {
-               { .addr = state->cfg->i2c_address, .flags = 0,        .buf = &reg, .len = 1 },
-               { .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b,  .len = 2 },
-       };
-       if (i2c_transfer(state->i2c, msg, 2) != 2) {
+       state->i2c_write_buffer[0] = reg;
+
+       memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+       state->msg[0].addr = state->cfg->i2c_address;
+       state->msg[0].flags = 0;
+       state->msg[0].buf = state->i2c_write_buffer;
+       state->msg[0].len = 1;
+       state->msg[1].addr = state->cfg->i2c_address;
+       state->msg[1].flags = I2C_M_RD;
+       state->msg[1].buf = state->i2c_read_buffer;
+       state->msg[1].len = 2;
+
+       if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
                printk(KERN_WARNING "DiB0070 I2C read failed\n");
                return 0;
        }
-       return (b[0] << 8) | b[1];
+       return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
 }
 
 static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
 {
-       u8 b[3] = { reg, val >> 8, val & 0xff };
-       struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 };
-       if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+       state->i2c_write_buffer[0] = reg;
+       state->i2c_write_buffer[1] = val >> 8;
+       state->i2c_write_buffer[2] = val & 0xff;
+
+       memset(state->msg, 0, sizeof(struct i2c_msg));
+       state->msg[0].addr = state->cfg->i2c_address;
+       state->msg[0].flags = 0;
+       state->msg[0].buf = state->i2c_write_buffer;
+       state->msg[0].len = 3;
+
+       if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
                printk(KERN_WARNING "DiB0070 I2C write failed\n");
                return -EREMOTEIO;
        }
index 52ff1a2..c9c935a 100644 (file)
@@ -191,6 +191,11 @@ struct dib0090_state {
        u8 wbd_calibration_gain;
        const struct dib0090_wbd_slope *current_wbd_table;
        u16 wbdmux;
+
+       /* for the I2C transfer */
+       struct i2c_msg msg[2];
+       u8 i2c_write_buffer[3];
+       u8 i2c_read_buffer[2];
 };
 
 struct dib0090_fw_state {
@@ -198,27 +203,48 @@ struct dib0090_fw_state {
        struct dvb_frontend *fe;
        struct dib0090_identity identity;
        const struct dib0090_config *config;
+
+       /* for the I2C transfer */
+       struct i2c_msg msg;
+       u8 i2c_write_buffer[2];
+       u8 i2c_read_buffer[2];
 };
 
 static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
 {
-       u8 b[2];
-       struct i2c_msg msg[2] = {
-               {.addr = state->config->i2c_address, .flags = 0, .buf = &reg, .len = 1},
-               {.addr = state->config->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2},
-       };
-       if (i2c_transfer(state->i2c, msg, 2) != 2) {
+       state->i2c_write_buffer[0] = reg;
+
+       memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+       state->msg[0].addr = state->config->i2c_address;
+       state->msg[0].flags = 0;
+       state->msg[0].buf = state->i2c_write_buffer;
+       state->msg[0].len = 1;
+       state->msg[1].addr = state->config->i2c_address;
+       state->msg[1].flags = I2C_M_RD;
+       state->msg[1].buf = state->i2c_read_buffer;
+       state->msg[1].len = 2;
+
+       if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
                printk(KERN_WARNING "DiB0090 I2C read failed\n");
                return 0;
        }
-       return (b[0] << 8) | b[1];
+
+       return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
 }
 
 static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
 {
-       u8 b[3] = { reg & 0xff, val >> 8, val & 0xff };
-       struct i2c_msg msg = {.addr = state->config->i2c_address, .flags = 0, .buf = b, .len = 3 };
-       if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+       state->i2c_write_buffer[0] = reg & 0xff;
+       state->i2c_write_buffer[1] = val >> 8;
+       state->i2c_write_buffer[2] = val & 0xff;
+
+       memset(state->msg, 0, sizeof(struct i2c_msg));
+       state->msg[0].addr = state->config->i2c_address;
+       state->msg[0].flags = 0;
+       state->msg[0].buf = state->i2c_write_buffer;
+       state->msg[0].len = 3;
+
+       if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
                printk(KERN_WARNING "DiB0090 I2C write failed\n");
                return -EREMOTEIO;
        }
@@ -227,20 +253,31 @@ static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
 
 static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)
 {
-       u8 b[2];
-       struct i2c_msg msg = {.addr = reg, .flags = I2C_M_RD, .buf = b, .len = 2 };
-       if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+       state->i2c_write_buffer[0] = reg;
+
+       memset(&state->msg, 0, sizeof(struct i2c_msg));
+       state->msg.addr = reg;
+       state->msg.flags = I2C_M_RD;
+       state->msg.buf = state->i2c_read_buffer;
+       state->msg.len = 2;
+       if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
                printk(KERN_WARNING "DiB0090 I2C read failed\n");
                return 0;
        }
-       return (b[0] << 8) | b[1];
+       return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
 }
 
 static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)
 {
-       u8 b[2] = { val >> 8, val & 0xff };
-       struct i2c_msg msg = {.addr = reg, .flags = 0, .buf = b, .len = 2 };
-       if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+       state->i2c_write_buffer[0] = val >> 8;
+       state->i2c_write_buffer[1] = val & 0xff;
+
+       memset(&state->msg, 0, sizeof(struct i2c_msg));
+       state->msg.addr = reg;
+       state->msg.flags = 0;
+       state->msg.buf = state->i2c_write_buffer;
+       state->msg.len = 2;
+       if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
                printk(KERN_WARNING "DiB0090 I2C write failed\n");
                return -EREMOTEIO;
        }
index 289a798..79cb1c2 100644 (file)
@@ -50,6 +50,11 @@ struct dib7000m_state {
        u16 revision;
 
        u8 agc_state;
+
+       /* for the I2C transfer */
+       struct i2c_msg msg[2];
+       u8 i2c_write_buffer[4];
+       u8 i2c_read_buffer[2];
 };
 
 enum dib7000m_power_mode {
@@ -64,29 +69,39 @@ enum dib7000m_power_mode {
 
 static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
 {
-       u8 wb[2] = { (reg >> 8) | 0x80, reg & 0xff };
-       u8 rb[2];
-       struct i2c_msg msg[2] = {
-               { .addr = state->i2c_addr >> 1, .flags = 0,        .buf = wb, .len = 2 },
-               { .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 },
-       };
-
-       if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
+       state->i2c_write_buffer[0] = (reg >> 8) | 0x80;
+       state->i2c_write_buffer[1] = reg & 0xff;
+
+       memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+       state->msg[0].addr = state->i2c_addr >> 1;
+       state->msg[0].flags = 0;
+       state->msg[0].buf = state->i2c_write_buffer;
+       state->msg[0].len = 2;
+       state->msg[1].addr = state->i2c_addr >> 1;
+       state->msg[1].flags = I2C_M_RD;
+       state->msg[1].buf = state->i2c_read_buffer;
+       state->msg[1].len = 2;
+
+       if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
                dprintk("i2c read error on %d",reg);
 
-       return (rb[0] << 8) | rb[1];
+       return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
 }
 
 static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
 {
-       u8 b[4] = {
-               (reg >> 8) & 0xff, reg & 0xff,
-               (val >> 8) & 0xff, val & 0xff,
-       };
-       struct i2c_msg msg = {
-               .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
-       };
-       return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+       state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+       state->i2c_write_buffer[1] = reg & 0xff;
+       state->i2c_write_buffer[2] = (val >> 8) & 0xff;
+       state->i2c_write_buffer[3] = val & 0xff;
+
+       memset(&state->msg[0], 0, sizeof(struct i2c_msg));
+       state->msg[0].addr = state->i2c_addr >> 1;
+       state->msg[0].flags = 0;
+       state->msg[0].buf = state->i2c_write_buffer;
+       state->msg[0].len = 4;
+
+       return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
 }
 static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf)
 {
index 900af60..0c9f40c 100644 (file)
@@ -63,6 +63,11 @@ struct dib7000p_state {
 
        u16 tuner_enable;
        struct i2c_adapter dib7090_tuner_adap;
+
+       /* for the I2C transfer */
+       struct i2c_msg msg[2];
+       u8 i2c_write_buffer[4];
+       u8 i2c_read_buffer[2];
 };
 
 enum dib7000p_power_mode {
@@ -76,29 +81,39 @@ static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
 
 static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
 {
-       u8 wb[2] = { reg >> 8, reg & 0xff };
-       u8 rb[2];
-       struct i2c_msg msg[2] = {
-               {.addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2},
-               {.addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2},
-       };
+       state->i2c_write_buffer[0] = reg >> 8;
+       state->i2c_write_buffer[1] = reg & 0xff;
+
+       memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+       state->msg[0].addr = state->i2c_addr >> 1;
+       state->msg[0].flags = 0;
+       state->msg[0].buf = state->i2c_write_buffer;
+       state->msg[0].len = 2;
+       state->msg[1].addr = state->i2c_addr >> 1;
+       state->msg[1].flags = I2C_M_RD;
+       state->msg[1].buf = state->i2c_read_buffer;
+       state->msg[1].len = 2;
 
-       if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
+       if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
                dprintk("i2c read error on %d", reg);
 
-       return (rb[0] << 8) | rb[1];
+       return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
 }
 
 static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
 {
-       u8 b[4] = {
-               (reg >> 8) & 0xff, reg & 0xff,
-               (val >> 8) & 0xff, val & 0xff,
-       };
-       struct i2c_msg msg = {
-               .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
-       };
-       return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+       state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+       state->i2c_write_buffer[1] = reg & 0xff;
+       state->i2c_write_buffer[2] = (val >> 8) & 0xff;
+       state->i2c_write_buffer[3] = val & 0xff;
+
+       memset(&state->msg[0], 0, sizeof(struct i2c_msg));
+       state->msg[0].addr = state->i2c_addr >> 1;
+       state->msg[0].flags = 0;
+       state->msg[0].buf = state->i2c_write_buffer;
+       state->msg[0].len = 4;
+
+       return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
 }
 
 static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
@@ -1550,11 +1565,24 @@ static void dib7000p_release(struct dvb_frontend *demod)
 
 int dib7000pc_detection(struct i2c_adapter *i2c_adap)
 {
-       u8 tx[2], rx[2];
+       u8 *tx, *rx;
        struct i2c_msg msg[2] = {
-               {.addr = 18 >> 1, .flags = 0, .buf = tx, .len = 2},
-               {.addr = 18 >> 1, .flags = I2C_M_RD, .buf = rx, .len = 2},
+               {.addr = 18 >> 1, .flags = 0, .len = 2},
+               {.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2},
        };
+       int ret = 0;
+
+       tx = kzalloc(2*sizeof(u8), GFP_KERNEL);
+       if (!tx)
+               return -ENOMEM;
+       rx = kzalloc(2*sizeof(u8), GFP_KERNEL);
+       if (!rx) {
+               goto rx_memory_error;
+               ret = -ENOMEM;
+       }
+
+       msg[0].buf = tx;
+       msg[1].buf = rx;
 
        tx[0] = 0x03;
        tx[1] = 0x00;
@@ -1574,7 +1602,11 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap)
                }
 
        dprintk("-D-  DiB7000PC not detected");
-       return 0;
+
+       kfree(rx);
+rx_memory_error:
+       kfree(tx);
+       return ret;
 }
 EXPORT_SYMBOL(dib7000pc_detection);
 
index c1c3e26..7d2ea11 100644 (file)
@@ -35,6 +35,8 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
 struct i2c_device {
        struct i2c_adapter *adap;
        u8 addr;
+       u8 *i2c_write_buffer;
+       u8 *i2c_read_buffer;
 };
 
 struct dib8000_state {
@@ -70,6 +72,11 @@ struct dib8000_state {
        u32 status;
 
        struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
+
+       /* for the I2C transfer */
+       struct i2c_msg msg[2];
+       u8 i2c_write_buffer[4];
+       u8 i2c_read_buffer[2];
 };
 
 enum dib8000_power_mode {
@@ -79,22 +86,41 @@ enum dib8000_power_mode {
 
 static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
 {
-       u8 wb[2] = { reg >> 8, reg & 0xff };
-       u8 rb[2];
        struct i2c_msg msg[2] = {
-               {.addr = i2c->addr >> 1,.flags = 0,.buf = wb,.len = 2},
-               {.addr = i2c->addr >> 1,.flags = I2C_M_RD,.buf = rb,.len = 2},
+               {.addr = i2c->addr >> 1, .flags = 0,
+                       .buf = i2c->i2c_write_buffer, .len = 2},
+               {.addr = i2c->addr >> 1, .flags = I2C_M_RD,
+                       .buf = i2c->i2c_read_buffer, .len = 2},
        };
 
+       msg[0].buf[0] = reg >> 8;
+       msg[0].buf[1] = reg & 0xff;
+
        if (i2c_transfer(i2c->adap, msg, 2) != 2)
                dprintk("i2c read error on %d", reg);
 
-       return (rb[0] << 8) | rb[1];
+       return (msg[1].buf[0] << 8) | msg[1].buf[1];
 }
 
 static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
 {
-       return dib8000_i2c_read16(&state->i2c, reg);
+       state->i2c_write_buffer[0] = reg >> 8;
+       state->i2c_write_buffer[1] = reg & 0xff;
+
+       memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+       state->msg[0].addr = state->i2c.addr >> 1;
+       state->msg[0].flags = 0;
+       state->msg[0].buf = state->i2c_write_buffer;
+       state->msg[0].len = 2;
+       state->msg[1].addr = state->i2c.addr >> 1;
+       state->msg[1].flags = I2C_M_RD;
+       state->msg[1].buf = state->i2c_read_buffer;
+       state->msg[1].len = 2;
+
+       if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
+               dprintk("i2c read error on %d", reg);
+
+       return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
 }
 
 static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
@@ -109,19 +135,34 @@ static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
 
 static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
 {
-       u8 b[4] = {
-               (reg >> 8) & 0xff, reg & 0xff,
-               (val >> 8) & 0xff, val & 0xff,
-       };
-       struct i2c_msg msg = {
-               .addr = i2c->addr >> 1,.flags = 0,.buf = b,.len = 4
-       };
-       return i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+       struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0,
+               .buf = i2c->i2c_write_buffer, .len = 4};
+       int ret = 0;
+
+       msg.buf[0] = (reg >> 8) & 0xff;
+       msg.buf[1] = reg & 0xff;
+       msg.buf[2] = (val >> 8) & 0xff;
+       msg.buf[3] = val & 0xff;
+
+       ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+
+       return ret;
 }
 
 static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
 {
-       return dib8000_i2c_write16(&state->i2c, reg, val);
+       state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+       state->i2c_write_buffer[1] = reg & 0xff;
+       state->i2c_write_buffer[2] = (val >> 8) & 0xff;
+       state->i2c_write_buffer[3] = val & 0xff;
+
+       memset(&state->msg[0], 0, sizeof(struct i2c_msg));
+       state->msg[0].addr = state->i2c.addr >> 1;
+       state->msg[0].flags = 0;
+       state->msg[0].buf = state->i2c_write_buffer;
+       state->msg[0].len = 4;
+
+       return i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
 }
 
 static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
@@ -980,30 +1021,31 @@ static void dib8000_update_timf(struct dib8000_state *state)
        dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);
 }
 
+static const u16 adc_target_16dB[11] = {
+       (1 << 13) - 825 - 117,
+       (1 << 13) - 837 - 117,
+       (1 << 13) - 811 - 117,
+       (1 << 13) - 766 - 117,
+       (1 << 13) - 737 - 117,
+       (1 << 13) - 693 - 117,
+       (1 << 13) - 648 - 117,
+       (1 << 13) - 619 - 117,
+       (1 << 13) - 575 - 117,
+       (1 << 13) - 531 - 117,
+       (1 << 13) - 501 - 117
+};
+static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
+
 static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
 {
        u16 mode, max_constellation, seg_diff_mask = 0, nbseg_diff = 0;
        u8 guard, crate, constellation, timeI;
-       u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
        u16 i, coeff[4], P_cfr_left_edge = 0, P_cfr_right_edge = 0, seg_mask13 = 0x1fff;        // All 13 segments enabled
        const s16 *ncoeff = NULL, *ana_fe;
        u16 tmcc_pow = 0;
        u16 coff_pow = 0x2800;
        u16 init_prbs = 0xfff;
        u16 ana_gain = 0;
-       u16 adc_target_16dB[11] = {
-               (1 << 13) - 825 - 117,
-               (1 << 13) - 837 - 117,
-               (1 << 13) - 811 - 117,
-               (1 << 13) - 766 - 117,
-               (1 << 13) - 737 - 117,
-               (1 << 13) - 693 - 117,
-               (1 << 13) - 648 - 117,
-               (1 << 13) - 619 - 117,
-               (1 << 13) - 575 - 117,
-               (1 << 13) - 531 - 117,
-               (1 << 13) - 501 - 117
-       };
 
        if (state->ber_monitored_layer != LAYER_ALL)
                dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer);
@@ -2379,10 +2421,22 @@ EXPORT_SYMBOL(dib8000_get_slave_frontend);
 
 int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr)
 {
-       int k = 0;
+       int k = 0, ret = 0;
        u8 new_addr = 0;
        struct i2c_device client = {.adap = host };
 
+       client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
+       if (!client.i2c_write_buffer) {
+               dprintk("%s: not enough memory", __func__);
+               return -ENOMEM;
+       }
+       client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
+       if (!client.i2c_read_buffer) {
+               dprintk("%s: not enough memory", __func__);
+               ret = -ENOMEM;
+               goto error_memory;
+       }
+
        for (k = no_of_demods - 1; k >= 0; k--) {
                /* designated i2c address */
                new_addr = first_addr + (k << 1);
@@ -2394,7 +2448,8 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau
                        client.addr = default_addr;
                        if (dib8000_identify(&client) == 0) {
                                dprintk("#%d: not identified", k);
-                               return -EINVAL;
+                               ret  = -EINVAL;
+                               goto error;
                        }
                }
 
@@ -2420,7 +2475,12 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau
                dib8000_i2c_write16(&client, 1286, 0);
        }
 
-       return 0;
+error:
+       kfree(client.i2c_read_buffer);
+error_memory:
+       kfree(client.i2c_write_buffer);
+
+       return ret;
 }
 
 EXPORT_SYMBOL(dib8000_i2c_enumeration);
@@ -2519,6 +2579,8 @@ struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, s
        memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
        state->i2c.adap = i2c_adap;
        state->i2c.addr = i2c_addr;
+       state->i2c.i2c_write_buffer = state->i2c_write_buffer;
+       state->i2c.i2c_read_buffer = state->i2c_read_buffer;
        state->gpio_val = cfg->gpio_val;
        state->gpio_dir = cfg->gpio_dir;
 
index 9151876..a085588 100644 (file)
@@ -27,6 +27,8 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
 struct i2c_device {
        struct i2c_adapter *i2c_adap;
        u8 i2c_addr;
+       u8 *i2c_read_buffer;
+       u8 *i2c_write_buffer;
 };
 
 /* lock */
@@ -92,11 +94,16 @@ struct dib9000_state {
 
        struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
        u16 component_bus_speed;
+
+       /* for the I2C transfer */
+       struct i2c_msg msg[2];
+       u8 i2c_write_buffer[255];
+       u8 i2c_read_buffer[255];
 };
 
-u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+static const u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0
+       0, 0, 0, 0, 0, 0, 0, 0
 };
 
 enum dib9000_power_mode {
@@ -217,25 +224,33 @@ static u16 dib9000_read16_attr(struct dib9000_state *state, u16 reg, u8 * b, u32
        u32 chunk_size = 126;
        u32 l;
        int ret;
-       u8 wb[2] = { reg >> 8, reg & 0xff };
-       struct i2c_msg msg[2] = {
-               {.addr = state->i2c.i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2},
-               {.addr = state->i2c.i2c_addr >> 1, .flags = I2C_M_RD, .buf = b, .len = len},
-       };
 
        if (state->platform.risc.fw_is_running && (reg < 1024))
                return dib9000_risc_apb_access_read(state, reg, attribute, NULL, 0, b, len);
 
+       memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+       state->msg[0].addr = state->i2c.i2c_addr >> 1;
+       state->msg[0].flags = 0;
+       state->msg[0].buf = state->i2c_write_buffer;
+       state->msg[0].len = 2;
+       state->msg[1].addr = state->i2c.i2c_addr >> 1;
+       state->msg[1].flags = I2C_M_RD;
+       state->msg[1].buf = b;
+       state->msg[1].len = len;
+
+       state->i2c_write_buffer[0] = reg >> 8;
+       state->i2c_write_buffer[1] = reg & 0xff;
+
        if (attribute & DATA_BUS_ACCESS_MODE_8BIT)
-               wb[0] |= (1 << 5);
+               state->i2c_write_buffer[0] |= (1 << 5);
        if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
-               wb[0] |= (1 << 4);
+               state->i2c_write_buffer[0] |= (1 << 4);
 
        do {
                l = len < chunk_size ? len : chunk_size;
-               msg[1].len = l;
-               msg[1].buf = b;
-               ret = i2c_transfer(state->i2c.i2c_adap, msg, 2) != 2 ? -EREMOTEIO : 0;
+               state->msg[1].len = l;
+               state->msg[1].buf = b;
+               ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 2) != 2 ? -EREMOTEIO : 0;
                if (ret != 0) {
                        dprintk("i2c read error on %d", reg);
                        return -EREMOTEIO;
@@ -253,50 +268,47 @@ static u16 dib9000_read16_attr(struct dib9000_state *state, u16 reg, u8 * b, u32
 
 static u16 dib9000_i2c_read16(struct i2c_device *i2c, u16 reg)
 {
-       u8 b[2];
-       u8 wb[2] = { reg >> 8, reg & 0xff };
        struct i2c_msg msg[2] = {
-               {.addr = i2c->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2},
-               {.addr = i2c->i2c_addr >> 1, .flags = I2C_M_RD, .buf = b, .len = 2},
+               {.addr = i2c->i2c_addr >> 1, .flags = 0,
+                       .buf = i2c->i2c_write_buffer, .len = 2},
+               {.addr = i2c->i2c_addr >> 1, .flags = I2C_M_RD,
+                       .buf = i2c->i2c_read_buffer, .len = 2},
        };
 
+       i2c->i2c_write_buffer[0] = reg >> 8;
+       i2c->i2c_write_buffer[1] = reg & 0xff;
+
        if (i2c_transfer(i2c->i2c_adap, msg, 2) != 2) {
                dprintk("read register %x error", reg);
                return 0;
        }
 
-       return (b[0] << 8) | b[1];
+       return (i2c->i2c_read_buffer[0] << 8) | i2c->i2c_read_buffer[1];
 }
 
 static inline u16 dib9000_read_word(struct dib9000_state *state, u16 reg)
 {
-       u8 b[2];
-       if (dib9000_read16_attr(state, reg, b, 2, 0) != 0)
+       if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2, 0) != 0)
                return 0;
-       return (b[0] << 8 | b[1]);
+       return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
 }
 
 static inline u16 dib9000_read_word_attr(struct dib9000_state *state, u16 reg, u16 attribute)
 {
-       u8 b[2];
-       if (dib9000_read16_attr(state, reg, b, 2, attribute) != 0)
+       if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2,
+                               attribute) != 0)
                return 0;
-       return (b[0] << 8 | b[1]);
+       return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
 }
 
 #define dib9000_read16_noinc_attr(state, reg, b, len, attribute) dib9000_read16_attr(state, reg, b, len, (attribute) | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
 
 static u16 dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 * buf, u32 len, u16 attribute)
 {
-       u8 b[255];
        u32 chunk_size = 126;
        u32 l;
        int ret;
 
-       struct i2c_msg msg = {
-               .addr = state->i2c.i2c_addr >> 1, .flags = 0, .buf = b, .len = len + 2
-       };
-
        if (state->platform.risc.fw_is_running && (reg < 1024)) {
                if (dib9000_risc_apb_access_write
                    (state, reg, DATA_BUS_ACCESS_MODE_16BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | attribute, buf, len) != 0)
@@ -304,20 +316,26 @@ static u16 dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 *
                return 0;
        }
 
-       b[0] = (reg >> 8) & 0xff;
-       b[1] = (reg) & 0xff;
+       memset(&state->msg[0], 0, sizeof(struct i2c_msg));
+       state->msg[0].addr = state->i2c.i2c_addr >> 1;
+       state->msg[0].flags = 0;
+       state->msg[0].buf = state->i2c_write_buffer;
+       state->msg[0].len = len + 2;
+
+       state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+       state->i2c_write_buffer[1] = (reg) & 0xff;
 
        if (attribute & DATA_BUS_ACCESS_MODE_8BIT)
-               b[0] |= (1 << 5);
+               state->i2c_write_buffer[0] |= (1 << 5);
        if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
-               b[0] |= (1 << 4);
+               state->i2c_write_buffer[0] |= (1 << 4);
 
        do {
                l = len < chunk_size ? len : chunk_size;
-               msg.len = l + 2;
-               memcpy(&b[2], buf, l);
+               state->msg[0].len = l + 2;
+               memcpy(&state->i2c_write_buffer[2], buf, l);
 
-               ret = i2c_transfer(state->i2c.i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+               ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
 
                buf += l;
                len -= l;
@@ -331,11 +349,16 @@ static u16 dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 *
 
 static int dib9000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
 {
-       u8 b[4] = { (reg >> 8) & 0xff, reg & 0xff, (val >> 8) & 0xff, val & 0xff };
        struct i2c_msg msg = {
-               .addr = i2c->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
+               .addr = i2c->i2c_addr >> 1, .flags = 0,
+               .buf = i2c->i2c_write_buffer, .len = 4
        };
 
+       i2c->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+       i2c->i2c_write_buffer[1] = reg & 0xff;
+       i2c->i2c_write_buffer[2] = (val >> 8) & 0xff;
+       i2c->i2c_write_buffer[3] = val & 0xff;
+
        return i2c_transfer(i2c->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
 }
 
@@ -1015,8 +1038,8 @@ static int dib9000_fw_memmbx_sync(struct dib9000_state *state, u8 i)
                return 0;
        dib9000_risc_mem_write(state, FE_MM_RW_SYNC, &i);
        do {
-               dib9000_risc_mem_read(state, FE_MM_RW_SYNC, &i, 1);
-       } while (i && index_loop--);
+               dib9000_risc_mem_read(state, FE_MM_RW_SYNC, state->i2c_read_buffer, 1);
+       } while (state->i2c_read_buffer[0] && index_loop--);
 
        if (index_loop > 0)
                return 0;
@@ -1139,7 +1162,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
 
                s8 intlv_native;
        };
-       struct dibDVBTChannel ch;
+       struct dibDVBTChannel *ch;
        int ret = 0;
 
        DibAcquireLock(&state->platform.risc.mem_mbx_lock);
@@ -1148,9 +1171,12 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
                ret = -EIO;
        }
 
-       dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION, (u8 *) &ch, sizeof(struct dibDVBTChannel));
+       dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION,
+                       state->i2c_read_buffer, sizeof(struct dibDVBTChannel));
+       ch = (struct dibDVBTChannel *)state->i2c_read_buffer;
+
 
-       switch (ch.spectrum_inversion & 0x7) {
+       switch (ch->spectrum_inversion & 0x7) {
        case 1:
                state->fe[0]->dtv_property_cache.inversion = INVERSION_ON;
                break;
@@ -1162,7 +1188,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
                state->fe[0]->dtv_property_cache.inversion = INVERSION_AUTO;
                break;
        }
-       switch (ch.nfft) {
+       switch (ch->nfft) {
        case 0:
                state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
                break;
@@ -1177,7 +1203,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
                state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO;
                break;
        }
-       switch (ch.guard) {
+       switch (ch->guard) {
        case 0:
                state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
                break;
@@ -1195,7 +1221,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
                state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO;
                break;
        }
-       switch (ch.constellation) {
+       switch (ch->constellation) {
        case 2:
                state->fe[0]->dtv_property_cache.modulation = QAM_64;
                break;
@@ -1210,7 +1236,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
                state->fe[0]->dtv_property_cache.modulation = QAM_AUTO;
                break;
        }
-       switch (ch.hrch) {
+       switch (ch->hrch) {
        case 0:
                state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_NONE;
                break;
@@ -1222,7 +1248,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
                state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_AUTO;
                break;
        }
-       switch (ch.code_rate_hp) {
+       switch (ch->code_rate_hp) {
        case 1:
                state->fe[0]->dtv_property_cache.code_rate_HP = FEC_1_2;
                break;
@@ -1243,7 +1269,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
                state->fe[0]->dtv_property_cache.code_rate_HP = FEC_AUTO;
                break;
        }
-       switch (ch.code_rate_lp) {
+       switch (ch->code_rate_lp) {
        case 1:
                state->fe[0]->dtv_property_cache.code_rate_LP = FEC_1_2;
                break;
@@ -1439,9 +1465,10 @@ static int dib9000_fw_tune(struct dvb_frontend *fe, struct dvb_frontend_paramete
                break;
        case CT_DEMOD_STEP_1:
                if (search)
-                       dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_SEARCH_STATE, (u8 *) &i, 1);
+                       dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_SEARCH_STATE, state->i2c_read_buffer, 1);
                else
-                       dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_TUNE_STATE, (u8 *) &i, 1);
+                       dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_TUNE_STATE, state->i2c_read_buffer, 1);
+               i = (s8)state->i2c_read_buffer[0];
                switch (i) {    /* something happened */
                case 0:
                        break;
@@ -2038,14 +2065,17 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
 static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber)
 {
        struct dib9000_state *state = fe->demodulator_priv;
-       u16 c[16];
+       u16 *c;
 
        DibAcquireLock(&state->platform.risc.mem_mbx_lock);
        if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
                return -EIO;
-       dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c));
+       dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR,
+                       state->i2c_read_buffer, 16 * 2);
        DibReleaseLock(&state->platform.risc.mem_mbx_lock);
 
+       c = (u16 *)state->i2c_read_buffer;
+
        *ber = c[10] << 16 | c[11];
        return 0;
 }
@@ -2054,7 +2084,7 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
 {
        struct dib9000_state *state = fe->demodulator_priv;
        u8 index_frontend;
-       u16 c[16];
+       u16 *c = (u16 *)state->i2c_read_buffer;
        u16 val;
 
        *strength = 0;
@@ -2069,7 +2099,7 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
        DibAcquireLock(&state->platform.risc.mem_mbx_lock);
        if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
                return -EIO;
-       dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c));
+       dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
        DibReleaseLock(&state->platform.risc.mem_mbx_lock);
 
        val = 65535 - c[4];
@@ -2083,14 +2113,14 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
 static u32 dib9000_get_snr(struct dvb_frontend *fe)
 {
        struct dib9000_state *state = fe->demodulator_priv;
-       u16 c[16];
+       u16 *c = (u16 *)state->i2c_read_buffer;
        u32 n, s, exp;
        u16 val;
 
        DibAcquireLock(&state->platform.risc.mem_mbx_lock);
        if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
                return -EIO;
-       dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c));
+       dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
        DibReleaseLock(&state->platform.risc.mem_mbx_lock);
 
        val = c[7];
@@ -2137,12 +2167,12 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr)
 static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
 {
        struct dib9000_state *state = fe->demodulator_priv;
-       u16 c[16];
+       u16 *c = (u16 *)state->i2c_read_buffer;
 
        DibAcquireLock(&state->platform.risc.mem_mbx_lock);
        if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
                return -EIO;
-       dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c));
+       dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
        DibReleaseLock(&state->platform.risc.mem_mbx_lock);
 
        *unc = c[12];
@@ -2151,10 +2181,22 @@ static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
 
 int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr)
 {
-       int k = 0;
+       int k = 0, ret = 0;
        u8 new_addr = 0;
        struct i2c_device client = {.i2c_adap = i2c };
 
+       client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
+       if (!client.i2c_write_buffer) {
+               dprintk("%s: not enough memory", __func__);
+               return -ENOMEM;
+       }
+       client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
+       if (!client.i2c_read_buffer) {
+               dprintk("%s: not enough memory", __func__);
+               ret = -ENOMEM;
+               goto error_memory;
+       }
+
        client.i2c_addr = default_addr + 16;
        dib9000_i2c_write16(&client, 1796, 0x0);
 
@@ -2178,7 +2220,8 @@ int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defaul
                        client.i2c_addr = default_addr;
                        if (dib9000_identify(&client) == 0) {
                                dprintk("DiB9000 #%d: not identified", k);
-                               return -EIO;
+                               ret = -EIO;
+                               goto error;
                        }
                }
 
@@ -2196,7 +2239,12 @@ int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defaul
                dib9000_i2c_write16(&client, 1795, 0);
        }
 
-       return 0;
+error:
+       kfree(client.i2c_read_buffer);
+error_memory:
+       kfree(client.i2c_write_buffer);
+
+       return ret;
 }
 EXPORT_SYMBOL(dib9000_i2c_enumeration);
 
@@ -2255,12 +2303,16 @@ struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, c
        if (st == NULL)
                return NULL;
        fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
-       if (fe == NULL)
+       if (fe == NULL) {
+               kfree(st);
                return NULL;
+       }
 
        memcpy(&st->chip.d9.cfg, cfg, sizeof(struct dib9000_config));
        st->i2c.i2c_adap = i2c_adap;
        st->i2c.i2c_addr = i2c_addr;
+       st->i2c.i2c_write_buffer = st->i2c_write_buffer;
+       st->i2c.i2c_read_buffer = st->i2c_read_buffer;
 
        st->gpio_dir = DIB9000_GPIO_DEFAULT_DIRECTIONS;
        st->gpio_val = DIB9000_GPIO_DEFAULT_VALUES;
index f6938f9..dc5d17a 100644 (file)
@@ -10,30 +10,39 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
 
 static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val)
 {
-       u8 b[4] = {
-               (reg >> 8) & 0xff, reg & 0xff,
-               (val >> 8) & 0xff, val & 0xff,
-       };
-       struct i2c_msg msg = {
-               .addr = mst->i2c_addr,.flags = 0,.buf = b,.len = 4
-       };
-
-       return i2c_transfer(mst->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+       mst->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+       mst->i2c_write_buffer[1] = reg & 0xff;
+       mst->i2c_write_buffer[2] = (val >> 8) & 0xff;
+       mst->i2c_write_buffer[3] = val & 0xff;
+
+       memset(mst->msg, 0, sizeof(struct i2c_msg));
+       mst->msg[0].addr = mst->i2c_addr;
+       mst->msg[0].flags = 0;
+       mst->msg[0].buf = mst->i2c_write_buffer;
+       mst->msg[0].len = 4;
+
+       return i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0;
 }
 
 static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg)
 {
-       u8 wb[2] = { reg >> 8, reg & 0xff };
-       u8 rb[2];
-       struct i2c_msg msg[2] = {
-               {.addr = mst->i2c_addr, .flags = 0, .buf = wb, .len = 2},
-               {.addr = mst->i2c_addr, .flags = I2C_M_RD, .buf = rb, .len = 2},
-       };
-
-       if (i2c_transfer(mst->i2c_adap, msg, 2) != 2)
+       mst->i2c_write_buffer[0] = reg >> 8;
+       mst->i2c_write_buffer[1] = reg & 0xff;
+
+       memset(mst->msg, 0, 2 * sizeof(struct i2c_msg));
+       mst->msg[0].addr = mst->i2c_addr;
+       mst->msg[0].flags = 0;
+       mst->msg[0].buf = mst->i2c_write_buffer;
+       mst->msg[0].len = 2;
+       mst->msg[1].addr = mst->i2c_addr;
+       mst->msg[1].flags = I2C_M_RD;
+       mst->msg[1].buf = mst->i2c_read_buffer;
+       mst->msg[1].len = 2;
+
+       if (i2c_transfer(mst->i2c_adap, mst->msg, 2) != 2)
                dprintk("i2c read error on %d", reg);
 
-       return (rb[0] << 8) | rb[1];
+       return (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1];
 }
 
 static int dibx000_is_i2c_done(struct dibx000_i2c_master *mst)
@@ -248,26 +257,32 @@ static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap,
                                        struct i2c_msg msg[], int num)
 {
        struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
-       struct i2c_msg m[2 + num];
-       u8 tx_open[4], tx_close[4];
 
-       memset(m, 0, sizeof(struct i2c_msg) * (2 + num));
+       if (num > 32) {
+               dprintk("%s: too much I2C message to be transmitted (%i).\
+                               Maximum is 32", __func__, num);
+               return -ENOMEM;
+       }
+
+       memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
 
        dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7);
 
-       dibx000_i2c_gate_ctrl(mst, tx_open, msg[0].addr, 1);
-       m[0].addr = mst->i2c_addr;
-       m[0].buf = tx_open;
-       m[0].len = 4;
+       /* open the gate */
+       dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
+       mst->msg[0].addr = mst->i2c_addr;
+       mst->msg[0].buf = &mst->i2c_write_buffer[0];
+       mst->msg[0].len = 4;
 
-       memcpy(&m[1], msg, sizeof(struct i2c_msg) * num);
+       memcpy(&mst->msg[1], msg, sizeof(struct i2c_msg) * num);
 
-       dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0);
-       m[num + 1].addr = mst->i2c_addr;
-       m[num + 1].buf = tx_close;
-       m[num + 1].len = 4;
+       /* close the gate */
+       dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[4], 0, 0);
+       mst->msg[num + 1].addr = mst->i2c_addr;
+       mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
+       mst->msg[num + 1].len = 4;
 
-       return i2c_transfer(mst->i2c_adap, m, 2 + num) == 2 + num ? num : -EIO;
+       return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO;
 }
 
 static struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = {
@@ -279,26 +294,32 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap,
                                        struct i2c_msg msg[], int num)
 {
        struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
-       struct i2c_msg m[2 + num];
-       u8 tx_open[4], tx_close[4];
 
-       memset(m, 0, sizeof(struct i2c_msg) * (2 + num));
+       if (num > 32) {
+               dprintk("%s: too much I2C message to be transmitted (%i).\
+                               Maximum is 32", __func__, num);
+               return -ENOMEM;
+       }
+
+       memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
 
        dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER);
 
-       dibx000_i2c_gate_ctrl(mst, tx_open, msg[0].addr, 1);
-       m[0].addr = mst->i2c_addr;
-       m[0].buf = tx_open;
-       m[0].len = 4;
+       /* open the gate */
+       dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
+       mst->msg[0].addr = mst->i2c_addr;
+       mst->msg[0].buf = &mst->i2c_write_buffer[0];
+       mst->msg[0].len = 4;
 
-       memcpy(&m[1], msg, sizeof(struct i2c_msg) * num);
+       memcpy(&mst->msg[1], msg, sizeof(struct i2c_msg) * num);
 
-       dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0);
-       m[num + 1].addr = mst->i2c_addr;
-       m[num + 1].buf = tx_close;
-       m[num + 1].len = 4;
+       /* close the gate */
+       dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[4], 0, 0);
+       mst->msg[num + 1].addr = mst->i2c_addr;
+       mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
+       mst->msg[num + 1].len = 4;
 
-       return i2c_transfer(mst->i2c_adap, m, 2 + num) == 2 + num ? num : -EIO;
+       return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO;
 }
 
 static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = {
index 977d343..f031165 100644 (file)
@@ -28,6 +28,11 @@ struct dibx000_i2c_master {
        u8 i2c_addr;
 
        u16 base_reg;
+
+       /* for the I2C transfer */
+       struct i2c_msg msg[34];
+       u8 i2c_write_buffer[8];
+       u8 i2c_read_buffer[2];
 };
 
 extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst,
diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c
deleted file mode 100644 (file)
index 536f02b..0000000
+++ /dev/null
@@ -1,1511 +0,0 @@
-/*
- * Driver for Micronas drx397xD demodulator
- *
- * Copyright (C) 2007 Henk Vergonet <Henk.Vergonet@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; 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, see <http://www.gnu.org/licenses/>.
- */
-
-#define DEBUG                  /* uncomment if you want debugging output */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/firmware.h>
-#include <linux/slab.h>
-#include <asm/div64.h>
-
-#include "dvb_frontend.h"
-#include "drx397xD.h"
-
-static const char mod_name[] = "drx397xD";
-
-#define MAX_CLOCK_DRIFT                200     /* maximal 200 PPM allowed */
-
-#define F_SET_0D0h     1
-#define F_SET_0D4h     2
-
-enum fw_ix {
-#define _FW_ENTRY(a, b, c)     b
-#include "drx397xD_fw.h"
-};
-
-/* chip specifics */
-struct drx397xD_state {
-       struct i2c_adapter *i2c;
-       struct dvb_frontend frontend;
-       struct drx397xD_config config;
-       enum fw_ix chip_rev;
-       int flags;
-       u32 bandwidth_parm;     /* internal bandwidth conversions */
-       u32 f_osc;              /* w90: actual osc frequency [Hz] */
-};
-
-/* Firmware */
-static const char *blob_name[] = {
-#define _BLOB_ENTRY(a, b)              a
-#include "drx397xD_fw.h"
-};
-
-enum blob_ix {
-#define _BLOB_ENTRY(a, b)              b
-#include "drx397xD_fw.h"
-};
-
-static struct {
-       const char *name;
-       const struct firmware *file;
-       rwlock_t lock;
-       int refcnt;
-       const u8 *data[ARRAY_SIZE(blob_name)];
-} fw[] = {
-#define _FW_ENTRY(a, b, c)     {                                       \
-                       .name   = a,                                    \
-                       .file   = NULL,                                 \
-                       .lock   = __RW_LOCK_UNLOCKED(fw[c].lock),       \
-                       .refcnt = 0,                                    \
-                       .data   = { }           }
-#include "drx397xD_fw.h"
-};
-
-/* use only with writer lock acquired */
-static void _drx_release_fw(struct drx397xD_state *s, enum fw_ix ix)
-{
-       memset(&fw[ix].data[0], 0, sizeof(fw[0].data));
-       if (fw[ix].file)
-               release_firmware(fw[ix].file);
-}
-
-static void drx_release_fw(struct drx397xD_state *s)
-{
-       enum fw_ix ix = s->chip_rev;
-
-       pr_debug("%s\n", __func__);
-
-       write_lock(&fw[ix].lock);
-       if (fw[ix].refcnt) {
-               fw[ix].refcnt--;
-               if (fw[ix].refcnt == 0)
-                       _drx_release_fw(s, ix);
-       }
-       write_unlock(&fw[ix].lock);
-}
-
-static int drx_load_fw(struct drx397xD_state *s, enum fw_ix ix)
-{
-       const u8 *data;
-       size_t size, len;
-       int i = 0, j, rc = -EINVAL;
-
-       pr_debug("%s\n", __func__);
-
-       if (ix < 0 || ix >= ARRAY_SIZE(fw))
-               return -EINVAL;
-       s->chip_rev = ix;
-
-       write_lock(&fw[ix].lock);
-       if (fw[ix].file) {
-               rc = 0;
-               goto exit_ok;
-       }
-       memset(&fw[ix].data[0], 0, sizeof(fw[0].data));
-
-       rc = request_firmware(&fw[ix].file, fw[ix].name, s->i2c->dev.parent);
-       if (rc != 0) {
-               printk(KERN_ERR "%s: Firmware \"%s\" not available\n",
-                      mod_name, fw[ix].name);
-               goto exit_err;
-       }
-
-       if (!fw[ix].file->data || fw[ix].file->size < 10)
-               goto exit_corrupt;
-
-       data = fw[ix].file->data;
-       size = fw[ix].file->size;
-
-       if (data[i++] != 2)     /* check firmware version */
-               goto exit_corrupt;
-
-       do {
-               switch (data[i++]) {
-               case 0x00:      /* bytecode */
-                       if (i >= size)
-                               break;
-                       i += data[i];
-               case 0x01:      /* reset */
-               case 0x02:      /* sleep */
-                       i++;
-                       break;
-               case 0xfe:      /* name */
-                       len = strnlen(&data[i], size - i);
-                       if (i + len + 1 >= size)
-                               goto exit_corrupt;
-                       if (data[i + len + 1] != 0)
-                               goto exit_corrupt;
-                       for (j = 0; j < ARRAY_SIZE(blob_name); j++) {
-                               if (strcmp(blob_name[j], &data[i]) == 0) {
-                                       fw[ix].data[j] = &data[i + len + 1];
-                                       pr_debug("Loading %s\n", blob_name[j]);
-                               }
-                       }
-                       i += len + 1;
-                       break;
-               case 0xff:      /* file terminator */
-                       if (i == size) {
-                               rc = 0;
-                               goto exit_ok;
-                       }
-               default:
-                       goto exit_corrupt;
-               }
-       } while (i < size);
-
-exit_corrupt:
-       printk(KERN_ERR "%s: Firmware is corrupt\n", mod_name);
-exit_err:
-       _drx_release_fw(s, ix);
-       fw[ix].refcnt--;
-exit_ok:
-       fw[ix].refcnt++;
-       write_unlock(&fw[ix].lock);
-
-       return rc;
-}
-
-/* i2c bus IO */
-static int write_fw(struct drx397xD_state *s, enum blob_ix ix)
-{
-       const u8 *data;
-       int len, rc = 0, i = 0;
-       struct i2c_msg msg = {
-               .addr = s->config.demod_address,
-               .flags = 0
-       };
-
-       if (ix < 0 || ix >= ARRAY_SIZE(blob_name)) {
-               pr_debug("%s drx_fw_ix_t out of range\n", __func__);
-               return -EINVAL;
-       }
-       pr_debug("%s %s\n", __func__, blob_name[ix]);
-
-       read_lock(&fw[s->chip_rev].lock);
-       data = fw[s->chip_rev].data[ix];
-       if (!data) {
-               rc = -EINVAL;
-               goto exit_rc;
-       }
-
-       for (;;) {
-               switch (data[i++]) {
-               case 0: /* bytecode */
-                       len = data[i++];
-                       msg.len = len;
-                       msg.buf = (__u8 *) &data[i];
-                       if (i2c_transfer(s->i2c, &msg, 1) != 1) {
-                               rc = -EIO;
-                               goto exit_rc;
-                       }
-                       i += len;
-                       break;
-               case 1: /* reset */
-               case 2: /* sleep */
-                       i++;
-                       break;
-               default:
-                       goto exit_rc;
-               }
-       }
-exit_rc:
-       read_unlock(&fw[s->chip_rev].lock);
-
-       return rc;
-}
-
-/* Function is not endian safe, use the RD16 wrapper below */
-static int _read16(struct drx397xD_state *s, __le32 i2c_adr)
-{
-       int rc;
-       u8 a[4];
-       __le16 v;
-       struct i2c_msg msg[2] = {
-               {
-                       .addr = s->config.demod_address,
-                       .flags = 0,
-                       .buf = a,
-                       .len = sizeof(a)
-               }, {
-                       .addr = s->config.demod_address,
-                       .flags = I2C_M_RD,
-                       .buf = (u8 *)&v,
-                       .len = sizeof(v)
-               }
-       };
-
-       *(__le32 *) a = i2c_adr;
-
-       rc = i2c_transfer(s->i2c, msg, 2);
-       if (rc != 2)
-               return -EIO;
-
-       return le16_to_cpu(v);
-}
-
-/* Function is not endian safe, use the WR16.. wrappers below */
-static int _write16(struct drx397xD_state *s, __le32 i2c_adr, __le16 val)
-{
-       u8 a[6];
-       int rc;
-       struct i2c_msg msg = {
-               .addr = s->config.demod_address,
-               .flags = 0,
-               .buf = a,
-               .len = sizeof(a)
-       };
-
-       *(__le32 *)a = i2c_adr;
-       *(__le16 *)&a[4] = val;
-
-       rc = i2c_transfer(s->i2c, &msg, 1);
-       if (rc != 1)
-               return -EIO;
-
-       return 0;
-}
-
-#define WR16(ss, adr, val) \
-               _write16(ss, I2C_ADR_C0(adr), cpu_to_le16(val))
-#define WR16_E0(ss, adr, val) \
-               _write16(ss, I2C_ADR_E0(adr), cpu_to_le16(val))
-#define RD16(ss, adr) \
-               _read16(ss, I2C_ADR_C0(adr))
-
-#define EXIT_RC(cmd)   \
-       if ((rc = (cmd)) < 0)   \
-               goto exit_rc
-
-/* Tuner callback */
-static int PLL_Set(struct drx397xD_state *s,
-                  struct dvb_frontend_parameters *fep, int *df_tuner)
-{
-       struct dvb_frontend *fe = &s->frontend;
-       u32 f_tuner, f = fep->frequency;
-       int rc;
-
-       pr_debug("%s\n", __func__);
-
-       if ((f > s->frontend.ops.tuner_ops.info.frequency_max) ||
-           (f < s->frontend.ops.tuner_ops.info.frequency_min))
-               return -EINVAL;
-
-       *df_tuner = 0;
-       if (!s->frontend.ops.tuner_ops.set_params ||
-           !s->frontend.ops.tuner_ops.get_frequency)
-               return -ENOSYS;
-
-       rc = s->frontend.ops.tuner_ops.set_params(fe, fep);
-       if (rc < 0)
-               return rc;
-
-       rc = s->frontend.ops.tuner_ops.get_frequency(fe, &f_tuner);
-       if (rc < 0)
-               return rc;
-
-       *df_tuner = f_tuner - f;
-       pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __func__, f,
-                f_tuner);
-
-       return 0;
-}
-
-/* Demodulator helper functions */
-static int SC_WaitForReady(struct drx397xD_state *s)
-{
-       int cnt = 1000;
-       int rc;
-
-       pr_debug("%s\n", __func__);
-
-       while (cnt--) {
-               rc = RD16(s, 0x820043);
-               if (rc == 0)
-                       return 0;
-       }
-
-       return -1;
-}
-
-static int SC_SendCommand(struct drx397xD_state *s, int cmd)
-{
-       int rc;
-
-       pr_debug("%s\n", __func__);
-
-       WR16(s, 0x820043, cmd);
-       SC_WaitForReady(s);
-       rc = RD16(s, 0x820042);
-       if ((rc & 0xffff) == 0xffff)
-               return -1;
-
-       return 0;
-}
-
-static int HI_Command(struct drx397xD_state *s, u16 cmd)
-{
-       int rc, cnt = 1000;
-
-       pr_debug("%s\n", __func__);
-
-       rc = WR16(s, 0x420032, cmd);
-       if (rc < 0)
-               return rc;
-
-       do {
-               rc = RD16(s, 0x420032);
-               if (rc == 0) {
-                       rc = RD16(s, 0x420031);
-                       return rc;
-               }
-               if (rc < 0)
-                       return rc;
-       } while (--cnt);
-
-       return rc;
-}
-
-static int HI_CfgCommand(struct drx397xD_state *s)
-{
-
-       pr_debug("%s\n", __func__);
-
-       WR16(s, 0x420033, 0x3973);
-       WR16(s, 0x420034, s->config.w50);       /* code 4, log 4 */
-       WR16(s, 0x420035, s->config.w52);       /* code 15,  log 9 */
-       WR16(s, 0x420036, s->config.demod_address << 1);
-       WR16(s, 0x420037, s->config.w56);       /* code (set_i2c ??  initX 1 ), log 1 */
-       /* WR16(s, 0x420033, 0x3973); */
-       if ((s->config.w56 & 8) == 0)
-               return HI_Command(s, 3);
-
-       return WR16(s, 0x420032, 0x3);
-}
-
-static const u8 fastIncrDecLUT_15273[] = {
-       0x0e, 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x12, 0x13, 0x14,
-       0x15, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x1c, 0x1d, 0x1f
-};
-
-static const u8 slowIncrDecLUT_15272[] = {
-       3, 4, 4, 5, 6
-};
-
-static int SetCfgIfAgc(struct drx397xD_state *s, struct drx397xD_CfgIfAgc *agc)
-{
-       u16 w06 = agc->w06;
-       u16 w08 = agc->w08;
-       u16 w0A = agc->w0A;
-       u16 w0C = agc->w0C;
-       int quot, rem, i, rc = -EINVAL;
-
-       pr_debug("%s\n", __func__);
-
-       if (agc->w04 > 0x3ff)
-               goto exit_rc;
-
-       if (agc->d00 == 1) {
-               EXIT_RC(RD16(s, 0x0c20010));
-               rc &= ~0x10;
-               EXIT_RC(WR16(s, 0x0c20010, rc));
-               return WR16(s, 0x0c20030, agc->w04 & 0x7ff);
-       }
-
-       if (agc->d00 != 0)
-               goto exit_rc;
-       if (w0A < w08)
-               goto exit_rc;
-       if (w0A > 0x3ff)
-               goto exit_rc;
-       if (w0C > 0x3ff)
-               goto exit_rc;
-       if (w06 > 0x3ff)
-               goto exit_rc;
-
-       EXIT_RC(RD16(s, 0x0c20010));
-       rc |= 0x10;
-       EXIT_RC(WR16(s, 0x0c20010, rc));
-
-       EXIT_RC(WR16(s, 0x0c20025, (w06 >> 1) & 0x1ff));
-       EXIT_RC(WR16(s, 0x0c20031, (w0A - w08) >> 1));
-       EXIT_RC(WR16(s, 0x0c20032, ((w0A + w08) >> 1) - 0x1ff));
-
-       quot = w0C / 113;
-       rem = w0C % 113;
-       if (quot <= 8) {
-               quot = 8 - quot;
-       } else {
-               quot = 0;
-               rem += 113;
-       }
-
-       EXIT_RC(WR16(s, 0x0c20024, quot));
-
-       i = fastIncrDecLUT_15273[rem / 8];
-       EXIT_RC(WR16(s, 0x0c2002d, i));
-       EXIT_RC(WR16(s, 0x0c2002e, i));
-
-       i = slowIncrDecLUT_15272[rem / 28];
-       EXIT_RC(WR16(s, 0x0c2002b, i));
-       rc = WR16(s, 0x0c2002c, i);
-exit_rc:
-       return rc;
-}
-
-static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc)
-{
-       u16 w04 = agc->w04;
-       u16 w06 = agc->w06;
-       int rc = -1;
-
-       pr_debug("%s %d 0x%x 0x%x\n", __func__, agc->d00, w04, w06);
-
-       if (w04 > 0x3ff)
-               goto exit_rc;
-
-       switch (agc->d00) {
-       case 1:
-               if (w04 == 0x3ff)
-                       w04 = 0x400;
-
-               EXIT_RC(WR16(s, 0x0c20036, w04));
-               s->config.w9C &= ~2;
-               EXIT_RC(WR16(s, 0x0c20015, s->config.w9C));
-               EXIT_RC(RD16(s, 0x0c20010));
-               rc &= 0xbfdf;
-               EXIT_RC(WR16(s, 0x0c20010, rc));
-               EXIT_RC(RD16(s, 0x0c20013));
-               rc &= ~2;
-               break;
-       case 0:
-               /* loc_8000659 */
-               s->config.w9C &= ~2;
-               EXIT_RC(WR16(s, 0x0c20015, s->config.w9C));
-               EXIT_RC(RD16(s, 0x0c20010));
-               rc &= 0xbfdf;
-               rc |= 0x4000;
-               EXIT_RC(WR16(s, 0x0c20010, rc));
-               EXIT_RC(WR16(s, 0x0c20051, (w06 >> 4) & 0x3f));
-               EXIT_RC(RD16(s, 0x0c20013));
-               rc &= ~2;
-               break;
-       default:
-               s->config.w9C |= 2;
-               EXIT_RC(WR16(s, 0x0c20015, s->config.w9C));
-               EXIT_RC(RD16(s, 0x0c20010));
-               rc &= 0xbfdf;
-               EXIT_RC(WR16(s, 0x0c20010, rc));
-
-               EXIT_RC(WR16(s, 0x0c20036, 0));
-
-               EXIT_RC(RD16(s, 0x0c20013));
-               rc |= 2;
-       }
-       rc = WR16(s, 0x0c20013, rc);
-
-exit_rc:
-       return rc;
-}
-
-static int GetLockStatus(struct drx397xD_state *s, int *lockstat)
-{
-       int rc;
-
-       *lockstat = 0;
-
-       rc = RD16(s, 0x082004b);
-       if (rc < 0)
-               return rc;
-
-       if (s->config.d60 != 2)
-               return 0;
-
-       if ((rc & 7) == 7)
-               *lockstat |= 1;
-       if ((rc & 3) == 3)
-               *lockstat |= 2;
-       if (rc & 1)
-               *lockstat |= 4;
-       return 0;
-}
-
-static int CorrectSysClockDeviation(struct drx397xD_state *s)
-{
-       int rc = -EINVAL;
-       int lockstat;
-       u32 clk, clk_limit;
-
-       pr_debug("%s\n", __func__);
-
-       if (s->config.d5C == 0) {
-               EXIT_RC(WR16(s, 0x08200e8, 0x010));
-               EXIT_RC(WR16(s, 0x08200e9, 0x113));
-               s->config.d5C = 1;
-               return rc;
-       }
-       if (s->config.d5C != 1)
-               goto exit_rc;
-
-       rc = RD16(s, 0x0820048);
-
-       rc = GetLockStatus(s, &lockstat);
-       if (rc < 0)
-               goto exit_rc;
-       if ((lockstat & 1) == 0)
-               goto exit_rc;
-
-       EXIT_RC(WR16(s, 0x0420033, 0x200));
-       EXIT_RC(WR16(s, 0x0420034, 0xc5));
-       EXIT_RC(WR16(s, 0x0420035, 0x10));
-       EXIT_RC(WR16(s, 0x0420036, 0x1));
-       EXIT_RC(WR16(s, 0x0420037, 0xa));
-       EXIT_RC(HI_Command(s, 6));
-       EXIT_RC(RD16(s, 0x0420040));
-       clk = rc;
-       EXIT_RC(RD16(s, 0x0420041));
-       clk |= rc << 16;
-
-       if (clk <= 0x26ffff)
-               goto exit_rc;
-       if (clk > 0x610000)
-               goto exit_rc;
-
-       if (!s->bandwidth_parm)
-               return -EINVAL;
-
-       /* round & convert to Hz */
-       clk = ((u64) (clk + 0x800000) * s->bandwidth_parm + (1 << 20)) >> 21;
-       clk_limit = s->config.f_osc * MAX_CLOCK_DRIFT / 1000;
-
-       if (clk - s->config.f_osc * 1000 + clk_limit <= 2 * clk_limit) {
-               s->f_osc = clk;
-               pr_debug("%s: osc %d %d [Hz]\n", __func__,
-                        s->config.f_osc * 1000, clk - s->config.f_osc * 1000);
-       }
-       rc = WR16(s, 0x08200e8, 0);
-
-exit_rc:
-       return rc;
-}
-
-static int ConfigureMPEGOutput(struct drx397xD_state *s, int type)
-{
-       int rc, si, bp;
-
-       pr_debug("%s\n", __func__);
-
-       si = s->config.wA0;
-       if (s->config.w98 == 0) {
-               si |= 1;
-               bp = 0;
-       } else {
-               si &= ~1;
-               bp = 0x200;
-       }
-       if (s->config.w9A == 0)
-               si |= 0x80;
-       else
-               si &= ~0x80;
-
-       EXIT_RC(WR16(s, 0x2150045, 0));
-       EXIT_RC(WR16(s, 0x2150010, si));
-       EXIT_RC(WR16(s, 0x2150011, bp));
-       rc = WR16(s, 0x2150012, (type == 0 ? 0xfff : 0));
-
-exit_rc:
-       return rc;
-}
-
-static int drx_tune(struct drx397xD_state *s,
-                   struct dvb_frontend_parameters *fep)
-{
-       u16 v22 = 0;
-       u16 v1C = 0;
-       u16 v1A = 0;
-       u16 v18 = 0;
-       u32 edi = 0, ebx = 0, ebp = 0, edx = 0;
-       u16 v20 = 0, v1E = 0, v16 = 0, v14 = 0, v12 = 0, v10 = 0, v0E = 0;
-
-       int rc, df_tuner = 0;
-       int a, b, c, d;
-       pr_debug("%s %d\n", __func__, s->config.d60);
-
-       if (s->config.d60 != 2)
-               goto set_tuner;
-       rc = CorrectSysClockDeviation(s);
-       if (rc < 0)
-               goto set_tuner;
-
-       s->config.d60 = 1;
-       rc = ConfigureMPEGOutput(s, 0);
-       if (rc < 0)
-               goto set_tuner;
-set_tuner:
-
-       rc = PLL_Set(s, fep, &df_tuner);
-       if (rc < 0) {
-               printk(KERN_ERR "Error in pll_set\n");
-               goto exit_rc;
-       }
-       msleep(200);
-
-       a = rc = RD16(s, 0x2150016);
-       if (rc < 0)
-               goto exit_rc;
-       b = rc = RD16(s, 0x2150010);
-       if (rc < 0)
-               goto exit_rc;
-       c = rc = RD16(s, 0x2150034);
-       if (rc < 0)
-               goto exit_rc;
-       d = rc = RD16(s, 0x2150035);
-       if (rc < 0)
-               goto exit_rc;
-       rc = WR16(s, 0x2150014, c);
-       rc = WR16(s, 0x2150015, d);
-       rc = WR16(s, 0x2150010, 0);
-       rc = WR16(s, 0x2150000, 2);
-       rc = WR16(s, 0x2150036, 0x0fff);
-       rc = WR16(s, 0x2150016, a);
-
-       rc = WR16(s, 0x2150010, 2);
-       rc = WR16(s, 0x2150007, 0);
-       rc = WR16(s, 0x2150000, 1);
-       rc = WR16(s, 0x2110000, 0);
-       rc = WR16(s, 0x0800000, 0);
-       rc = WR16(s, 0x2800000, 0);
-       rc = WR16(s, 0x2110010, 0x664);
-
-       rc = write_fw(s, DRXD_ResetECRAM);
-       rc = WR16(s, 0x2110000, 1);
-
-       rc = write_fw(s, DRXD_InitSC);
-       if (rc < 0)
-               goto exit_rc;
-
-       rc = SetCfgIfAgc(s, &s->config.ifagc);
-       if (rc < 0)
-               goto exit_rc;
-
-       rc = SetCfgRfAgc(s, &s->config.rfagc);
-       if (rc < 0)
-               goto exit_rc;
-
-       if (fep->u.ofdm.transmission_mode != TRANSMISSION_MODE_2K)
-               v22 = 1;
-       switch (fep->u.ofdm.transmission_mode) {
-       case TRANSMISSION_MODE_8K:
-               edi = 1;
-               if (s->chip_rev == DRXD_FW_B1)
-                       break;
-
-               rc = WR16(s, 0x2010010, 0);
-               if (rc < 0)
-                       break;
-               v1C = 0x63;
-               v1A = 0x53;
-               v18 = 0x43;
-               break;
-       default:
-               edi = 0;
-               if (s->chip_rev == DRXD_FW_B1)
-                       break;
-
-               rc = WR16(s, 0x2010010, 1);
-               if (rc < 0)
-                       break;
-
-               v1C = 0x61;
-               v1A = 0x47;
-               v18 = 0x41;
-       }
-
-       switch (fep->u.ofdm.guard_interval) {
-       case GUARD_INTERVAL_1_4:
-               edi |= 0x0c;
-               break;
-       case GUARD_INTERVAL_1_8:
-               edi |= 0x08;
-               break;
-       case GUARD_INTERVAL_1_16:
-               edi |= 0x04;
-               break;
-       case GUARD_INTERVAL_1_32:
-               break;
-       default:
-               v22 |= 2;
-       }
-
-       ebx = 0;
-       ebp = 0;
-       v20 = 0;
-       v1E = 0;
-       v16 = 0;
-       v14 = 0;
-       v12 = 0;
-       v10 = 0;
-       v0E = 0;
-
-       switch (fep->u.ofdm.hierarchy_information) {
-       case HIERARCHY_1:
-               edi |= 0x40;
-               if (s->chip_rev == DRXD_FW_B1)
-                       break;
-               rc = WR16(s, 0x1c10047, 1);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x2010012, 1);
-               if (rc < 0)
-                       goto exit_rc;
-               ebx = 0x19f;
-               ebp = 0x1fb;
-               v20 = 0x0c0;
-               v1E = 0x195;
-               v16 = 0x1d6;
-               v14 = 0x1ef;
-               v12 = 4;
-               v10 = 5;
-               v0E = 5;
-               break;
-       case HIERARCHY_2:
-               edi |= 0x80;
-               if (s->chip_rev == DRXD_FW_B1)
-                       break;
-               rc = WR16(s, 0x1c10047, 2);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x2010012, 2);
-               if (rc < 0)
-                       goto exit_rc;
-               ebx = 0x08f;
-               ebp = 0x12f;
-               v20 = 0x0c0;
-               v1E = 0x11e;
-               v16 = 0x1d6;
-               v14 = 0x15e;
-               v12 = 4;
-               v10 = 5;
-               v0E = 5;
-               break;
-       case HIERARCHY_4:
-               edi |= 0xc0;
-               if (s->chip_rev == DRXD_FW_B1)
-                       break;
-               rc = WR16(s, 0x1c10047, 3);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x2010012, 3);
-               if (rc < 0)
-                       goto exit_rc;
-               ebx = 0x14d;
-               ebp = 0x197;
-               v20 = 0x0c0;
-               v1E = 0x1ce;
-               v16 = 0x1d6;
-               v14 = 0x11a;
-               v12 = 4;
-               v10 = 6;
-               v0E = 5;
-               break;
-       default:
-               v22 |= 8;
-               if (s->chip_rev == DRXD_FW_B1)
-                       break;
-               rc = WR16(s, 0x1c10047, 0);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x2010012, 0);
-               if (rc < 0)
-                       goto exit_rc;
-                               /* QPSK    QAM16  QAM64 */
-               ebx = 0x19f;    /*                 62   */
-               ebp = 0x1fb;    /*                 15   */
-               v20 = 0x16a;    /*  62                  */
-               v1E = 0x195;    /*         62           */
-               v16 = 0x1bb;    /*  15                  */
-               v14 = 0x1ef;    /*         15           */
-               v12 = 5;        /*  16                  */
-               v10 = 5;        /*         16           */
-               v0E = 5;        /*                 16   */
-       }
-
-       switch (fep->u.ofdm.constellation) {
-       default:
-               v22 |= 4;
-       case QPSK:
-               if (s->chip_rev == DRXD_FW_B1)
-                       break;
-
-               rc = WR16(s, 0x1c10046, 0);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x2010011, 0);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x201001a, 0x10);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x201001b, 0);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x201001c, 0);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x1c10062, v20);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x1c1002a, v1C);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x1c10015, v16);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x1c10016, v12);
-               if (rc < 0)
-                       goto exit_rc;
-               break;
-       case QAM_16:
-               edi |= 0x10;
-               if (s->chip_rev == DRXD_FW_B1)
-                       break;
-
-               rc = WR16(s, 0x1c10046, 1);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x2010011, 1);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x201001a, 0x10);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x201001b, 4);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x201001c, 0);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x1c10062, v1E);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x1c1002a, v1A);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x1c10015, v14);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x1c10016, v10);
-               if (rc < 0)
-                       goto exit_rc;
-               break;
-       case QAM_64:
-               edi |= 0x20;
-               rc = WR16(s, 0x1c10046, 2);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x2010011, 2);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x201001a, 0x20);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x201001b, 8);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x201001c, 2);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x1c10062, ebx);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x1c1002a, v18);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x1c10015, ebp);
-               if (rc < 0)
-                       goto exit_rc;
-               rc = WR16(s, 0x1c10016, v0E);
-               if (rc < 0)
-                       goto exit_rc;
-               break;
-       }
-
-       if (s->config.s20d24 == 1) {
-               rc = WR16(s, 0x2010013, 0);
-       } else {
-               rc = WR16(s, 0x2010013, 1);
-               edi |= 0x1000;
-       }
-
-       switch (fep->u.ofdm.code_rate_HP) {
-       default:
-               v22 |= 0x10;
-       case FEC_1_2:
-               if (s->chip_rev == DRXD_FW_B1)
-                       break;
-               rc = WR16(s, 0x2090011, 0);
-               break;
-       case FEC_2_3:
-               edi |= 0x200;
-               if (s->chip_rev == DRXD_FW_B1)
-                       break;
-               rc = WR16(s, 0x2090011, 1);
-               break;
-       case FEC_3_4:
-               edi |= 0x400;
-               if (s->chip_rev == DRXD_FW_B1)
-                       break;
-               rc = WR16(s, 0x2090011, 2);
-               break;
-       case FEC_5_6:           /* 5 */
-               edi |= 0x600;
-               if (s->chip_rev == DRXD_FW_B1)
-                       break;
-               rc = WR16(s, 0x2090011, 3);
-               break;
-       case FEC_7_8:           /* 7 */
-               edi |= 0x800;
-               if (s->chip_rev == DRXD_FW_B1)
-                       break;
-               rc = WR16(s, 0x2090011, 4);
-               break;
-       };
-       if (rc < 0)
-               goto exit_rc;
-
-       switch (fep->u.ofdm.bandwidth) {
-       default:
-               rc = -EINVAL;
-               goto exit_rc;
-       case BANDWIDTH_8_MHZ:   /* 0 */
-       case BANDWIDTH_AUTO:
-               rc = WR16(s, 0x0c2003f, 0x32);
-               s->bandwidth_parm = ebx = 0x8b8249;
-               edx = 0;
-               break;
-       case BANDWIDTH_7_MHZ:
-               rc = WR16(s, 0x0c2003f, 0x3b);
-               s->bandwidth_parm = ebx = 0x7a1200;
-               edx = 0x4807;
-               break;
-       case BANDWIDTH_6_MHZ:
-               rc = WR16(s, 0x0c2003f, 0x47);
-               s->bandwidth_parm = ebx = 0x68a1b6;
-               edx = 0x0f07;
-               break;
-       };
-
-       if (rc < 0)
-               goto exit_rc;
-
-       rc = WR16(s, 0x08200ec, edx);
-       if (rc < 0)
-               goto exit_rc;
-
-       rc = RD16(s, 0x0820050);
-       if (rc < 0)
-               goto exit_rc;
-       rc = WR16(s, 0x0820050, rc);
-
-       {
-               /* Configure bandwidth specific factor */
-               ebx = div64_u64(((u64) (s->f_osc) << 21) + (ebx >> 1),
-                                    (u64)ebx) - 0x800000;
-               EXIT_RC(WR16(s, 0x0c50010, ebx & 0xffff));
-               EXIT_RC(WR16(s, 0x0c50011, ebx >> 16));
-
-               /* drx397xD oscillator calibration */
-               ebx = div64_u64(((u64) (s->config.f_if + df_tuner) << 28) +
-                                    (s->f_osc >> 1), (u64)s->f_osc);
-       }
-       ebx &= 0xfffffff;
-       if (fep->inversion == INVERSION_ON)
-               ebx = 0x10000000 - ebx;
-
-       EXIT_RC(WR16(s, 0x0c30010, ebx & 0xffff));
-       EXIT_RC(WR16(s, 0x0c30011, ebx >> 16));
-
-       EXIT_RC(WR16(s, 0x0800000, 1));
-       EXIT_RC(RD16(s, 0x0800000));
-
-
-       EXIT_RC(SC_WaitForReady(s));
-       EXIT_RC(WR16(s, 0x0820042, 0));
-       EXIT_RC(WR16(s, 0x0820041, v22));
-       EXIT_RC(WR16(s, 0x0820040, edi));
-       EXIT_RC(SC_SendCommand(s, 3));
-
-       rc = RD16(s, 0x0800000);
-
-       SC_WaitForReady(s);
-       WR16(s, 0x0820042, 0);
-       WR16(s, 0x0820041, 1);
-       WR16(s, 0x0820040, 1);
-       SC_SendCommand(s, 1);
-
-
-       rc = WR16(s, 0x2150000, 2);
-       rc = WR16(s, 0x2150016, a);
-       rc = WR16(s, 0x2150010, 4);
-       rc = WR16(s, 0x2150036, 0);
-       rc = WR16(s, 0x2150000, 1);
-       s->config.d60 = 2;
-
-exit_rc:
-       return rc;
-}
-
-/*******************************************************************************
- * DVB interface
- ******************************************************************************/
-
-static int drx397x_init(struct dvb_frontend *fe)
-{
-       struct drx397xD_state *s = fe->demodulator_priv;
-       int rc;
-
-       pr_debug("%s\n", __func__);
-
-       s->config.rfagc.d00 = 2;        /* 0x7c */
-       s->config.rfagc.w04 = 0;
-       s->config.rfagc.w06 = 0x3ff;
-
-       s->config.ifagc.d00 = 0;        /* 0x68 */
-       s->config.ifagc.w04 = 0;
-       s->config.ifagc.w06 = 140;
-       s->config.ifagc.w08 = 0;
-       s->config.ifagc.w0A = 0x3ff;
-       s->config.ifagc.w0C = 0x388;
-
-       /* for signal strength calculations */
-       s->config.ss76 = 820;
-       s->config.ss78 = 2200;
-       s->config.ss7A = 150;
-
-       /* HI_CfgCommand */
-       s->config.w50 = 4;
-       s->config.w52 = 9;
-
-       s->config.f_if = 42800000;      /* d14: intermediate frequency [Hz] */
-       s->config.f_osc = 48000;        /* s66 : oscillator frequency [kHz] */
-       s->config.w92 = 12000;
-
-       s->config.w9C = 0x000e;
-       s->config.w9E = 0x0000;
-
-       /* ConfigureMPEGOutput params */
-       s->config.wA0 = 4;
-       s->config.w98 = 1;
-       s->config.w9A = 1;
-
-       /* get chip revision */
-       rc = RD16(s, 0x2410019);
-       if (rc < 0)
-               return -ENODEV;
-
-       if (rc == 0) {
-               printk(KERN_INFO "%s: chip revision A2\n", mod_name);
-               rc = drx_load_fw(s, DRXD_FW_A2);
-       } else {
-
-               rc = (rc >> 12) - 3;
-               switch (rc) {
-               case 1:
-                       s->flags |= F_SET_0D4h;
-               case 0:
-               case 4:
-                       s->flags |= F_SET_0D0h;
-                       break;
-               case 2:
-               case 5:
-                       break;
-               case 3:
-                       s->flags |= F_SET_0D4h;
-                       break;
-               default:
-                       return -ENODEV;
-               };
-               printk(KERN_INFO "%s: chip revision B1.%d\n", mod_name, rc);
-               rc = drx_load_fw(s, DRXD_FW_B1);
-       }
-       if (rc < 0)
-               goto error;
-
-       rc = WR16(s, 0x0420033, 0x3973);
-       if (rc < 0)
-               goto error;
-
-       rc = HI_Command(s, 2);
-
-       msleep(1);
-
-       if (s->chip_rev == DRXD_FW_A2) {
-               rc = WR16(s, 0x043012d, 0x47F);
-               if (rc < 0)
-                       goto error;
-       }
-       rc = WR16_E0(s, 0x0400000, 0);
-       if (rc < 0)
-               goto error;
-
-       if (s->config.w92 > 20000 || s->config.w92 % 4000) {
-               printk(KERN_ERR "%s: invalid osc frequency\n", mod_name);
-               rc = -1;
-               goto error;
-       }
-
-       rc = WR16(s, 0x2410010, 1);
-       if (rc < 0)
-               goto error;
-       rc = WR16(s, 0x2410011, 0x15);
-       if (rc < 0)
-               goto error;
-       rc = WR16(s, 0x2410012, s->config.w92 / 4000);
-       if (rc < 0)
-               goto error;
-#ifdef ORIG_FW
-       rc = WR16(s, 0x2410015, 2);
-       if (rc < 0)
-               goto error;
-#endif
-       rc = WR16(s, 0x2410017, 0x3973);
-       if (rc < 0)
-               goto error;
-
-       s->f_osc = s->config.f_osc * 1000;      /* initial estimator */
-
-       s->config.w56 = 1;
-
-       rc = HI_CfgCommand(s);
-       if (rc < 0)
-               goto error;
-
-       rc = write_fw(s, DRXD_InitAtomicRead);
-       if (rc < 0)
-               goto error;
-
-       if (s->chip_rev == DRXD_FW_A2) {
-               rc = WR16(s, 0x2150013, 0);
-               if (rc < 0)
-                       goto error;
-       }
-
-       rc = WR16_E0(s, 0x0400002, 0);
-       if (rc < 0)
-               goto error;
-       rc = WR16(s, 0x0400002, 0);
-       if (rc < 0)
-               goto error;
-
-       if (s->chip_rev == DRXD_FW_A2) {
-               rc = write_fw(s, DRXD_ResetCEFR);
-               if (rc < 0)
-                       goto error;
-       }
-       rc = write_fw(s, DRXD_microcode);
-       if (rc < 0)
-               goto error;
-
-       s->config.w9C = 0x0e;
-       if (s->flags & F_SET_0D0h) {
-               s->config.w9C = 0;
-               rc = RD16(s, 0x0c20010);
-               if (rc < 0)
-                       goto write_DRXD_InitFE_1;
-
-               rc &= ~0x1000;
-               rc = WR16(s, 0x0c20010, rc);
-               if (rc < 0)
-                       goto write_DRXD_InitFE_1;
-
-               rc = RD16(s, 0x0c20011);
-               if (rc < 0)
-                       goto write_DRXD_InitFE_1;
-
-               rc &= ~0x8;
-               rc = WR16(s, 0x0c20011, rc);
-               if (rc < 0)
-                       goto write_DRXD_InitFE_1;
-
-               rc = WR16(s, 0x0c20012, 1);
-       }
-
-write_DRXD_InitFE_1:
-
-       rc = write_fw(s, DRXD_InitFE_1);
-       if (rc < 0)
-               goto error;
-
-       rc = 1;
-       if (s->chip_rev == DRXD_FW_B1) {
-               if (s->flags & F_SET_0D0h)
-                       rc = 0;
-       } else {
-               if (s->flags & F_SET_0D0h)
-                       rc = 4;
-       }
-
-       rc = WR16(s, 0x0C20012, rc);
-       if (rc < 0)
-               goto error;
-
-       rc = WR16(s, 0x0C20013, s->config.w9E);
-       if (rc < 0)
-               goto error;
-       rc = WR16(s, 0x0C20015, s->config.w9C);
-       if (rc < 0)
-               goto error;
-
-       rc = write_fw(s, DRXD_InitFE_2);
-       if (rc < 0)
-               goto error;
-       rc = write_fw(s, DRXD_InitFT);
-       if (rc < 0)
-               goto error;
-       rc = write_fw(s, DRXD_InitCP);
-       if (rc < 0)
-               goto error;
-       rc = write_fw(s, DRXD_InitCE);
-       if (rc < 0)
-               goto error;
-       rc = write_fw(s, DRXD_InitEQ);
-       if (rc < 0)
-               goto error;
-       rc = write_fw(s, DRXD_InitEC);
-       if (rc < 0)
-               goto error;
-       rc = write_fw(s, DRXD_InitSC);
-       if (rc < 0)
-               goto error;
-
-       rc = SetCfgIfAgc(s, &s->config.ifagc);
-       if (rc < 0)
-               goto error;
-
-       rc = SetCfgRfAgc(s, &s->config.rfagc);
-       if (rc < 0)
-               goto error;
-
-       rc = ConfigureMPEGOutput(s, 1);
-       rc = WR16(s, 0x08201fe, 0x0017);
-       rc = WR16(s, 0x08201ff, 0x0101);
-
-       s->config.d5C = 0;
-       s->config.d60 = 1;
-       s->config.d48 = 1;
-
-error:
-       return rc;
-}
-
-static int drx397x_get_frontend(struct dvb_frontend *fe,
-                               struct dvb_frontend_parameters *params)
-{
-       return 0;
-}
-
-static int drx397x_set_frontend(struct dvb_frontend *fe,
-                               struct dvb_frontend_parameters *params)
-{
-       struct drx397xD_state *s = fe->demodulator_priv;
-
-       s->config.s20d24 = 1;
-
-       return drx_tune(s, params);
-}
-
-static int drx397x_get_tune_settings(struct dvb_frontend *fe,
-                                    struct dvb_frontend_tune_settings
-                                    *fe_tune_settings)
-{
-       fe_tune_settings->min_delay_ms = 10000;
-       fe_tune_settings->step_size = 0;
-       fe_tune_settings->max_drift = 0;
-
-       return 0;
-}
-
-static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-       struct drx397xD_state *s = fe->demodulator_priv;
-       int lockstat;
-
-       GetLockStatus(s, &lockstat);
-
-       *status = 0;
-       if (lockstat & 2) {
-               CorrectSysClockDeviation(s);
-               ConfigureMPEGOutput(s, 1);
-               *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI;
-       }
-       if (lockstat & 4)
-               *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
-
-       return 0;
-}
-
-static int drx397x_read_ber(struct dvb_frontend *fe, unsigned int *ber)
-{
-       *ber = 0;
-
-       return 0;
-}
-
-static int drx397x_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-       *snr = 0;
-
-       return 0;
-}
-
-static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-       struct drx397xD_state *s = fe->demodulator_priv;
-       int rc;
-
-       if (s->config.ifagc.d00 == 2) {
-               *strength = 0xffff;
-               return 0;
-       }
-       rc = RD16(s, 0x0c20035);
-       if (rc < 0) {
-               *strength = 0;
-               return 0;
-       }
-       rc &= 0x3ff;
-       /* Signal strength is calculated using the following formula:
-        *
-        * a = 2200 * 150 / (2200 + 150);
-        * a = a * 3300 /  (a + 820);
-        * b = 2200 * 3300 / (2200 + 820);
-        * c = (((b-a) * rc) >> 10  + a) << 4;
-        * strength = ~c & 0xffff;
-        *
-        * The following does the same but with less rounding errors:
-        */
-       *strength = ~(7720 + (rc * 30744 >> 10));
-
-       return 0;
-}
-
-static int drx397x_read_ucblocks(struct dvb_frontend *fe,
-                                unsigned int *ucblocks)
-{
-       *ucblocks = 0;
-
-       return 0;
-}
-
-static int drx397x_sleep(struct dvb_frontend *fe)
-{
-       return 0;
-}
-
-static void drx397x_release(struct dvb_frontend *fe)
-{
-       struct drx397xD_state *s = fe->demodulator_priv;
-       printk(KERN_INFO "%s: release demodulator\n", mod_name);
-       if (s) {
-               drx_release_fw(s);
-               kfree(s);
-       }
-
-}
-
-static struct dvb_frontend_ops drx397x_ops = {
-
-       .info = {
-                .name                  = "Micronas DRX397xD DVB-T Frontend",
-                .type                  = FE_OFDM,
-                .frequency_min         = 47125000,
-                .frequency_max         = 855250000,
-                .frequency_stepsize    = 166667,
-                .frequency_tolerance   = 0,
-                .caps =                                  /* 0x0C01B2EAE */
-                        FE_CAN_FEC_1_2                 | /* = 0x2, */
-                        FE_CAN_FEC_2_3                 | /* = 0x4, */
-                        FE_CAN_FEC_3_4                 | /* = 0x8, */
-                        FE_CAN_FEC_5_6                 | /* = 0x20, */
-                        FE_CAN_FEC_7_8                 | /* = 0x80, */
-                        FE_CAN_FEC_AUTO                | /* = 0x200, */
-                        FE_CAN_QPSK                    | /* = 0x400, */
-                        FE_CAN_QAM_16                  | /* = 0x800, */
-                        FE_CAN_QAM_64                  | /* = 0x2000, */
-                        FE_CAN_QAM_AUTO                | /* = 0x10000, */
-                        FE_CAN_TRANSMISSION_MODE_AUTO  | /* = 0x20000, */
-                        FE_CAN_GUARD_INTERVAL_AUTO     | /* = 0x80000, */
-                        FE_CAN_HIERARCHY_AUTO          | /* = 0x100000, */
-                        FE_CAN_RECOVER                 | /* = 0x40000000, */
-                        FE_CAN_MUTE_TS                   /* = 0x80000000 */
-        },
-
-       .release = drx397x_release,
-       .init = drx397x_init,
-       .sleep = drx397x_sleep,
-
-       .set_frontend = drx397x_set_frontend,
-       .get_tune_settings = drx397x_get_tune_settings,
-       .get_frontend = drx397x_get_frontend,
-
-       .read_status = drx397x_read_status,
-       .read_snr = drx397x_read_snr,
-       .read_signal_strength = drx397x_read_signal_strength,
-       .read_ber = drx397x_read_ber,
-       .read_ucblocks = drx397x_read_ucblocks,
-};
-
-struct dvb_frontend *drx397xD_attach(const struct drx397xD_config *config,
-                                    struct i2c_adapter *i2c)
-{
-       struct drx397xD_state *state;
-
-       /* allocate memory for the internal state */
-       state = kzalloc(sizeof(struct drx397xD_state), GFP_KERNEL);
-       if (!state)
-               goto error;
-
-       /* setup the state */
-       state->i2c = i2c;
-       memcpy(&state->config, config, sizeof(struct drx397xD_config));
-
-       /* check if the demod is there */
-       if (RD16(state, 0x2410019) < 0)
-               goto error;
-
-       /* create dvb_frontend */
-       memcpy(&state->frontend.ops, &drx397x_ops,
-                       sizeof(struct dvb_frontend_ops));
-       state->frontend.demodulator_priv = state;
-
-       return &state->frontend;
-error:
-       kfree(state);
-
-       return NULL;
-}
-EXPORT_SYMBOL(drx397xD_attach);
-
-MODULE_DESCRIPTION("Micronas DRX397xD DVB-T Frontend");
-MODULE_AUTHOR("Henk Vergonet");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/media/dvb/frontends/drx397xD.h b/drivers/media/dvb/frontends/drx397xD.h
deleted file mode 100644 (file)
index ba05d17..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- *  Driver for Micronas DVB-T drx397xD demodulator
- *
- *  Copyright (C) 2007 Henk vergonet <Henk.Vergonet@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; 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.=
- */
-
-#ifndef _DRX397XD_H_INCLUDED
-#define _DRX397XD_H_INCLUDED
-
-#include <linux/dvb/frontend.h>
-
-#define DRX_F_STEPSIZE 166667
-#define DRX_F_OFFSET   36000000
-
-#define I2C_ADR_C0(x) \
-(      cpu_to_le32( \
-               (u32)( \
-                       (((u32)(x) & (u32)0x000000ffUL)      ) | \
-                       (((u32)(x) & (u32)0x0000ff00UL) << 16) | \
-                       (((u32)(x) & (u32)0x0fff0000UL) >>  8) | \
-                        (           (u32)0x00c00000UL)          \
-                     )) \
-)
-
-#define I2C_ADR_E0(x) \
-(      cpu_to_le32( \
-               (u32)( \
-                       (((u32)(x) & (u32)0x000000ffUL)      ) | \
-                       (((u32)(x) & (u32)0x0000ff00UL) << 16) | \
-                       (((u32)(x) & (u32)0x0fff0000UL) >>  8) | \
-                        (           (u32)0x00e00000UL)          \
-                     )) \
-)
-
-struct drx397xD_CfgRfAgc       /* 0x7c */
-{
-       int d00;        /* 2 */
-       u16 w04;
-       u16 w06;
-};
-
-struct drx397xD_CfgIfAgc       /* 0x68 */
-{
-       int d00;        /* 0 */
-       u16 w04;        /* 0 */
-       u16 w06;
-       u16 w08;
-       u16 w0A;
-       u16 w0C;
-};
-
-struct drx397xD_s20 {
-       int d04;
-       u32 d18;
-       u32 d1C;
-       u32 d20;
-       u32 d14;
-       u32 d24;
-       u32 d0C;
-       u32 d08;
-};
-
-struct drx397xD_config
-{
-       /* demodulator's I2C address */
-       u8      demod_address;          /* 0x0f */
-
-       struct drx397xD_CfgIfAgc  ifagc;  /* 0x68 */
-       struct drx397xD_CfgRfAgc  rfagc;  /* 0x7c */
-       u32     s20d24;
-
-       /* HI_CfgCommand parameters */
-       u16     w50, w52, /* w54, */ w56;
-
-       int     d5C;
-       int     d60;
-       int     d48;
-       int     d28;
-
-       u32     f_if;   /* d14: intermediate frequency [Hz]             */
-                       /*      36000000 on Cinergy 2400i DT            */
-                       /*      42800000 on Pinnacle Hybrid PRO 330e    */
-
-       u16     f_osc;  /* s66: 48000 oscillator frequency [kHz]        */
-
-       u16     w92;    /* 20000 */
-
-       u16     wA0;
-       u16     w98;
-       u16     w9A;
-
-       u16     w9C;    /* 0xe0 */
-       u16     w9E;    /* 0x00 */
-
-       /* used for signal strength calculations in
-          drx397x_read_signal_strength
-       */
-       u16     ss78;   // 2200
-       u16     ss7A;   // 150
-       u16     ss76;   // 820
-};
-
-#if defined(CONFIG_DVB_DRX397XD) || (defined(CONFIG_DVB_DRX397XD_MODULE) && defined(MODULE))
-extern struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config,
-                                          struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config,
-                                          struct i2c_adapter *i2c)
-{
-       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-       return NULL;
-}
-#endif /* CONFIG_DVB_DRX397XD */
-
-#endif /* _DRX397XD_H_INCLUDED */
diff --git a/drivers/media/dvb/frontends/drx397xD_fw.h b/drivers/media/dvb/frontends/drx397xD_fw.h
deleted file mode 100644 (file)
index c8b44c1..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Firmware definitions for Micronas drx397xD
- *
- * Copyright (C) 2007 Henk Vergonet <Henk.Vergonet@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; 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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifdef _FW_ENTRY
-       _FW_ENTRY("drx397xD.A2.fw",     DRXD_FW_A2 = 0, DRXD_FW_A2      ),
-       _FW_ENTRY("drx397xD.B1.fw",     DRXD_FW_B1,     DRXD_FW_B1      ),
-#undef _FW_ENTRY
-#endif /* _FW_ENTRY */
-
-#ifdef _BLOB_ENTRY
-       _BLOB_ENTRY("InitAtomicRead",   DRXD_InitAtomicRead = 0 ),
-       _BLOB_ENTRY("InitCE",           DRXD_InitCE             ),
-       _BLOB_ENTRY("InitCP",           DRXD_InitCP             ),
-       _BLOB_ENTRY("InitEC",           DRXD_InitEC             ),
-       _BLOB_ENTRY("InitEQ",           DRXD_InitEQ             ),
-       _BLOB_ENTRY("InitFE_1",         DRXD_InitFE_1           ),
-       _BLOB_ENTRY("InitFE_2",         DRXD_InitFE_2           ),
-       _BLOB_ENTRY("InitFT",           DRXD_InitFT             ),
-       _BLOB_ENTRY("InitSC",           DRXD_InitSC             ),
-       _BLOB_ENTRY("ResetCEFR",        DRXD_ResetCEFR          ),
-       _BLOB_ENTRY("ResetECRAM",       DRXD_ResetECRAM         ),
-       _BLOB_ENTRY("microcode",        DRXD_microcode          ),
-#undef _BLOB_ENTRY
-#endif /* _BLOB_ENTRY */
diff --git a/drivers/media/dvb/frontends/drxd.h b/drivers/media/dvb/frontends/drxd.h
new file mode 100644 (file)
index 0000000..7113535
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * drxd.h: DRXD DVB-T demodulator driver
+ *
+ * Copyright (C) 2005-2007 Micronas
+ *
+ * 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
+ */
+
+#ifndef _DRXD_H_
+#define _DRXD_H_
+
+#include <linux/types.h>
+#include <linux/i2c.h>
+
+struct drxd_config {
+       u8 index;
+
+       u8 pll_address;
+       u8 pll_type;
+#define DRXD_PLL_NONE     0
+#define DRXD_PLL_DTT7520X 1
+#define DRXD_PLL_MT3X0823 2
+
+       u32 clock;
+       u8 insert_rs_byte;
+
+       u8 demod_address;
+       u8 demoda_address;
+       u8 demod_revision;
+
+       /* If the tuner is not behind an i2c gate, be sure to flip this bit
+          or else the i2c bus could get wedged */
+       u8 disable_i2c_gate_ctrl;
+
+       u32 IF;
+       int (*pll_set) (void *priv, void *priv_params,
+                       u8 pll_addr, u8 demoda_addr, s32 *off);
+        s16(*osc_deviation) (void *priv, s16 dev, int flag);
+};
+
+extern
+struct dvb_frontend *drxd_attach(const struct drxd_config *config,
+                                void *priv, struct i2c_adapter *i2c,
+                                struct device *dev);
+extern int drxd_config_i2c(struct dvb_frontend *, int);
+#endif
diff --git a/drivers/media/dvb/frontends/drxd_firm.c b/drivers/media/dvb/frontends/drxd_firm.c
new file mode 100644 (file)
index 0000000..5418b0b
--- /dev/null
@@ -0,0 +1,929 @@
+/*
+ * drxd_firm.c : DRXD firmware tables
+ *
+ * Copyright (C) 2006-2007 Micronas
+ *
+ * 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
+ */
+
+/* TODO: generate this file with a script from a settings file */
+
+/* Contains A2 firmware version: 1.4.2
+ * Contains B1 firmware version: 3.3.33
+ * Contains settings from driver 1.4.23
+*/
+
+#include "drxd_firm.h"
+
+#define ADDRESS(x)     ((x) & 0xFF), (((x)>>8) & 0xFF), (((x)>>16) & 0xFF), (((x)>>24) & 0xFF)
+#define LENGTH(x)      ((x) & 0xFF), (((x)>>8) & 0xFF)
+
+/* Is written via block write, must be little endian */
+#define DATA16(x)      ((x) & 0xFF), (((x)>>8) & 0xFF)
+
+#define WRBLOCK(a, l) ADDRESS(a), LENGTH(l)
+#define WR16(a, d) ADDRESS(a), LENGTH(1), DATA16(d)
+
+#define END_OF_TABLE      0xFF, 0xFF, 0xFF, 0xFF
+
+/* HI firmware patches */
+
+#define HI_TR_FUNC_ADDR HI_IF_RAM_USR_BEGIN__A
+#define HI_TR_FUNC_SIZE 9      /* size of this function in instruction words */
+
+u8 DRXD_InitAtomicRead[] = {
+       WRBLOCK(HI_TR_FUNC_ADDR, HI_TR_FUNC_SIZE),
+       0x26, 0x00,             /* 0         -> ring.rdy;           */
+       0x60, 0x04,             /* r0rami.dt -> ring.xba;           */
+       0x61, 0x04,             /* r0rami.dt -> ring.xad;           */
+       0xE3, 0x07,             /* HI_RA_RAM_USR_BEGIN -> ring.iad; */
+       0x40, 0x00,             /* (long immediate)                 */
+       0x64, 0x04,             /* r0rami.dt -> ring.len;           */
+       0x65, 0x04,             /* r0rami.dt -> ring.ctl;           */
+       0x26, 0x00,             /* 0         -> ring.rdy;           */
+       0x38, 0x00,             /* 0         -> jumps.ad;           */
+       END_OF_TABLE
+};
+
+/* Pins D0 and D1 of the parallel MPEG output can be used
+   to set the I2C address of a device. */
+
+#define HI_RST_FUNC_ADDR (HI_IF_RAM_USR_BEGIN__A + HI_TR_FUNC_SIZE)
+#define HI_RST_FUNC_SIZE 54    /* size of this function in instruction words */
+
+/* D0 Version */
+u8 DRXD_HiI2cPatch_1[] = {
+       WRBLOCK(HI_RST_FUNC_ADDR, HI_RST_FUNC_SIZE),
+       0xC8, 0x07, 0x01, 0x00, /* MASK      -> reg0.dt;                        */
+       0xE0, 0x07, 0x15, 0x02, /* (EC__BLK << 6) + EC_OC_REG__BNK -> ring.xba; */
+       0xE1, 0x07, 0x12, 0x00, /* EC_OC_REG_OC_MPG_SIO__A -> ring.xad;         */
+       0xA2, 0x00,             /* M_BNK_ID_DAT -> ring.iba;                    */
+       0x23, 0x00,             /* &data     -> ring.iad;                       */
+       0x24, 0x00,             /* 0         -> ring.len;                       */
+       0xA5, 0x02,             /* M_RC_CTR_SWAP | M_RC_CTR_READ -> ring.ctl;   */
+       0x26, 0x00,             /* 0         -> ring.rdy;                       */
+       0x42, 0x00,             /* &data+1   -> w0ram.ad;                       */
+       0xC0, 0x07, 0xFF, 0x0F, /* -1        -> w0ram.dt;                       */
+       0x63, 0x00,             /* &data+1   -> ring.iad;                       */
+       0x65, 0x02,             /* M_RC_CTR_SWAP | M_RC_CTR_WRITE -> ring.ctl;  */
+       0x26, 0x00,             /* 0         -> ring.rdy;                       */
+       0xE1, 0x07, 0x38, 0x00, /* EC_OC_REG_OCR_MPG_USR_DAT__A -> ring.xad;    */
+       0xA5, 0x02,             /* M_RC_CTR_SWAP | M_RC_CTR_READ -> ring.ctl;   */
+       0x26, 0x00,             /* 0         -> ring.rdy;                       */
+       0xE1, 0x07, 0x12, 0x00, /* EC_OC_REG_OC_MPG_SIO__A -> ring.xad;         */
+       0x23, 0x00,             /* &data     -> ring.iad;                       */
+       0x65, 0x02,             /* M_RC_CTR_SWAP | M_RC_CTR_WRITE -> ring.ctl;  */
+       0x26, 0x00,             /* 0         -> ring.rdy;                       */
+       0x42, 0x00,             /* &data+1   -> w0ram.ad;                       */
+       0x0F, 0x04,             /* r0ram.dt  -> and.op;                         */
+       0x1C, 0x06,             /* reg0.dt   -> and.tr;                         */
+       0xCF, 0x04,             /* and.rs    -> add.op;                         */
+       0xD0, 0x07, 0x70, 0x00, /* DEF_DEV_ID -> add.tr;                        */
+       0xD0, 0x04,             /* add.rs    -> add.tr;                         */
+       0xC8, 0x04,             /* add.rs    -> reg0.dt;                        */
+       0x60, 0x00,             /* reg0.dt   -> w0ram.dt;                       */
+       0xC2, 0x07, 0x10, 0x00, /* SLV0_BASE -> w0rami.ad;                      */
+       0x01, 0x00,             /* 0         -> w0rami.dt;                      */
+       0x01, 0x06,             /* reg0.dt   -> w0rami.dt;                      */
+       0xC2, 0x07, 0x20, 0x00, /* SLV1_BASE -> w0rami.ad;                      */
+       0x01, 0x00,             /* 0         -> w0rami.dt;                      */
+       0x01, 0x06,             /* reg0.dt   -> w0rami.dt;                      */
+       0xC2, 0x07, 0x30, 0x00, /* CMD_BASE  -> w0rami.ad;                      */
+       0x01, 0x00,             /* 0         -> w0rami.dt;                      */
+       0x01, 0x00,             /* 0         -> w0rami.dt;                      */
+       0x01, 0x00,             /* 0         -> w0rami.dt;                      */
+       0x68, 0x00,             /* M_IC_SEL_PT1 -> i2c.sel;                     */
+       0x29, 0x00,             /* M_IC_CMD_RESET -> i2c.cmd;                   */
+       0x28, 0x00,             /* M_IC_SEL_PT0 -> i2c.sel;                     */
+       0x29, 0x00,             /* M_IC_CMD_RESET -> i2c.cmd;                   */
+       0xF8, 0x07, 0x2F, 0x00, /* 0x2F      -> jumps.ad;                       */
+
+       WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 0) + 1)),
+            (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+       WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 1) + 1)),
+            (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+       WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 2) + 1)),
+            (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+       WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 3) + 1)),
+            (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+
+       /* Force quick and dirty reset */
+       WR16(B_HI_CT_REG_COMM_STATE__A, 0),
+       END_OF_TABLE
+};
+
+/* D0,D1 Version */
+u8 DRXD_HiI2cPatch_3[] = {
+       WRBLOCK(HI_RST_FUNC_ADDR, HI_RST_FUNC_SIZE),
+       0xC8, 0x07, 0x03, 0x00, /* MASK      -> reg0.dt;                        */
+       0xE0, 0x07, 0x15, 0x02, /* (EC__BLK << 6) + EC_OC_REG__BNK -> ring.xba; */
+       0xE1, 0x07, 0x12, 0x00, /* EC_OC_REG_OC_MPG_SIO__A -> ring.xad;         */
+       0xA2, 0x00,             /* M_BNK_ID_DAT -> ring.iba;                    */
+       0x23, 0x00,             /* &data     -> ring.iad;                       */
+       0x24, 0x00,             /* 0         -> ring.len;                       */
+       0xA5, 0x02,             /* M_RC_CTR_SWAP | M_RC_CTR_READ -> ring.ctl;   */
+       0x26, 0x00,             /* 0         -> ring.rdy;                       */
+       0x42, 0x00,             /* &data+1   -> w0ram.ad;                       */
+       0xC0, 0x07, 0xFF, 0x0F, /* -1        -> w0ram.dt;                       */
+       0x63, 0x00,             /* &data+1   -> ring.iad;                       */
+       0x65, 0x02,             /* M_RC_CTR_SWAP | M_RC_CTR_WRITE -> ring.ctl;  */
+       0x26, 0x00,             /* 0         -> ring.rdy;                       */
+       0xE1, 0x07, 0x38, 0x00, /* EC_OC_REG_OCR_MPG_USR_DAT__A -> ring.xad;    */
+       0xA5, 0x02,             /* M_RC_CTR_SWAP | M_RC_CTR_READ -> ring.ctl;   */
+       0x26, 0x00,             /* 0         -> ring.rdy;                       */
+       0xE1, 0x07, 0x12, 0x00, /* EC_OC_REG_OC_MPG_SIO__A -> ring.xad;         */
+       0x23, 0x00,             /* &data     -> ring.iad;                       */
+       0x65, 0x02,             /* M_RC_CTR_SWAP | M_RC_CTR_WRITE -> ring.ctl;  */
+       0x26, 0x00,             /* 0         -> ring.rdy;                       */
+       0x42, 0x00,             /* &data+1   -> w0ram.ad;                       */
+       0x0F, 0x04,             /* r0ram.dt  -> and.op;                         */
+       0x1C, 0x06,             /* reg0.dt   -> and.tr;                         */
+       0xCF, 0x04,             /* and.rs    -> add.op;                         */
+       0xD0, 0x07, 0x70, 0x00, /* DEF_DEV_ID -> add.tr;                        */
+       0xD0, 0x04,             /* add.rs    -> add.tr;                         */
+       0xC8, 0x04,             /* add.rs    -> reg0.dt;                        */
+       0x60, 0x00,             /* reg0.dt   -> w0ram.dt;                       */
+       0xC2, 0x07, 0x10, 0x00, /* SLV0_BASE -> w0rami.ad;                      */
+       0x01, 0x00,             /* 0         -> w0rami.dt;                      */
+       0x01, 0x06,             /* reg0.dt   -> w0rami.dt;                      */
+       0xC2, 0x07, 0x20, 0x00, /* SLV1_BASE -> w0rami.ad;                      */
+       0x01, 0x00,             /* 0         -> w0rami.dt;                      */
+       0x01, 0x06,             /* reg0.dt   -> w0rami.dt;                      */
+       0xC2, 0x07, 0x30, 0x00, /* CMD_BASE  -> w0rami.ad;                      */
+       0x01, 0x00,             /* 0         -> w0rami.dt;                      */
+       0x01, 0x00,             /* 0         -> w0rami.dt;                      */
+       0x01, 0x00,             /* 0         -> w0rami.dt;                      */
+       0x68, 0x00,             /* M_IC_SEL_PT1 -> i2c.sel;                     */
+       0x29, 0x00,             /* M_IC_CMD_RESET -> i2c.cmd;                   */
+       0x28, 0x00,             /* M_IC_SEL_PT0 -> i2c.sel;                     */
+       0x29, 0x00,             /* M_IC_CMD_RESET -> i2c.cmd;                   */
+       0xF8, 0x07, 0x2F, 0x00, /* 0x2F      -> jumps.ad;                       */
+
+       WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 0) + 1)),
+            (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+       WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 1) + 1)),
+            (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+       WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 2) + 1)),
+            (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+       WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 3) + 1)),
+            (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+
+       /* Force quick and dirty reset */
+       WR16(B_HI_CT_REG_COMM_STATE__A, 0),
+       END_OF_TABLE
+};
+
+u8 DRXD_ResetCEFR[] = {
+       WRBLOCK(CE_REG_FR_TREAL00__A, 57),
+       0x52, 0x00,             /* CE_REG_FR_TREAL00__A */
+       0x00, 0x00,             /* CE_REG_FR_TIMAG00__A */
+       0x52, 0x00,             /* CE_REG_FR_TREAL01__A */
+       0x00, 0x00,             /* CE_REG_FR_TIMAG01__A */
+       0x52, 0x00,             /* CE_REG_FR_TREAL02__A */
+       0x00, 0x00,             /* CE_REG_FR_TIMAG02__A */
+       0x52, 0x00,             /* CE_REG_FR_TREAL03__A */
+       0x00, 0x00,             /* CE_REG_FR_TIMAG03__A */
+       0x52, 0x00,             /* CE_REG_FR_TREAL04__A */
+       0x00, 0x00,             /* CE_REG_FR_TIMAG04__A */
+       0x52, 0x00,             /* CE_REG_FR_TREAL05__A */
+       0x00, 0x00,             /* CE_REG_FR_TIMAG05__A */
+       0x52, 0x00,             /* CE_REG_FR_TREAL06__A */
+       0x00, 0x00,             /* CE_REG_FR_TIMAG06__A */
+       0x52, 0x00,             /* CE_REG_FR_TREAL07__A */
+       0x00, 0x00,             /* CE_REG_FR_TIMAG07__A */
+       0x52, 0x00,             /* CE_REG_FR_TREAL08__A */
+       0x00, 0x00,             /* CE_REG_FR_TIMAG08__A */
+       0x52, 0x00,             /* CE_REG_FR_TREAL09__A */
+       0x00, 0x00,             /* CE_REG_FR_TIMAG09__A */
+       0x52, 0x00,             /* CE_REG_FR_TREAL10__A */
+       0x00, 0x00,             /* CE_REG_FR_TIMAG10__A */
+       0x52, 0x00,             /* CE_REG_FR_TREAL11__A */
+       0x00, 0x00,             /* CE_REG_FR_TIMAG11__A */
+
+       0x52, 0x00,             /* CE_REG_FR_MID_TAP__A */
+
+       0x0B, 0x00,             /* CE_REG_FR_SQS_G00__A */
+       0x0B, 0x00,             /* CE_REG_FR_SQS_G01__A */
+       0x0B, 0x00,             /* CE_REG_FR_SQS_G02__A */
+       0x0B, 0x00,             /* CE_REG_FR_SQS_G03__A */
+       0x0B, 0x00,             /* CE_REG_FR_SQS_G04__A */
+       0x0B, 0x00,             /* CE_REG_FR_SQS_G05__A */
+       0x0B, 0x00,             /* CE_REG_FR_SQS_G06__A */
+       0x0B, 0x00,             /* CE_REG_FR_SQS_G07__A */
+       0x0B, 0x00,             /* CE_REG_FR_SQS_G08__A */
+       0x0B, 0x00,             /* CE_REG_FR_SQS_G09__A */
+       0x0B, 0x00,             /* CE_REG_FR_SQS_G10__A */
+       0x0B, 0x00,             /* CE_REG_FR_SQS_G11__A */
+       0x0B, 0x00,             /* CE_REG_FR_SQS_G12__A */
+
+       0xFF, 0x01,             /* CE_REG_FR_RIO_G00__A */
+       0x90, 0x01,             /* CE_REG_FR_RIO_G01__A */
+       0x0B, 0x01,             /* CE_REG_FR_RIO_G02__A */
+       0xC8, 0x00,             /* CE_REG_FR_RIO_G03__A */
+       0xA0, 0x00,             /* CE_REG_FR_RIO_G04__A */
+       0x85, 0x00,             /* CE_REG_FR_RIO_G05__A */
+       0x72, 0x00,             /* CE_REG_FR_RIO_G06__A */
+       0x64, 0x00,             /* CE_REG_FR_RIO_G07__A */
+       0x59, 0x00,             /* CE_REG_FR_RIO_G08__A */
+       0x50, 0x00,             /* CE_REG_FR_RIO_G09__A */
+       0x49, 0x00,             /* CE_REG_FR_RIO_G10__A */
+
+       0x10, 0x00,             /* CE_REG_FR_MODE__A     */
+       0x78, 0x00,             /* CE_REG_FR_SQS_TRH__A  */
+       0x00, 0x00,             /* CE_REG_FR_RIO_GAIN__A */
+       0x00, 0x02,             /* CE_REG_FR_BYPASS__A   */
+       0x0D, 0x00,             /* CE_REG_FR_PM_SET__A   */
+       0x07, 0x00,             /* CE_REG_FR_ERR_SH__A   */
+       0x04, 0x00,             /* CE_REG_FR_MAN_SH__A   */
+       0x06, 0x00,             /* CE_REG_FR_TAP_SH__A   */
+
+       END_OF_TABLE
+};
+
+u8 DRXD_InitFEA2_1[] = {
+       WRBLOCK(FE_AD_REG_PD__A, 3),
+       0x00, 0x00,             /* FE_AD_REG_PD__A          */
+       0x01, 0x00,             /* FE_AD_REG_INVEXT__A      */
+       0x00, 0x00,             /* FE_AD_REG_CLKNEG__A      */
+
+       WRBLOCK(FE_AG_REG_DCE_AUR_CNT__A, 2),
+       0x10, 0x00,             /* FE_AG_REG_DCE_AUR_CNT__A */
+       0x10, 0x00,             /* FE_AG_REG_DCE_RUR_CNT__A */
+
+       WRBLOCK(FE_AG_REG_ACE_AUR_CNT__A, 2),
+       0x0E, 0x00,             /* FE_AG_REG_ACE_AUR_CNT__A */
+       0x00, 0x00,             /* FE_AG_REG_ACE_RUR_CNT__A */
+
+       WRBLOCK(FE_AG_REG_EGC_FLA_RGN__A, 5),
+       0x04, 0x00,             /* FE_AG_REG_EGC_FLA_RGN__A */
+       0x1F, 0x00,             /* FE_AG_REG_EGC_SLO_RGN__A */
+       0x00, 0x00,             /* FE_AG_REG_EGC_JMP_PSN__A */
+       0x00, 0x00,             /* FE_AG_REG_EGC_FLA_INC__A */
+       0x00, 0x00,             /* FE_AG_REG_EGC_FLA_DEC__A */
+
+       WRBLOCK(FE_AG_REG_GC1_AGC_MAX__A, 2),
+       0xFF, 0x01,             /* FE_AG_REG_GC1_AGC_MAX__A */
+       0x00, 0xFE,             /* FE_AG_REG_GC1_AGC_MIN__A */
+
+       WRBLOCK(FE_AG_REG_IND_WIN__A, 29),
+       0x00, 0x00,             /* FE_AG_REG_IND_WIN__A     */
+       0x05, 0x00,             /* FE_AG_REG_IND_THD_LOL__A */
+       0x0F, 0x00,             /* FE_AG_REG_IND_THD_HIL__A */
+       0x00, 0x00,             /* FE_AG_REG_IND_DEL__A     don't care */
+       0x1E, 0x00,             /* FE_AG_REG_IND_PD1_WRI__A */
+       0x0C, 0x00,             /* FE_AG_REG_PDA_AUR_CNT__A */
+       0x00, 0x00,             /* FE_AG_REG_PDA_RUR_CNT__A */
+       0x00, 0x00,             /* FE_AG_REG_PDA_AVE_DAT__A don't care  */
+       0x00, 0x00,             /* FE_AG_REG_PDC_RUR_CNT__A */
+       0x01, 0x00,             /* FE_AG_REG_PDC_SET_LVL__A */
+       0x02, 0x00,             /* FE_AG_REG_PDC_FLA_RGN__A */
+       0x00, 0x00,             /* FE_AG_REG_PDC_JMP_PSN__A don't care  */
+       0xFF, 0xFF,             /* FE_AG_REG_PDC_FLA_STP__A */
+       0xFF, 0xFF,             /* FE_AG_REG_PDC_SLO_STP__A */
+       0x00, 0x1F,             /* FE_AG_REG_PDC_PD2_WRI__A don't care  */
+       0x00, 0x00,             /* FE_AG_REG_PDC_MAP_DAT__A don't care  */
+       0x02, 0x00,             /* FE_AG_REG_PDC_MAX__A     */
+       0x0C, 0x00,             /* FE_AG_REG_TGA_AUR_CNT__A */
+       0x00, 0x00,             /* FE_AG_REG_TGA_RUR_CNT__A */
+       0x00, 0x00,             /* FE_AG_REG_TGA_AVE_DAT__A don't care  */
+       0x00, 0x00,             /* FE_AG_REG_TGC_RUR_CNT__A */
+       0x22, 0x00,             /* FE_AG_REG_TGC_SET_LVL__A */
+       0x15, 0x00,             /* FE_AG_REG_TGC_FLA_RGN__A */
+       0x00, 0x00,             /* FE_AG_REG_TGC_JMP_PSN__A don't care  */
+       0x01, 0x00,             /* FE_AG_REG_TGC_FLA_STP__A */
+       0x0A, 0x00,             /* FE_AG_REG_TGC_SLO_STP__A */
+       0x00, 0x00,             /* FE_AG_REG_TGC_MAP_DAT__A don't care  */
+       0x10, 0x00,             /* FE_AG_REG_FGA_AUR_CNT__A */
+       0x10, 0x00,             /* FE_AG_REG_FGA_RUR_CNT__A */
+
+       WRBLOCK(FE_AG_REG_BGC_FGC_WRI__A, 2),
+       0x00, 0x00,             /* FE_AG_REG_BGC_FGC_WRI__A */
+       0x00, 0x00,             /* FE_AG_REG_BGC_CGC_WRI__A */
+
+       WRBLOCK(FE_FD_REG_SCL__A, 3),
+       0x05, 0x00,             /* FE_FD_REG_SCL__A         */
+       0x03, 0x00,             /* FE_FD_REG_MAX_LEV__A     */
+       0x05, 0x00,             /* FE_FD_REG_NR__A          */
+
+       WRBLOCK(FE_CF_REG_SCL__A, 5),
+       0x16, 0x00,             /* FE_CF_REG_SCL__A         */
+       0x04, 0x00,             /* FE_CF_REG_MAX_LEV__A     */
+       0x06, 0x00,             /* FE_CF_REG_NR__A          */
+       0x00, 0x00,             /* FE_CF_REG_IMP_VAL__A     */
+       0x01, 0x00,             /* FE_CF_REG_MEAS_VAL__A    */
+
+       WRBLOCK(FE_CU_REG_FRM_CNT_RST__A, 2),
+       0x00, 0x08,             /* FE_CU_REG_FRM_CNT_RST__A */
+       0x00, 0x00,             /* FE_CU_REG_FRM_CNT_STR__A */
+
+       END_OF_TABLE
+};
+
+   /* with PGA */
+/*   WR16COND( DRXD_WITH_PGA, FE_AG_REG_AG_PGA_MODE__A   , 0x0004), */
+   /* without PGA */
+/*   WR16COND( DRXD_WITHOUT_PGA, FE_AG_REG_AG_PGA_MODE__A   , 0x0001), */
+/*   WR16(FE_AG_REG_AG_AGC_SIO__A,  (extAttr -> FeAgRegAgAgcSio), 0x0000 );*/
+/*   WR16(FE_AG_REG_AG_PWD__A        ,(extAttr -> FeAgRegAgPwd), 0x0000 );*/
+
+u8 DRXD_InitFEA2_2[] = {
+       WR16(FE_AG_REG_CDR_RUR_CNT__A, 0x0010),
+       WR16(FE_AG_REG_FGM_WRI__A, 48),
+       /* Activate measurement, activate scale */
+       WR16(FE_FD_REG_MEAS_VAL__A, 0x0001),
+
+       WR16(FE_CU_REG_COMM_EXEC__A, 0x0001),
+       WR16(FE_CF_REG_COMM_EXEC__A, 0x0001),
+       WR16(FE_IF_REG_COMM_EXEC__A, 0x0001),
+       WR16(FE_FD_REG_COMM_EXEC__A, 0x0001),
+       WR16(FE_FS_REG_COMM_EXEC__A, 0x0001),
+       WR16(FE_AD_REG_COMM_EXEC__A, 0x0001),
+       WR16(FE_AG_REG_COMM_EXEC__A, 0x0001),
+       WR16(FE_AG_REG_AG_MODE_LOP__A, 0x895E),
+
+       END_OF_TABLE
+};
+
+u8 DRXD_InitFEB1_1[] = {
+       WR16(B_FE_AD_REG_PD__A, 0x0000),
+       WR16(B_FE_AD_REG_CLKNEG__A, 0x0000),
+       WR16(B_FE_AG_REG_BGC_FGC_WRI__A, 0x0000),
+       WR16(B_FE_AG_REG_BGC_CGC_WRI__A, 0x0000),
+       WR16(B_FE_AG_REG_AG_MODE_LOP__A, 0x000a),
+       WR16(B_FE_AG_REG_IND_PD1_WRI__A, 35),
+       WR16(B_FE_AG_REG_IND_WIN__A, 0),
+       WR16(B_FE_AG_REG_IND_THD_LOL__A, 8),
+       WR16(B_FE_AG_REG_IND_THD_HIL__A, 8),
+       WR16(B_FE_CF_REG_IMP_VAL__A, 1),
+       WR16(B_FE_AG_REG_EGC_FLA_RGN__A, 7),
+       END_OF_TABLE
+};
+
+       /* with PGA */
+/*      WR16(B_FE_AG_REG_AG_PGA_MODE__A   , 0x0000, 0x0000); */
+       /* without PGA */
+/*      WR16(B_FE_AG_REG_AG_PGA_MODE__A   ,
+            B_FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN, 0x0000);*/
+                                                                            /*   WR16(B_FE_AG_REG_AG_AGC_SIO__A,(extAttr -> FeAgRegAgAgcSio), 0x0000 );*//*added HS 23-05-2005 */
+/*   WR16(B_FE_AG_REG_AG_PWD__A    ,(extAttr -> FeAgRegAgPwd), 0x0000 );*/
+
+u8 DRXD_InitFEB1_2[] = {
+       WR16(B_FE_COMM_EXEC__A, 0x0001),
+
+       /* RF-AGC setup */
+       WR16(B_FE_AG_REG_PDA_AUR_CNT__A, 0x0C),
+       WR16(B_FE_AG_REG_PDC_SET_LVL__A, 0x01),
+       WR16(B_FE_AG_REG_PDC_FLA_RGN__A, 0x02),
+       WR16(B_FE_AG_REG_PDC_FLA_STP__A, 0xFFFF),
+       WR16(B_FE_AG_REG_PDC_SLO_STP__A, 0xFFFF),
+       WR16(B_FE_AG_REG_PDC_MAX__A, 0x02),
+       WR16(B_FE_AG_REG_TGA_AUR_CNT__A, 0x0C),
+       WR16(B_FE_AG_REG_TGC_SET_LVL__A, 0x22),
+       WR16(B_FE_AG_REG_TGC_FLA_RGN__A, 0x15),
+       WR16(B_FE_AG_REG_TGC_FLA_STP__A, 0x01),
+       WR16(B_FE_AG_REG_TGC_SLO_STP__A, 0x0A),
+
+       WR16(B_FE_CU_REG_DIV_NFC_CLP__A, 0),
+       WR16(B_FE_CU_REG_CTR_NFC_OCR__A, 25000),
+       WR16(B_FE_CU_REG_CTR_NFC_ICR__A, 1),
+       END_OF_TABLE
+};
+
+u8 DRXD_InitCPA2[] = {
+       WRBLOCK(CP_REG_BR_SPL_OFFSET__A, 2),
+       0x07, 0x00,             /* CP_REG_BR_SPL_OFFSET__A  */
+       0x0A, 0x00,             /* CP_REG_BR_STR_DEL__A     */
+
+       WRBLOCK(CP_REG_RT_ANG_INC0__A, 4),
+       0x00, 0x00,             /* CP_REG_RT_ANG_INC0__A    */
+       0x00, 0x00,             /* CP_REG_RT_ANG_INC1__A    */
+       0x03, 0x00,             /* CP_REG_RT_DETECT_ENA__A  */
+       0x03, 0x00,             /* CP_REG_RT_DETECT_TRH__A  */
+
+       WRBLOCK(CP_REG_AC_NEXP_OFFS__A, 5),
+       0x32, 0x00,             /* CP_REG_AC_NEXP_OFFS__A   */
+       0x62, 0x00,             /* CP_REG_AC_AVER_POW__A    */
+       0x82, 0x00,             /* CP_REG_AC_MAX_POW__A     */
+       0x26, 0x00,             /* CP_REG_AC_WEIGHT_MAN__A  */
+       0x0F, 0x00,             /* CP_REG_AC_WEIGHT_EXP__A  */
+
+       WRBLOCK(CP_REG_AC_AMP_MODE__A, 2),
+       0x02, 0x00,             /* CP_REG_AC_AMP_MODE__A    */
+       0x01, 0x00,             /* CP_REG_AC_AMP_FIX__A     */
+
+       WR16(CP_REG_INTERVAL__A, 0x0005),
+       WR16(CP_REG_RT_EXP_MARG__A, 0x0004),
+       WR16(CP_REG_AC_ANG_MODE__A, 0x0003),
+
+       WR16(CP_REG_COMM_EXEC__A, 0x0001),
+       END_OF_TABLE
+};
+
+u8 DRXD_InitCPB1[] = {
+       WR16(B_CP_REG_BR_SPL_OFFSET__A, 0x0008),
+       WR16(B_CP_COMM_EXEC__A, 0x0001),
+       END_OF_TABLE
+};
+
+u8 DRXD_InitCEA2[] = {
+       WRBLOCK(CE_REG_AVG_POW__A, 4),
+       0x62, 0x00,             /* CE_REG_AVG_POW__A        */
+       0x78, 0x00,             /* CE_REG_MAX_POW__A        */
+       0x62, 0x00,             /* CE_REG_ATT__A            */
+       0x17, 0x00,             /* CE_REG_NRED__A           */
+
+       WRBLOCK(CE_REG_NE_ERR_SELECT__A, 2),
+       0x07, 0x00,             /* CE_REG_NE_ERR_SELECT__A  */
+       0xEB, 0xFF,             /* CE_REG_NE_TD_CAL__A      */
+
+       WRBLOCK(CE_REG_NE_MIXAVG__A, 2),
+       0x06, 0x00,             /* CE_REG_NE_MIXAVG__A      */
+       0x00, 0x00,             /* CE_REG_NE_NUPD_OFS__A    */
+
+       WRBLOCK(CE_REG_PE_NEXP_OFFS__A, 2),
+       0x00, 0x00,             /* CE_REG_PE_NEXP_OFFS__A   */
+       0x00, 0x00,             /* CE_REG_PE_TIMESHIFT__A   */
+
+       WRBLOCK(CE_REG_TP_A0_TAP_NEW__A, 3),
+       0x00, 0x01,             /* CE_REG_TP_A0_TAP_NEW__A       */
+       0x01, 0x00,             /* CE_REG_TP_A0_TAP_NEW_VALID__A */
+       0x0E, 0x00,             /* CE_REG_TP_A0_MU_LMS_STEP__A   */
+
+       WRBLOCK(CE_REG_TP_A1_TAP_NEW__A, 3),
+       0x00, 0x00,             /* CE_REG_TP_A1_TAP_NEW__A        */
+       0x01, 0x00,             /* CE_REG_TP_A1_TAP_NEW_VALID__A  */
+       0x0A, 0x00,             /* CE_REG_TP_A1_MU_LMS_STEP__A    */
+
+       WRBLOCK(CE_REG_FI_SHT_INCR__A, 2),
+       0x12, 0x00,             /* CE_REG_FI_SHT_INCR__A          */
+       0x0C, 0x00,             /* CE_REG_FI_EXP_NORM__A          */
+
+       WRBLOCK(CE_REG_IR_INPUTSEL__A, 3),
+       0x00, 0x00,             /* CE_REG_IR_INPUTSEL__A          */
+       0x00, 0x00,             /* CE_REG_IR_STARTPOS__A          */
+       0xFF, 0x00,             /* CE_REG_IR_NEXP_THRES__A        */
+
+       WR16(CE_REG_TI_NEXP_OFFS__A, 0x0000),
+
+       END_OF_TABLE
+};
+
+u8 DRXD_InitCEB1[] = {
+       WR16(B_CE_REG_TI_PHN_ENABLE__A, 0x0001),
+       WR16(B_CE_REG_FR_PM_SET__A, 0x000D),
+
+       END_OF_TABLE
+};
+
+u8 DRXD_InitEQA2[] = {
+       WRBLOCK(EQ_REG_OT_QNT_THRES0__A, 4),
+       0x1E, 0x00,             /* EQ_REG_OT_QNT_THRES0__A        */
+       0x1F, 0x00,             /* EQ_REG_OT_QNT_THRES1__A        */
+       0x06, 0x00,             /* EQ_REG_OT_CSI_STEP__A          */
+       0x02, 0x00,             /* EQ_REG_OT_CSI_OFFSET__A        */
+
+       WR16(EQ_REG_TD_REQ_SMB_CNT__A, 0x0200),
+       WR16(EQ_REG_IS_CLIP_EXP__A, 0x001F),
+       WR16(EQ_REG_SN_OFFSET__A, (u16) (-7)),
+       WR16(EQ_REG_RC_SEL_CAR__A, 0x0002),
+       WR16(EQ_REG_COMM_EXEC__A, 0x0001),
+       END_OF_TABLE
+};
+
+u8 DRXD_InitEQB1[] = {
+       WR16(B_EQ_REG_COMM_EXEC__A, 0x0001),
+       END_OF_TABLE
+};
+
+u8 DRXD_ResetECRAM[] = {
+       /* Reset packet sync bytes in EC_VD ram */
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (0 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (1 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (2 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (3 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (4 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (5 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (6 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (7 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (8 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (9 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (10 * 17), 0x0000),
+
+       /* Reset packet sync bytes in EC_RS ram */
+       WR16(EC_RS_EC_RAM__A, 0x0000),
+       WR16(EC_RS_EC_RAM__A + 204, 0x0000),
+       END_OF_TABLE
+};
+
+u8 DRXD_InitECA2[] = {
+       WRBLOCK(EC_SB_REG_CSI_HI__A, 6),
+       0x1F, 0x00,             /* EC_SB_REG_CSI_HI__A            */
+       0x1E, 0x00,             /* EC_SB_REG_CSI_LO__A            */
+       0x01, 0x00,             /* EC_SB_REG_SMB_TGL__A           */
+       0x7F, 0x00,             /* EC_SB_REG_SNR_HI__A            */
+       0x7F, 0x00,             /* EC_SB_REG_SNR_MID__A           */
+       0x7F, 0x00,             /* EC_SB_REG_SNR_LO__A            */
+
+       WRBLOCK(EC_RS_REG_REQ_PCK_CNT__A, 2),
+       0x00, 0x10,             /* EC_RS_REG_REQ_PCK_CNT__A       */
+       DATA16(EC_RS_REG_VAL_PCK),      /* EC_RS_REG_VAL__A               */
+
+       WRBLOCK(EC_OC_REG_TMD_TOP_MODE__A, 5),
+       0x03, 0x00,             /* EC_OC_REG_TMD_TOP_MODE__A      */
+       0xF4, 0x01,             /* EC_OC_REG_TMD_TOP_CNT__A       */
+       0xC0, 0x03,             /* EC_OC_REG_TMD_HIL_MAR__A       */
+       0x40, 0x00,             /* EC_OC_REG_TMD_LOL_MAR__A       */
+       0x03, 0x00,             /* EC_OC_REG_TMD_CUR_CNT__A       */
+
+       WRBLOCK(EC_OC_REG_AVR_ASH_CNT__A, 2),
+       0x06, 0x00,             /* EC_OC_REG_AVR_ASH_CNT__A       */
+       0x02, 0x00,             /* EC_OC_REG_AVR_BSH_CNT__A       */
+
+       WRBLOCK(EC_OC_REG_RCN_MODE__A, 7),
+       0x07, 0x00,             /* EC_OC_REG_RCN_MODE__A          */
+       0x00, 0x00,             /* EC_OC_REG_RCN_CRA_LOP__A       */
+       0xc0, 0x00,             /* EC_OC_REG_RCN_CRA_HIP__A       */
+       0x00, 0x10,             /* EC_OC_REG_RCN_CST_LOP__A       */
+       0x00, 0x00,             /* EC_OC_REG_RCN_CST_HIP__A       */
+       0xFF, 0x01,             /* EC_OC_REG_RCN_SET_LVL__A       */
+       0x0D, 0x00,             /* EC_OC_REG_RCN_GAI_LVL__A       */
+
+       WRBLOCK(EC_OC_REG_RCN_CLP_LOP__A, 2),
+       0x00, 0x00,             /* EC_OC_REG_RCN_CLP_LOP__A       */
+       0xC0, 0x00,             /* EC_OC_REG_RCN_CLP_HIP__A       */
+
+       WR16(EC_SB_REG_CSI_OFS__A, 0x0001),
+       WR16(EC_VD_REG_FORCE__A, 0x0002),
+       WR16(EC_VD_REG_REQ_SMB_CNT__A, 0x0001),
+       WR16(EC_VD_REG_RLK_ENA__A, 0x0001),
+       WR16(EC_OD_REG_SYNC__A, 0x0664),
+       WR16(EC_OC_REG_OC_MON_SIO__A, 0x0000),
+       WR16(EC_OC_REG_SNC_ISC_LVL__A, 0x0D0C),
+       /* Output zero on monitorbus pads, power saving */
+       WR16(EC_OC_REG_OCR_MON_UOS__A,
+            (EC_OC_REG_OCR_MON_UOS_DAT_0_ENABLE |
+             EC_OC_REG_OCR_MON_UOS_DAT_1_ENABLE |
+             EC_OC_REG_OCR_MON_UOS_DAT_2_ENABLE |
+             EC_OC_REG_OCR_MON_UOS_DAT_3_ENABLE |
+             EC_OC_REG_OCR_MON_UOS_DAT_4_ENABLE |
+             EC_OC_REG_OCR_MON_UOS_DAT_5_ENABLE |
+             EC_OC_REG_OCR_MON_UOS_DAT_6_ENABLE |
+             EC_OC_REG_OCR_MON_UOS_DAT_7_ENABLE |
+             EC_OC_REG_OCR_MON_UOS_DAT_8_ENABLE |
+             EC_OC_REG_OCR_MON_UOS_DAT_9_ENABLE |
+             EC_OC_REG_OCR_MON_UOS_VAL_ENABLE |
+             EC_OC_REG_OCR_MON_UOS_CLK_ENABLE)),
+       WR16(EC_OC_REG_OCR_MON_WRI__A,
+            EC_OC_REG_OCR_MON_WRI_INIT),
+
+/*   CHK_ERROR(ResetECRAM(demod)); */
+       /* Reset packet sync bytes in EC_VD ram */
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (0 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (1 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (2 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (3 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (4 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (5 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (6 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (7 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (8 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (9 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (10 * 17), 0x0000),
+
+       /* Reset packet sync bytes in EC_RS ram */
+       WR16(EC_RS_EC_RAM__A, 0x0000),
+       WR16(EC_RS_EC_RAM__A + 204, 0x0000),
+
+       WR16(EC_SB_REG_COMM_EXEC__A, 0x0001),
+       WR16(EC_VD_REG_COMM_EXEC__A, 0x0001),
+       WR16(EC_OD_REG_COMM_EXEC__A, 0x0001),
+       WR16(EC_RS_REG_COMM_EXEC__A, 0x0001),
+       END_OF_TABLE
+};
+
+u8 DRXD_InitECB1[] = {
+       WR16(B_EC_SB_REG_CSI_OFS0__A, 0x0001),
+       WR16(B_EC_SB_REG_CSI_OFS1__A, 0x0001),
+       WR16(B_EC_SB_REG_CSI_OFS2__A, 0x0001),
+       WR16(B_EC_SB_REG_CSI_LO__A, 0x000c),
+       WR16(B_EC_SB_REG_CSI_HI__A, 0x0018),
+       WR16(B_EC_SB_REG_SNR_HI__A, 0x007f),
+       WR16(B_EC_SB_REG_SNR_MID__A, 0x007f),
+       WR16(B_EC_SB_REG_SNR_LO__A, 0x007f),
+
+       WR16(B_EC_OC_REG_DTO_CLKMODE__A, 0x0002),
+       WR16(B_EC_OC_REG_DTO_PER__A, 0x0006),
+       WR16(B_EC_OC_REG_DTO_BUR__A, 0x0001),
+       WR16(B_EC_OC_REG_RCR_CLKMODE__A, 0x0000),
+       WR16(B_EC_OC_REG_RCN_GAI_LVL__A, 0x000D),
+       WR16(B_EC_OC_REG_OC_MPG_SIO__A, 0x0000),
+
+       /* Needed because shadow registers do not have correct default value */
+       WR16(B_EC_OC_REG_RCN_CST_LOP__A, 0x1000),
+       WR16(B_EC_OC_REG_RCN_CST_HIP__A, 0x0000),
+       WR16(B_EC_OC_REG_RCN_CRA_LOP__A, 0x0000),
+       WR16(B_EC_OC_REG_RCN_CRA_HIP__A, 0x00C0),
+       WR16(B_EC_OC_REG_RCN_CLP_LOP__A, 0x0000),
+       WR16(B_EC_OC_REG_RCN_CLP_HIP__A, 0x00C0),
+       WR16(B_EC_OC_REG_DTO_INC_LOP__A, 0x0000),
+       WR16(B_EC_OC_REG_DTO_INC_HIP__A, 0x00C0),
+
+       WR16(B_EC_OD_REG_SYNC__A, 0x0664),
+       WR16(B_EC_RS_REG_REQ_PCK_CNT__A, 0x1000),
+
+/*   CHK_ERROR(ResetECRAM(demod)); */
+       /* Reset packet sync bytes in EC_VD ram */
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (0 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (1 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (2 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (3 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (4 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (5 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (6 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (7 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (8 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (9 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (10 * 17), 0x0000),
+
+       /* Reset packet sync bytes in EC_RS ram */
+       WR16(EC_RS_EC_RAM__A, 0x0000),
+       WR16(EC_RS_EC_RAM__A + 204, 0x0000),
+
+       WR16(B_EC_SB_REG_COMM_EXEC__A, 0x0001),
+       WR16(B_EC_VD_REG_COMM_EXEC__A, 0x0001),
+       WR16(B_EC_OD_REG_COMM_EXEC__A, 0x0001),
+       WR16(B_EC_RS_REG_COMM_EXEC__A, 0x0001),
+       END_OF_TABLE
+};
+
+u8 DRXD_ResetECA2[] = {
+
+       WR16(EC_OC_REG_COMM_EXEC__A, 0x0000),
+       WR16(EC_OD_REG_COMM_EXEC__A, 0x0000),
+
+       WRBLOCK(EC_OC_REG_TMD_TOP_MODE__A, 5),
+       0x03, 0x00,             /* EC_OC_REG_TMD_TOP_MODE__A      */
+       0xF4, 0x01,             /* EC_OC_REG_TMD_TOP_CNT__A       */
+       0xC0, 0x03,             /* EC_OC_REG_TMD_HIL_MAR__A       */
+       0x40, 0x00,             /* EC_OC_REG_TMD_LOL_MAR__A       */
+       0x03, 0x00,             /* EC_OC_REG_TMD_CUR_CNT__A       */
+
+       WRBLOCK(EC_OC_REG_AVR_ASH_CNT__A, 2),
+       0x06, 0x00,             /* EC_OC_REG_AVR_ASH_CNT__A       */
+       0x02, 0x00,             /* EC_OC_REG_AVR_BSH_CNT__A       */
+
+       WRBLOCK(EC_OC_REG_RCN_MODE__A, 7),
+       0x07, 0x00,             /* EC_OC_REG_RCN_MODE__A          */
+       0x00, 0x00,             /* EC_OC_REG_RCN_CRA_LOP__A       */
+       0xc0, 0x00,             /* EC_OC_REG_RCN_CRA_HIP__A       */
+       0x00, 0x10,             /* EC_OC_REG_RCN_CST_LOP__A       */
+       0x00, 0x00,             /* EC_OC_REG_RCN_CST_HIP__A       */
+       0xFF, 0x01,             /* EC_OC_REG_RCN_SET_LVL__A       */
+       0x0D, 0x00,             /* EC_OC_REG_RCN_GAI_LVL__A       */
+
+       WRBLOCK(EC_OC_REG_RCN_CLP_LOP__A, 2),
+       0x00, 0x00,             /* EC_OC_REG_RCN_CLP_LOP__A       */
+       0xC0, 0x00,             /* EC_OC_REG_RCN_CLP_HIP__A       */
+
+       WR16(EC_OD_REG_SYNC__A, 0x0664),
+       WR16(EC_OC_REG_OC_MON_SIO__A, 0x0000),
+       WR16(EC_OC_REG_SNC_ISC_LVL__A, 0x0D0C),
+       /* Output zero on monitorbus pads, power saving */
+       WR16(EC_OC_REG_OCR_MON_UOS__A,
+            (EC_OC_REG_OCR_MON_UOS_DAT_0_ENABLE |
+             EC_OC_REG_OCR_MON_UOS_DAT_1_ENABLE |
+             EC_OC_REG_OCR_MON_UOS_DAT_2_ENABLE |
+             EC_OC_REG_OCR_MON_UOS_DAT_3_ENABLE |
+             EC_OC_REG_OCR_MON_UOS_DAT_4_ENABLE |
+             EC_OC_REG_OCR_MON_UOS_DAT_5_ENABLE |
+             EC_OC_REG_OCR_MON_UOS_DAT_6_ENABLE |
+             EC_OC_REG_OCR_MON_UOS_DAT_7_ENABLE |
+             EC_OC_REG_OCR_MON_UOS_DAT_8_ENABLE |
+             EC_OC_REG_OCR_MON_UOS_DAT_9_ENABLE |
+             EC_OC_REG_OCR_MON_UOS_VAL_ENABLE |
+             EC_OC_REG_OCR_MON_UOS_CLK_ENABLE)),
+       WR16(EC_OC_REG_OCR_MON_WRI__A,
+            EC_OC_REG_OCR_MON_WRI_INIT),
+
+/*   CHK_ERROR(ResetECRAM(demod)); */
+       /* Reset packet sync bytes in EC_VD ram */
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (0 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (1 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (2 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (3 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (4 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (5 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (6 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (7 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (8 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (9 * 17), 0x0000),
+       WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (10 * 17), 0x0000),
+
+       /* Reset packet sync bytes in EC_RS ram */
+       WR16(EC_RS_EC_RAM__A, 0x0000),
+       WR16(EC_RS_EC_RAM__A + 204, 0x0000),
+
+       WR16(EC_OD_REG_COMM_EXEC__A, 0x0001),
+       END_OF_TABLE
+};
+
+u8 DRXD_InitSC[] = {
+       WR16(SC_COMM_EXEC__A, 0),
+       WR16(SC_COMM_STATE__A, 0),
+
+#ifdef COMPILE_FOR_QT
+       WR16(SC_RA_RAM_BE_OPT_DELAY__A, 0x100),
+#endif
+
+       /* SC is not started, this is done in SetChannels() */
+       END_OF_TABLE
+};
+
+/* Diversity settings */
+
+u8 DRXD_InitDiversityFront[] = {
+       /* Start demod ********* RF in , diversity out **************************** */
+       WR16(B_SC_RA_RAM_CONFIG__A, B_SC_RA_RAM_CONFIG_FR_ENABLE__M |
+            B_SC_RA_RAM_CONFIG_FREQSCAN__M),
+
+       WR16(B_SC_RA_RAM_LC_ABS_2K__A, 0x7),
+       WR16(B_SC_RA_RAM_LC_ABS_8K__A, 0x7),
+       WR16(B_SC_RA_RAM_IR_COARSE_8K_LENGTH__A, IRLEN_COARSE_8K),
+       WR16(B_SC_RA_RAM_IR_COARSE_8K_FREQINC__A, 1 << (11 - IRLEN_COARSE_8K)),
+       WR16(B_SC_RA_RAM_IR_COARSE_8K_KAISINC__A, 1 << (17 - IRLEN_COARSE_8K)),
+       WR16(B_SC_RA_RAM_IR_FINE_8K_LENGTH__A, IRLEN_FINE_8K),
+       WR16(B_SC_RA_RAM_IR_FINE_8K_FREQINC__A, 1 << (11 - IRLEN_FINE_8K)),
+       WR16(B_SC_RA_RAM_IR_FINE_8K_KAISINC__A, 1 << (17 - IRLEN_FINE_8K)),
+
+       WR16(B_SC_RA_RAM_IR_COARSE_2K_LENGTH__A, IRLEN_COARSE_2K),
+       WR16(B_SC_RA_RAM_IR_COARSE_2K_FREQINC__A, 1 << (11 - IRLEN_COARSE_2K)),
+       WR16(B_SC_RA_RAM_IR_COARSE_2K_KAISINC__A, 1 << (17 - IRLEN_COARSE_2K)),
+       WR16(B_SC_RA_RAM_IR_FINE_2K_LENGTH__A, IRLEN_FINE_2K),
+       WR16(B_SC_RA_RAM_IR_FINE_2K_FREQINC__A, 1 << (11 - IRLEN_FINE_2K)),
+       WR16(B_SC_RA_RAM_IR_FINE_2K_KAISINC__A, 1 << (17 - IRLEN_FINE_2K)),
+
+       WR16(B_LC_RA_RAM_FILTER_CRMM_A__A, 7),
+       WR16(B_LC_RA_RAM_FILTER_CRMM_B__A, 4),
+       WR16(B_LC_RA_RAM_FILTER_SRMM_A__A, 7),
+       WR16(B_LC_RA_RAM_FILTER_SRMM_B__A, 4),
+       WR16(B_LC_RA_RAM_FILTER_SYM_SET__A, 500),
+
+       WR16(B_CC_REG_DIVERSITY__A, 0x0001),
+       WR16(B_EC_OC_REG_OC_MODE_HIP__A, 0x0010),
+       WR16(B_EQ_REG_RC_SEL_CAR__A, B_EQ_REG_RC_SEL_CAR_PASS_B_CE |
+            B_EQ_REG_RC_SEL_CAR_LOCAL_B_CE | B_EQ_REG_RC_SEL_CAR_MEAS_B_CE),
+
+       /*    0x2a ), *//* CE to PASS mux */
+
+       END_OF_TABLE
+};
+
+u8 DRXD_InitDiversityEnd[] = {
+       /* End demod *********** combining RF in and diversity in, MPEG TS out **** */
+       /* disable near/far; switch on timing slave mode */
+       WR16(B_SC_RA_RAM_CONFIG__A, B_SC_RA_RAM_CONFIG_FR_ENABLE__M |
+            B_SC_RA_RAM_CONFIG_FREQSCAN__M |
+            B_SC_RA_RAM_CONFIG_DIV_ECHO_ENABLE__M |
+            B_SC_RA_RAM_CONFIG_SLAVE__M |
+            B_SC_RA_RAM_CONFIG_DIV_BLANK_ENABLE__M
+/* MV from CtrlDiversity */
+           ),
+#ifdef DRXDDIV_SRMM_SLAVING
+       WR16(SC_RA_RAM_LC_ABS_2K__A, 0x3c7),
+       WR16(SC_RA_RAM_LC_ABS_8K__A, 0x3c7),
+#else
+       WR16(SC_RA_RAM_LC_ABS_2K__A, 0x7),
+       WR16(SC_RA_RAM_LC_ABS_8K__A, 0x7),
+#endif
+
+       WR16(B_SC_RA_RAM_IR_COARSE_8K_LENGTH__A, IRLEN_COARSE_8K),
+       WR16(B_SC_RA_RAM_IR_COARSE_8K_FREQINC__A, 1 << (11 - IRLEN_COARSE_8K)),
+       WR16(B_SC_RA_RAM_IR_COARSE_8K_KAISINC__A, 1 << (17 - IRLEN_COARSE_8K)),
+       WR16(B_SC_RA_RAM_IR_FINE_8K_LENGTH__A, IRLEN_FINE_8K),
+       WR16(B_SC_RA_RAM_IR_FINE_8K_FREQINC__A, 1 << (11 - IRLEN_FINE_8K)),
+       WR16(B_SC_RA_RAM_IR_FINE_8K_KAISINC__A, 1 << (17 - IRLEN_FINE_8K)),
+
+       WR16(B_SC_RA_RAM_IR_COARSE_2K_LENGTH__A, IRLEN_COARSE_2K),
+       WR16(B_SC_RA_RAM_IR_COARSE_2K_FREQINC__A, 1 << (11 - IRLEN_COARSE_2K)),
+       WR16(B_SC_RA_RAM_IR_COARSE_2K_KAISINC__A, 1 << (17 - IRLEN_COARSE_2K)),
+       WR16(B_SC_RA_RAM_IR_FINE_2K_LENGTH__A, IRLEN_FINE_2K),
+       WR16(B_SC_RA_RAM_IR_FINE_2K_FREQINC__A, 1 << (11 - IRLEN_FINE_2K)),
+       WR16(B_SC_RA_RAM_IR_FINE_2K_KAISINC__A, 1 << (17 - IRLEN_FINE_2K)),
+
+       WR16(B_LC_RA_RAM_FILTER_CRMM_A__A, 7),
+       WR16(B_LC_RA_RAM_FILTER_CRMM_B__A, 4),
+       WR16(B_LC_RA_RAM_FILTER_SRMM_A__A, 7),
+       WR16(B_LC_RA_RAM_FILTER_SRMM_B__A, 4),
+       WR16(B_LC_RA_RAM_FILTER_SYM_SET__A, 500),
+
+       WR16(B_CC_REG_DIVERSITY__A, 0x0001),
+       END_OF_TABLE
+};
+
+u8 DRXD_DisableDiversity[] = {
+       WR16(B_SC_RA_RAM_LC_ABS_2K__A, B_SC_RA_RAM_LC_ABS_2K__PRE),
+       WR16(B_SC_RA_RAM_LC_ABS_8K__A, B_SC_RA_RAM_LC_ABS_8K__PRE),
+       WR16(B_SC_RA_RAM_IR_COARSE_8K_LENGTH__A,
+            B_SC_RA_RAM_IR_COARSE_8K_LENGTH__PRE),
+       WR16(B_SC_RA_RAM_IR_COARSE_8K_FREQINC__A,
+            B_SC_RA_RAM_IR_COARSE_8K_FREQINC__PRE),
+       WR16(B_SC_RA_RAM_IR_COARSE_8K_KAISINC__A,
+            B_SC_RA_RAM_IR_COARSE_8K_KAISINC__PRE),
+       WR16(B_SC_RA_RAM_IR_FINE_8K_LENGTH__A,
+            B_SC_RA_RAM_IR_FINE_8K_LENGTH__PRE),
+       WR16(B_SC_RA_RAM_IR_FINE_8K_FREQINC__A,
+            B_SC_RA_RAM_IR_FINE_8K_FREQINC__PRE),
+       WR16(B_SC_RA_RAM_IR_FINE_8K_KAISINC__A,
+            B_SC_RA_RAM_IR_FINE_8K_KAISINC__PRE),
+
+       WR16(B_SC_RA_RAM_IR_COARSE_2K_LENGTH__A,
+            B_SC_RA_RAM_IR_COARSE_2K_LENGTH__PRE),
+       WR16(B_SC_RA_RAM_IR_COARSE_2K_FREQINC__A,
+            B_SC_RA_RAM_IR_COARSE_2K_FREQINC__PRE),
+       WR16(B_SC_RA_RAM_IR_COARSE_2K_KAISINC__A,
+            B_SC_RA_RAM_IR_COARSE_2K_KAISINC__PRE),
+       WR16(B_SC_RA_RAM_IR_FINE_2K_LENGTH__A,
+            B_SC_RA_RAM_IR_FINE_2K_LENGTH__PRE),
+       WR16(B_SC_RA_RAM_IR_FINE_2K_FREQINC__A,
+            B_SC_RA_RAM_IR_FINE_2K_FREQINC__PRE),
+       WR16(B_SC_RA_RAM_IR_FINE_2K_KAISINC__A,
+            B_SC_RA_RAM_IR_FINE_2K_KAISINC__PRE),
+
+       WR16(B_LC_RA_RAM_FILTER_CRMM_A__A, B_LC_RA_RAM_FILTER_CRMM_A__PRE),
+       WR16(B_LC_RA_RAM_FILTER_CRMM_B__A, B_LC_RA_RAM_FILTER_CRMM_B__PRE),
+       WR16(B_LC_RA_RAM_FILTER_SRMM_A__A, B_LC_RA_RAM_FILTER_SRMM_A__PRE),
+       WR16(B_LC_RA_RAM_FILTER_SRMM_B__A, B_LC_RA_RAM_FILTER_SRMM_B__PRE),
+       WR16(B_LC_RA_RAM_FILTER_SYM_SET__A, B_LC_RA_RAM_FILTER_SYM_SET__PRE),
+
+       WR16(B_CC_REG_DIVERSITY__A, 0x0000),
+       WR16(B_EQ_REG_RC_SEL_CAR__A, B_EQ_REG_RC_SEL_CAR_INIT), /* combining disabled */
+
+       END_OF_TABLE
+};
+
+u8 DRXD_StartDiversityFront[] = {
+       /* Start demod, RF in and diversity out, no combining */
+       WR16(B_FE_CF_REG_IMP_VAL__A, 0x0),
+       WR16(B_FE_AD_REG_FDB_IN__A, 0x0),
+       WR16(B_FE_AD_REG_INVEXT__A, 0x0),
+       WR16(B_EQ_REG_COMM_MB__A, 0x12),        /* EQ to MB out */
+       WR16(B_EQ_REG_RC_SEL_CAR__A, B_EQ_REG_RC_SEL_CAR_PASS_B_CE |    /* CE to PASS mux */
+            B_EQ_REG_RC_SEL_CAR_LOCAL_B_CE | B_EQ_REG_RC_SEL_CAR_MEAS_B_CE),
+
+       WR16(SC_RA_RAM_ECHO_SHIFT_LIM__A, 2),
+
+       END_OF_TABLE
+};
+
+u8 DRXD_StartDiversityEnd[] = {
+       /* End demod, combining RF in and diversity in, MPEG TS out */
+       WR16(B_FE_CF_REG_IMP_VAL__A, 0x0),      /* disable impulse noise cruncher */
+       WR16(B_FE_AD_REG_INVEXT__A, 0x0),       /* clock inversion (for sohard board) */
+       WR16(B_CP_REG_BR_STR_DEL__A, 10),       /* apperently no mb delay matching is best */
+
+       WR16(B_EQ_REG_RC_SEL_CAR__A, B_EQ_REG_RC_SEL_CAR_DIV_ON |       /* org = 0x81 combining enabled */
+            B_EQ_REG_RC_SEL_CAR_MEAS_A_CC |
+            B_EQ_REG_RC_SEL_CAR_PASS_A_CC | B_EQ_REG_RC_SEL_CAR_LOCAL_A_CC),
+
+       END_OF_TABLE
+};
+
+u8 DRXD_DiversityDelay8MHZ[] = {
+       WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_32__A, 1150 - 50),
+       WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_16__A, 1100 - 50),
+       WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_8__A, 1000 - 50),
+       WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_4__A, 800 - 50),
+       WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_32__A, 5420 - 50),
+       WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_16__A, 5200 - 50),
+       WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_8__A, 4800 - 50),
+       WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_4__A, 4000 - 50),
+       END_OF_TABLE
+};
+
+u8 DRXD_DiversityDelay6MHZ[] = /* also used ok for 7 MHz */
+{
+       WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_32__A, 1100 - 50),
+       WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_16__A, 1000 - 50),
+       WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_8__A, 900 - 50),
+       WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_4__A, 600 - 50),
+       WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_32__A, 5300 - 50),
+       WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_16__A, 5000 - 50),
+       WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_8__A, 4500 - 50),
+       WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_4__A, 3500 - 50),
+       END_OF_TABLE
+};
diff --git a/drivers/media/dvb/frontends/drxd_firm.h b/drivers/media/dvb/frontends/drxd_firm.h
new file mode 100644 (file)
index 0000000..41597e8
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * drxd_firm.h
+ *
+ * Copyright (C) 2006-2007 Micronas
+ *
+ * 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
+ */
+
+#ifndef _DRXD_FIRM_H_
+#define _DRXD_FIRM_H_
+
+#include <linux/types.h>
+#include "drxd_map_firm.h"
+
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 4
+#define VERSION_PATCH 23
+
+#define HI_TR_FUNC_ADDR HI_IF_RAM_USR_BEGIN__A
+
+#define DRXD_MAX_RETRIES (1000)
+#define HI_I2C_DELAY     84
+#define HI_I2C_BRIDGE_DELAY   750
+
+#define EQ_TD_TPS_PWR_UNKNOWN          0x00C0  /* Unknown configurations */
+#define EQ_TD_TPS_PWR_QPSK             0x016a
+#define EQ_TD_TPS_PWR_QAM16_ALPHAN     0x0195
+#define EQ_TD_TPS_PWR_QAM16_ALPHA1     0x0195
+#define EQ_TD_TPS_PWR_QAM16_ALPHA2     0x011E
+#define EQ_TD_TPS_PWR_QAM16_ALPHA4     0x01CE
+#define EQ_TD_TPS_PWR_QAM64_ALPHAN     0x019F
+#define EQ_TD_TPS_PWR_QAM64_ALPHA1     0x019F
+#define EQ_TD_TPS_PWR_QAM64_ALPHA2     0x00F8
+#define EQ_TD_TPS_PWR_QAM64_ALPHA4     0x014D
+
+#define DRXD_DEF_AG_PWD_CONSUMER 0x000E
+#define DRXD_DEF_AG_PWD_PRO 0x0000
+#define DRXD_DEF_AG_AGC_SIO 0x0000
+
+#define DRXD_FE_CTRL_MAX 1023
+
+#define DRXD_OSCDEV_DO_SCAN  (16)
+
+#define DRXD_OSCDEV_DONT_SCAN  (0)
+
+#define DRXD_OSCDEV_STEP  (275)
+
+#define DRXD_SCAN_TIMEOUT    (650)
+
+#define DRXD_BANDWIDTH_8MHZ_IN_HZ  (0x8B8249L)
+#define DRXD_BANDWIDTH_7MHZ_IN_HZ  (0x7A1200L)
+#define DRXD_BANDWIDTH_6MHZ_IN_HZ  (0x68A1B6L)
+
+#define IRLEN_COARSE_8K       (10)
+#define IRLEN_FINE_8K         (10)
+#define IRLEN_COARSE_2K       (7)
+#define IRLEN_FINE_2K         (9)
+#define DIFF_INVALID          (511)
+#define DIFF_TARGET           (4)
+#define DIFF_MARGIN           (1)
+
+extern u8 DRXD_InitAtomicRead[];
+extern u8 DRXD_HiI2cPatch_1[];
+extern u8 DRXD_HiI2cPatch_3[];
+
+extern u8 DRXD_InitSC[];
+
+extern u8 DRXD_ResetCEFR[];
+extern u8 DRXD_InitFEA2_1[];
+extern u8 DRXD_InitFEA2_2[];
+extern u8 DRXD_InitCPA2[];
+extern u8 DRXD_InitCEA2[];
+extern u8 DRXD_InitEQA2[];
+extern u8 DRXD_InitECA2[];
+extern u8 DRXD_ResetECA2[];
+extern u8 DRXD_ResetECRAM[];
+
+extern u8 DRXD_A2_microcode[];
+extern u32 DRXD_A2_microcode_length;
+
+extern u8 DRXD_InitFEB1_1[];
+extern u8 DRXD_InitFEB1_2[];
+extern u8 DRXD_InitCPB1[];
+extern u8 DRXD_InitCEB1[];
+extern u8 DRXD_InitEQB1[];
+extern u8 DRXD_InitECB1[];
+
+extern u8 DRXD_InitDiversityFront[];
+extern u8 DRXD_InitDiversityEnd[];
+extern u8 DRXD_DisableDiversity[];
+extern u8 DRXD_StartDiversityFront[];
+extern u8 DRXD_StartDiversityEnd[];
+
+extern u8 DRXD_DiversityDelay8MHZ[];
+extern u8 DRXD_DiversityDelay6MHZ[];
+
+extern u8 DRXD_B1_microcode[];
+extern u32 DRXD_B1_microcode_length;
+
+#endif
diff --git a/drivers/media/dvb/frontends/drxd_hard.c b/drivers/media/dvb/frontends/drxd_hard.c
new file mode 100644 (file)
index 0000000..ea4c1c3
--- /dev/null
@@ -0,0 +1,3001 @@
+/*
+ * drxd_hard.c: DVB-T Demodulator Micronas DRX3975D-A2,DRX397xD-B1
+ *
+ * Copyright (C) 2003-2007 Micronas
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/version.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "drxd.h"
+#include "drxd_firm.h"
+
+#define DRX_FW_FILENAME_A2 "drxd-a2-1.1.fw"
+#define DRX_FW_FILENAME_B1 "drxd-b1-1.1.fw"
+
+#define CHUNK_SIZE 48
+
+#define DRX_I2C_RMW           0x10
+#define DRX_I2C_BROADCAST     0x20
+#define DRX_I2C_CLEARCRC      0x80
+#define DRX_I2C_SINGLE_MASTER 0xC0
+#define DRX_I2C_MODEFLAGS     0xC0
+#define DRX_I2C_FLAGS         0xF0
+
+#ifndef SIZEOF_ARRAY
+#define SIZEOF_ARRAY(array) (sizeof((array))/sizeof((array)[0]))
+#endif
+
+#define DEFAULT_LOCK_TIMEOUT    1100
+
+#define DRX_CHANNEL_AUTO 0
+#define DRX_CHANNEL_HIGH 1
+#define DRX_CHANNEL_LOW  2
+
+#define DRX_LOCK_MPEG  1
+#define DRX_LOCK_FEC   2
+#define DRX_LOCK_DEMOD 4
+
+/****************************************************************************/
+
+enum CSCDState {
+       CSCD_INIT = 0,
+       CSCD_SET,
+       CSCD_SAVED
+};
+
+enum CDrxdState {
+       DRXD_UNINITIALIZED = 0,
+       DRXD_STOPPED,
+       DRXD_STARTED
+};
+
+enum AGC_CTRL_MODE {
+       AGC_CTRL_AUTO = 0,
+       AGC_CTRL_USER,
+       AGC_CTRL_OFF
+};
+
+enum OperationMode {
+       OM_Default,
+       OM_DVBT_Diversity_Front,
+       OM_DVBT_Diversity_End
+};
+
+struct SCfgAgc {
+       enum AGC_CTRL_MODE ctrlMode;
+       u16 outputLevel;        /* range [0, ... , 1023], 1/n of fullscale range */
+       u16 settleLevel;        /* range [0, ... , 1023], 1/n of fullscale range */
+       u16 minOutputLevel;     /* range [0, ... , 1023], 1/n of fullscale range */
+       u16 maxOutputLevel;     /* range [0, ... , 1023], 1/n of fullscale range */
+       u16 speed;              /* range [0, ... , 1023], 1/n of fullscale range */
+
+       u16 R1;
+       u16 R2;
+       u16 R3;
+};
+
+struct SNoiseCal {
+       int cpOpt;
+       u16 cpNexpOfs;
+       u16 tdCal2k;
+       u16 tdCal8k;
+};
+
+enum app_env {
+       APPENV_STATIC = 0,
+       APPENV_PORTABLE = 1,
+       APPENV_MOBILE = 2
+};
+
+enum EIFFilter {
+       IFFILTER_SAW = 0,
+       IFFILTER_DISCRETE = 1
+};
+
+struct drxd_state {
+       struct dvb_frontend frontend;
+       struct dvb_frontend_ops ops;
+       struct dvb_frontend_parameters param;
+
+       const struct firmware *fw;
+       struct device *dev;
+
+       struct i2c_adapter *i2c;
+       void *priv;
+       struct drxd_config config;
+
+       int i2c_access;
+       int init_done;
+       struct mutex mutex;
+
+       u8 chip_adr;
+       u16 hi_cfg_timing_div;
+       u16 hi_cfg_bridge_delay;
+       u16 hi_cfg_wakeup_key;
+       u16 hi_cfg_ctrl;
+
+       u16 intermediate_freq;
+       u16 osc_clock_freq;
+
+       enum CSCDState cscd_state;
+       enum CDrxdState drxd_state;
+
+       u16 sys_clock_freq;
+       s16 osc_clock_deviation;
+       u16 expected_sys_clock_freq;
+
+       u16 insert_rs_byte;
+       u16 enable_parallel;
+
+       int operation_mode;
+
+       struct SCfgAgc if_agc_cfg;
+       struct SCfgAgc rf_agc_cfg;
+
+       struct SNoiseCal noise_cal;
+
+       u32 fe_fs_add_incr;
+       u32 org_fe_fs_add_incr;
+       u16 current_fe_if_incr;
+
+       u16 m_FeAgRegAgPwd;
+       u16 m_FeAgRegAgAgcSio;
+
+       u16 m_EcOcRegOcModeLop;
+       u16 m_EcOcRegSncSncLvl;
+       u8 *m_InitAtomicRead;
+       u8 *m_HiI2cPatch;
+
+       u8 *m_ResetCEFR;
+       u8 *m_InitFE_1;
+       u8 *m_InitFE_2;
+       u8 *m_InitCP;
+       u8 *m_InitCE;
+       u8 *m_InitEQ;
+       u8 *m_InitSC;
+       u8 *m_InitEC;
+       u8 *m_ResetECRAM;
+       u8 *m_InitDiversityFront;
+       u8 *m_InitDiversityEnd;
+       u8 *m_DisableDiversity;
+       u8 *m_StartDiversityFront;
+       u8 *m_StartDiversityEnd;
+
+       u8 *m_DiversityDelay8MHZ;
+       u8 *m_DiversityDelay6MHZ;
+
+       u8 *microcode;
+       u32 microcode_length;
+
+       int type_A;
+       int PGA;
+       int diversity;
+       int tuner_mirrors;
+
+       enum app_env app_env_default;
+       enum app_env app_env_diversity;
+
+};
+
+/****************************************************************************/
+/* I2C **********************************************************************/
+/****************************************************************************/
+
+static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 * data, int len)
+{
+       struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len };
+
+       if (i2c_transfer(adap, &msg, 1) != 1)
+               return -1;
+       return 0;
+}
+
+static int i2c_read(struct i2c_adapter *adap,
+                   u8 adr, u8 *msg, int len, u8 *answ, int alen)
+{
+       struct i2c_msg msgs[2] = {
+               {
+                       .addr = adr, .flags = 0,
+                       .buf = msg, .len = len
+               }, {
+                       .addr = adr, .flags = I2C_M_RD,
+                       .buf = answ, .len = alen
+               }
+       };
+       if (i2c_transfer(adap, msgs, 2) != 2)
+               return -1;
+       return 0;
+}
+
+inline u32 MulDiv32(u32 a, u32 b, u32 c)
+{
+       u64 tmp64;
+
+       tmp64 = (u64)a * (u64)b;
+       do_div(tmp64, c);
+
+       return (u32) tmp64;
+}
+
+static int Read16(struct drxd_state *state, u32 reg, u16 *data, u8 flags)
+{
+       u8 adr = state->config.demod_address;
+       u8 mm1[4] = { reg & 0xff, (reg >> 16) & 0xff,
+               flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff
+       };
+       u8 mm2[2];
+       if (i2c_read(state->i2c, adr, mm1, 4, mm2, 2) < 0)
+               return -1;
+       if (data)
+               *data = mm2[0] | (mm2[1] << 8);
+       return mm2[0] | (mm2[1] << 8);
+}
+
+static int Read32(struct drxd_state *state, u32 reg, u32 *data, u8 flags)
+{
+       u8 adr = state->config.demod_address;
+       u8 mm1[4] = { reg & 0xff, (reg >> 16) & 0xff,
+               flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff
+       };
+       u8 mm2[4];
+
+       if (i2c_read(state->i2c, adr, mm1, 4, mm2, 4) < 0)
+               return -1;
+       if (data)
+               *data =
+                   mm2[0] | (mm2[1] << 8) | (mm2[2] << 16) | (mm2[3] << 24);
+       return 0;
+}
+
+static int Write16(struct drxd_state *state, u32 reg, u16 data, u8 flags)
+{
+       u8 adr = state->config.demod_address;
+       u8 mm[6] = { reg & 0xff, (reg >> 16) & 0xff,
+               flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff,
+               data & 0xff, (data >> 8) & 0xff
+       };
+
+       if (i2c_write(state->i2c, adr, mm, 6) < 0)
+               return -1;
+       return 0;
+}
+
+static int Write32(struct drxd_state *state, u32 reg, u32 data, u8 flags)
+{
+       u8 adr = state->config.demod_address;
+       u8 mm[8] = { reg & 0xff, (reg >> 16) & 0xff,
+               flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff,
+               data & 0xff, (data >> 8) & 0xff,
+               (data >> 16) & 0xff, (data >> 24) & 0xff
+       };
+
+       if (i2c_write(state->i2c, adr, mm, 8) < 0)
+               return -1;
+       return 0;
+}
+
+static int write_chunk(struct drxd_state *state,
+                      u32 reg, u8 *data, u32 len, u8 flags)
+{
+       u8 adr = state->config.demod_address;
+       u8 mm[CHUNK_SIZE + 4] = { reg & 0xff, (reg >> 16) & 0xff,
+               flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff
+       };
+       int i;
+
+       for (i = 0; i < len; i++)
+               mm[4 + i] = data[i];
+       if (i2c_write(state->i2c, adr, mm, 4 + len) < 0) {
+               printk(KERN_ERR "error in write_chunk\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int WriteBlock(struct drxd_state *state,
+                     u32 Address, u16 BlockSize, u8 *pBlock, u8 Flags)
+{
+       while (BlockSize > 0) {
+               u16 Chunk = BlockSize > CHUNK_SIZE ? CHUNK_SIZE : BlockSize;
+
+               if (write_chunk(state, Address, pBlock, Chunk, Flags) < 0)
+                       return -1;
+               pBlock += Chunk;
+               Address += (Chunk >> 1);
+               BlockSize -= Chunk;
+       }
+       return 0;
+}
+
+static int WriteTable(struct drxd_state *state, u8 * pTable)
+{
+       int status = 0;
+
+       if (pTable == NULL)
+               return 0;
+
+       while (!status) {
+               u16 Length;
+               u32 Address = pTable[0] | (pTable[1] << 8) |
+                   (pTable[2] << 16) | (pTable[3] << 24);
+
+               if (Address == 0xFFFFFFFF)
+                       break;
+               pTable += sizeof(u32);
+
+               Length = pTable[0] | (pTable[1] << 8);
+               pTable += sizeof(u16);
+               if (!Length)
+                       break;
+               status = WriteBlock(state, Address, Length * 2, pTable, 0);
+               pTable += (Length * 2);
+       }
+       return status;
+}
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+static int ResetCEFR(struct drxd_state *state)
+{
+       return WriteTable(state, state->m_ResetCEFR);
+}
+
+static int InitCP(struct drxd_state *state)
+{
+       return WriteTable(state, state->m_InitCP);
+}
+
+static int InitCE(struct drxd_state *state)
+{
+       int status;
+       enum app_env AppEnv = state->app_env_default;
+
+       do {
+               status = WriteTable(state, state->m_InitCE);
+               if (status < 0)
+                       break;
+
+               if (state->operation_mode == OM_DVBT_Diversity_Front ||
+                   state->operation_mode == OM_DVBT_Diversity_End) {
+                       AppEnv = state->app_env_diversity;
+               }
+               if (AppEnv == APPENV_STATIC) {
+                       status = Write16(state, CE_REG_TAPSET__A, 0x0000, 0);
+                       if (status < 0)
+                               break;
+               } else if (AppEnv == APPENV_PORTABLE) {
+                       status = Write16(state, CE_REG_TAPSET__A, 0x0001, 0);
+                       if (status < 0)
+                               break;
+               } else if (AppEnv == APPENV_MOBILE && state->type_A) {
+                       status = Write16(state, CE_REG_TAPSET__A, 0x0002, 0);
+                       if (status < 0)
+                               break;
+               } else if (AppEnv == APPENV_MOBILE && !state->type_A) {
+                       status = Write16(state, CE_REG_TAPSET__A, 0x0006, 0);
+                       if (status < 0)
+                               break;
+               }
+
+               /* start ce */
+               status = Write16(state, B_CE_REG_COMM_EXEC__A, 0x0001, 0);
+               if (status < 0)
+                       break;
+       } while (0);
+       return status;
+}
+
+static int StopOC(struct drxd_state *state)
+{
+       int status = 0;
+       u16 ocSyncLvl = 0;
+       u16 ocModeLop = state->m_EcOcRegOcModeLop;
+       u16 dtoIncLop = 0;
+       u16 dtoIncHip = 0;
+
+       do {
+               /* Store output configuration */
+               status = Read16(state, EC_OC_REG_SNC_ISC_LVL__A, &ocSyncLvl, 0);
+               if (status < 0)
+                       break;
+               /* CHK_ERROR(Read16(EC_OC_REG_OC_MODE_LOP__A, &ocModeLop)); */
+               state->m_EcOcRegSncSncLvl = ocSyncLvl;
+               /* m_EcOcRegOcModeLop = ocModeLop; */
+
+               /* Flush FIFO (byte-boundary) at fixed rate */
+               status = Read16(state, EC_OC_REG_RCN_MAP_LOP__A, &dtoIncLop, 0);
+               if (status < 0)
+                       break;
+               status = Read16(state, EC_OC_REG_RCN_MAP_HIP__A, &dtoIncHip, 0);
+               if (status < 0)
+                       break;
+               status = Write16(state, EC_OC_REG_DTO_INC_LOP__A, dtoIncLop, 0);
+               if (status < 0)
+                       break;
+               status = Write16(state, EC_OC_REG_DTO_INC_HIP__A, dtoIncHip, 0);
+               if (status < 0)
+                       break;
+               ocModeLop &= ~(EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC__M);
+               ocModeLop |= EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC_STATIC;
+               status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, ocModeLop, 0);
+               if (status < 0)
+                       break;
+               status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_HOLD, 0);
+               if (status < 0)
+                       break;
+
+               msleep(1);
+               /* Output pins to '0' */
+               status = Write16(state, EC_OC_REG_OCR_MPG_UOS__A, EC_OC_REG_OCR_MPG_UOS__M, 0);
+               if (status < 0)
+                       break;
+
+               /* Force the OC out of sync */
+               ocSyncLvl &= ~(EC_OC_REG_SNC_ISC_LVL_OSC__M);
+               status = Write16(state, EC_OC_REG_SNC_ISC_LVL__A, ocSyncLvl, 0);
+               if (status < 0)
+                       break;
+               ocModeLop &= ~(EC_OC_REG_OC_MODE_LOP_PAR_ENA__M);
+               ocModeLop |= EC_OC_REG_OC_MODE_LOP_PAR_ENA_ENABLE;
+               ocModeLop |= 0x2;       /* Magically-out-of-sync */
+               status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, ocModeLop, 0);
+               if (status < 0)
+                       break;
+               status = Write16(state, EC_OC_REG_COMM_INT_STA__A, 0x0, 0);
+               if (status < 0)
+                       break;
+               status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_ACTIVE, 0);
+               if (status < 0)
+                       break;
+       } while (0);
+
+       return status;
+}
+
+static int StartOC(struct drxd_state *state)
+{
+       int status = 0;
+
+       do {
+               /* Stop OC */
+               status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_HOLD, 0);
+               if (status < 0)
+                       break;
+
+               /* Restore output configuration */
+               status = Write16(state, EC_OC_REG_SNC_ISC_LVL__A, state->m_EcOcRegSncSncLvl, 0);
+               if (status < 0)
+                       break;
+               status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, state->m_EcOcRegOcModeLop, 0);
+               if (status < 0)
+                       break;
+
+               /* Output pins active again */
+               status = Write16(state, EC_OC_REG_OCR_MPG_UOS__A, EC_OC_REG_OCR_MPG_UOS_INIT, 0);
+               if (status < 0)
+                       break;
+
+               /* Start OC */
+               status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_ACTIVE, 0);
+               if (status < 0)
+                       break;
+       } while (0);
+       return status;
+}
+
+static int InitEQ(struct drxd_state *state)
+{
+       return WriteTable(state, state->m_InitEQ);
+}
+
+static int InitEC(struct drxd_state *state)
+{
+       return WriteTable(state, state->m_InitEC);
+}
+
+static int InitSC(struct drxd_state *state)
+{
+       return WriteTable(state, state->m_InitSC);
+}
+
+static int InitAtomicRead(struct drxd_state *state)
+{
+       return WriteTable(state, state->m_InitAtomicRead);
+}
+
+static int CorrectSysClockDeviation(struct drxd_state *state);
+
+static int DRX_GetLockStatus(struct drxd_state *state, u32 * pLockStatus)
+{
+       u16 ScRaRamLock = 0;
+       const u16 mpeg_lock_mask = (SC_RA_RAM_LOCK_MPEG__M |
+                                   SC_RA_RAM_LOCK_FEC__M |
+                                   SC_RA_RAM_LOCK_DEMOD__M);
+       const u16 fec_lock_mask = (SC_RA_RAM_LOCK_FEC__M |
+                                  SC_RA_RAM_LOCK_DEMOD__M);
+       const u16 demod_lock_mask = SC_RA_RAM_LOCK_DEMOD__M;
+
+       int status;
+
+       *pLockStatus = 0;
+
+       status = Read16(state, SC_RA_RAM_LOCK__A, &ScRaRamLock, 0x0000);
+       if (status < 0) {
+               printk(KERN_ERR "Can't read SC_RA_RAM_LOCK__A status = %08x\n", status);
+               return status;
+       }
+
+       if (state->drxd_state != DRXD_STARTED)
+               return 0;
+
+       if ((ScRaRamLock & mpeg_lock_mask) == mpeg_lock_mask) {
+               *pLockStatus |= DRX_LOCK_MPEG;
+               CorrectSysClockDeviation(state);
+       }
+
+       if ((ScRaRamLock & fec_lock_mask) == fec_lock_mask)
+               *pLockStatus |= DRX_LOCK_FEC;
+
+       if ((ScRaRamLock & demod_lock_mask) == demod_lock_mask)
+               *pLockStatus |= DRX_LOCK_DEMOD;
+       return 0;
+}
+
+/****************************************************************************/
+
+static int SetCfgIfAgc(struct drxd_state *state, struct SCfgAgc *cfg)
+{
+       int status;
+
+       if (cfg->outputLevel > DRXD_FE_CTRL_MAX)
+               return -1;
+
+       if (cfg->ctrlMode == AGC_CTRL_USER) {
+               do {
+                       u16 FeAgRegPm1AgcWri;
+                       u16 FeAgRegAgModeLop;
+
+                       status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &FeAgRegAgModeLop, 0);
+                       if (status < 0)
+                               break;
+                       FeAgRegAgModeLop &= (~FE_AG_REG_AG_MODE_LOP_MODE_4__M);
+                       FeAgRegAgModeLop |= FE_AG_REG_AG_MODE_LOP_MODE_4_STATIC;
+                       status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, FeAgRegAgModeLop, 0);
+                       if (status < 0)
+                               break;
+
+                       FeAgRegPm1AgcWri = (u16) (cfg->outputLevel &
+                                                 FE_AG_REG_PM1_AGC_WRI__M);
+                       status = Write16(state, FE_AG_REG_PM1_AGC_WRI__A, FeAgRegPm1AgcWri, 0);
+                       if (status < 0)
+                               break;
+               } while (0);
+       } else if (cfg->ctrlMode == AGC_CTRL_AUTO) {
+               if (((cfg->maxOutputLevel) < (cfg->minOutputLevel)) ||
+                   ((cfg->maxOutputLevel) > DRXD_FE_CTRL_MAX) ||
+                   ((cfg->speed) > DRXD_FE_CTRL_MAX) ||
+                   ((cfg->settleLevel) > DRXD_FE_CTRL_MAX)
+                   )
+                       return -1;
+               do {
+                       u16 FeAgRegAgModeLop;
+                       u16 FeAgRegEgcSetLvl;
+                       u16 slope, offset;
+
+                       /* == Mode == */
+
+                       status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &FeAgRegAgModeLop, 0);
+                       if (status < 0)
+                               break;
+                       FeAgRegAgModeLop &= (~FE_AG_REG_AG_MODE_LOP_MODE_4__M);
+                       FeAgRegAgModeLop |=
+                           FE_AG_REG_AG_MODE_LOP_MODE_4_DYNAMIC;
+                       status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, FeAgRegAgModeLop, 0);
+                       if (status < 0)
+                               break;
+
+                       /* == Settle level == */
+
+                       FeAgRegEgcSetLvl = (u16) ((cfg->settleLevel >> 1) &
+                                                 FE_AG_REG_EGC_SET_LVL__M);
+                       status = Write16(state, FE_AG_REG_EGC_SET_LVL__A, FeAgRegEgcSetLvl, 0);
+                       if (status < 0)
+                               break;
+
+                       /* == Min/Max == */
+
+                       slope = (u16) ((cfg->maxOutputLevel -
+                                       cfg->minOutputLevel) / 2);
+                       offset = (u16) ((cfg->maxOutputLevel +
+                                        cfg->minOutputLevel) / 2 - 511);
+
+                       status = Write16(state, FE_AG_REG_GC1_AGC_RIC__A, slope, 0);
+                       if (status < 0)
+                               break;
+                       status = Write16(state, FE_AG_REG_GC1_AGC_OFF__A, offset, 0);
+                       if (status < 0)
+                               break;
+
+                       /* == Speed == */
+                       {
+                               const u16 maxRur = 8;
+                               const u16 slowIncrDecLUT[] = { 3, 4, 4, 5, 6 };
+                               const u16 fastIncrDecLUT[] = { 14, 15, 15, 16,
+                                       17, 18, 18, 19,
+                                       20, 21, 22, 23,
+                                       24, 26, 27, 28,
+                                       29, 31
+                               };
+
+                               u16 fineSteps = (DRXD_FE_CTRL_MAX + 1) /
+                                   (maxRur + 1);
+                               u16 fineSpeed = (u16) (cfg->speed -
+                                                      ((cfg->speed /
+                                                        fineSteps) *
+                                                       fineSteps));
+                               u16 invRurCount = (u16) (cfg->speed /
+                                                        fineSteps);
+                               u16 rurCount;
+                               if (invRurCount > maxRur) {
+                                       rurCount = 0;
+                                       fineSpeed += fineSteps;
+                               } else {
+                                       rurCount = maxRur - invRurCount;
+                               }
+
+                               /*
+                                  fastInc = default *
+                                  (2^(fineSpeed/fineSteps))
+                                  => range[default...2*default>
+                                  slowInc = default *
+                                  (2^(fineSpeed/fineSteps))
+                                */
+                               {
+                                       u16 fastIncrDec =
+                                           fastIncrDecLUT[fineSpeed /
+                                                          ((fineSteps /
+                                                            (14 + 1)) + 1)];
+                                       u16 slowIncrDec =
+                                           slowIncrDecLUT[fineSpeed /
+                                                          (fineSteps /
+                                                           (3 + 1))];
+
+                                       status = Write16(state, FE_AG_REG_EGC_RUR_CNT__A, rurCount, 0);
+                                       if (status < 0)
+                                               break;
+                                       status = Write16(state, FE_AG_REG_EGC_FAS_INC__A, fastIncrDec, 0);
+                                       if (status < 0)
+                                               break;
+                                       status = Write16(state, FE_AG_REG_EGC_FAS_DEC__A, fastIncrDec, 0);
+                                       if (status < 0)
+                                               break;
+                                       status = Write16(state, FE_AG_REG_EGC_SLO_INC__A, slowIncrDec, 0);
+                                       if (status < 0)
+                                               break;
+                                       status = Write16(state, FE_AG_REG_EGC_SLO_DEC__A, slowIncrDec, 0);
+                                       if (status < 0)
+                                               break;
+                               }
+                       }
+               } while (0);
+
+       } else {
+               /* No OFF mode for IF control */
+               return -1;
+       }
+       return status;
+}
+
+static int SetCfgRfAgc(struct drxd_state *state, struct SCfgAgc *cfg)
+{
+       int status = 0;
+
+       if (cfg->outputLevel > DRXD_FE_CTRL_MAX)
+               return -1;
+
+       if (cfg->ctrlMode == AGC_CTRL_USER) {
+               do {
+                       u16 AgModeLop = 0;
+                       u16 level = (cfg->outputLevel);
+
+                       if (level == DRXD_FE_CTRL_MAX)
+                               level++;
+
+                       status = Write16(state, FE_AG_REG_PM2_AGC_WRI__A, level, 0x0000);
+                       if (status < 0)
+                               break;
+
+                       /*==== Mode ====*/
+
+                       /* Powerdown PD2, WRI source */
+                       state->m_FeAgRegAgPwd &= ~(FE_AG_REG_AG_PWD_PWD_PD2__M);
+                       state->m_FeAgRegAgPwd |=
+                           FE_AG_REG_AG_PWD_PWD_PD2_DISABLE;
+                       status = Write16(state, FE_AG_REG_AG_PWD__A, state->m_FeAgRegAgPwd, 0x0000);
+                       if (status < 0)
+                               break;
+
+                       status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
+                       if (status < 0)
+                               break;
+                       AgModeLop &= (~(FE_AG_REG_AG_MODE_LOP_MODE_5__M |
+                                       FE_AG_REG_AG_MODE_LOP_MODE_E__M));
+                       AgModeLop |= (FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC |
+                                     FE_AG_REG_AG_MODE_LOP_MODE_E_STATIC);
+                       status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
+                       if (status < 0)
+                               break;
+
+                       /* enable AGC2 pin */
+                       {
+                               u16 FeAgRegAgAgcSio = 0;
+                               status = Read16(state, FE_AG_REG_AG_AGC_SIO__A, &FeAgRegAgAgcSio, 0x0000);
+                               if (status < 0)
+                                       break;
+                               FeAgRegAgAgcSio &=
+                                   ~(FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M);
+                               FeAgRegAgAgcSio |=
+                                   FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_OUTPUT;
+                               status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, FeAgRegAgAgcSio, 0x0000);
+                               if (status < 0)
+                                       break;
+                       }
+
+               } while (0);
+       } else if (cfg->ctrlMode == AGC_CTRL_AUTO) {
+               u16 AgModeLop = 0;
+
+               do {
+                       u16 level;
+                       /* Automatic control */
+                       /* Powerup PD2, AGC2 as output, TGC source */
+                       (state->m_FeAgRegAgPwd) &=
+                           ~(FE_AG_REG_AG_PWD_PWD_PD2__M);
+                       (state->m_FeAgRegAgPwd) |=
+                           FE_AG_REG_AG_PWD_PWD_PD2_DISABLE;
+                       status = Write16(state, FE_AG_REG_AG_PWD__A, (state->m_FeAgRegAgPwd), 0x0000);
+                       if (status < 0)
+                               break;
+
+                       status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
+                       if (status < 0)
+                               break;
+                       AgModeLop &= (~(FE_AG_REG_AG_MODE_LOP_MODE_5__M |
+                                       FE_AG_REG_AG_MODE_LOP_MODE_E__M));
+                       AgModeLop |= (FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC |
+                                     FE_AG_REG_AG_MODE_LOP_MODE_E_DYNAMIC);
+                       status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
+                       if (status < 0)
+                               break;
+                       /* Settle level */
+                       level = (((cfg->settleLevel) >> 4) &
+                                FE_AG_REG_TGC_SET_LVL__M);
+                       status = Write16(state, FE_AG_REG_TGC_SET_LVL__A, level, 0x0000);
+                       if (status < 0)
+                               break;
+
+                       /* Min/max: don't care */
+
+                       /* Speed: TODO */
+
+                       /* enable AGC2 pin */
+                       {
+                               u16 FeAgRegAgAgcSio = 0;
+                               status = Read16(state, FE_AG_REG_AG_AGC_SIO__A, &FeAgRegAgAgcSio, 0x0000);
+                               if (status < 0)
+                                       break;
+                               FeAgRegAgAgcSio &=
+                                   ~(FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M);
+                               FeAgRegAgAgcSio |=
+                                   FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_OUTPUT;
+                               status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, FeAgRegAgAgcSio, 0x0000);
+                               if (status < 0)
+                                       break;
+                       }
+
+               } while (0);
+       } else {
+               u16 AgModeLop = 0;
+
+               do {
+                       /* No RF AGC control */
+                       /* Powerdown PD2, AGC2 as output, WRI source */
+                       (state->m_FeAgRegAgPwd) &=
+                           ~(FE_AG_REG_AG_PWD_PWD_PD2__M);
+                       (state->m_FeAgRegAgPwd) |=
+                           FE_AG_REG_AG_PWD_PWD_PD2_ENABLE;
+                       status = Write16(state, FE_AG_REG_AG_PWD__A, (state->m_FeAgRegAgPwd), 0x0000);
+                       if (status < 0)
+                               break;
+
+                       status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
+                       if (status < 0)
+                               break;
+                       AgModeLop &= (~(FE_AG_REG_AG_MODE_LOP_MODE_5__M |
+                                       FE_AG_REG_AG_MODE_LOP_MODE_E__M));
+                       AgModeLop |= (FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC |
+                                     FE_AG_REG_AG_MODE_LOP_MODE_E_STATIC);
+                       status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
+                       if (status < 0)
+                               break;
+
+                       /* set FeAgRegAgAgcSio AGC2 (RF) as input */
+                       {
+                               u16 FeAgRegAgAgcSio = 0;
+                               status = Read16(state, FE_AG_REG_AG_AGC_SIO__A, &FeAgRegAgAgcSio, 0x0000);
+                               if (status < 0)
+                                       break;
+                               FeAgRegAgAgcSio &=
+                                   ~(FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M);
+                               FeAgRegAgAgcSio |=
+                                   FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_INPUT;
+                               status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, FeAgRegAgAgcSio, 0x0000);
+                               if (status < 0)
+                                       break;
+                       }
+               } while (0);
+       }
+       return status;
+}
+
+static int ReadIFAgc(struct drxd_state *state, u32 * pValue)
+{
+       int status = 0;
+
+       *pValue = 0;
+       if (state->if_agc_cfg.ctrlMode != AGC_CTRL_OFF) {
+               u16 Value;
+               status = Read16(state, FE_AG_REG_GC1_AGC_DAT__A, &Value, 0);
+               Value &= FE_AG_REG_GC1_AGC_DAT__M;
+               if (status >= 0) {
+                       /*           3.3V
+                          |
+                          R1
+                          |
+                          Vin - R3 - * -- Vout
+                          |
+                          R2
+                          |
+                          GND
+                        */
+                       u32 R1 = state->if_agc_cfg.R1;
+                       u32 R2 = state->if_agc_cfg.R2;
+                       u32 R3 = state->if_agc_cfg.R3;
+
+                       u32 Vmax = (3300 * R2) / (R1 + R2);
+                       u32 Rpar = (R2 * R3) / (R3 + R2);
+                       u32 Vmin = (3300 * Rpar) / (R1 + Rpar);
+                       u32 Vout = Vmin + ((Vmax - Vmin) * Value) / 1024;
+
+                       *pValue = Vout;
+               }
+       }
+       return status;
+}
+
+static int load_firmware(struct drxd_state *state, const char *fw_name)
+{
+       const struct firmware *fw;
+
+       if (request_firmware(&fw, fw_name, state->dev) < 0) {
+               printk(KERN_ERR "drxd: firmware load failure [%s]\n", fw_name);
+               return -EIO;
+       }
+
+       state->microcode = kzalloc(fw->size, GFP_KERNEL);
+       if (state->microcode == NULL) {
+               printk(KERN_ERR "drxd: firmware load failure: nomemory\n");
+               return -ENOMEM;
+       }
+
+       memcpy(state->microcode, fw->data, fw->size);
+       state->microcode_length = fw->size;
+       return 0;
+}
+
+static int DownloadMicrocode(struct drxd_state *state,
+                            const u8 *pMCImage, u32 Length)
+{
+       u8 *pSrc;
+       u16 Flags;
+       u32 Address;
+       u16 nBlocks;
+       u16 BlockSize;
+       u16 BlockCRC;
+       u32 offset = 0;
+       int i, status = 0;
+
+       pSrc = (u8 *) pMCImage;
+       Flags = (pSrc[0] << 8) | pSrc[1];
+       pSrc += sizeof(u16);
+       offset += sizeof(u16);
+       nBlocks = (pSrc[0] << 8) | pSrc[1];
+       pSrc += sizeof(u16);
+       offset += sizeof(u16);
+
+       for (i = 0; i < nBlocks; i++) {
+               Address = (pSrc[0] << 24) | (pSrc[1] << 16) |
+                   (pSrc[2] << 8) | pSrc[3];
+               pSrc += sizeof(u32);
+               offset += sizeof(u32);
+
+               BlockSize = ((pSrc[0] << 8) | pSrc[1]) * sizeof(u16);
+               pSrc += sizeof(u16);
+               offset += sizeof(u16);
+
+               Flags = (pSrc[0] << 8) | pSrc[1];
+               pSrc += sizeof(u16);
+               offset += sizeof(u16);
+
+               BlockCRC = (pSrc[0] << 8) | pSrc[1];
+               pSrc += sizeof(u16);
+               offset += sizeof(u16);
+
+               status = WriteBlock(state, Address, BlockSize,
+                                   pSrc, DRX_I2C_CLEARCRC);
+               if (status < 0)
+                       break;
+               pSrc += BlockSize;
+               offset += BlockSize;
+       }
+
+       return status;
+}
+
+static int HI_Command(struct drxd_state *state, u16 cmd, u16 * pResult)
+{
+       u32 nrRetries = 0;
+       u16 waitCmd;
+       int status;
+
+       status = Write16(state, HI_RA_RAM_SRV_CMD__A, cmd, 0);
+       if (status < 0)
+               return status;
+
+       do {
+               nrRetries += 1;
+               if (nrRetries > DRXD_MAX_RETRIES) {
+                       status = -1;
+                       break;
+               };
+               status = Read16(state, HI_RA_RAM_SRV_CMD__A, &waitCmd, 0);
+       } while (waitCmd != 0);
+
+       if (status >= 0)
+               status = Read16(state, HI_RA_RAM_SRV_RES__A, pResult, 0);
+       return status;
+}
+
+static int HI_CfgCommand(struct drxd_state *state)
+{
+       int status = 0;
+
+       mutex_lock(&state->mutex);
+       Write16(state, HI_RA_RAM_SRV_CFG_KEY__A, HI_RA_RAM_SRV_RST_KEY_ACT, 0);
+       Write16(state, HI_RA_RAM_SRV_CFG_DIV__A, state->hi_cfg_timing_div, 0);
+       Write16(state, HI_RA_RAM_SRV_CFG_BDL__A, state->hi_cfg_bridge_delay, 0);
+       Write16(state, HI_RA_RAM_SRV_CFG_WUP__A, state->hi_cfg_wakeup_key, 0);
+       Write16(state, HI_RA_RAM_SRV_CFG_ACT__A, state->hi_cfg_ctrl, 0);
+
+       Write16(state, HI_RA_RAM_SRV_CFG_KEY__A, HI_RA_RAM_SRV_RST_KEY_ACT, 0);
+
+       if ((state->hi_cfg_ctrl & HI_RA_RAM_SRV_CFG_ACT_PWD_EXE) ==
+           HI_RA_RAM_SRV_CFG_ACT_PWD_EXE)
+               status = Write16(state, HI_RA_RAM_SRV_CMD__A,
+                                HI_RA_RAM_SRV_CMD_CONFIG, 0);
+       else
+               status = HI_Command(state, HI_RA_RAM_SRV_CMD_CONFIG, 0);
+       mutex_unlock(&state->mutex);
+       return status;
+}
+
+static int InitHI(struct drxd_state *state)
+{
+       state->hi_cfg_wakeup_key = (state->chip_adr);
+       /* port/bridge/power down ctrl */
+       state->hi_cfg_ctrl = HI_RA_RAM_SRV_CFG_ACT_SLV0_ON;
+       return HI_CfgCommand(state);
+}
+
+static int HI_ResetCommand(struct drxd_state *state)
+{
+       int status;
+
+       mutex_lock(&state->mutex);
+       status = Write16(state, HI_RA_RAM_SRV_RST_KEY__A,
+                        HI_RA_RAM_SRV_RST_KEY_ACT, 0);
+       if (status == 0)
+               status = HI_Command(state, HI_RA_RAM_SRV_CMD_RESET, 0);
+       mutex_unlock(&state->mutex);
+       msleep(1);
+       return status;
+}
+
+static int DRX_ConfigureI2CBridge(struct drxd_state *state, int bEnableBridge)
+{
+       state->hi_cfg_ctrl &= (~HI_RA_RAM_SRV_CFG_ACT_BRD__M);
+       if (bEnableBridge)
+               state->hi_cfg_ctrl |= HI_RA_RAM_SRV_CFG_ACT_BRD_ON;
+       else
+               state->hi_cfg_ctrl |= HI_RA_RAM_SRV_CFG_ACT_BRD_OFF;
+
+       return HI_CfgCommand(state);
+}
+
+#define HI_TR_WRITE      0x9
+#define HI_TR_READ       0xA
+#define HI_TR_READ_WRITE 0xB
+#define HI_TR_BROADCAST  0x4
+
+#if 0
+static int AtomicReadBlock(struct drxd_state *state,
+                          u32 Addr, u16 DataSize, u8 *pData, u8 Flags)
+{
+       int status;
+       int i = 0;
+
+       /* Parameter check */
+       if ((!pData) || ((DataSize & 1) != 0))
+               return -1;
+
+       mutex_lock(&state->mutex);
+
+       do {
+               /* Instruct HI to read n bytes */
+               /* TODO use proper names forthese egisters */
+               status = Write16(state, HI_RA_RAM_SRV_CFG_KEY__A, (HI_TR_FUNC_ADDR & 0xFFFF), 0);
+               if (status < 0)
+                       break;
+               status = Write16(state, HI_RA_RAM_SRV_CFG_DIV__A, (u16) (Addr >> 16), 0);
+               if (status < 0)
+                       break;
+               status = Write16(state, HI_RA_RAM_SRV_CFG_BDL__A, (u16) (Addr & 0xFFFF), 0);
+               if (status < 0)
+                       break;
+               status = Write16(state, HI_RA_RAM_SRV_CFG_WUP__A, (u16) ((DataSize / 2) - 1), 0);
+               if (status < 0)
+                       break;
+               status = Write16(state, HI_RA_RAM_SRV_CFG_ACT__A, HI_TR_READ, 0);
+               if (status < 0)
+                       break;
+
+               status = HI_Command(state, HI_RA_RAM_SRV_CMD_EXECUTE, 0);
+               if (status < 0)
+                       break;
+
+       } while (0);
+
+       if (status >= 0) {
+               for (i = 0; i < (DataSize / 2); i += 1) {
+                       u16 word;
+
+                       status = Read16(state, (HI_RA_RAM_USR_BEGIN__A + i),
+                                       &word, 0);
+                       if (status < 0)
+                               break;
+                       pData[2 * i] = (u8) (word & 0xFF);
+                       pData[(2 * i) + 1] = (u8) (word >> 8);
+               }
+       }
+       mutex_unlock(&state->mutex);
+       return status;
+}
+
+static int AtomicReadReg32(struct drxd_state *state,
+                          u32 Addr, u32 *pData, u8 Flags)
+{
+       u8 buf[sizeof(u32)];
+       int status;
+
+       if (!pData)
+               return -1;
+       status = AtomicReadBlock(state, Addr, sizeof(u32), buf, Flags);
+       *pData = (((u32) buf[0]) << 0) +
+           (((u32) buf[1]) << 8) +
+           (((u32) buf[2]) << 16) + (((u32) buf[3]) << 24);
+       return status;
+}
+#endif
+
+static int StopAllProcessors(struct drxd_state *state)
+{
+       return Write16(state, HI_COMM_EXEC__A,
+                      SC_COMM_EXEC_CTL_STOP, DRX_I2C_BROADCAST);
+}
+
+static int EnableAndResetMB(struct drxd_state *state)
+{
+       if (state->type_A) {
+               /* disable? monitor bus observe @ EC_OC */
+               Write16(state, EC_OC_REG_OC_MON_SIO__A, 0x0000, 0x0000);
+       }
+
+       /* do inverse broadcast, followed by explicit write to HI */
+       Write16(state, HI_COMM_MB__A, 0x0000, DRX_I2C_BROADCAST);
+       Write16(state, HI_COMM_MB__A, 0x0000, 0x0000);
+       return 0;
+}
+
+static int InitCC(struct drxd_state *state)
+{
+       if (state->osc_clock_freq == 0 ||
+           state->osc_clock_freq > 20000 ||
+           (state->osc_clock_freq % 4000) != 0) {
+               printk(KERN_ERR "invalid osc frequency %d\n", state->osc_clock_freq);
+               return -1;
+       }
+
+       Write16(state, CC_REG_OSC_MODE__A, CC_REG_OSC_MODE_M20, 0);
+       Write16(state, CC_REG_PLL_MODE__A, CC_REG_PLL_MODE_BYPASS_PLL |
+               CC_REG_PLL_MODE_PUMP_CUR_12, 0);
+       Write16(state, CC_REG_REF_DIVIDE__A, state->osc_clock_freq / 4000, 0);
+       Write16(state, CC_REG_PWD_MODE__A, CC_REG_PWD_MODE_DOWN_PLL, 0);
+       Write16(state, CC_REG_UPDATE__A, CC_REG_UPDATE_KEY, 0);
+
+       return 0;
+}
+
+static int ResetECOD(struct drxd_state *state)
+{
+       int status = 0;
+
+       if (state->type_A)
+               status = Write16(state, EC_OD_REG_SYNC__A, 0x0664, 0);
+       else
+               status = Write16(state, B_EC_OD_REG_SYNC__A, 0x0664, 0);
+
+       if (!(status < 0))
+               status = WriteTable(state, state->m_ResetECRAM);
+       if (!(status < 0))
+               status = Write16(state, EC_OD_REG_COMM_EXEC__A, 0x0001, 0);
+       return status;
+}
+
+/* Configure PGA switch */
+
+static int SetCfgPga(struct drxd_state *state, int pgaSwitch)
+{
+       int status;
+       u16 AgModeLop = 0;
+       u16 AgModeHip = 0;
+       do {
+               if (pgaSwitch) {
+                       /* PGA on */
+                       /* fine gain */
+                       status = Read16(state, B_FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
+                       if (status < 0)
+                               break;
+                       AgModeLop &= (~(B_FE_AG_REG_AG_MODE_LOP_MODE_C__M));
+                       AgModeLop |= B_FE_AG_REG_AG_MODE_LOP_MODE_C_DYNAMIC;
+                       status = Write16(state, B_FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
+                       if (status < 0)
+                               break;
+
+                       /* coarse gain */
+                       status = Read16(state, B_FE_AG_REG_AG_MODE_HIP__A, &AgModeHip, 0x0000);
+                       if (status < 0)
+                               break;
+                       AgModeHip &= (~(B_FE_AG_REG_AG_MODE_HIP_MODE_J__M));
+                       AgModeHip |= B_FE_AG_REG_AG_MODE_HIP_MODE_J_DYNAMIC;
+                       status = Write16(state, B_FE_AG_REG_AG_MODE_HIP__A, AgModeHip, 0x0000);
+                       if (status < 0)
+                               break;
+
+                       /* enable fine and coarse gain, enable AAF,
+                          no ext resistor */
+                       status = Write16(state, B_FE_AG_REG_AG_PGA_MODE__A, B_FE_AG_REG_AG_PGA_MODE_PFY_PCY_AFY_REN, 0x0000);
+                       if (status < 0)
+                               break;
+               } else {
+                       /* PGA off, bypass */
+
+                       /* fine gain */
+                       status = Read16(state, B_FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
+                       if (status < 0)
+                               break;
+                       AgModeLop &= (~(B_FE_AG_REG_AG_MODE_LOP_MODE_C__M));
+                       AgModeLop |= B_FE_AG_REG_AG_MODE_LOP_MODE_C_STATIC;
+                       status = Write16(state, B_FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
+                       if (status < 0)
+                               break;
+
+                       /* coarse gain */
+                       status = Read16(state, B_FE_AG_REG_AG_MODE_HIP__A, &AgModeHip, 0x0000);
+                       if (status < 0)
+                               break;
+                       AgModeHip &= (~(B_FE_AG_REG_AG_MODE_HIP_MODE_J__M));
+                       AgModeHip |= B_FE_AG_REG_AG_MODE_HIP_MODE_J_STATIC;
+                       status = Write16(state, B_FE_AG_REG_AG_MODE_HIP__A, AgModeHip, 0x0000);
+                       if (status < 0)
+                               break;
+
+                       /* disable fine and coarse gain, enable AAF,
+                          no ext resistor */
+                       status = Write16(state, B_FE_AG_REG_AG_PGA_MODE__A, B_FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN, 0x0000);
+                       if (status < 0)
+                               break;
+               }
+       } while (0);
+       return status;
+}
+
+static int InitFE(struct drxd_state *state)
+{
+       int status;
+
+       do {
+               status = WriteTable(state, state->m_InitFE_1);
+               if (status < 0)
+                       break;
+
+               if (state->type_A) {
+                       status = Write16(state, FE_AG_REG_AG_PGA_MODE__A,
+                                        FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN,
+                                        0);
+               } else {
+                       if (state->PGA)
+                               status = SetCfgPga(state, 0);
+                       else
+                               status =
+                                   Write16(state, B_FE_AG_REG_AG_PGA_MODE__A,
+                                           B_FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN,
+                                           0);
+               }
+
+               if (status < 0)
+                       break;
+               status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, state->m_FeAgRegAgAgcSio, 0x0000);
+               if (status < 0)
+                       break;
+               status = Write16(state, FE_AG_REG_AG_PWD__A, state->m_FeAgRegAgPwd, 0x0000);
+               if (status < 0)
+                       break;
+
+               status = WriteTable(state, state->m_InitFE_2);
+               if (status < 0)
+                       break;
+
+       } while (0);
+
+       return status;
+}
+
+static int InitFT(struct drxd_state *state)
+{
+       /*
+          norm OFFSET,  MB says =2 voor 8K en =3 voor 2K waarschijnlijk
+          SC stuff
+        */
+       return Write16(state, FT_REG_COMM_EXEC__A, 0x0001, 0x0000);
+}
+
+static int SC_WaitForReady(struct drxd_state *state)
+{
+       u16 curCmd;
+       int i;
+
+       for (i = 0; i < DRXD_MAX_RETRIES; i += 1) {
+               int status = Read16(state, SC_RA_RAM_CMD__A, &curCmd, 0);
+               if (status == 0 || curCmd == 0)
+                       return status;
+       }
+       return -1;
+}
+
+static int SC_SendCommand(struct drxd_state *state, u16 cmd)
+{
+       int status = 0;
+       u16 errCode;
+
+       Write16(state, SC_RA_RAM_CMD__A, cmd, 0);
+       SC_WaitForReady(state);
+
+       Read16(state, SC_RA_RAM_CMD_ADDR__A, &errCode, 0);
+
+       if (errCode == 0xFFFF) {
+               printk(KERN_ERR "Command Error\n");
+               status = -1;
+       }
+
+       return status;
+}
+
+static int SC_ProcStartCommand(struct drxd_state *state,
+                              u16 subCmd, u16 param0, u16 param1)
+{
+       int status = 0;
+       u16 scExec;
+
+       mutex_lock(&state->mutex);
+       do {
+               Read16(state, SC_COMM_EXEC__A, &scExec, 0);
+               if (scExec != 1) {
+                       status = -1;
+                       break;
+               }
+               SC_WaitForReady(state);
+               Write16(state, SC_RA_RAM_CMD_ADDR__A, subCmd, 0);
+               Write16(state, SC_RA_RAM_PARAM1__A, param1, 0);
+               Write16(state, SC_RA_RAM_PARAM0__A, param0, 0);
+
+               SC_SendCommand(state, SC_RA_RAM_CMD_PROC_START);
+       } while (0);
+       mutex_unlock(&state->mutex);
+       return status;
+}
+
+static int SC_SetPrefParamCommand(struct drxd_state *state,
+                                 u16 subCmd, u16 param0, u16 param1)
+{
+       int status;
+
+       mutex_lock(&state->mutex);
+       do {
+               status = SC_WaitForReady(state);
+               if (status < 0)
+                       break;
+               status = Write16(state, SC_RA_RAM_CMD_ADDR__A, subCmd, 0);
+               if (status < 0)
+                       break;
+               status = Write16(state, SC_RA_RAM_PARAM1__A, param1, 0);
+               if (status < 0)
+                       break;
+               status = Write16(state, SC_RA_RAM_PARAM0__A, param0, 0);
+               if (status < 0)
+                       break;
+
+               status = SC_SendCommand(state, SC_RA_RAM_CMD_SET_PREF_PARAM);
+               if (status < 0)
+                       break;
+       } while (0);
+       mutex_unlock(&state->mutex);
+       return status;
+}
+
+#if 0
+static int SC_GetOpParamCommand(struct drxd_state *state, u16 * result)
+{
+       int status = 0;
+
+       mutex_lock(&state->mutex);
+       do {
+               status = SC_WaitForReady(state);
+               if (status < 0)
+                       break;
+               status = SC_SendCommand(state, SC_RA_RAM_CMD_GET_OP_PARAM);
+               if (status < 0)
+                       break;
+               status = Read16(state, SC_RA_RAM_PARAM0__A, result, 0);
+               if (status < 0)
+                       break;
+       } while (0);
+       mutex_unlock(&state->mutex);
+       return status;
+}
+#endif
+
+static int ConfigureMPEGOutput(struct drxd_state *state, int bEnableOutput)
+{
+       int status;
+
+       do {
+               u16 EcOcRegIprInvMpg = 0;
+               u16 EcOcRegOcModeLop = 0;
+               u16 EcOcRegOcModeHip = 0;
+               u16 EcOcRegOcMpgSio = 0;
+
+               /*CHK_ERROR(Read16(state, EC_OC_REG_OC_MODE_LOP__A, &EcOcRegOcModeLop, 0)); */
+
+               if (state->operation_mode == OM_DVBT_Diversity_Front) {
+                       if (bEnableOutput) {
+                               EcOcRegOcModeHip |=
+                                   B_EC_OC_REG_OC_MODE_HIP_MPG_BUS_SRC_MONITOR;
+                       } else
+                               EcOcRegOcMpgSio |= EC_OC_REG_OC_MPG_SIO__M;
+                       EcOcRegOcModeLop |=
+                           EC_OC_REG_OC_MODE_LOP_PAR_ENA_DISABLE;
+               } else {
+                       EcOcRegOcModeLop = state->m_EcOcRegOcModeLop;
+
+                       if (bEnableOutput)
+                               EcOcRegOcMpgSio &= (~(EC_OC_REG_OC_MPG_SIO__M));
+                       else
+                               EcOcRegOcMpgSio |= EC_OC_REG_OC_MPG_SIO__M;
+
+                       /* Don't Insert RS Byte */
+                       if (state->insert_rs_byte) {
+                               EcOcRegOcModeLop &=
+                                   (~(EC_OC_REG_OC_MODE_LOP_PAR_ENA__M));
+                               EcOcRegOcModeHip &=
+                                   (~EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL__M);
+                               EcOcRegOcModeHip |=
+                                   EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_ENABLE;
+                       } else {
+                               EcOcRegOcModeLop |=
+                                   EC_OC_REG_OC_MODE_LOP_PAR_ENA_DISABLE;
+                               EcOcRegOcModeHip &=
+                                   (~EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL__M);
+                               EcOcRegOcModeHip |=
+                                   EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_DISABLE;
+                       }
+
+                       /* Mode = Parallel */
+                       if (state->enable_parallel)
+                               EcOcRegOcModeLop &=
+                                   (~(EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE__M));
+                       else
+                               EcOcRegOcModeLop |=
+                                   EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE_SERIAL;
+               }
+               /* Invert Data */
+               /* EcOcRegIprInvMpg |= 0x00FF; */
+               EcOcRegIprInvMpg &= (~(0x00FF));
+
+               /* Invert Error ( we don't use the pin ) */
+               /*  EcOcRegIprInvMpg |= 0x0100; */
+               EcOcRegIprInvMpg &= (~(0x0100));
+
+               /* Invert Start ( we don't use the pin ) */
+               /* EcOcRegIprInvMpg |= 0x0200; */
+               EcOcRegIprInvMpg &= (~(0x0200));
+
+               /* Invert Valid ( we don't use the pin ) */
+               /* EcOcRegIprInvMpg |= 0x0400; */
+               EcOcRegIprInvMpg &= (~(0x0400));
+
+               /* Invert Clock */
+               /* EcOcRegIprInvMpg |= 0x0800; */
+               EcOcRegIprInvMpg &= (~(0x0800));
+
+               /* EcOcRegOcModeLop =0x05; */
+               status = Write16(state, EC_OC_REG_IPR_INV_MPG__A, EcOcRegIprInvMpg, 0);
+               if (status < 0)
+                       break;
+               status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, EcOcRegOcModeLop, 0);
+               if (status < 0)
+                       break;
+               status = Write16(state, EC_OC_REG_OC_MODE_HIP__A, EcOcRegOcModeHip, 0x0000);
+               if (status < 0)
+                       break;
+               status = Write16(state, EC_OC_REG_OC_MPG_SIO__A, EcOcRegOcMpgSio, 0);
+               if (status < 0)
+                       break;
+       } while (0);
+       return status;
+}
+
+static int SetDeviceTypeId(struct drxd_state *state)
+{
+       int status = 0;
+       u16 deviceId = 0;
+
+       do {
+               status = Read16(state, CC_REG_JTAGID_L__A, &deviceId, 0);
+               if (status < 0)
+                       break;
+               /* TODO: why twice? */
+               status = Read16(state, CC_REG_JTAGID_L__A, &deviceId, 0);
+               if (status < 0)
+                       break;
+               printk(KERN_INFO "drxd: deviceId = %04x\n", deviceId);
+
+               state->type_A = 0;
+               state->PGA = 0;
+               state->diversity = 0;
+               if (deviceId == 0) {    /* on A2 only 3975 available */
+                       state->type_A = 1;
+                       printk(KERN_INFO "DRX3975D-A2\n");
+               } else {
+                       deviceId >>= 12;
+                       printk(KERN_INFO "DRX397%dD-B1\n", deviceId);
+                       switch (deviceId) {
+                       case 4:
+                               state->diversity = 1;
+                       case 3:
+                       case 7:
+                               state->PGA = 1;
+                               break;
+                       case 6:
+                               state->diversity = 1;
+                       case 5:
+                       case 8:
+                               break;
+                       default:
+                               status = -1;
+                               break;
+                       }
+               }
+       } while (0);
+
+       if (status < 0)
+               return status;
+
+       /* Init Table selection */
+       state->m_InitAtomicRead = DRXD_InitAtomicRead;
+       state->m_InitSC = DRXD_InitSC;
+       state->m_ResetECRAM = DRXD_ResetECRAM;
+       if (state->type_A) {
+               state->m_ResetCEFR = DRXD_ResetCEFR;
+               state->m_InitFE_1 = DRXD_InitFEA2_1;
+               state->m_InitFE_2 = DRXD_InitFEA2_2;
+               state->m_InitCP = DRXD_InitCPA2;
+               state->m_InitCE = DRXD_InitCEA2;
+               state->m_InitEQ = DRXD_InitEQA2;
+               state->m_InitEC = DRXD_InitECA2;
+               if (load_firmware(state, DRX_FW_FILENAME_A2))
+                       return -EIO;
+       } else {
+               state->m_ResetCEFR = NULL;
+               state->m_InitFE_1 = DRXD_InitFEB1_1;
+               state->m_InitFE_2 = DRXD_InitFEB1_2;
+               state->m_InitCP = DRXD_InitCPB1;
+               state->m_InitCE = DRXD_InitCEB1;
+               state->m_InitEQ = DRXD_InitEQB1;
+               state->m_InitEC = DRXD_InitECB1;
+               if (load_firmware(state, DRX_FW_FILENAME_B1))
+                       return -EIO;
+       }
+       if (state->diversity) {
+               state->m_InitDiversityFront = DRXD_InitDiversityFront;
+               state->m_InitDiversityEnd = DRXD_InitDiversityEnd;
+               state->m_DisableDiversity = DRXD_DisableDiversity;
+               state->m_StartDiversityFront = DRXD_StartDiversityFront;
+               state->m_StartDiversityEnd = DRXD_StartDiversityEnd;
+               state->m_DiversityDelay8MHZ = DRXD_DiversityDelay8MHZ;
+               state->m_DiversityDelay6MHZ = DRXD_DiversityDelay6MHZ;
+       } else {
+               state->m_InitDiversityFront = NULL;
+               state->m_InitDiversityEnd = NULL;
+               state->m_DisableDiversity = NULL;
+               state->m_StartDiversityFront = NULL;
+               state->m_StartDiversityEnd = NULL;
+               state->m_DiversityDelay8MHZ = NULL;
+               state->m_DiversityDelay6MHZ = NULL;
+       }
+
+       return status;
+}
+
+static int CorrectSysClockDeviation(struct drxd_state *state)
+{
+       int status;
+       s32 incr = 0;
+       s32 nomincr = 0;
+       u32 bandwidth = 0;
+       u32 sysClockInHz = 0;
+       u32 sysClockFreq = 0;   /* in kHz */
+       s16 oscClockDeviation;
+       s16 Diff;
+
+       do {
+               /* Retrieve bandwidth and incr, sanity check */
+
+               /* These accesses should be AtomicReadReg32, but that
+                  causes trouble (at least for diversity */
+               status = Read32(state, LC_RA_RAM_IFINCR_NOM_L__A, ((u32 *) &nomincr), 0);
+               if (status < 0)
+                       break;
+               status = Read32(state, FE_IF_REG_INCR0__A, (u32 *) &incr, 0);
+               if (status < 0)
+                       break;
+
+               if (state->type_A) {
+                       if ((nomincr - incr < -500) || (nomincr - incr > 500))
+                               break;
+               } else {
+                       if ((nomincr - incr < -2000) || (nomincr - incr > 2000))
+                               break;
+               }
+
+               switch (state->param.u.ofdm.bandwidth) {
+               case BANDWIDTH_8_MHZ:
+                       bandwidth = DRXD_BANDWIDTH_8MHZ_IN_HZ;
+                       break;
+               case BANDWIDTH_7_MHZ:
+                       bandwidth = DRXD_BANDWIDTH_7MHZ_IN_HZ;
+                       break;
+               case BANDWIDTH_6_MHZ:
+                       bandwidth = DRXD_BANDWIDTH_6MHZ_IN_HZ;
+                       break;
+               default:
+                       return -1;
+                       break;
+               }
+
+               /* Compute new sysclock value
+                  sysClockFreq = (((incr + 2^23)*bandwidth)/2^21)/1000 */
+               incr += (1 << 23);
+               sysClockInHz = MulDiv32(incr, bandwidth, 1 << 21);
+               sysClockFreq = (u32) (sysClockInHz / 1000);
+               /* rounding */
+               if ((sysClockInHz % 1000) > 500)
+                       sysClockFreq++;
+
+               /* Compute clock deviation in ppm */
+               oscClockDeviation = (u16) ((((s32) (sysClockFreq) -
+                                            (s32)
+                                            (state->expected_sys_clock_freq)) *
+                                           1000000L) /
+                                          (s32)
+                                          (state->expected_sys_clock_freq));
+
+               Diff = oscClockDeviation - state->osc_clock_deviation;
+               /*printk(KERN_INFO "sysclockdiff=%d\n", Diff); */
+               if (Diff >= -200 && Diff <= 200) {
+                       state->sys_clock_freq = (u16) sysClockFreq;
+                       if (oscClockDeviation != state->osc_clock_deviation) {
+                               if (state->config.osc_deviation) {
+                                       state->config.osc_deviation(state->priv,
+                                                                   oscClockDeviation,
+                                                                   1);
+                                       state->osc_clock_deviation =
+                                           oscClockDeviation;
+                               }
+                       }
+                       /* switch OFF SRMM scan in SC */
+                       status = Write16(state, SC_RA_RAM_SAMPLE_RATE_COUNT__A, DRXD_OSCDEV_DONT_SCAN, 0);
+                       if (status < 0)
+                               break;
+                       /* overrule FE_IF internal value for
+                          proper re-locking */
+                       status = Write16(state, SC_RA_RAM_IF_SAVE__AX, state->current_fe_if_incr, 0);
+                       if (status < 0)
+                               break;
+                       state->cscd_state = CSCD_SAVED;
+               }
+       } while (0);
+
+       return status;
+}
+
+static int DRX_Stop(struct drxd_state *state)
+{
+       int status;
+
+       if (state->drxd_state != DRXD_STARTED)
+               return 0;
+
+       do {
+               if (state->cscd_state != CSCD_SAVED) {
+                       u32 lock;
+                       status = DRX_GetLockStatus(state, &lock);
+                       if (status < 0)
+                               break;
+               }
+
+               status = StopOC(state);
+               if (status < 0)
+                       break;
+
+               state->drxd_state = DRXD_STOPPED;
+
+               status = ConfigureMPEGOutput(state, 0);
+               if (status < 0)
+                       break;
+
+               if (state->type_A) {
+                       /* Stop relevant processors off the device */
+                       status = Write16(state, EC_OD_REG_COMM_EXEC__A, 0x0000, 0x0000);
+                       if (status < 0)
+                               break;
+
+                       status = Write16(state, SC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+                       if (status < 0)
+                               break;
+                       status = Write16(state, LC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+                       if (status < 0)
+                               break;
+               } else {
+                       /* Stop all processors except HI & CC & FE */
+                       status = Write16(state, B_SC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+                       if (status < 0)
+                               break;
+                       status = Write16(state, B_LC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+                       if (status < 0)
+                               break;
+                       status = Write16(state, B_FT_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+                       if (status < 0)
+                               break;
+                       status = Write16(state, B_CP_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+                       if (status < 0)
+                               break;
+                       status = Write16(state, B_CE_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+                       if (status < 0)
+                               break;
+                       status = Write16(state, B_EQ_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+                       if (status < 0)
+                               break;
+                       status = Write16(state, EC_OD_REG_COMM_EXEC__A, 0x0000, 0);
+                       if (status < 0)
+                               break;
+               }
+
+       } while (0);
+       return status;
+}
+
+int SetOperationMode(struct drxd_state *state, int oMode)
+{
+       int status;
+
+       do {
+               if (state->drxd_state != DRXD_STOPPED) {
+                       status = -1;
+                       break;
+               }
+
+               if (oMode == state->operation_mode) {
+                       status = 0;
+                       break;
+               }
+
+               if (oMode != OM_Default && !state->diversity) {
+                       status = -1;
+                       break;
+               }
+
+               switch (oMode) {
+               case OM_DVBT_Diversity_Front:
+                       status = WriteTable(state, state->m_InitDiversityFront);
+                       break;
+               case OM_DVBT_Diversity_End:
+                       status = WriteTable(state, state->m_InitDiversityEnd);
+                       break;
+               case OM_Default:
+                       /* We need to check how to
+                          get DRXD out of diversity */
+               default:
+                       status = WriteTable(state, state->m_DisableDiversity);
+                       break;
+               }
+       } while (0);
+
+       if (!status)
+               state->operation_mode = oMode;
+       return status;
+}
+
+static int StartDiversity(struct drxd_state *state)
+{
+       int status = 0;
+       u16 rcControl;
+
+       do {
+               if (state->operation_mode == OM_DVBT_Diversity_Front) {
+                       status = WriteTable(state, state->m_StartDiversityFront);
+                       if (status < 0)
+                               break;
+               } else if (state->operation_mode == OM_DVBT_Diversity_End) {
+                       status = WriteTable(state, state->m_StartDiversityEnd);
+                       if (status < 0)
+                               break;
+                       if (state->param.u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
+                               status = WriteTable(state, state->m_DiversityDelay8MHZ);
+                               if (status < 0)
+                                       break;
+                       } else {
+                               status = WriteTable(state, state->m_DiversityDelay6MHZ);
+                               if (status < 0)
+                                       break;
+                       }
+
+                       status = Read16(state, B_EQ_REG_RC_SEL_CAR__A, &rcControl, 0);
+                       if (status < 0)
+                               break;
+                       rcControl &= ~(B_EQ_REG_RC_SEL_CAR_FFTMODE__M);
+                       rcControl |= B_EQ_REG_RC_SEL_CAR_DIV_ON |
+                           /*  combining enabled */
+                           B_EQ_REG_RC_SEL_CAR_MEAS_A_CC |
+                           B_EQ_REG_RC_SEL_CAR_PASS_A_CC |
+                           B_EQ_REG_RC_SEL_CAR_LOCAL_A_CC;
+                       status = Write16(state, B_EQ_REG_RC_SEL_CAR__A, rcControl, 0);
+                       if (status < 0)
+                               break;
+               }
+       } while (0);
+       return status;
+}
+
+static int SetFrequencyShift(struct drxd_state *state,
+                            u32 offsetFreq, int channelMirrored)
+{
+       int negativeShift = (state->tuner_mirrors == channelMirrored);
+
+       /* Handle all mirroring
+        *
+        * Note: ADC mirroring (aliasing) is implictly handled by limiting
+        * feFsRegAddInc to 28 bits below
+        * (if the result before masking is more than 28 bits, this means
+        *  that the ADC is mirroring.
+        * The masking is in fact the aliasing of the ADC)
+        *
+        */
+
+       /* Compute register value, unsigned computation */
+       state->fe_fs_add_incr = MulDiv32(state->intermediate_freq +
+                                        offsetFreq,
+                                        1 << 28, state->sys_clock_freq);
+       /* Remove integer part */
+       state->fe_fs_add_incr &= 0x0FFFFFFFL;
+       if (negativeShift)
+               state->fe_fs_add_incr = ((1 << 28) - state->fe_fs_add_incr);
+
+       /* Save the frequency shift without tunerOffset compensation
+          for CtrlGetChannel. */
+       state->org_fe_fs_add_incr = MulDiv32(state->intermediate_freq,
+                                            1 << 28, state->sys_clock_freq);
+       /* Remove integer part */
+       state->org_fe_fs_add_incr &= 0x0FFFFFFFL;
+       if (negativeShift)
+               state->org_fe_fs_add_incr = ((1L << 28) -
+                                            state->org_fe_fs_add_incr);
+
+       return Write32(state, FE_FS_REG_ADD_INC_LOP__A,
+                      state->fe_fs_add_incr, 0);
+}
+
+static int SetCfgNoiseCalibration(struct drxd_state *state,
+                                 struct SNoiseCal *noiseCal)
+{
+       u16 beOptEna;
+       int status = 0;
+
+       do {
+               status = Read16(state, SC_RA_RAM_BE_OPT_ENA__A, &beOptEna, 0);
+               if (status < 0)
+                       break;
+               if (noiseCal->cpOpt) {
+                       beOptEna |= (1 << SC_RA_RAM_BE_OPT_ENA_CP_OPT);
+               } else {
+                       beOptEna &= ~(1 << SC_RA_RAM_BE_OPT_ENA_CP_OPT);
+                       status = Write16(state, CP_REG_AC_NEXP_OFFS__A, noiseCal->cpNexpOfs, 0);
+                       if (status < 0)
+                               break;
+               }
+               status = Write16(state, SC_RA_RAM_BE_OPT_ENA__A, beOptEna, 0);
+               if (status < 0)
+                       break;
+
+               if (!state->type_A) {
+                       status = Write16(state, B_SC_RA_RAM_CO_TD_CAL_2K__A, noiseCal->tdCal2k, 0);
+                       if (status < 0)
+                               break;
+                       status = Write16(state, B_SC_RA_RAM_CO_TD_CAL_8K__A, noiseCal->tdCal8k, 0);
+                       if (status < 0)
+                               break;
+               }
+       } while (0);
+
+       return status;
+}
+
+static int DRX_Start(struct drxd_state *state, s32 off)
+{
+       struct dvb_ofdm_parameters *p = &state->param.u.ofdm;
+       int status;
+
+       u16 transmissionParams = 0;
+       u16 operationMode = 0;
+       u16 qpskTdTpsPwr = 0;
+       u16 qam16TdTpsPwr = 0;
+       u16 qam64TdTpsPwr = 0;
+       u32 feIfIncr = 0;
+       u32 bandwidth = 0;
+       int mirrorFreqSpect;
+
+       u16 qpskSnCeGain = 0;
+       u16 qam16SnCeGain = 0;
+       u16 qam64SnCeGain = 0;
+       u16 qpskIsGainMan = 0;
+       u16 qam16IsGainMan = 0;
+       u16 qam64IsGainMan = 0;
+       u16 qpskIsGainExp = 0;
+       u16 qam16IsGainExp = 0;
+       u16 qam64IsGainExp = 0;
+       u16 bandwidthParam = 0;
+
+       if (off < 0)
+               off = (off - 500) / 1000;
+       else
+               off = (off + 500) / 1000;
+
+       do {
+               if (state->drxd_state != DRXD_STOPPED)
+                       return -1;
+               status = ResetECOD(state);
+               if (status < 0)
+                       break;
+               if (state->type_A) {
+                       status = InitSC(state);
+                       if (status < 0)
+                               break;
+               } else {
+                       status = InitFT(state);
+                       if (status < 0)
+                               break;
+                       status = InitCP(state);
+                       if (status < 0)
+                               break;
+                       status = InitCE(state);
+                       if (status < 0)
+                               break;
+                       status = InitEQ(state);
+                       if (status < 0)
+                               break;
+                       status = InitSC(state);
+                       if (status < 0)
+                               break;
+               }
+
+               /* Restore current IF & RF AGC settings */
+
+               status = SetCfgIfAgc(state, &state->if_agc_cfg);
+               if (status < 0)
+                       break;
+               status = SetCfgRfAgc(state, &state->rf_agc_cfg);
+               if (status < 0)
+                       break;
+
+               mirrorFreqSpect = (state->param.inversion == INVERSION_ON);
+
+               switch (p->transmission_mode) {
+               default:        /* Not set, detect it automatically */
+                       operationMode |= SC_RA_RAM_OP_AUTO_MODE__M;
+                       /* fall through , try first guess DRX_FFTMODE_8K */
+               case TRANSMISSION_MODE_8K:
+                       transmissionParams |= SC_RA_RAM_OP_PARAM_MODE_8K;
+                       if (state->type_A) {
+                               status = Write16(state, EC_SB_REG_TR_MODE__A, EC_SB_REG_TR_MODE_8K, 0x0000);
+                               if (status < 0)
+                                       break;
+                               qpskSnCeGain = 99;
+                               qam16SnCeGain = 83;
+                               qam64SnCeGain = 67;
+                       }
+                       break;
+               case TRANSMISSION_MODE_2K:
+                       transmissionParams |= SC_RA_RAM_OP_PARAM_MODE_2K;
+                       if (state->type_A) {
+                               status = Write16(state, EC_SB_REG_TR_MODE__A, EC_SB_REG_TR_MODE_2K, 0x0000);
+                               if (status < 0)
+                                       break;
+                               qpskSnCeGain = 97;
+                               qam16SnCeGain = 71;
+                               qam64SnCeGain = 65;
+                       }
+                       break;
+               }
+
+               switch (p->guard_interval) {
+               case GUARD_INTERVAL_1_4:
+                       transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_4;
+                       break;
+               case GUARD_INTERVAL_1_8:
+                       transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_8;
+                       break;
+               case GUARD_INTERVAL_1_16:
+                       transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_16;
+                       break;
+               case GUARD_INTERVAL_1_32:
+                       transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_32;
+                       break;
+               default:        /* Not set, detect it automatically */
+                       operationMode |= SC_RA_RAM_OP_AUTO_GUARD__M;
+                       /* try first guess 1/4 */
+                       transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_4;
+                       break;
+               }
+
+               switch (p->hierarchy_information) {
+               case HIERARCHY_1:
+                       transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_A1;
+                       if (state->type_A) {
+                               status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0001, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EC_SB_REG_ALPHA__A, 0x0001, 0x0000);
+                               if (status < 0)
+                                       break;
+
+                               qpskTdTpsPwr = EQ_TD_TPS_PWR_UNKNOWN;
+                               qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHA1;
+                               qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHA1;
+
+                               qpskIsGainMan =
+                                   SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE;
+                               qam16IsGainMan =
+                                   SC_RA_RAM_EQ_IS_GAIN_16QAM_MAN__PRE;
+                               qam64IsGainMan =
+                                   SC_RA_RAM_EQ_IS_GAIN_64QAM_MAN__PRE;
+
+                               qpskIsGainExp =
+                                   SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE;
+                               qam16IsGainExp =
+                                   SC_RA_RAM_EQ_IS_GAIN_16QAM_EXP__PRE;
+                               qam64IsGainExp =
+                                   SC_RA_RAM_EQ_IS_GAIN_64QAM_EXP__PRE;
+                       }
+                       break;
+
+               case HIERARCHY_2:
+                       transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_A2;
+                       if (state->type_A) {
+                               status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0002, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EC_SB_REG_ALPHA__A, 0x0002, 0x0000);
+                               if (status < 0)
+                                       break;
+
+                               qpskTdTpsPwr = EQ_TD_TPS_PWR_UNKNOWN;
+                               qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHA2;
+                               qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHA2;
+
+                               qpskIsGainMan =
+                                   SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE;
+                               qam16IsGainMan =
+                                   SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_MAN__PRE;
+                               qam64IsGainMan =
+                                   SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_MAN__PRE;
+
+                               qpskIsGainExp =
+                                   SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE;
+                               qam16IsGainExp =
+                                   SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_EXP__PRE;
+                               qam64IsGainExp =
+                                   SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_EXP__PRE;
+                       }
+                       break;
+               case HIERARCHY_4:
+                       transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_A4;
+                       if (state->type_A) {
+                               status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0003, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EC_SB_REG_ALPHA__A, 0x0003, 0x0000);
+                               if (status < 0)
+                                       break;
+
+                               qpskTdTpsPwr = EQ_TD_TPS_PWR_UNKNOWN;
+                               qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHA4;
+                               qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHA4;
+
+                               qpskIsGainMan =
+                                   SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE;
+                               qam16IsGainMan =
+                                   SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_MAN__PRE;
+                               qam64IsGainMan =
+                                   SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_MAN__PRE;
+
+                               qpskIsGainExp =
+                                   SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE;
+                               qam16IsGainExp =
+                                   SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_EXP__PRE;
+                               qam64IsGainExp =
+                                   SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_EXP__PRE;
+                       }
+                       break;
+               case HIERARCHY_AUTO:
+               default:
+                       /* Not set, detect it automatically, start with none */
+                       operationMode |= SC_RA_RAM_OP_AUTO_HIER__M;
+                       transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_NO;
+                       if (state->type_A) {
+                               status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0000, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EC_SB_REG_ALPHA__A, 0x0000, 0x0000);
+                               if (status < 0)
+                                       break;
+
+                               qpskTdTpsPwr = EQ_TD_TPS_PWR_QPSK;
+                               qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHAN;
+                               qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHAN;
+
+                               qpskIsGainMan =
+                                   SC_RA_RAM_EQ_IS_GAIN_QPSK_MAN__PRE;
+                               qam16IsGainMan =
+                                   SC_RA_RAM_EQ_IS_GAIN_16QAM_MAN__PRE;
+                               qam64IsGainMan =
+                                   SC_RA_RAM_EQ_IS_GAIN_64QAM_MAN__PRE;
+
+                               qpskIsGainExp =
+                                   SC_RA_RAM_EQ_IS_GAIN_QPSK_EXP__PRE;
+                               qam16IsGainExp =
+                                   SC_RA_RAM_EQ_IS_GAIN_16QAM_EXP__PRE;
+                               qam64IsGainExp =
+                                   SC_RA_RAM_EQ_IS_GAIN_64QAM_EXP__PRE;
+                       }
+                       break;
+               }
+               status = status;
+               if (status < 0)
+                       break;
+
+               switch (p->constellation) {
+               default:
+                       operationMode |= SC_RA_RAM_OP_AUTO_CONST__M;
+                       /* fall through , try first guess
+                          DRX_CONSTELLATION_QAM64 */
+               case QAM_64:
+                       transmissionParams |= SC_RA_RAM_OP_PARAM_CONST_QAM64;
+                       if (state->type_A) {
+                               status = Write16(state, EQ_REG_OT_CONST__A, 0x0002, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EC_SB_REG_CONST__A, EC_SB_REG_CONST_64QAM, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EC_SB_REG_SCALE_MSB__A, 0x0020, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EC_SB_REG_SCALE_BIT2__A, 0x0008, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EC_SB_REG_SCALE_LSB__A, 0x0002, 0x0000);
+                               if (status < 0)
+                                       break;
+
+                               status = Write16(state, EQ_REG_TD_TPS_PWR_OFS__A, qam64TdTpsPwr, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EQ_REG_SN_CEGAIN__A, qam64SnCeGain, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EQ_REG_IS_GAIN_MAN__A, qam64IsGainMan, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EQ_REG_IS_GAIN_EXP__A, qam64IsGainExp, 0x0000);
+                               if (status < 0)
+                                       break;
+                       }
+                       break;
+               case QPSK:
+                       transmissionParams |= SC_RA_RAM_OP_PARAM_CONST_QPSK;
+                       if (state->type_A) {
+                               status = Write16(state, EQ_REG_OT_CONST__A, 0x0000, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EC_SB_REG_CONST__A, EC_SB_REG_CONST_QPSK, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EC_SB_REG_SCALE_MSB__A, 0x0010, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EC_SB_REG_SCALE_BIT2__A, 0x0000, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EC_SB_REG_SCALE_LSB__A, 0x0000, 0x0000);
+                               if (status < 0)
+                                       break;
+
+                               status = Write16(state, EQ_REG_TD_TPS_PWR_OFS__A, qpskTdTpsPwr, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EQ_REG_SN_CEGAIN__A, qpskSnCeGain, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EQ_REG_IS_GAIN_MAN__A, qpskIsGainMan, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EQ_REG_IS_GAIN_EXP__A, qpskIsGainExp, 0x0000);
+                               if (status < 0)
+                                       break;
+                       }
+                       break;
+
+               case QAM_16:
+                       transmissionParams |= SC_RA_RAM_OP_PARAM_CONST_QAM16;
+                       if (state->type_A) {
+                               status = Write16(state, EQ_REG_OT_CONST__A, 0x0001, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EC_SB_REG_CONST__A, EC_SB_REG_CONST_16QAM, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EC_SB_REG_SCALE_MSB__A, 0x0010, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EC_SB_REG_SCALE_BIT2__A, 0x0004, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EC_SB_REG_SCALE_LSB__A, 0x0000, 0x0000);
+                               if (status < 0)
+                                       break;
+
+                               status = Write16(state, EQ_REG_TD_TPS_PWR_OFS__A, qam16TdTpsPwr, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EQ_REG_SN_CEGAIN__A, qam16SnCeGain, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EQ_REG_IS_GAIN_MAN__A, qam16IsGainMan, 0x0000);
+                               if (status < 0)
+                                       break;
+                               status = Write16(state, EQ_REG_IS_GAIN_EXP__A, qam16IsGainExp, 0x0000);
+                               if (status < 0)
+                                       break;
+                       }
+                       break;
+
+               }
+               status = status;
+               if (status < 0)
+                       break;
+
+               switch (DRX_CHANNEL_HIGH) {
+               default:
+               case DRX_CHANNEL_AUTO:
+               case DRX_CHANNEL_LOW:
+                       transmissionParams |= SC_RA_RAM_OP_PARAM_PRIO_LO;
+                       status = Write16(state, EC_SB_REG_PRIOR__A, EC_SB_REG_PRIOR_LO, 0x0000);
+                       if (status < 0)
+                               break;
+                       break;
+               case DRX_CHANNEL_HIGH:
+                       transmissionParams |= SC_RA_RAM_OP_PARAM_PRIO_HI;
+                       status = Write16(state, EC_SB_REG_PRIOR__A, EC_SB_REG_PRIOR_HI, 0x0000);
+                       if (status < 0)
+                               break;
+                       break;
+
+               }
+
+               switch (p->code_rate_HP) {
+               case FEC_1_2:
+                       transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_1_2;
+                       if (state->type_A) {
+                               status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C1_2, 0x0000);
+                               if (status < 0)
+                                       break;
+                       }
+                       break;
+               default:
+                       operationMode |= SC_RA_RAM_OP_AUTO_RATE__M;
+               case FEC_2_3:
+                       transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_2_3;
+                       if (state->type_A) {
+                               status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C2_3, 0x0000);
+                               if (status < 0)
+                                       break;
+                       }
+                       break;
+               case FEC_3_4:
+                       transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_3_4;
+                       if (state->type_A) {
+                               status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C3_4, 0x0000);
+                               if (status < 0)
+                                       break;
+                       }
+                       break;
+               case FEC_5_6:
+                       transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_5_6;
+                       if (state->type_A) {
+                               status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C5_6, 0x0000);
+                               if (status < 0)
+                                       break;
+                       }
+                       break;
+               case FEC_7_8:
+                       transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_7_8;
+                       if (state->type_A) {
+                               status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C7_8, 0x0000);
+                               if (status < 0)
+                                       break;
+                       }
+                       break;
+               }
+               status = status;
+               if (status < 0)
+                       break;
+
+               /* First determine real bandwidth (Hz) */
+               /* Also set delay for impulse noise cruncher (only A2) */
+               /* Also set parameters for EC_OC fix, note
+                  EC_OC_REG_TMD_HIL_MAR is changed
+                  by SC for fix for some 8K,1/8 guard but is restored by
+                  InitEC and ResetEC
+                  functions */
+               switch (p->bandwidth) {
+               case BANDWIDTH_AUTO:
+               case BANDWIDTH_8_MHZ:
+                       /* (64/7)*(8/8)*1000000 */
+                       bandwidth = DRXD_BANDWIDTH_8MHZ_IN_HZ;
+
+                       bandwidthParam = 0;
+                       status = Write16(state,
+                                        FE_AG_REG_IND_DEL__A, 50, 0x0000);
+                       break;
+               case BANDWIDTH_7_MHZ:
+                       /* (64/7)*(7/8)*1000000 */
+                       bandwidth = DRXD_BANDWIDTH_7MHZ_IN_HZ;
+                       bandwidthParam = 0x4807;        /*binary:0100 1000 0000 0111 */
+                       status = Write16(state,
+                                        FE_AG_REG_IND_DEL__A, 59, 0x0000);
+                       break;
+               case BANDWIDTH_6_MHZ:
+                       /* (64/7)*(6/8)*1000000 */
+                       bandwidth = DRXD_BANDWIDTH_6MHZ_IN_HZ;
+                       bandwidthParam = 0x0F07;        /*binary: 0000 1111 0000 0111 */
+                       status = Write16(state,
+                                        FE_AG_REG_IND_DEL__A, 71, 0x0000);
+                       break;
+               default:
+                       status = -EINVAL;
+               }
+               if (status < 0)
+                       break;
+
+               status = Write16(state, SC_RA_RAM_BAND__A, bandwidthParam, 0x0000);
+               if (status < 0)
+                       break;
+
+               {
+                       u16 sc_config;
+                       status = Read16(state, SC_RA_RAM_CONFIG__A, &sc_config, 0);
+                       if (status < 0)
+                               break;
+
+                       /* enable SLAVE mode in 2k 1/32 to
+                          prevent timing change glitches */
+                       if ((p->transmission_mode == TRANSMISSION_MODE_2K) &&
+                           (p->guard_interval == GUARD_INTERVAL_1_32)) {
+                               /* enable slave */
+                               sc_config |= SC_RA_RAM_CONFIG_SLAVE__M;
+                       } else {
+                               /* disable slave */
+                               sc_config &= ~SC_RA_RAM_CONFIG_SLAVE__M;
+                       }
+                       status = Write16(state, SC_RA_RAM_CONFIG__A, sc_config, 0);
+                       if (status < 0)
+                               break;
+               }
+
+               status = SetCfgNoiseCalibration(state, &state->noise_cal);
+               if (status < 0)
+                       break;
+
+               if (state->cscd_state == CSCD_INIT) {
+                       /* switch on SRMM scan in SC */
+                       status = Write16(state, SC_RA_RAM_SAMPLE_RATE_COUNT__A, DRXD_OSCDEV_DO_SCAN, 0x0000);
+                       if (status < 0)
+                               break;
+/*            CHK_ERROR(Write16(SC_RA_RAM_SAMPLE_RATE_STEP__A, DRXD_OSCDEV_STEP, 0x0000));*/
+                       state->cscd_state = CSCD_SET;
+               }
+
+               /* Now compute FE_IF_REG_INCR */
+               /*((( SysFreq/BandWidth)/2)/2) -1) * 2^23) =>
+                  ((SysFreq / BandWidth) * (2^21) ) - (2^23) */
+               feIfIncr = MulDiv32(state->sys_clock_freq * 1000,
+                                   (1ULL << 21), bandwidth) - (1 << 23);
+               status = Write16(state, FE_IF_REG_INCR0__A, (u16) (feIfIncr & FE_IF_REG_INCR0__M), 0x0000);
+               if (status < 0)
+                       break;
+               status = Write16(state, FE_IF_REG_INCR1__A, (u16) ((feIfIncr >> FE_IF_REG_INCR0__W) & FE_IF_REG_INCR1__M), 0x0000);
+               if (status < 0)
+                       break;
+               /* Bandwidth setting done */
+
+               /* Mirror & frequency offset */
+               SetFrequencyShift(state, off, mirrorFreqSpect);
+
+               /* Start SC, write channel settings to SC */
+
+               /* Enable SC after setting all other parameters */
+               status = Write16(state, SC_COMM_STATE__A, 0, 0x0000);
+               if (status < 0)
+                       break;
+               status = Write16(state, SC_COMM_EXEC__A, 1, 0x0000);
+               if (status < 0)
+                       break;
+
+               /* Write SC parameter registers, operation mode */
+#if 1
+               operationMode = (SC_RA_RAM_OP_AUTO_MODE__M |
+                                SC_RA_RAM_OP_AUTO_GUARD__M |
+                                SC_RA_RAM_OP_AUTO_CONST__M |
+                                SC_RA_RAM_OP_AUTO_HIER__M |
+                                SC_RA_RAM_OP_AUTO_RATE__M);
+#endif
+               status = SC_SetPrefParamCommand(state, 0x0000, transmissionParams, operationMode);
+               if (status < 0)
+                       break;
+
+               /* Start correct processes to get in lock */
+               status = SC_ProcStartCommand(state, SC_RA_RAM_PROC_LOCKTRACK, SC_RA_RAM_SW_EVENT_RUN_NMASK__M, SC_RA_RAM_LOCKTRACK_MIN);
+               if (status < 0)
+                       break;
+
+               status = StartOC(state);
+               if (status < 0)
+                       break;
+
+               if (state->operation_mode != OM_Default) {
+                       status = StartDiversity(state);
+                       if (status < 0)
+                               break;
+               }
+
+               state->drxd_state = DRXD_STARTED;
+       } while (0);
+
+       return status;
+}
+
+static int CDRXD(struct drxd_state *state, u32 IntermediateFrequency)
+{
+       u32 ulRfAgcOutputLevel = 0xffffffff;
+       u32 ulRfAgcSettleLevel = 528;   /* Optimum value for MT2060 */
+       u32 ulRfAgcMinLevel = 0;        /* Currently unused */
+       u32 ulRfAgcMaxLevel = DRXD_FE_CTRL_MAX; /* Currently unused */
+       u32 ulRfAgcSpeed = 0;   /* Currently unused */
+       u32 ulRfAgcMode = 0;    /*2;   Off */
+       u32 ulRfAgcR1 = 820;
+       u32 ulRfAgcR2 = 2200;
+       u32 ulRfAgcR3 = 150;
+       u32 ulIfAgcMode = 0;    /* Auto */
+       u32 ulIfAgcOutputLevel = 0xffffffff;
+       u32 ulIfAgcSettleLevel = 0xffffffff;
+       u32 ulIfAgcMinLevel = 0xffffffff;
+       u32 ulIfAgcMaxLevel = 0xffffffff;
+       u32 ulIfAgcSpeed = 0xffffffff;
+       u32 ulIfAgcR1 = 820;
+       u32 ulIfAgcR2 = 2200;
+       u32 ulIfAgcR3 = 150;
+       u32 ulClock = state->config.clock;
+       u32 ulSerialMode = 0;
+       u32 ulEcOcRegOcModeLop = 4;     /* Dynamic DTO source */
+       u32 ulHiI2cDelay = HI_I2C_DELAY;
+       u32 ulHiI2cBridgeDelay = HI_I2C_BRIDGE_DELAY;
+       u32 ulHiI2cPatch = 0;
+       u32 ulEnvironment = APPENV_PORTABLE;
+       u32 ulEnvironmentDiversity = APPENV_MOBILE;
+       u32 ulIFFilter = IFFILTER_SAW;
+
+       state->if_agc_cfg.ctrlMode = AGC_CTRL_AUTO;
+       state->if_agc_cfg.outputLevel = 0;
+       state->if_agc_cfg.settleLevel = 140;
+       state->if_agc_cfg.minOutputLevel = 0;
+       state->if_agc_cfg.maxOutputLevel = 1023;
+       state->if_agc_cfg.speed = 904;
+
+       if (ulIfAgcMode == 1 && ulIfAgcOutputLevel <= DRXD_FE_CTRL_MAX) {
+               state->if_agc_cfg.ctrlMode = AGC_CTRL_USER;
+               state->if_agc_cfg.outputLevel = (u16) (ulIfAgcOutputLevel);
+       }
+
+       if (ulIfAgcMode == 0 &&
+           ulIfAgcSettleLevel <= DRXD_FE_CTRL_MAX &&
+           ulIfAgcMinLevel <= DRXD_FE_CTRL_MAX &&
+           ulIfAgcMaxLevel <= DRXD_FE_CTRL_MAX &&
+           ulIfAgcSpeed <= DRXD_FE_CTRL_MAX) {
+               state->if_agc_cfg.ctrlMode = AGC_CTRL_AUTO;
+               state->if_agc_cfg.settleLevel = (u16) (ulIfAgcSettleLevel);
+               state->if_agc_cfg.minOutputLevel = (u16) (ulIfAgcMinLevel);
+               state->if_agc_cfg.maxOutputLevel = (u16) (ulIfAgcMaxLevel);
+               state->if_agc_cfg.speed = (u16) (ulIfAgcSpeed);
+       }
+
+       state->if_agc_cfg.R1 = (u16) (ulIfAgcR1);
+       state->if_agc_cfg.R2 = (u16) (ulIfAgcR2);
+       state->if_agc_cfg.R3 = (u16) (ulIfAgcR3);
+
+       state->rf_agc_cfg.R1 = (u16) (ulRfAgcR1);
+       state->rf_agc_cfg.R2 = (u16) (ulRfAgcR2);
+       state->rf_agc_cfg.R3 = (u16) (ulRfAgcR3);
+
+       state->rf_agc_cfg.ctrlMode = AGC_CTRL_AUTO;
+       /* rest of the RFAgcCfg structure currently unused */
+       if (ulRfAgcMode == 1 && ulRfAgcOutputLevel <= DRXD_FE_CTRL_MAX) {
+               state->rf_agc_cfg.ctrlMode = AGC_CTRL_USER;
+               state->rf_agc_cfg.outputLevel = (u16) (ulRfAgcOutputLevel);
+       }
+
+       if (ulRfAgcMode == 0 &&
+           ulRfAgcSettleLevel <= DRXD_FE_CTRL_MAX &&
+           ulRfAgcMinLevel <= DRXD_FE_CTRL_MAX &&
+           ulRfAgcMaxLevel <= DRXD_FE_CTRL_MAX &&
+           ulRfAgcSpeed <= DRXD_FE_CTRL_MAX) {
+               state->rf_agc_cfg.ctrlMode = AGC_CTRL_AUTO;
+               state->rf_agc_cfg.settleLevel = (u16) (ulRfAgcSettleLevel);
+               state->rf_agc_cfg.minOutputLevel = (u16) (ulRfAgcMinLevel);
+               state->rf_agc_cfg.maxOutputLevel = (u16) (ulRfAgcMaxLevel);
+               state->rf_agc_cfg.speed = (u16) (ulRfAgcSpeed);
+       }
+
+       if (ulRfAgcMode == 2)
+               state->rf_agc_cfg.ctrlMode = AGC_CTRL_OFF;
+
+       if (ulEnvironment <= 2)
+               state->app_env_default = (enum app_env)
+                   (ulEnvironment);
+       if (ulEnvironmentDiversity <= 2)
+               state->app_env_diversity = (enum app_env)
+                   (ulEnvironmentDiversity);
+
+       if (ulIFFilter == IFFILTER_DISCRETE) {
+               /* discrete filter */
+               state->noise_cal.cpOpt = 0;
+               state->noise_cal.cpNexpOfs = 40;
+               state->noise_cal.tdCal2k = -40;
+               state->noise_cal.tdCal8k = -24;
+       } else {
+               /* SAW filter */
+               state->noise_cal.cpOpt = 1;
+               state->noise_cal.cpNexpOfs = 0;
+               state->noise_cal.tdCal2k = -21;
+               state->noise_cal.tdCal8k = -24;
+       }
+       state->m_EcOcRegOcModeLop = (u16) (ulEcOcRegOcModeLop);
+
+       state->chip_adr = (state->config.demod_address << 1) | 1;
+       switch (ulHiI2cPatch) {
+       case 1:
+               state->m_HiI2cPatch = DRXD_HiI2cPatch_1;
+               break;
+       case 3:
+               state->m_HiI2cPatch = DRXD_HiI2cPatch_3;
+               break;
+       default:
+               state->m_HiI2cPatch = NULL;
+       }
+
+       /* modify tuner and clock attributes */
+       state->intermediate_freq = (u16) (IntermediateFrequency / 1000);
+       /* expected system clock frequency in kHz */
+       state->expected_sys_clock_freq = 48000;
+       /* real system clock frequency in kHz */
+       state->sys_clock_freq = 48000;
+       state->osc_clock_freq = (u16) ulClock;
+       state->osc_clock_deviation = 0;
+       state->cscd_state = CSCD_INIT;
+       state->drxd_state = DRXD_UNINITIALIZED;
+
+       state->PGA = 0;
+       state->type_A = 0;
+       state->tuner_mirrors = 0;
+
+       /* modify MPEG output attributes */
+       state->insert_rs_byte = state->config.insert_rs_byte;
+       state->enable_parallel = (ulSerialMode != 1);
+
+       /* Timing div, 250ns/Psys */
+       /* Timing div, = ( delay (nano seconds) * sysclk (kHz) )/ 1000 */
+
+       state->hi_cfg_timing_div = (u16) ((state->sys_clock_freq / 1000) *
+                                         ulHiI2cDelay) / 1000;
+       /* Bridge delay, uses oscilator clock */
+       /* Delay = ( delay (nano seconds) * oscclk (kHz) )/ 1000 */
+       state->hi_cfg_bridge_delay = (u16) ((state->osc_clock_freq / 1000) *
+                                           ulHiI2cBridgeDelay) / 1000;
+
+       state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_CONSUMER;
+       /* state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_PRO; */
+       state->m_FeAgRegAgAgcSio = DRXD_DEF_AG_AGC_SIO;
+       return 0;
+}
+
+int DRXD_init(struct drxd_state *state, const u8 * fw, u32 fw_size)
+{
+       int status = 0;
+       u32 driverVersion;
+
+       if (state->init_done)
+               return 0;
+
+       CDRXD(state, state->config.IF ? state->config.IF : 36000000);
+
+       do {
+               state->operation_mode = OM_Default;
+
+               status = SetDeviceTypeId(state);
+               if (status < 0)
+                       break;
+
+               /* Apply I2c address patch to B1 */
+               if (!state->type_A && state->m_HiI2cPatch != NULL)
+                       status = WriteTable(state, state->m_HiI2cPatch);
+                       if (status < 0)
+                               break;
+
+               if (state->type_A) {
+                       /* HI firmware patch for UIO readout,
+                          avoid clearing of result register */
+                       status = Write16(state, 0x43012D, 0x047f, 0);
+                       if (status < 0)
+                               break;
+               }
+
+               status = HI_ResetCommand(state);
+               if (status < 0)
+                       break;
+
+               status = StopAllProcessors(state);
+               if (status < 0)
+                       break;
+               status = InitCC(state);
+               if (status < 0)
+                       break;
+
+               state->osc_clock_deviation = 0;
+
+               if (state->config.osc_deviation)
+                       state->osc_clock_deviation =
+                           state->config.osc_deviation(state->priv, 0, 0);
+               {
+                       /* Handle clock deviation */
+                       s32 devB;
+                       s32 devA = (s32) (state->osc_clock_deviation) *
+                           (s32) (state->expected_sys_clock_freq);
+                       /* deviation in kHz */
+                       s32 deviation = (devA / (1000000L));
+                       /* rounding, signed */
+                       if (devA > 0)
+                               devB = (2);
+                       else
+                               devB = (-2);
+                       if ((devB * (devA % 1000000L) > 1000000L)) {
+                               /* add +1 or -1 */
+                               deviation += (devB / 2);
+                       }
+
+                       state->sys_clock_freq =
+                           (u16) ((state->expected_sys_clock_freq) +
+                                  deviation);
+               }
+               status = InitHI(state);
+               if (status < 0)
+                       break;
+               status = InitAtomicRead(state);
+               if (status < 0)
+                       break;
+
+               status = EnableAndResetMB(state);
+               if (status < 0)
+                       break;
+               if (state->type_A)
+                       status = ResetCEFR(state);
+                       if (status < 0)
+                               break;
+
+               if (fw) {
+                       status = DownloadMicrocode(state, fw, fw_size);
+                       if (status < 0)
+                               break;
+               } else {
+                       status = DownloadMicrocode(state, state->microcode, state->microcode_length);
+                       if (status < 0)
+                               break;
+               }
+
+               if (state->PGA) {
+                       state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_PRO;
+                       SetCfgPga(state, 0);    /* PGA = 0 dB */
+               } else {
+                       state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_CONSUMER;
+               }
+
+               state->m_FeAgRegAgAgcSio = DRXD_DEF_AG_AGC_SIO;
+
+               status = InitFE(state);
+               if (status < 0)
+                       break;
+               status = InitFT(state);
+               if (status < 0)
+                       break;
+               status = InitCP(state);
+               if (status < 0)
+                       break;
+               status = InitCE(state);
+               if (status < 0)
+                       break;
+               status = InitEQ(state);
+               if (status < 0)
+                       break;
+               status = InitEC(state);
+               if (status < 0)
+                       break;
+               status = InitSC(state);
+               if (status < 0)
+                       break;
+
+               status = SetCfgIfAgc(state, &state->if_agc_cfg);
+               if (status < 0)
+                       break;
+               status = SetCfgRfAgc(state, &state->rf_agc_cfg);
+               if (status < 0)
+                       break;
+
+               state->cscd_state = CSCD_INIT;
+               status = Write16(state, SC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+               if (status < 0)
+                       break;
+               status = Write16(state, LC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+               if (status < 0)
+                       break;
+
+               driverVersion = (((VERSION_MAJOR / 10) << 4) +
+                                (VERSION_MAJOR % 10)) << 24;
+               driverVersion += (((VERSION_MINOR / 10) << 4) +
+                                 (VERSION_MINOR % 10)) << 16;
+               driverVersion += ((VERSION_PATCH / 1000) << 12) +
+                   ((VERSION_PATCH / 100) << 8) +
+                   ((VERSION_PATCH / 10) << 4) + (VERSION_PATCH % 10);
+
+               status = Write32(state, SC_RA_RAM_DRIVER_VERSION__AX, driverVersion, 0);
+               if (status < 0)
+                       break;
+
+               status = StopOC(state);
+               if (status < 0)
+                       break;
+
+               state->drxd_state = DRXD_STOPPED;
+               state->init_done = 1;
+               status = 0;
+       } while (0);
+       return status;
+}
+
+int DRXD_status(struct drxd_state *state, u32 * pLockStatus)
+{
+       DRX_GetLockStatus(state, pLockStatus);
+
+       /*if (*pLockStatus&DRX_LOCK_MPEG) */
+       if (*pLockStatus & DRX_LOCK_FEC) {
+               ConfigureMPEGOutput(state, 1);
+               /* Get status again, in case we have MPEG lock now */
+               /*DRX_GetLockStatus(state, pLockStatus); */
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+static int drxd_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
+{
+       struct drxd_state *state = fe->demodulator_priv;
+       u32 value;
+       int res;
+
+       res = ReadIFAgc(state, &value);
+       if (res < 0)
+               *strength = 0;
+       else
+               *strength = 0xffff - (value << 4);
+       return 0;
+}
+
+static int drxd_read_status(struct dvb_frontend *fe, fe_status_t * status)
+{
+       struct drxd_state *state = fe->demodulator_priv;
+       u32 lock;
+
+       DRXD_status(state, &lock);
+       *status = 0;
+       /* No MPEG lock in V255 firmware, bug ? */
+#if 1
+       if (lock & DRX_LOCK_MPEG)
+               *status |= FE_HAS_LOCK;
+#else
+       if (lock & DRX_LOCK_FEC)
+               *status |= FE_HAS_LOCK;
+#endif
+       if (lock & DRX_LOCK_FEC)
+               *status |= FE_HAS_VITERBI | FE_HAS_SYNC;
+       if (lock & DRX_LOCK_DEMOD)
+               *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+
+       return 0;
+}
+
+static int drxd_init(struct dvb_frontend *fe)
+{
+       struct drxd_state *state = fe->demodulator_priv;
+       int err = 0;
+
+/*     if (request_firmware(&state->fw, "drxd.fw", state->dev)<0) */
+       return DRXD_init(state, 0, 0);
+
+       err = DRXD_init(state, state->fw->data, state->fw->size);
+       release_firmware(state->fw);
+       return err;
+}
+
+int drxd_config_i2c(struct dvb_frontend *fe, int onoff)
+{
+       struct drxd_state *state = fe->demodulator_priv;
+
+       if (state->config.disable_i2c_gate_ctrl == 1)
+               return 0;
+
+       return DRX_ConfigureI2CBridge(state, onoff);
+}
+EXPORT_SYMBOL(drxd_config_i2c);
+
+static int drxd_get_tune_settings(struct dvb_frontend *fe,
+                                 struct dvb_frontend_tune_settings *sets)
+{
+       sets->min_delay_ms = 10000;
+       sets->max_drift = 0;
+       sets->step_size = 0;
+       return 0;
+}
+
+static int drxd_read_ber(struct dvb_frontend *fe, u32 * ber)
+{
+       *ber = 0;
+       return 0;
+}
+
+static int drxd_read_snr(struct dvb_frontend *fe, u16 * snr)
+{
+       *snr = 0;
+       return 0;
+}
+
+static int drxd_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks)
+{
+       *ucblocks = 0;
+       return 0;
+}
+
+static int drxd_sleep(struct dvb_frontend *fe)
+{
+       struct drxd_state *state = fe->demodulator_priv;
+
+       ConfigureMPEGOutput(state, 0);
+       return 0;
+}
+
+static int drxd_get_frontend(struct dvb_frontend *fe,
+                            struct dvb_frontend_parameters *param)
+{
+       return 0;
+}
+
+static int drxd_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       return drxd_config_i2c(fe, enable);
+}
+
+static int drxd_set_frontend(struct dvb_frontend *fe,
+                            struct dvb_frontend_parameters *param)
+{
+       struct drxd_state *state = fe->demodulator_priv;
+       s32 off = 0;
+
+       state->param = *param;
+       DRX_Stop(state);
+
+       if (fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, param);
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
+       }
+
+       /* FIXME: move PLL drivers */
+       if (state->config.pll_set &&
+           state->config.pll_set(state->priv, param,
+                                 state->config.pll_address,
+                                 state->config.demoda_address, &off) < 0) {
+               printk(KERN_ERR "Error in pll_set\n");
+               return -1;
+       }
+
+       msleep(200);
+
+       return DRX_Start(state, off);
+}
+
+static void drxd_release(struct dvb_frontend *fe)
+{
+       struct drxd_state *state = fe->demodulator_priv;
+
+       kfree(state);
+}
+
+static struct dvb_frontend_ops drxd_ops = {
+
+       .info = {
+                .name = "Micronas DRXD DVB-T",
+                .type = FE_OFDM,
+                .frequency_min = 47125000,
+                .frequency_max = 855250000,
+                .frequency_stepsize = 166667,
+                .frequency_tolerance = 0,
+                .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+                FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+                FE_CAN_FEC_AUTO |
+                FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+                FE_CAN_QAM_AUTO |
+                FE_CAN_TRANSMISSION_MODE_AUTO |
+                FE_CAN_GUARD_INTERVAL_AUTO |
+                FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS},
+
+       .release = drxd_release,
+       .init = drxd_init,
+       .sleep = drxd_sleep,
+       .i2c_gate_ctrl = drxd_i2c_gate_ctrl,
+
+       .set_frontend = drxd_set_frontend,
+       .get_frontend = drxd_get_frontend,
+       .get_tune_settings = drxd_get_tune_settings,
+
+       .read_status = drxd_read_status,
+       .read_ber = drxd_read_ber,
+       .read_signal_strength = drxd_read_signal_strength,
+       .read_snr = drxd_read_snr,
+       .read_ucblocks = drxd_read_ucblocks,
+};
+
+struct dvb_frontend *drxd_attach(const struct drxd_config *config,
+                                void *priv, struct i2c_adapter *i2c,
+                                struct device *dev)
+{
+       struct drxd_state *state = NULL;
+
+       state = kmalloc(sizeof(struct drxd_state), GFP_KERNEL);
+       if (!state)
+               return NULL;
+       memset(state, 0, sizeof(*state));
+
+       memcpy(&state->ops, &drxd_ops, sizeof(struct dvb_frontend_ops));
+       state->dev = dev;
+       state->config = *config;
+       state->i2c = i2c;
+       state->priv = priv;
+
+       mutex_init(&state->mutex);
+
+       if (Read16(state, 0, 0, 0) < 0)
+               goto error;
+
+       memcpy(&state->frontend.ops, &drxd_ops,
+              sizeof(struct dvb_frontend_ops));
+       state->frontend.demodulator_priv = state;
+       ConfigureMPEGOutput(state, 0);
+       return &state->frontend;
+
+error:
+       printk(KERN_ERR "drxd: not found\n");
+       kfree(state);
+       return NULL;
+}
+EXPORT_SYMBOL(drxd_attach);
+
+MODULE_DESCRIPTION("DRXD driver");
+MODULE_AUTHOR("Micronas");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/drxd_map_firm.h b/drivers/media/dvb/frontends/drxd_map_firm.h
new file mode 100644 (file)
index 0000000..6bc553a
--- /dev/null
@@ -0,0 +1,1013 @@
+/*
+ * drx3973d_map_firm.h
+ *
+ * Copyright (C) 2006-2007 Micronas
+ *
+ * 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
+ */
+
+#ifndef __DRX3973D_MAP__H__
+#define __DRX3973D_MAP__H__
+
+/*
+ * Note: originally, this file contained 12000+ lines of data
+ * Probably a few lines for every firwmare assembler instruction. However,
+ * only a few defines were actually used. So, removed all uneeded lines.
+ * If ever needed, the other lines can be easily obtained via git history.
+ */
+
+#define HI_COMM_EXEC__A                                              0x400000
+#define HI_COMM_MB__A                                                0x400002
+#define HI_CT_REG_COMM_STATE__A                                      0x410001
+#define HI_RA_RAM_SRV_RES__A                                         0x420031
+#define HI_RA_RAM_SRV_CMD__A                                         0x420032
+#define   HI_RA_RAM_SRV_CMD_RESET                                    0x2
+#define   HI_RA_RAM_SRV_CMD_CONFIG                                   0x3
+#define   HI_RA_RAM_SRV_CMD_EXECUTE                                  0x6
+#define HI_RA_RAM_SRV_RST_KEY__A                                     0x420033
+#define   HI_RA_RAM_SRV_RST_KEY_ACT                                  0x3973
+#define HI_RA_RAM_SRV_CFG_KEY__A                                     0x420033
+#define HI_RA_RAM_SRV_CFG_DIV__A                                     0x420034
+#define HI_RA_RAM_SRV_CFG_BDL__A                                     0x420035
+#define HI_RA_RAM_SRV_CFG_WUP__A                                     0x420036
+#define HI_RA_RAM_SRV_CFG_ACT__A                                     0x420037
+#define     HI_RA_RAM_SRV_CFG_ACT_SLV0_ON                            0x1
+#define   HI_RA_RAM_SRV_CFG_ACT_BRD__M                               0x4
+#define     HI_RA_RAM_SRV_CFG_ACT_BRD_OFF                            0x0
+#define     HI_RA_RAM_SRV_CFG_ACT_BRD_ON                             0x4
+#define     HI_RA_RAM_SRV_CFG_ACT_PWD_EXE                            0x8
+#define HI_RA_RAM_USR_BEGIN__A                                       0x420040
+#define HI_IF_RAM_TRP_BPT0__AX                                       0x430000
+#define HI_IF_RAM_USR_BEGIN__A                                       0x430200
+#define SC_COMM_EXEC__A                                              0x800000
+#define     SC_COMM_EXEC_CTL_STOP                                    0x0
+#define SC_COMM_STATE__A                                             0x800001
+#define SC_RA_RAM_PARAM0__A                                          0x820040
+#define SC_RA_RAM_PARAM1__A                                          0x820041
+#define SC_RA_RAM_CMD_ADDR__A                                        0x820042
+#define SC_RA_RAM_CMD__A                                             0x820043
+#define   SC_RA_RAM_CMD_PROC_START                                   0x1
+#define   SC_RA_RAM_CMD_SET_PREF_PARAM                               0x3
+#define   SC_RA_RAM_CMD_GET_OP_PARAM                                 0x5
+#define   SC_RA_RAM_SW_EVENT_RUN_NMASK__M                            0x1
+#define   SC_RA_RAM_LOCKTRACK_MIN                                    0x1
+#define     SC_RA_RAM_OP_PARAM_MODE_2K                               0x0
+#define     SC_RA_RAM_OP_PARAM_MODE_8K                               0x1
+#define     SC_RA_RAM_OP_PARAM_GUARD_32                              0x0
+#define     SC_RA_RAM_OP_PARAM_GUARD_16                              0x4
+#define     SC_RA_RAM_OP_PARAM_GUARD_8                               0x8
+#define     SC_RA_RAM_OP_PARAM_GUARD_4                               0xC
+#define     SC_RA_RAM_OP_PARAM_CONST_QPSK                            0x0
+#define     SC_RA_RAM_OP_PARAM_CONST_QAM16                           0x10
+#define     SC_RA_RAM_OP_PARAM_CONST_QAM64                           0x20
+#define     SC_RA_RAM_OP_PARAM_HIER_NO                               0x0
+#define     SC_RA_RAM_OP_PARAM_HIER_A1                               0x40
+#define     SC_RA_RAM_OP_PARAM_HIER_A2                               0x80
+#define     SC_RA_RAM_OP_PARAM_HIER_A4                               0xC0
+#define     SC_RA_RAM_OP_PARAM_RATE_1_2                              0x0
+#define     SC_RA_RAM_OP_PARAM_RATE_2_3                              0x200
+#define     SC_RA_RAM_OP_PARAM_RATE_3_4                              0x400
+#define     SC_RA_RAM_OP_PARAM_RATE_5_6                              0x600
+#define     SC_RA_RAM_OP_PARAM_RATE_7_8                              0x800
+#define     SC_RA_RAM_OP_PARAM_PRIO_HI                               0x0
+#define     SC_RA_RAM_OP_PARAM_PRIO_LO                               0x1000
+#define   SC_RA_RAM_OP_AUTO_MODE__M                                  0x1
+#define   SC_RA_RAM_OP_AUTO_GUARD__M                                 0x2
+#define   SC_RA_RAM_OP_AUTO_CONST__M                                 0x4
+#define   SC_RA_RAM_OP_AUTO_HIER__M                                  0x8
+#define   SC_RA_RAM_OP_AUTO_RATE__M                                  0x10
+#define SC_RA_RAM_LOCK__A                                            0x82004B
+#define   SC_RA_RAM_LOCK_DEMOD__M                                    0x1
+#define   SC_RA_RAM_LOCK_FEC__M                                      0x2
+#define   SC_RA_RAM_LOCK_MPEG__M                                     0x4
+#define SC_RA_RAM_BE_OPT_ENA__A                                      0x82004C
+#define   SC_RA_RAM_BE_OPT_ENA_CP_OPT                                0x1
+#define SC_RA_RAM_BE_OPT_DELAY__A                                    0x82004D
+#define SC_RA_RAM_CONFIG__A                                          0x820050
+#define   SC_RA_RAM_CONFIG_FR_ENABLE__M                              0x4
+#define   SC_RA_RAM_CONFIG_FREQSCAN__M                               0x10
+#define   SC_RA_RAM_CONFIG_SLAVE__M                                  0x20
+#define SC_RA_RAM_IF_SAVE__AX                                        0x82008E
+#define SC_RA_RAM_IR_COARSE_2K_LENGTH__A                             0x8200D1
+#define SC_RA_RAM_IR_COARSE_2K_LENGTH__PRE                           0x9
+#define SC_RA_RAM_IR_COARSE_2K_FREQINC__A                            0x8200D2
+#define SC_RA_RAM_IR_COARSE_2K_FREQINC__PRE                          0x4
+#define SC_RA_RAM_IR_COARSE_2K_KAISINC__A                            0x8200D3
+#define SC_RA_RAM_IR_COARSE_2K_KAISINC__PRE                          0x100
+#define SC_RA_RAM_IR_COARSE_8K_LENGTH__A                             0x8200D4
+#define SC_RA_RAM_IR_COARSE_8K_LENGTH__PRE                           0x8
+#define SC_RA_RAM_IR_COARSE_8K_FREQINC__A                            0x8200D5
+#define SC_RA_RAM_IR_COARSE_8K_FREQINC__PRE                          0x8
+#define SC_RA_RAM_IR_COARSE_8K_KAISINC__A                            0x8200D6
+#define SC_RA_RAM_IR_COARSE_8K_KAISINC__PRE                          0x200
+#define SC_RA_RAM_IR_FINE_2K_LENGTH__A                               0x8200D7
+#define SC_RA_RAM_IR_FINE_2K_LENGTH__PRE                             0x9
+#define SC_RA_RAM_IR_FINE_2K_FREQINC__A                              0x8200D8
+#define SC_RA_RAM_IR_FINE_2K_FREQINC__PRE                            0x4
+#define SC_RA_RAM_IR_FINE_2K_KAISINC__A                              0x8200D9
+#define SC_RA_RAM_IR_FINE_2K_KAISINC__PRE                            0x100
+#define SC_RA_RAM_IR_FINE_8K_LENGTH__A                               0x8200DA
+#define SC_RA_RAM_IR_FINE_8K_LENGTH__PRE                             0xB
+#define SC_RA_RAM_IR_FINE_8K_FREQINC__A                              0x8200DB
+#define SC_RA_RAM_IR_FINE_8K_FREQINC__PRE                            0x1
+#define SC_RA_RAM_IR_FINE_8K_KAISINC__A                              0x8200DC
+#define SC_RA_RAM_IR_FINE_8K_KAISINC__PRE                            0x40
+#define SC_RA_RAM_ECHO_SHIFT_LIM__A                                  0x8200DD
+#define SC_RA_RAM_SAMPLE_RATE_COUNT__A                               0x8200E8
+#define SC_RA_RAM_SAMPLE_RATE_STEP__A                                0x8200E9
+#define SC_RA_RAM_BAND__A                                            0x8200EC
+#define SC_RA_RAM_LC_ABS_2K__A                                       0x8200F4
+#define SC_RA_RAM_LC_ABS_2K__PRE                                     0x1F
+#define SC_RA_RAM_LC_ABS_8K__A                                       0x8200F5
+#define SC_RA_RAM_LC_ABS_8K__PRE                                     0x1F
+#define SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE                        0x1D6
+#define SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE                        0x4
+#define SC_RA_RAM_EQ_IS_GAIN_QPSK_MAN__PRE                           0x1BB
+#define SC_RA_RAM_EQ_IS_GAIN_QPSK_EXP__PRE                           0x5
+#define SC_RA_RAM_EQ_IS_GAIN_16QAM_MAN__PRE                          0x1EF
+#define SC_RA_RAM_EQ_IS_GAIN_16QAM_EXP__PRE                          0x5
+#define SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_MAN__PRE                       0x15E
+#define SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_EXP__PRE                       0x5
+#define SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_MAN__PRE                       0x11A
+#define SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_EXP__PRE                       0x6
+#define SC_RA_RAM_EQ_IS_GAIN_64QAM_MAN__PRE                          0x1FB
+#define SC_RA_RAM_EQ_IS_GAIN_64QAM_EXP__PRE                          0x5
+#define SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_MAN__PRE                       0x12F
+#define SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_EXP__PRE                       0x5
+#define SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_MAN__PRE                       0x197
+#define SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_EXP__PRE                       0x5
+#define SC_RA_RAM_DRIVER_VERSION__AX                                 0x8201FE
+#define   SC_RA_RAM_PROC_LOCKTRACK                                   0x0
+#define FE_COMM_EXEC__A                                              0xC00000
+#define FE_AD_REG_COMM_EXEC__A                                       0xC10000
+#define FE_AD_REG_FDB_IN__A                                          0xC10012
+#define FE_AD_REG_PD__A                                              0xC10013
+#define FE_AD_REG_INVEXT__A                                          0xC10014
+#define FE_AD_REG_CLKNEG__A                                          0xC10015
+#define FE_AG_REG_COMM_EXEC__A                                       0xC20000
+#define FE_AG_REG_AG_MODE_LOP__A                                     0xC20010
+#define   FE_AG_REG_AG_MODE_LOP_MODE_4__M                            0x10
+#define     FE_AG_REG_AG_MODE_LOP_MODE_4_STATIC                      0x0
+#define     FE_AG_REG_AG_MODE_LOP_MODE_4_DYNAMIC                     0x10
+#define   FE_AG_REG_AG_MODE_LOP_MODE_5__M                            0x20
+#define     FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC                      0x0
+#define   FE_AG_REG_AG_MODE_LOP_MODE_C__M                            0x1000
+#define     FE_AG_REG_AG_MODE_LOP_MODE_C_STATIC                      0x0
+#define     FE_AG_REG_AG_MODE_LOP_MODE_C_DYNAMIC                     0x1000
+#define   FE_AG_REG_AG_MODE_LOP_MODE_E__M                            0x4000
+#define     FE_AG_REG_AG_MODE_LOP_MODE_E_STATIC                      0x0
+#define     FE_AG_REG_AG_MODE_LOP_MODE_E_DYNAMIC                     0x4000
+#define FE_AG_REG_AG_MODE_HIP__A                                     0xC20011
+#define FE_AG_REG_AG_PGA_MODE__A                                     0xC20012
+#define   FE_AG_REG_AG_PGA_MODE_PFY_PCY_AFY_REN                      0x0
+#define   FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN                      0x1
+#define FE_AG_REG_AG_AGC_SIO__A                                      0xC20013
+#define   FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M                          0x2
+#define     FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_OUTPUT                    0x0
+#define     FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_INPUT                     0x2
+#define FE_AG_REG_AG_PWD__A                                          0xC20015
+#define   FE_AG_REG_AG_PWD_PWD_PD2__M                                0x2
+#define     FE_AG_REG_AG_PWD_PWD_PD2_DISABLE                         0x0
+#define     FE_AG_REG_AG_PWD_PWD_PD2_ENABLE                          0x2
+#define FE_AG_REG_DCE_AUR_CNT__A                                     0xC20016
+#define FE_AG_REG_DCE_RUR_CNT__A                                     0xC20017
+#define FE_AG_REG_ACE_AUR_CNT__A                                     0xC2001A
+#define FE_AG_REG_ACE_RUR_CNT__A                                     0xC2001B
+#define FE_AG_REG_CDR_RUR_CNT__A                                     0xC20020
+#define FE_AG_REG_EGC_RUR_CNT__A                                     0xC20024
+#define FE_AG_REG_EGC_SET_LVL__A                                     0xC20025
+#define FE_AG_REG_EGC_SET_LVL__M                                     0x1FF
+#define FE_AG_REG_EGC_FLA_RGN__A                                     0xC20026
+#define FE_AG_REG_EGC_SLO_RGN__A                                     0xC20027
+#define FE_AG_REG_EGC_JMP_PSN__A                                     0xC20028
+#define FE_AG_REG_EGC_FLA_INC__A                                     0xC20029
+#define FE_AG_REG_EGC_FLA_DEC__A                                     0xC2002A
+#define FE_AG_REG_EGC_SLO_INC__A                                     0xC2002B
+#define FE_AG_REG_EGC_SLO_DEC__A                                     0xC2002C
+#define FE_AG_REG_EGC_FAS_INC__A                                     0xC2002D
+#define FE_AG_REG_EGC_FAS_DEC__A                                     0xC2002E
+#define FE_AG_REG_PM1_AGC_WRI__A                                     0xC20030
+#define FE_AG_REG_PM1_AGC_WRI__M                                     0x7FF
+#define FE_AG_REG_GC1_AGC_RIC__A                                     0xC20031
+#define FE_AG_REG_GC1_AGC_OFF__A                                     0xC20032
+#define FE_AG_REG_GC1_AGC_MAX__A                                     0xC20033
+#define FE_AG_REG_GC1_AGC_MIN__A                                     0xC20034
+#define FE_AG_REG_GC1_AGC_DAT__A                                     0xC20035
+#define FE_AG_REG_GC1_AGC_DAT__M                                     0x3FF
+#define FE_AG_REG_PM2_AGC_WRI__A                                     0xC20036
+#define FE_AG_REG_IND_WIN__A                                         0xC2003C
+#define FE_AG_REG_IND_THD_LOL__A                                     0xC2003D
+#define FE_AG_REG_IND_THD_HIL__A                                     0xC2003E
+#define FE_AG_REG_IND_DEL__A                                         0xC2003F
+#define FE_AG_REG_IND_PD1_WRI__A                                     0xC20040
+#define FE_AG_REG_PDA_AUR_CNT__A                                     0xC20041
+#define FE_AG_REG_PDA_RUR_CNT__A                                     0xC20042
+#define FE_AG_REG_PDA_AVE_DAT__A                                     0xC20043
+#define FE_AG_REG_PDC_RUR_CNT__A                                     0xC20044
+#define FE_AG_REG_PDC_SET_LVL__A                                     0xC20045
+#define FE_AG_REG_PDC_FLA_RGN__A                                     0xC20046
+#define FE_AG_REG_PDC_JMP_PSN__A                                     0xC20047
+#define FE_AG_REG_PDC_FLA_STP__A                                     0xC20048
+#define FE_AG_REG_PDC_SLO_STP__A                                     0xC20049
+#define FE_AG_REG_PDC_PD2_WRI__A                                     0xC2004A
+#define FE_AG_REG_PDC_MAP_DAT__A                                     0xC2004B
+#define FE_AG_REG_PDC_MAX__A                                         0xC2004C
+#define FE_AG_REG_TGA_AUR_CNT__A                                     0xC2004D
+#define FE_AG_REG_TGA_RUR_CNT__A                                     0xC2004E
+#define FE_AG_REG_TGA_AVE_DAT__A                                     0xC2004F
+#define FE_AG_REG_TGC_RUR_CNT__A                                     0xC20050
+#define FE_AG_REG_TGC_SET_LVL__A                                     0xC20051
+#define FE_AG_REG_TGC_SET_LVL__M                                     0x3F
+#define FE_AG_REG_TGC_FLA_RGN__A                                     0xC20052
+#define FE_AG_REG_TGC_JMP_PSN__A                                     0xC20053
+#define FE_AG_REG_TGC_FLA_STP__A                                     0xC20054
+#define FE_AG_REG_TGC_SLO_STP__A                                     0xC20055
+#define FE_AG_REG_TGC_MAP_DAT__A                                     0xC20056
+#define FE_AG_REG_FGA_AUR_CNT__A                                     0xC20057
+#define FE_AG_REG_FGA_RUR_CNT__A                                     0xC20058
+#define FE_AG_REG_FGM_WRI__A                                         0xC20061
+#define FE_AG_REG_BGC_FGC_WRI__A                                     0xC20068
+#define FE_AG_REG_BGC_CGC_WRI__A                                     0xC20069
+#define FE_FS_REG_COMM_EXEC__A                                       0xC30000
+#define FE_FS_REG_ADD_INC_LOP__A                                     0xC30010
+#define FE_FD_REG_COMM_EXEC__A                                       0xC40000
+#define FE_FD_REG_SCL__A                                             0xC40010
+#define FE_FD_REG_MAX_LEV__A                                         0xC40011
+#define FE_FD_REG_NR__A                                              0xC40012
+#define FE_FD_REG_MEAS_VAL__A                                        0xC40014
+#define FE_IF_REG_COMM_EXEC__A                                       0xC50000
+#define FE_IF_REG_INCR0__A                                           0xC50010
+#define FE_IF_REG_INCR0__W                                           16
+#define FE_IF_REG_INCR0__M                                           0xFFFF
+#define FE_IF_REG_INCR1__A                                           0xC50011
+#define FE_IF_REG_INCR1__M                                           0xFF
+#define FE_CF_REG_COMM_EXEC__A                                       0xC60000
+#define FE_CF_REG_SCL__A                                             0xC60010
+#define FE_CF_REG_MAX_LEV__A                                         0xC60011
+#define FE_CF_REG_NR__A                                              0xC60012
+#define FE_CF_REG_IMP_VAL__A                                         0xC60013
+#define FE_CF_REG_MEAS_VAL__A                                        0xC60014
+#define FE_CU_REG_COMM_EXEC__A                                       0xC70000
+#define FE_CU_REG_FRM_CNT_RST__A                                     0xC70011
+#define FE_CU_REG_FRM_CNT_STR__A                                     0xC70012
+#define FT_COMM_EXEC__A                                              0x1000000
+#define FT_REG_COMM_EXEC__A                                          0x1010000
+#define CP_COMM_EXEC__A                                              0x1400000
+#define CP_REG_COMM_EXEC__A                                          0x1410000
+#define CP_REG_INTERVAL__A                                           0x1410011
+#define CP_REG_BR_SPL_OFFSET__A                                      0x1410023
+#define CP_REG_BR_STR_DEL__A                                         0x1410024
+#define CP_REG_RT_ANG_INC0__A                                        0x1410030
+#define CP_REG_RT_ANG_INC1__A                                        0x1410031
+#define CP_REG_RT_DETECT_ENA__A                                      0x1410032
+#define CP_REG_RT_DETECT_TRH__A                                      0x1410033
+#define CP_REG_RT_EXP_MARG__A                                        0x141003E
+#define CP_REG_AC_NEXP_OFFS__A                                       0x1410040
+#define CP_REG_AC_AVER_POW__A                                        0x1410041
+#define CP_REG_AC_MAX_POW__A                                         0x1410042
+#define CP_REG_AC_WEIGHT_MAN__A                                      0x1410043
+#define CP_REG_AC_WEIGHT_EXP__A                                      0x1410044
+#define CP_REG_AC_AMP_MODE__A                                        0x1410047
+#define CP_REG_AC_AMP_FIX__A                                         0x1410048
+#define CP_REG_AC_ANG_MODE__A                                        0x141004A
+#define CE_COMM_EXEC__A                                              0x1800000
+#define CE_REG_COMM_EXEC__A                                          0x1810000
+#define CE_REG_TAPSET__A                                             0x1810011
+#define CE_REG_AVG_POW__A                                            0x1810012
+#define CE_REG_MAX_POW__A                                            0x1810013
+#define CE_REG_ATT__A                                                0x1810014
+#define CE_REG_NRED__A                                               0x1810015
+#define CE_REG_NE_ERR_SELECT__A                                      0x1810043
+#define CE_REG_NE_TD_CAL__A                                          0x1810044
+#define CE_REG_NE_MIXAVG__A                                          0x1810046
+#define CE_REG_NE_NUPD_OFS__A                                        0x1810047
+#define CE_REG_PE_NEXP_OFFS__A                                       0x1810050
+#define CE_REG_PE_TIMESHIFT__A                                       0x1810051
+#define CE_REG_TP_A0_TAP_NEW__A                                      0x1810064
+#define CE_REG_TP_A0_TAP_NEW_VALID__A                                0x1810065
+#define CE_REG_TP_A0_MU_LMS_STEP__A                                  0x1810066
+#define CE_REG_TP_A1_TAP_NEW__A                                      0x1810068
+#define CE_REG_TP_A1_TAP_NEW_VALID__A                                0x1810069
+#define CE_REG_TP_A1_MU_LMS_STEP__A                                  0x181006A
+#define CE_REG_TI_NEXP_OFFS__A                                       0x1810070
+#define CE_REG_FI_SHT_INCR__A                                        0x1810090
+#define CE_REG_FI_EXP_NORM__A                                        0x1810091
+#define CE_REG_IR_INPUTSEL__A                                        0x18100A0
+#define CE_REG_IR_STARTPOS__A                                        0x18100A1
+#define CE_REG_IR_NEXP_THRES__A                                      0x18100A2
+#define CE_REG_FR_TREAL00__A                                         0x1820010
+#define CE_REG_FR_TIMAG00__A                                         0x1820011
+#define CE_REG_FR_TREAL01__A                                         0x1820012
+#define CE_REG_FR_TIMAG01__A                                         0x1820013
+#define CE_REG_FR_TREAL02__A                                         0x1820014
+#define CE_REG_FR_TIMAG02__A                                         0x1820015
+#define CE_REG_FR_TREAL03__A                                         0x1820016
+#define CE_REG_FR_TIMAG03__A                                         0x1820017
+#define CE_REG_FR_TREAL04__A                                         0x1820018
+#define CE_REG_FR_TIMAG04__A                                         0x1820019
+#define CE_REG_FR_TREAL05__A                                         0x182001A
+#define CE_REG_FR_TIMAG05__A                                         0x182001B
+#define CE_REG_FR_TREAL06__A                                         0x182001C
+#define CE_REG_FR_TIMAG06__A                                         0x182001D
+#define CE_REG_FR_TREAL07__A                                         0x182001E
+#define CE_REG_FR_TIMAG07__A                                         0x182001F
+#define CE_REG_FR_TREAL08__A                                         0x1820020
+#define CE_REG_FR_TIMAG08__A                                         0x1820021
+#define CE_REG_FR_TREAL09__A                                         0x1820022
+#define CE_REG_FR_TIMAG09__A                                         0x1820023
+#define CE_REG_FR_TREAL10__A                                         0x1820024
+#define CE_REG_FR_TIMAG10__A                                         0x1820025
+#define CE_REG_FR_TREAL11__A                                         0x1820026
+#define CE_REG_FR_TIMAG11__A                                         0x1820027
+#define CE_REG_FR_MID_TAP__A                                         0x1820028
+#define CE_REG_FR_SQS_G00__A                                         0x1820029
+#define CE_REG_FR_SQS_G01__A                                         0x182002A
+#define CE_REG_FR_SQS_G02__A                                         0x182002B
+#define CE_REG_FR_SQS_G03__A                                         0x182002C
+#define CE_REG_FR_SQS_G04__A                                         0x182002D
+#define CE_REG_FR_SQS_G05__A                                         0x182002E
+#define CE_REG_FR_SQS_G06__A                                         0x182002F
+#define CE_REG_FR_SQS_G07__A                                         0x1820030
+#define CE_REG_FR_SQS_G08__A                                         0x1820031
+#define CE_REG_FR_SQS_G09__A                                         0x1820032
+#define CE_REG_FR_SQS_G10__A                                         0x1820033
+#define CE_REG_FR_SQS_G11__A                                         0x1820034
+#define CE_REG_FR_SQS_G12__A                                         0x1820035
+#define CE_REG_FR_RIO_G00__A                                         0x1820036
+#define CE_REG_FR_RIO_G01__A                                         0x1820037
+#define CE_REG_FR_RIO_G02__A                                         0x1820038
+#define CE_REG_FR_RIO_G03__A                                         0x1820039
+#define CE_REG_FR_RIO_G04__A                                         0x182003A
+#define CE_REG_FR_RIO_G05__A                                         0x182003B
+#define CE_REG_FR_RIO_G06__A                                         0x182003C
+#define CE_REG_FR_RIO_G07__A                                         0x182003D
+#define CE_REG_FR_RIO_G08__A                                         0x182003E
+#define CE_REG_FR_RIO_G09__A                                         0x182003F
+#define CE_REG_FR_RIO_G10__A                                         0x1820040
+#define CE_REG_FR_MODE__A                                            0x1820041
+#define CE_REG_FR_SQS_TRH__A                                         0x1820042
+#define CE_REG_FR_RIO_GAIN__A                                        0x1820043
+#define CE_REG_FR_BYPASS__A                                          0x1820044
+#define CE_REG_FR_PM_SET__A                                          0x1820045
+#define CE_REG_FR_ERR_SH__A                                          0x1820046
+#define CE_REG_FR_MAN_SH__A                                          0x1820047
+#define CE_REG_FR_TAP_SH__A                                          0x1820048
+#define EQ_COMM_EXEC__A                                              0x1C00000
+#define EQ_REG_COMM_EXEC__A                                          0x1C10000
+#define EQ_REG_COMM_MB__A                                            0x1C10002
+#define EQ_REG_IS_GAIN_MAN__A                                        0x1C10015
+#define EQ_REG_IS_GAIN_EXP__A                                        0x1C10016
+#define EQ_REG_IS_CLIP_EXP__A                                        0x1C10017
+#define EQ_REG_SN_CEGAIN__A                                          0x1C1002A
+#define EQ_REG_SN_OFFSET__A                                          0x1C1002B
+#define EQ_REG_RC_SEL_CAR__A                                         0x1C10032
+#define   EQ_REG_RC_SEL_CAR_INIT                                     0x0
+#define     EQ_REG_RC_SEL_CAR_DIV_ON                                 0x1
+#define     EQ_REG_RC_SEL_CAR_PASS_A_CC                              0x0
+#define     EQ_REG_RC_SEL_CAR_PASS_B_CE                              0x2
+#define     EQ_REG_RC_SEL_CAR_LOCAL_A_CC                             0x0
+#define     EQ_REG_RC_SEL_CAR_LOCAL_B_CE                             0x8
+#define     EQ_REG_RC_SEL_CAR_MEAS_A_CC                              0x0
+#define     EQ_REG_RC_SEL_CAR_MEAS_B_CE                              0x20
+#define EQ_REG_OT_CONST__A                                           0x1C10046
+#define EQ_REG_OT_ALPHA__A                                           0x1C10047
+#define EQ_REG_OT_QNT_THRES0__A                                      0x1C10048
+#define EQ_REG_OT_QNT_THRES1__A                                      0x1C10049
+#define EQ_REG_OT_CSI_STEP__A                                        0x1C1004A
+#define EQ_REG_OT_CSI_OFFSET__A                                      0x1C1004B
+#define EQ_REG_TD_REQ_SMB_CNT__A                                     0x1C10061
+#define EQ_REG_TD_TPS_PWR_OFS__A                                     0x1C10062
+#define EC_SB_REG_COMM_EXEC__A                                       0x2010000
+#define EC_SB_REG_TR_MODE__A                                         0x2010010
+#define   EC_SB_REG_TR_MODE_8K                                       0x0
+#define   EC_SB_REG_TR_MODE_2K                                       0x1
+#define EC_SB_REG_CONST__A                                           0x2010011
+#define   EC_SB_REG_CONST_QPSK                                       0x0
+#define   EC_SB_REG_CONST_16QAM                                      0x1
+#define   EC_SB_REG_CONST_64QAM                                      0x2
+#define EC_SB_REG_ALPHA__A                                           0x2010012
+#define EC_SB_REG_PRIOR__A                                           0x2010013
+#define   EC_SB_REG_PRIOR_HI                                         0x0
+#define   EC_SB_REG_PRIOR_LO                                         0x1
+#define EC_SB_REG_CSI_HI__A                                          0x2010014
+#define EC_SB_REG_CSI_LO__A                                          0x2010015
+#define EC_SB_REG_SMB_TGL__A                                         0x2010016
+#define EC_SB_REG_SNR_HI__A                                          0x2010017
+#define EC_SB_REG_SNR_MID__A                                         0x2010018
+#define EC_SB_REG_SNR_LO__A                                          0x2010019
+#define EC_SB_REG_SCALE_MSB__A                                       0x201001A
+#define EC_SB_REG_SCALE_BIT2__A                                      0x201001B
+#define EC_SB_REG_SCALE_LSB__A                                       0x201001C
+#define EC_SB_REG_CSI_OFS__A                                         0x201001D
+#define EC_VD_REG_COMM_EXEC__A                                       0x2090000
+#define EC_VD_REG_FORCE__A                                           0x2090010
+#define EC_VD_REG_SET_CODERATE__A                                    0x2090011
+#define   EC_VD_REG_SET_CODERATE_C1_2                                0x0
+#define   EC_VD_REG_SET_CODERATE_C2_3                                0x1
+#define   EC_VD_REG_SET_CODERATE_C3_4                                0x2
+#define   EC_VD_REG_SET_CODERATE_C5_6                                0x3
+#define   EC_VD_REG_SET_CODERATE_C7_8                                0x4
+#define EC_VD_REG_REQ_SMB_CNT__A                                     0x2090012
+#define EC_VD_REG_RLK_ENA__A                                         0x2090014
+#define EC_OD_REG_COMM_EXEC__A                                       0x2110000
+#define EC_OD_REG_SYNC__A                                            0x2110010
+#define EC_OD_DEINT_RAM__A                                           0x2120000
+#define EC_RS_REG_COMM_EXEC__A                                       0x2130000
+#define EC_RS_REG_REQ_PCK_CNT__A                                     0x2130010
+#define EC_RS_REG_VAL__A                                             0x2130011
+#define   EC_RS_REG_VAL_PCK                                          0x1
+#define EC_RS_EC_RAM__A                                              0x2140000
+#define EC_OC_REG_COMM_EXEC__A                                       0x2150000
+#define     EC_OC_REG_COMM_EXEC_CTL_ACTIVE                           0x1
+#define     EC_OC_REG_COMM_EXEC_CTL_HOLD                             0x2
+#define EC_OC_REG_COMM_INT_STA__A                                    0x2150007
+#define EC_OC_REG_OC_MODE_LOP__A                                     0x2150010
+#define   EC_OC_REG_OC_MODE_LOP_PAR_ENA__M                           0x1
+#define     EC_OC_REG_OC_MODE_LOP_PAR_ENA_ENABLE                     0x0
+#define     EC_OC_REG_OC_MODE_LOP_PAR_ENA_DISABLE                    0x1
+#define   EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC__M                       0x4
+#define     EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC_STATIC                 0x0
+#define   EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE__M                       0x80
+#define     EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE_SERIAL                 0x80
+#define EC_OC_REG_OC_MODE_HIP__A                                     0x2150011
+#define     EC_OC_REG_OC_MODE_HIP_MPG_BUS_SRC_MONITOR                0x10
+#define   EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL__M                       0x200
+#define     EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_DISABLE                0x0
+#define     EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_ENABLE                 0x200
+#define EC_OC_REG_OC_MPG_SIO__A                                      0x2150012
+#define EC_OC_REG_OC_MPG_SIO__M                                      0xFFF
+#define EC_OC_REG_OC_MON_SIO__A                                      0x2150013
+#define EC_OC_REG_DTO_INC_LOP__A                                     0x2150014
+#define EC_OC_REG_DTO_INC_HIP__A                                     0x2150015
+#define EC_OC_REG_SNC_ISC_LVL__A                                     0x2150016
+#define   EC_OC_REG_SNC_ISC_LVL_OSC__M                               0xF0
+#define EC_OC_REG_TMD_TOP_MODE__A                                    0x215001D
+#define EC_OC_REG_TMD_TOP_CNT__A                                     0x215001E
+#define EC_OC_REG_TMD_HIL_MAR__A                                     0x215001F
+#define EC_OC_REG_TMD_LOL_MAR__A                                     0x2150020
+#define EC_OC_REG_TMD_CUR_CNT__A                                     0x2150021
+#define EC_OC_REG_AVR_ASH_CNT__A                                     0x2150023
+#define EC_OC_REG_AVR_BSH_CNT__A                                     0x2150024
+#define EC_OC_REG_RCN_MODE__A                                        0x2150027
+#define EC_OC_REG_RCN_CRA_LOP__A                                     0x2150028
+#define EC_OC_REG_RCN_CRA_HIP__A                                     0x2150029
+#define EC_OC_REG_RCN_CST_LOP__A                                     0x215002A
+#define EC_OC_REG_RCN_CST_HIP__A                                     0x215002B
+#define EC_OC_REG_RCN_SET_LVL__A                                     0x215002C
+#define EC_OC_REG_RCN_GAI_LVL__A                                     0x215002D
+#define EC_OC_REG_RCN_CLP_LOP__A                                     0x2150032
+#define EC_OC_REG_RCN_CLP_HIP__A                                     0x2150033
+#define EC_OC_REG_RCN_MAP_LOP__A                                     0x2150034
+#define EC_OC_REG_RCN_MAP_HIP__A                                     0x2150035
+#define EC_OC_REG_OCR_MPG_UOS__A                                     0x2150036
+#define EC_OC_REG_OCR_MPG_UOS__M                                     0xFFF
+#define   EC_OC_REG_OCR_MPG_UOS_INIT                                 0x0
+#define EC_OC_REG_OCR_MPG_USR_DAT__A                                 0x2150038
+#define EC_OC_REG_OCR_MON_UOS__A                                     0x2150039
+#define     EC_OC_REG_OCR_MON_UOS_DAT_0_ENABLE                       0x1
+#define     EC_OC_REG_OCR_MON_UOS_DAT_1_ENABLE                       0x2
+#define     EC_OC_REG_OCR_MON_UOS_DAT_2_ENABLE                       0x4
+#define     EC_OC_REG_OCR_MON_UOS_DAT_3_ENABLE                       0x8
+#define     EC_OC_REG_OCR_MON_UOS_DAT_4_ENABLE                       0x10
+#define     EC_OC_REG_OCR_MON_UOS_DAT_5_ENABLE                       0x20
+#define     EC_OC_REG_OCR_MON_UOS_DAT_6_ENABLE                       0x40
+#define     EC_OC_REG_OCR_MON_UOS_DAT_7_ENABLE                       0x80
+#define     EC_OC_REG_OCR_MON_UOS_DAT_8_ENABLE                       0x100
+#define     EC_OC_REG_OCR_MON_UOS_DAT_9_ENABLE                       0x200
+#define     EC_OC_REG_OCR_MON_UOS_VAL_ENABLE                         0x400
+#define     EC_OC_REG_OCR_MON_UOS_CLK_ENABLE                         0x800
+#define EC_OC_REG_OCR_MON_WRI__A                                     0x215003A
+#define   EC_OC_REG_OCR_MON_WRI_INIT                                 0x0
+#define EC_OC_REG_IPR_INV_MPG__A                                     0x2150045
+#define CC_REG_OSC_MODE__A                                           0x2410010
+#define   CC_REG_OSC_MODE_M20                                        0x1
+#define CC_REG_PLL_MODE__A                                           0x2410011
+#define     CC_REG_PLL_MODE_BYPASS_PLL                               0x1
+#define     CC_REG_PLL_MODE_PUMP_CUR_12                              0x14
+#define CC_REG_REF_DIVIDE__A                                         0x2410012
+#define CC_REG_PWD_MODE__A                                           0x2410015
+#define   CC_REG_PWD_MODE_DOWN_PLL                                   0x2
+#define CC_REG_UPDATE__A                                             0x2410017
+#define   CC_REG_UPDATE_KEY                                          0x3973
+#define CC_REG_JTAGID_L__A                                           0x2410019
+#define LC_COMM_EXEC__A                                              0x2800000
+#define LC_RA_RAM_IFINCR_NOM_L__A                                    0x282000C
+#define LC_RA_RAM_FILTER_SYM_SET__A                                  0x282001A
+#define LC_RA_RAM_FILTER_SYM_SET__PRE                                0x3E8
+#define LC_RA_RAM_FILTER_CRMM_A__A                                   0x2820060
+#define LC_RA_RAM_FILTER_CRMM_A__PRE                                 0x4
+#define LC_RA_RAM_FILTER_CRMM_B__A                                   0x2820061
+#define LC_RA_RAM_FILTER_CRMM_B__PRE                                 0x1
+#define LC_RA_RAM_FILTER_SRMM_A__A                                   0x2820068
+#define LC_RA_RAM_FILTER_SRMM_A__PRE                                 0x4
+#define LC_RA_RAM_FILTER_SRMM_B__A                                   0x2820069
+#define LC_RA_RAM_FILTER_SRMM_B__PRE                                 0x1
+#define B_HI_COMM_EXEC__A                                            0x400000
+#define B_HI_COMM_MB__A                                              0x400002
+#define B_HI_CT_REG_COMM_STATE__A                                    0x410001
+#define B_HI_RA_RAM_SRV_RES__A                                       0x420031
+#define B_HI_RA_RAM_SRV_CMD__A                                       0x420032
+#define   B_HI_RA_RAM_SRV_CMD_RESET                                  0x2
+#define   B_HI_RA_RAM_SRV_CMD_CONFIG                                 0x3
+#define   B_HI_RA_RAM_SRV_CMD_EXECUTE                                0x6
+#define B_HI_RA_RAM_SRV_RST_KEY__A                                   0x420033
+#define   B_HI_RA_RAM_SRV_RST_KEY_ACT                                0x3973
+#define B_HI_RA_RAM_SRV_CFG_KEY__A                                   0x420033
+#define B_HI_RA_RAM_SRV_CFG_DIV__A                                   0x420034
+#define B_HI_RA_RAM_SRV_CFG_BDL__A                                   0x420035
+#define B_HI_RA_RAM_SRV_CFG_WUP__A                                   0x420036
+#define B_HI_RA_RAM_SRV_CFG_ACT__A                                   0x420037
+#define     B_HI_RA_RAM_SRV_CFG_ACT_SLV0_ON                          0x1
+#define   B_HI_RA_RAM_SRV_CFG_ACT_BRD__M                             0x4
+#define     B_HI_RA_RAM_SRV_CFG_ACT_BRD_OFF                          0x0
+#define     B_HI_RA_RAM_SRV_CFG_ACT_BRD_ON                           0x4
+#define     B_HI_RA_RAM_SRV_CFG_ACT_PWD_EXE                          0x8
+#define B_HI_RA_RAM_USR_BEGIN__A                                     0x420040
+#define B_HI_IF_RAM_TRP_BPT0__AX                                     0x430000
+#define B_HI_IF_RAM_USR_BEGIN__A                                     0x430200
+#define B_SC_COMM_EXEC__A                                            0x800000
+#define     B_SC_COMM_EXEC_CTL_STOP                                  0x0
+#define B_SC_COMM_STATE__A                                           0x800001
+#define B_SC_RA_RAM_PARAM0__A                                        0x820040
+#define B_SC_RA_RAM_PARAM1__A                                        0x820041
+#define B_SC_RA_RAM_CMD_ADDR__A                                      0x820042
+#define B_SC_RA_RAM_CMD__A                                           0x820043
+#define   B_SC_RA_RAM_CMD_PROC_START                                 0x1
+#define   B_SC_RA_RAM_CMD_SET_PREF_PARAM                             0x3
+#define   B_SC_RA_RAM_CMD_GET_OP_PARAM                               0x5
+#define   B_SC_RA_RAM_SW_EVENT_RUN_NMASK__M                          0x1
+#define   B_SC_RA_RAM_LOCKTRACK_MIN                                  0x1
+#define     B_SC_RA_RAM_OP_PARAM_MODE_2K                             0x0
+#define     B_SC_RA_RAM_OP_PARAM_MODE_8K                             0x1
+#define     B_SC_RA_RAM_OP_PARAM_GUARD_32                            0x0
+#define     B_SC_RA_RAM_OP_PARAM_GUARD_16                            0x4
+#define     B_SC_RA_RAM_OP_PARAM_GUARD_8                             0x8
+#define     B_SC_RA_RAM_OP_PARAM_GUARD_4                             0xC
+#define     B_SC_RA_RAM_OP_PARAM_CONST_QPSK                          0x0
+#define     B_SC_RA_RAM_OP_PARAM_CONST_QAM16                         0x10
+#define     B_SC_RA_RAM_OP_PARAM_CONST_QAM64                         0x20
+#define     B_SC_RA_RAM_OP_PARAM_HIER_NO                             0x0
+#define     B_SC_RA_RAM_OP_PARAM_HIER_A1                             0x40
+#define     B_SC_RA_RAM_OP_PARAM_HIER_A2                             0x80
+#define     B_SC_RA_RAM_OP_PARAM_HIER_A4                             0xC0
+#define     B_SC_RA_RAM_OP_PARAM_RATE_1_2                            0x0
+#define     B_SC_RA_RAM_OP_PARAM_RATE_2_3                            0x200
+#define     B_SC_RA_RAM_OP_PARAM_RATE_3_4                            0x400
+#define     B_SC_RA_RAM_OP_PARAM_RATE_5_6                            0x600
+#define     B_SC_RA_RAM_OP_PARAM_RATE_7_8                            0x800
+#define     B_SC_RA_RAM_OP_PARAM_PRIO_HI                             0x0
+#define     B_SC_RA_RAM_OP_PARAM_PRIO_LO                             0x1000
+#define   B_SC_RA_RAM_OP_AUTO_MODE__M                                0x1
+#define   B_SC_RA_RAM_OP_AUTO_GUARD__M                               0x2
+#define   B_SC_RA_RAM_OP_AUTO_CONST__M                               0x4
+#define   B_SC_RA_RAM_OP_AUTO_HIER__M                                0x8
+#define   B_SC_RA_RAM_OP_AUTO_RATE__M                                0x10
+#define B_SC_RA_RAM_LOCK__A                                          0x82004B
+#define   B_SC_RA_RAM_LOCK_DEMOD__M                                  0x1
+#define   B_SC_RA_RAM_LOCK_FEC__M                                    0x2
+#define   B_SC_RA_RAM_LOCK_MPEG__M                                   0x4
+#define B_SC_RA_RAM_BE_OPT_ENA__A                                    0x82004C
+#define   B_SC_RA_RAM_BE_OPT_ENA_CP_OPT                              0x1
+#define B_SC_RA_RAM_BE_OPT_DELAY__A                                  0x82004D
+#define B_SC_RA_RAM_CONFIG__A                                        0x820050
+#define   B_SC_RA_RAM_CONFIG_FR_ENABLE__M                            0x4
+#define   B_SC_RA_RAM_CONFIG_FREQSCAN__M                             0x10
+#define   B_SC_RA_RAM_CONFIG_SLAVE__M                                0x20
+#define   B_SC_RA_RAM_CONFIG_DIV_BLANK_ENABLE__M                     0x200
+#define   B_SC_RA_RAM_CONFIG_DIV_ECHO_ENABLE__M                      0x400
+#define B_SC_RA_RAM_CO_TD_CAL_2K__A                                  0x82005D
+#define B_SC_RA_RAM_CO_TD_CAL_8K__A                                  0x82005E
+#define B_SC_RA_RAM_IF_SAVE__AX                                      0x82008E
+#define B_SC_RA_RAM_DIVERSITY_DELAY_2K_32__A                         0x820098
+#define B_SC_RA_RAM_DIVERSITY_DELAY_2K_16__A                         0x820099
+#define B_SC_RA_RAM_DIVERSITY_DELAY_2K_8__A                          0x82009A
+#define B_SC_RA_RAM_DIVERSITY_DELAY_2K_4__A                          0x82009B
+#define B_SC_RA_RAM_DIVERSITY_DELAY_8K_32__A                         0x82009C
+#define B_SC_RA_RAM_DIVERSITY_DELAY_8K_16__A                         0x82009D
+#define B_SC_RA_RAM_DIVERSITY_DELAY_8K_8__A                          0x82009E
+#define B_SC_RA_RAM_DIVERSITY_DELAY_8K_4__A                          0x82009F
+#define B_SC_RA_RAM_IR_COARSE_2K_LENGTH__A                           0x8200D1
+#define B_SC_RA_RAM_IR_COARSE_2K_LENGTH__PRE                         0x9
+#define B_SC_RA_RAM_IR_COARSE_2K_FREQINC__A                          0x8200D2
+#define B_SC_RA_RAM_IR_COARSE_2K_FREQINC__PRE                        0x4
+#define B_SC_RA_RAM_IR_COARSE_2K_KAISINC__A                          0x8200D3
+#define B_SC_RA_RAM_IR_COARSE_2K_KAISINC__PRE                        0x100
+#define B_SC_RA_RAM_IR_COARSE_8K_LENGTH__A                           0x8200D4
+#define B_SC_RA_RAM_IR_COARSE_8K_LENGTH__PRE                         0x8
+#define B_SC_RA_RAM_IR_COARSE_8K_FREQINC__A                          0x8200D5
+#define B_SC_RA_RAM_IR_COARSE_8K_FREQINC__PRE                        0x8
+#define B_SC_RA_RAM_IR_COARSE_8K_KAISINC__A                          0x8200D6
+#define B_SC_RA_RAM_IR_COARSE_8K_KAISINC__PRE                        0x200
+#define B_SC_RA_RAM_IR_FINE_2K_LENGTH__A                             0x8200D7
+#define B_SC_RA_RAM_IR_FINE_2K_LENGTH__PRE                           0x9
+#define B_SC_RA_RAM_IR_FINE_2K_FREQINC__A                            0x8200D8
+#define B_SC_RA_RAM_IR_FINE_2K_FREQINC__PRE                          0x4
+#define B_SC_RA_RAM_IR_FINE_2K_KAISINC__A                            0x8200D9
+#define B_SC_RA_RAM_IR_FINE_2K_KAISINC__PRE                          0x100
+#define B_SC_RA_RAM_IR_FINE_8K_LENGTH__A                             0x8200DA
+#define B_SC_RA_RAM_IR_FINE_8K_LENGTH__PRE                           0xB
+#define B_SC_RA_RAM_IR_FINE_8K_FREQINC__A                            0x8200DB
+#define B_SC_RA_RAM_IR_FINE_8K_FREQINC__PRE                          0x1
+#define B_SC_RA_RAM_IR_FINE_8K_KAISINC__A                            0x8200DC
+#define B_SC_RA_RAM_IR_FINE_8K_KAISINC__PRE                          0x40
+#define B_SC_RA_RAM_ECHO_SHIFT_LIM__A                                0x8200DD
+#define B_SC_RA_RAM_SAMPLE_RATE_COUNT__A                             0x8200E8
+#define B_SC_RA_RAM_SAMPLE_RATE_STEP__A                              0x8200E9
+#define B_SC_RA_RAM_BAND__A                                          0x8200EC
+#define B_SC_RA_RAM_LC_ABS_2K__A                                     0x8200F4
+#define B_SC_RA_RAM_LC_ABS_2K__PRE                                   0x1F
+#define B_SC_RA_RAM_LC_ABS_8K__A                                     0x8200F5
+#define B_SC_RA_RAM_LC_ABS_8K__PRE                                   0x1F
+#define B_SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE                      0x100
+#define B_SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE                      0x4
+#define B_SC_RA_RAM_EQ_IS_GAIN_QPSK_MAN__PRE                         0x1E2
+#define B_SC_RA_RAM_EQ_IS_GAIN_QPSK_EXP__PRE                         0x4
+#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_MAN__PRE                        0x10D
+#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_EXP__PRE                        0x5
+#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_MAN__PRE                     0x17D
+#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_EXP__PRE                     0x4
+#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_MAN__PRE                     0x133
+#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_EXP__PRE                     0x5
+#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_MAN__PRE                        0x114
+#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_EXP__PRE                        0x5
+#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_MAN__PRE                     0x14A
+#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_EXP__PRE                     0x4
+#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_MAN__PRE                     0x1BB
+#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_EXP__PRE                     0x4
+#define B_SC_RA_RAM_DRIVER_VERSION__AX                               0x8201FE
+#define   B_SC_RA_RAM_PROC_LOCKTRACK                                 0x0
+#define B_FE_COMM_EXEC__A                                            0xC00000
+#define B_FE_AD_REG_COMM_EXEC__A                                     0xC10000
+#define B_FE_AD_REG_FDB_IN__A                                        0xC10012
+#define B_FE_AD_REG_PD__A                                            0xC10013
+#define B_FE_AD_REG_INVEXT__A                                        0xC10014
+#define B_FE_AD_REG_CLKNEG__A                                        0xC10015
+#define B_FE_AG_REG_COMM_EXEC__A                                     0xC20000
+#define B_FE_AG_REG_AG_MODE_LOP__A                                   0xC20010
+#define   B_FE_AG_REG_AG_MODE_LOP_MODE_4__M                          0x10
+#define     B_FE_AG_REG_AG_MODE_LOP_MODE_4_STATIC                    0x0
+#define     B_FE_AG_REG_AG_MODE_LOP_MODE_4_DYNAMIC                   0x10
+#define   B_FE_AG_REG_AG_MODE_LOP_MODE_5__M                          0x20
+#define     B_FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC                    0x0
+#define   B_FE_AG_REG_AG_MODE_LOP_MODE_C__M                          0x1000
+#define     B_FE_AG_REG_AG_MODE_LOP_MODE_C_STATIC                    0x0
+#define     B_FE_AG_REG_AG_MODE_LOP_MODE_C_DYNAMIC                   0x1000
+#define   B_FE_AG_REG_AG_MODE_LOP_MODE_E__M                          0x4000
+#define     B_FE_AG_REG_AG_MODE_LOP_MODE_E_STATIC                    0x0
+#define     B_FE_AG_REG_AG_MODE_LOP_MODE_E_DYNAMIC                   0x4000
+#define B_FE_AG_REG_AG_MODE_HIP__A                                   0xC20011
+#define   B_FE_AG_REG_AG_MODE_HIP_MODE_J__M                          0x8
+#define     B_FE_AG_REG_AG_MODE_HIP_MODE_J_STATIC                    0x0
+#define     B_FE_AG_REG_AG_MODE_HIP_MODE_J_DYNAMIC                   0x8
+#define B_FE_AG_REG_AG_PGA_MODE__A                                   0xC20012
+#define   B_FE_AG_REG_AG_PGA_MODE_PFY_PCY_AFY_REN                    0x0
+#define   B_FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN                    0x1
+#define B_FE_AG_REG_AG_AGC_SIO__A                                    0xC20013
+#define   B_FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M                        0x2
+#define     B_FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_OUTPUT                  0x0
+#define     B_FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_INPUT                   0x2
+#define B_FE_AG_REG_AG_PWD__A                                        0xC20015
+#define   B_FE_AG_REG_AG_PWD_PWD_PD2__M                              0x2
+#define     B_FE_AG_REG_AG_PWD_PWD_PD2_DISABLE                       0x0
+#define     B_FE_AG_REG_AG_PWD_PWD_PD2_ENABLE                        0x2
+#define B_FE_AG_REG_DCE_AUR_CNT__A                                   0xC20016
+#define B_FE_AG_REG_DCE_RUR_CNT__A                                   0xC20017
+#define B_FE_AG_REG_ACE_AUR_CNT__A                                   0xC2001A
+#define B_FE_AG_REG_ACE_RUR_CNT__A                                   0xC2001B
+#define B_FE_AG_REG_CDR_RUR_CNT__A                                   0xC20020
+#define B_FE_AG_REG_EGC_RUR_CNT__A                                   0xC20024
+#define B_FE_AG_REG_EGC_SET_LVL__A                                   0xC20025
+#define B_FE_AG_REG_EGC_SET_LVL__M                                   0x1FF
+#define B_FE_AG_REG_EGC_FLA_RGN__A                                   0xC20026
+#define B_FE_AG_REG_EGC_SLO_RGN__A                                   0xC20027
+#define B_FE_AG_REG_EGC_JMP_PSN__A                                   0xC20028
+#define B_FE_AG_REG_EGC_FLA_INC__A                                   0xC20029
+#define B_FE_AG_REG_EGC_FLA_DEC__A                                   0xC2002A
+#define B_FE_AG_REG_EGC_SLO_INC__A                                   0xC2002B
+#define B_FE_AG_REG_EGC_SLO_DEC__A                                   0xC2002C
+#define B_FE_AG_REG_EGC_FAS_INC__A                                   0xC2002D
+#define B_FE_AG_REG_EGC_FAS_DEC__A                                   0xC2002E
+#define B_FE_AG_REG_PM1_AGC_WRI__A                                   0xC20030
+#define B_FE_AG_REG_PM1_AGC_WRI__M                                   0x7FF
+#define B_FE_AG_REG_GC1_AGC_RIC__A                                   0xC20031
+#define B_FE_AG_REG_GC1_AGC_OFF__A                                   0xC20032
+#define B_FE_AG_REG_GC1_AGC_MAX__A                                   0xC20033
+#define B_FE_AG_REG_GC1_AGC_MIN__A                                   0xC20034
+#define B_FE_AG_REG_GC1_AGC_DAT__A                                   0xC20035
+#define B_FE_AG_REG_GC1_AGC_DAT__M                                   0x3FF
+#define B_FE_AG_REG_PM2_AGC_WRI__A                                   0xC20036
+#define B_FE_AG_REG_IND_WIN__A                                       0xC2003C
+#define B_FE_AG_REG_IND_THD_LOL__A                                   0xC2003D
+#define B_FE_AG_REG_IND_THD_HIL__A                                   0xC2003E
+#define B_FE_AG_REG_IND_DEL__A                                       0xC2003F
+#define B_FE_AG_REG_IND_PD1_WRI__A                                   0xC20040
+#define B_FE_AG_REG_PDA_AUR_CNT__A                                   0xC20041
+#define B_FE_AG_REG_PDA_RUR_CNT__A                                   0xC20042
+#define B_FE_AG_REG_PDA_AVE_DAT__A                                   0xC20043
+#define B_FE_AG_REG_PDC_RUR_CNT__A                                   0xC20044
+#define B_FE_AG_REG_PDC_SET_LVL__A                                   0xC20045
+#define B_FE_AG_REG_PDC_FLA_RGN__A                                   0xC20046
+#define B_FE_AG_REG_PDC_JMP_PSN__A                                   0xC20047
+#define B_FE_AG_REG_PDC_FLA_STP__A                                   0xC20048
+#define B_FE_AG_REG_PDC_SLO_STP__A                                   0xC20049
+#define B_FE_AG_REG_PDC_PD2_WRI__A                                   0xC2004A
+#define B_FE_AG_REG_PDC_MAP_DAT__A                                   0xC2004B
+#define B_FE_AG_REG_PDC_MAX__A                                       0xC2004C
+#define B_FE_AG_REG_TGA_AUR_CNT__A                                   0xC2004D
+#define B_FE_AG_REG_TGA_RUR_CNT__A                                   0xC2004E
+#define B_FE_AG_REG_TGA_AVE_DAT__A                                   0xC2004F
+#define B_FE_AG_REG_TGC_RUR_CNT__A                                   0xC20050
+#define B_FE_AG_REG_TGC_SET_LVL__A                                   0xC20051
+#define B_FE_AG_REG_TGC_SET_LVL__M                                   0x3F
+#define B_FE_AG_REG_TGC_FLA_RGN__A                                   0xC20052
+#define B_FE_AG_REG_TGC_JMP_PSN__A                                   0xC20053
+#define B_FE_AG_REG_TGC_FLA_STP__A                                   0xC20054
+#define B_FE_AG_REG_TGC_SLO_STP__A                                   0xC20055
+#define B_FE_AG_REG_TGC_MAP_DAT__A                                   0xC20056
+#define B_FE_AG_REG_FGM_WRI__A                                       0xC20061
+#define B_FE_AG_REG_BGC_FGC_WRI__A                                   0xC20068
+#define B_FE_AG_REG_BGC_CGC_WRI__A                                   0xC20069
+#define B_FE_FS_REG_COMM_EXEC__A                                     0xC30000
+#define B_FE_FS_REG_ADD_INC_LOP__A                                   0xC30010
+#define B_FE_FD_REG_COMM_EXEC__A                                     0xC40000
+#define B_FE_FD_REG_SCL__A                                           0xC40010
+#define B_FE_FD_REG_MAX_LEV__A                                       0xC40011
+#define B_FE_FD_REG_NR__A                                            0xC40012
+#define B_FE_FD_REG_MEAS_VAL__A                                      0xC40014
+#define B_FE_IF_REG_COMM_EXEC__A                                     0xC50000
+#define B_FE_IF_REG_INCR0__A                                         0xC50010
+#define B_FE_IF_REG_INCR0__W                                         16
+#define B_FE_IF_REG_INCR0__M                                         0xFFFF
+#define B_FE_IF_REG_INCR1__A                                         0xC50011
+#define B_FE_IF_REG_INCR1__M                                         0xFF
+#define B_FE_CF_REG_COMM_EXEC__A                                     0xC60000
+#define B_FE_CF_REG_SCL__A                                           0xC60010
+#define B_FE_CF_REG_MAX_LEV__A                                       0xC60011
+#define B_FE_CF_REG_NR__A                                            0xC60012
+#define B_FE_CF_REG_IMP_VAL__A                                       0xC60013
+#define B_FE_CF_REG_MEAS_VAL__A                                      0xC60014
+#define B_FE_CU_REG_COMM_EXEC__A                                     0xC70000
+#define B_FE_CU_REG_FRM_CNT_RST__A                                   0xC70011
+#define B_FE_CU_REG_FRM_CNT_STR__A                                   0xC70012
+#define B_FE_CU_REG_CTR_NFC_ICR__A                                   0xC70020
+#define B_FE_CU_REG_CTR_NFC_OCR__A                                   0xC70021
+#define B_FE_CU_REG_DIV_NFC_CLP__A                                   0xC70027
+#define B_FT_COMM_EXEC__A                                            0x1000000
+#define B_FT_REG_COMM_EXEC__A                                        0x1010000
+#define B_CP_COMM_EXEC__A                                            0x1400000
+#define B_CP_REG_COMM_EXEC__A                                        0x1410000
+#define B_CP_REG_INTERVAL__A                                         0x1410011
+#define B_CP_REG_BR_SPL_OFFSET__A                                    0x1410023
+#define B_CP_REG_BR_STR_DEL__A                                       0x1410024
+#define B_CP_REG_RT_ANG_INC0__A                                      0x1410030
+#define B_CP_REG_RT_ANG_INC1__A                                      0x1410031
+#define B_CP_REG_RT_DETECT_TRH__A                                    0x1410033
+#define B_CP_REG_AC_NEXP_OFFS__A                                     0x1410040
+#define B_CP_REG_AC_AVER_POW__A                                      0x1410041
+#define B_CP_REG_AC_MAX_POW__A                                       0x1410042
+#define B_CP_REG_AC_WEIGHT_MAN__A                                    0x1410043
+#define B_CP_REG_AC_WEIGHT_EXP__A                                    0x1410044
+#define B_CP_REG_AC_AMP_MODE__A                                      0x1410047
+#define B_CP_REG_AC_AMP_FIX__A                                       0x1410048
+#define B_CP_REG_AC_ANG_MODE__A                                      0x141004A
+#define B_CE_COMM_EXEC__A                                            0x1800000
+#define B_CE_REG_COMM_EXEC__A                                        0x1810000
+#define B_CE_REG_TAPSET__A                                           0x1810011
+#define B_CE_REG_AVG_POW__A                                          0x1810012
+#define B_CE_REG_MAX_POW__A                                          0x1810013
+#define B_CE_REG_ATT__A                                              0x1810014
+#define B_CE_REG_NRED__A                                             0x1810015
+#define B_CE_REG_NE_ERR_SELECT__A                                    0x1810043
+#define B_CE_REG_NE_TD_CAL__A                                        0x1810044
+#define B_CE_REG_NE_MIXAVG__A                                        0x1810046
+#define B_CE_REG_NE_NUPD_OFS__A                                      0x1810047
+#define B_CE_REG_PE_NEXP_OFFS__A                                     0x1810050
+#define B_CE_REG_PE_TIMESHIFT__A                                     0x1810051
+#define B_CE_REG_TP_A0_TAP_NEW__A                                    0x1810064
+#define B_CE_REG_TP_A0_TAP_NEW_VALID__A                              0x1810065
+#define B_CE_REG_TP_A0_MU_LMS_STEP__A                                0x1810066
+#define B_CE_REG_TP_A1_TAP_NEW__A                                    0x1810068
+#define B_CE_REG_TP_A1_TAP_NEW_VALID__A                              0x1810069
+#define B_CE_REG_TP_A1_MU_LMS_STEP__A                                0x181006A
+#define B_CE_REG_TI_PHN_ENABLE__A                                    0x1810073
+#define B_CE_REG_FI_SHT_INCR__A                                      0x1810090
+#define B_CE_REG_FI_EXP_NORM__A                                      0x1810091
+#define B_CE_REG_IR_INPUTSEL__A                                      0x18100A0
+#define B_CE_REG_IR_STARTPOS__A                                      0x18100A1
+#define B_CE_REG_IR_NEXP_THRES__A                                    0x18100A2
+#define B_CE_REG_FR_TREAL00__A                                       0x1820010
+#define B_CE_REG_FR_TIMAG00__A                                       0x1820011
+#define B_CE_REG_FR_TREAL01__A                                       0x1820012
+#define B_CE_REG_FR_TIMAG01__A                                       0x1820013
+#define B_CE_REG_FR_TREAL02__A                                       0x1820014
+#define B_CE_REG_FR_TIMAG02__A                                       0x1820015
+#define B_CE_REG_FR_TREAL03__A                                       0x1820016
+#define B_CE_REG_FR_TIMAG03__A                                       0x1820017
+#define B_CE_REG_FR_TREAL04__A                                       0x1820018
+#define B_CE_REG_FR_TIMAG04__A                                       0x1820019
+#define B_CE_REG_FR_TREAL05__A                                       0x182001A
+#define B_CE_REG_FR_TIMAG05__A                                       0x182001B
+#define B_CE_REG_FR_TREAL06__A                                       0x182001C
+#define B_CE_REG_FR_TIMAG06__A                                       0x182001D
+#define B_CE_REG_FR_TREAL07__A                                       0x182001E
+#define B_CE_REG_FR_TIMAG07__A                                       0x182001F
+#define B_CE_REG_FR_TREAL08__A                                       0x1820020
+#define B_CE_REG_FR_TIMAG08__A                                       0x1820021
+#define B_CE_REG_FR_TREAL09__A                                       0x1820022
+#define B_CE_REG_FR_TIMAG09__A                                       0x1820023
+#define B_CE_REG_FR_TREAL10__A                                       0x1820024
+#define B_CE_REG_FR_TIMAG10__A                                       0x1820025
+#define B_CE_REG_FR_TREAL11__A                                       0x1820026
+#define B_CE_REG_FR_TIMAG11__A                                       0x1820027
+#define B_CE_REG_FR_MID_TAP__A                                       0x1820028
+#define B_CE_REG_FR_SQS_G00__A                                       0x1820029
+#define B_CE_REG_FR_SQS_G01__A                                       0x182002A
+#define B_CE_REG_FR_SQS_G02__A                                       0x182002B
+#define B_CE_REG_FR_SQS_G03__A                                       0x182002C
+#define B_CE_REG_FR_SQS_G04__A                                       0x182002D
+#define B_CE_REG_FR_SQS_G05__A                                       0x182002E
+#define B_CE_REG_FR_SQS_G06__A                                       0x182002F
+#define B_CE_REG_FR_SQS_G07__A                                       0x1820030
+#define B_CE_REG_FR_SQS_G08__A                                       0x1820031
+#define B_CE_REG_FR_SQS_G09__A                                       0x1820032
+#define B_CE_REG_FR_SQS_G10__A                                       0x1820033
+#define B_CE_REG_FR_SQS_G11__A                                       0x1820034
+#define B_CE_REG_FR_SQS_G12__A                                       0x1820035
+#define B_CE_REG_FR_RIO_G00__A                                       0x1820036
+#define B_CE_REG_FR_RIO_G01__A                                       0x1820037
+#define B_CE_REG_FR_RIO_G02__A                                       0x1820038
+#define B_CE_REG_FR_RIO_G03__A                                       0x1820039
+#define B_CE_REG_FR_RIO_G04__A                                       0x182003A
+#define B_CE_REG_FR_RIO_G05__A                                       0x182003B
+#define B_CE_REG_FR_RIO_G06__A                                       0x182003C
+#define B_CE_REG_FR_RIO_G07__A                                       0x182003D
+#define B_CE_REG_FR_RIO_G08__A                                       0x182003E
+#define B_CE_REG_FR_RIO_G09__A                                       0x182003F
+#define B_CE_REG_FR_RIO_G10__A                                       0x1820040
+#define B_CE_REG_FR_MODE__A                                          0x1820041
+#define B_CE_REG_FR_SQS_TRH__A                                       0x1820042
+#define B_CE_REG_FR_RIO_GAIN__A                                      0x1820043
+#define B_CE_REG_FR_BYPASS__A                                        0x1820044
+#define B_CE_REG_FR_PM_SET__A                                        0x1820045
+#define B_CE_REG_FR_ERR_SH__A                                        0x1820046
+#define B_CE_REG_FR_MAN_SH__A                                        0x1820047
+#define B_CE_REG_FR_TAP_SH__A                                        0x1820048
+#define B_EQ_COMM_EXEC__A                                            0x1C00000
+#define B_EQ_REG_COMM_EXEC__A                                        0x1C10000
+#define B_EQ_REG_COMM_MB__A                                          0x1C10002
+#define B_EQ_REG_IS_GAIN_MAN__A                                      0x1C10015
+#define B_EQ_REG_IS_GAIN_EXP__A                                      0x1C10016
+#define B_EQ_REG_IS_CLIP_EXP__A                                      0x1C10017
+#define B_EQ_REG_SN_CEGAIN__A                                        0x1C1002A
+#define B_EQ_REG_SN_OFFSET__A                                        0x1C1002B
+#define B_EQ_REG_RC_SEL_CAR__A                                       0x1C10032
+#define   B_EQ_REG_RC_SEL_CAR_INIT                                   0x2
+#define     B_EQ_REG_RC_SEL_CAR_DIV_ON                               0x1
+#define     B_EQ_REG_RC_SEL_CAR_PASS_A_CC                            0x0
+#define     B_EQ_REG_RC_SEL_CAR_PASS_B_CE                            0x2
+#define     B_EQ_REG_RC_SEL_CAR_LOCAL_A_CC                           0x0
+#define     B_EQ_REG_RC_SEL_CAR_LOCAL_B_CE                           0x8
+#define     B_EQ_REG_RC_SEL_CAR_MEAS_A_CC                            0x0
+#define     B_EQ_REG_RC_SEL_CAR_MEAS_B_CE                            0x20
+#define   B_EQ_REG_RC_SEL_CAR_FFTMODE__M                             0x80
+#define B_EQ_REG_OT_CONST__A                                         0x1C10046
+#define B_EQ_REG_OT_ALPHA__A                                         0x1C10047
+#define B_EQ_REG_OT_QNT_THRES0__A                                    0x1C10048
+#define B_EQ_REG_OT_QNT_THRES1__A                                    0x1C10049
+#define B_EQ_REG_OT_CSI_STEP__A                                      0x1C1004A
+#define B_EQ_REG_OT_CSI_OFFSET__A                                    0x1C1004B
+#define B_EQ_REG_TD_REQ_SMB_CNT__A                                   0x1C10061
+#define B_EQ_REG_TD_TPS_PWR_OFS__A                                   0x1C10062
+#define B_EC_SB_REG_COMM_EXEC__A                                     0x2010000
+#define B_EC_SB_REG_TR_MODE__A                                       0x2010010
+#define   B_EC_SB_REG_TR_MODE_8K                                     0x0
+#define   B_EC_SB_REG_TR_MODE_2K                                     0x1
+#define B_EC_SB_REG_CONST__A                                         0x2010011
+#define   B_EC_SB_REG_CONST_QPSK                                     0x0
+#define   B_EC_SB_REG_CONST_16QAM                                    0x1
+#define   B_EC_SB_REG_CONST_64QAM                                    0x2
+#define B_EC_SB_REG_ALPHA__A                                         0x2010012
+#define B_EC_SB_REG_PRIOR__A                                         0x2010013
+#define   B_EC_SB_REG_PRIOR_HI                                       0x0
+#define   B_EC_SB_REG_PRIOR_LO                                       0x1
+#define B_EC_SB_REG_CSI_HI__A                                        0x2010014
+#define B_EC_SB_REG_CSI_LO__A                                        0x2010015
+#define B_EC_SB_REG_SMB_TGL__A                                       0x2010016
+#define B_EC_SB_REG_SNR_HI__A                                        0x2010017
+#define B_EC_SB_REG_SNR_MID__A                                       0x2010018
+#define B_EC_SB_REG_SNR_LO__A                                        0x2010019
+#define B_EC_SB_REG_SCALE_MSB__A                                     0x201001A
+#define B_EC_SB_REG_SCALE_BIT2__A                                    0x201001B
+#define B_EC_SB_REG_SCALE_LSB__A                                     0x201001C
+#define B_EC_SB_REG_CSI_OFS0__A                                      0x201001D
+#define B_EC_SB_REG_CSI_OFS1__A                                      0x201001E
+#define B_EC_SB_REG_CSI_OFS2__A                                      0x201001F
+#define B_EC_VD_REG_COMM_EXEC__A                                     0x2090000
+#define B_EC_VD_REG_FORCE__A                                         0x2090010
+#define B_EC_VD_REG_SET_CODERATE__A                                  0x2090011
+#define   B_EC_VD_REG_SET_CODERATE_C1_2                              0x0
+#define   B_EC_VD_REG_SET_CODERATE_C2_3                              0x1
+#define   B_EC_VD_REG_SET_CODERATE_C3_4                              0x2
+#define   B_EC_VD_REG_SET_CODERATE_C5_6                              0x3
+#define   B_EC_VD_REG_SET_CODERATE_C7_8                              0x4
+#define B_EC_VD_REG_REQ_SMB_CNT__A                                   0x2090012
+#define B_EC_VD_REG_RLK_ENA__A                                       0x2090014
+#define B_EC_OD_REG_COMM_EXEC__A                                     0x2110000
+#define B_EC_OD_REG_SYNC__A                                          0x2110664
+#define B_EC_OD_DEINT_RAM__A                                         0x2120000
+#define B_EC_RS_REG_COMM_EXEC__A                                     0x2130000
+#define B_EC_RS_REG_REQ_PCK_CNT__A                                   0x2130010
+#define B_EC_RS_REG_VAL__A                                           0x2130011
+#define   B_EC_RS_REG_VAL_PCK                                        0x1
+#define B_EC_RS_EC_RAM__A                                            0x2140000
+#define B_EC_OC_REG_COMM_EXEC__A                                     0x2150000
+#define     B_EC_OC_REG_COMM_EXEC_CTL_ACTIVE                         0x1
+#define     B_EC_OC_REG_COMM_EXEC_CTL_HOLD                           0x2
+#define B_EC_OC_REG_COMM_INT_STA__A                                  0x2150007
+#define B_EC_OC_REG_OC_MODE_LOP__A                                   0x2150010
+#define   B_EC_OC_REG_OC_MODE_LOP_PAR_ENA__M                         0x1
+#define     B_EC_OC_REG_OC_MODE_LOP_PAR_ENA_ENABLE                   0x0
+#define     B_EC_OC_REG_OC_MODE_LOP_PAR_ENA_DISABLE                  0x1
+#define   B_EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC__M                     0x4
+#define     B_EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC_STATIC               0x0
+#define   B_EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE__M                     0x80
+#define     B_EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE_SERIAL               0x80
+#define B_EC_OC_REG_OC_MODE_HIP__A                                   0x2150011
+#define     B_EC_OC_REG_OC_MODE_HIP_MPG_BUS_SRC_MONITOR              0x10
+#define   B_EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL__M                     0x200
+#define     B_EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_DISABLE              0x0
+#define     B_EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_ENABLE               0x200
+#define B_EC_OC_REG_OC_MPG_SIO__A                                    0x2150012
+#define B_EC_OC_REG_OC_MPG_SIO__M                                    0xFFF
+#define B_EC_OC_REG_DTO_INC_LOP__A                                   0x2150014
+#define B_EC_OC_REG_DTO_INC_HIP__A                                   0x2150015
+#define B_EC_OC_REG_SNC_ISC_LVL__A                                   0x2150016
+#define   B_EC_OC_REG_SNC_ISC_LVL_OSC__M                             0xF0
+#define B_EC_OC_REG_TMD_TOP_MODE__A                                  0x215001D
+#define B_EC_OC_REG_TMD_TOP_CNT__A                                   0x215001E
+#define B_EC_OC_REG_TMD_HIL_MAR__A                                   0x215001F
+#define B_EC_OC_REG_TMD_LOL_MAR__A                                   0x2150020
+#define B_EC_OC_REG_TMD_CUR_CNT__A                                   0x2150021
+#define B_EC_OC_REG_AVR_ASH_CNT__A                                   0x2150023
+#define B_EC_OC_REG_AVR_BSH_CNT__A                                   0x2150024
+#define B_EC_OC_REG_RCN_MODE__A                                      0x2150027
+#define B_EC_OC_REG_RCN_CRA_LOP__A                                   0x2150028
+#define B_EC_OC_REG_RCN_CRA_HIP__A                                   0x2150029
+#define B_EC_OC_REG_RCN_CST_LOP__A                                   0x215002A
+#define B_EC_OC_REG_RCN_CST_HIP__A                                   0x215002B
+#define B_EC_OC_REG_RCN_SET_LVL__A                                   0x215002C
+#define B_EC_OC_REG_RCN_GAI_LVL__A                                   0x215002D
+#define B_EC_OC_REG_RCN_CLP_LOP__A                                   0x2150032
+#define B_EC_OC_REG_RCN_CLP_HIP__A                                   0x2150033
+#define B_EC_OC_REG_RCN_MAP_LOP__A                                   0x2150034
+#define B_EC_OC_REG_RCN_MAP_HIP__A                                   0x2150035
+#define B_EC_OC_REG_OCR_MPG_UOS__A                                   0x2150036
+#define B_EC_OC_REG_OCR_MPG_UOS__M                                   0xFFF
+#define   B_EC_OC_REG_OCR_MPG_UOS_INIT                               0x0
+#define B_EC_OC_REG_OCR_MPG_USR_DAT__A                               0x2150038
+#define B_EC_OC_REG_IPR_INV_MPG__A                                   0x2150045
+#define B_EC_OC_REG_DTO_CLKMODE__A                                   0x2150047
+#define B_EC_OC_REG_DTO_PER__A                                       0x2150048
+#define B_EC_OC_REG_DTO_BUR__A                                       0x2150049
+#define B_EC_OC_REG_RCR_CLKMODE__A                                   0x215004A
+#define B_CC_REG_OSC_MODE__A                                         0x2410010
+#define   B_CC_REG_OSC_MODE_M20                                      0x1
+#define B_CC_REG_PLL_MODE__A                                         0x2410011
+#define     B_CC_REG_PLL_MODE_BYPASS_PLL                             0x1
+#define     B_CC_REG_PLL_MODE_PUMP_CUR_12                            0x14
+#define B_CC_REG_REF_DIVIDE__A                                       0x2410012
+#define B_CC_REG_PWD_MODE__A                                         0x2410015
+#define   B_CC_REG_PWD_MODE_DOWN_PLL                                 0x2
+#define B_CC_REG_UPDATE__A                                           0x2410017
+#define   B_CC_REG_UPDATE_KEY                                        0x3973
+#define B_CC_REG_JTAGID_L__A                                         0x2410019
+#define B_CC_REG_DIVERSITY__A                                        0x241001B
+#define B_LC_COMM_EXEC__A                                            0x2800000
+#define B_LC_RA_RAM_IFINCR_NOM_L__A                                  0x282000C
+#define B_LC_RA_RAM_FILTER_SYM_SET__A                                0x282001A
+#define B_LC_RA_RAM_FILTER_SYM_SET__PRE                              0x3E8
+#define B_LC_RA_RAM_FILTER_CRMM_A__A                                 0x2820060
+#define B_LC_RA_RAM_FILTER_CRMM_A__PRE                               0x4
+#define B_LC_RA_RAM_FILTER_CRMM_B__A                                 0x2820061
+#define B_LC_RA_RAM_FILTER_CRMM_B__PRE                               0x1
+#define B_LC_RA_RAM_FILTER_SRMM_A__A                                 0x2820068
+#define B_LC_RA_RAM_FILTER_SRMM_A__PRE                               0x4
+#define B_LC_RA_RAM_FILTER_SRMM_B__A                                 0x2820069
+#define B_LC_RA_RAM_FILTER_SRMM_B__PRE                               0x1
+
+#endif
index fa79b7c..c983f2f 100644 (file)
@@ -61,7 +61,7 @@ static u8 stv0288_earda_inittab[] = {
        0x3d, 0x30,
        0x40, 0x63,
        0x41, 0x04,
-       0x42, 0x60,
+       0x42, 0x20,
        0x43, 0x00,
        0x44, 0x00,
        0x45, 0x00,
index 6c2e929..9a517a4 100644 (file)
@@ -218,11 +218,13 @@ static int ix2505v_set_params(struct dvb_frontend *fe,
                fe->ops.i2c_gate_ctrl(fe, 1);
 
        len = sizeof(data);
-
        ret |= ix2505v_write(state, data, len);
 
        data[2] |= 0x4; /* set TM = 1 other bits same */
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+
        len = 1;
        ret |= ix2505v_write(state, &data[2], len); /* write byte 4 only */
 
@@ -233,12 +235,12 @@ static int ix2505v_set_params(struct dvb_frontend *fe,
 
        deb_info("Data 2=[%x%x]\n", data[2], data[3]);
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+
        len = 2;
        ret |= ix2505v_write(state, &data[2], len); /* write byte 4 & 5 */
 
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 0);
-
        if (state->config->min_delay_ms)
                msleep(state->config->min_delay_ms);
 
index e3fe17f..8e0cfad 100644 (file)
@@ -253,7 +253,7 @@ static u8 stv0288_inittab[] = {
        0x3d, 0x30,
        0x40, 0x63,
        0x41, 0x04,
-       0x42, 0x60,
+       0x42, 0x20,
        0x43, 0x00,
        0x44, 0x00,
        0x45, 0x00,
index 4e3db3a..42684be 100644 (file)
@@ -64,6 +64,7 @@ struct stv0299_state {
        fe_code_rate_t fec_inner;
        int errmode;
        u32 ucblocks;
+       u8 mcr_reg;
 };
 
 #define STATUS_BER 0
@@ -457,6 +458,9 @@ static int stv0299_init (struct dvb_frontend* fe)
 
        dprintk("stv0299: init chip\n");
 
+       stv0299_writeregI(state, 0x02, 0x30 | state->mcr_reg);
+       msleep(50);
+
        for (i = 0; ; i += 2)  {
                reg = state->config->inittab[i];
                val = state->config->inittab[i+1];
@@ -464,6 +468,8 @@ static int stv0299_init (struct dvb_frontend* fe)
                        break;
                if (reg == 0x0c && state->config->op0_off)
                        val &= ~0x10;
+               if (reg == 0x2)
+                       state->mcr_reg = val & 0xf;
                stv0299_writeregI(state, reg, val);
        }
 
@@ -618,7 +624,7 @@ static int stv0299_sleep(struct dvb_frontend* fe)
 {
        struct stv0299_state* state = fe->demodulator_priv;
 
-       stv0299_writeregI(state, 0x02, 0x80);
+       stv0299_writeregI(state, 0x02, 0xb0 | state->mcr_reg);
        state->initialised = 0;
 
        return 0;
@@ -680,7 +686,7 @@ struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
        state->errmode = STATUS_BER;
 
        /* check if the demod is there */
-       stv0299_writeregI(state, 0x02, 0x34); /* standby off */
+       stv0299_writeregI(state, 0x02, 0x30); /* standby off */
        msleep(200);
        id = stv0299_readreg(state, 0x00);
 
index 07f3fc0..96d86d6 100644 (file)
@@ -42,7 +42,7 @@ static int sharp_z0194a_set_symbol_rate(struct dvb_frontend *fe,
 
 static u8 sharp_z0194a_inittab[] = {
        0x01, 0x15,
-       0x02, 0x00,
+       0x02, 0x30,
        0x03, 0x00,
        0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
        0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
index 70e73af..1402062 100644 (file)
@@ -44,7 +44,7 @@
 
 static unsigned int verbose;
 module_param(verbose, int, 0644);
-MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 0 (no)");
 
 #define DRIVER_NAME    "Hopper"
 
index 40da225..05cbb9d 100644 (file)
@@ -52,7 +52,7 @@
 
 static unsigned int verbose;
 module_param(verbose, int, 0644);
-MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 0 (no)");
 
 static int devs;
 
index 10a432a..371558a 100644 (file)
@@ -48,7 +48,7 @@
 
 int __devinit mantis_pci_init(struct mantis_pci *mantis)
 {
-       u8 revision, latency;
+       u8 latency;
        struct mantis_hwconfig *config  = mantis->hwconfig;
        struct pci_dev *pdev            = mantis->pdev;
        int err, ret = 0;
@@ -95,9 +95,8 @@ int __devinit mantis_pci_init(struct mantis_pci *mantis)
        }
 
        pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
-       pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
        mantis->latency = latency;
-       mantis->revision = revision;
+       mantis->revision = pdev->revision;
 
        dprintk(MANTIS_ERROR, 0, "    Mantis Rev %d [%04x:%04x], ",
                mantis->revision,
index deec927..2ae0afa 100644 (file)
@@ -37,7 +37,7 @@
 
 u8 lgtdqcs001f_inittab[] = {
        0x01, 0x15,
-       0x02, 0x00,
+       0x02, 0x30,
        0x03, 0x00,
        0x04, 0x2a,
        0x05, 0x85,
index 0486919..b81df5f 100644 (file)
@@ -1090,6 +1090,7 @@ pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        i2c_adap->algo = &pt1_i2c_algo;
        i2c_adap->algo_data = NULL;
        i2c_adap->dev.parent = &pdev->dev;
+       strcpy(i2c_adap->name, DRIVER_NAME);
        i2c_set_adapdata(i2c_adap, pt1);
        ret = i2c_add_adapter(i2c_adap);
        if (ret < 0)
@@ -1156,10 +1157,10 @@ err_pt1_disable_ram:
        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_pt1_cleanup_adapters:
+       pt1_cleanup_adapters(pt1);
 err_kfree:
        pci_set_drvdata(pdev, NULL);
        kfree(pt1);
index 0b8da57..0c8164a 100644 (file)
@@ -297,9 +297,8 @@ static void smsusb_term_device(struct usb_interface *intf)
                if (dev->coredev)
                        smscore_unregister_device(dev->coredev);
 
-               kfree(dev);
-
                sms_info("device %p destroyed", dev);
+               kfree(dev);
        }
 
        usb_set_intfdata(intf, NULL);
index 44afab2..9d83ced 100644 (file)
@@ -95,6 +95,8 @@ config DVB_BUDGET_CI
        select DVB_STB0899 if !DVB_FE_CUSTOMISE
        select DVB_STB6100 if !DVB_FE_CUSTOMISE
        select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+       select DVB_STV0288 if !DVB_FE_CUSTOMISE
+       select DVB_STB6000 if !DVB_FE_CUSTOMISE
        select DVB_TDA10023 if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
        depends on RC_CORE
index 1d79ada..926f299 100644 (file)
@@ -52,6 +52,7 @@
 #include "bsru6.h"
 #include "tda1002x.h"
 #include "tda827x.h"
+#include "bsbe1-d01a.h"
 
 #define MODULE_NAME "budget_ci"
 
@@ -224,6 +225,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
        case 0x1017:
        case 0x1019:
        case 0x101a:
+       case 0x101b:
                /* for the Technotrend 1500 bundled remote */
                dev->map_name = RC_MAP_TT_1500;
                break;
@@ -1388,6 +1390,23 @@ static void frontend_init(struct budget_ci *budget_ci)
                }
                break;
 
+       case 0x101b: /* TT S-1500B (BSBE1-D01A - STV0288/STB6000/LNBP21) */
+               budget_ci->budget.dvb_frontend = dvb_attach(stv0288_attach, &stv0288_bsbe1_d01a_config, &budget_ci->budget.i2c_adap);
+               if (budget_ci->budget.dvb_frontend) {
+                       if (dvb_attach(stb6000_attach, budget_ci->budget.dvb_frontend, 0x63, &budget_ci->budget.i2c_adap)) {
+                               if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) {
+                                       printk(KERN_ERR "%s: No LNBP21 found!\n", __func__);
+                                       dvb_frontend_detach(budget_ci->budget.dvb_frontend);
+                                       budget_ci->budget.dvb_frontend = NULL;
+                               }
+                       } else {
+                               printk(KERN_ERR "%s: No STB6000 found!\n", __func__);
+                               dvb_frontend_detach(budget_ci->budget.dvb_frontend);
+                               budget_ci->budget.dvb_frontend = NULL;
+                       }
+               }
+               break;
+
        case 0x1019:            // TT S2-3200 PCI
                /*
                 * NOTE! on some STB0899 versions, the internal PLL takes a longer time
@@ -1518,6 +1537,7 @@ MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(tt3200, "TT-Budget S2-3200 PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(ttbs1500b, "TT-Budget S-1500B PCI", BUDGET_TT);
 
 static struct pci_device_id pci_tbl[] = {
        MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
@@ -1528,6 +1548,7 @@ static struct pci_device_id pci_tbl[] = {
        MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
        MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a),
        MAKE_EXTENSION_PCI(tt3200, 0x13c2, 0x1019),
+       MAKE_EXTENSION_PCI(ttbs1500b, 0x13c2, 0x101b),
        {
         .vendor = 0,
         }
index cbe2f0d..420bb42 100644 (file)
@@ -52,7 +52,7 @@
     my TTUSB, so let it undef'd unless you want to implement another
     frontend. never tested.
 
-  DEBUG:
+  debug:
     define it to > 3 for really hardcore debugging. you probably don't want
     this unless the device doesn't load at all. > 2 for bandwidth statistics.
 */
@@ -134,20 +134,19 @@ struct ttusb {
 /* ugly workaround ... don't know why it's necessary to read */
 /* all result codes. */
 
-#define DEBUG 0
 static int ttusb_cmd(struct ttusb *ttusb,
              const u8 * data, int len, int needresult)
 {
        int actual_len;
        int err;
-#if DEBUG >= 3
        int i;
 
-       printk(">");
-       for (i = 0; i < len; ++i)
-               printk(" %02x", data[i]);
-       printk("\n");
-#endif
+       if (debug >= 3) {
+               printk(KERN_DEBUG ">");
+               for (i = 0; i < len; ++i)
+                       printk(KERN_CONT " %02x", data[i]);
+               printk(KERN_CONT "\n");
+       }
 
        if (mutex_lock_interruptible(&ttusb->semusb) < 0)
                return -EAGAIN;
@@ -176,13 +175,15 @@ static int ttusb_cmd(struct ttusb *ttusb,
                mutex_unlock(&ttusb->semusb);
                return err;
        }
-#if DEBUG >= 3
-       actual_len = ttusb->last_result[3] + 4;
-       printk("<");
-       for (i = 0; i < actual_len; ++i)
-               printk(" %02x", ttusb->last_result[i]);
-       printk("\n");
-#endif
+
+       if (debug >= 3) {
+               actual_len = ttusb->last_result[3] + 4;
+               printk(KERN_DEBUG "<");
+               for (i = 0; i < actual_len; ++i)
+                       printk(KERN_CONT " %02x", ttusb->last_result[i]);
+               printk(KERN_CONT "\n");
+       }
+
        if (!needresult)
                mutex_unlock(&ttusb->semusb);
        return 0;
@@ -636,16 +637,13 @@ static void ttusb_process_frame(struct ttusb *ttusb, u8 * data, int len)
                                ++ttusb->mux_state;
                        else {
                                ttusb->mux_state = 0;
-#if DEBUG > 3
-                               if (ttusb->insync)
-                                       printk("%02x ", data[-1]);
-#else
                                if (ttusb->insync) {
-                                       printk("%s: lost sync.\n",
+                                       dprintk("%s: %02x\n",
+                                               __func__, data[-1]);
+                                       printk(KERN_INFO "%s: lost sync.\n",
                                               __func__);
                                        ttusb->insync = 0;
                                }
-#endif
                        }
                        break;
                case 3:
@@ -744,6 +742,9 @@ static void ttusb_process_frame(struct ttusb *ttusb, u8 * data, int len)
 static void ttusb_iso_irq(struct urb *urb)
 {
        struct ttusb *ttusb = urb->context;
+       struct usb_iso_packet_descriptor *d;
+       u8 *data;
+       int len, i;
 
        if (!ttusb->iso_streaming)
                return;
@@ -755,21 +756,14 @@ static void ttusb_iso_irq(struct urb *urb)
 #endif
 
        if (!urb->status) {
-               int i;
                for (i = 0; i < urb->number_of_packets; ++i) {
-                       struct usb_iso_packet_descriptor *d;
-                       u8 *data;
-                       int len;
                        numpkt++;
                        if (time_after_eq(jiffies, lastj + HZ)) {
-#if DEBUG > 2
-                               printk
-                                   ("frames/s: %d (ts: %d, stuff %d, sec: %d, invalid: %d, all: %d)\n",
-                                    numpkt * HZ / (jiffies - lastj),
-                                    numts, numstuff, numsec, numinvalid,
-                                    numts + numstuff + numsec +
-                                    numinvalid);
-#endif
+                               dprintk("frames/s: %lu (ts: %d, stuff %d, "
+                                       "sec: %d, invalid: %d, all: %d)\n",
+                                       numpkt * HZ / (jiffies - lastj),
+                                       numts, numstuff, numsec, numinvalid,
+                                       numts + numstuff + numsec + numinvalid);
                                numts = numstuff = numsec = numinvalid = 0;
                                lastj = jiffies;
                                numpkt = 0;
index 38ae6cd..0e740c9 100644 (file)
@@ -174,15 +174,27 @@ static int si470x_set_chan(struct si470x_device *radio, unsigned short chan)
        if (retval < 0)
                goto done;
 
-       /* wait till tune operation has completed */
-       timeout = jiffies + msecs_to_jiffies(tune_timeout);
-       do {
-               retval = si470x_get_register(radio, STATUSRSSI);
-               if (retval < 0)
-                       goto stop;
-               timed_out = time_after(jiffies, timeout);
-       } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
-               (!timed_out));
+       /* currently I2C driver only uses interrupt way to tune */
+       if (radio->stci_enabled) {
+               INIT_COMPLETION(radio->completion);
+
+               /* wait till tune operation has completed */
+               retval = wait_for_completion_timeout(&radio->completion,
+                               msecs_to_jiffies(tune_timeout));
+               if (!retval)
+                       timed_out = true;
+       } else {
+               /* wait till tune operation has completed */
+               timeout = jiffies + msecs_to_jiffies(tune_timeout);
+               do {
+                       retval = si470x_get_register(radio, STATUSRSSI);
+                       if (retval < 0)
+                               goto stop;
+                       timed_out = time_after(jiffies, timeout);
+               } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
+                               && (!timed_out));
+       }
+
        if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
                dev_warn(&radio->videodev->dev, "tune does not complete\n");
        if (timed_out)
@@ -310,15 +322,27 @@ static int si470x_set_seek(struct si470x_device *radio,
        if (retval < 0)
                goto done;
 
-       /* wait till seek operation has completed */
-       timeout = jiffies + msecs_to_jiffies(seek_timeout);
-       do {
-               retval = si470x_get_register(radio, STATUSRSSI);
-               if (retval < 0)
-                       goto stop;
-               timed_out = time_after(jiffies, timeout);
-       } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
-               (!timed_out));
+       /* currently I2C driver only uses interrupt way to seek */
+       if (radio->stci_enabled) {
+               INIT_COMPLETION(radio->completion);
+
+               /* wait till seek operation has completed */
+               retval = wait_for_completion_timeout(&radio->completion,
+                               msecs_to_jiffies(seek_timeout));
+               if (!retval)
+                       timed_out = true;
+       } else {
+               /* wait till seek operation has completed */
+               timeout = jiffies + msecs_to_jiffies(seek_timeout);
+               do {
+                       retval = si470x_get_register(radio, STATUSRSSI);
+                       if (retval < 0)
+                               goto stop;
+                       timed_out = time_after(jiffies, timeout);
+               } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
+                               && (!timed_out));
+       }
+
        if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
                dev_warn(&radio->videodev->dev, "seek does not complete\n");
        if (radio->registers[STATUSRSSI] & STATUSRSSI_SF)
index 4ce541a..a2a6777 100644 (file)
@@ -197,8 +197,9 @@ int si470x_fops_open(struct file *file)
                if (retval < 0)
                        goto done;
 
-               /* enable RDS interrupt */
+               /* enable RDS / STC interrupt */
                radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDSIEN;
+               radio->registers[SYSCONFIG1] |= SYSCONFIG1_STCIEN;
                radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_GPIO2;
                radio->registers[SYSCONFIG1] |= 0x1 << 2;
                retval = si470x_set_register(radio, SYSCONFIG1);
@@ -261,12 +262,11 @@ int si470x_vidioc_querycap(struct file *file, void *priv,
  **************************************************************************/
 
 /*
- * si470x_i2c_interrupt_work - rds processing function
+ * si470x_i2c_interrupt - interrupt handler
  */
-static void si470x_i2c_interrupt_work(struct work_struct *work)
+static irqreturn_t si470x_i2c_interrupt(int irq, void *dev_id)
 {
-       struct si470x_device *radio = container_of(work,
-                       struct si470x_device, radio_work);
+       struct si470x_device *radio = dev_id;
        unsigned char regnr;
        unsigned char blocknum;
        unsigned short bler; /* rds block errors */
@@ -274,21 +274,29 @@ static void si470x_i2c_interrupt_work(struct work_struct *work)
        unsigned char tmpbuf[3];
        int retval = 0;
 
+       /* check Seek/Tune Complete */
+       retval = si470x_get_register(radio, STATUSRSSI);
+       if (retval < 0)
+               goto end;
+
+       if (radio->registers[STATUSRSSI] & STATUSRSSI_STC)
+               complete(&radio->completion);
+
        /* safety checks */
        if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
-               return;
+               goto end;
 
        /* Update RDS registers */
-       for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) {
+       for (regnr = 1; regnr < RDS_REGISTER_NUM; regnr++) {
                retval = si470x_get_register(radio, STATUSRSSI + regnr);
                if (retval < 0)
-                       return;
+                       goto end;
        }
 
        /* get rds blocks */
        if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0)
                /* No RDS group ready, better luck next time */
-               return;
+               goto end;
 
        for (blocknum = 0; blocknum < 4; blocknum++) {
                switch (blocknum) {
@@ -342,19 +350,8 @@ static void si470x_i2c_interrupt_work(struct work_struct *work)
 
        if (radio->wr_index != radio->rd_index)
                wake_up_interruptible(&radio->read_queue);
-}
-
-
-/*
- * si470x_i2c_interrupt - interrupt handler
- */
-static irqreturn_t si470x_i2c_interrupt(int irq, void *dev_id)
-{
-       struct si470x_device *radio = dev_id;
-
-       if (!work_pending(&radio->radio_work))
-               schedule_work(&radio->radio_work);
 
+end:
        return IRQ_HANDLED;
 }
 
@@ -376,7 +373,6 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client,
                goto err_initial;
        }
 
-       INIT_WORK(&radio->radio_work, si470x_i2c_interrupt_work);
        radio->users = 0;
        radio->client = client;
        mutex_init(&radio->lock);
@@ -441,7 +437,11 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client,
        radio->rd_index = 0;
        init_waitqueue_head(&radio->read_queue);
 
-       retval = request_irq(client->irq, si470x_i2c_interrupt,
+       /* mark Seek/Tune Complete Interrupt enabled */
+       radio->stci_enabled = true;
+       init_completion(&radio->completion);
+
+       retval = request_threaded_irq(client->irq, NULL, si470x_i2c_interrupt,
                        IRQF_TRIGGER_FALLING, DRIVER_NAME, radio);
        if (retval) {
                dev_err(&client->dev, "Failed to register interrupt\n");
@@ -479,7 +479,6 @@ static __devexit int si470x_i2c_remove(struct i2c_client *client)
        struct si470x_device *radio = i2c_get_clientdata(client);
 
        free_irq(client->irq, radio);
-       cancel_work_sync(&radio->radio_work);
        video_unregister_device(radio->videodev);
        kfree(radio);
 
@@ -491,8 +490,9 @@ static __devexit int si470x_i2c_remove(struct i2c_client *client)
 /*
  * si470x_i2c_suspend - suspend the device
  */
-static int si470x_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
+static int si470x_i2c_suspend(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct si470x_device *radio = i2c_get_clientdata(client);
 
        /* power down */
@@ -507,8 +507,9 @@ static int si470x_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
 /*
  * si470x_i2c_resume - resume the device
  */
-static int si470x_i2c_resume(struct i2c_client *client)
+static int si470x_i2c_resume(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct si470x_device *radio = i2c_get_clientdata(client);
 
        /* power up : need 110ms */
@@ -519,9 +520,8 @@ static int si470x_i2c_resume(struct i2c_client *client)
 
        return 0;
 }
-#else
-#define si470x_i2c_suspend     NULL
-#define si470x_i2c_resume      NULL
+
+static SIMPLE_DEV_PM_OPS(si470x_i2c_pm, si470x_i2c_suspend, si470x_i2c_resume);
 #endif
 
 
@@ -532,11 +532,12 @@ static struct i2c_driver si470x_i2c_driver = {
        .driver = {
                .name           = "si470x",
                .owner          = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm             = &si470x_i2c_pm,
+#endif
        },
        .probe                  = si470x_i2c_probe,
        .remove                 = __devexit_p(si470x_i2c_remove),
-       .suspend                = si470x_i2c_suspend,
-       .resume                 = si470x_i2c_resume,
        .id_table               = si470x_i2c_id,
 };
 
index 4a4e908..68da001 100644 (file)
@@ -158,6 +158,9 @@ struct si470x_device {
        unsigned int rd_index;
        unsigned int wr_index;
 
+       struct completion completion;
+       bool stci_enabled;              /* Seek/Tune Complete Interrupt */
+
 #if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE)
        /* reference to USB and video device */
        struct usb_device *usbdev;
@@ -179,7 +182,6 @@ struct si470x_device {
 
 #if defined(CONFIG_I2C_SI470X) || defined(CONFIG_I2C_SI470X_MODULE)
        struct i2c_client *client;
-       struct work_struct radio_work;
 #endif
 };
 
index 5db6fd1..1a45a5d 100644 (file)
@@ -55,8 +55,6 @@
 #define FM_DRV_TX_TIMEOUT      (5*HZ)  /* 5 seconds */
 #define FM_DRV_RX_SEEK_TIMEOUT (20*HZ) /* 20 seconds */
 
-#define NO_OF_ENTRIES_IN_ARRAY(array) (sizeof(array) / sizeof(array[0]))
-
 #define fmerr(format, ...) \
        printk(KERN_ERR "fmdrv: " format, ## __VA_ARGS__)
 #define fmwarn(format, ...) \
index 7f03142..154c337 100644 (file)
@@ -161,6 +161,17 @@ config IR_NUVOTON
           To compile this driver as a module, choose M here: the
           module will be called nuvoton-cir.
 
+config IR_REDRAT3
+       tristate "RedRat3 IR Transceiver"
+       depends on USB_ARCH_HAS_HCD
+       depends on RC_CORE
+       select USB
+       ---help---
+          Say Y here if you want to use a RedRat3 Infrared Transceiver.
+
+          To compile this driver as a module, choose M here: the
+          module will be called redrat3.
+
 config IR_STREAMZAP
        tristate "Streamzap PC Remote IR Receiver"
        depends on USB_ARCH_HAS_HCD
index c6cfe70..1f90a21 100644 (file)
@@ -18,6 +18,7 @@ obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o
 obj-$(CONFIG_IR_MCEUSB) += mceusb.o
 obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o
 obj-$(CONFIG_IR_ENE) += ene_ir.o
+obj-$(CONFIG_IR_REDRAT3) += redrat3.o
 obj-$(CONFIG_IR_STREAMZAP) += streamzap.o
 obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o
 obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o
index 8fc0f08..3f3c707 100644 (file)
@@ -443,16 +443,6 @@ static int display_close(struct inode *inode, struct file *file)
        } else {
                ictx->display_isopen = false;
                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);
@@ -1492,7 +1482,6 @@ static void imon_incoming_packet(struct imon_context *ictx,
        struct device *dev = ictx->dev;
        unsigned long flags;
        u32 kc;
-       bool norelease = false;
        int i;
        u64 scancode;
        int press_type = 0;
@@ -1560,7 +1549,6 @@ static void imon_incoming_packet(struct imon_context *ictx,
             !(buf[1] & 0x1 || buf[1] >> 2 & 0x1))) {
                len = 8;
                imon_pad_to_keys(ictx, buf);
-               norelease = true;
        }
 
        if (debug) {
@@ -1982,7 +1970,7 @@ static struct input_dev *imon_init_touch(struct imon_context *ictx)
        return touch;
 
 touch_register_failed:
-       input_free_device(ictx->touch);
+       input_free_device(touch);
 
 touch_alloc_failed:
        return NULL;
@@ -2274,14 +2262,12 @@ static int __devinit imon_probe(struct usb_interface *interface,
        struct usb_host_interface *iface_desc = NULL;
        struct usb_interface *first_if;
        struct device *dev = &interface->dev;
-       int ifnum, code_length, sysfs_err;
+       int ifnum, sysfs_err;
        int ret = 0;
        struct imon_context *ictx = NULL;
        struct imon_context *first_if_ctx = NULL;
        u16 vendor, product;
 
-       code_length = BUF_CHUNK_SIZE * 8;
-
        usbdev     = usb_get_dev(interface_to_usbdev(interface));
        iface_desc = interface->cur_altsetting;
        ifnum      = iface_desc->desc.bInterfaceNumber;
@@ -2366,8 +2352,6 @@ static void __devexit imon_disconnect(struct usb_interface *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
@@ -2391,24 +2375,20 @@ static void __devexit imon_disconnect(struct usb_interface *interface)
                if (ictx->display_supported) {
                        if (ictx->display_type == IMON_DISPLAY_TYPE_LCD)
                                usb_deregister_dev(interface, &imon_lcd_class);
-                       else
+                       else if (ictx->display_type == IMON_DISPLAY_TYPE_VFD)
                                usb_deregister_dev(interface, &imon_vfd_class);
                }
        } else {
                ictx->dev_present_intf1 = false;
                usb_kill_urb(ictx->rx_urb_intf1);
-               if (ictx->display_type == IMON_DISPLAY_TYPE_VGA)
+               if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) {
                        input_unregister_device(ictx->touch);
+                       del_timer_sync(&ictx->ttimer);
+               }
        }
 
-       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
-               mutex_unlock(&ictx->lock);
+       if (!ictx->dev_present_intf0 && !ictx->dev_present_intf1)
+               free_imon_context(ictx);
 
        mutex_unlock(&driver_lock);
 
index 43908a7..e716b93 100644 (file)
@@ -1250,11 +1250,9 @@ static void it8709_disable(struct ite_dev *dev)
        ite_dbg("%s called", __func__);
 
        /* clear out all interrupt enable flags */
-       it8709_wr(dev,
-                           it8709_rr(dev,
-                                     IT85_C0IER) & ~(IT85_IEC | IT85_RFOIE |
-                                                     IT85_RDAIE |
-                                                     IT85_TLDLIE), IT85_C0IER);
+       it8709_wr(dev, it8709_rr(dev, IT85_C0IER) &
+                       ~(IT85_IEC | IT85_RFOIE | IT85_RDAIE | IT85_TLDLIE),
+                 IT85_C0IER);
 
        /* disable the receiver */
        it8709_disable_rx(dev);
@@ -1270,11 +1268,9 @@ static void it8709_init_hardware(struct ite_dev *dev)
        ite_dbg("%s called", __func__);
 
        /* disable all the interrupts */
-       it8709_wr(dev,
-                           it8709_rr(dev,
-                                     IT85_C0IER) & ~(IT85_IEC | IT85_RFOIE |
-                                                     IT85_RDAIE |
-                                                     IT85_TLDLIE), IT85_C0IER);
+       it8709_wr(dev, it8709_rr(dev, IT85_C0IER) &
+                       ~(IT85_IEC | IT85_RFOIE | IT85_RDAIE | IT85_TLDLIE),
+                 IT85_C0IER);
 
        /* program the baud rate divisor */
        it8709_wr(dev, ITE_BAUDRATE_DIVISOR & 0xff, IT85_C0BDLR);
@@ -1282,28 +1278,22 @@ static void it8709_init_hardware(struct ite_dev *dev)
                        IT85_C0BDHR);
 
        /* program the C0MSTCR register defaults */
-       it8709_wr(dev, (it8709_rr(dev, IT85_C0MSTCR) & ~(IT85_ILSEL |
-                                                                  IT85_ILE
-                                                                  | IT85_FIFOTL
-                                                                  |
-                                                                  IT85_FIFOCLR
-                                                                  |
-                                                                  IT85_RESET))
-                           | IT85_FIFOTL_DEFAULT, IT85_C0MSTCR);
+       it8709_wr(dev, (it8709_rr(dev, IT85_C0MSTCR) &
+                       ~(IT85_ILSEL | IT85_ILE | IT85_FIFOTL
+                         | IT85_FIFOCLR | IT85_RESET)) | IT85_FIFOTL_DEFAULT,
+                 IT85_C0MSTCR);
 
        /* program the C0RCR register defaults */
-       it8709_wr(dev,
-                           (it8709_rr(dev, IT85_C0RCR) &
-                            ~(IT85_RXEN | IT85_RDWOS | IT85_RXEND
-                              | IT85_RXACT | IT85_RXDCR)) |
-                           ITE_RXDCR_DEFAULT, IT85_C0RCR);
+       it8709_wr(dev, (it8709_rr(dev, IT85_C0RCR) &
+                       ~(IT85_RXEN | IT85_RDWOS | IT85_RXEND | IT85_RXACT
+                         | IT85_RXDCR)) | ITE_RXDCR_DEFAULT,
+                 IT85_C0RCR);
 
        /* program the C0TCR register defaults */
-       it8709_wr(dev, (it8709_rr(dev, IT85_C0TCR)
-                                 &~(IT85_TXMPM | IT85_TXMPW))
-                           |IT85_TXRLE | IT85_TXENDF |
-                           IT85_TXMPM_DEFAULT |
-                           IT85_TXMPW_DEFAULT, IT85_C0TCR);
+       it8709_wr(dev, (it8709_rr(dev, IT85_C0TCR) & ~(IT85_TXMPM | IT85_TXMPW))
+                       | IT85_TXRLE | IT85_TXENDF | IT85_TXMPM_DEFAULT
+                       | IT85_TXMPW_DEFAULT,
+                 IT85_C0TCR);
 
        /* program the carrier parameters */
        ite_set_carrier_params(dev);
@@ -1660,6 +1650,9 @@ static int ite_suspend(struct pnp_dev *pdev, pm_message_t state)
 
        ite_dbg("%s called", __func__);
 
+       /* wait for any transmission to end */
+       wait_event_interruptible(dev->tx_ended, !dev->transmitting);
+
        spin_lock_irqsave(&dev->lock, flags);
 
        /* disable all interrupts */
@@ -1680,13 +1673,10 @@ static int ite_resume(struct pnp_dev *pdev)
 
        spin_lock_irqsave(&dev->lock, flags);
 
-       if (dev->transmitting) {
-               /* wake up the transmitter */
-               wake_up_interruptible(&dev->tx_queue);
-       } else {
-               /* enable the receiver */
-               dev->params.enable_rx(dev);
-       }
+       /* reinitialize hardware config registers */
+       dev->params.init_hardware(dev);
+       /* enable the receiver */
+       dev->params.enable_rx(dev);
 
        spin_unlock_irqrestore(&dev->lock, flags);
 
index 85cac7d..b57fc83 100644 (file)
@@ -77,6 +77,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-terratec-slim.o \
                        rc-terratec-slim-2.o \
                        rc-tevii-nec.o \
+                       rc-tivo.o \
                        rc-total-media-in-hand.o \
                        rc-trekstor.o \
                        rc-tt-1500.o \
index bdf97b7..22f54d4 100644 (file)
@@ -52,7 +52,7 @@ static struct rc_map_table avermedia_cardbus[] = {
        { 0x28, KEY_SELECT },           /* Select */
        { 0x29, KEY_BLUE },             /* Blue/Picture */
        { 0x2a, KEY_BACKSPACE },        /* Back */
-       { 0x2b, KEY_MEDIA },            /* PIP (Picture-in-picture) */
+       { 0x2b, KEY_VIDEO },            /* PIP (Picture-in-picture) */
        { 0x2c, KEY_DOWN },
        { 0x2e, KEY_DOT },
        { 0x2f, KEY_TV },               /* Live TV */
index 937a819..0ea2aa1 100644 (file)
@@ -111,7 +111,7 @@ static struct rc_map_table imon_mce[] = {
        { 0x800ff44d, KEY_TITLE },
 
        { 0x800ff40c, KEY_POWER },
-       { 0x800ff40d, KEY_LEFTMETA }, /* Windows MCE button */
+       { 0x800ff40d, KEY_MEDIA }, /* Windows MCE button */
 
 };
 
index 63d42bd..75d3843 100644 (file)
@@ -87,7 +87,7 @@ static struct rc_map_table imon_pad[] = {
 
        { 0x2b8515b7, KEY_VIDEO },
        { 0x299195b7, KEY_AUDIO },
-       { 0x2ba115b7, KEY_CAMERA },
+       { 0x2ba115b7, KEY_IMAGES },
        { 0x28a515b7, KEY_TV },
        { 0x29a395b7, KEY_DVD },
        { 0x29a295b7, KEY_DVD },
@@ -97,7 +97,7 @@ static struct rc_map_table imon_pad[] = {
        { 0x2ba395b7, KEY_MENU },
 
        { 0x288515b7, KEY_BOOKMARKS },
-       { 0x2ab715b7, KEY_MEDIA }, /* Thumbnail */
+       { 0x2ab715b7, KEY_CAMERA }, /* Thumbnail */
        { 0x298595b7, KEY_SUBTITLE },
        { 0x2b8595b7, KEY_LANGUAGE },
 
@@ -125,7 +125,7 @@ static struct rc_map_table imon_pad[] = {
        { 0x2b8195b7, KEY_CONTEXT_MENU }, /* Left Menu*/
        { 0x02000065, KEY_COMPOSE }, /* RightMenu */
        { 0x28b715b7, KEY_COMPOSE }, /* RightMenu */
-       { 0x2ab195b7, KEY_LEFTMETA }, /* Go or MultiMon */
+       { 0x2ab195b7, KEY_MEDIA }, /* Go or MultiMon */
        { 0x29b715b7, KEY_DASHBOARD }, /* AppLauncher */
 };
 
index 08d1831..7fa17a3 100644 (file)
@@ -17,7 +17,7 @@
  */
 
 static struct rc_map_table kworld_plus_tv_analog[] = {
-       { 0x0c, KEY_LEFTMETA },         /* Kworld key */
+       { 0x0c, KEY_MEDIA },            /* Kworld key */
        { 0x16, KEY_CLOSECD },          /* -> ) */
        { 0x1d, KEY_POWER2 },
 
index 8dd519e..01b69bc 100644 (file)
@@ -30,7 +30,7 @@ static struct rc_map_table rc6_mce[] = {
        { 0x800f040a, KEY_DELETE },
        { 0x800f040b, KEY_ENTER },
        { 0x800f040c, KEY_POWER },              /* PC Power */
-       { 0x800f040d, KEY_LEFTMETA },           /* Windows MCE button */
+       { 0x800f040d, KEY_MEDIA },              /* Windows MCE button */
        { 0x800f040e, KEY_MUTE },
        { 0x800f040f, KEY_INFO },
 
@@ -87,7 +87,7 @@ static struct rc_map_table rc6_mce[] = {
 
        { 0x800f0465, KEY_POWER2 },     /* TV Power */
        { 0x800f046e, KEY_PLAYPAUSE },
-       { 0x800f046f, KEY_MEDIA },      /* Start media application (NEW) */
+       { 0x800f046f, KEY_PLAYER },     /* Start media application (NEW) */
 
        { 0x800f0480, KEY_BRIGHTNESSDOWN },
        { 0x800f0481, KEY_PLAYPAUSE },
diff --git a/drivers/media/rc/keymaps/rc-tivo.c b/drivers/media/rc/keymaps/rc-tivo.c
new file mode 100644 (file)
index 0000000..98ad085
--- /dev/null
@@ -0,0 +1,98 @@
+/* rc-tivo.c - Keytable for TiVo remotes
+ *
+ * Copyright (c) 2011 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>
+
+/*
+ * Initial mapping is for the TiVo remote included in the Nero LiquidTV bundle,
+ * which also ships with a TiVo-branded IR transceiver, supported by the mceusb
+ * driver. Note that the remote uses an NEC-ish protocol, but instead of having
+ * a command/not_command pair, it has a vendor ID of 0xa10c, but some keys, the
+ * NEC extended checksums do pass, so the table presently has the intended
+ * values and the checksum-passed versions for those keys.
+ */
+static struct rc_map_table tivo[] = {
+       { 0xa10c900f, KEY_MEDIA },      /* TiVo Button */
+       { 0xa10c0807, KEY_POWER2 },     /* TV Power */
+       { 0xa10c8807, KEY_TV },         /* Live TV/Swap */
+       { 0xa10c2c03, KEY_VIDEO_NEXT }, /* TV Input */
+       { 0xa10cc807, KEY_INFO },
+       { 0xa10cfa05, KEY_CYCLEWINDOWS }, /* Window */
+       { 0x0085305f, KEY_CYCLEWINDOWS },
+       { 0xa10c6c03, KEY_EPG },        /* Guide */
+
+       { 0xa10c2807, KEY_UP },
+       { 0xa10c6807, KEY_DOWN },
+       { 0xa10ce807, KEY_LEFT },
+       { 0xa10ca807, KEY_RIGHT },
+
+       { 0xa10c1807, KEY_SCROLLDOWN }, /* Red Thumbs Down */
+       { 0xa10c9807, KEY_SELECT },
+       { 0xa10c5807, KEY_SCROLLUP },   /* Green Thumbs Up */
+
+       { 0xa10c3807, KEY_VOLUMEUP },
+       { 0xa10cb807, KEY_VOLUMEDOWN },
+       { 0xa10cd807, KEY_MUTE },
+       { 0xa10c040b, KEY_RECORD },
+       { 0xa10c7807, KEY_CHANNELUP },
+       { 0xa10cf807, KEY_CHANNELDOWN },
+       { 0x0085301f, KEY_CHANNELDOWN },
+
+       { 0xa10c840b, KEY_PLAY },
+       { 0xa10cc40b, KEY_PAUSE },
+       { 0xa10ca40b, KEY_SLOW },
+       { 0xa10c440b, KEY_REWIND },
+       { 0xa10c240b, KEY_FASTFORWARD },
+       { 0xa10c640b, KEY_PREVIOUS },
+       { 0xa10ce40b, KEY_NEXT },       /* ->| */
+
+       { 0xa10c220d, KEY_ZOOM },       /* Aspect */
+       { 0xa10c120d, KEY_STOP },
+       { 0xa10c520d, KEY_DVD },        /* DVD Menu */
+
+       { 0xa10c140b, KEY_NUMERIC_1 },
+       { 0xa10c940b, KEY_NUMERIC_2 },
+       { 0xa10c540b, KEY_NUMERIC_3 },
+       { 0xa10cd40b, KEY_NUMERIC_4 },
+       { 0xa10c340b, KEY_NUMERIC_5 },
+       { 0xa10cb40b, KEY_NUMERIC_6 },
+       { 0xa10c740b, KEY_NUMERIC_7 },
+       { 0xa10cf40b, KEY_NUMERIC_8 },
+       { 0x0085302f, KEY_NUMERIC_8 },
+       { 0xa10c0c03, KEY_NUMERIC_9 },
+       { 0xa10c8c03, KEY_NUMERIC_0 },
+       { 0xa10ccc03, KEY_ENTER },
+       { 0xa10c4c03, KEY_CLEAR },
+};
+
+static struct rc_map_list tivo_map = {
+       .map = {
+               .scan    = tivo,
+               .size    = ARRAY_SIZE(tivo),
+               .rc_type = RC_TYPE_NEC,
+               .name    = RC_MAP_TIVO,
+       }
+};
+
+static int __init init_rc_map_tivo(void)
+{
+       return rc_map_register(&tivo_map);
+}
+
+static void __exit exit_rc_map_tivo(void)
+{
+       rc_map_unregister(&tivo_map);
+}
+
+module_init(init_rc_map_tivo)
+module_exit(exit_rc_map_tivo)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
index 0062ca2..d8a34c1 100644 (file)
@@ -32,8 +32,8 @@ static struct rc_map_table winfast[] = {
        { 0x02, KEY_TUNER },            /* TV/FM, not on Y0400052 */
        { 0x1e, KEY_VIDEO },            /* Video Source */
        { 0x16, KEY_INFO },             /* Display information */
-       { 0x04, KEY_LEFT },
-       { 0x08, KEY_RIGHT },
+       { 0x04, KEY_RIGHT },
+       { 0x08, KEY_LEFT },
        { 0x0c, KEY_UP },
        { 0x10, KEY_DOWN },
        { 0x03, KEY_ZOOM },             /* fullscreen */
index 0c273ec..ad927fc 100644 (file)
@@ -149,6 +149,8 @@ enum mceusb_model_type {
        POLARIS_EVK,
        CX_HYBRID_TV,
        MULTIFUNCTION,
+       TIVO_KIT,
+       MCE_GEN2_NO_TX,
 };
 
 struct mceusb_model {
@@ -172,6 +174,10 @@ static const struct mceusb_model mceusb_model[] = {
        [MCE_GEN2] = {
                .mce_gen2 = 1,
        },
+       [MCE_GEN2_NO_TX] = {
+               .mce_gen2 = 1,
+               .no_tx = 1,
+       },
        [MCE_GEN2_TX_INV] = {
                .mce_gen2 = 1,
                .tx_mask_normal = 1,
@@ -197,6 +203,10 @@ static const struct mceusb_model mceusb_model[] = {
                .mce_gen2 = 1,
                .ir_intfnum = 2,
        },
+       [TIVO_KIT] = {
+               .mce_gen2 = 1,
+               .rc_map = RC_MAP_TIVO,
+       },
 };
 
 static struct usb_device_id mceusb_dev_table[] = {
@@ -279,7 +289,8 @@ static struct usb_device_id mceusb_dev_table[] = {
        /* Formosa21 / eHome Infrared Receiver */
        { USB_DEVICE(VENDOR_FORMOSA, 0xe016) },
        /* Formosa aim / Trust MCE Infrared Receiver */
-       { USB_DEVICE(VENDOR_FORMOSA, 0xe017) },
+       { USB_DEVICE(VENDOR_FORMOSA, 0xe017),
+         .driver_info = MCE_GEN2_NO_TX },
        /* Formosa Industrial Computing / Beanbag Emulation Device */
        { USB_DEVICE(VENDOR_FORMOSA, 0xe018) },
        /* Formosa21 / eHome Infrared Receiver */
@@ -308,7 +319,8 @@ static struct usb_device_id mceusb_dev_table[] = {
        /* Northstar Systems, Inc. eHome Infrared Transceiver */
        { USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) },
        /* TiVo PC IR Receiver */
-       { USB_DEVICE(VENDOR_TIVO, 0x2000) },
+       { USB_DEVICE(VENDOR_TIVO, 0x2000),
+         .driver_info = TIVO_KIT },
        /* Conexant Hybrid TV "Shelby" Polaris SDK */
        { USB_DEVICE(VENDOR_CONEXANT, 0x58a1),
          .driver_info = POLARIS_EVK },
@@ -603,11 +615,10 @@ static void mce_async_callback(struct urb *urb, struct pt_regs *regs)
 }
 
 /* request incoming or send outgoing usb packet - used to initialize remote */
-static void mce_request_packet(struct mceusb_dev *ir,
-                              struct usb_endpoint_descriptor *ep,
-                              unsigned char *data, int size, int urb_type)
+static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data,
+                              int size, int urb_type)
 {
-       int res;
+       int res, pipe;
        struct urb *async_urb;
        struct device *dev = ir->dev;
        unsigned char *async_buf;
@@ -627,10 +638,11 @@ static void mce_request_packet(struct mceusb_dev *ir,
                }
 
                /* outbound data */
-               usb_fill_int_urb(async_urb, ir->usbdev,
-                       usb_sndintpipe(ir->usbdev, ep->bEndpointAddress),
+               pipe = usb_sndintpipe(ir->usbdev,
+                                     ir->usb_ep_out->bEndpointAddress);
+               usb_fill_int_urb(async_urb, ir->usbdev, pipe,
                        async_buf, size, (usb_complete_t)mce_async_callback,
-                       ir, ep->bInterval);
+                       ir, ir->usb_ep_out->bInterval);
                memcpy(async_buf, data, size);
 
        } else if (urb_type == MCEUSB_RX) {
@@ -658,12 +670,12 @@ static void mce_request_packet(struct mceusb_dev *ir,
 
 static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size)
 {
-       mce_request_packet(ir, ir->usb_ep_out, data, size, MCEUSB_TX);
+       mce_request_packet(ir, data, size, MCEUSB_TX);
 }
 
 static void mce_sync_in(struct mceusb_dev *ir, unsigned char *data, int size)
 {
-       mce_request_packet(ir, ir->usb_ep_in, data, size, MCEUSB_RX);
+       mce_request_packet(ir, data, size, MCEUSB_RX);
 }
 
 /* Send data out the IR blaster port(s) */
index d4d6449..bf3060e 100644 (file)
@@ -37,8 +37,6 @@
 
 #include "nuvoton-cir.h"
 
-static char *chip_id = "w836x7hg";
-
 /* write val to config reg */
 static inline void nvt_cr_write(struct nvt_dev *nvt, u8 val, u8 reg)
 {
@@ -233,6 +231,8 @@ static int nvt_hw_detect(struct nvt_dev *nvt)
        unsigned long flags;
        u8 chip_major, chip_minor;
        int ret = 0;
+       char chip_id[12];
+       bool chip_unknown = false;
 
        nvt_efm_enable(nvt);
 
@@ -246,15 +246,39 @@ static int nvt_hw_detect(struct nvt_dev *nvt)
        }
 
        chip_minor = nvt_cr_read(nvt, CR_CHIP_ID_LO);
-       nvt_dbg("%s: chip id: 0x%02x 0x%02x", chip_id, chip_major, chip_minor);
 
-       if (chip_major != CHIP_ID_HIGH ||
-           (chip_minor != CHIP_ID_LOW && chip_minor != CHIP_ID_LOW2)) {
-               nvt_pr(KERN_ERR, "%s: unsupported chip, id: 0x%02x 0x%02x",
-                      chip_id, chip_major, chip_minor);
-               ret = -ENODEV;
+       /* these are the known working chip revisions... */
+       switch (chip_major) {
+       case CHIP_ID_HIGH_667:
+               strcpy(chip_id, "w83667hg\0");
+               if (chip_minor != CHIP_ID_LOW_667)
+                       chip_unknown = true;
+               break;
+       case CHIP_ID_HIGH_677B:
+               strcpy(chip_id, "w83677hg\0");
+               if (chip_minor != CHIP_ID_LOW_677B2 &&
+                   chip_minor != CHIP_ID_LOW_677B3)
+                       chip_unknown = true;
+               break;
+       case CHIP_ID_HIGH_677C:
+               strcpy(chip_id, "w83677hg-c\0");
+               if (chip_minor != CHIP_ID_LOW_677C)
+                       chip_unknown = true;
+               break;
+       default:
+               strcpy(chip_id, "w836x7hg\0");
+               chip_unknown = true;
+               break;
        }
 
+       /* warn, but still let the driver load, if we don't know this chip */
+       if (chip_unknown)
+               nvt_pr(KERN_WARNING, "%s: unknown chip, id: 0x%02x 0x%02x, "
+                      "it may not work...", chip_id, chip_major, chip_minor);
+       else
+               nvt_dbg("%s: chip id: 0x%02x 0x%02x",
+                       chip_id, chip_major, chip_minor);
+
        nvt_efm_disable(nvt);
 
        spin_lock_irqsave(&nvt->nvt_lock, flags);
@@ -267,13 +291,23 @@ static int nvt_hw_detect(struct nvt_dev *nvt)
 
 static void nvt_cir_ldev_init(struct nvt_dev *nvt)
 {
-       u8 val;
+       u8 val, psreg, psmask, psval;
+
+       if (nvt->chip_major == CHIP_ID_HIGH_667) {
+               psreg = CR_MULTIFUNC_PIN_SEL;
+               psmask = MULTIFUNC_PIN_SEL_MASK;
+               psval = MULTIFUNC_ENABLE_CIR | MULTIFUNC_ENABLE_CIRWB;
+       } else {
+               psreg = CR_OUTPUT_PIN_SEL;
+               psmask = OUTPUT_PIN_SEL_MASK;
+               psval = OUTPUT_ENABLE_CIR | OUTPUT_ENABLE_CIRWB;
+       }
 
-       /* output pin selection (Pin95=CIRRX, Pin96=CIRTX1, WB enabled */
-       val = nvt_cr_read(nvt, CR_OUTPUT_PIN_SEL);
-       val &= OUTPUT_PIN_SEL_MASK;
-       val |= (OUTPUT_ENABLE_CIR | OUTPUT_ENABLE_CIRWB);
-       nvt_cr_write(nvt, val, CR_OUTPUT_PIN_SEL);
+       /* output pin selection: enable CIR, with WB sensor enabled */
+       val = nvt_cr_read(nvt, psreg);
+       val &= psmask;
+       val |= psval;
+       nvt_cr_write(nvt, val, psreg);
 
        /* Select CIR logical device and enable */
        nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
@@ -640,7 +674,7 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
                                rawir.pulse ? "pulse" : "space",
                                rawir.duration);
 
-                       ir_raw_event_store(nvt->rdev, &rawir);
+                       ir_raw_event_store_with_filter(nvt->rdev, &rawir);
                }
 
                /*
@@ -1070,18 +1104,20 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
        rdev->tx_ir = nvt_tx_ir;
        rdev->s_tx_carrier = nvt_set_tx_carrier;
        rdev->input_name = "Nuvoton w836x7hg Infrared Remote Transceiver";
+       rdev->input_phys = "nuvoton/cir0";
        rdev->input_id.bustype = BUS_HOST;
        rdev->input_id.vendor = PCI_VENDOR_ID_WINBOND2;
        rdev->input_id.product = nvt->chip_major;
        rdev->input_id.version = nvt->chip_minor;
+       rdev->dev.parent = &pdev->dev;
        rdev->driver_name = NVT_DRIVER_NAME;
        rdev->map_name = RC_MAP_RC6_MCE;
+       rdev->timeout = US_TO_NS(1000);
+       /* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */
+       rdev->rx_resolution = US_TO_NS(CIR_SAMPLE_PERIOD);
 #if 0
        rdev->min_timeout = XYZ;
        rdev->max_timeout = XYZ;
-       rdev->timeout = XYZ;
-       /* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */
-       rdev->rx_resolution = XYZ;
        /* tx bits */
        rdev->tx_resolution = XYZ;
 #endif
@@ -1090,8 +1126,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
        if (ret)
                goto failure;
 
-       device_set_wakeup_capable(&pdev->dev, 1);
-       device_set_wakeup_enable(&pdev->dev, 1);
+       device_init_wakeup(&pdev->dev, true);
        nvt->rdev = rdev;
        nvt_pr(KERN_NOTICE, "driver has been successfully loaded\n");
        if (debug) {
index 048135e..379795d 100644 (file)
@@ -330,9 +330,13 @@ struct nvt_dev {
 #define EFER_EFM_DISABLE       0xaa
 
 /* Chip IDs found in CR_CHIP_ID_{HI,LO} */
-#define CHIP_ID_HIGH           0xb4
-#define CHIP_ID_LOW            0x72
-#define CHIP_ID_LOW2           0x73
+#define CHIP_ID_HIGH_667       0xa5
+#define CHIP_ID_HIGH_677B      0xb4
+#define CHIP_ID_HIGH_677C      0xc3
+#define CHIP_ID_LOW_667                0x13
+#define CHIP_ID_LOW_677B2      0x72
+#define CHIP_ID_LOW_677B3      0x73
+#define CHIP_ID_LOW_677C       0x33
 
 /* Config regs we need to care about */
 #define CR_SOFTWARE_RESET      0x02
@@ -341,6 +345,7 @@ struct nvt_dev {
 #define CR_CHIP_ID_LO          0x21
 #define CR_DEV_POWER_DOWN      0x22 /* bit 2 is CIR power, default power on */
 #define CR_OUTPUT_PIN_SEL      0x27
+#define CR_MULTIFUNC_PIN_SEL   0x2c
 #define CR_LOGICAL_DEV_EN      0x30 /* valid for all logical devices */
 /* next three regs valid for both the CIR and CIR_WAKE logical devices */
 #define CR_CIR_BASE_ADDR_HI    0x60
@@ -364,10 +369,16 @@ struct nvt_dev {
 #define CIR_INTR_MOUSE_IRQ_BIT 0x80
 #define PME_INTR_CIR_PASS_BIT  0x08
 
+/* w83677hg CIR pin config */
 #define OUTPUT_PIN_SEL_MASK    0xbc
 #define OUTPUT_ENABLE_CIR      0x01 /* Pin95=CIRRX, Pin96=CIRTX1 */
 #define OUTPUT_ENABLE_CIRWB    0x40 /* enable wide-band sensor */
 
+/* w83667hg CIR pin config */
+#define MULTIFUNC_PIN_SEL_MASK 0x1f
+#define MULTIFUNC_ENABLE_CIR   0x80 /* Pin75=CIRRX, Pin76=CIRTX1 */
+#define MULTIFUNC_ENABLE_CIRWB 0x20 /* enable wide-band sensor */
+
 /* MCE CIR signal length, related on sample period */
 
 /* MCE CIR controller signal length: about 43ms
index 49cee61..cc846b2 100644 (file)
@@ -146,6 +146,12 @@ static int loop_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
                if (rawir.duration)
                        ir_raw_event_store_with_filter(dev, &rawir);
        }
+
+       /* Fake a silence long enough to cause us to go idle */
+       rawir.pulse = false;
+       rawir.duration = dev->timeout;
+       ir_raw_event_store_with_filter(dev, &rawir);
+
        ir_raw_event_handle(dev);
 
 out:
index a270664..f57cd56 100644 (file)
@@ -749,6 +749,9 @@ static struct {
  * it is trigged by reading /sys/class/rc/rc?/protocols.
  * It returns the protocol names of supported protocols.
  * Enabled protocols are printed in brackets.
+ *
+ * dev->lock is taken to guard against races between device
+ * registration, store_protocols and show_protocols.
  */
 static ssize_t show_protocols(struct device *device,
                              struct device_attribute *mattr, char *buf)
@@ -762,6 +765,8 @@ static ssize_t show_protocols(struct device *device,
        if (!dev)
                return -EINVAL;
 
+       mutex_lock(&dev->lock);
+
        if (dev->driver_type == RC_DRIVER_SCANCODE) {
                enabled = dev->rc_map.rc_type;
                allowed = dev->allowed_protos;
@@ -784,6 +789,9 @@ static ssize_t show_protocols(struct device *device,
        if (tmp != buf)
                tmp--;
        *tmp = '\n';
+
+       mutex_unlock(&dev->lock);
+
        return tmp + 1 - buf;
 }
 
@@ -802,6 +810,9 @@ static ssize_t show_protocols(struct device *device,
  * Writing "none" will disable all protocols.
  * Returns -EINVAL if an invalid protocol combination or unknown protocol name
  * is used, otherwise @len.
+ *
+ * dev->lock is taken to guard against races between device
+ * registration, store_protocols and show_protocols.
  */
 static ssize_t store_protocols(struct device *device,
                               struct device_attribute *mattr,
@@ -815,18 +826,22 @@ static ssize_t store_protocols(struct device *device,
        u64 mask;
        int rc, i, count = 0;
        unsigned long flags;
+       ssize_t ret;
 
        /* Device is being removed */
        if (!dev)
                return -EINVAL;
 
+       mutex_lock(&dev->lock);
+
        if (dev->driver_type == RC_DRIVER_SCANCODE)
                type = dev->rc_map.rc_type;
        else if (dev->raw)
                type = dev->raw->enabled_protocols;
        else {
                IR_dprintk(1, "Protocol switching not supported\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
 
        while ((tmp = strsep((char **) &data, " \n")) != NULL) {
@@ -860,7 +875,8 @@ static ssize_t store_protocols(struct device *device,
                        }
                        if (i == ARRAY_SIZE(proto_names)) {
                                IR_dprintk(1, "Unknown protocol: '%s'\n", tmp);
-                               return -EINVAL;
+                               ret = -EINVAL;
+                               goto out;
                        }
                        count++;
                }
@@ -875,7 +891,8 @@ static ssize_t store_protocols(struct device *device,
 
        if (!count) {
                IR_dprintk(1, "Protocol not specified\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
 
        if (dev->change_protocol) {
@@ -883,7 +900,8 @@ static ssize_t store_protocols(struct device *device,
                if (rc < 0) {
                        IR_dprintk(1, "Error setting protocols to 0x%llx\n",
                                   (long long)type);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto out;
                }
        }
 
@@ -898,7 +916,11 @@ static ssize_t store_protocols(struct device *device,
        IR_dprintk(1, "Current protocol(s): 0x%llx\n",
                   (long long)type);
 
-       return len;
+       ret = len;
+
+out:
+       mutex_unlock(&dev->lock);
+       return ret;
 }
 
 static void rc_dev_release(struct device *device)
@@ -974,6 +996,7 @@ struct rc_dev *rc_allocate_device(void)
 
        spin_lock_init(&dev->rc_map.lock);
        spin_lock_init(&dev->keylock);
+       mutex_init(&dev->lock);
        setup_timer(&dev->timer_keyup, ir_timer_keyup, (unsigned long)dev);
 
        dev->dev.type = &rc_dev_type;
@@ -1019,12 +1042,21 @@ int rc_register_device(struct rc_dev *dev)
        if (dev->close)
                dev->input_dev->close = ir_close;
 
+       /*
+        * Take the lock here, as the device sysfs node will appear
+        * when device_add() is called, which may trigger an ir-keytable udev
+        * rule, which will in turn call show_protocols and access either
+        * dev->rc_map.rc_type or dev->raw->enabled_protocols before it has
+        * been initialized.
+        */
+       mutex_lock(&dev->lock);
+
        dev->devno = (unsigned long)(atomic_inc_return(&devno) - 1);
        dev_set_name(&dev->dev, "rc%ld", dev->devno);
        dev_set_drvdata(&dev->dev, dev);
        rc = device_add(&dev->dev);
        if (rc)
-               return rc;
+               goto out_unlock;
 
        rc = ir_setkeytable(dev, rc_map);
        if (rc)
@@ -1046,6 +1078,13 @@ int rc_register_device(struct rc_dev *dev)
         */
        dev->input_dev->rep[REP_DELAY] = 500;
 
+       /*
+        * As a repeat event on protocols like RC-5 and NEC take as long as
+        * 110/114ms, using 33ms as a repeat period is not the right thing
+        * to do.
+        */
+       dev->input_dev->rep[REP_PERIOD] = 125;
+
        path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
        printk(KERN_INFO "%s: %s as %s\n",
                dev_name(&dev->dev),
@@ -1058,6 +1097,7 @@ int rc_register_device(struct rc_dev *dev)
                if (rc < 0)
                        goto out_input;
        }
+       mutex_unlock(&dev->lock);
 
        if (dev->change_protocol) {
                rc = dev->change_protocol(dev, rc_map->rc_type);
@@ -1083,6 +1123,8 @@ out_table:
        ir_free_table(&dev->rc_map);
 out_dev:
        device_del(&dev->dev);
+out_unlock:
+       mutex_unlock(&dev->lock);
        return rc;
 }
 EXPORT_SYMBOL_GPL(rc_register_device);
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
new file mode 100644 (file)
index 0000000..5147767
--- /dev/null
@@ -0,0 +1,1344 @@
+/*
+ * USB RedRat3 IR Transceiver rc-core driver
+ *
+ * Copyright (c) 2011 by Jarod Wilson <jarod@redhat.com>
+ *  based heavily on the work of Stephen Cox, with additional
+ *  help from RedRat Ltd.
+ *
+ * This driver began life based an an old version of the first-generation
+ * lirc_mceusb driver from the lirc 0.7.2 distribution. It was then
+ * significantly rewritten by Stephen Cox with the aid of RedRat Ltd's
+ * Chris Dodge.
+ *
+ * The driver was then ported to rc-core and significantly rewritten again,
+ * by Jarod, using the in-kernel mceusb driver as a guide, after an initial
+ * port effort was started by Stephen.
+ *
+ * TODO LIST:
+ * - fix lirc not showing repeats properly
+ * --
+ *
+ * The RedRat3 is a USB transceiver with both send & receive,
+ * with 2 separate sensors available for receive to enable
+ * both good long range reception for general use, and good
+ * short range reception when required for learning a signal.
+ *
+ * http://www.redrat.co.uk/
+ *
+ * It uses its own little protocol to communicate, the required
+ * parts of which are embedded within this driver.
+ * --
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+#include <media/rc-core.h>
+
+/* Driver Information */
+#define DRIVER_VERSION "0.70"
+#define DRIVER_AUTHOR "Jarod Wilson <jarod@redhat.com>"
+#define DRIVER_AUTHOR2 "The Dweller, Stephen Cox"
+#define DRIVER_DESC "RedRat3 USB IR Transceiver Driver"
+#define DRIVER_NAME "redrat3"
+
+/* module parameters */
+#ifdef CONFIG_USB_DEBUG
+static int debug = 1;
+#else
+static int debug;
+#endif
+
+#define RR3_DEBUG_STANDARD             0x1
+#define RR3_DEBUG_FUNCTION_TRACE       0x2
+
+#define rr3_dbg(dev, fmt, ...)                                 \
+       do {                                                    \
+               if (debug & RR3_DEBUG_STANDARD)                 \
+                       dev_info(dev, fmt, ## __VA_ARGS__);     \
+       } while (0)
+
+#define rr3_ftr(dev, fmt, ...)                                 \
+       do {                                                    \
+               if (debug & RR3_DEBUG_FUNCTION_TRACE)           \
+                       dev_info(dev, fmt, ## __VA_ARGS__);     \
+       } while (0)
+
+/* bulk data transfer types */
+#define RR3_ERROR              0x01
+#define RR3_MOD_SIGNAL_IN      0x20
+#define RR3_MOD_SIGNAL_OUT     0x21
+
+/* Get the RR firmware version */
+#define RR3_FW_VERSION         0xb1
+#define RR3_FW_VERSION_LEN     64
+/* Send encoded signal bulk-sent earlier*/
+#define RR3_TX_SEND_SIGNAL     0xb3
+#define RR3_SET_IR_PARAM       0xb7
+#define RR3_GET_IR_PARAM       0xb8
+/* Blink the red LED on the device */
+#define RR3_BLINK_LED          0xb9
+/* Read serial number of device */
+#define RR3_READ_SER_NO                0xba
+#define RR3_SER_NO_LEN         4
+/* Start capture with the RC receiver */
+#define RR3_RC_DET_ENABLE      0xbb
+/* Stop capture with the RC receiver */
+#define RR3_RC_DET_DISABLE     0xbc
+/* Return the status of RC detector capture */
+#define RR3_RC_DET_STATUS      0xbd
+/* Reset redrat */
+#define RR3_RESET              0xa0
+
+/* Max number of lengths in the signal. */
+#define RR3_IR_IO_MAX_LENGTHS  0x01
+/* Periods to measure mod. freq. */
+#define RR3_IR_IO_PERIODS_MF   0x02
+/* Size of memory for main signal data */
+#define RR3_IR_IO_SIG_MEM_SIZE 0x03
+/* Delta value when measuring lengths */
+#define RR3_IR_IO_LENGTH_FUZZ  0x04
+/* Timeout for end of signal detection */
+#define RR3_IR_IO_SIG_TIMEOUT  0x05
+/* Minumum value for pause recognition. */
+#define RR3_IR_IO_MIN_PAUSE    0x06
+
+/* Clock freq. of EZ-USB chip */
+#define RR3_CLK                        24000000
+/* Clock periods per timer count */
+#define RR3_CLK_PER_COUNT      12
+/* (RR3_CLK / RR3_CLK_PER_COUNT) */
+#define RR3_CLK_CONV_FACTOR    2000000
+/* USB bulk-in IR data endpoint address */
+#define RR3_BULK_IN_EP_ADDR    0x82
+
+/* Raw Modulated signal data value offsets */
+#define RR3_PAUSE_OFFSET       0
+#define RR3_FREQ_COUNT_OFFSET  4
+#define RR3_NUM_PERIOD_OFFSET  6
+#define RR3_MAX_LENGTHS_OFFSET 8
+#define RR3_NUM_LENGTHS_OFFSET 9
+#define RR3_MAX_SIGS_OFFSET    10
+#define RR3_NUM_SIGS_OFFSET    12
+#define RR3_REPEATS_OFFSET     14
+
+/* Size of the fixed-length portion of the signal */
+#define RR3_HEADER_LENGTH      15
+#define RR3_DRIVER_MAXLENS     128
+#define RR3_MAX_SIG_SIZE       512
+#define RR3_MAX_BUF_SIZE       \
+       ((2 * RR3_HEADER_LENGTH) + RR3_DRIVER_MAXLENS + RR3_MAX_SIG_SIZE)
+#define RR3_TIME_UNIT          50
+#define RR3_END_OF_SIGNAL      0x7f
+#define RR3_TX_HEADER_OFFSET   4
+#define RR3_TX_TRAILER_LEN     2
+#define RR3_RX_MIN_TIMEOUT     5
+#define RR3_RX_MAX_TIMEOUT     2000
+
+/* The 8051's CPUCS Register address */
+#define RR3_CPUCS_REG_ADDR     0x7f92
+
+#define USB_RR3USB_VENDOR_ID   0x112a
+#define USB_RR3USB_PRODUCT_ID  0x0001
+#define USB_RR3IIUSB_PRODUCT_ID        0x0005
+
+/* table of devices that work with this driver */
+static struct usb_device_id redrat3_dev_table[] = {
+       /* Original version of the RedRat3 */
+       {USB_DEVICE(USB_RR3USB_VENDOR_ID, USB_RR3USB_PRODUCT_ID)},
+       /* Second Version/release of the RedRat3 - RetRat3-II */
+       {USB_DEVICE(USB_RR3USB_VENDOR_ID, USB_RR3IIUSB_PRODUCT_ID)},
+       {}                      /* Terminating entry */
+};
+
+/* Structure to hold all of our device specific stuff */
+struct redrat3_dev {
+       /* core device bits */
+       struct rc_dev *rc;
+       struct device *dev;
+
+       /* save off the usb device pointer */
+       struct usb_device *udev;
+
+       /* the receive endpoint */
+       struct usb_endpoint_descriptor *ep_in;
+       /* the buffer to receive data */
+       unsigned char *bulk_in_buf;
+       /* urb used to read ir data */
+       struct urb *read_urb;
+
+       /* the send endpoint */
+       struct usb_endpoint_descriptor *ep_out;
+       /* the buffer to send data */
+       unsigned char *bulk_out_buf;
+       /* the urb used to send data */
+       struct urb *write_urb;
+
+       /* usb dma */
+       dma_addr_t dma_in;
+       dma_addr_t dma_out;
+
+       /* true if write urb is busy */
+       bool write_busy;
+       /* wait for the write to finish */
+       struct completion write_finished;
+
+       /* locks this structure */
+       struct mutex lock;
+
+       /* rx signal timeout timer */
+       struct timer_list rx_timeout;
+
+       /* Is the device currently receiving? */
+       bool recv_in_progress;
+       /* is the detector enabled*/
+       bool det_enabled;
+       /* Is the device currently transmitting?*/
+       bool transmitting;
+
+       /* store for current packet */
+       char pbuf[RR3_MAX_BUF_SIZE];
+       u16 pktlen;
+       u16 pkttype;
+       u16 bytes_read;
+       /* indicate whether we are going to reprocess
+        * the USB callback with a bigger buffer */
+       int buftoosmall;
+       char *datap;
+
+       u32 carrier;
+
+       char name[128];
+       char phys[64];
+};
+
+/* All incoming data buffers adhere to a very specific data format */
+struct redrat3_signal_header {
+       u16 length;     /* Length of data being transferred */
+       u16 transfer_type; /* Type of data transferred */
+       u32 pause;      /* Pause between main and repeat signals */
+       u16 mod_freq_count; /* Value of timer on mod. freq. measurement */
+       u16 no_periods; /* No. of periods over which mod. freq. is measured */
+       u8 max_lengths; /* Max no. of lengths (i.e. size of array) */
+       u8 no_lengths;  /* Actual no. of elements in lengths array */
+       u16 max_sig_size; /* Max no. of values in signal data array */
+       u16 sig_size;   /* Acuto no. of values in signal data array */
+       u8 no_repeats;  /* No. of repeats of repeat signal section */
+       /* Here forward is the lengths and signal data */
+};
+
+static void redrat3_dump_signal_header(struct redrat3_signal_header *header)
+{
+       pr_info("%s:\n", __func__);
+       pr_info(" * length: %u, transfer_type: 0x%02x\n",
+               header->length, header->transfer_type);
+       pr_info(" * pause: %u, freq_count: %u, no_periods: %u\n",
+               header->pause, header->mod_freq_count, header->no_periods);
+       pr_info(" * lengths: %u (max: %u)\n",
+               header->no_lengths, header->max_lengths);
+       pr_info(" * sig_size: %u (max: %u)\n",
+               header->sig_size, header->max_sig_size);
+       pr_info(" * repeats: %u\n", header->no_repeats);
+}
+
+static void redrat3_dump_signal_data(char *buffer, u16 len)
+{
+       int offset, i;
+       char *data_vals;
+
+       pr_info("%s:", __func__);
+
+       offset = RR3_TX_HEADER_OFFSET + RR3_HEADER_LENGTH
+                + (RR3_DRIVER_MAXLENS * sizeof(u16));
+
+       /* read RR3_DRIVER_MAXLENS from ctrl msg */
+       data_vals = buffer + offset;
+
+       for (i = 0; i < len; i++) {
+               if (i % 10 == 0)
+                       pr_cont("\n * ");
+               pr_cont("%02x ", *data_vals++);
+       }
+
+       pr_cont("\n");
+}
+
+/*
+ * redrat3_issue_async
+ *
+ *  Issues an async read to the ir data in port..
+ *  sets the callback to be redrat3_handle_async
+ */
+static void redrat3_issue_async(struct redrat3_dev *rr3)
+{
+       int res;
+
+       rr3_ftr(rr3->dev, "Entering %s\n", __func__);
+
+       if (!rr3->det_enabled) {
+               dev_warn(rr3->dev, "not issuing async read, "
+                        "detector not enabled\n");
+               return;
+       }
+
+       memset(rr3->bulk_in_buf, 0, rr3->ep_in->wMaxPacketSize);
+       res = usb_submit_urb(rr3->read_urb, GFP_ATOMIC);
+       if (res)
+               rr3_dbg(rr3->dev, "%s: receive request FAILED! "
+                       "(res %d, len %d)\n", __func__, res,
+                       rr3->read_urb->transfer_buffer_length);
+}
+
+static void redrat3_dump_fw_error(struct redrat3_dev *rr3, int code)
+{
+       if (!rr3->transmitting && (code != 0x40))
+               dev_info(rr3->dev, "fw error code 0x%02x: ", code);
+
+       switch (code) {
+       case 0x00:
+               pr_cont("No Error\n");
+               break;
+
+       /* Codes 0x20 through 0x2f are IR Firmware Errors */
+       case 0x20:
+               pr_cont("Initial signal pulse not long enough "
+                       "to measure carrier frequency\n");
+               break;
+       case 0x21:
+               pr_cont("Not enough length values allocated for signal\n");
+               break;
+       case 0x22:
+               pr_cont("Not enough memory allocated for signal data\n");
+               break;
+       case 0x23:
+               pr_cont("Too many signal repeats\n");
+               break;
+       case 0x28:
+               pr_cont("Insufficient memory available for IR signal "
+                       "data memory allocation\n");
+               break;
+       case 0x29:
+               pr_cont("Insufficient memory available "
+                       "for IrDa signal data memory allocation\n");
+               break;
+
+       /* Codes 0x30 through 0x3f are USB Firmware Errors */
+       case 0x30:
+               pr_cont("Insufficient memory available for bulk "
+                       "transfer structure\n");
+               break;
+
+       /*
+        * Other error codes... These are primarily errors that can occur in
+        * the control messages sent to the redrat
+        */
+       case 0x40:
+               if (!rr3->transmitting)
+                       pr_cont("Signal capture has been terminated\n");
+               break;
+       case 0x41:
+               pr_cont("Attempt to set/get and unknown signal I/O "
+                       "algorithm parameter\n");
+               break;
+       case 0x42:
+               pr_cont("Signal capture already started\n");
+               break;
+
+       default:
+               pr_cont("Unknown Error\n");
+               break;
+       }
+}
+
+static u32 redrat3_val_to_mod_freq(struct redrat3_signal_header *ph)
+{
+       u32 mod_freq = 0;
+
+       if (ph->mod_freq_count != 0)
+               mod_freq = (RR3_CLK * ph->no_periods) /
+                               (ph->mod_freq_count * RR3_CLK_PER_COUNT);
+
+       return mod_freq;
+}
+
+/* this function scales down the figures for the same result... */
+static u32 redrat3_len_to_us(u32 length)
+{
+       u32 biglen = length * 1000;
+       u32 divisor = (RR3_CLK_CONV_FACTOR) / 1000;
+       u32 result = (u32) (biglen / divisor);
+
+       /* don't allow zero lengths to go back, breaks lirc */
+       return result ? result : 1;
+}
+
+/*
+ * convert us back into redrat3 lengths
+ *
+ * length * 1000   length * 1000000
+ * ------------- = ---------------- = micro
+ * rr3clk / 1000       rr3clk
+
+ * 6 * 2       4 * 3        micro * rr3clk          micro * rr3clk / 1000
+ * ----- = 4   ----- = 6    -------------- = len    ---------------------
+ *   3           2             1000000                    1000
+ */
+static u32 redrat3_us_to_len(u32 microsec)
+{
+       u32 result;
+       u32 divisor;
+
+       microsec &= IR_MAX_DURATION;
+       divisor = (RR3_CLK_CONV_FACTOR / 1000);
+       result = (u32)(microsec * divisor) / 1000;
+
+       /* don't allow zero lengths to go back, breaks lirc */
+       return result ? result : 1;
+
+}
+
+/* timer callback to send long trailing space on receive timeout */
+static void redrat3_rx_timeout(unsigned long data)
+{
+       struct redrat3_dev *rr3 = (struct redrat3_dev *)data;
+       DEFINE_IR_RAW_EVENT(rawir);
+
+       rawir.pulse = false;
+       rawir.duration = rr3->rc->timeout;
+       rr3_dbg(rr3->dev, "storing trailing space with duration %d\n",
+               rawir.duration);
+       ir_raw_event_store_with_filter(rr3->rc, &rawir);
+
+       rr3_dbg(rr3->dev, "calling ir_raw_event_handle\n");
+       ir_raw_event_handle(rr3->rc);
+
+       rr3_dbg(rr3->dev, "calling ir_raw_event_reset\n");
+       ir_raw_event_reset(rr3->rc);
+}
+
+static void redrat3_process_ir_data(struct redrat3_dev *rr3)
+{
+       DEFINE_IR_RAW_EVENT(rawir);
+       struct redrat3_signal_header header;
+       struct device *dev;
+       int i;
+       unsigned long delay;
+       u32 mod_freq, single_len;
+       u16 *len_vals;
+       u8 *data_vals;
+       u32 tmp32;
+       u16 tmp16;
+       char *sig_data;
+
+       if (!rr3) {
+               pr_err("%s called with no context!\n", __func__);
+               return;
+       }
+
+       rr3_ftr(rr3->dev, "Entered %s\n", __func__);
+
+       dev = rr3->dev;
+       sig_data = rr3->pbuf;
+
+       header.length = rr3->pktlen;
+       header.transfer_type = rr3->pkttype;
+
+       /* Sanity check */
+       if (!(header.length >= RR3_HEADER_LENGTH))
+               dev_warn(dev, "read returned less than rr3 header len\n");
+
+       delay = usecs_to_jiffies(rr3->rc->timeout / 1000);
+       mod_timer(&rr3->rx_timeout, jiffies + delay);
+
+       memcpy(&tmp32, sig_data + RR3_PAUSE_OFFSET, sizeof(tmp32));
+       header.pause = be32_to_cpu(tmp32);
+
+       memcpy(&tmp16, sig_data + RR3_FREQ_COUNT_OFFSET, sizeof(tmp16));
+       header.mod_freq_count = be16_to_cpu(tmp16);
+
+       memcpy(&tmp16, sig_data + RR3_NUM_PERIOD_OFFSET, sizeof(tmp16));
+       header.no_periods = be16_to_cpu(tmp16);
+
+       header.max_lengths = sig_data[RR3_MAX_LENGTHS_OFFSET];
+       header.no_lengths = sig_data[RR3_NUM_LENGTHS_OFFSET];
+
+       memcpy(&tmp16, sig_data + RR3_MAX_SIGS_OFFSET, sizeof(tmp16));
+       header.max_sig_size = be16_to_cpu(tmp16);
+
+       memcpy(&tmp16, sig_data + RR3_NUM_SIGS_OFFSET, sizeof(tmp16));
+       header.sig_size = be16_to_cpu(tmp16);
+
+       header.no_repeats= sig_data[RR3_REPEATS_OFFSET];
+
+       if (debug) {
+               redrat3_dump_signal_header(&header);
+               redrat3_dump_signal_data(sig_data, header.sig_size);
+       }
+
+       mod_freq = redrat3_val_to_mod_freq(&header);
+       rr3_dbg(dev, "Got mod_freq of %u\n", mod_freq);
+
+       /* Here we pull out the 'length' values from the signal */
+       len_vals = (u16 *)(sig_data + RR3_HEADER_LENGTH);
+
+       data_vals = sig_data + RR3_HEADER_LENGTH +
+                   (header.max_lengths * sizeof(u16));
+
+       /* process each rr3 encoded byte into an int */
+       for (i = 0; i < header.sig_size; i++) {
+               u16 val = len_vals[data_vals[i]];
+               single_len = redrat3_len_to_us((u32)be16_to_cpu(val));
+
+               /* cap the value to IR_MAX_DURATION */
+               single_len &= IR_MAX_DURATION;
+
+               /* we should always get pulse/space/pulse/space samples */
+               if (i % 2)
+                       rawir.pulse = false;
+               else
+                       rawir.pulse = true;
+
+               rawir.duration = US_TO_NS(single_len);
+               rr3_dbg(dev, "storing %s with duration %d (i: %d)\n",
+                       rawir.pulse ? "pulse" : "space", rawir.duration, i);
+               ir_raw_event_store_with_filter(rr3->rc, &rawir);
+       }
+
+       /* add a trailing space, if need be */
+       if (i % 2) {
+               rawir.pulse = false;
+               /* this duration is made up, and may not be ideal... */
+               rawir.duration = rr3->rc->timeout / 2;
+               rr3_dbg(dev, "storing trailing space with duration %d\n",
+                       rawir.duration);
+               ir_raw_event_store_with_filter(rr3->rc, &rawir);
+       }
+
+       rr3_dbg(dev, "calling ir_raw_event_handle\n");
+       ir_raw_event_handle(rr3->rc);
+
+       return;
+}
+
+/* Util fn to send rr3 cmds */
+static u8 redrat3_send_cmd(int cmd, struct redrat3_dev *rr3)
+{
+       struct usb_device *udev;
+       u8 *data;
+       int res;
+
+       data = kzalloc(sizeof(u8), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       udev = rr3->udev;
+       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), cmd,
+                             USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                             0x0000, 0x0000, data, sizeof(u8), HZ * 10);
+
+       if (res < 0) {
+               dev_err(rr3->dev, "%s: Error sending rr3 cmd res %d, data %d",
+                       __func__, res, *data);
+               res = -EIO;
+       } else
+               res = (u8)data[0];
+
+       kfree(data);
+
+       return res;
+}
+
+/* Enables the long range detector and starts async receive */
+static int redrat3_enable_detector(struct redrat3_dev *rr3)
+{
+       struct device *dev = rr3->dev;
+       u8 ret;
+
+       rr3_ftr(dev, "Entering %s\n", __func__);
+
+       ret = redrat3_send_cmd(RR3_RC_DET_ENABLE, rr3);
+       if (ret != 0)
+               dev_dbg(dev, "%s: unexpected ret of %d\n",
+                       __func__, ret);
+
+       ret = redrat3_send_cmd(RR3_RC_DET_STATUS, rr3);
+       if (ret != 1) {
+               dev_err(dev, "%s: detector status: %d, should be 1\n",
+                       __func__, ret);
+               return -EIO;
+       }
+
+       rr3->det_enabled = true;
+       redrat3_issue_async(rr3);
+
+       return 0;
+}
+
+/* Disables the rr3 long range detector */
+static void redrat3_disable_detector(struct redrat3_dev *rr3)
+{
+       struct device *dev = rr3->dev;
+       u8 ret;
+
+       rr3_ftr(dev, "Entering %s\n", __func__);
+
+       ret = redrat3_send_cmd(RR3_RC_DET_DISABLE, rr3);
+       if (ret != 0)
+               dev_err(dev, "%s: failure!\n", __func__);
+
+       ret = redrat3_send_cmd(RR3_RC_DET_STATUS, rr3);
+       if (ret != 0)
+               dev_warn(dev, "%s: detector status: %d, should be 0\n",
+                        __func__, ret);
+
+       rr3->det_enabled = false;
+}
+
+static inline void redrat3_delete(struct redrat3_dev *rr3,
+                                 struct usb_device *udev)
+{
+       rr3_ftr(rr3->dev, "%s cleaning up\n", __func__);
+       usb_kill_urb(rr3->read_urb);
+       usb_kill_urb(rr3->write_urb);
+
+       usb_free_urb(rr3->read_urb);
+       usb_free_urb(rr3->write_urb);
+
+       usb_free_coherent(udev, rr3->ep_in->wMaxPacketSize,
+                         rr3->bulk_in_buf, rr3->dma_in);
+       usb_free_coherent(udev, rr3->ep_out->wMaxPacketSize,
+                         rr3->bulk_out_buf, rr3->dma_out);
+
+       kfree(rr3);
+}
+
+static u32 redrat3_get_timeout(struct device *dev,
+                              struct rc_dev *rc, struct usb_device *udev)
+{
+       u32 *tmp;
+       u32 timeout = MS_TO_NS(150); /* a sane default, if things go haywire */
+       int len, ret, pipe;
+
+       len = sizeof(*tmp);
+       tmp = kzalloc(len, GFP_KERNEL);
+       if (!tmp) {
+               dev_warn(dev, "Memory allocation faillure\n");
+               return timeout;
+       }
+
+       pipe = usb_rcvctrlpipe(udev, 0);
+       ret = usb_control_msg(udev, pipe, RR3_GET_IR_PARAM,
+                             USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                             RR3_IR_IO_SIG_TIMEOUT, 0, tmp, len, HZ * 5);
+       if (ret != len) {
+               dev_warn(dev, "Failed to read timeout from hardware\n");
+               return timeout;
+       }
+
+       timeout = US_TO_NS(redrat3_len_to_us(be32_to_cpu(*tmp)));
+       if (timeout < rc->min_timeout)
+               timeout = rc->min_timeout;
+       else if (timeout > rc->max_timeout)
+               timeout = rc->max_timeout;
+
+       rr3_dbg(dev, "Got timeout of %d ms\n", timeout / (1000 * 1000));
+       return timeout;
+}
+
+static void redrat3_reset(struct redrat3_dev *rr3)
+{
+       struct usb_device *udev = rr3->udev;
+       struct device *dev = rr3->dev;
+       int rc, rxpipe, txpipe;
+       u8 *val;
+       int len = sizeof(u8);
+
+       rr3_ftr(dev, "Entering %s\n", __func__);
+
+       rxpipe = usb_rcvctrlpipe(udev, 0);
+       txpipe = usb_sndctrlpipe(udev, 0);
+
+       val = kzalloc(len, GFP_KERNEL);
+       if (!val) {
+               dev_err(dev, "Memory allocation failure\n");
+               return;
+       }
+
+       *val = 0x01;
+       rc = usb_control_msg(udev, rxpipe, RR3_RESET,
+                            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                            RR3_CPUCS_REG_ADDR, 0, val, len, HZ * 25);
+       rr3_dbg(dev, "reset returned 0x%02x\n", rc);
+
+       *val = 5;
+       rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM,
+                            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+                            RR3_IR_IO_LENGTH_FUZZ, 0, val, len, HZ * 25);
+       rr3_dbg(dev, "set ir parm len fuzz %d rc 0x%02x\n", *val, rc);
+
+       *val = RR3_DRIVER_MAXLENS;
+       rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM,
+                            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+                            RR3_IR_IO_MAX_LENGTHS, 0, val, len, HZ * 25);
+       rr3_dbg(dev, "set ir parm max lens %d rc 0x%02x\n", *val, rc);
+
+       kfree(val);
+}
+
+static void redrat3_get_firmware_rev(struct redrat3_dev *rr3)
+{
+       int rc = 0;
+       char *buffer;
+
+       rr3_ftr(rr3->dev, "Entering %s\n", __func__);
+
+       buffer = kzalloc(sizeof(char) * (RR3_FW_VERSION_LEN + 1), GFP_KERNEL);
+       if (!buffer) {
+               dev_err(rr3->dev, "Memory allocation failure\n");
+               return;
+       }
+
+       rc = usb_control_msg(rr3->udev, usb_rcvctrlpipe(rr3->udev, 0),
+                            RR3_FW_VERSION,
+                            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                            0, 0, buffer, RR3_FW_VERSION_LEN, HZ * 5);
+
+       if (rc >= 0)
+               dev_info(rr3->dev, "Firmware rev: %s", buffer);
+       else
+               dev_err(rr3->dev, "Problem fetching firmware ID\n");
+
+       kfree(buffer);
+       rr3_ftr(rr3->dev, "Exiting %s\n", __func__);
+}
+
+static void redrat3_read_packet_start(struct redrat3_dev *rr3, int len)
+{
+       u16 tx_error;
+       u16 hdrlen;
+
+       rr3_ftr(rr3->dev, "Entering %s\n", __func__);
+
+       /* grab the Length and type of transfer */
+       memcpy(&(rr3->pktlen), (unsigned char *) rr3->bulk_in_buf,
+              sizeof(rr3->pktlen));
+       memcpy(&(rr3->pkttype), ((unsigned char *) rr3->bulk_in_buf +
+               sizeof(rr3->pktlen)),
+              sizeof(rr3->pkttype));
+
+       /*data needs conversion to know what its real values are*/
+       rr3->pktlen = be16_to_cpu(rr3->pktlen);
+       rr3->pkttype = be16_to_cpu(rr3->pkttype);
+
+       switch (rr3->pkttype) {
+       case RR3_ERROR:
+               memcpy(&tx_error, ((unsigned char *)rr3->bulk_in_buf
+                       + (sizeof(rr3->pktlen) + sizeof(rr3->pkttype))),
+                      sizeof(tx_error));
+               tx_error = be16_to_cpu(tx_error);
+               redrat3_dump_fw_error(rr3, tx_error);
+               break;
+
+       case RR3_MOD_SIGNAL_IN:
+               hdrlen = sizeof(rr3->pktlen) + sizeof(rr3->pkttype);
+               rr3->bytes_read = len;
+               rr3->bytes_read -= hdrlen;
+               rr3->datap = &(rr3->pbuf[0]);
+
+               memcpy(rr3->datap, ((unsigned char *)rr3->bulk_in_buf + hdrlen),
+                      rr3->bytes_read);
+               rr3->datap += rr3->bytes_read;
+               rr3_dbg(rr3->dev, "bytes_read %d, pktlen %d\n",
+                       rr3->bytes_read, rr3->pktlen);
+               break;
+
+       default:
+               rr3_dbg(rr3->dev, "ignoring packet with type 0x%02x, "
+                       "len of %d, 0x%02x\n", rr3->pkttype, len, rr3->pktlen);
+               break;
+       }
+}
+
+static void redrat3_read_packet_continue(struct redrat3_dev *rr3, int len)
+{
+
+       rr3_ftr(rr3->dev, "Entering %s\n", __func__);
+
+       memcpy(rr3->datap, (unsigned char *)rr3->bulk_in_buf, len);
+       rr3->datap += len;
+
+       rr3->bytes_read += len;
+       rr3_dbg(rr3->dev, "bytes_read %d, pktlen %d\n",
+               rr3->bytes_read, rr3->pktlen);
+}
+
+/* gather IR data from incoming urb, process it when we have enough */
+static int redrat3_get_ir_data(struct redrat3_dev *rr3, int len)
+{
+       struct device *dev = rr3->dev;
+       int ret = 0;
+
+       rr3_ftr(dev, "Entering %s\n", __func__);
+
+       if (rr3->pktlen > RR3_MAX_BUF_SIZE) {
+               dev_err(rr3->dev, "error: packet larger than buffer\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if ((rr3->bytes_read == 0) &&
+           (len >= (sizeof(rr3->pkttype) + sizeof(rr3->pktlen)))) {
+               redrat3_read_packet_start(rr3, len);
+       } else if (rr3->bytes_read != 0) {
+               redrat3_read_packet_continue(rr3, len);
+       } else if (rr3->bytes_read == 0) {
+               dev_err(dev, "error: no packet data read\n");
+               ret = -ENODATA;
+               goto out;
+       }
+
+       if (rr3->bytes_read > rr3->pktlen) {
+               dev_err(dev, "bytes_read (%d) greater than pktlen (%d)\n",
+                       rr3->bytes_read, rr3->pktlen);
+               ret = -EINVAL;
+               goto out;
+       } else if (rr3->bytes_read < rr3->pktlen)
+               /* we're still accumulating data */
+               return 0;
+
+       /* if we get here, we've got IR data to decode */
+       if (rr3->pkttype == RR3_MOD_SIGNAL_IN)
+               redrat3_process_ir_data(rr3);
+       else
+               rr3_dbg(dev, "discarding non-signal data packet "
+                       "(type 0x%02x)\n", rr3->pkttype);
+
+out:
+       rr3->bytes_read = 0;
+       rr3->pktlen = 0;
+       rr3->pkttype = 0;
+       return ret;
+}
+
+/* callback function from USB when async USB request has completed */
+static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs)
+{
+       struct redrat3_dev *rr3;
+
+       if (!urb)
+               return;
+
+       rr3 = urb->context;
+       if (!rr3) {
+               pr_err("%s called with invalid context!\n", __func__);
+               usb_unlink_urb(urb);
+               return;
+       }
+
+       rr3_ftr(rr3->dev, "Entering %s\n", __func__);
+
+       if (!rr3->det_enabled) {
+               rr3_dbg(rr3->dev, "received a read callback but detector "
+                       "disabled - ignoring\n");
+               return;
+       }
+
+       switch (urb->status) {
+       case 0:
+               redrat3_get_ir_data(rr3, urb->actual_length);
+               break;
+
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               usb_unlink_urb(urb);
+               return;
+
+       case -EPIPE:
+       default:
+               dev_warn(rr3->dev, "Error: urb status = %d\n", urb->status);
+               rr3->bytes_read = 0;
+               rr3->pktlen = 0;
+               rr3->pkttype = 0;
+               break;
+       }
+
+       if (!rr3->transmitting)
+               redrat3_issue_async(rr3);
+       else
+               rr3_dbg(rr3->dev, "IR transmit in progress\n");
+}
+
+static void redrat3_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
+{
+       struct redrat3_dev *rr3;
+       int len;
+
+       if (!urb)
+               return;
+
+       rr3 = urb->context;
+       if (rr3) {
+               len = urb->actual_length;
+               rr3_ftr(rr3->dev, "%s: called (status=%d len=%d)\n",
+                       __func__, urb->status, len);
+       }
+}
+
+static u16 mod_freq_to_val(unsigned int mod_freq)
+{
+       int mult = 6000000;
+
+       /* Clk used in mod. freq. generation is CLK24/4. */
+       return (u16)(65536 - (mult / mod_freq));
+}
+
+static int redrat3_set_tx_carrier(struct rc_dev *dev, u32 carrier)
+{
+       struct redrat3_dev *rr3 = dev->priv;
+
+       rr3->carrier = carrier;
+
+       return carrier;
+}
+
+static int redrat3_transmit_ir(struct rc_dev *rcdev, int *txbuf, u32 n)
+{
+       struct redrat3_dev *rr3 = rcdev->priv;
+       struct device *dev = rr3->dev;
+       struct redrat3_signal_header header;
+       int i, j, count, ret, ret_len, offset;
+       int lencheck, cur_sample_len, pipe;
+       char *buffer = NULL, *sigdata = NULL;
+       int *sample_lens = NULL;
+       u32 tmpi;
+       u16 tmps;
+       u8 *datap;
+       u8 curlencheck = 0;
+       u16 *lengths_ptr;
+       int sendbuf_len;
+
+       rr3_ftr(dev, "Entering %s\n", __func__);
+
+       if (rr3->transmitting) {
+               dev_warn(dev, "%s: transmitter already in use\n", __func__);
+               return -EAGAIN;
+       }
+
+       count = n / sizeof(int);
+       if (count > (RR3_DRIVER_MAXLENS * 2))
+               return -EINVAL;
+
+       rr3->transmitting = true;
+
+       redrat3_disable_detector(rr3);
+
+       if (rr3->det_enabled) {
+               dev_err(dev, "%s: cannot tx while rx is enabled\n", __func__);
+               ret = -EIO;
+               goto out;
+       }
+
+       sample_lens = kzalloc(sizeof(int) * RR3_DRIVER_MAXLENS, GFP_KERNEL);
+       if (!sample_lens) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       for (i = 0; i < count; i++) {
+               for (lencheck = 0; lencheck < curlencheck; lencheck++) {
+                       cur_sample_len = redrat3_us_to_len(txbuf[i]);
+                       if (sample_lens[lencheck] == cur_sample_len)
+                               break;
+               }
+               if (lencheck == curlencheck) {
+                       cur_sample_len = redrat3_us_to_len(txbuf[i]);
+                       rr3_dbg(dev, "txbuf[%d]=%u, pos %d, enc %u\n",
+                               i, txbuf[i], curlencheck, cur_sample_len);
+                       if (curlencheck < 255) {
+                               /* now convert the value to a proper
+                                * rr3 value.. */
+                               sample_lens[curlencheck] = cur_sample_len;
+                               curlencheck++;
+                       } else {
+                               dev_err(dev, "signal too long\n");
+                               ret = -EINVAL;
+                               goto out;
+                       }
+               }
+       }
+
+       sigdata = kzalloc((count + RR3_TX_TRAILER_LEN), GFP_KERNEL);
+       if (!sigdata) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       sigdata[count] = RR3_END_OF_SIGNAL;
+       sigdata[count + 1] = RR3_END_OF_SIGNAL;
+       for (i = 0; i < count; i++) {
+               for (j = 0; j < curlencheck; j++) {
+                       if (sample_lens[j] == redrat3_us_to_len(txbuf[i]))
+                               sigdata[i] = j;
+               }
+       }
+
+       offset = RR3_TX_HEADER_OFFSET;
+       sendbuf_len = RR3_HEADER_LENGTH + (sizeof(u16) * RR3_DRIVER_MAXLENS)
+                       + count + RR3_TX_TRAILER_LEN + offset;
+
+       buffer = kzalloc(sendbuf_len, GFP_KERNEL);
+       if (!buffer) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /* fill in our packet header */
+       header.length = sendbuf_len - offset;
+       header.transfer_type = RR3_MOD_SIGNAL_OUT;
+       header.pause = redrat3_len_to_us(100);
+       header.mod_freq_count = mod_freq_to_val(rr3->carrier);
+       header.no_periods = 0; /* n/a to transmit */
+       header.max_lengths = RR3_DRIVER_MAXLENS;
+       header.no_lengths = curlencheck;
+       header.max_sig_size = RR3_MAX_SIG_SIZE;
+       header.sig_size = count + RR3_TX_TRAILER_LEN;
+       /* we currently rely on repeat handling in the IR encoding source */
+       header.no_repeats = 0;
+
+       tmps = cpu_to_be16(header.length);
+       memcpy(buffer, &tmps, 2);
+
+       tmps = cpu_to_be16(header.transfer_type);
+       memcpy(buffer + 2, &tmps, 2);
+
+       tmpi = cpu_to_be32(header.pause);
+       memcpy(buffer + offset, &tmpi, sizeof(tmpi));
+
+       tmps = cpu_to_be16(header.mod_freq_count);
+       memcpy(buffer + offset + RR3_FREQ_COUNT_OFFSET, &tmps, 2);
+
+       buffer[offset + RR3_NUM_LENGTHS_OFFSET] = header.no_lengths;
+
+       tmps = cpu_to_be16(header.sig_size);
+       memcpy(buffer + offset + RR3_NUM_SIGS_OFFSET, &tmps, 2);
+
+       buffer[offset + RR3_REPEATS_OFFSET] = header.no_repeats;
+
+       lengths_ptr = (u16 *)(buffer + offset + RR3_HEADER_LENGTH);
+       for (i = 0; i < curlencheck; ++i)
+               lengths_ptr[i] = cpu_to_be16(sample_lens[i]);
+
+       datap = (u8 *)(buffer + offset + RR3_HEADER_LENGTH +
+                           (sizeof(u16) * RR3_DRIVER_MAXLENS));
+       memcpy(datap, sigdata, (count + RR3_TX_TRAILER_LEN));
+
+       if (debug) {
+               redrat3_dump_signal_header(&header);
+               redrat3_dump_signal_data(buffer, header.sig_size);
+       }
+
+       pipe = usb_sndbulkpipe(rr3->udev, rr3->ep_out->bEndpointAddress);
+       tmps = usb_bulk_msg(rr3->udev, pipe, buffer,
+                           sendbuf_len, &ret_len, 10 * HZ);
+       rr3_dbg(dev, "sent %d bytes, (ret %d)\n", ret_len, tmps);
+
+       /* now tell the hardware to transmit what we sent it */
+       pipe = usb_rcvctrlpipe(rr3->udev, 0);
+       ret = usb_control_msg(rr3->udev, pipe, RR3_TX_SEND_SIGNAL,
+                             USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                             0, 0, buffer, 2, HZ * 10);
+
+       if (ret < 0)
+               dev_err(dev, "Error: control msg send failed, rc %d\n", ret);
+       else
+               ret = n;
+
+out:
+       kfree(sample_lens);
+       kfree(buffer);
+       kfree(sigdata);
+
+       rr3->transmitting = false;
+
+       redrat3_enable_detector(rr3);
+
+       return ret;
+}
+
+static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)
+{
+       struct device *dev = rr3->dev;
+       struct rc_dev *rc;
+       int ret = -ENODEV;
+       u16 prod = le16_to_cpu(rr3->udev->descriptor.idProduct);
+
+       rc = rc_allocate_device();
+       if (!rc) {
+               dev_err(dev, "remote input dev allocation failed\n");
+               goto out;
+       }
+
+       snprintf(rr3->name, sizeof(rr3->name), "RedRat3%s "
+                "Infrared Remote Transceiver (%04x:%04x)",
+                prod == USB_RR3IIUSB_PRODUCT_ID ? "-II" : "",
+                le16_to_cpu(rr3->udev->descriptor.idVendor), prod);
+
+       usb_make_path(rr3->udev, rr3->phys, sizeof(rr3->phys));
+
+       rc->input_name = rr3->name;
+       rc->input_phys = rr3->phys;
+       usb_to_input_id(rr3->udev, &rc->input_id);
+       rc->dev.parent = dev;
+       rc->priv = rr3;
+       rc->driver_type = RC_DRIVER_IR_RAW;
+       rc->allowed_protos = RC_TYPE_ALL;
+       rc->min_timeout = MS_TO_NS(RR3_RX_MIN_TIMEOUT);
+       rc->max_timeout = MS_TO_NS(RR3_RX_MAX_TIMEOUT);
+       rc->timeout = redrat3_get_timeout(dev, rc, rr3->udev);
+       rc->tx_ir = redrat3_transmit_ir;
+       rc->s_tx_carrier = redrat3_set_tx_carrier;
+       rc->driver_name = DRIVER_NAME;
+       rc->map_name = RC_MAP_HAUPPAUGE;
+
+       ret = rc_register_device(rc);
+       if (ret < 0) {
+               dev_err(dev, "remote dev registration failed\n");
+               goto out;
+       }
+
+       return rc;
+
+out:
+       rc_free_device(rc);
+       return NULL;
+}
+
+static int __devinit redrat3_dev_probe(struct usb_interface *intf,
+                                      const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct device *dev = &intf->dev;
+       struct usb_host_interface *uhi;
+       struct redrat3_dev *rr3;
+       struct usb_endpoint_descriptor *ep;
+       struct usb_endpoint_descriptor *ep_in = NULL;
+       struct usb_endpoint_descriptor *ep_out = NULL;
+       u8 addr, attrs;
+       int pipe, i;
+       int retval = -ENOMEM;
+
+       rr3_ftr(dev, "%s called\n", __func__);
+
+       uhi = intf->cur_altsetting;
+
+       /* find our bulk-in and bulk-out endpoints */
+       for (i = 0; i < uhi->desc.bNumEndpoints; ++i) {
+               ep = &uhi->endpoint[i].desc;
+               addr = ep->bEndpointAddress;
+               attrs = ep->bmAttributes;
+
+               if ((ep_in == NULL) &&
+                   ((addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) &&
+                   ((attrs & USB_ENDPOINT_XFERTYPE_MASK) ==
+                    USB_ENDPOINT_XFER_BULK)) {
+                       rr3_dbg(dev, "found bulk-in endpoint at 0x%02x\n",
+                               ep->bEndpointAddress);
+                       /* data comes in on 0x82, 0x81 is for other data... */
+                       if (ep->bEndpointAddress == RR3_BULK_IN_EP_ADDR)
+                               ep_in = ep;
+               }
+
+               if ((ep_out == NULL) &&
+                   ((addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) &&
+                   ((attrs & USB_ENDPOINT_XFERTYPE_MASK) ==
+                    USB_ENDPOINT_XFER_BULK)) {
+                       rr3_dbg(dev, "found bulk-out endpoint at 0x%02x\n",
+                               ep->bEndpointAddress);
+                       ep_out = ep;
+               }
+       }
+
+       if (!ep_in || !ep_out) {
+               dev_err(dev, "Couldn't find both in and out endpoints\n");
+               retval = -ENODEV;
+               goto no_endpoints;
+       }
+
+       /* allocate memory for our device state and initialize it */
+       rr3 = kzalloc(sizeof(*rr3), GFP_KERNEL);
+       if (rr3 == NULL) {
+               dev_err(dev, "Memory allocation failure\n");
+               goto error;
+       }
+
+       rr3->dev = &intf->dev;
+
+       /* set up bulk-in endpoint */
+       rr3->read_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!rr3->read_urb) {
+               dev_err(dev, "Read urb allocation failure\n");
+               goto error;
+       }
+
+       rr3->ep_in = ep_in;
+       rr3->bulk_in_buf = usb_alloc_coherent(udev, ep_in->wMaxPacketSize,
+                                             GFP_ATOMIC, &rr3->dma_in);
+       if (!rr3->bulk_in_buf) {
+               dev_err(dev, "Read buffer allocation failure\n");
+               goto error;
+       }
+
+       pipe = usb_rcvbulkpipe(udev, ep_in->bEndpointAddress);
+       usb_fill_bulk_urb(rr3->read_urb, udev, pipe,
+                         rr3->bulk_in_buf, ep_in->wMaxPacketSize,
+                         (usb_complete_t)redrat3_handle_async, rr3);
+
+       /* set up bulk-out endpoint*/
+       rr3->write_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!rr3->write_urb) {
+               dev_err(dev, "Write urb allocation failure\n");
+               goto error;
+       }
+
+       rr3->ep_out = ep_out;
+       rr3->bulk_out_buf = usb_alloc_coherent(udev, ep_out->wMaxPacketSize,
+                                              GFP_ATOMIC, &rr3->dma_out);
+       if (!rr3->bulk_out_buf) {
+               dev_err(dev, "Write buffer allocation failure\n");
+               goto error;
+       }
+
+       pipe = usb_sndbulkpipe(udev, ep_out->bEndpointAddress);
+       usb_fill_bulk_urb(rr3->write_urb, udev, pipe,
+                         rr3->bulk_out_buf, ep_out->wMaxPacketSize,
+                         (usb_complete_t)redrat3_write_bulk_callback, rr3);
+
+       mutex_init(&rr3->lock);
+       rr3->udev = udev;
+
+       redrat3_reset(rr3);
+       redrat3_get_firmware_rev(rr3);
+
+       /* might be all we need to do? */
+       retval = redrat3_enable_detector(rr3);
+       if (retval < 0)
+               goto error;
+
+       /* default.. will get overridden by any sends with a freq defined */
+       rr3->carrier = 38000;
+
+       rr3->rc = redrat3_init_rc_dev(rr3);
+       if (!rr3->rc)
+               goto error;
+
+       setup_timer(&rr3->rx_timeout, redrat3_rx_timeout, (unsigned long)rr3);
+
+       /* we can register the device now, as it is ready */
+       usb_set_intfdata(intf, rr3);
+
+       rr3_ftr(dev, "Exiting %s\n", __func__);
+       return 0;
+
+error:
+       redrat3_delete(rr3, rr3->udev);
+
+no_endpoints:
+       dev_err(dev, "%s: retval = %x", __func__, retval);
+
+       return retval;
+}
+
+static void __devexit redrat3_dev_disconnect(struct usb_interface *intf)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct redrat3_dev *rr3 = usb_get_intfdata(intf);
+
+       rr3_ftr(&intf->dev, "Entering %s\n", __func__);
+
+       if (!rr3)
+               return;
+
+       redrat3_disable_detector(rr3);
+
+       usb_set_intfdata(intf, NULL);
+       rc_unregister_device(rr3->rc);
+       redrat3_delete(rr3, udev);
+
+       rr3_ftr(&intf->dev, "RedRat3 IR Transceiver now disconnected\n");
+}
+
+static int redrat3_dev_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct redrat3_dev *rr3 = usb_get_intfdata(intf);
+       rr3_ftr(rr3->dev, "suspend\n");
+       usb_kill_urb(rr3->read_urb);
+       return 0;
+}
+
+static int redrat3_dev_resume(struct usb_interface *intf)
+{
+       struct redrat3_dev *rr3 = usb_get_intfdata(intf);
+       rr3_ftr(rr3->dev, "resume\n");
+       if (usb_submit_urb(rr3->read_urb, GFP_ATOMIC))
+               return -EIO;
+       return 0;
+}
+
+static struct usb_driver redrat3_dev_driver = {
+       .name           = DRIVER_NAME,
+       .probe          = redrat3_dev_probe,
+       .disconnect     = redrat3_dev_disconnect,
+       .suspend        = redrat3_dev_suspend,
+       .resume         = redrat3_dev_resume,
+       .reset_resume   = redrat3_dev_resume,
+       .id_table       = redrat3_dev_table
+};
+
+static int __init redrat3_dev_init(void)
+{
+       int ret;
+
+       ret = usb_register(&redrat3_dev_driver);
+       if (ret < 0)
+               pr_err(DRIVER_NAME
+                      ": usb register failed, result = %d\n", ret);
+
+       return ret;
+}
+
+static void __exit redrat3_dev_exit(void)
+{
+       usb_deregister(&redrat3_dev_driver);
+}
+
+module_init(redrat3_dev_init);
+module_exit(redrat3_dev_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_AUTHOR(DRIVER_AUTHOR2);
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(usb, redrat3_dev_table);
+
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable module debug spew. 0 = no debugging (default) "
+                "0x1 = standard debug messages, 0x2 = function tracing debug. "
+                "Flag bits are addative (i.e., 0x3 for both debug types).");
index 186de55..5d06b89 100644 (file)
  *    o DSDT dumps
  *
  *  Supported features:
+ *    o IR Receive
+ *    o IR Transmit
  *    o Wake-On-CIR functionality
  *
  *  To do:
  *    o Learning
- *    o IR Transmit
  *
  *  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
@@ -50,6 +51,8 @@
 #include <linux/io.h>
 #include <linux/bitrev.h>
 #include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
 #include <media/rc-core.h>
 
 #define DRVNAME "winbond-cir"
 #define WBCIR_IRQ_NONE         0x00
 /* RX data bit for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */
 #define WBCIR_IRQ_RX           0x01
+/* TX data low bit for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */
+#define WBCIR_IRQ_TX_LOW       0x02
 /* Over/Under-flow bit for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */
 #define WBCIR_IRQ_ERR          0x04
+/* TX data empty bit for WBCEIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */
+#define WBCIR_IRQ_TX_EMPTY     0x20
 /* Led enable/disable bit for WBCIR_REG_ECEIR_CTS */
 #define WBCIR_LED_ENABLE       0x80
 /* RX data available bit for WBCIR_REG_SP3_LSR */
 #define WBCIR_RX_AVAIL         0x01
+/* RX data overrun error bit for WBCIR_REG_SP3_LSR */
+#define WBCIR_RX_OVERRUN       0x02
+/* TX End-Of-Transmission bit for WBCIR_REG_SP3_ASCR */
+#define WBCIR_TX_EOT           0x04
 /* RX disable bit for WBCIR_REG_SP3_ASCR */
 #define WBCIR_RX_DISABLE       0x20
+/* TX data underrun error bit for WBCIR_REG_SP3_ASCR */
+#define WBCIR_TX_UNDERRUN      0x40
 /* Extended mode enable bit for WBCIR_REG_SP3_EXCR1 */
 #define WBCIR_EXT_ENABLE       0x01
 /* Select compare register in WBCIR_REG_WCEIR_INDEX (bits 5 & 6) */
@@ -154,6 +167,21 @@ enum wbcir_protocol {
        IR_PROTOCOL_RC6          = 0x2,
 };
 
+/* Possible states for IR reception */
+enum wbcir_rxstate {
+       WBCIR_RXSTATE_INACTIVE = 0,
+       WBCIR_RXSTATE_ACTIVE,
+       WBCIR_RXSTATE_ERROR
+};
+
+/* Possible states for IR transmission */
+enum wbcir_txstate {
+       WBCIR_TXSTATE_INACTIVE = 0,
+       WBCIR_TXSTATE_ACTIVE,
+       WBCIR_TXSTATE_DONE,
+       WBCIR_TXSTATE_ERROR
+};
+
 /* Misc */
 #define WBCIR_NAME     "Winbond CIR"
 #define WBCIR_ID_FAMILY          0xF1 /* Family ID for the WPCD376I    */
@@ -166,22 +194,29 @@ enum wbcir_protocol {
 /* Per-device data */
 struct wbcir_data {
        spinlock_t spinlock;
+       struct rc_dev *dev;
+       struct led_classdev led;
 
        unsigned long wbase;        /* Wake-Up Baseaddr         */
        unsigned long ebase;        /* Enhanced Func. Baseaddr  */
        unsigned long sbase;        /* Serial Port Baseaddr     */
        unsigned int  irq;          /* Serial Port IRQ          */
+       u8 irqmask;
 
-       struct rc_dev *dev;
-
+       /* RX state */
+       enum wbcir_rxstate rxstate;
        struct led_trigger *rxtrigger;
-       struct led_trigger *txtrigger;
-       struct led_classdev led;
+       struct ir_raw_event rxev;
 
-       /* RX irdata state */
-       bool irdata_active;
-       bool irdata_error;
-       struct ir_raw_event ev;
+       /* TX state */
+       enum wbcir_txstate txstate;
+       struct led_trigger *txtrigger;
+       u32 txlen;
+       u32 txoff;
+       u32 *txbuf;
+       wait_queue_head_t txwaitq;
+       u8 txmask;
+       u32 txcarrier;
 };
 
 static enum wbcir_protocol protocol = IR_PROTOCOL_RC6;
@@ -193,6 +228,10 @@ static int invert; /* default = 0 */
 module_param(invert, bool, 0444);
 MODULE_PARM_DESC(invert, "Invert the signal from the IR receiver");
 
+static int txandrx; /* default = 0 */
+module_param(txandrx, bool, 0444);
+MODULE_PARM_DESC(invert, "Allow simultaneous TX and RX");
+
 static unsigned int wake_sc = 0x800F040C;
 module_param(wake_sc, uint, 0644);
 MODULE_PARM_DESC(wake_sc, "Scancode of the power-on IR command");
@@ -228,6 +267,17 @@ wbcir_select_bank(struct wbcir_data *data, enum wbcir_bank bank)
        outb(bank, data->sbase + WBCIR_REG_SP3_BSR);
 }
 
+static inline void
+wbcir_set_irqmask(struct wbcir_data *data, u8 irqmask)
+{
+       if (data->irqmask == irqmask)
+               return;
+
+       wbcir_select_bank(data, WBCIR_BANK_0);
+       outb(irqmask, data->sbase + WBCIR_REG_SP3_IER);
+       data->irqmask = irqmask;
+}
+
 static enum led_brightness
 wbcir_led_brightness_get(struct led_classdev *led_cdev)
 {
@@ -279,97 +329,297 @@ wbcir_to_rc6cells(u8 val)
  *
  *****************************************************************************/
 
+static void
+wbcir_idle_rx(struct rc_dev *dev, bool idle)
+{
+       struct wbcir_data *data = dev->priv;
+
+       if (!idle && data->rxstate == WBCIR_RXSTATE_INACTIVE) {
+               data->rxstate = WBCIR_RXSTATE_ACTIVE;
+               led_trigger_event(data->rxtrigger, LED_FULL);
+       }
+
+       if (idle && data->rxstate != WBCIR_RXSTATE_INACTIVE)
+               /* Tell hardware to go idle by setting RXINACTIVE */
+               outb(WBCIR_RX_DISABLE, data->sbase + WBCIR_REG_SP3_ASCR);
+}
+
+static void
+wbcir_irq_rx(struct wbcir_data *data, struct pnp_dev *device)
+{
+       u8 irdata;
+       DEFINE_IR_RAW_EVENT(rawir);
+
+       /* Since RXHDLEV is set, at least 8 bytes are in the FIFO */
+       while (inb(data->sbase + WBCIR_REG_SP3_LSR) & WBCIR_RX_AVAIL) {
+               irdata = inb(data->sbase + WBCIR_REG_SP3_RXDATA);
+               if (data->rxstate == WBCIR_RXSTATE_ERROR)
+                       continue;
+               rawir.pulse = irdata & 0x80 ? false : true;
+               rawir.duration = US_TO_NS((irdata & 0x7F) * 10);
+               ir_raw_event_store_with_filter(data->dev, &rawir);
+       }
+
+       /* Check if we should go idle */
+       if (data->dev->idle) {
+               led_trigger_event(data->rxtrigger, LED_OFF);
+               data->rxstate = WBCIR_RXSTATE_INACTIVE;
+       }
+
+       ir_raw_event_handle(data->dev);
+}
+
+static void
+wbcir_irq_tx(struct wbcir_data *data)
+{
+       unsigned int space;
+       unsigned int used;
+       u8 bytes[16];
+       u8 byte;
+
+       if (!data->txbuf)
+               return;
+
+       switch (data->txstate) {
+       case WBCIR_TXSTATE_INACTIVE:
+               /* TX FIFO empty */
+               space = 16;
+               led_trigger_event(data->txtrigger, LED_FULL);
+               break;
+       case WBCIR_TXSTATE_ACTIVE:
+               /* TX FIFO low (3 bytes or less) */
+               space = 13;
+               break;
+       case WBCIR_TXSTATE_ERROR:
+               space = 0;
+               break;
+       default:
+               return;
+       }
+
+       /*
+        * TX data is run-length coded in bytes: YXXXXXXX
+        * Y = space (1) or pulse (0)
+        * X = duration, encoded as (X + 1) * 10us (i.e 10 to 1280 us)
+        */
+       for (used = 0; used < space && data->txoff != data->txlen; used++) {
+               if (data->txbuf[data->txoff] == 0) {
+                       data->txoff++;
+                       continue;
+               }
+               byte = min((u32)0x80, data->txbuf[data->txoff]);
+               data->txbuf[data->txoff] -= byte;
+               byte--;
+               byte |= (data->txoff % 2 ? 0x80 : 0x00); /* pulse/space */
+               bytes[used] = byte;
+       }
+
+       while (data->txbuf[data->txoff] == 0 && data->txoff != data->txlen)
+               data->txoff++;
+
+       if (used == 0) {
+               /* Finished */
+               if (data->txstate == WBCIR_TXSTATE_ERROR)
+                       /* Clear TX underrun bit */
+                       outb(WBCIR_TX_UNDERRUN, data->sbase + WBCIR_REG_SP3_ASCR);
+               else
+                       data->txstate = WBCIR_TXSTATE_DONE;
+               wbcir_set_irqmask(data, WBCIR_IRQ_RX | WBCIR_IRQ_ERR);
+               led_trigger_event(data->txtrigger, LED_OFF);
+               wake_up(&data->txwaitq);
+       } else if (data->txoff == data->txlen) {
+               /* At the end of transmission, tell the hw before last byte */
+               outsb(data->sbase + WBCIR_REG_SP3_TXDATA, bytes, used - 1);
+               outb(WBCIR_TX_EOT, data->sbase + WBCIR_REG_SP3_ASCR);
+               outb(bytes[used - 1], data->sbase + WBCIR_REG_SP3_TXDATA);
+               wbcir_set_irqmask(data, WBCIR_IRQ_RX | WBCIR_IRQ_ERR |
+                                 WBCIR_IRQ_TX_EMPTY);
+       } else {
+               /* More data to follow... */
+               outsb(data->sbase + WBCIR_REG_SP3_RXDATA, bytes, used);
+               if (data->txstate == WBCIR_TXSTATE_INACTIVE) {
+                       wbcir_set_irqmask(data, WBCIR_IRQ_RX | WBCIR_IRQ_ERR |
+                                         WBCIR_IRQ_TX_LOW);
+                       data->txstate = WBCIR_TXSTATE_ACTIVE;
+               }
+       }
+}
+
 static irqreturn_t
 wbcir_irq_handler(int irqno, void *cookie)
 {
        struct pnp_dev *device = cookie;
        struct wbcir_data *data = pnp_get_drvdata(device);
        unsigned long flags;
-       u8 irdata[8];
-       u8 disable = true;
        u8 status;
-       int i;
 
        spin_lock_irqsave(&data->spinlock, flags);
-
        wbcir_select_bank(data, WBCIR_BANK_0);
-
        status = inb(data->sbase + WBCIR_REG_SP3_EIR);
+       status &= data->irqmask;
 
-       if (!(status & (WBCIR_IRQ_RX | WBCIR_IRQ_ERR))) {
+       if (!status) {
                spin_unlock_irqrestore(&data->spinlock, flags);
                return IRQ_NONE;
        }
 
-       /* Check for e.g. buffer overflow */
        if (status & WBCIR_IRQ_ERR) {
-               data->irdata_error = true;
-               ir_raw_event_reset(data->dev);
-       }
-
-       if (!(status & WBCIR_IRQ_RX))
-               goto out;
+               /* RX overflow? (read clears bit) */
+               if (inb(data->sbase + WBCIR_REG_SP3_LSR) & WBCIR_RX_OVERRUN) {
+                       data->rxstate = WBCIR_RXSTATE_ERROR;
+                       ir_raw_event_reset(data->dev);
+               }
 
-       if (!data->irdata_active) {
-               data->irdata_active = true;
-               led_trigger_event(data->rxtrigger, LED_FULL);
+               /* TX underflow? */
+               if (inb(data->sbase + WBCIR_REG_SP3_ASCR) & WBCIR_TX_UNDERRUN)
+                       data->txstate = WBCIR_TXSTATE_ERROR;
        }
 
-       /* Since RXHDLEV is set, at least 8 bytes are in the FIFO */
-       insb(data->sbase + WBCIR_REG_SP3_RXDATA, &irdata[0], 8);
+       if (status & WBCIR_IRQ_RX)
+               wbcir_irq_rx(data, device);
 
-       for (i = 0; i < 8; i++) {
-               u8 pulse;
-               u32 duration;
+       if (status & (WBCIR_IRQ_TX_LOW | WBCIR_IRQ_TX_EMPTY))
+               wbcir_irq_tx(data);
 
-               if (irdata[i] != 0xFF && irdata[i] != 0x00)
-                       disable = false;
-
-               if (data->irdata_error)
-                       continue;
+       spin_unlock_irqrestore(&data->spinlock, flags);
+       return IRQ_HANDLED;
+}
 
-               pulse = irdata[i] & 0x80 ? false : true;
-               duration = (irdata[i] & 0x7F) * 10000; /* ns */
+/*****************************************************************************
+ *
+ * RC-CORE INTERFACE FUNCTIONS
+ *
+ *****************************************************************************/
 
-               if (data->ev.pulse != pulse) {
-                       if (data->ev.duration != 0) {
-                               ir_raw_event_store(data->dev, &data->ev);
-                               data->ev.duration = 0;
-                       }
+static int
+wbcir_txcarrier(struct rc_dev *dev, u32 carrier)
+{
+       struct wbcir_data *data = dev->priv;
+       unsigned long flags;
+       u8 val;
+       u32 freq;
+
+       freq = DIV_ROUND_CLOSEST(carrier, 1000);
+       if (freq < 30 || freq > 60)
+               return -EINVAL;
+
+       switch (freq) {
+       case 58:
+       case 59:
+       case 60:
+               val = freq - 58;
+               freq *= 1000;
+               break;
+       case 57:
+               val = freq - 27;
+               freq = 56900;
+               break;
+       default:
+               val = freq - 27;
+               freq *= 1000;
+               break;
+       }
 
-                       data->ev.pulse = pulse;
-               }
+       spin_lock_irqsave(&data->spinlock, flags);
+       if (data->txstate != WBCIR_TXSTATE_INACTIVE) {
+               spin_unlock_irqrestore(&data->spinlock, flags);
+               return -EBUSY;
+       }
 
-               data->ev.duration += duration;
+       if (data->txcarrier != freq) {
+               wbcir_select_bank(data, WBCIR_BANK_7);
+               wbcir_set_bits(data->sbase + WBCIR_REG_SP3_IRTXMC, val, 0x1F);
+               data->txcarrier = freq;
        }
 
-       if (disable) {
-               if (data->ev.duration != 0 && !data->irdata_error) {
-                       ir_raw_event_store(data->dev, &data->ev);
-                       data->ev.duration = 0;
-               }
+       spin_unlock_irqrestore(&data->spinlock, flags);
+       return 0;
+}
 
-               /* Set RXINACTIVE */
-               outb(WBCIR_RX_DISABLE, data->sbase + WBCIR_REG_SP3_ASCR);
+static int
+wbcir_txmask(struct rc_dev *dev, u32 mask)
+{
+       struct wbcir_data *data = dev->priv;
+       unsigned long flags;
+       u8 val;
 
-               /* Drain the FIFO */
-               while (inb(data->sbase + WBCIR_REG_SP3_LSR) & WBCIR_RX_AVAIL)
-                       inb(data->sbase + WBCIR_REG_SP3_RXDATA);
+       /* Four outputs, only one output can be enabled at a time */
+       switch (mask) {
+       case 0x1:
+               val = 0x0;
+               break;
+       case 0x2:
+               val = 0x1;
+               break;
+       case 0x4:
+               val = 0x2;
+               break;
+       case 0x8:
+               val = 0x3;
+               break;
+       default:
+               return -EINVAL;
+       }
 
-               ir_raw_event_reset(data->dev);
-               data->irdata_error = false;
-               data->irdata_active = false;
-               led_trigger_event(data->rxtrigger, LED_OFF);
+       spin_lock_irqsave(&data->spinlock, flags);
+       if (data->txstate != WBCIR_TXSTATE_INACTIVE) {
+               spin_unlock_irqrestore(&data->spinlock, flags);
+               return -EBUSY;
        }
 
-       ir_raw_event_handle(data->dev);
+       if (data->txmask != mask) {
+               wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CTS, val, 0x0c);
+               data->txmask = mask;
+       }
 
-out:
        spin_unlock_irqrestore(&data->spinlock, flags);
-       return IRQ_HANDLED;
+       return 0;
 }
 
+static int
+wbcir_tx(struct rc_dev *dev, int *buf, u32 bufsize)
+{
+       struct wbcir_data *data = dev->priv;
+       u32 count;
+       unsigned i;
+       unsigned long flags;
+
+       /* bufsize has been sanity checked by the caller */
+       count = bufsize / sizeof(int);
 
+       /* Not sure if this is possible, but better safe than sorry */
+       spin_lock_irqsave(&data->spinlock, flags);
+       if (data->txstate != WBCIR_TXSTATE_INACTIVE) {
+               spin_unlock_irqrestore(&data->spinlock, flags);
+               return -EBUSY;
+       }
+
+       /* Convert values to multiples of 10us */
+       for (i = 0; i < count; i++)
+               buf[i] = DIV_ROUND_CLOSEST(buf[i], 10);
+
+       /* Fill the TX fifo once, the irq handler will do the rest */
+       data->txbuf = buf;
+       data->txlen = count;
+       data->txoff = 0;
+       wbcir_irq_tx(data);
+
+       /* Wait for the TX to complete */
+       while (data->txstate == WBCIR_TXSTATE_ACTIVE) {
+               spin_unlock_irqrestore(&data->spinlock, flags);
+               wait_event(data->txwaitq, data->txstate != WBCIR_TXSTATE_ACTIVE);
+               spin_lock_irqsave(&data->spinlock, flags);
+       }
+
+       /* We're done */
+       if (data->txstate == WBCIR_TXSTATE_ERROR)
+               count = -EAGAIN;
+       data->txstate = WBCIR_TXSTATE_INACTIVE;
+       data->txbuf = NULL;
+       spin_unlock_irqrestore(&data->spinlock, flags);
+
+       return count;
+}
 
 /*****************************************************************************
  *
@@ -382,7 +632,7 @@ wbcir_shutdown(struct pnp_dev *device)
 {
        struct device *dev = &device->dev;
        struct wbcir_data *data = pnp_get_drvdata(device);
-       int do_wake = 1;
+       bool do_wake = true;
        u8 match[11];
        u8 mask[11];
        u8 rc6_csl = 0;
@@ -392,14 +642,14 @@ wbcir_shutdown(struct pnp_dev *device)
        memset(mask, 0, sizeof(mask));
 
        if (wake_sc == INVALID_SCANCODE || !device_may_wakeup(dev)) {
-               do_wake = 0;
+               do_wake = false;
                goto finish;
        }
 
        switch (protocol) {
        case IR_PROTOCOL_RC5:
                if (wake_sc > 0xFFF) {
-                       do_wake = 0;
+                       do_wake = false;
                        dev_err(dev, "RC5 - Invalid wake scancode\n");
                        break;
                }
@@ -418,7 +668,7 @@ wbcir_shutdown(struct pnp_dev *device)
 
        case IR_PROTOCOL_NEC:
                if (wake_sc > 0xFFFFFF) {
-                       do_wake = 0;
+                       do_wake = false;
                        dev_err(dev, "NEC - Invalid wake scancode\n");
                        break;
                }
@@ -440,7 +690,7 @@ wbcir_shutdown(struct pnp_dev *device)
 
                if (wake_rc6mode == 0) {
                        if (wake_sc > 0xFFFF) {
-                               do_wake = 0;
+                               do_wake = false;
                                dev_err(dev, "RC6 - Invalid wake scancode\n");
                                break;
                        }
@@ -496,7 +746,7 @@ wbcir_shutdown(struct pnp_dev *device)
                        } else if (wake_sc <= 0x007FFFFF) {
                                rc6_csl = 60;
                        } else {
-                               do_wake = 0;
+                               do_wake = false;
                                dev_err(dev, "RC6 - Invalid wake scancode\n");
                                break;
                        }
@@ -508,14 +758,14 @@ wbcir_shutdown(struct pnp_dev *device)
                        mask[i++] = 0x0F;
 
                } else {
-                       do_wake = 0;
+                       do_wake = false;
                        dev_err(dev, "RC6 - Invalid wake mode\n");
                }
 
                break;
 
        default:
-               do_wake = 0;
+               do_wake = false;
                break;
        }
 
@@ -551,21 +801,18 @@ finish:
                wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x00, 0x01);
        }
 
-       /* Disable interrupts */
-       wbcir_select_bank(data, WBCIR_BANK_0);
-       outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
-
-       /* Disable LED */
-       data->irdata_active = false;
-       led_trigger_event(data->rxtrigger, LED_OFF);
-
        /*
         * ACPI will set the HW disable bit for SP3 which means that the
         * output signals are left in an undefined state which may cause
         * spurious interrupts which we need to ignore until the hardware
         * is reinitialized.
         */
+       wbcir_set_irqmask(data, WBCIR_IRQ_NONE);
        disable_irq(data->irq);
+
+       /* Disable LED */
+       led_trigger_event(data->rxtrigger, LED_OFF);
+       led_trigger_event(data->txtrigger, LED_OFF);
 }
 
 static int
@@ -581,8 +828,7 @@ wbcir_init_hw(struct wbcir_data *data)
        u8 tmp;
 
        /* Disable interrupts */
-       wbcir_select_bank(data, WBCIR_BANK_0);
-       outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
+       wbcir_set_irqmask(data, WBCIR_IRQ_NONE);
 
        /* Set PROT_SEL, RX_INV, Clear CEIR_EN (needed for the led) */
        tmp = protocol << 4;
@@ -606,10 +852,11 @@ wbcir_init_hw(struct wbcir_data *data)
                outb(0x00, data->ebase + WBCIR_REG_ECEIR_CCTL);
 
        /*
-        * Clear IR LED, set SP3 clock to 24Mhz
+        * Clear IR LED, set SP3 clock to 24Mhz, set TX mask to IRTX1,
         * set SP3_IRRX_SW to binary 01, helpfully not documented
         */
        outb(0x10, data->ebase + WBCIR_REG_ECEIR_CTS);
+       data->txmask = 0x1;
 
        /* Enable extended mode */
        wbcir_select_bank(data, WBCIR_BANK_2);
@@ -657,18 +904,21 @@ wbcir_init_hw(struct wbcir_data *data)
        wbcir_select_bank(data, WBCIR_BANK_4);
        outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR1);
 
-       /* Enable MSR interrupt, Clear AUX_IRX */
+       /* Disable MSR interrupt, clear AUX_IRX, mask RX during TX? */
        wbcir_select_bank(data, WBCIR_BANK_5);
-       outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR2);
+       outb(txandrx ? 0x03 : 0x02, data->sbase + WBCIR_REG_SP3_IRCR2);
 
        /* Disable CRC */
        wbcir_select_bank(data, WBCIR_BANK_6);
        outb(0x20, data->sbase + WBCIR_REG_SP3_IRCR3);
 
-       /* Set RX/TX (de)modulation freq, not really used */
+       /* Set RX demodulation freq, not really used */
        wbcir_select_bank(data, WBCIR_BANK_7);
        outb(0xF2, data->sbase + WBCIR_REG_SP3_IRRXDC);
+
+       /* Set TX modulation, 36kHz, 7us pulse width */
        outb(0x69, data->sbase + WBCIR_REG_SP3_IRTXMC);
+       data->txcarrier = 36000;
 
        /* Set invert and pin direction */
        if (invert)
@@ -683,16 +933,23 @@ wbcir_init_hw(struct wbcir_data *data)
        /* Clear AUX status bits */
        outb(0xE0, data->sbase + WBCIR_REG_SP3_ASCR);
 
-       /* Clear IR decoding state */
-       data->irdata_active = false;
-       led_trigger_event(data->rxtrigger, LED_OFF);
-       data->irdata_error = false;
-       data->ev.duration = 0;
+       /* Clear RX state */
+       data->rxstate = WBCIR_RXSTATE_INACTIVE;
+       data->rxev.duration = 0;
        ir_raw_event_reset(data->dev);
        ir_raw_event_handle(data->dev);
 
+       /*
+        * Check TX state, if we did a suspend/resume cycle while TX was
+        * active, we will have a process waiting in txwaitq.
+        */
+       if (data->txstate == WBCIR_TXSTATE_ACTIVE) {
+               data->txstate = WBCIR_TXSTATE_ERROR;
+               wake_up(&data->txwaitq);
+       }
+
        /* Enable interrupts */
-       outb(WBCIR_IRQ_RX | WBCIR_IRQ_ERR, data->sbase + WBCIR_REG_SP3_IER);
+       wbcir_set_irqmask(data, WBCIR_IRQ_RX | WBCIR_IRQ_ERR);
 }
 
 static int
@@ -729,6 +986,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
        pnp_set_drvdata(device, data);
 
        spin_lock_init(&data->spinlock);
+       init_waitqueue_head(&data->txwaitq);
        data->ebase = pnp_port_start(device, 0);
        data->wbase = pnp_port_start(device, 1);
        data->sbase = pnp_port_start(device, 2);
@@ -807,6 +1065,11 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
        data->dev->input_id.vendor = PCI_VENDOR_ID_WINBOND;
        data->dev->input_id.product = WBCIR_ID_FAMILY;
        data->dev->input_id.version = WBCIR_ID_CHIP;
+       data->dev->map_name = RC_MAP_RC6_MCE;
+       data->dev->s_idle = wbcir_idle_rx;
+       data->dev->s_tx_mask = wbcir_txmask;
+       data->dev->s_tx_carrier = wbcir_txcarrier;
+       data->dev->tx_ir = wbcir_tx;
        data->dev->priv = data;
        data->dev->dev.parent = &device->dev;
 
@@ -849,9 +1112,7 @@ wbcir_remove(struct pnp_dev *device)
        struct wbcir_data *data = pnp_get_drvdata(device);
 
        /* Disable interrupts */
-       wbcir_select_bank(data, WBCIR_BANK_0);
-       outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
-
+       wbcir_set_irqmask(data, WBCIR_IRQ_NONE);
        free_irq(data->irq, device);
 
        /* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */
index 00f51dd..3be180b 100644 (file)
@@ -128,10 +128,10 @@ config VIDEO_IR_I2C
 # Encoder / Decoder module configuration
 #
 
-menu "Encoders/decoders and other helper chips"
+menu "Encoders, decoders, sensors and other helper chips"
        visible if !VIDEO_HELPER_CHIPS_AUTO
 
-comment "Audio decoders"
+comment "Audio decoders, processors and mixers"
 
 config VIDEO_TVAUDIO
        tristate "Simple audio decoder chips"
@@ -210,15 +210,6 @@ config VIDEO_CS53L32A
          To compile this driver as a module, choose M here: the
          module will be called cs53l32a.
 
-config VIDEO_M52790
-       tristate "Mitsubishi M52790 A/V switch"
-       depends on VIDEO_V4L2 && I2C
-       ---help---
-        Support for the Mitsubishi M52790 A/V switch.
-
-        To compile this driver as a module, choose M here: the
-        module will be called m52790.
-
 config VIDEO_TLV320AIC23B
        tristate "Texas Instruments TLV320AIC23B audio codec"
        depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
@@ -321,29 +312,6 @@ config VIDEO_KS0127
          To compile this driver as a module, choose M here: the
          module will be called ks0127.
 
-config VIDEO_OV7670
-       tristate "OmniVision OV7670 sensor support"
-       depends on I2C && VIDEO_V4L2
-       ---help---
-         This is a Video4Linux2 sensor-level driver for the OmniVision
-         OV7670 VGA camera.  It currently only works with the M88ALP01
-         controller.
-
-config VIDEO_MT9V011
-       tristate "Micron mt9v011 sensor support"
-       depends on I2C && VIDEO_V4L2
-       ---help---
-         This is a Video4Linux2 sensor-level driver for the Micron
-         mt0v011 1.3 Mpixel camera.  It currently only works with the
-         em28xx driver.
-
-config VIDEO_TCM825X
-       tristate "TCM825x camera sensor support"
-       depends on I2C && VIDEO_V4L2
-       ---help---
-         This is a driver for the Toshiba TCM825x VGA camera sensor.
-         It is used for example in Nokia N800.
-
 config VIDEO_SAA7110
        tristate "Philips SAA7110 video decoder"
        depends on VIDEO_V4L2 && I2C
@@ -362,15 +330,6 @@ config VIDEO_SAA711X
          To compile this driver as a module, choose M here: the
          module will be called saa7115.
 
-config VIDEO_SAA717X
-       tristate "Philips SAA7171/3/4 audio/video decoders"
-       depends on VIDEO_V4L2 && I2C
-       ---help---
-         Support for the Philips SAA7171/3/4 audio/video decoders.
-
-         To compile this driver as a module, choose M here: the
-         module will be called saa717x.
-
 config VIDEO_SAA7191
        tristate "Philips SAA7191 video decoder"
        depends on VIDEO_V4L2 && I2C
@@ -420,6 +379,15 @@ config VIDEO_VPX3220
 
 comment "Video and audio decoders"
 
+config VIDEO_SAA717X
+       tristate "Philips SAA7171/3/4 audio/video decoders"
+       depends on VIDEO_V4L2 && I2C
+       ---help---
+         Support for the Philips SAA7171/3/4 audio/video decoders.
+
+         To compile this driver as a module, choose M here: the
+         module will be called saa717x.
+
 source "drivers/media/video/cx25840/Kconfig"
 
 comment "MPEG video encoders"
@@ -474,15 +442,6 @@ config VIDEO_ADV7175
          To compile this driver as a module, choose M here: the
          module will be called adv7175.
 
-config VIDEO_THS7303
-       tristate "THS7303 Video Amplifier"
-       depends on I2C
-       help
-         Support for TI THS7303 video amplifier
-
-         To compile this driver as a module, choose M here: the
-         module will be called ths7303.
-
 config VIDEO_ADV7343
        tristate "ADV7343 video encoder"
        depends on I2C
@@ -498,6 +457,38 @@ config VIDEO_AK881X
        help
          Video output driver for AKM AK8813 and AK8814 TV encoders
 
+comment "Camera sensor devices"
+
+config VIDEO_OV7670
+       tristate "OmniVision OV7670 sensor support"
+       depends on I2C && VIDEO_V4L2
+       ---help---
+         This is a Video4Linux2 sensor-level driver for the OmniVision
+         OV7670 VGA camera.  It currently only works with the M88ALP01
+         controller.
+
+config VIDEO_MT9V011
+       tristate "Micron mt9v011 sensor support"
+       depends on I2C && VIDEO_V4L2
+       ---help---
+         This is a Video4Linux2 sensor-level driver for the Micron
+         mt0v011 1.3 Mpixel camera.  It currently only works with the
+         em28xx driver.
+
+config VIDEO_MT9V032
+       tristate "Micron MT9V032 sensor support"
+       depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+       ---help---
+         This is a Video4Linux2 sensor-level driver for the Micron
+         MT9V032 752x480 CMOS sensor.
+
+config VIDEO_TCM825X
+       tristate "TCM825x camera sensor support"
+       depends on I2C && VIDEO_V4L2
+       ---help---
+         This is a driver for the Toshiba TCM825x VGA camera sensor.
+         It is used for example in Nokia N800.
+
 comment "Video improvement chips"
 
 config VIDEO_UPD64031A
@@ -523,6 +514,26 @@ config VIDEO_UPD64083
          To compile this driver as a module, choose M here: the
          module will be called upd64083.
 
+comment "Miscelaneous helper chips"
+
+config VIDEO_THS7303
+       tristate "THS7303 Video Amplifier"
+       depends on I2C
+       help
+         Support for TI THS7303 video amplifier
+
+         To compile this driver as a module, choose M here: the
+         module will be called ths7303.
+
+config VIDEO_M52790
+       tristate "Mitsubishi M52790 A/V switch"
+       depends on VIDEO_V4L2 && I2C
+       ---help---
+        Support for the Mitsubishi M52790 A/V switch.
+
+        To compile this driver as a module, choose M here: the
+        module will be called m52790.
+
 endmenu # encoder / decoder chips
 
 config VIDEO_SH_VOU
@@ -682,7 +693,7 @@ config VIDEO_TIMBERDALE
        select VIDEO_ADV7180
        select VIDEOBUF_DMA_CONTIG
        ---help---
-       Add support for the Video In peripherial of the timberdale FPGA.
+         Add support for the Video In peripherial of the timberdale FPGA.
 
 source "drivers/media/video/cx88/Kconfig"
 
@@ -916,7 +927,7 @@ config VIDEO_OMAP2
          This is a v4l2 driver for the TI OMAP2 camera capture interface
 
 config VIDEO_MX2_HOSTSUPPORT
-        bool
+       bool
 
 config VIDEO_MX2
        tristate "i.MX27/i.MX25 Camera Sensor Interface driver"
@@ -927,6 +938,26 @@ config VIDEO_MX2
          This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor
          Interface
 
+config  VIDEO_SAMSUNG_S5P_FIMC
+       tristate "Samsung S5P and EXYNOS4 camera host interface driver"
+       depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P
+       select VIDEOBUF2_DMA_CONTIG
+       select V4L2_MEM2MEM_DEV
+       ---help---
+         This is a v4l2 driver for Samsung S5P and EXYNOS4 camera
+         host interface and video postprocessor.
+
+         To compile this driver as a module, choose M here: the
+         module will be called s5p-fimc.
+
+config VIDEO_S5P_MIPI_CSIS
+       tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver"
+       depends on VIDEO_V4L2 && PM_RUNTIME && VIDEO_V4L2_SUBDEV_API
+       ---help---
+         This is a v4l2 driver for Samsung S5P/EXYNOS4 MIPI-CSI receiver.
+
+         To compile this driver as a module, choose M here: the
+         module will be called s5p-csis.
 
 #
 # USB Multimedia device configuration
@@ -983,7 +1014,7 @@ config USB_STKWEBCAM
          Supported devices are typically found in some Asus laptops,
          with USB id 174f:a311 and 05e1:0501. Other Syntek cameras
          may be supported by the stk11xx driver, from which this is
-         derived, see <http://sourceforge.net/projects/syntekdriver/> 
+         derived, see <http://sourceforge.net/projects/syntekdriver/>
 
          To compile this driver as a module, choose M here: the
          module will be called stkwebcam.
@@ -1022,13 +1053,5 @@ config VIDEO_MEM2MEM_TESTDEV
          This is a virtual test device for the memory-to-memory driver
          framework.
 
-config  VIDEO_SAMSUNG_S5P_FIMC
-       tristate "Samsung S5P FIMC (video postprocessor) driver"
-       depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P
-       select VIDEOBUF2_DMA_CONTIG
-       select V4L2_MEM2MEM_DEV
-       help
-         This is a v4l2 driver for the S5P camera interface
-         (video postprocessor)
 
 endif # V4L_MEM2MEM_DRIVERS
index ace5d8b..9519160 100644 (file)
@@ -66,6 +66,7 @@ obj-$(CONFIG_VIDEO_OV7670)    += ov7670.o
 obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
 obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
 obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
+obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
 obj-$(CONFIG_VIDEO_SR030PC30)  += sr030pc30.o
 obj-$(CONFIG_VIDEO_NOON010PC30)        += noon010pc30.o
 
@@ -164,6 +165,7 @@ obj-$(CONFIG_VIDEO_PXA27x)          += pxa_camera.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2)     += sh_mobile_csi2.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)      += sh_mobile_ceu_camera.o
 obj-$(CONFIG_VIDEO_OMAP1)              += omap1_camera.o
+
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC)   += s5p-fimc/
 
 obj-$(CONFIG_ARCH_DAVINCI)             += davinci/
index 91399c9..a97cf27 100644 (file)
@@ -4303,7 +4303,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
                goto fail0;
        }
 
-       pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
+       btv->revision = dev->revision;
        pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
        printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
               bttv_num,btv->id, btv->revision, pci_name(dev));
index 5111bbc..0073a8c 100644 (file)
@@ -1313,7 +1313,7 @@ static int cpia2_g_priority(struct file *file, void *_fh, enum v4l2_priority *p)
 static int cpia2_s_priority(struct file *file, void *_fh, enum v4l2_priority prio)
 {
        struct camera_data *cam = video_drvdata(file);
-       struct cpia2_fh *fh = fh;
+       struct cpia2_fh *fh = _fh;
 
        if (cam->streaming && prio != fh->prio &&
                        fh->prio == V4L2_PRIORITY_RECORD)
index d9d2f6a..53b3c77 100644 (file)
@@ -2,6 +2,7 @@ config VIDEO_CX18
        tristate "Conexant cx23418 MPEG encoder support"
        depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL
        select I2C_ALGOBIT
+       select VIDEOBUF_VMALLOC
        depends on RC_CORE
        select VIDEO_TUNER
        select VIDEO_TVEEPROM
@@ -9,6 +10,9 @@ config VIDEO_CX18
        select VIDEO_CS5345
        select DVB_S5H1409 if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+       select DVB_S5H1411 if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
        ---help---
          This is a video4linux driver for Conexant cx23418 based
          PCI combo video recorder devices.
index 68ad196..c07c849 100644 (file)
@@ -39,6 +39,16 @@ static struct cx18_card_tuner_i2c cx18_i2c_std = {
        .tv    = { 0x61, 0x60, I2C_CLIENT_END },
 };
 
+/*
+ * usual i2c tuner addresses to probe with additional demod address for
+ * an NXP TDA8295 at 0x42 (N.B. it can possibly be at 0x4b or 0x4c too).
+ */
+static struct cx18_card_tuner_i2c cx18_i2c_nxp = {
+       .radio = { I2C_CLIENT_END },
+       .demod = { 0x42, 0x43, I2C_CLIENT_END },
+       .tv    = { 0x61, 0x60, I2C_CLIENT_END },
+};
+
 /* Please add new PCI IDs to: http://pci-ids.ucw.cz/
    This keeps the PCI ID database up to date. Note that the entries
    must be added under vendor 0x4444 (Conexant) as subsystem IDs.
@@ -131,15 +141,15 @@ static const struct cx18_card cx18_card_hvr1600_s5h1411 = {
                .tune_lane = 0,
                .initial_emrs = 0,
        },
-       .gpio_init.initial_value = 0x3001,
-       .gpio_init.direction = 0x3001,
+       .gpio_init.initial_value = 0x3801,
+       .gpio_init.direction = 0x3801,
        .gpio_i2c_slave_reset = {
-               .active_lo_mask = 0x3001,
+               .active_lo_mask = 0x3801,
                .msecs_asserted = 10,
                .msecs_recovery = 40,
                .ir_reset_mask  = 0x0001,
        },
-       .i2c = &cx18_i2c_std,
+       .i2c = &cx18_i2c_nxp,
 };
 
 static const struct cx18_card cx18_card_hvr1600_samsung = {
index 3e75006..add7391 100644 (file)
@@ -109,7 +109,7 @@ struct cx18_card_tuner {
 
 struct cx18_card_tuner_i2c {
        unsigned short radio[2];/* radio tuner i2c address to probe */
-       unsigned short demod[2];/* demodulator i2c address to probe */
+       unsigned short demod[3];/* demodulator i2c address to probe */
        unsigned short tv[4];   /* tv tuner i2c addresses to probe */
 };
 
index 321c1b7..9e2f870 100644 (file)
@@ -423,7 +423,16 @@ static void cx18_process_eeprom(struct cx18 *cx)
                return;
 
        /* autodetect tuner standard */
-       if (tv.tuner_formats & V4L2_STD_PAL) {
+#define TVEEPROM_TUNER_FORMAT_ALL (V4L2_STD_B  | V4L2_STD_GH | \
+                                  V4L2_STD_MN | \
+                                  V4L2_STD_PAL_I | \
+                                  V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC | \
+                                  V4L2_STD_DK)
+       if ((tv.tuner_formats & TVEEPROM_TUNER_FORMAT_ALL)
+                                       == TVEEPROM_TUNER_FORMAT_ALL) {
+               CX18_DEBUG_INFO("Worldwide tuner detected\n");
+               cx->std = V4L2_STD_ALL;
+       } else if (tv.tuner_formats & V4L2_STD_PAL) {
                CX18_DEBUG_INFO("PAL tuner detected\n");
                cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
        } else if (tv.tuner_formats & V4L2_STD_NTSC) {
@@ -818,7 +827,7 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev,
        cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
        pci_write_config_word(pci_dev, PCI_COMMAND, cmd);
 
-       pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &cx->card_rev);
+       cx->card_rev = pci_dev->revision;
        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency);
 
        if (pci_latency < 64 && cx18_pci_latency) {
@@ -1001,7 +1010,15 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
        if (cx->card->hw_all & CX18_HW_TVEEPROM) {
                /* Based on the model number the cardtype may be changed.
                   The PCI IDs are not always reliable. */
+               const struct cx18_card *orig_card = cx->card;
                cx18_process_eeprom(cx);
+
+               if (cx->card != orig_card) {
+                       /* Changed the cardtype; re-reset the I2C chips */
+                       cx18_gpio_init(cx);
+                       cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL,
+                                       core, reset, (u32) CX18_GPIO_RESET_I2C);
+               }
        }
        if (cx->card->comment)
                CX18_INFO("%s", cx->card->comment);
@@ -1087,6 +1104,8 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
        /* The tuner is fixed to the standard. The other inputs (e.g. S-Video)
           are not. */
        cx->tuner_std = cx->std;
+       if (cx->std == V4L2_STD_ALL)
+               cx->std = V4L2_STD_NTSC_M;
 
        retval = cx18_streams_setup(cx);
        if (retval) {
@@ -1133,6 +1152,7 @@ int cx18_init_on_first_open(struct cx18 *cx)
        int fw_retry_count = 3;
        struct v4l2_frequency vf;
        struct cx18_open_id fh;
+       v4l2_std_id std;
 
        fh.cx = cx;
 
@@ -1220,7 +1240,8 @@ int cx18_init_on_first_open(struct cx18 *cx)
        /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
           in one place. */
        cx->std++;              /* Force full standard initialization */
-       cx18_s_std(NULL, &fh, &cx->tuner_std);
+       std = (cx->tuner_std == V4L2_STD_ALL) ? V4L2_STD_NTSC_M : cx->tuner_std;
+       cx18_s_std(NULL, &fh, &std);
        cx18_s_frequency(NULL, &fh, &vf);
        return 0;
 }
index b86a740..0864272 100644 (file)
 #include "dvb_net.h"
 #include "dvbdev.h"
 
+/* Videobuf / YUV support */
+#include <media/videobuf-core.h>
+#include <media/videobuf-vmalloc.h>
+
 #ifndef CONFIG_PCI
 #  error "This driver requires kernel PCI support."
 #endif
@@ -403,6 +407,23 @@ struct cx18_stream {
        struct cx18_queue q_idle;       /* idle - not in rotation */
 
        struct work_struct out_work_order;
+
+       /* Videobuf for YUV video */
+       u32 pixelformat;
+       struct list_head vb_capture;    /* video capture queue */
+       spinlock_t vb_lock;
+       struct timer_list vb_timeout;
+
+       struct videobuf_queue vbuf_q;
+       spinlock_t vbuf_q_lock; /* Protect vbuf_q */
+       enum v4l2_buf_type vb_type;
+};
+
+struct cx18_videobuf_buffer {
+       /* Common video buffer sub-system struct */
+       struct videobuf_buffer vb;
+       v4l2_std_id tvnorm; /* selected tv norm */
+       u32 bytes_used;
 };
 
 struct cx18_open_id {
@@ -410,6 +431,10 @@ struct cx18_open_id {
        u32 open_id;
        int type;
        struct cx18 *cx;
+
+       struct videobuf_queue vbuf_q;
+       spinlock_t s_lock; /* Protect vbuf_q */
+       enum v4l2_buf_type vb_type;
 };
 
 static inline struct cx18_open_id *fh2id(struct v4l2_fh *fh)
index e9802d9..07411f3 100644 (file)
@@ -597,6 +597,13 @@ ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count,
        mutex_unlock(&cx->serialize_lock);
        if (rc)
                return rc;
+
+       if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+               (id->type == CX18_ENC_STREAM_TYPE_YUV)) {
+               return videobuf_read_stream(&s->vbuf_q, buf, count, pos, 0,
+                       filp->f_flags & O_NONBLOCK);
+       }
+
        return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
 }
 
@@ -622,6 +629,15 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
                CX18_DEBUG_FILE("Encoder poll started capture\n");
        }
 
+       if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+               (id->type == CX18_ENC_STREAM_TYPE_YUV)) {
+               int videobuf_poll = videobuf_poll_stream(filp, &s->vbuf_q, wait);
+                if (eof && videobuf_poll == POLLERR)
+                        return POLLHUP;
+                else
+                        return videobuf_poll;
+       }
+
        /* add stream's waitq to the poll list */
        CX18_DEBUG_HI_FILE("Encoder poll\n");
        poll_wait(filp, &s->waitq, wait);
@@ -633,6 +649,58 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
        return 0;
 }
 
+int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct cx18_open_id *id = file->private_data;
+       struct cx18 *cx = id->cx;
+       struct cx18_stream *s = &cx->streams[id->type];
+       int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags);
+
+       if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+               (id->type == CX18_ENC_STREAM_TYPE_YUV)) {
+
+               /* Start a capture if there is none */
+               if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+                       int rc;
+
+                       mutex_lock(&cx->serialize_lock);
+                       rc = cx18_start_capture(id);
+                       mutex_unlock(&cx->serialize_lock);
+                       if (rc) {
+                               CX18_DEBUG_INFO(
+                                       "Could not start capture for %s (%d)\n",
+                                       s->name, rc);
+                               return -EINVAL;
+                       }
+                       CX18_DEBUG_FILE("Encoder mmap started capture\n");
+               }
+
+               return videobuf_mmap_mapper(&s->vbuf_q, vma);
+       }
+
+       return -EINVAL;
+}
+
+void cx18_vb_timeout(unsigned long data)
+{
+       struct cx18_stream *s = (struct cx18_stream *)data;
+       struct cx18_videobuf_buffer *buf;
+       unsigned long flags;
+
+       /* Return all of the buffers in error state, so the vbi/vid inode
+        * can return from blocking.
+        */
+       spin_lock_irqsave(&s->vb_lock, flags);
+       while (!list_empty(&s->vb_capture)) {
+               buf = list_entry(s->vb_capture.next,
+                       struct cx18_videobuf_buffer, vb.queue);
+               list_del(&buf->vb.queue);
+               buf->vb.state = VIDEOBUF_ERROR;
+               wake_up(&buf->vb.done);
+       }
+       spin_unlock_irqrestore(&s->vb_lock, flags);
+}
+
 void cx18_stop_capture(struct cx18_open_id *id, int gop_end)
 {
        struct cx18 *cx = id->cx;
@@ -716,6 +784,8 @@ int cx18_v4l2_close(struct file *filp)
                cx18_release_stream(s);
        } else {
                cx18_stop_capture(id, 0);
+               if (id->type == CX18_ENC_STREAM_TYPE_YUV)
+                       videobuf_mmap_free(&id->vbuf_q);
        }
        kfree(id);
        mutex_unlock(&cx->serialize_lock);
index 5c8fcb8..b9e5110 100644 (file)
@@ -33,6 +33,8 @@ int cx18_start_capture(struct cx18_open_id *id);
 void cx18_stop_capture(struct cx18_open_id *id, int gop_end);
 void cx18_mute(struct cx18 *cx);
 void cx18_unmute(struct cx18 *cx);
+int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma);
+void cx18_vb_timeout(unsigned long data);
 
 /* Shared with cx18-alsa module */
 int cx18_claim_stream(struct cx18_open_id *id, int type);
index 4f041c0..1933d4d 100644 (file)
@@ -150,6 +150,7 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
 {
        struct cx18_open_id *id = fh2id(fh);
        struct cx18 *cx = id->cx;
+       struct cx18_stream *s = &cx->streams[id->type];
        struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
 
        pixfmt->width = cx->cxhdl.width;
@@ -158,9 +159,13 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
        pixfmt->field = V4L2_FIELD_INTERLACED;
        pixfmt->priv = 0;
        if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
-               pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
-               /* YUV size is (Y=(h*720) + UV=(h*(720/2))) */
-               pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2;
+               pixfmt->pixelformat = s->pixelformat;
+               /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
+                  UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */
+               if (s->pixelformat == V4L2_PIX_FMT_HM12)
+                       pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2;
+               else
+                       pixfmt->sizeimage = pixfmt->height * 720 * 2;
                pixfmt->bytesperline = 720;
        } else {
                pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
@@ -237,7 +242,6 @@ static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
        h = min(h, cx->is_50hz ? 576 : 480);
        h = max(h, min_h);
 
-       cx18_g_fmt_vid_cap(file, fh, fmt);
        fmt->fmt.pix.width = w;
        fmt->fmt.pix.height = h;
        return 0;
@@ -274,6 +278,7 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
        struct cx18_open_id *id = fh2id(fh);
        struct cx18 *cx = id->cx;
        struct v4l2_mbus_framefmt mbus_fmt;
+       struct cx18_stream *s = &cx->streams[id->type];
        int ret;
        int w, h;
 
@@ -283,12 +288,15 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
        w = fmt->fmt.pix.width;
        h = fmt->fmt.pix.height;
 
-       if (cx->cxhdl.width == w && cx->cxhdl.height == h)
+       if (cx->cxhdl.width == w && cx->cxhdl.height == h &&
+           s->pixelformat == fmt->fmt.pix.pixelformat)
                return 0;
 
        if (atomic_read(&cx->ana_capturing) > 0)
                return -EBUSY;
 
+       s->pixelformat = fmt->fmt.pix.pixelformat;
+
        mbus_fmt.width = cx->cxhdl.width = w;
        mbus_fmt.height = cx->cxhdl.height = h;
        mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
@@ -540,16 +548,19 @@ static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
 static int cx18_enum_fmt_vid_cap(struct file *file, void *fh,
                                        struct v4l2_fmtdesc *fmt)
 {
-       static struct v4l2_fmtdesc formats[] = {
+       static const struct v4l2_fmtdesc formats[] = {
                { 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
                  "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 }
                },
                { 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED,
                  "MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 }
-               }
+               },
+               { 2, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
+                 "UYVY 4:2:2", V4L2_PIX_FMT_UYVY, { 0, 0, 0, 0 }
+               },
        };
 
-       if (fmt->index > 1)
+       if (fmt->index > ARRAY_SIZE(formats) - 1)
                return -EINVAL;
        *fmt = formats[fmt->index];
        return 0;
@@ -863,6 +874,117 @@ static int cx18_g_enc_index(struct file *file, void *fh,
        return 0;
 }
 
+static struct videobuf_queue *cx18_vb_queue(struct cx18_open_id *id)
+{
+       struct videobuf_queue *q = NULL;
+       struct cx18 *cx = id->cx;
+       struct cx18_stream *s = &cx->streams[id->type];
+
+       switch (s->vb_type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               q = &s->vbuf_q;
+               break;
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               break;
+       default:
+               break;
+       }
+       return q;
+}
+
+static int cx18_streamon(struct file *file, void *priv,
+       enum v4l2_buf_type type)
+{
+       struct cx18_open_id *id = file->private_data;
+       struct cx18 *cx = id->cx;
+       struct cx18_stream *s = &cx->streams[id->type];
+
+       /* Start the hardware only if we're the video device */
+       if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+               (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+               return -EINVAL;
+
+       if (id->type != CX18_ENC_STREAM_TYPE_YUV)
+               return -EINVAL;
+
+       /* Establish a buffer timeout */
+       mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies);
+
+       return videobuf_streamon(cx18_vb_queue(id));
+}
+
+static int cx18_streamoff(struct file *file, void *priv,
+       enum v4l2_buf_type type)
+{
+       struct cx18_open_id *id = file->private_data;
+       struct cx18 *cx = id->cx;
+       struct cx18_stream *s = &cx->streams[id->type];
+
+       /* Start the hardware only if we're the video device */
+       if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+               (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+               return -EINVAL;
+
+       if (id->type != CX18_ENC_STREAM_TYPE_YUV)
+               return -EINVAL;
+
+       return videobuf_streamoff(cx18_vb_queue(id));
+}
+
+static int cx18_reqbufs(struct file *file, void *priv,
+       struct v4l2_requestbuffers *rb)
+{
+       struct cx18_open_id *id = file->private_data;
+       struct cx18 *cx = id->cx;
+       struct cx18_stream *s = &cx->streams[id->type];
+
+       if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+               (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+               return -EINVAL;
+
+       return videobuf_reqbufs(cx18_vb_queue(id), rb);
+}
+
+static int cx18_querybuf(struct file *file, void *priv,
+       struct v4l2_buffer *b)
+{
+       struct cx18_open_id *id = file->private_data;
+       struct cx18 *cx = id->cx;
+       struct cx18_stream *s = &cx->streams[id->type];
+
+       if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+               (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+               return -EINVAL;
+
+       return videobuf_querybuf(cx18_vb_queue(id), b);
+}
+
+static int cx18_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+       struct cx18_open_id *id = file->private_data;
+       struct cx18 *cx = id->cx;
+       struct cx18_stream *s = &cx->streams[id->type];
+
+       if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+               (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+               return -EINVAL;
+
+       return videobuf_qbuf(cx18_vb_queue(id), b);
+}
+
+static int cx18_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+       struct cx18_open_id *id = file->private_data;
+       struct cx18 *cx = id->cx;
+       struct cx18_stream *s = &cx->streams[id->type];
+
+       if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+               (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+               return -EINVAL;
+
+       return videobuf_dqbuf(cx18_vb_queue(id), b, file->f_flags & O_NONBLOCK);
+}
+
 static int cx18_encoder_cmd(struct file *file, void *fh,
                                struct v4l2_encoder_cmd *enc)
 {
@@ -1081,6 +1203,12 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = {
        .vidioc_s_register              = cx18_s_register,
 #endif
        .vidioc_default                 = cx18_default,
+       .vidioc_streamon                = cx18_streamon,
+       .vidioc_streamoff               = cx18_streamoff,
+       .vidioc_reqbufs                 = cx18_reqbufs,
+       .vidioc_querybuf                = cx18_querybuf,
+       .vidioc_qbuf                    = cx18_qbuf,
+       .vidioc_dqbuf                   = cx18_dqbuf,
 };
 
 void cx18_set_funcs(struct video_device *vdev)
index 9605d54..c07191e 100644 (file)
@@ -81,6 +81,7 @@ static const struct cx18_api_info api_info[] = {
        API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM,           0),
        API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER,      0),
        API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS,                    0),
+       API_ENTRY(CPU, CX18_CPU_SET_VFC_PARAM,                  0),
        API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK,                 0),
        API_ENTRY(CPU, CX18_CPU_DE_SET_MDL,                     API_FAST),
        API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL,                 API_SLOW),
@@ -158,6 +159,60 @@ static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl)
        }
 }
 
+static void cx18_mdl_send_to_videobuf(struct cx18_stream *s,
+       struct cx18_mdl *mdl)
+{
+       struct cx18_videobuf_buffer *vb_buf;
+       struct cx18_buffer *buf;
+       u8 *p;
+       u32 offset = 0;
+       int dispatch = 0;
+
+       if (mdl->bytesused == 0)
+               return;
+
+       /* Acquire a videobuf buffer, clone to and and release it */
+       spin_lock(&s->vb_lock);
+       if (list_empty(&s->vb_capture))
+               goto out;
+
+       vb_buf = list_first_entry(&s->vb_capture, struct cx18_videobuf_buffer,
+               vb.queue);
+
+       p = videobuf_to_vmalloc(&vb_buf->vb);
+       if (!p)
+               goto out;
+
+       offset = vb_buf->bytes_used;
+       list_for_each_entry(buf, &mdl->buf_list, list) {
+               if (buf->bytesused == 0)
+                       break;
+
+               if ((offset + buf->bytesused) <= vb_buf->vb.bsize) {
+                       memcpy(p + offset, buf->buf, buf->bytesused);
+                       offset += buf->bytesused;
+                       vb_buf->bytes_used += buf->bytesused;
+               }
+       }
+
+       /* If we've filled the buffer as per the callers res then dispatch it */
+       if (vb_buf->bytes_used >= (vb_buf->vb.width * vb_buf->vb.height * 2)) {
+               dispatch = 1;
+               vb_buf->bytes_used = 0;
+       }
+
+       if (dispatch) {
+               vb_buf->vb.ts = ktime_to_timeval(ktime_get());
+               list_del(&vb_buf->vb.queue);
+               vb_buf->vb.state = VIDEOBUF_DONE;
+               wake_up(&vb_buf->vb.done);
+       }
+
+       mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies);
+
+out:
+       spin_unlock(&s->vb_lock);
+}
 
 static void cx18_mdl_send_to_alsa(struct cx18 *cx, struct cx18_stream *s,
                                  struct cx18_mdl *mdl)
@@ -263,6 +318,9 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order)
                        } else {
                                cx18_enqueue(s, mdl, &s->q_full);
                        }
+               } else if (s->type == CX18_ENC_STREAM_TYPE_YUV) {
+                       cx18_mdl_send_to_videobuf(s, mdl);
+                       cx18_enqueue(s, mdl, &s->q_free);
                } else {
                        cx18_enqueue(s, mdl, &s->q_full);
                        if (s->type == CX18_ENC_STREAM_TYPE_IDX)
index 6fbc356..852f420 100644 (file)
@@ -44,6 +44,7 @@ static struct v4l2_file_operations cx18_v4l2_enc_fops = {
        .unlocked_ioctl = cx18_v4l2_ioctl,
        .release = cx18_v4l2_close,
        .poll = cx18_v4l2_enc_poll,
+       .mmap = cx18_v4l2_mmap,
 };
 
 /* offset from 0 to register ts v4l2 minors on */
@@ -97,6 +98,141 @@ static struct {
        },
 };
 
+
+void cx18_dma_free(struct videobuf_queue *q,
+       struct cx18_stream *s, struct cx18_videobuf_buffer *buf)
+{
+       videobuf_waiton(q, &buf->vb, 0, 0);
+       videobuf_vmalloc_free(&buf->vb);
+       buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int cx18_prepare_buffer(struct videobuf_queue *q,
+       struct cx18_stream *s,
+       struct cx18_videobuf_buffer *buf,
+       u32 pixelformat,
+       unsigned int width, unsigned int height,
+       enum v4l2_field field)
+{
+        struct cx18 *cx = s->cx;
+       int rc = 0;
+
+       /* check settings */
+       buf->bytes_used = 0;
+
+       if ((width  < 48) || (height < 32))
+               return -EINVAL;
+
+       buf->vb.size = (width * height * 2);
+       if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size))
+               return -EINVAL;
+
+       /* alloc + fill struct (if changed) */
+       if (buf->vb.width != width || buf->vb.height != height ||
+           buf->vb.field != field || s->pixelformat != pixelformat ||
+           buf->tvnorm != cx->std) {
+
+               buf->vb.width  = width;
+               buf->vb.height = height;
+               buf->vb.field  = field;
+               buf->tvnorm    = cx->std;
+               s->pixelformat = pixelformat;
+
+               cx18_dma_free(q, s, buf);
+       }
+
+       if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size))
+               return -EINVAL;
+
+       if (buf->vb.field == 0)
+               buf->vb.field = V4L2_FIELD_INTERLACED;
+
+       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+               buf->vb.width  = width;
+               buf->vb.height = height;
+               buf->vb.field  = field;
+               buf->tvnorm    = cx->std;
+               s->pixelformat = pixelformat;
+
+               rc = videobuf_iolock(q, &buf->vb, NULL);
+               if (rc != 0)
+                       goto fail;
+       }
+       buf->vb.state = VIDEOBUF_PREPARED;
+       return 0;
+
+fail:
+       cx18_dma_free(q, s, buf);
+       return rc;
+
+}
+
+/* VB_MIN_BUFSIZE is lcm(1440 * 480, 1440 * 576)
+   1440 is a single line of 4:2:2 YUV at 720 luma samples wide
+*/
+#define VB_MIN_BUFFERS 32
+#define VB_MIN_BUFSIZE 4147200
+
+static int buffer_setup(struct videobuf_queue *q,
+       unsigned int *count, unsigned int *size)
+{
+       struct cx18_stream *s = q->priv_data;
+       struct cx18 *cx = s->cx;
+
+       *size = 2 * cx->cxhdl.width * cx->cxhdl.height;
+       if (*count == 0)
+               *count = VB_MIN_BUFFERS;
+
+       while (*size * *count > VB_MIN_BUFFERS * VB_MIN_BUFSIZE)
+               (*count)--;
+
+       q->field = V4L2_FIELD_INTERLACED;
+       q->last = V4L2_FIELD_INTERLACED;
+
+       return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *q,
+       struct videobuf_buffer *vb,
+       enum v4l2_field field)
+{
+       struct cx18_videobuf_buffer *buf =
+               container_of(vb, struct cx18_videobuf_buffer, vb);
+       struct cx18_stream *s = q->priv_data;
+       struct cx18 *cx = s->cx;
+
+       return cx18_prepare_buffer(q, s, buf, s->pixelformat,
+               cx->cxhdl.width, cx->cxhdl.height, field);
+}
+
+static void buffer_release(struct videobuf_queue *q,
+       struct videobuf_buffer *vb)
+{
+       struct cx18_videobuf_buffer *buf =
+               container_of(vb, struct cx18_videobuf_buffer, vb);
+       struct cx18_stream *s = q->priv_data;
+
+       cx18_dma_free(q, s, buf);
+}
+
+static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+       struct cx18_videobuf_buffer *buf =
+               container_of(vb, struct cx18_videobuf_buffer, vb);
+       struct cx18_stream *s = q->priv_data;
+
+       buf->vb.state = VIDEOBUF_QUEUED;
+
+       list_add_tail(&buf->vb.queue, &s->vb_capture);
+}
+
+static struct videobuf_queue_ops cx18_videobuf_qops = {
+       .buf_setup    = buffer_setup,
+       .buf_prepare  = buffer_prepare,
+       .buf_queue    = buffer_queue,
+       .buf_release  = buffer_release,
+};
+
 static void cx18_stream_init(struct cx18 *cx, int type)
 {
        struct cx18_stream *s = &cx->streams[type];
@@ -132,6 +268,26 @@ static void cx18_stream_init(struct cx18 *cx, int type)
        cx18_queue_init(&s->q_idle);
 
        INIT_WORK(&s->out_work_order, cx18_out_work_handler);
+
+       INIT_LIST_HEAD(&s->vb_capture);
+       s->vb_timeout.function = cx18_vb_timeout;
+       s->vb_timeout.data = (unsigned long)s;
+       init_timer(&s->vb_timeout);
+       spin_lock_init(&s->vb_lock);
+       if (type == CX18_ENC_STREAM_TYPE_YUV) {
+               spin_lock_init(&s->vbuf_q_lock);
+
+               s->vb_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               videobuf_queue_vmalloc_init(&s->vbuf_q, &cx18_videobuf_qops,
+                       &cx->pci_dev->dev, &s->vbuf_q_lock,
+                       V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                       V4L2_FIELD_INTERLACED,
+                       sizeof(struct cx18_videobuf_buffer),
+                       s, &cx->serialize_lock);
+
+               /* Assume the previous pixel default */
+               s->pixelformat = V4L2_PIX_FMT_HM12;
+       }
 }
 
 static int cx18_prep_dev(struct cx18 *cx, int type)
@@ -372,6 +528,9 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister)
                if (vdev == NULL)
                        continue;
 
+               if (type == CX18_ENC_STREAM_TYPE_YUV)
+                       videobuf_mmap_free(&cx->streams[type].vbuf_q);
+
                cx18_stream_free(&cx->streams[type]);
 
                /* Unregister or release device */
@@ -581,7 +740,10 @@ static void cx18_stream_configure_mdls(struct cx18_stream *s)
                 * Set the MDL size to the exact size needed for one frame.
                 * Use enough buffers per MDL to cover the MDL size
                 */
-               s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2;
+               if (s->pixelformat == V4L2_PIX_FMT_HM12)
+                       s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2;
+               else
+                       s->mdl_size = 720 * s->cx->cxhdl.height * 2;
                s->bufs_per_mdl = s->mdl_size / s->buf_size;
                if (s->mdl_size % s->buf_size)
                        s->bufs_per_mdl++;
@@ -729,6 +891,19 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
                    test_bit(CX18_F_I_RADIO_USER, &cx->i_flags))
                        cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
                          (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1);
+
+               /* Enable the Video Format Converter for UYVY 4:2:2 support,
+                * rather than the default HM12 Macroblovk 4:2:0 support.
+                */
+               if (captype == CAPTURE_CHANNEL_TYPE_YUV) {
+                       if (s->pixelformat == V4L2_PIX_FMT_UYVY)
+                               cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2,
+                                       s->handle, 1);
+                       else
+                               /* If in doubt, default to HM12 */
+                               cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2,
+                                       s->handle, 0);
+               }
        }
 
        if (atomic_read(&cx->tot_capturing) == 0) {
index 3e1aec4..cd189b6 100644 (file)
@@ -24,7 +24,7 @@
 
 #define CX18_DRIVER_NAME "cx18"
 #define CX18_DRIVER_VERSION_MAJOR 1
-#define CX18_DRIVER_VERSION_MINOR 4
+#define CX18_DRIVER_VERSION_MINOR 5
 #define CX18_DRIVER_VERSION_PATCHLEVEL 0
 
 #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL)
index 935f557..767a8d2 100644 (file)
    ReturnCode */
 #define CX18_CPU_GET_ENC_PTS                   (CPU_CMD_MASK_CAPTURE | 0x0022)
 
+/* Description: Set VFC parameters
+   IN[0] - task handle
+   IN[1] - VFC enable flag, 1 - enable, 0 - disable
+*/
+#define CX18_CPU_SET_VFC_PARAM                  (CPU_CMD_MASK_CAPTURE | 0x0023)
+
 /* Below is the list of commands related to the data exchange */
 #define CPU_CMD_MASK_DE                        (CPU_CMD_MASK | 0x040000)
 
index f49230d..2270381 100644 (file)
@@ -401,6 +401,44 @@ struct cx231xx_board cx231xx_boards[] = {
                        .gpio = NULL,
                } },
        },
+       [CX231XX_BOARD_KWORLD_UB430_USB_HYBRID] = {
+               .name = "Kworld UB430 USB Hybrid",
+               .tuner_type = TUNER_NXP_TDA18271,
+               .tuner_addr = 0x60,
+               .decoder = CX231XX_AVDECODER,
+               .output_mode = OUT_MODE_VIP11,
+               .demod_xfer_mode = 0,
+               .ctl_pin_status_mask = 0xFFFFFFC4,
+               .agc_analog_digital_select_gpio = 0x11, /* According with PV cxPolaris.inf file */
+               .tuner_sif_gpio = -1,
+               .tuner_scl_gpio = -1,
+               .tuner_sda_gpio = -1,
+               .gpio_pin_status_mask = 0x4001000,
+               .tuner_i2c_master = 2,
+               .demod_i2c_master = 1,
+               .ir_i2c_master = 2,
+               .has_dvb = 1,
+               .demod_addr = 0x10,
+               .norm = V4L2_STD_PAL_M,
+               .input = {{
+                       .type = CX231XX_VMUX_TELEVISION,
+                       .vmux = CX231XX_VIN_3_1,
+                       .amux = CX231XX_AMUX_VIDEO,
+                       .gpio = NULL,
+               }, {
+                       .type = CX231XX_VMUX_COMPOSITE1,
+                       .vmux = CX231XX_VIN_2_1,
+                       .amux = CX231XX_AMUX_LINE_IN,
+                       .gpio = NULL,
+               }, {
+                       .type = CX231XX_VMUX_SVIDEO,
+                       .vmux = CX231XX_VIN_1_1 |
+                               (CX231XX_VIN_1_2 << 8) |
+                               CX25840_SVIDEO_ON,
+                       .amux = CX231XX_AMUX_LINE_IN,
+                       .gpio = NULL,
+               } },
+       },
        [CX231XX_BOARD_PV_PLAYTV_USB_HYBRID] = {
                .name = "Pixelview PlayTV USB Hybrid",
                .tuner_type = TUNER_NXP_TDA18271,
@@ -469,6 +507,31 @@ struct cx231xx_board cx231xx_boards[] = {
                        }
                },
        },
+
+       [CX231XX_BOARD_ICONBIT_U100] = {
+               .name = "Iconbit Analog Stick U100 FM",
+               .tuner_type = TUNER_ABSENT,
+               .decoder = CX231XX_AVDECODER,
+               .output_mode = OUT_MODE_VIP11,
+               .demod_xfer_mode = 0,
+               .ctl_pin_status_mask = 0xFFFFFFC4,
+               .agc_analog_digital_select_gpio = 0x1C,
+               .gpio_pin_status_mask = 0x4001000,
+
+               .input = {{
+                       .type = CX231XX_VMUX_COMPOSITE1,
+                       .vmux = CX231XX_VIN_2_1,
+                       .amux = CX231XX_AMUX_LINE_IN,
+                       .gpio = NULL,
+               }, {
+                       .type = CX231XX_VMUX_SVIDEO,
+                       .vmux = CX231XX_VIN_1_1 |
+                               (CX231XX_VIN_1_2 << 8) |
+                               CX25840_SVIDEO_ON,
+                       .amux = CX231XX_AMUX_LINE_IN,
+                       .gpio = NULL,
+               } },
+       },
 };
 const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
 
@@ -500,6 +563,10 @@ struct usb_device_id cx231xx_id_table[] = {
         .driver_info = CX231XX_BOARD_PV_PLAYTV_USB_HYBRID},
        {USB_DEVICE(USB_VID_PIXELVIEW, 0x5014),
         .driver_info = CX231XX_BOARD_PV_XCAPTURE_USB},
+       {USB_DEVICE(0x1b80, 0xe424),
+        .driver_info = CX231XX_BOARD_KWORLD_UB430_USB_HYBRID},
+       {USB_DEVICE(0x1f4d, 0x0237),
+        .driver_info = CX231XX_BOARD_ICONBIT_U100},
        {},
 };
 
index 363aa60..da9a4a0 100644 (file)
@@ -704,6 +704,7 @@ static int dvb_init(struct cx231xx *dev)
                break;
 
        case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
+       case CX231XX_BOARD_KWORLD_UB430_USB_HYBRID:
 
                printk(KERN_INFO "%s: looking for demod on i2c bus: %d\n",
                       __func__, i2c_adapter_id(&dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap));
index bd4a9cf..46dd840 100644 (file)
@@ -65,6 +65,8 @@
 #define CX231XX_BOARD_HAUPPAUGE_USBLIVE2 9
 #define CX231XX_BOARD_PV_PLAYTV_USB_HYBRID 10
 #define CX231XX_BOARD_PV_XCAPTURE_USB 11
+#define CX231XX_BOARD_KWORLD_UB430_USB_HYBRID 12
+#define CX231XX_BOARD_ICONBIT_U100 13
 
 /* Limits minimum and default number of buffers */
 #define CX231XX_MIN_BUF                 4
index ea88722..2354336 100644 (file)
@@ -1399,6 +1399,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
                else
                        altera_init(&netup_config, fw);
 
+               release_firmware(fw);
                break;
        }
        }
index 9933810..64d9b21 100644 (file)
@@ -2045,7 +2045,7 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
        }
 
        /* print pci info */
-       pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+       dev->pci_rev = pci_dev->revision;
        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
        printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
               "latency: %d, mmio: 0x%llx\n", dev->name,
index bca307e..11e49bb 100644 (file)
@@ -1060,18 +1060,21 @@ static int mpeg_open(struct file *file)
 
        /* Make sure we can acquire the hardware */
        drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
-       if (drv) {
-               err = drv->request_acquire(drv);
-               if(err != 0) {
-                       dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err);
-                       mutex_unlock(&dev->core->lock);
-                       return err;
-               }
+       if (!drv) {
+               dprintk(1, "%s: blackbird driver is not loaded\n", __func__);
+               mutex_unlock(&dev->core->lock);
+               return -ENODEV;
+       }
+
+       err = drv->request_acquire(drv);
+       if (err != 0) {
+               dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err);
+               mutex_unlock(&dev->core->lock);
+               return err;
        }
 
-       if (!atomic_read(&dev->core->mpeg_users) && blackbird_initialize_codec(dev) < 0) {
-               if (drv)
-                       drv->request_release(drv);
+       if (!dev->core->mpeg_users && blackbird_initialize_codec(dev) < 0) {
+               drv->request_release(drv);
                mutex_unlock(&dev->core->lock);
                return -EINVAL;
        }
@@ -1080,8 +1083,7 @@ static int mpeg_open(struct file *file)
        /* allocate + initialize per filehandle data */
        fh = kzalloc(sizeof(*fh),GFP_KERNEL);
        if (NULL == fh) {
-               if (drv)
-                       drv->request_release(drv);
+               drv->request_release(drv);
                mutex_unlock(&dev->core->lock);
                return -ENOMEM;
        }
@@ -1099,7 +1101,7 @@ static int mpeg_open(struct file *file)
        cx88_set_scale(dev->core, dev->width, dev->height,
                        fh->mpegq.field);
 
-       atomic_inc(&dev->core->mpeg_users);
+       dev->core->mpeg_users++;
        mutex_unlock(&dev->core->lock);
        return 0;
 }
@@ -1110,7 +1112,9 @@ static int mpeg_release(struct file *file)
        struct cx8802_dev *dev = fh->dev;
        struct cx8802_driver *drv = NULL;
 
-       if (dev->mpeg_active && atomic_read(&dev->core->mpeg_users) == 1)
+       mutex_lock(&dev->core->lock);
+
+       if (dev->mpeg_active && dev->core->mpeg_users == 1)
                blackbird_stop_codec(dev);
 
        cx8802_cancel_buffers(fh->dev);
@@ -1119,17 +1123,18 @@ static int mpeg_release(struct file *file)
 
        videobuf_mmap_free(&fh->mpegq);
 
-       mutex_lock(&dev->core->lock);
        file->private_data = NULL;
        kfree(fh);
-       mutex_unlock(&dev->core->lock);
 
        /* Make sure we release the hardware */
        drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
+       WARN_ON(!drv);
        if (drv)
                drv->request_release(drv);
 
-       atomic_dec(&dev->core->mpeg_users);
+       dev->core->mpeg_users--;
+
+       mutex_unlock(&dev->core->lock);
 
        return 0;
 }
@@ -1334,11 +1339,9 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
        blackbird_register_video(dev);
 
        /* initial device configuration: needed ? */
-       mutex_lock(&dev->core->lock);
 //     init_controls(core);
        cx88_set_tvnorm(core,core->tvnorm);
        cx88_video_mux(core,0);
-       mutex_unlock(&dev->core->lock);
 
        return 0;
 
index 7b8c9d3..c69df7e 100644 (file)
@@ -133,6 +133,7 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire)
                return -EINVAL;
        }
 
+       mutex_lock(&dev->core->lock);
        drv = cx8802_get_driver(dev, CX88_MPEG_DVB);
        if (drv) {
                if (acquire){
@@ -143,6 +144,7 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire)
                        dev->frontends.active_fe_id = 0;
                }
        }
+       mutex_unlock(&dev->core->lock);
 
        return ret;
 }
index addf954..1a7b983 100644 (file)
@@ -78,6 +78,7 @@ static void flush_request_modules(struct cx8802_dev *dev)
 
 
 static LIST_HEAD(cx8802_devlist);
+static DEFINE_MUTEX(cx8802_mutex);
 /* ------------------------------------------------------------------ */
 
 static int cx8802_start_dma(struct cx8802_dev    *dev,
@@ -474,7 +475,7 @@ static int cx8802_init_common(struct cx8802_dev *dev)
                return -EIO;
        }
 
-       pci_read_config_byte(dev->pci, PCI_CLASS_REVISION, &dev->pci_rev);
+       dev->pci_rev = dev->pci->revision;
        pci_read_config_byte(dev->pci, PCI_LATENCY_TIMER,  &dev->pci_lat);
        printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, "
               "latency: %d, mmio: 0x%llx\n", dev->core->name,
@@ -624,13 +625,11 @@ static int cx8802_request_acquire(struct cx8802_driver *drv)
 
        if (drv->advise_acquire)
        {
-               mutex_lock(&drv->core->lock);
                core->active_ref++;
                if (core->active_type_id == CX88_BOARD_NONE) {
                        core->active_type_id = drv->type_id;
                        drv->advise_acquire(drv);
                }
-               mutex_unlock(&drv->core->lock);
 
                mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __func__, cx_read(MO_GP0_IO));
        }
@@ -643,14 +642,12 @@ static int cx8802_request_release(struct cx8802_driver *drv)
 {
        struct cx88_core *core = drv->core;
 
-       mutex_lock(&drv->core->lock);
        if (drv->advise_release && --core->active_ref == 0)
        {
                drv->advise_release(drv);
                core->active_type_id = CX88_BOARD_NONE;
                mpeg_dbg(1,"%s() Post release GPIO=%x\n", __func__, cx_read(MO_GP0_IO));
        }
-       mutex_unlock(&drv->core->lock);
 
        return 0;
 }
@@ -693,6 +690,8 @@ int cx8802_register_driver(struct cx8802_driver *drv)
                return err;
        }
 
+       mutex_lock(&cx8802_mutex);
+
        list_for_each_entry(dev, &cx8802_devlist, devlist) {
                printk(KERN_INFO
                       "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n",
@@ -702,8 +701,10 @@ int cx8802_register_driver(struct cx8802_driver *drv)
 
                /* Bring up a new struct for each driver instance */
                driver = kzalloc(sizeof(*drv),GFP_KERNEL);
-               if (driver == NULL)
-                       return -ENOMEM;
+               if (driver == NULL) {
+                       err = -ENOMEM;
+                       goto out;
+               }
 
                /* Snapshot of the driver registration data */
                drv->core = dev->core;
@@ -713,21 +714,23 @@ int cx8802_register_driver(struct cx8802_driver *drv)
                drv->request_release = cx8802_request_release;
                memcpy(driver, drv, sizeof(*driver));
 
+               mutex_lock(&drv->core->lock);
                err = drv->probe(driver);
                if (err == 0) {
                        i++;
-                       mutex_lock(&drv->core->lock);
                        list_add_tail(&driver->drvlist, &dev->drvlist);
-                       mutex_unlock(&drv->core->lock);
                } else {
                        printk(KERN_ERR
                               "%s/2: cx8802 probe failed, err = %d\n",
                               dev->core->name, err);
                }
-
+               mutex_unlock(&drv->core->lock);
        }
 
-       return i ? 0 : -ENODEV;
+       err = i ? 0 : -ENODEV;
+out:
+       mutex_unlock(&cx8802_mutex);
+       return err;
 }
 
 int cx8802_unregister_driver(struct cx8802_driver *drv)
@@ -741,6 +744,8 @@ int cx8802_unregister_driver(struct cx8802_driver *drv)
               drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird",
               drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive");
 
+       mutex_lock(&cx8802_mutex);
+
        list_for_each_entry(dev, &cx8802_devlist, devlist) {
                printk(KERN_INFO
                       "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n",
@@ -748,6 +753,8 @@ int cx8802_unregister_driver(struct cx8802_driver *drv)
                       dev->pci->subsystem_device, dev->core->board.name,
                       dev->core->boardnr);
 
+               mutex_lock(&dev->core->lock);
+
                list_for_each_entry_safe(d, dtmp, &dev->drvlist, drvlist) {
                        /* only unregister the correct driver type */
                        if (d->type_id != drv->type_id)
@@ -755,17 +762,18 @@ int cx8802_unregister_driver(struct cx8802_driver *drv)
 
                        err = d->remove(d);
                        if (err == 0) {
-                               mutex_lock(&drv->core->lock);
                                list_del(&d->drvlist);
-                               mutex_unlock(&drv->core->lock);
                                kfree(d);
                        } else
                                printk(KERN_ERR "%s/2: cx8802 driver remove "
                                       "failed (%d)\n", dev->core->name, err);
                }
 
+               mutex_unlock(&dev->core->lock);
        }
 
+       mutex_unlock(&cx8802_mutex);
+
        return err;
 }
 
@@ -803,7 +811,9 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev,
                goto fail_free;
 
        INIT_LIST_HEAD(&dev->drvlist);
+       mutex_lock(&cx8802_mutex);
        list_add_tail(&dev->devlist,&cx8802_devlist);
+       mutex_unlock(&cx8802_mutex);
 
        /* now autoload cx88-dvb or cx88-blackbird */
        request_modules(dev);
@@ -827,6 +837,8 @@ static void __devexit cx8802_remove(struct pci_dev *pci_dev)
 
        flush_request_modules(dev);
 
+       mutex_lock(&dev->core->lock);
+
        if (!list_empty(&dev->drvlist)) {
                struct cx8802_driver *drv, *tmp;
                int err;
@@ -838,9 +850,7 @@ static void __devexit cx8802_remove(struct pci_dev *pci_dev)
                list_for_each_entry_safe(drv, tmp, &dev->drvlist, drvlist) {
                        err = drv->remove(drv);
                        if (err == 0) {
-                               mutex_lock(&drv->core->lock);
                                list_del(&drv->drvlist);
-                               mutex_unlock(&drv->core->lock);
                        } else
                                printk(KERN_ERR "%s/2: cx8802 driver remove "
                                       "failed (%d)\n", dev->core->name, err);
@@ -848,6 +858,8 @@ static void __devexit cx8802_remove(struct pci_dev *pci_dev)
                }
        }
 
+       mutex_unlock(&dev->core->lock);
+
        /* Destroy any 8802 reference. */
        dev->core->dvbdev = NULL;
 
index 287a41e..cef4f28 100644 (file)
@@ -824,7 +824,7 @@ static int video_open(struct file *file)
                call_all(core, tuner, s_radio);
        }
 
-       atomic_inc(&core->users);
+       core->users++;
        mutex_unlock(&core->lock);
 
        return 0;
@@ -922,7 +922,8 @@ static int video_release(struct file *file)
        file->private_data = NULL;
        kfree(fh);
 
-       if(atomic_dec_and_test(&dev->core->users))
+       dev->core->users--;
+       if (!dev->core->users)
                call_all(dev->core, core, s_power, 0);
        mutex_unlock(&dev->core->lock);
 
@@ -1832,7 +1833,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
        dev->core = core;
 
        /* print pci info */
-       pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+       dev->pci_rev = pci_dev->revision;
        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
        printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
               "latency: %d, mmio: 0x%llx\n", core->name,
index 9b3742a..a399a8b 100644 (file)
@@ -389,8 +389,8 @@ struct cx88_core {
        struct mutex               lock;
        /* various v4l controls */
        u32                        freq;
-       atomic_t                   users;
-       atomic_t                   mpeg_users;
+       int                        users;
+       int                        mpeg_users;
 
        /* cx88-video needs to access cx8802 for hybrid tuner pll access. */
        struct cx8802_dev          *dvbdev;
@@ -505,6 +505,8 @@ struct cx8802_driver {
        int (*suspend)(struct pci_dev *pci_dev, pm_message_t state);
        int (*resume)(struct pci_dev *pci_dev);
 
+       /* Callers to the following functions must hold core->lock */
+
        /* MPEG 8802 -> mini driver - Driver probe and configuration */
        int (*probe)(struct cx8802_driver *drv);
        int (*remove)(struct cx8802_driver *drv);
@@ -561,8 +563,9 @@ struct cx8802_dev {
        /* for switching modulation types */
        unsigned char              ts_gen_cntrl;
 
-       /* List of attached drivers */
+       /* List of attached drivers; must hold core->lock to access */
        struct list_head           drvlist;
+
        struct work_struct         request_module_wk;
 };
 
@@ -685,6 +688,8 @@ int cx88_audio_thread(void *data);
 
 int cx8802_register_driver(struct cx8802_driver *drv);
 int cx8802_unregister_driver(struct cx8802_driver *drv);
+
+/* Caller must hold core->lock */
 struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype);
 
 /* ----------------------------------------------------------- */
index 985100e..3cb78f2 100644 (file)
@@ -38,6 +38,8 @@ config VIDEO_EM28XX_DVB
        select DVB_ZL10353 if !DVB_FE_CUSTOMISE
        select DVB_TDA10023 if !DVB_FE_CUSTOMISE
        select DVB_S921 if !DVB_FE_CUSTOMISE
+       select DVB_DRXD if !DVB_FE_CUSTOMISE
+       select DVB_CXD2820R if !DVB_FE_CUSTOMISE
        select VIDEOBUF_DVB
        ---help---
          This adds support for DVB cards based on the
index 69fcea8..4e37375 100644 (file)
@@ -100,6 +100,13 @@ static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
        { -1,                   -1,     -1,             -1},
 };
 
+/* Board Hauppauge WinTV HVR 900 (R2) digital */
+static struct em28xx_reg_seq hauppauge_wintv_hvr_900R2_digital[] = {
+       {EM28XX_R08_GPIO,       0x2e,   ~EM_GPIO_4,     10},
+       {EM2880_R04_GPO,        0x0c,   0x0f,           10},
+       { -1,                   -1,     -1,             -1},
+};
+
 /* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */
 static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = {
        {EM28XX_R08_GPIO,       0x69,   ~EM_GPIO_4,      10},
@@ -282,6 +289,16 @@ static struct em28xx_reg_seq leadership_reset[] = {
        {       -1,             -1,     -1,     -1},
 };
 
+/* 2013:024f PCTV Systems nanoStick T2 290e
+ * GPIO_6 - demod reset
+ * GPIO_7 - LED
+ */
+static struct em28xx_reg_seq pctv_290e[] = {
+       {EM2874_R80_GPIO,       0x00,   0xff,           80},
+       {EM2874_R80_GPIO,       0x40,   0xff,           80}, /* GPIO_6 = 1 */
+       {EM2874_R80_GPIO,       0xc0,   0xff,           80}, /* GPIO_7 = 1 */
+       {-1,                    -1,     -1,             -1},
+};
 
 /*
  *  Board definitions
@@ -859,6 +876,8 @@ struct em28xx_board em28xx_boards[] = {
                .tuner_type   = TUNER_XC2028,
                .tuner_gpio   = default_tuner_gpio,
                .mts_firmware = 1,
+               .has_dvb      = 1,
+               .dvb_gpio     = hauppauge_wintv_hvr_900R2_digital,
                .ir_codes     = RC_MAP_HAUPPAUGE,
                .decoder      = EM28XX_TVP5150,
                .input        = { {
@@ -1448,12 +1467,14 @@ struct em28xx_board em28xx_boards[] = {
                        .gpio     = pinnacle_hybrid_pro_analog,
                } },
        },
-       [EM2882_BOARD_PINNACLE_HYBRID_PRO] = {
-               .name         = "Pinnacle Hybrid Pro (2)",
-               .valid        = EM28XX_BOARD_NOT_VALIDATED,
+       [EM2882_BOARD_PINNACLE_HYBRID_PRO_330E] = {
+               .name         = "Pinnacle Hybrid Pro (330e)",
                .tuner_type   = TUNER_XC2028,
                .tuner_gpio   = default_tuner_gpio,
                .mts_firmware = 1,
+               .has_dvb      = 1,
+               .dvb_gpio     = hauppauge_wintv_hvr_900R2_digital,
+               .ir_codes     = RC_MAP_PINNACLE_PCTV_HD,
                .decoder      = EM28XX_TVP5150,
                .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
@@ -1749,6 +1770,17 @@ struct em28xx_board em28xx_boards[] = {
                .dvb_gpio   = kworld_a340_digital,
                .tuner_gpio = default_tuner_gpio,
        },
+       /* 2013:024f PCTV Systems nanoStick T2 290e.
+        * Empia EM28174, Sony CXD2820R and NXP TDA18271HD/C2 */
+       [EM28174_BOARD_PCTV_290E] = {
+               .i2c_speed      = EM2874_I2C_SECONDARY_BUS_SELECT |
+                       EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ,
+               .xclk          = EM28XX_XCLK_FREQUENCY_12MHZ,
+               .name          = "PCTV Systems nanoStick T2 290e",
+               .tuner_type    = TUNER_ABSENT,
+               .tuner_gpio    = pctv_290e,
+               .has_dvb       = 1,
+       },
 };
 const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
@@ -1863,7 +1895,7 @@ struct usb_device_id em28xx_id_table[] = {
        { USB_DEVICE(0x2304, 0x021a),
                        .driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
        { USB_DEVICE(0x2304, 0x0226),
-                       .driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO },
+                       .driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO_330E },
        { USB_DEVICE(0x2304, 0x0227),
                        .driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO },
        { USB_DEVICE(0x0413, 0x6023),
@@ -1876,6 +1908,8 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM2860_BOARD_GADMEI_UTV330 },
        { USB_DEVICE(0x1b80, 0xa340),
                        .driver_info = EM2870_BOARD_KWORLD_A340 },
+       { USB_DEVICE(0x2013, 0x024f),
+                       .driver_info = EM28174_BOARD_PCTV_290E },
        { },
 };
 MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -2229,7 +2263,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
                ctl->demod = XC3028_FE_ZARLINK456;
                break;
        case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
-               /* djh - Not sure which demod we need here */
+       case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
                ctl->demod = XC3028_FE_DEFAULT;
                break;
        case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
@@ -2799,6 +2833,11 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
                        dev->reg_gpio_num = EM2874_R80_GPIO;
                        dev->wait_after_write = 0;
                        break;
+               case CHIP_ID_EM28174:
+                       em28xx_info("chip ID is em28174\n");
+                       dev->reg_gpio_num = EM2874_R80_GPIO;
+                       dev->wait_after_write = 0;
+                       break;
                case CHIP_ID_EM2883:
                        em28xx_info("chip ID is em2882/em2883\n");
                        dev->wait_after_write = 0;
index 44c63cb..e33f145 100644 (file)
@@ -489,7 +489,8 @@ int em28xx_audio_setup(struct em28xx *dev)
        int vid1, vid2, feat, cfg;
        u32 vid;
 
-       if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874) {
+       if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874
+               || dev->chip_id == CHIP_ID_EM28174) {
                /* Digital only device - don't load any alsa module */
                dev->audio_mode.has_audio = 0;
                dev->has_audio_class = 0;
@@ -614,7 +615,7 @@ int em28xx_capture_start(struct em28xx *dev, int start)
 {
        int rc;
 
-       if (dev->chip_id == CHIP_ID_EM2874) {
+       if (dev->chip_id == CHIP_ID_EM2874 || dev->chip_id == CHIP_ID_EM28174) {
                /* The Transport Stream Enable Register moved in em2874 */
                if (!start) {
                        rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
@@ -1111,6 +1112,10 @@ int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev)
                /* FIXME - for now assume 564 like it was before, but the
                   em2874 code should be added to return the proper value... */
                packet_size = 564;
+       } else if (dev->chip_id == CHIP_ID_EM28174) {
+               /* FIXME same as em2874. 564 was enough for 22 Mbit DVB-T
+                  but too much for 44 Mbit DVB-C. */
+               packet_size = 752;
        } else {
                /* TS max packet size stored in bits 1-0 of R01 */
                chip_cfg2 = em28xx_read_reg(dev, EM28XX_R01_CHIPCFG2);
index c7c04bf..7904ca4 100644 (file)
@@ -38,6 +38,8 @@
 #include "tda1002x.h"
 #include "tda18271.h"
 #include "s921.h"
+#include "drxd.h"
+#include "cxd2820r.h"
 
 MODULE_DESCRIPTION("driver for em28xx based DVB cards");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
@@ -58,7 +60,7 @@ if (debug >= level)                                           \
 #define EM28XX_DVB_MAX_PACKETS 64
 
 struct em28xx_dvb {
-       struct dvb_frontend        *frontend;
+       struct dvb_frontend        *fe[2];
 
        /* feed count management */
        struct mutex               lock;
@@ -285,12 +287,13 @@ static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = {
        .if2 = 45600,
 };
 
-#ifdef EM28XX_DRX397XD_SUPPORT
-/* [TODO] djh - not sure yet what the device config needs to contain */
-static struct drx397xD_config em28xx_drx397xD_with_xc3028 = {
-       .demod_address = (0xe0 >> 1),
+static struct drxd_config em28xx_drxd = {
+       .index = 0, .demod_address = 0x70, .demod_revision = 0xa2,
+       .demoda_address = 0x00, .pll_address = 0x00,
+       .pll_type = DRXD_PLL_NONE, .clock = 12000, .insert_rs_byte = 1,
+       .pll_set = NULL, .osc_deviation = NULL, .IF = 42800000,
+       .disable_i2c_gate_ctrl = 1,
 };
-#endif
 
 static int mt352_terratec_xs_init(struct dvb_frontend *fe)
 {
@@ -332,6 +335,26 @@ static struct tda10023_config em28xx_tda10023_config = {
        .invert = 1,
 };
 
+static struct cxd2820r_config em28xx_cxd2820r_config = {
+       .i2c_address = (0xd8 >> 1),
+       .ts_mode = CXD2820R_TS_SERIAL,
+       .if_dvbt_6  = 3300,
+       .if_dvbt_7  = 3500,
+       .if_dvbt_8  = 4000,
+       .if_dvbt2_6 = 3300,
+       .if_dvbt2_7 = 3500,
+       .if_dvbt2_8 = 4000,
+       .if_dvbc    = 5000,
+
+       /* enable LNA for DVB-T2 and DVB-C */
+       .gpio_dvbt2[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L,
+       .gpio_dvbc[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L,
+};
+
+static struct tda18271_config em28xx_cxd2820r_tda18271_config = {
+       .output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
 /* ------------------------------------------------------------------ */
 
 static int attach_xc3028(u8 addr, struct em28xx *dev)
@@ -343,17 +366,17 @@ static int attach_xc3028(u8 addr, struct em28xx *dev)
        cfg.i2c_adap  = &dev->i2c_adap;
        cfg.i2c_addr  = addr;
 
-       if (!dev->dvb->frontend) {
+       if (!dev->dvb->fe[0]) {
                em28xx_errdev("/2: dvb frontend not attached. "
                                "Can't attach xc3028\n");
                return -EINVAL;
        }
 
-       fe = dvb_attach(xc2028_attach, dev->dvb->frontend, &cfg);
+       fe = dvb_attach(xc2028_attach, dev->dvb->fe[0], &cfg);
        if (!fe) {
                em28xx_errdev("/2: xc3028 attach failed\n");
-               dvb_frontend_detach(dev->dvb->frontend);
-               dev->dvb->frontend = NULL;
+               dvb_frontend_detach(dev->dvb->fe[0]);
+               dev->dvb->fe[0] = NULL;
                return -EINVAL;
        }
 
@@ -383,16 +406,28 @@ static int register_dvb(struct em28xx_dvb *dvb,
        }
 
        /* Ensure all frontends negotiate bus access */
-       dvb->frontend->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
+       dvb->fe[0]->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
+       if (dvb->fe[1])
+               dvb->fe[1]->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
 
        dvb->adapter.priv = dev;
 
        /* register frontend */
-       result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+       result = dvb_register_frontend(&dvb->adapter, dvb->fe[0]);
        if (result < 0) {
                printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
                       dev->name, result);
-               goto fail_frontend;
+               goto fail_frontend0;
+       }
+
+       /* register 2nd frontend */
+       if (dvb->fe[1]) {
+               result = dvb_register_frontend(&dvb->adapter, dvb->fe[1]);
+               if (result < 0) {
+                       printk(KERN_WARNING "%s: 2nd dvb_register_frontend failed (errno = %d)\n",
+                               dev->name, result);
+                       goto fail_frontend1;
+               }
        }
 
        /* register demux stuff */
@@ -458,9 +493,14 @@ fail_fe_hw:
 fail_dmxdev:
        dvb_dmx_release(&dvb->demux);
 fail_dmx:
-       dvb_unregister_frontend(dvb->frontend);
-fail_frontend:
-       dvb_frontend_detach(dvb->frontend);
+       if (dvb->fe[1])
+               dvb_unregister_frontend(dvb->fe[1]);
+       dvb_unregister_frontend(dvb->fe[0]);
+fail_frontend1:
+       if (dvb->fe[1])
+               dvb_frontend_detach(dvb->fe[1]);
+fail_frontend0:
+       dvb_frontend_detach(dvb->fe[0]);
        dvb_unregister_adapter(&dvb->adapter);
 fail_adapter:
        return result;
@@ -473,12 +513,15 @@ static void unregister_dvb(struct em28xx_dvb *dvb)
        dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
        dvb_dmxdev_release(&dvb->dmxdev);
        dvb_dmx_release(&dvb->demux);
-       dvb_unregister_frontend(dvb->frontend);
-       dvb_frontend_detach(dvb->frontend);
+       if (dvb->fe[1])
+               dvb_unregister_frontend(dvb->fe[1]);
+       dvb_unregister_frontend(dvb->fe[0]);
+       if (dvb->fe[1])
+               dvb_frontend_detach(dvb->fe[1]);
+       dvb_frontend_detach(dvb->fe[0]);
        dvb_unregister_adapter(&dvb->adapter);
 }
 
-
 static int dvb_init(struct em28xx *dev)
 {
        int result = 0;
@@ -497,16 +540,17 @@ static int dvb_init(struct em28xx *dev)
                return -ENOMEM;
        }
        dev->dvb = dvb;
+       dvb->fe[0] = dvb->fe[1] = NULL;
 
        mutex_lock(&dev->lock);
        em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
        /* init frontend */
        switch (dev->model) {
        case EM2874_LEADERSHIP_ISDBT:
-               dvb->frontend = dvb_attach(s921_attach,
+               dvb->fe[0] = dvb_attach(s921_attach,
                                &sharp_isdbt, &dev->i2c_adap);
 
-               if (!dvb->frontend) {
+               if (!dvb->fe[0]) {
                        result = -EINVAL;
                        goto out_free;
                }
@@ -516,7 +560,7 @@ static int dvb_init(struct em28xx *dev)
        case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
        case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
        case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
-               dvb->frontend = dvb_attach(lgdt330x_attach,
+               dvb->fe[0] = dvb_attach(lgdt330x_attach,
                                           &em2880_lgdt3303_dev,
                                           &dev->i2c_adap);
                if (attach_xc3028(0x61, dev) < 0) {
@@ -525,7 +569,7 @@ static int dvb_init(struct em28xx *dev)
                }
                break;
        case EM2880_BOARD_KWORLD_DVB_310U:
-               dvb->frontend = dvb_attach(zl10353_attach,
+               dvb->fe[0] = dvb_attach(zl10353_attach,
                                           &em28xx_zl10353_with_xc3028,
                                           &dev->i2c_adap);
                if (attach_xc3028(0x61, dev) < 0) {
@@ -536,7 +580,7 @@ static int dvb_init(struct em28xx *dev)
        case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
        case EM2882_BOARD_TERRATEC_HYBRID_XS:
        case EM2880_BOARD_EMPIRE_DUAL_TV:
-               dvb->frontend = dvb_attach(zl10353_attach,
+               dvb->fe[0] = dvb_attach(zl10353_attach,
                                           &em28xx_zl10353_xc3028_no_i2c_gate,
                                           &dev->i2c_adap);
                if (attach_xc3028(0x61, dev) < 0) {
@@ -549,13 +593,13 @@ static int dvb_init(struct em28xx *dev)
        case EM2881_BOARD_PINNACLE_HYBRID_PRO:
        case EM2882_BOARD_DIKOM_DK300:
        case EM2882_BOARD_KWORLD_VS_DVBT:
-               dvb->frontend = dvb_attach(zl10353_attach,
+               dvb->fe[0] = dvb_attach(zl10353_attach,
                                           &em28xx_zl10353_xc3028_no_i2c_gate,
                                           &dev->i2c_adap);
-               if (dvb->frontend == NULL) {
+               if (dvb->fe[0] == NULL) {
                        /* This board could have either a zl10353 or a mt352.
                           If the chip id isn't for zl10353, try mt352 */
-                       dvb->frontend = dvb_attach(mt352_attach,
+                       dvb->fe[0] = dvb_attach(mt352_attach,
                                                   &terratec_xs_mt352_cfg,
                                                   &dev->i2c_adap);
                }
@@ -567,7 +611,7 @@ static int dvb_init(struct em28xx *dev)
                break;
        case EM2883_BOARD_KWORLD_HYBRID_330U:
        case EM2882_BOARD_EVGA_INDTUBE:
-               dvb->frontend = dvb_attach(s5h1409_attach,
+               dvb->fe[0] = dvb_attach(s5h1409_attach,
                                           &em28xx_s5h1409_with_xc3028,
                                           &dev->i2c_adap);
                if (attach_xc3028(0x61, dev) < 0) {
@@ -576,11 +620,11 @@ static int dvb_init(struct em28xx *dev)
                }
                break;
        case EM2882_BOARD_KWORLD_ATSC_315U:
-               dvb->frontend = dvb_attach(lgdt330x_attach,
+               dvb->fe[0] = dvb_attach(lgdt330x_attach,
                                           &em2880_lgdt3303_dev,
                                           &dev->i2c_adap);
-               if (dvb->frontend != NULL) {
-                       if (!dvb_attach(simple_tuner_attach, dvb->frontend,
+               if (dvb->fe[0] != NULL) {
+                       if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
                                &dev->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) {
                                result = -EINVAL;
                                goto out_free;
@@ -588,25 +632,21 @@ static int dvb_init(struct em28xx *dev)
                }
                break;
        case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
-#ifdef EM28XX_DRX397XD_SUPPORT
-               /* We don't have the config structure properly populated, so
-                  this is commented out for now */
-               dvb->frontend = dvb_attach(drx397xD_attach,
-                                          &em28xx_drx397xD_with_xc3028,
-                                          &dev->i2c_adap);
+       case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
+               dvb->fe[0] = dvb_attach(drxd_attach, &em28xx_drxd, NULL,
+                                          &dev->i2c_adap, &dev->udev->dev);
                if (attach_xc3028(0x61, dev) < 0) {
                        result = -EINVAL;
                        goto out_free;
                }
                break;
-#endif
        case EM2870_BOARD_REDDO_DVB_C_USB_BOX:
                /* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */
-               dvb->frontend = dvb_attach(tda10023_attach,
+               dvb->fe[0] = dvb_attach(tda10023_attach,
                        &em28xx_tda10023_config,
                        &dev->i2c_adap, 0x48);
-               if (dvb->frontend) {
-                       if (!dvb_attach(simple_tuner_attach, dvb->frontend,
+               if (dvb->fe[0]) {
+                       if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
                                &dev->i2c_adap, 0x60, TUNER_PHILIPS_CU1216L)) {
                                result = -EINVAL;
                                goto out_free;
@@ -614,25 +654,53 @@ static int dvb_init(struct em28xx *dev)
                }
                break;
        case EM2870_BOARD_KWORLD_A340:
-               dvb->frontend = dvb_attach(lgdt3305_attach,
+               dvb->fe[0] = dvb_attach(lgdt3305_attach,
                                           &em2870_lgdt3304_dev,
                                           &dev->i2c_adap);
-               if (dvb->frontend != NULL)
-                       dvb_attach(tda18271_attach, dvb->frontend, 0x60,
+               if (dvb->fe[0] != NULL)
+                       dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
                                   &dev->i2c_adap, &kworld_a340_config);
                break;
+       case EM28174_BOARD_PCTV_290E:
+               /* MFE
+                * FE 0 = DVB-T/T2 + FE 1 = DVB-C, both sharing same tuner. */
+               /* FE 0 */
+               dvb->fe[0] = dvb_attach(cxd2820r_attach,
+                       &em28xx_cxd2820r_config, &dev->i2c_adap, NULL);
+               if (dvb->fe[0]) {
+                       struct i2c_adapter *i2c_tuner;
+                       i2c_tuner = cxd2820r_get_tuner_i2c_adapter(dvb->fe[0]);
+                       /* FE 0 attach tuner */
+                       if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
+                               i2c_tuner, &em28xx_cxd2820r_tda18271_config)) {
+                               dvb_frontend_detach(dvb->fe[0]);
+                               result = -EINVAL;
+                               goto out_free;
+                       }
+                       /* FE 1. This dvb_attach() cannot fail. */
+                       dvb->fe[1] = dvb_attach(cxd2820r_attach, NULL, NULL,
+                               dvb->fe[0]);
+                       dvb->fe[1]->id = 1;
+                       /* FE 1 attach tuner */
+                       if (!dvb_attach(tda18271_attach, dvb->fe[1], 0x60,
+                               i2c_tuner, &em28xx_cxd2820r_tda18271_config)) {
+                               dvb_frontend_detach(dvb->fe[1]);
+                               /* leave FE 0 still active */
+                       }
+               }
+               break;
        default:
                em28xx_errdev("/2: The frontend of your DVB/ATSC card"
                                " isn't supported yet\n");
                break;
        }
-       if (NULL == dvb->frontend) {
+       if (NULL == dvb->fe[0]) {
                em28xx_errdev("/2: frontend initialization failed\n");
                result = -EINVAL;
                goto out_free;
        }
        /* define general-purpose callback pointer */
-       dvb->frontend->callback = em28xx_tuner_callback;
+       dvb->fe[0]->callback = em28xx_tuner_callback;
 
        /* register everything */
        result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
index 71474d3..4739fc7 100644 (file)
@@ -332,7 +332,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
        struct em28xx_eeprom *em_eeprom = (void *)eedata;
        int i, err, size = len, block;
 
-       if (dev->chip_id == CHIP_ID_EM2874) {
+       if (dev->chip_id == CHIP_ID_EM2874 || dev->chip_id == CHIP_ID_EM28174) {
                /* Empia switched to a 16-bit addressable eeprom in newer
                   devices.  While we could certainly write a routine to read
                   the eeprom, there is nothing of use in there that cannot be
index 91e9055..e92a28e 100644 (file)
@@ -201,6 +201,7 @@ enum em28xx_chip_id {
        CHIP_ID_EM2870 = 35,
        CHIP_ID_EM2883 = 36,
        CHIP_ID_EM2874 = 65,
+       CHIP_ID_EM28174 = 113,
 };
 
 /*
index 6f2795a..3cca331 100644 (file)
@@ -97,7 +97,7 @@
 #define EM2881_BOARD_PINNACLE_HYBRID_PRO         53
 #define EM2882_BOARD_KWORLD_VS_DVBT              54
 #define EM2882_BOARD_TERRATEC_HYBRID_XS                  55
-#define EM2882_BOARD_PINNACLE_HYBRID_PRO         56
+#define EM2882_BOARD_PINNACLE_HYBRID_PRO_330E    56
 #define EM2883_BOARD_KWORLD_HYBRID_330U                  57
 #define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU     58
 #define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850     60
 #define EM2882_BOARD_DIKOM_DK300                 75
 #define EM2870_BOARD_KWORLD_A340                 76
 #define EM2874_LEADERSHIP_ISDBT                          77
+#define EM28174_BOARD_PCTV_290E                   78
 
 
 /* Limits minimum and default number of buffers */
index 031af16..908d701 100644 (file)
@@ -766,7 +766,7 @@ inline void viu_activate_overlay(struct viu_reg *viu_reg)
        out_be32(&vr->picture_count, reg_val.picture_count);
 }
 
-static int viu_start_preview(struct viu_dev *dev, struct viu_fh *fh)
+static int viu_setup_preview(struct viu_dev *dev, struct viu_fh *fh)
 {
        int bpp;
 
@@ -805,11 +805,6 @@ static int viu_start_preview(struct viu_dev *dev, struct viu_fh *fh)
        /* setup the base address of the overlay buffer */
        reg_val.field_base_addr = (u32)dev->ovbuf.base;
 
-       dev->ovenable = 1;
-       viu_activate_overlay(dev->vr);
-
-       /* start dma */
-       viu_start_dma(dev);
        return 0;
 }
 
@@ -825,13 +820,11 @@ static int vidioc_s_fmt_overlay(struct file *file, void *priv,
        if (err)
                return err;
 
-       mutex_lock(&dev->lock);
        fh->win = f->fmt.win;
 
        spin_lock_irqsave(&dev->slock, flags);
-       viu_start_preview(dev, fh);
+       viu_setup_preview(dev, fh);
        spin_unlock_irqrestore(&dev->slock, flags);
-       mutex_unlock(&dev->lock);
        return 0;
 }
 
@@ -841,6 +834,28 @@ static int vidioc_try_fmt_overlay(struct file *file, void *priv,
        return 0;
 }
 
+static int vidioc_overlay(struct file *file, void *priv, unsigned int on)
+{
+       struct viu_fh  *fh  = priv;
+       struct viu_dev *dev = (struct viu_dev *)fh->dev;
+       unsigned long  flags;
+
+       if (on) {
+               spin_lock_irqsave(&dev->slock, flags);
+               viu_activate_overlay(dev->vr);
+               dev->ovenable = 1;
+
+               /* start dma */
+               viu_start_dma(dev);
+               spin_unlock_irqrestore(&dev->slock, flags);
+       } else {
+               viu_stop_dma(dev);
+               dev->ovenable = 0;
+       }
+
+       return 0;
+}
+
 int vidioc_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg)
 {
        struct viu_fh  *fh = priv;
@@ -911,12 +926,16 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 {
        struct viu_fh *fh = priv;
+       struct viu_dev *dev = fh->dev;
 
        if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
        if (fh->type != i)
                return -EINVAL;
 
+       if (dev->ovenable)
+               dev->ovenable = 0;
+
        viu_start_dma(fh->dev);
 
        return videobuf_streamon(&fh->vb_vidq);
@@ -1311,7 +1330,8 @@ static int viu_open(struct file *file)
        videobuf_queue_dma_contig_init(&fh->vb_vidq, &viu_video_qops,
                                       dev->dev, &fh->vbq_lock,
                                       fh->type, V4L2_FIELD_INTERLACED,
-                                      sizeof(struct viu_buf), fh, NULL);
+                                      sizeof(struct viu_buf), fh,
+                                      &fh->dev->lock);
        return 0;
 }
 
@@ -1401,7 +1421,7 @@ static struct v4l2_file_operations viu_fops = {
        .release        = viu_release,
        .read           = viu_read,
        .poll           = viu_poll,
-       .ioctl          = video_ioctl2, /* V4L2 ioctl handler */
+       .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
        .mmap           = viu_mmap,
 };
 
@@ -1415,6 +1435,7 @@ static const struct v4l2_ioctl_ops viu_ioctl_ops = {
        .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_overlay,
        .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_overlay,
        .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_overlay,
+       .vidioc_overlay       = vidioc_overlay,
        .vidioc_g_fbuf        = vidioc_g_fbuf,
        .vidioc_s_fbuf        = vidioc_s_fbuf,
        .vidioc_reqbufs       = vidioc_reqbufs,
@@ -1498,9 +1519,6 @@ static int __devinit viu_of_probe(struct platform_device *op)
        INIT_LIST_HEAD(&viu_dev->vidq.active);
        INIT_LIST_HEAD(&viu_dev->vidq.queued);
 
-       /* initialize locks */
-       mutex_init(&viu_dev->lock);
-
        snprintf(viu_dev->v4l2_dev.name,
                 sizeof(viu_dev->v4l2_dev.name), "%s", "VIU");
        ret = v4l2_device_register(viu_dev->dev, &viu_dev->v4l2_dev);
@@ -1531,8 +1549,15 @@ static int __devinit viu_of_probe(struct platform_device *op)
 
        viu_dev->vdev = vdev;
 
+       /* initialize locks */
+       mutex_init(&viu_dev->lock);
+       viu_dev->vdev->lock = &viu_dev->lock;
+       spin_lock_init(&viu_dev->slock);
+
        video_set_drvdata(viu_dev->vdev, viu_dev);
 
+       mutex_lock(&viu_dev->lock);
+
        ret = video_register_device(viu_dev->vdev, VFL_TYPE_GRABBER, -1);
        if (ret < 0) {
                video_device_release(viu_dev->vdev);
@@ -1559,6 +1584,8 @@ static int __devinit viu_of_probe(struct platform_device *op)
                goto err_irq;
        }
 
+       mutex_unlock(&viu_dev->lock);
+
        dev_info(&op->dev, "Freescale VIU Video Capture Board\n");
        return ret;
 
@@ -1568,6 +1595,7 @@ err_irq:
 err_clk:
        video_unregister_device(viu_dev->vdev);
 err_vdev:
+       mutex_unlock(&viu_dev->lock);
        i2c_put_adapter(ad);
        v4l2_device_unregister(&viu_dev->v4l2_dev);
 err:
index eb04e8b..34ae2c2 100644 (file)
@@ -77,6 +77,15 @@ config USB_GSPCA_JEILINJ
          To compile this driver as a module, choose M here: the
          module will be called gspca_jeilinj.
 
+config USB_GSPCA_KINECT
+       tristate "Kinect sensor device USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+         Say Y here if you want support for the Microsoft Kinect sensor device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called gspca_kinect.
+
 config USB_GSPCA_KONICA
        tristate "Konica USB Camera V4L2 driver"
        depends on VIDEO_V4L2 && USB_GSPCA
index 855fbc8..802fbe1 100644 (file)
@@ -5,6 +5,7 @@ obj-$(CONFIG_USB_GSPCA_CPIA1)    += gspca_cpia1.o
 obj-$(CONFIG_USB_GSPCA_ETOMS)    += gspca_etoms.o
 obj-$(CONFIG_USB_GSPCA_FINEPIX)  += gspca_finepix.o
 obj-$(CONFIG_USB_GSPCA_JEILINJ)  += gspca_jeilinj.o
+obj-$(CONFIG_USB_GSPCA_KINECT)   += gspca_kinect.o
 obj-$(CONFIG_USB_GSPCA_KONICA)   += gspca_konica.o
 obj-$(CONFIG_USB_GSPCA_MARS)     += gspca_mars.o
 obj-$(CONFIG_USB_GSPCA_MR97310A) += gspca_mr97310a.o
@@ -46,6 +47,7 @@ gspca_cpia1-objs    := cpia1.o
 gspca_etoms-objs    := etoms.o
 gspca_finepix-objs  := finepix.o
 gspca_jeilinj-objs  := jeilinj.o
+gspca_kinect-objs   := kinect.o
 gspca_konica-objs   := konica.o
 gspca_mars-objs     := mars.o
 gspca_mr97310a-objs := mr97310a.o
index 9ddbac6..f2a9451 100644 (file)
@@ -1262,7 +1262,7 @@ static int set_flicker(struct gspca_dev *gspca_dev, int on, int apply)
 static void monitor_exposure(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       u8 exp_acc, bcomp, gain, coarseL, cmd[8];
+       u8 exp_acc, bcomp, cmd[8];
        int ret, light_exp, dark_exp, very_dark_exp;
        int old_exposure, new_exposure, framerate;
        int setfps = 0, setexp = 0, setflicker = 0;
@@ -1284,8 +1284,6 @@ static void monitor_exposure(struct gspca_dev *gspca_dev)
        }
        exp_acc = gspca_dev->usb_buf[0];
        bcomp = gspca_dev->usb_buf[1];
-       gain = gspca_dev->usb_buf[2];
-       coarseL = gspca_dev->usb_buf[3];
 
        light_exp = sd->params.colourParams.brightness +
                    TC - 50 + EXP_ACC_LIGHT;
@@ -1772,9 +1770,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
-#ifdef GSPCA_DEBUG
        struct sd *sd = (struct sd *) gspca_dev;
-#endif
        int ret;
 
        /* Start / Stop the camera to make sure we are talking to
index 9908303..e8e071a 100644 (file)
@@ -499,21 +499,8 @@ MODULE_DEVICE_TABLE(usb, device_table);
 static int sd_probe(struct usb_interface *intf,
                                const struct usb_device_id *id)
 {
-       struct gspca_dev *gspca_dev;
-       s32 ret;
-
-       ret = gspca_dev_probe(intf, id,
+       return gspca_dev_probe(intf, id,
                        &sd_desc_mi1320, sizeof(struct sd), THIS_MODULE);
-
-       if (ret >= 0) {
-               gspca_dev = usb_get_intfdata(intf);
-
-               PDEBUG(D_PROBE,
-                       "Camera is now controlling video device %s",
-                       video_device_node_name(&gspca_dev->vdev));
-       }
-
-       return ret;
 }
 
 static void sd_disconnect(struct usb_interface *intf)
index e526aa3..08ce994 100644 (file)
@@ -55,7 +55,7 @@ MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("GSPCA USB Camera Driver");
 MODULE_LICENSE("GPL");
 
-#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 12, 0)
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 13, 0)
 
 #ifdef GSPCA_DEBUG
 int gspca_debug = D_ERR | D_PROBE;
@@ -2495,6 +2495,6 @@ module_exit(gspca_exit);
 module_param_named(debug, gspca_debug, int, 0644);
 MODULE_PARM_DESC(debug,
                "Debug (bit) 0x01:error 0x02:probe 0x04:config"
-               " 0x08:stream 0x10:frame 0x20:packet 0x40:USBin 0x80:USBout"
+               " 0x08:stream 0x10:frame 0x20:packet"
                " 0x0100: v4l2");
 #endif
index 4175522..49e2fcb 100644 (file)
@@ -9,7 +9,7 @@
 #include <linux/mutex.h>
 
 /* compilation option */
-#define GSPCA_DEBUG 1
+/*#define GSPCA_DEBUG 1*/
 
 #ifdef GSPCA_DEBUG
 /* GSPCA our debug messages */
@@ -25,8 +25,8 @@ extern int gspca_debug;
 #define D_STREAM 0x08
 #define D_FRAM 0x10
 #define D_PACK 0x20
-#define D_USBI 0x40
-#define D_USBO 0x80
+#define D_USBI 0x00
+#define D_USBO 0x00
 #define D_V4L2 0x0100
 #else
 #define PDEBUG(level, fmt, args...)
index 36dae38..1bd9c4b 100644 (file)
@@ -6,6 +6,9 @@
  *
  * Copyright (C) 2009 Theodore Kilgore
  *
+ * Sportscam DV15 support and control settings are
+ * Copyright (C) 2011 Patrice Chotard
+ *
  * 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
@@ -23,7 +26,6 @@
 
 #define MODULE_NAME "jeilinj"
 
-#include <linux/workqueue.h>
 #include <linux/slab.h>
 #include "gspca.h"
 #include "jpeg.h"
@@ -34,29 +36,51 @@ MODULE_LICENSE("GPL");
 
 /* Default timeouts, in ms */
 #define JEILINJ_CMD_TIMEOUT 500
+#define JEILINJ_CMD_DELAY 160
 #define JEILINJ_DATA_TIMEOUT 1000
 
 /* Maximum transfer size to use. */
 #define JEILINJ_MAX_TRANSFER 0x200
-
 #define FRAME_HEADER_LEN 0x10
+#define FRAME_START 0xFFFFFFFF
+
+enum {
+       SAKAR_57379,
+       SPORTSCAM_DV15,
+};
+
+#define CAMQUALITY_MIN 0       /* highest cam quality */
+#define CAMQUALITY_MAX 97      /* lowest cam quality  */
+
+enum e_ctrl {
+       LIGHTFREQ,
+       AUTOGAIN,
+       RED,
+       GREEN,
+       BLUE,
+       NCTRLS          /* number of controls */
+};
 
 /* Structure to hold all of our device specific stuff */
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
+       struct gspca_ctrl ctrls[NCTRLS];
+       int blocks_left;
        const struct v4l2_pix_format *cap_mode;
        /* Driver stuff */
-       struct work_struct work_struct;
-       struct workqueue_struct *work_thread;
+       u8 type;
        u8 quality;                              /* image quality */
-       u8 jpegqual;                            /* webcam quality */
+#define QUALITY_MIN 35
+#define QUALITY_MAX 85
+#define QUALITY_DEF 85
        u8 jpeg_hdr[JPEG_HDR_SZ];
 };
 
-       struct jlj_command {
-               unsigned char instruction[2];
-               unsigned char ack_wanted;
-       };
+struct jlj_command {
+       unsigned char instruction[2];
+       unsigned char ack_wanted;
+       unsigned char delay;
+};
 
 /* AFAICT these cameras will only do 320x240. */
 static struct v4l2_pix_format jlj_mode[] = {
@@ -64,6 +88,11 @@ static struct v4l2_pix_format jlj_mode[] = {
                .bytesperline = 320,
                .sizeimage = 320 * 240,
                .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 0},
+       { 640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480,
+               .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 0}
 };
 
@@ -73,178 +102,295 @@ static struct v4l2_pix_format jlj_mode[] = {
  */
 
 /* All commands are two bytes only */
-static int jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command)
+static void jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command)
 {
        int retval;
 
+       if (gspca_dev->usb_err < 0)
+               return;
        memcpy(gspca_dev->usb_buf, command, 2);
        retval = usb_bulk_msg(gspca_dev->dev,
                        usb_sndbulkpipe(gspca_dev->dev, 3),
                        gspca_dev->usb_buf, 2, NULL, 500);
-       if (retval < 0)
+       if (retval < 0) {
                err("command write [%02x] error %d",
                                gspca_dev->usb_buf[0], retval);
-       return retval;
+               gspca_dev->usb_err = retval;
+       }
 }
 
 /* Responses are one byte only */
-static int jlj_read1(struct gspca_dev *gspca_dev, unsigned char response)
+static void jlj_read1(struct gspca_dev *gspca_dev, unsigned char response)
 {
        int retval;
 
+       if (gspca_dev->usb_err < 0)
+               return;
        retval = usb_bulk_msg(gspca_dev->dev,
        usb_rcvbulkpipe(gspca_dev->dev, 0x84),
                                gspca_dev->usb_buf, 1, NULL, 500);
        response = gspca_dev->usb_buf[0];
-       if (retval < 0)
+       if (retval < 0) {
                err("read command [%02x] error %d",
                                gspca_dev->usb_buf[0], retval);
-       return retval;
+               gspca_dev->usb_err = retval;
+       }
 }
 
-static int jlj_start(struct gspca_dev *gspca_dev)
+static void setfreq(struct gspca_dev *gspca_dev)
 {
-       int i;
-       int retval = -1;
-       u8 response = 0xff;
-       struct jlj_command start_commands[] = {
-               {{0x71, 0x81}, 0},
-               {{0x70, 0x05}, 0},
-               {{0x95, 0x70}, 1},
-               {{0x71, 0x81}, 0},
-               {{0x70, 0x04}, 0},
-               {{0x95, 0x70}, 1},
-               {{0x71, 0x00}, 0},
-               {{0x70, 0x08}, 0},
-               {{0x95, 0x70}, 1},
-               {{0x94, 0x02}, 0},
-               {{0xde, 0x24}, 0},
-               {{0x94, 0x02}, 0},
-               {{0xdd, 0xf0}, 0},
-               {{0x94, 0x02}, 0},
-               {{0xe3, 0x2c}, 0},
-               {{0x94, 0x02}, 0},
-               {{0xe4, 0x00}, 0},
-               {{0x94, 0x02}, 0},
-               {{0xe5, 0x00}, 0},
-               {{0x94, 0x02}, 0},
-               {{0xe6, 0x2c}, 0},
-               {{0x94, 0x03}, 0},
-               {{0xaa, 0x00}, 0},
-               {{0x71, 0x1e}, 0},
-               {{0x70, 0x06}, 0},
-               {{0x71, 0x80}, 0},
-               {{0x70, 0x07}, 0}
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 freq_commands[][2] = {
+               {0x71, 0x80},
+               {0x70, 0x07}
        };
-       for (i = 0; i < ARRAY_SIZE(start_commands); i++) {
-               retval = jlj_write2(gspca_dev, start_commands[i].instruction);
-               if (retval < 0)
-                       return retval;
-               if (start_commands[i].ack_wanted)
-                       retval = jlj_read1(gspca_dev, response);
-               if (retval < 0)
-                       return retval;
-       }
-       PDEBUG(D_ERR, "jlj_start retval is %d", retval);
-       return retval;
+
+       freq_commands[0][1] |= (sd->ctrls[LIGHTFREQ].val >> 1);
+
+       jlj_write2(gspca_dev, freq_commands[0]);
+       jlj_write2(gspca_dev, freq_commands[1]);
 }
 
-static int jlj_stop(struct gspca_dev *gspca_dev)
+static void setcamquality(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 quality_commands[][2] = {
+               {0x71, 0x1E},
+               {0x70, 0x06}
+       };
+       u8 camquality;
+
+       /* adapt camera quality from jpeg quality */
+       camquality = ((QUALITY_MAX - sd->quality) * CAMQUALITY_MAX)
+               / (QUALITY_MAX - QUALITY_MIN);
+       quality_commands[0][1] += camquality;
+
+       jlj_write2(gspca_dev, quality_commands[0]);
+       jlj_write2(gspca_dev, quality_commands[1]);
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 autogain_commands[][2] = {
+               {0x94, 0x02},
+               {0xcf, 0x00}
+       };
+
+       autogain_commands[1][1] = (sd->ctrls[AUTOGAIN].val << 4);
+
+       jlj_write2(gspca_dev, autogain_commands[0]);
+       jlj_write2(gspca_dev, autogain_commands[1]);
+}
+
+static void setred(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 setred_commands[][2] = {
+               {0x94, 0x02},
+               {0xe6, 0x00}
+       };
+
+       setred_commands[1][1] = sd->ctrls[RED].val;
+
+       jlj_write2(gspca_dev, setred_commands[0]);
+       jlj_write2(gspca_dev, setred_commands[1]);
+}
+
+static void setgreen(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 setgreen_commands[][2] = {
+               {0x94, 0x02},
+               {0xe7, 0x00}
+       };
+
+       setgreen_commands[1][1] = sd->ctrls[GREEN].val;
+
+       jlj_write2(gspca_dev, setgreen_commands[0]);
+       jlj_write2(gspca_dev, setgreen_commands[1]);
+}
+
+static void setblue(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 setblue_commands[][2] = {
+               {0x94, 0x02},
+               {0xe9, 0x00}
+       };
+
+       setblue_commands[1][1] = sd->ctrls[BLUE].val;
+
+       jlj_write2(gspca_dev, setblue_commands[0]);
+       jlj_write2(gspca_dev, setblue_commands[1]);
+}
+
+static const struct ctrl sd_ctrls[NCTRLS] = {
+[LIGHTFREQ] = {
+           {
+               .id      = V4L2_CID_POWER_LINE_FREQUENCY,
+               .type    = V4L2_CTRL_TYPE_MENU,
+               .name    = "Light frequency filter",
+               .minimum = V4L2_CID_POWER_LINE_FREQUENCY_DISABLED, /* 1 */
+               .maximum = V4L2_CID_POWER_LINE_FREQUENCY_60HZ, /* 2 */
+               .step    = 1,
+               .default_value = V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
+           },
+           .set_control = setfreq
+       },
+[AUTOGAIN] = {
+           {
+               .id = V4L2_CID_AUTOGAIN,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Automatic Gain (and Exposure)",
+               .minimum = 0,
+               .maximum = 3,
+               .step = 1,
+#define AUTOGAIN_DEF 0
+               .default_value = AUTOGAIN_DEF,
+          },
+          .set_control = setautogain
+       },
+[RED] = {
+           {
+               .id = V4L2_CID_RED_BALANCE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "red balance",
+               .minimum = 0,
+               .maximum = 3,
+               .step = 1,
+#define RED_BALANCE_DEF 2
+               .default_value = RED_BALANCE_DEF,
+          },
+          .set_control = setred
+       },
+
+[GREEN]        = {
+           {
+               .id = V4L2_CID_GAIN,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "green balance",
+               .minimum = 0,
+               .maximum = 3,
+               .step = 1,
+#define GREEN_BALANCE_DEF 2
+               .default_value = GREEN_BALANCE_DEF,
+          },
+          .set_control = setgreen
+       },
+[BLUE] = {
+           {
+               .id = V4L2_CID_BLUE_BALANCE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "blue balance",
+               .minimum = 0,
+               .maximum = 3,
+               .step = 1,
+#define BLUE_BALANCE_DEF 2
+               .default_value = BLUE_BALANCE_DEF,
+          },
+          .set_control = setblue
+       },
+};
+
+static int jlj_start(struct gspca_dev *gspca_dev)
 {
        int i;
-       int retval;
-       struct jlj_command stop_commands[] = {
-               {{0x71, 0x00}, 0},
-               {{0x70, 0x09}, 0},
-               {{0x71, 0x80}, 0},
-               {{0x70, 0x05}, 0}
+       int start_commands_size;
+       u8 response = 0xff;
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct jlj_command start_commands[] = {
+               {{0x71, 0x81}, 0, 0},
+               {{0x70, 0x05}, 0, JEILINJ_CMD_DELAY},
+               {{0x95, 0x70}, 1, 0},
+               {{0x71, 0x81 - gspca_dev->curr_mode}, 0, 0},
+               {{0x70, 0x04}, 0, JEILINJ_CMD_DELAY},
+               {{0x95, 0x70}, 1, 0},
+               {{0x71, 0x00}, 0, 0},   /* start streaming ??*/
+               {{0x70, 0x08}, 0, JEILINJ_CMD_DELAY},
+               {{0x95, 0x70}, 1, 0},
+#define SPORTSCAM_DV15_CMD_SIZE 9
+               {{0x94, 0x02}, 0, 0},
+               {{0xde, 0x24}, 0, 0},
+               {{0x94, 0x02}, 0, 0},
+               {{0xdd, 0xf0}, 0, 0},
+               {{0x94, 0x02}, 0, 0},
+               {{0xe3, 0x2c}, 0, 0},
+               {{0x94, 0x02}, 0, 0},
+               {{0xe4, 0x00}, 0, 0},
+               {{0x94, 0x02}, 0, 0},
+               {{0xe5, 0x00}, 0, 0},
+               {{0x94, 0x02}, 0, 0},
+               {{0xe6, 0x2c}, 0, 0},
+               {{0x94, 0x03}, 0, 0},
+               {{0xaa, 0x00}, 0, 0}
        };
-       for (i = 0; i < ARRAY_SIZE(stop_commands); i++) {
-               retval = jlj_write2(gspca_dev, stop_commands[i].instruction);
-               if (retval < 0)
-                       return retval;
+
+       sd->blocks_left = 0;
+       /* Under Windows, USB spy shows that only the 9 first start
+        * commands are used for SPORTSCAM_DV15 webcam
+        */
+       if (sd->type == SPORTSCAM_DV15)
+               start_commands_size = SPORTSCAM_DV15_CMD_SIZE;
+       else
+               start_commands_size = ARRAY_SIZE(start_commands);
+
+       for (i = 0; i < start_commands_size; i++) {
+               jlj_write2(gspca_dev, start_commands[i].instruction);
+               if (start_commands[i].delay)
+                       msleep(start_commands[i].delay);
+               if (start_commands[i].ack_wanted)
+                       jlj_read1(gspca_dev, response);
        }
-       return retval;
+       setcamquality(gspca_dev);
+       msleep(2);
+       setfreq(gspca_dev);
+       if (gspca_dev->usb_err < 0)
+               PDEBUG(D_ERR, "Start streaming command failed");
+       return gspca_dev->usb_err;
 }
 
-/* This function is called as a workqueue function and runs whenever the camera
- * is streaming data. Because it is a workqueue function it is allowed to sleep
- * so we can use synchronous USB calls. To avoid possible collisions with other
- * threads attempting to use the camera's USB interface the gspca usb_lock is
- * used when performing the one USB control operation inside the workqueue,
- * which tells the camera to close the stream. In practice the only thing
- * which needs to be protected against is the usb_set_interface call that
- * gspca makes during stream_off. Otherwise the camera doesn't provide any
- * controls that the user could try to change.
- */
-
-static void jlj_dostream(struct work_struct *work)
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       u8 *data, int len)
 {
-       struct sd *dev = container_of(work, struct sd, work_struct);
-       struct gspca_dev *gspca_dev = &dev->gspca_dev;
-       int blocks_left; /* 0x200-sized blocks remaining in current frame. */
-       int act_len;
+       struct sd *sd = (struct sd *) gspca_dev;
        int packet_type;
-       int ret;
-       u8 *buffer;
+       u32 header_marker;
 
-       buffer = kmalloc(JEILINJ_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
-       if (!buffer) {
-               err("Couldn't allocate USB buffer");
-               goto quit_stream;
+       PDEBUG(D_STREAM, "Got %d bytes out of %d for Block 0",
+                       len, JEILINJ_MAX_TRANSFER);
+       if (len != JEILINJ_MAX_TRANSFER) {
+               PDEBUG(D_PACK, "bad length");
+               goto discard;
        }
-       while (gspca_dev->present && gspca_dev->streaming) {
-               /*
-                * Now request data block 0. Line 0 reports the size
-                * to download, in blocks of size 0x200, and also tells the
-                * "actual" data size, in bytes, which seems best to ignore.
-                */
-               ret = usb_bulk_msg(gspca_dev->dev,
-                               usb_rcvbulkpipe(gspca_dev->dev, 0x82),
-                               buffer, JEILINJ_MAX_TRANSFER, &act_len,
-                               JEILINJ_DATA_TIMEOUT);
-               PDEBUG(D_STREAM,
-                       "Got %d bytes out of %d for Block 0",
-                       act_len, JEILINJ_MAX_TRANSFER);
-               if (ret < 0 || act_len < FRAME_HEADER_LEN)
-                       goto quit_stream;
-               blocks_left = buffer[0x0a] - 1;
-               PDEBUG(D_STREAM, "blocks_left = 0x%x", blocks_left);
-
+       /* check if it's start of frame */
+       header_marker = ((u32 *)data)[0];
+       if (header_marker == FRAME_START) {
+               sd->blocks_left = data[0x0a] - 1;
+               PDEBUG(D_STREAM, "blocks_left = 0x%x", sd->blocks_left);
                /* Start a new frame, and add the JPEG header, first thing */
                gspca_frame_add(gspca_dev, FIRST_PACKET,
-                               dev->jpeg_hdr, JPEG_HDR_SZ);
+                               sd->jpeg_hdr, JPEG_HDR_SZ);
                /* Toss line 0 of data block 0, keep the rest. */
                gspca_frame_add(gspca_dev, INTER_PACKET,
-                               buffer + FRAME_HEADER_LEN,
+                               data + FRAME_HEADER_LEN,
                                JEILINJ_MAX_TRANSFER - FRAME_HEADER_LEN);
-
-               while (blocks_left > 0) {
-                       if (!gspca_dev->present)
-                               goto quit_stream;
-                       ret = usb_bulk_msg(gspca_dev->dev,
-                               usb_rcvbulkpipe(gspca_dev->dev, 0x82),
-                               buffer, JEILINJ_MAX_TRANSFER, &act_len,
-                               JEILINJ_DATA_TIMEOUT);
-                       if (ret < 0 || act_len < JEILINJ_MAX_TRANSFER)
-                               goto quit_stream;
-                       PDEBUG(D_STREAM,
-                               "%d blocks remaining for frame", blocks_left);
-                       blocks_left -= 1;
-                       if (blocks_left == 0)
-                               packet_type = LAST_PACKET;
-                       else
-                               packet_type = INTER_PACKET;
-                       gspca_frame_add(gspca_dev, packet_type,
-                                       buffer, JEILINJ_MAX_TRANSFER);
-               }
-       }
-quit_stream:
-       mutex_lock(&gspca_dev->usb_lock);
-       if (gspca_dev->present)
-               jlj_stop(gspca_dev);
-       mutex_unlock(&gspca_dev->usb_lock);
-       kfree(buffer);
+       } else if (sd->blocks_left > 0) {
+               PDEBUG(D_STREAM, "%d blocks remaining for frame",
+                               sd->blocks_left);
+               sd->blocks_left -= 1;
+               if (sd->blocks_left == 0)
+                       packet_type = LAST_PACKET;
+               else
+                       packet_type = INTER_PACKET;
+               gspca_frame_add(gspca_dev, packet_type,
+                               data, JEILINJ_MAX_TRANSFER);
+       } else
+               goto discard;
+       return;
+discard:
+       /* Discard data until a new frame starts. */
+       gspca_dev->last_packet_type = DISCARD_PACKET;
 }
 
 /* This function is called at probe time just before sd_init */
@@ -254,78 +400,169 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct cam *cam = &gspca_dev->cam;
        struct sd *dev  = (struct sd *) gspca_dev;
 
-       dev->quality  = 85;
-       dev->jpegqual = 85;
+       dev->type = id->driver_info;
+       gspca_dev->cam.ctrls = dev->ctrls;
+       dev->quality = QUALITY_DEF;
+       dev->ctrls[LIGHTFREQ].def = V4L2_CID_POWER_LINE_FREQUENCY_60HZ;
+       dev->ctrls[RED].def = RED_BALANCE_DEF;
+       dev->ctrls[GREEN].def = GREEN_BALANCE_DEF;
+       dev->ctrls[BLUE].def = BLUE_BALANCE_DEF;
        PDEBUG(D_PROBE,
                "JEILINJ camera detected"
                " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
        cam->cam_mode = jlj_mode;
-       cam->nmodes = 1;
+       cam->nmodes = ARRAY_SIZE(jlj_mode);
        cam->bulk = 1;
-       /* We don't use the buffer gspca allocates so make it small. */
-       cam->bulk_size = 32;
-       INIT_WORK(&dev->work_struct, jlj_dostream);
+       cam->bulk_nurbs = 1;
+       cam->bulk_size = JEILINJ_MAX_TRANSFER;
        return 0;
 }
 
-/* called on streamoff with alt==0 and on disconnect */
-/* the usb_lock is held at entry - restore on exit */
-static void sd_stop0(struct gspca_dev *gspca_dev)
+static void sd_stopN(struct gspca_dev *gspca_dev)
 {
-       struct sd *dev = (struct sd *) gspca_dev;
+       int i;
+       u8 *buf;
+       u8 stop_commands[][2] = {
+               {0x71, 0x00},
+               {0x70, 0x09},
+               {0x71, 0x80},
+               {0x70, 0x05}
+       };
+
+       for (;;) {
+               /* get the image remaining blocks */
+               usb_bulk_msg(gspca_dev->dev,
+                               gspca_dev->urb[0]->pipe,
+                               gspca_dev->urb[0]->transfer_buffer,
+                               JEILINJ_MAX_TRANSFER, NULL,
+                               JEILINJ_DATA_TIMEOUT);
+
+               /* search for 0xff 0xd9  (EOF for JPEG) */
+               i = 0;
+               buf = gspca_dev->urb[0]->transfer_buffer;
+               while ((i < (JEILINJ_MAX_TRANSFER - 1)) &&
+                       ((buf[i] != 0xff) || (buf[i+1] != 0xd9)))
+                       i++;
 
-       /* wait for the work queue to terminate */
-       mutex_unlock(&gspca_dev->usb_lock);
-       /* This waits for jlj_dostream to finish */
-       destroy_workqueue(dev->work_thread);
-       dev->work_thread = NULL;
-       mutex_lock(&gspca_dev->usb_lock);
+               if (i != (JEILINJ_MAX_TRANSFER - 1))
+                       /* last remaining block found */
+                       break;
+               }
+
+       for (i = 0; i < ARRAY_SIZE(stop_commands); i++)
+               jlj_write2(gspca_dev, stop_commands[i]);
 }
 
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
-       return 0;
+       return gspca_dev->usb_err;
 }
 
 /* Set up for getting frames. */
 static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *dev = (struct sd *) gspca_dev;
-       int ret;
 
        /* create the JPEG header */
        jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width,
                        0x21);          /* JPEG 422 */
        jpeg_set_qual(dev->jpeg_hdr, dev->quality);
-       PDEBUG(D_STREAM, "Start streaming at 320x240");
-       ret = jlj_start(gspca_dev);
-       if (ret < 0) {
-               PDEBUG(D_ERR, "Start streaming command failed");
-               return ret;
-       }
-       /* Start the workqueue function to do the streaming */
-       dev->work_thread = create_singlethread_workqueue(MODULE_NAME);
-       queue_work(dev->work_thread, &dev->work_struct);
-
-       return 0;
+       PDEBUG(D_STREAM, "Start streaming at %dx%d",
+               gspca_dev->height, gspca_dev->width);
+       jlj_start(gspca_dev);
+       return gspca_dev->usb_err;
 }
 
 /* Table of supported USB devices */
 static const struct usb_device_id device_table[] = {
-       {USB_DEVICE(0x0979, 0x0280)},
+       {USB_DEVICE(0x0979, 0x0280), .driver_info = SAKAR_57379},
+       {USB_DEVICE(0x0979, 0x0270), .driver_info = SPORTSCAM_DV15},
        {}
 };
 
 MODULE_DEVICE_TABLE(usb, device_table);
 
+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, "disable");
+                       return 0;
+               case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+                       strcpy((char *) menu->name, "50 Hz");
+                       return 0;
+               case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+                       strcpy((char *) menu->name, "60 Hz");
+                       return 0;
+               }
+               break;
+       }
+       return -EINVAL;
+}
+
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (jcomp->quality < QUALITY_MIN)
+               sd->quality = QUALITY_MIN;
+       else if (jcomp->quality > QUALITY_MAX)
+               sd->quality = QUALITY_MAX;
+       else
+               sd->quality = jcomp->quality;
+       if (gspca_dev->streaming) {
+               jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+               setcamquality(gspca_dev);
+       }
+       return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       memset(jcomp, 0, sizeof *jcomp);
+       jcomp->quality = sd->quality;
+       jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+                       | V4L2_JPEG_MARKER_DQT;
+       return 0;
+}
+
+
 /* sub-driver description */
-static const struct sd_desc sd_desc = {
+static const struct sd_desc sd_desc_sakar_57379 = {
        .name   = MODULE_NAME,
        .config = sd_config,
        .init   = sd_init,
        .start  = sd_start,
-       .stop0  = sd_stop0,
+       .stopN  = sd_stopN,
+       .pkt_scan = sd_pkt_scan,
+};
+
+/* sub-driver description */
+static const struct sd_desc sd_desc_sportscam_dv15 = {
+       .name   = MODULE_NAME,
+       .config = sd_config,
+       .init   = sd_init,
+       .start  = sd_start,
+       .stopN  = sd_stopN,
+       .pkt_scan = sd_pkt_scan,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .querymenu = sd_querymenu,
+       .get_jcomp = sd_get_jcomp,
+       .set_jcomp = sd_set_jcomp,
+};
+
+static const struct sd_desc *sd_desc[2] = {
+       &sd_desc_sakar_57379,
+       &sd_desc_sportscam_dv15
 };
 
 /* -- device connect -- */
@@ -333,7 +570,7 @@ static int sd_probe(struct usb_interface *intf,
                const struct usb_device_id *id)
 {
        return gspca_dev_probe(intf, id,
-                       &sd_desc,
+                       sd_desc[id->driver_info],
                        sizeof(struct sd),
                        THIS_MODULE);
 }
diff --git a/drivers/media/video/gspca/kinect.c b/drivers/media/video/gspca/kinect.c
new file mode 100644 (file)
index 0000000..66671a4
--- /dev/null
@@ -0,0 +1,429 @@
+/*
+ * kinect sensor device camera, gspca driver
+ *
+ * Copyright (C) 2011  Antonio Ospite <ospite@studenti.unina.it>
+ *
+ * Based on the OpenKinect project and libfreenect
+ * http://openkinect.org/wiki/Init_Analysis
+ *
+ * Special thanks to Steven Toth and kernellabs.com for sponsoring a Kinect
+ * sensor device which I tested the driver on.
+ *
+ * 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
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "kinect"
+
+#include "gspca.h"
+
+#define CTRL_TIMEOUT 500
+
+MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
+MODULE_DESCRIPTION("GSPCA/Kinect Sensor Device USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+#ifdef DEBUG
+int gspca_debug = D_ERR | D_PROBE | D_CONF | D_STREAM | D_FRAM | D_PACK |
+       D_USBI | D_USBO | D_V4L2;
+#endif
+
+struct pkt_hdr {
+       uint8_t magic[2];
+       uint8_t pad;
+       uint8_t flag;
+       uint8_t unk1;
+       uint8_t seq;
+       uint8_t unk2;
+       uint8_t unk3;
+       uint32_t timestamp;
+};
+
+struct cam_hdr {
+       uint8_t magic[2];
+       uint16_t len;
+       uint16_t cmd;
+       uint16_t tag;
+};
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev; /* !! must be the first item */
+       uint16_t cam_tag;           /* a sequence number for packets */
+       uint8_t stream_flag;        /* to identify different stream types */
+       uint8_t obuf[0x400];        /* output buffer for control commands */
+       uint8_t ibuf[0x200];        /* input buffer for control commands */
+};
+
+/* V4L2 controls supported by the driver */
+/* controls prototypes here */
+
+static const struct ctrl sd_ctrls[] = {
+};
+
+#define MODE_640x480   0x0001
+#define MODE_640x488   0x0002
+#define MODE_1280x1024 0x0004
+
+#define FORMAT_BAYER   0x0010
+#define FORMAT_UYVY    0x0020
+#define FORMAT_Y10B    0x0040
+
+#define FPS_HIGH       0x0100
+
+static const struct v4l2_pix_format video_camera_mode[] = {
+       {640, 480, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,
+        .bytesperline = 640,
+        .sizeimage = 640 * 480,
+        .colorspace = V4L2_COLORSPACE_SRGB,
+        .priv = MODE_640x480 | FORMAT_BAYER | FPS_HIGH},
+       {640, 480, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE,
+        .bytesperline = 640 * 2,
+        .sizeimage = 640 * 480 * 2,
+        .colorspace = V4L2_COLORSPACE_SRGB,
+        .priv = MODE_640x480 | FORMAT_UYVY},
+       {1280, 1024, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,
+        .bytesperline = 1280,
+        .sizeimage = 1280 * 1024,
+        .colorspace = V4L2_COLORSPACE_SRGB,
+        .priv = MODE_1280x1024 | FORMAT_BAYER},
+       {640, 488, V4L2_PIX_FMT_Y10BPACK, V4L2_FIELD_NONE,
+        .bytesperline = 640 * 10 / 8,
+        .sizeimage =  640 * 488 * 10 / 8,
+        .colorspace = V4L2_COLORSPACE_SRGB,
+        .priv = MODE_640x488 | FORMAT_Y10B | FPS_HIGH},
+       {1280, 1024, V4L2_PIX_FMT_Y10BPACK, V4L2_FIELD_NONE,
+        .bytesperline = 1280 * 10 / 8,
+        .sizeimage =  1280 * 1024 * 10 / 8,
+        .colorspace = V4L2_COLORSPACE_SRGB,
+        .priv = MODE_1280x1024 | FORMAT_Y10B},
+};
+
+static int kinect_write(struct usb_device *udev, uint8_t *data,
+                       uint16_t wLength)
+{
+       return usb_control_msg(udev,
+                             usb_sndctrlpipe(udev, 0),
+                             0x00,
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             0, 0, data, wLength, CTRL_TIMEOUT);
+}
+
+static int kinect_read(struct usb_device *udev, uint8_t *data, uint16_t wLength)
+{
+       return usb_control_msg(udev,
+                             usb_rcvctrlpipe(udev, 0),
+                             0x00,
+                             USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             0, 0, data, wLength, CTRL_TIMEOUT);
+}
+
+static int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf,
+               unsigned int cmd_len, void *replybuf, unsigned int reply_len)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *udev = gspca_dev->dev;
+       int res, actual_len;
+       uint8_t *obuf = sd->obuf;
+       uint8_t *ibuf = sd->ibuf;
+       struct cam_hdr *chdr = (void *)obuf;
+       struct cam_hdr *rhdr = (void *)ibuf;
+
+       if (cmd_len & 1 || cmd_len > (0x400 - sizeof(*chdr))) {
+               err("send_cmd: Invalid command length (0x%x)", cmd_len);
+               return -1;
+       }
+
+       chdr->magic[0] = 0x47;
+       chdr->magic[1] = 0x4d;
+       chdr->cmd = cpu_to_le16(cmd);
+       chdr->tag = cpu_to_le16(sd->cam_tag);
+       chdr->len = cpu_to_le16(cmd_len / 2);
+
+       memcpy(obuf+sizeof(*chdr), cmdbuf, cmd_len);
+
+       res = kinect_write(udev, obuf, cmd_len + sizeof(*chdr));
+       PDEBUG(D_USBO, "Control cmd=%04x tag=%04x len=%04x: %d", cmd,
+               sd->cam_tag, cmd_len, res);
+       if (res < 0) {
+               err("send_cmd: Output control transfer failed (%d)", res);
+               return res;
+       }
+
+       do {
+               actual_len = kinect_read(udev, ibuf, 0x200);
+       } while (actual_len == 0);
+       PDEBUG(D_USBO, "Control reply: %d", res);
+       if (actual_len < sizeof(*rhdr)) {
+               err("send_cmd: Input control transfer failed (%d)", res);
+               return res;
+       }
+       actual_len -= sizeof(*rhdr);
+
+       if (rhdr->magic[0] != 0x52 || rhdr->magic[1] != 0x42) {
+               err("send_cmd: Bad magic %02x %02x", rhdr->magic[0],
+                       rhdr->magic[1]);
+               return -1;
+       }
+       if (rhdr->cmd != chdr->cmd) {
+               err("send_cmd: Bad cmd %02x != %02x", rhdr->cmd, chdr->cmd);
+               return -1;
+       }
+       if (rhdr->tag != chdr->tag) {
+               err("send_cmd: Bad tag %04x != %04x", rhdr->tag, chdr->tag);
+               return -1;
+       }
+       if (cpu_to_le16(rhdr->len) != (actual_len/2)) {
+               err("send_cmd: Bad len %04x != %04x",
+                               cpu_to_le16(rhdr->len), (int)(actual_len/2));
+               return -1;
+       }
+
+       if (actual_len > reply_len) {
+               warn("send_cmd: Data buffer is %d bytes long, but got %d bytes",
+                               reply_len, actual_len);
+               memcpy(replybuf, ibuf+sizeof(*rhdr), reply_len);
+       } else {
+               memcpy(replybuf, ibuf+sizeof(*rhdr), actual_len);
+       }
+
+       sd->cam_tag++;
+
+       return actual_len;
+}
+
+static int write_register(struct gspca_dev *gspca_dev, uint16_t reg,
+                       uint16_t data)
+{
+       uint16_t reply[2];
+       uint16_t cmd[2];
+       int res;
+
+       cmd[0] = cpu_to_le16(reg);
+       cmd[1] = cpu_to_le16(data);
+
+       PDEBUG(D_USBO, "Write Reg 0x%04x <= 0x%02x", reg, data);
+       res = send_cmd(gspca_dev, 0x03, cmd, 4, reply, 4);
+       if (res < 0)
+               return res;
+       if (res != 2) {
+               warn("send_cmd returned %d [%04x %04x], 0000 expected",
+                               res, reply[0], reply[1]);
+       }
+       return 0;
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                    const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct cam *cam;
+
+       sd->cam_tag = 0;
+
+       /* Only video stream is supported for now,
+        * which has stream flag = 0x80 */
+       sd->stream_flag = 0x80;
+
+       cam = &gspca_dev->cam;
+
+       cam->cam_mode = video_camera_mode;
+       cam->nmodes = ARRAY_SIZE(video_camera_mode);
+
+#if 0
+       /* Setting those values is not needed for video stream */
+       cam->npkt = 15;
+       gspca_dev->pkt_size = 960 * 2;
+#endif
+
+       return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+       PDEBUG(D_PROBE, "Kinect Camera device.");
+
+       return 0;
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+       int mode;
+       uint8_t fmt_reg, fmt_val;
+       uint8_t res_reg, res_val;
+       uint8_t fps_reg, fps_val;
+       uint8_t mode_val;
+
+       mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+
+       if (mode & FORMAT_Y10B) {
+               fmt_reg = 0x19;
+               res_reg = 0x1a;
+               fps_reg = 0x1b;
+               mode_val = 0x03;
+       } else {
+               fmt_reg = 0x0c;
+               res_reg = 0x0d;
+               fps_reg = 0x0e;
+               mode_val = 0x01;
+       }
+
+       /* format */
+       if (mode & FORMAT_UYVY)
+               fmt_val = 0x05;
+       else
+               fmt_val = 0x00;
+
+       if (mode & MODE_1280x1024)
+               res_val = 0x02;
+       else
+               res_val = 0x01;
+
+       if (mode & FPS_HIGH)
+               fps_val = 0x1e;
+       else
+               fps_val = 0x0f;
+
+
+       /* turn off IR-reset function */
+       write_register(gspca_dev, 0x105, 0x00);
+
+       /* Reset video stream */
+       write_register(gspca_dev, 0x05, 0x00);
+
+       /* Due to some ridiculous condition in the firmware, we have to start
+        * and stop the depth stream before the camera will hand us 1280x1024
+        * IR.  This is a stupid workaround, but we've yet to find a better
+        * solution.
+        *
+        * Thanks to Drew Fisher for figuring this out.
+        */
+       if (mode & (FORMAT_Y10B | MODE_1280x1024)) {
+               write_register(gspca_dev, 0x13, 0x01);
+               write_register(gspca_dev, 0x14, 0x1e);
+               write_register(gspca_dev, 0x06, 0x02);
+               write_register(gspca_dev, 0x06, 0x00);
+       }
+
+       write_register(gspca_dev, fmt_reg, fmt_val);
+       write_register(gspca_dev, res_reg, res_val);
+       write_register(gspca_dev, fps_reg, fps_val);
+
+       /* Start video stream */
+       write_register(gspca_dev, 0x05, mode_val);
+
+       /* disable Hflip */
+       write_register(gspca_dev, 0x47, 0x00);
+
+       return 0;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       /* reset video stream */
+       write_register(gspca_dev, 0x05, 0x00);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *__data, int len)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       struct pkt_hdr *hdr = (void *)__data;
+       uint8_t *data = __data + sizeof(*hdr);
+       int datalen = len - sizeof(*hdr);
+
+       uint8_t sof = sd->stream_flag | 1;
+       uint8_t mof = sd->stream_flag | 2;
+       uint8_t eof = sd->stream_flag | 5;
+
+       if (len < 12)
+               return;
+
+       if (hdr->magic[0] != 'R' || hdr->magic[1] != 'B') {
+               warn("[Stream %02x] Invalid magic %02x%02x", sd->stream_flag,
+                               hdr->magic[0], hdr->magic[1]);
+               return;
+       }
+
+       if (hdr->flag == sof)
+               gspca_frame_add(gspca_dev, FIRST_PACKET, data, datalen);
+
+       else if (hdr->flag == mof)
+               gspca_frame_add(gspca_dev, INTER_PACKET, data, datalen);
+
+       else if (hdr->flag == eof)
+               gspca_frame_add(gspca_dev, LAST_PACKET, data, datalen);
+
+       else
+               warn("Packet type not recognized...");
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+       .name      = MODULE_NAME,
+       .ctrls     = sd_ctrls,
+       .nctrls    = ARRAY_SIZE(sd_ctrls),
+       .config    = sd_config,
+       .init      = sd_init,
+       .start     = sd_start,
+       .stopN     = sd_stopN,
+       .pkt_scan  = sd_pkt_scan,
+       /*
+       .querymenu = sd_querymenu,
+       .get_streamparm = sd_get_streamparm,
+       .set_streamparm = sd_set_streamparm,
+       */
+};
+
+/* -- module initialisation -- */
+static const struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x045e, 0x02ae)},
+       {}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                               THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name       = MODULE_NAME,
+       .id_table   = device_table,
+       .probe      = sd_probe,
+       .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend    = gspca_suspend,
+       .resume     = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       return usb_register(&sd_driver);
+}
+
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
index 41dce49..9d0b460 100644 (file)
@@ -1375,7 +1375,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
 {
        struct sd *sd = (struct sd *) gspca_dev;
        struct cam *cam;
-       int data1, data2;
        const u16 (*init_data)[2];
        static const u16 (*(init_data_tb[]))[2] = {
                spca508_vista_init_data,        /* CreativeVista 0 */
@@ -1386,6 +1385,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
                spca508_init_data,              /* ViewQuestVQ110 5 */
        };
 
+#ifdef GSPCA_DEBUG
+       int data1, data2;
+
        /* Read from global register the USB product and vendor IDs, just to
         * prove that we can communicate with the device.  This works, which
         * confirms at we are communicating properly and that the device
@@ -1400,6 +1402,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
        data1 = reg_read(gspca_dev, 0x8621);
        PDEBUG(D_PROBE, "Window 1 average luminance: %d", data1);
+#endif
 
        cam = &gspca_dev->cam;
        cam->cam_mode = sif_mode;
index 87be52b..7637477 100644 (file)
@@ -436,17 +436,14 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 static int sd_querymenu(struct gspca_dev *gspca_dev,
                        struct v4l2_querymenu *menu)
 {
+       static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"};
+
        switch (menu->id) {
        case V4L2_CID_POWER_LINE_FREQUENCY:
-               switch (menu->index) {
-               case 1:         /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
-                       strcpy((char *) menu->name, "50 Hz");
-                       return 0;
-               case 2:         /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
-                       strcpy((char *) menu->name, "60 Hz");
-                       return 0;
-               }
-               break;
+               if ((unsigned) menu->index >= ARRAY_SIZE(freq_nm))
+                       break;
+               strcpy((char *) menu->name, freq_nm[menu->index]);
+               return 0;
        }
        return -EINVAL;
 }
index ac47b4c..75a5b9c 100644 (file)
@@ -217,6 +217,8 @@ static int pb0100_start(struct sd *sd)
 
        intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
        alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
+       if (!alt)
+               return -ENODEV;
        packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
 
        /* If we don't have enough bandwidth use a lower framerate */
index 543542a..b089c0d 100644 (file)
@@ -396,57 +396,6 @@ static void reg_w_riv(struct gspca_dev *gspca_dev,
                req, index, value);
 }
 
-/* read 1 byte */
-static u8 reg_r_1(struct gspca_dev *gspca_dev,
-                       u16 value)      /* wValue */
-{
-       int ret;
-
-       if (gspca_dev->usb_err < 0)
-               return 0;
-       ret = usb_control_msg(gspca_dev->dev,
-                       usb_rcvctrlpipe(gspca_dev->dev, 0),
-                       0x20,                   /* request */
-                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       value,
-                       0,                      /* index */
-                       gspca_dev->usb_buf, 1,
-                       500);                   /* timeout */
-       if (ret < 0) {
-               err("reg_r_1 err %d", ret);
-               gspca_dev->usb_err = ret;
-               return 0;
-       }
-       return gspca_dev->usb_buf[0];
-}
-
-/* read 1 or 2 bytes */
-static u16 reg_r_12(struct gspca_dev *gspca_dev,
-                       u8 req,         /* bRequest */
-                       u16 index,      /* wIndex */
-                       u16 length)     /* wLength (1 or 2 only) */
-{
-       int ret;
-
-       if (gspca_dev->usb_err < 0)
-               return 0;
-       gspca_dev->usb_buf[1] = 0;
-       ret = usb_control_msg(gspca_dev->dev,
-                       usb_rcvctrlpipe(gspca_dev->dev, 0),
-                       req,
-                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       0,              /* value */
-                       index,
-                       gspca_dev->usb_buf, length,
-                       500);
-       if (ret < 0) {
-               err("reg_r_12 err %d", ret);
-               gspca_dev->usb_err = ret;
-               return 0;
-       }
-       return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
-}
-
 static void write_vector(struct gspca_dev *gspca_dev,
                        const struct cmd *data, int ncmds)
 {
@@ -473,44 +422,46 @@ static void setup_qtable(struct gspca_dev *gspca_dev,
 static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
                             u8 req, u16 idx, u16 val)
 {
-       u16 notdone;
-
        reg_w_riv(gspca_dev, req, idx, val);
-       notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
+       reg_r(gspca_dev, 0x01, 0x0001, 1);
+       PDEBUG(D_FRAM, "before wait 0x%04x", gspca_dev->usb_buf[0]);
        reg_w_riv(gspca_dev, req, idx, val);
 
-       PDEBUG(D_FRAM, "before wait 0x%04x", notdone);
-
        msleep(200);
-       notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
-       PDEBUG(D_FRAM, "after wait 0x%04x", notdone);
+       reg_r(gspca_dev, 0x01, 0x0001, 1);
+       PDEBUG(D_FRAM, "after wait 0x%04x", gspca_dev->usb_buf[0]);
 }
 
+#ifdef GSPCA_DEBUG
 static void spca504_read_info(struct gspca_dev *gspca_dev)
 {
        int i;
        u8 info[6];
 
-       for (i = 0; i < 6; i++)
-               info[i] = reg_r_1(gspca_dev, i);
+       for (i = 0; i < 6; i++) {
+               reg_r(gspca_dev, 0, i, 1);
+               info[i] = gspca_dev->usb_buf[0];
+       }
        PDEBUG(D_STREAM,
                "Read info: %d %d %d %d %d %d."
                " Should be 1,0,2,2,0,0",
                info[0], info[1], info[2],
                info[3], info[4], info[5]);
 }
+#endif
 
 static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
                        u8 req,
-                       u16 idx, u16 val, u16 endcode, u8 count)
+                       u16 idx, u16 val, u8 endcode, u8 count)
 {
        u16 status;
 
        reg_w_riv(gspca_dev, req, idx, val);
-       status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
+       reg_r(gspca_dev, 0x01, 0x0001, 1);
        if (gspca_dev->usb_err < 0)
                return;
-       PDEBUG(D_FRAM, "Status 0x%04x Need 0x%04x", status, endcode);
+       PDEBUG(D_FRAM, "Status 0x%02x Need 0x%02x",
+                       gspca_dev->usb_buf[0], endcode);
        if (!count)
                return;
        count = 200;
@@ -518,7 +469,8 @@ static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
                msleep(10);
                /* gsmart mini2 write a each wait setting 1 ms is enough */
 /*             reg_w_riv(gspca_dev, req, idx, val); */
-               status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
+               reg_r(gspca_dev, 0x01, 0x0001, 1);
+               status = gspca_dev->usb_buf[0];
                if (status == endcode) {
                        PDEBUG(D_FRAM, "status 0x%04x after wait %d",
                                status, 200 - count);
@@ -555,17 +507,19 @@ static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
        }
 }
 
+#ifdef GSPCA_DEBUG
 static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
 {
        u8 *data;
 
        data = gspca_dev->usb_buf;
        reg_r(gspca_dev, 0x20, 0, 5);
-       PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ",
+       PDEBUG(D_STREAM, "FirmWare: %d %d %d %d %d",
                data[0], data[1], data[2], data[3], data[4]);
        reg_r(gspca_dev, 0x23, 0, 64);
        reg_r(gspca_dev, 0x23, 1, 64);
 }
+#endif
 
 static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
 {
@@ -578,7 +532,9 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
                reg_w_riv(gspca_dev, 0x31, 0, 0);
                spca504B_WaitCmdStatus(gspca_dev);
                spca504B_PollingDataReady(gspca_dev);
+#ifdef GSPCA_DEBUG
                spca50x_GetFirmware(gspca_dev);
+#endif
                reg_w_1(gspca_dev, 0x24, 0, 8, 2);              /* type */
                reg_r(gspca_dev, 0x24, 8, 1);
 
@@ -628,7 +584,8 @@ static void spca504_wait_status(struct gspca_dev *gspca_dev)
        cnt = 256;
        while (--cnt > 0) {
                /* With this we get the status, when return 0 it's all ok */
-               if (reg_r_12(gspca_dev, 0x06, 0x00, 1) == 0)
+               reg_r(gspca_dev, 0x06, 0x00, 1);
+               if (gspca_dev->usb_buf[0] == 0)
                        return;
                msleep(10);
        }
@@ -772,10 +729,14 @@ static int sd_init(struct gspca_dev *gspca_dev)
                /* fall thru */
        case BRIDGE_SPCA533:
                spca504B_PollingDataReady(gspca_dev);
+#ifdef GSPCA_DEBUG
                spca50x_GetFirmware(gspca_dev);
+#endif
                break;
        case BRIDGE_SPCA536:
+#ifdef GSPCA_DEBUG
                spca50x_GetFirmware(gspca_dev);
+#endif
                reg_r(gspca_dev, 0x00, 0x5002, 1);
                reg_w_1(gspca_dev, 0x24, 0, 0, 0);
                reg_r(gspca_dev, 0x24, 0, 1);
@@ -801,7 +762,9 @@ static int sd_init(struct gspca_dev *gspca_dev)
 /*     case BRIDGE_SPCA504: */
                PDEBUG(D_STREAM, "Opening SPCA504");
                if (sd->subtype == AiptekMiniPenCam13) {
+#ifdef GSPCA_DEBUG
                        spca504_read_info(gspca_dev);
+#endif
 
                        /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
                        spca504A_acknowledged_command(gspca_dev, 0x24,
@@ -873,7 +836,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
                break;
        case BRIDGE_SPCA504:
                if (sd->subtype == AiptekMiniPenCam13) {
+#ifdef GSPCA_DEBUG
                        spca504_read_info(gspca_dev);
+#endif
 
                        /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
                        spca504A_acknowledged_command(gspca_dev, 0x24,
@@ -885,7 +850,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
                                                        0, 0, 0x9d, 1);
                } else {
                        spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
+#ifdef GSPCA_DEBUG
                        spca504_read_info(gspca_dev);
+#endif
                        spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
                        spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
                }
index a3eccd8..7e762d5 100644 (file)
@@ -92,8 +92,6 @@ static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_geteffect(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[] = {
        {
@@ -1379,17 +1377,14 @@ static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val)
 static int sd_querymenu(struct gspca_dev *gspca_dev,
                        struct v4l2_querymenu *menu)
 {
+       static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"};
+
        switch (menu->id) {
        case V4L2_CID_POWER_LINE_FREQUENCY:
-               switch (menu->index) {
-               case 1:         /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
-                       strcpy((char *) menu->name, "50 Hz");
-                       return 0;
-               case 2:         /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
-                       strcpy((char *) menu->name, "60 Hz");
-                       return 0;
-               }
-               break;
+               if ((unsigned) menu->index >= ARRAY_SIZE(freq_nm))
+                       break;
+               strcpy((char *) menu->name, freq_nm[menu->index]);
+               return 0;
        case V4L2_CID_EFFECTS:
                if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) {
                        strncpy((char *) menu->name,
index fa164e8..61cdd56 100644 (file)
@@ -3065,15 +3065,10 @@ static const struct usb_action mc501cb_InitialScale[] = {       /* 320x240 */
        {0xaa, 0x55, 0x0010}, /* 00,55,10,aa */
        {0xa0, 0xf0, 0x0199}, /* 01,99,F0,cc */
        {0xa0, 0x80, 0x019a}, /* 01,9A,80,cc */
-       {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
-       {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
-       {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */
-       {0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */
-       {0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */
        {}
 };
 
-static const struct usb_action mc501cb_50HZScale[] = {
+static const struct usb_action mc501cb_50HZ[] = {
        {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
        {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
        {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */
@@ -3082,15 +3077,10 @@ static const struct usb_action mc501cb_50HZScale[] = {
        {0xaa, 0x3c, 0x004c}, /* 00,3C,4C,aa */
        {0xaa, 0x3d, 0x001d}, /* 00,3D,1D,aa */
        {0xaa, 0x3e, 0x004c}, /* 00,3E,4C,aa */
-       {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
-       {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
-       {0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */
-       {0xaa, 0x37, 0x0098}, /* 00,37,98,aa */
-       {0xaa, 0x3b, 0x003a}, /* 00,3B,3A,aa */
        {}
 };
 
-static const struct usb_action mc501cb_50HZ[] = {
+static const struct usb_action mc501cb_50HZScale[] = {
        {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
        {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
        {0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */
@@ -3099,15 +3089,10 @@ static const struct usb_action mc501cb_50HZ[] = {
        {0xaa, 0x3c, 0x0098}, /* 00,3C,98,aa */
        {0xaa, 0x3d, 0x003a}, /* 00,3D,3A,aa */
        {0xaa, 0x3e, 0x0098}, /* 00,3E,98,aa */
-       {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
-       {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
-       {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
-       {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */
-       {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */
        {}
 };
 
-static const struct usb_action mc501cb_60HZScale[] = {
+static const struct usb_action mc501cb_60HZ[] = {
        {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
        {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
        {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
@@ -3116,15 +3101,10 @@ static const struct usb_action mc501cb_60HZScale[] = {
        {0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */
        {0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */
        {0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */
-       {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
-       {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
-       {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
-       {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */
-       {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */
        {}
 };
 
-static const struct usb_action mc501cb_60HZ[] = {
+static const struct usb_action mc501cb_60HZScale[] = {
        {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
        {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
        {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
@@ -3133,15 +3113,10 @@ static const struct usb_action mc501cb_60HZ[] = {
        {0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */
        {0xaa, 0x3b, 0x0030}, /* 00,3B,30,aa */
        {0xaa, 0x3c, 0x00d4}, /* 00,3C,D4,aa */
-       {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
-       {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
-       {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
-       {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */
-       {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */
        {}
 };
 
-static const struct usb_action mc501cb_NoFlikerScale[] = {
+static const struct usb_action mc501cb_NoFliker[] = {
        {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
        {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
        {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
@@ -3150,15 +3125,10 @@ static const struct usb_action mc501cb_NoFlikerScale[] = {
        {0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */
        {0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */
        {0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */
-       {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
-       {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
-       {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
-       {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */
-       {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */
        {}
 };
 
-static const struct usb_action mc501cb_NoFliker[] = {
+static const struct usb_action mc501cb_NoFlikerScale[] = {
        {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
        {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
        {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
@@ -6296,7 +6266,6 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        int i;
-       u8 retbyte;
        u16 retword;
 
 /*fixme: lack of 8b=b3 (11,12)-> 10, 8b=e0 (14,15,16)-> 12 found in gspcav1*/
@@ -6389,8 +6358,12 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
        retword |= i2c_read(gspca_dev, 0x01);           /* ID 1 */
        PDEBUG(D_PROBE, "probe 3wr vga 2 0x%04x", retword);
        if (retword == 0x2030) {
+#ifdef GSPCA_DEBUG
+               u8 retbyte;
+
                retbyte = i2c_read(gspca_dev, 0x02);    /* revision number */
                PDEBUG(D_PROBE, "sensor PO2030 rev 0x%02x", retbyte);
+#endif
                send_unknown(gspca_dev, SENSOR_PO2030);
                return retword;
        }
index 3994642..a4e4dfd 100644 (file)
@@ -810,7 +810,6 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev,
                          const struct pci_device_id *pci_id)
 {
        u16 cmd;
-       u8 card_rev;
        unsigned char pci_latency;
 
        IVTV_DEBUG_INFO("Enabling pci device\n");
@@ -857,7 +856,6 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev,
        }
        IVTV_DEBUG_INFO("Bus Mastering Enabled.\n");
 
-       pci_read_config_byte(pdev, PCI_CLASS_REVISION, &card_rev);
        pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
 
        if (pci_latency < 64 && ivtv_pci_latency) {
@@ -874,7 +872,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev,
 
        IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, "
                   "irq: %d, latency: %d, memory: 0x%lx\n",
-                  pdev->device, card_rev, pdev->bus->number,
+                  pdev->device, pdev->revision, pdev->bus->number,
                   PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
                   pdev->irq, pci_latency, (unsigned long)itv->base_addr);
 
index 53fa2a7..ebebed9 100644 (file)
@@ -315,10 +315,20 @@ static int mt9m111_setup_rect(struct i2c_client *client,
 static int mt9m111_setup_pixfmt(struct i2c_client *client, u16 outfmt)
 {
        int ret;
+       u16 mask = MT9M111_OUTFMT_PROCESSED_BAYER | MT9M111_OUTFMT_RGB |
+               MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_SWAP_RGB_EVEN |
+               MT9M111_OUTFMT_RGB565 | MT9M111_OUTFMT_RGB555 |
+               MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr |
+               MT9M111_OUTFMT_SWAP_YCbCr_C_Y;
 
-       ret = reg_write(OUTPUT_FORMAT_CTRL2_A, outfmt);
+       ret = reg_read(OUTPUT_FORMAT_CTRL2_A);
+       if (ret >= 0)
+               ret = reg_write(OUTPUT_FORMAT_CTRL2_A, (ret & ~mask) | outfmt);
        if (!ret)
-               ret = reg_write(OUTPUT_FORMAT_CTRL2_B, outfmt);
+               ret = reg_read(OUTPUT_FORMAT_CTRL2_B);
+       if (ret >= 0)
+               ret = reg_write(OUTPUT_FORMAT_CTRL2_B, (ret & ~mask) | outfmt);
+
        return ret;
 }
 
index e313d83..fc76ed1 100644 (file)
@@ -228,7 +228,7 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
 
        flags = soc_camera_apply_sensor_flags(icl, flags);
 
-       if (flags & SOCAM_PCLK_SAMPLE_RISING)
+       if (flags & SOCAM_PCLK_SAMPLE_FALLING)
                pixclk |= 0x10;
 
        if (!(flags & SOCAM_HSYNC_ACTIVE_HIGH))
diff --git a/drivers/media/video/mt9v032.c b/drivers/media/video/mt9v032.c
new file mode 100644 (file)
index 0000000..1319c2c
--- /dev/null
@@ -0,0 +1,773 @@
+/*
+ * Driver for MT9V032 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2010, Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * Based on the MT9M001 driver,
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.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/delay.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-mediabus.h>
+
+#include <media/mt9v032.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#define MT9V032_PIXEL_ARRAY_HEIGHT                     492
+#define MT9V032_PIXEL_ARRAY_WIDTH                      782
+
+#define MT9V032_CHIP_VERSION                           0x00
+#define                MT9V032_CHIP_ID_REV1                    0x1311
+#define                MT9V032_CHIP_ID_REV3                    0x1313
+#define MT9V032_ROW_START                              0x01
+#define                MT9V032_ROW_START_MIN                   4
+#define                MT9V032_ROW_START_DEF                   10
+#define                MT9V032_ROW_START_MAX                   482
+#define MT9V032_COLUMN_START                           0x02
+#define                MT9V032_COLUMN_START_MIN                1
+#define                MT9V032_COLUMN_START_DEF                2
+#define                MT9V032_COLUMN_START_MAX                752
+#define MT9V032_WINDOW_HEIGHT                          0x03
+#define                MT9V032_WINDOW_HEIGHT_MIN               1
+#define                MT9V032_WINDOW_HEIGHT_DEF               480
+#define                MT9V032_WINDOW_HEIGHT_MAX               480
+#define MT9V032_WINDOW_WIDTH                           0x04
+#define                MT9V032_WINDOW_WIDTH_MIN                1
+#define                MT9V032_WINDOW_WIDTH_DEF                752
+#define                MT9V032_WINDOW_WIDTH_MAX                752
+#define MT9V032_HORIZONTAL_BLANKING                    0x05
+#define                MT9V032_HORIZONTAL_BLANKING_MIN         43
+#define                MT9V032_HORIZONTAL_BLANKING_MAX         1023
+#define MT9V032_VERTICAL_BLANKING                      0x06
+#define                MT9V032_VERTICAL_BLANKING_MIN           4
+#define                MT9V032_VERTICAL_BLANKING_MAX           3000
+#define MT9V032_CHIP_CONTROL                           0x07
+#define                MT9V032_CHIP_CONTROL_MASTER_MODE        (1 << 3)
+#define                MT9V032_CHIP_CONTROL_DOUT_ENABLE        (1 << 7)
+#define                MT9V032_CHIP_CONTROL_SEQUENTIAL         (1 << 8)
+#define MT9V032_SHUTTER_WIDTH1                         0x08
+#define MT9V032_SHUTTER_WIDTH2                         0x09
+#define MT9V032_SHUTTER_WIDTH_CONTROL                  0x0a
+#define MT9V032_TOTAL_SHUTTER_WIDTH                    0x0b
+#define                MT9V032_TOTAL_SHUTTER_WIDTH_MIN         1
+#define                MT9V032_TOTAL_SHUTTER_WIDTH_DEF         480
+#define                MT9V032_TOTAL_SHUTTER_WIDTH_MAX         32767
+#define MT9V032_RESET                                  0x0c
+#define MT9V032_READ_MODE                              0x0d
+#define                MT9V032_READ_MODE_ROW_BIN_MASK          (3 << 0)
+#define                MT9V032_READ_MODE_ROW_BIN_SHIFT         0
+#define                MT9V032_READ_MODE_COLUMN_BIN_MASK       (3 << 2)
+#define                MT9V032_READ_MODE_COLUMN_BIN_SHIFT      2
+#define                MT9V032_READ_MODE_ROW_FLIP              (1 << 4)
+#define                MT9V032_READ_MODE_COLUMN_FLIP           (1 << 5)
+#define                MT9V032_READ_MODE_DARK_COLUMNS          (1 << 6)
+#define                MT9V032_READ_MODE_DARK_ROWS             (1 << 7)
+#define MT9V032_PIXEL_OPERATION_MODE                   0x0f
+#define                MT9V032_PIXEL_OPERATION_MODE_COLOR      (1 << 2)
+#define                MT9V032_PIXEL_OPERATION_MODE_HDR        (1 << 6)
+#define MT9V032_ANALOG_GAIN                            0x35
+#define                MT9V032_ANALOG_GAIN_MIN                 16
+#define                MT9V032_ANALOG_GAIN_DEF                 16
+#define                MT9V032_ANALOG_GAIN_MAX                 64
+#define MT9V032_MAX_ANALOG_GAIN                                0x36
+#define                MT9V032_MAX_ANALOG_GAIN_MAX             127
+#define MT9V032_FRAME_DARK_AVERAGE                     0x42
+#define MT9V032_DARK_AVG_THRESH                                0x46
+#define                MT9V032_DARK_AVG_LOW_THRESH_MASK        (255 << 0)
+#define                MT9V032_DARK_AVG_LOW_THRESH_SHIFT       0
+#define                MT9V032_DARK_AVG_HIGH_THRESH_MASK       (255 << 8)
+#define                MT9V032_DARK_AVG_HIGH_THRESH_SHIFT      8
+#define MT9V032_ROW_NOISE_CORR_CONTROL                 0x70
+#define                MT9V032_ROW_NOISE_CORR_ENABLE           (1 << 5)
+#define                MT9V032_ROW_NOISE_CORR_USE_BLK_AVG      (1 << 7)
+#define MT9V032_PIXEL_CLOCK                            0x74
+#define                MT9V032_PIXEL_CLOCK_INV_LINE            (1 << 0)
+#define                MT9V032_PIXEL_CLOCK_INV_FRAME           (1 << 1)
+#define                MT9V032_PIXEL_CLOCK_XOR_LINE            (1 << 2)
+#define                MT9V032_PIXEL_CLOCK_CONT_LINE           (1 << 3)
+#define                MT9V032_PIXEL_CLOCK_INV_PXL_CLK         (1 << 4)
+#define MT9V032_TEST_PATTERN                           0x7f
+#define                MT9V032_TEST_PATTERN_DATA_MASK          (1023 << 0)
+#define                MT9V032_TEST_PATTERN_DATA_SHIFT         0
+#define                MT9V032_TEST_PATTERN_USE_DATA           (1 << 10)
+#define                MT9V032_TEST_PATTERN_GRAY_MASK          (3 << 11)
+#define                MT9V032_TEST_PATTERN_GRAY_NONE          (0 << 11)
+#define                MT9V032_TEST_PATTERN_GRAY_VERTICAL      (1 << 11)
+#define                MT9V032_TEST_PATTERN_GRAY_HORIZONTAL    (2 << 11)
+#define                MT9V032_TEST_PATTERN_GRAY_DIAGONAL      (3 << 11)
+#define                MT9V032_TEST_PATTERN_ENABLE             (1 << 13)
+#define                MT9V032_TEST_PATTERN_FLIP               (1 << 14)
+#define MT9V032_AEC_AGC_ENABLE                         0xaf
+#define                MT9V032_AEC_ENABLE                      (1 << 0)
+#define                MT9V032_AGC_ENABLE                      (1 << 1)
+#define MT9V032_THERMAL_INFO                           0xc1
+
+struct mt9v032 {
+       struct v4l2_subdev subdev;
+       struct media_pad pad;
+
+       struct v4l2_mbus_framefmt format;
+       struct v4l2_rect crop;
+
+       struct v4l2_ctrl_handler ctrls;
+
+       struct mutex power_lock;
+       int power_count;
+
+       struct mt9v032_platform_data *pdata;
+       u16 chip_control;
+       u16 aec_agc;
+};
+
+static struct mt9v032 *to_mt9v032(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct mt9v032, subdev);
+}
+
+static int mt9v032_read(struct i2c_client *client, const u8 reg)
+{
+       s32 data = i2c_smbus_read_word_data(client, reg);
+       dev_dbg(&client->dev, "%s: read 0x%04x from 0x%02x\n", __func__,
+               swab16(data), reg);
+       return data < 0 ? data : swab16(data);
+}
+
+static int mt9v032_write(struct i2c_client *client, const u8 reg,
+                        const u16 data)
+{
+       dev_dbg(&client->dev, "%s: writing 0x%04x to 0x%02x\n", __func__,
+               data, reg);
+       return i2c_smbus_write_word_data(client, reg, swab16(data));
+}
+
+static int mt9v032_set_chip_control(struct mt9v032 *mt9v032, u16 clear, u16 set)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+       u16 value = (mt9v032->chip_control & ~clear) | set;
+       int ret;
+
+       ret = mt9v032_write(client, MT9V032_CHIP_CONTROL, value);
+       if (ret < 0)
+               return ret;
+
+       mt9v032->chip_control = value;
+       return 0;
+}
+
+static int
+mt9v032_update_aec_agc(struct mt9v032 *mt9v032, u16 which, int enable)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+       u16 value = mt9v032->aec_agc;
+       int ret;
+
+       if (enable)
+               value |= which;
+       else
+               value &= ~which;
+
+       ret = mt9v032_write(client, MT9V032_AEC_AGC_ENABLE, value);
+       if (ret < 0)
+               return ret;
+
+       mt9v032->aec_agc = value;
+       return 0;
+}
+
+static int mt9v032_power_on(struct mt9v032 *mt9v032)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+       int ret;
+
+       if (mt9v032->pdata->set_clock) {
+               mt9v032->pdata->set_clock(&mt9v032->subdev, 25000000);
+               udelay(1);
+       }
+
+       /* Reset the chip and stop data read out */
+       ret = mt9v032_write(client, MT9V032_RESET, 1);
+       if (ret < 0)
+               return ret;
+
+       ret = mt9v032_write(client, MT9V032_RESET, 0);
+       if (ret < 0)
+               return ret;
+
+       return mt9v032_write(client, MT9V032_CHIP_CONTROL, 0);
+}
+
+static void mt9v032_power_off(struct mt9v032 *mt9v032)
+{
+       if (mt9v032->pdata->set_clock)
+               mt9v032->pdata->set_clock(&mt9v032->subdev, 0);
+}
+
+static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+       int ret;
+
+       if (!on) {
+               mt9v032_power_off(mt9v032);
+               return 0;
+       }
+
+       ret = mt9v032_power_on(mt9v032);
+       if (ret < 0)
+               return ret;
+
+       /* Configure the pixel clock polarity */
+       if (mt9v032->pdata && mt9v032->pdata->clk_pol) {
+               ret = mt9v032_write(client, MT9V032_PIXEL_CLOCK,
+                               MT9V032_PIXEL_CLOCK_INV_PXL_CLK);
+               if (ret < 0)
+                       return ret;
+       }
+
+       /* Disable the noise correction algorithm and restore the controls. */
+       ret = mt9v032_write(client, MT9V032_ROW_NOISE_CORR_CONTROL, 0);
+       if (ret < 0)
+               return ret;
+
+       return v4l2_ctrl_handler_setup(&mt9v032->ctrls);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev video operations
+ */
+
+static struct v4l2_mbus_framefmt *
+__mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh,
+                        unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+       switch (which) {
+       case V4L2_SUBDEV_FORMAT_TRY:
+               return v4l2_subdev_get_try_format(fh, pad);
+       case V4L2_SUBDEV_FORMAT_ACTIVE:
+               return &mt9v032->format;
+       default:
+               return NULL;
+       }
+}
+
+static struct v4l2_rect *
+__mt9v032_get_pad_crop(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh,
+                      unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+       switch (which) {
+       case V4L2_SUBDEV_FORMAT_TRY:
+               return v4l2_subdev_get_try_crop(fh, pad);
+       case V4L2_SUBDEV_FORMAT_ACTIVE:
+               return &mt9v032->crop;
+       default:
+               return NULL;
+       }
+}
+
+static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+       const u16 mode = MT9V032_CHIP_CONTROL_MASTER_MODE
+                      | MT9V032_CHIP_CONTROL_DOUT_ENABLE
+                      | MT9V032_CHIP_CONTROL_SEQUENTIAL;
+       struct i2c_client *client = v4l2_get_subdevdata(subdev);
+       struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+       struct v4l2_mbus_framefmt *format = &mt9v032->format;
+       struct v4l2_rect *crop = &mt9v032->crop;
+       unsigned int hratio;
+       unsigned int vratio;
+       int ret;
+
+       if (!enable)
+               return mt9v032_set_chip_control(mt9v032, mode, 0);
+
+       /* Configure the window size and row/column bin */
+       hratio = DIV_ROUND_CLOSEST(crop->width, format->width);
+       vratio = DIV_ROUND_CLOSEST(crop->height, format->height);
+
+       ret = mt9v032_write(client, MT9V032_READ_MODE,
+                   (hratio - 1) << MT9V032_READ_MODE_ROW_BIN_SHIFT |
+                   (vratio - 1) << MT9V032_READ_MODE_COLUMN_BIN_SHIFT);
+       if (ret < 0)
+               return ret;
+
+       ret = mt9v032_write(client, MT9V032_COLUMN_START, crop->left);
+       if (ret < 0)
+               return ret;
+
+       ret = mt9v032_write(client, MT9V032_ROW_START, crop->top);
+       if (ret < 0)
+               return ret;
+
+       ret = mt9v032_write(client, MT9V032_WINDOW_WIDTH, crop->width);
+       if (ret < 0)
+               return ret;
+
+       ret = mt9v032_write(client, MT9V032_WINDOW_HEIGHT, crop->height);
+       if (ret < 0)
+               return ret;
+
+       ret = mt9v032_write(client, MT9V032_HORIZONTAL_BLANKING,
+                           max(43, 660 - crop->width));
+       if (ret < 0)
+               return ret;
+
+       /* Switch to master "normal" mode */
+       return mt9v032_set_chip_control(mt9v032, 0, mode);
+}
+
+static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev,
+                                 struct v4l2_subdev_fh *fh,
+                                 struct v4l2_subdev_mbus_code_enum *code)
+{
+       if (code->index > 0)
+               return -EINVAL;
+
+       code->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+       return 0;
+}
+
+static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev,
+                                  struct v4l2_subdev_fh *fh,
+                                  struct v4l2_subdev_frame_size_enum *fse)
+{
+       if (fse->index >= 8 || fse->code != V4L2_MBUS_FMT_SGRBG10_1X10)
+               return -EINVAL;
+
+       fse->min_width = MT9V032_WINDOW_WIDTH_DEF / fse->index;
+       fse->max_width = fse->min_width;
+       fse->min_height = MT9V032_WINDOW_HEIGHT_DEF / fse->index;
+       fse->max_height = fse->min_height;
+
+       return 0;
+}
+
+static int mt9v032_get_format(struct v4l2_subdev *subdev,
+                             struct v4l2_subdev_fh *fh,
+                             struct v4l2_subdev_format *format)
+{
+       struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+
+       format->format = *__mt9v032_get_pad_format(mt9v032, fh, format->pad,
+                                                  format->which);
+       return 0;
+}
+
+static int mt9v032_set_format(struct v4l2_subdev *subdev,
+                             struct v4l2_subdev_fh *fh,
+                             struct v4l2_subdev_format *format)
+{
+       struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+       struct v4l2_mbus_framefmt *__format;
+       struct v4l2_rect *__crop;
+       unsigned int width;
+       unsigned int height;
+       unsigned int hratio;
+       unsigned int vratio;
+
+       __crop = __mt9v032_get_pad_crop(mt9v032, fh, format->pad,
+                                       format->which);
+
+       /* Clamp the width and height to avoid dividing by zero. */
+       width = clamp_t(unsigned int, ALIGN(format->format.width, 2),
+                       max(__crop->width / 8, MT9V032_WINDOW_WIDTH_MIN),
+                       __crop->width);
+       height = clamp_t(unsigned int, ALIGN(format->format.height, 2),
+                        max(__crop->height / 8, MT9V032_WINDOW_HEIGHT_MIN),
+                        __crop->height);
+
+       hratio = DIV_ROUND_CLOSEST(__crop->width, width);
+       vratio = DIV_ROUND_CLOSEST(__crop->height, height);
+
+       __format = __mt9v032_get_pad_format(mt9v032, fh, format->pad,
+                                           format->which);
+       __format->width = __crop->width / hratio;
+       __format->height = __crop->height / vratio;
+
+       format->format = *__format;
+
+       return 0;
+}
+
+static int mt9v032_get_crop(struct v4l2_subdev *subdev,
+                           struct v4l2_subdev_fh *fh,
+                           struct v4l2_subdev_crop *crop)
+{
+       struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+
+       crop->rect = *__mt9v032_get_pad_crop(mt9v032, fh, crop->pad,
+                                            crop->which);
+       return 0;
+}
+
+static int mt9v032_set_crop(struct v4l2_subdev *subdev,
+                           struct v4l2_subdev_fh *fh,
+                           struct v4l2_subdev_crop *crop)
+{
+       struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+       struct v4l2_mbus_framefmt *__format;
+       struct v4l2_rect *__crop;
+       struct v4l2_rect rect;
+
+       /* Clamp the crop rectangle boundaries and align them to a multiple of 2
+        * pixels.
+        */
+       rect.left = clamp(ALIGN(crop->rect.left, 2),
+                         MT9V032_COLUMN_START_MIN,
+                         MT9V032_COLUMN_START_MAX);
+       rect.top = clamp(ALIGN(crop->rect.top, 2),
+                        MT9V032_ROW_START_MIN,
+                        MT9V032_ROW_START_MAX);
+       rect.width = clamp(ALIGN(crop->rect.width, 2),
+                          MT9V032_WINDOW_WIDTH_MIN,
+                          MT9V032_WINDOW_WIDTH_MAX);
+       rect.height = clamp(ALIGN(crop->rect.height, 2),
+                           MT9V032_WINDOW_HEIGHT_MIN,
+                           MT9V032_WINDOW_HEIGHT_MAX);
+
+       rect.width = min(rect.width, MT9V032_PIXEL_ARRAY_WIDTH - rect.left);
+       rect.height = min(rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top);
+
+       __crop = __mt9v032_get_pad_crop(mt9v032, fh, crop->pad, crop->which);
+
+       if (rect.width != __crop->width || rect.height != __crop->height) {
+               /* Reset the output image size if the crop rectangle size has
+                * been modified.
+                */
+               __format = __mt9v032_get_pad_format(mt9v032, fh, crop->pad,
+                                                   crop->which);
+               __format->width = rect.width;
+               __format->height = rect.height;
+       }
+
+       *__crop = rect;
+       crop->rect = rect;
+
+       return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev control operations
+ */
+
+#define V4L2_CID_TEST_PATTERN          (V4L2_CID_USER_BASE | 0x1001)
+
+static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct mt9v032 *mt9v032 =
+                       container_of(ctrl->handler, struct mt9v032, ctrls);
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+       u16 data;
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUTOGAIN:
+               return mt9v032_update_aec_agc(mt9v032, MT9V032_AGC_ENABLE,
+                                             ctrl->val);
+
+       case V4L2_CID_GAIN:
+               return mt9v032_write(client, MT9V032_ANALOG_GAIN, ctrl->val);
+
+       case V4L2_CID_EXPOSURE_AUTO:
+               return mt9v032_update_aec_agc(mt9v032, MT9V032_AEC_ENABLE,
+                                             ctrl->val);
+
+       case V4L2_CID_EXPOSURE:
+               return mt9v032_write(client, MT9V032_TOTAL_SHUTTER_WIDTH,
+                                    ctrl->val);
+
+       case V4L2_CID_TEST_PATTERN:
+               switch (ctrl->val) {
+               case 0:
+                       data = 0;
+                       break;
+               case 1:
+                       data = MT9V032_TEST_PATTERN_GRAY_VERTICAL
+                            | MT9V032_TEST_PATTERN_ENABLE;
+                       break;
+               case 2:
+                       data = MT9V032_TEST_PATTERN_GRAY_HORIZONTAL
+                            | MT9V032_TEST_PATTERN_ENABLE;
+                       break;
+               case 3:
+                       data = MT9V032_TEST_PATTERN_GRAY_DIAGONAL
+                            | MT9V032_TEST_PATTERN_ENABLE;
+                       break;
+               default:
+                       data = (ctrl->val << MT9V032_TEST_PATTERN_DATA_SHIFT)
+                            | MT9V032_TEST_PATTERN_USE_DATA
+                            | MT9V032_TEST_PATTERN_ENABLE
+                            | MT9V032_TEST_PATTERN_FLIP;
+                       break;
+               }
+
+               return mt9v032_write(client, MT9V032_TEST_PATTERN, data);
+       }
+
+       return 0;
+}
+
+static struct v4l2_ctrl_ops mt9v032_ctrl_ops = {
+       .s_ctrl = mt9v032_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config mt9v032_ctrls[] = {
+       {
+               .ops            = &mt9v032_ctrl_ops,
+               .id             = V4L2_CID_TEST_PATTERN,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Test pattern",
+               .min            = 0,
+               .max            = 1023,
+               .step           = 1,
+               .def            = 0,
+               .flags          = 0,
+       }
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev core operations
+ */
+
+static int mt9v032_set_power(struct v4l2_subdev *subdev, int on)
+{
+       struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+       int ret = 0;
+
+       mutex_lock(&mt9v032->power_lock);
+
+       /* If the power count is modified from 0 to != 0 or from != 0 to 0,
+        * update the power state.
+        */
+       if (mt9v032->power_count == !on) {
+               ret = __mt9v032_set_power(mt9v032, !!on);
+               if (ret < 0)
+                       goto done;
+       }
+
+       /* Update the power count. */
+       mt9v032->power_count += on ? 1 : -1;
+       WARN_ON(mt9v032->power_count < 0);
+
+done:
+       mutex_unlock(&mt9v032->power_lock);
+       return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev internal operations
+ */
+
+static int mt9v032_registered(struct v4l2_subdev *subdev)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(subdev);
+       struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+       s32 data;
+       int ret;
+
+       dev_info(&client->dev, "Probing MT9V032 at address 0x%02x\n",
+                       client->addr);
+
+       ret = mt9v032_power_on(mt9v032);
+       if (ret < 0) {
+               dev_err(&client->dev, "MT9V032 power up failed\n");
+               return ret;
+       }
+
+       /* Read and check the sensor version */
+       data = mt9v032_read(client, MT9V032_CHIP_VERSION);
+       if (data != MT9V032_CHIP_ID_REV1 && data != MT9V032_CHIP_ID_REV3) {
+               dev_err(&client->dev, "MT9V032 not detected, wrong version "
+                               "0x%04x\n", data);
+               return -ENODEV;
+       }
+
+       mt9v032_power_off(mt9v032);
+
+       dev_info(&client->dev, "MT9V032 detected at address 0x%02x\n",
+                       client->addr);
+
+       return ret;
+}
+
+static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+       struct v4l2_mbus_framefmt *format;
+       struct v4l2_rect *crop;
+
+       crop = v4l2_subdev_get_try_crop(fh, 0);
+       crop->left = MT9V032_COLUMN_START_DEF;
+       crop->top = MT9V032_ROW_START_DEF;
+       crop->width = MT9V032_WINDOW_WIDTH_DEF;
+       crop->height = MT9V032_WINDOW_HEIGHT_DEF;
+
+       format = v4l2_subdev_get_try_format(fh, 0);
+       format->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+       format->width = MT9V032_WINDOW_WIDTH_DEF;
+       format->height = MT9V032_WINDOW_HEIGHT_DEF;
+       format->field = V4L2_FIELD_NONE;
+       format->colorspace = V4L2_COLORSPACE_SRGB;
+
+       return mt9v032_set_power(subdev, 1);
+}
+
+static int mt9v032_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+       return mt9v032_set_power(subdev, 0);
+}
+
+static struct v4l2_subdev_core_ops mt9v032_subdev_core_ops = {
+       .s_power        = mt9v032_set_power,
+};
+
+static struct v4l2_subdev_video_ops mt9v032_subdev_video_ops = {
+       .s_stream       = mt9v032_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops mt9v032_subdev_pad_ops = {
+       .enum_mbus_code = mt9v032_enum_mbus_code,
+       .enum_frame_size = mt9v032_enum_frame_size,
+       .get_fmt = mt9v032_get_format,
+       .set_fmt = mt9v032_set_format,
+       .get_crop = mt9v032_get_crop,
+       .set_crop = mt9v032_set_crop,
+};
+
+static struct v4l2_subdev_ops mt9v032_subdev_ops = {
+       .core   = &mt9v032_subdev_core_ops,
+       .video  = &mt9v032_subdev_video_ops,
+       .pad    = &mt9v032_subdev_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops mt9v032_subdev_internal_ops = {
+       .registered = mt9v032_registered,
+       .open = mt9v032_open,
+       .close = mt9v032_close,
+};
+
+/* -----------------------------------------------------------------------------
+ * Driver initialization and probing
+ */
+
+static int mt9v032_probe(struct i2c_client *client,
+               const struct i2c_device_id *did)
+{
+       struct mt9v032 *mt9v032;
+       unsigned int i;
+       int ret;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_WORD_DATA)) {
+               dev_warn(&client->adapter->dev,
+                        "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+               return -EIO;
+       }
+
+       mt9v032 = kzalloc(sizeof(*mt9v032), GFP_KERNEL);
+       if (!mt9v032)
+               return -ENOMEM;
+
+       mutex_init(&mt9v032->power_lock);
+       mt9v032->pdata = client->dev.platform_data;
+
+       v4l2_ctrl_handler_init(&mt9v032->ctrls, ARRAY_SIZE(mt9v032_ctrls) + 4);
+
+       v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
+                         V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+       v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
+                         V4L2_CID_GAIN, MT9V032_ANALOG_GAIN_MIN,
+                         MT9V032_ANALOG_GAIN_MAX, 1, MT9V032_ANALOG_GAIN_DEF);
+       v4l2_ctrl_new_std_menu(&mt9v032->ctrls, &mt9v032_ctrl_ops,
+                              V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, 0,
+                              V4L2_EXPOSURE_AUTO);
+       v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
+                         V4L2_CID_EXPOSURE, MT9V032_TOTAL_SHUTTER_WIDTH_MIN,
+                         MT9V032_TOTAL_SHUTTER_WIDTH_MAX, 1,
+                         MT9V032_TOTAL_SHUTTER_WIDTH_DEF);
+
+       for (i = 0; i < ARRAY_SIZE(mt9v032_ctrls); ++i)
+               v4l2_ctrl_new_custom(&mt9v032->ctrls, &mt9v032_ctrls[i], NULL);
+
+       mt9v032->subdev.ctrl_handler = &mt9v032->ctrls;
+
+       if (mt9v032->ctrls.error)
+               printk(KERN_INFO "%s: control initialization error %d\n",
+                      __func__, mt9v032->ctrls.error);
+
+       mt9v032->crop.left = MT9V032_COLUMN_START_DEF;
+       mt9v032->crop.top = MT9V032_ROW_START_DEF;
+       mt9v032->crop.width = MT9V032_WINDOW_WIDTH_DEF;
+       mt9v032->crop.height = MT9V032_WINDOW_HEIGHT_DEF;
+
+       mt9v032->format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+       mt9v032->format.width = MT9V032_WINDOW_WIDTH_DEF;
+       mt9v032->format.height = MT9V032_WINDOW_HEIGHT_DEF;
+       mt9v032->format.field = V4L2_FIELD_NONE;
+       mt9v032->format.colorspace = V4L2_COLORSPACE_SRGB;
+
+       mt9v032->aec_agc = MT9V032_AEC_ENABLE | MT9V032_AGC_ENABLE;
+
+       v4l2_i2c_subdev_init(&mt9v032->subdev, client, &mt9v032_subdev_ops);
+       mt9v032->subdev.internal_ops = &mt9v032_subdev_internal_ops;
+       mt9v032->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+       mt9v032->pad.flags = MEDIA_PAD_FL_SOURCE;
+       ret = media_entity_init(&mt9v032->subdev.entity, 1, &mt9v032->pad, 0);
+       if (ret < 0)
+               kfree(mt9v032);
+
+       return ret;
+}
+
+static int mt9v032_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+       struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+
+       v4l2_device_unregister_subdev(subdev);
+       media_entity_cleanup(&subdev->entity);
+       kfree(mt9v032);
+       return 0;
+}
+
+static const struct i2c_device_id mt9v032_id[] = {
+       { "mt9v032", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9v032_id);
+
+static struct i2c_driver mt9v032_driver = {
+       .driver = {
+               .name = "mt9v032",
+       },
+       .probe          = mt9v032_probe,
+       .remove         = mt9v032_remove,
+       .id_table       = mt9v032_id,
+};
+
+static int __init mt9v032_init(void)
+{
+       return i2c_add_driver(&mt9v032_driver);
+}
+
+static void __exit mt9v032_exit(void)
+{
+       i2c_del_driver(&mt9v032_driver);
+}
+
+module_init(mt9v032_init);
+module_exit(mt9v032_exit);
+
+MODULE_DESCRIPTION("Aptina MT9V032 Camera driver");
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_LICENSE("GPL");
index 502e2a4..c7680eb 100644 (file)
@@ -400,6 +400,35 @@ static int mx3_videobuf_init(struct vb2_buffer *vb)
        return 0;
 }
 
+static int mx3_stop_streaming(struct vb2_queue *q)
+{
+       struct soc_camera_device *icd = soc_camera_from_vb2q(q);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct mx3_camera_dev *mx3_cam = ici->priv;
+       struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
+       struct dma_chan *chan;
+       struct mx3_camera_buffer *buf, *tmp;
+       unsigned long flags;
+
+       if (ichan) {
+               chan = &ichan->dma_chan;
+               chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+       }
+
+       spin_lock_irqsave(&mx3_cam->lock, flags);
+
+       mx3_cam->active = NULL;
+
+       list_for_each_entry_safe(buf, tmp, &mx3_cam->capture, queue) {
+               buf->state = CSI_BUF_NEEDS_INIT;
+               list_del_init(&buf->queue);
+       }
+
+       spin_unlock_irqrestore(&mx3_cam->lock, flags);
+
+       return 0;
+}
+
 static struct vb2_ops mx3_videobuf_ops = {
        .queue_setup    = mx3_videobuf_setup,
        .buf_prepare    = mx3_videobuf_prepare,
@@ -408,6 +437,7 @@ static struct vb2_ops mx3_videobuf_ops = {
        .buf_init       = mx3_videobuf_init,
        .wait_prepare   = soc_camera_unlock,
        .wait_finish    = soc_camera_lock,
+       .stop_streaming = mx3_stop_streaming,
 };
 
 static int mx3_camera_init_videobuf(struct vb2_queue *q,
@@ -658,8 +688,8 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id
 
        fmt = soc_mbus_get_fmtdesc(code);
        if (!fmt) {
-               dev_err(icd->dev.parent,
-                       "Invalid format code #%u: %d\n", idx, code);
+               dev_warn(icd->dev.parent,
+                        "Unsupported format code #%u: %d\n", idx, code);
                return 0;
        }
 
@@ -712,13 +742,9 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id
 
 static void configure_geometry(struct mx3_camera_dev *mx3_cam,
                               unsigned int width, unsigned int height,
-                              enum v4l2_mbus_pixelcode code)
+                              const struct soc_mbus_pixelfmt *fmt)
 {
        u32 ctrl, width_field, height_field;
-       const struct soc_mbus_pixelfmt *fmt;
-
-       fmt = soc_mbus_get_fmtdesc(code);
-       BUG_ON(!fmt);
 
        if (fourcc_to_ipu_pix(fmt->fourcc) == IPU_PIX_FMT_GENERIC) {
                /*
@@ -726,8 +752,10 @@ static void configure_geometry(struct mx3_camera_dev *mx3_cam,
                 * the width parameter count the number of samples to
                 * capture to complete the whole image width.
                 */
-               width *= soc_mbus_samples_per_pixel(fmt);
-               BUG_ON(width < 0);
+               unsigned int num, den;
+               int ret = soc_mbus_samples_per_pixel(fmt, &num, &den);
+               BUG_ON(ret < 0);
+               width = width * num / den;
        }
 
        /* Setup frame size - this cannot be changed on-the-fly... */
@@ -774,8 +802,8 @@ static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam)
  */
 static inline void stride_align(__u32 *width)
 {
-       if (((*width + 7) &  ~7) < 4096)
-               *width = (*width + 7) &  ~7;
+       if (ALIGN(*width, 8) < 4096)
+               *width = ALIGN(*width, 8);
        else
                *width = *width &  ~7;
 }
@@ -801,11 +829,14 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd,
        if (ret < 0)
                return ret;
 
-       /* The capture device might have changed its output  */
+       /* The capture device might have changed its output sizes */
        ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
        if (ret < 0)
                return ret;
 
+       if (mf.code != icd->current_fmt->code)
+               return -EINVAL;
+
        if (mf.width & 7) {
                /* Ouch! We can only handle 8-byte aligned width... */
                stride_align(&mf.width);
@@ -815,7 +846,8 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd,
        }
 
        if (mf.width != icd->user_width || mf.height != icd->user_height)
-               configure_geometry(mx3_cam, mf.width, mf.height, mf.code);
+               configure_geometry(mx3_cam, mf.width, mf.height,
+                                  icd->current_fmt->host_fmt);
 
        dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n",
                mf.width, mf.height);
@@ -853,7 +885,7 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
         * mxc_v4l2_s_fmt()
         */
 
-       configure_geometry(mx3_cam, pix->width, pix->height, xlate->code);
+       configure_geometry(mx3_cam, pix->width, pix->height, xlate->host_fmt);
 
        mf.width        = pix->width;
        mf.height       = pix->height;
index 5954b93..e7cfc85 100644 (file)
@@ -990,63 +990,80 @@ static void omap1_cam_remove_device(struct soc_camera_device *icd)
 }
 
 /* Duplicate standard formats based on host capability of byte swapping */
-static const struct soc_mbus_pixelfmt omap1_cam_formats[] = {
-       [V4L2_MBUS_FMT_UYVY8_2X8] = {
+static const struct soc_mbus_lookup omap1_cam_formats[] = {
+{
+       .code = V4L2_MBUS_FMT_UYVY8_2X8,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_YUYV,
                .name                   = "YUYV",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_BE,
        },
-       [V4L2_MBUS_FMT_VYUY8_2X8] = {
+}, {
+       .code = V4L2_MBUS_FMT_VYUY8_2X8,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_YVYU,
                .name                   = "YVYU",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_BE,
        },
-       [V4L2_MBUS_FMT_YUYV8_2X8] = {
+}, {
+       .code = V4L2_MBUS_FMT_YUYV8_2X8,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_UYVY,
                .name                   = "UYVY",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_BE,
        },
-       [V4L2_MBUS_FMT_YVYU8_2X8] = {
+}, {
+       .code = V4L2_MBUS_FMT_YVYU8_2X8,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_VYUY,
                .name                   = "VYUY",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_BE,
        },
-       [V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE] = {
+}, {
+       .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_RGB555,
                .name                   = "RGB555",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_BE,
        },
-       [V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE] = {
+}, {
+       .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_RGB555X,
                .name                   = "RGB555X",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_BE,
        },
-       [V4L2_MBUS_FMT_RGB565_2X8_BE] = {
+}, {
+       .code = V4L2_MBUS_FMT_RGB565_2X8_BE,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_RGB565,
                .name                   = "RGB565",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_BE,
        },
-       [V4L2_MBUS_FMT_RGB565_2X8_LE] = {
+}, {
+       .code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_RGB565X,
                .name                   = "RGB565X",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_BE,
        },
+},
 };
 
 static int omap1_cam_get_formats(struct soc_camera_device *icd,
@@ -1065,7 +1082,7 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd,
 
        fmt = soc_mbus_get_fmtdesc(code);
        if (!fmt) {
-               dev_err(dev, "%s: invalid format code #%d: %d\n", __func__,
+               dev_warn(dev, "%s: unsupported format code #%d: %d\n", __func__,
                                idx, code);
                return 0;
        }
@@ -1085,12 +1102,14 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd,
        case V4L2_MBUS_FMT_RGB565_2X8_LE:
                formats++;
                if (xlate) {
-                       xlate->host_fmt = &omap1_cam_formats[code];
+                       xlate->host_fmt = soc_mbus_find_fmtdesc(code,
+                                               omap1_cam_formats,
+                                               ARRAY_SIZE(omap1_cam_formats));
                        xlate->code     = code;
                        xlate++;
                        dev_dbg(dev,
                                "%s: providing format %s as byte swapped code #%d\n",
-                               __func__, omap1_cam_formats[code].name, code);
+                               __func__, xlate->host_fmt->name, code);
                }
        default:
                if (xlate)
index ca9f83a..453627b 100644 (file)
@@ -278,12 +278,10 @@ static struct v4l2_standard generic_standards[] = {
        }
 };
 
-#define generic_standards_cnt ARRAY_SIZE(generic_standards)
-
 static struct v4l2_standard *match_std(v4l2_std_id id)
 {
        unsigned int idx;
-       for (idx = 0; idx < generic_standards_cnt; idx++) {
+       for (idx = 0; idx < ARRAY_SIZE(generic_standards); idx++) {
                if (generic_standards[idx].id & id) {
                        return generic_standards + idx;
                }
@@ -370,7 +368,11 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
 
        stddefs = kzalloc(sizeof(struct v4l2_standard) * std_cnt,
                          GFP_KERNEL);
-       for (idx = 0; idx < std_cnt; idx++) stddefs[idx].index = idx;
+       if (!stddefs)
+               return NULL;
+
+       for (idx = 0; idx < std_cnt; idx++)
+               stddefs[idx].index = idx;
 
        idx = 0;
 
index 780af5f..356cd42 100644 (file)
@@ -1850,7 +1850,6 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
        } else {
                /* Device is closed, so we can safely unregister it */
                PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
-               pwc_cleanup(pdev);
 
 disconnect_out:
                /* search device_hint[] table if we occupy a slot, by any chance */
@@ -1860,6 +1859,7 @@ disconnect_out:
        }
 
        mutex_unlock(&pdev->modlock);
+       pwc_cleanup(pdev);
 }
 
 
index aa87e46..f85c512 100644 (file)
@@ -379,8 +379,27 @@ static int pwc_s_input(struct file *file, void *fh, unsigned int i)
 
 static int pwc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c)
 {
-       int i;
-
+       int i, idx;
+       u32 id;
+
+       id = c->id;
+       if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {
+               id &= V4L2_CTRL_ID_MASK;
+               id++;
+               idx = -1;
+               for (i = 0; i < ARRAY_SIZE(pwc_controls); i++) {
+                       if (pwc_controls[i].id < id)
+                               continue;
+                       if (idx >= 0
+                        && pwc_controls[i].id > pwc_controls[idx].id)
+                               continue;
+                       idx = i;
+               }
+               if (idx < 0)
+                       return -EINVAL;
+               memcpy(c, &pwc_controls[idx], sizeof pwc_controls[0]);
+               return 0;
+       }
        for (i = 0; i < sizeof(pwc_controls) / sizeof(struct v4l2_queryctrl); i++) {
                if (pwc_controls[i].id == c->id) {
                        PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
index c1ee09a..b42bfa5 100644 (file)
@@ -1155,15 +1155,11 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct pxa_camera_dev *pcdev = ici->priv;
        unsigned long bus_flags, camera_flags, common_flags;
-       const struct soc_mbus_pixelfmt *fmt;
        int ret;
        struct pxa_cam *cam = icd->host_priv;
 
-       fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code);
-       if (!fmt)
-               return -EINVAL;
-
-       ret = test_platform_param(pcdev, fmt->bits_per_sample, &bus_flags);
+       ret = test_platform_param(pcdev, icd->current_fmt->host_fmt->bits_per_sample,
+                                 &bus_flags);
        if (ret < 0)
                return ret;
 
index 561909b..5b9dce8 100644 (file)
@@ -394,12 +394,17 @@ static unsigned int vid_limit = 16;       /* Video memory limit, in Mb */
 /* start video number */
 static int video_nr = -1;      /* /dev/videoN, -1 for autodetect */
 
+/* Enable jpeg capture. */
+static int jpeg_enable = 1;
+
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Debug level(0-100) default 0");
 module_param(vid_limit, int, 0644);
 MODULE_PARM_DESC(vid_limit, "video memory limit(Mb)");
 module_param(video_nr, int, 0644);
 MODULE_PARM_DESC(video_nr, "start video minor(-1 default autodetect)");
+module_param(jpeg_enable, int, 0644);
+MODULE_PARM_DESC(jpeg_enable, "Jpeg enable(1-on 0-off) default 1");
 
 /* USB device table */
 #define USB_SENSORAY_VID       0x1943
@@ -413,6 +418,7 @@ MODULE_DEVICE_TABLE(usb, s2255_table);
 #define BUFFER_TIMEOUT msecs_to_jiffies(400)
 
 /* image formats.  */
+/* JPEG formats must be defined last to support jpeg_enable parameter */
 static const struct s2255_fmt formats[] = {
        {
                .name = "4:2:2, planar, YUV422P",
@@ -428,14 +434,18 @@ static const struct s2255_fmt formats[] = {
                .name = "4:2:2, packed, UYVY",
                .fourcc = V4L2_PIX_FMT_UYVY,
                .depth = 16
+       }, {
+               .name = "8bpp GREY",
+               .fourcc = V4L2_PIX_FMT_GREY,
+               .depth = 8
        }, {
                .name = "JPG",
                .fourcc = V4L2_PIX_FMT_JPEG,
                .depth = 24
        }, {
-               .name = "8bpp GREY",
-               .fourcc = V4L2_PIX_FMT_GREY,
-               .depth = 8
+               .name = "MJPG",
+               .fourcc = V4L2_PIX_FMT_MJPEG,
+               .depth = 24
        }
 };
 
@@ -610,6 +620,9 @@ static const struct s2255_fmt *format_by_fourcc(int fourcc)
        for (i = 0; i < ARRAY_SIZE(formats); i++) {
                if (-1 == formats[i].fourcc)
                        continue;
+       if (!jpeg_enable && ((formats[i].fourcc == V4L2_PIX_FMT_JPEG) ||
+                            (formats[i].fourcc == V4L2_PIX_FMT_MJPEG)))
+           continue;
                if (formats[i].fourcc == fourcc)
                        return formats + i;
        }
@@ -653,6 +666,7 @@ static void s2255_fillbuff(struct s2255_channel *channel,
                        memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height);
                        break;
                case V4L2_PIX_FMT_JPEG:
+               case V4L2_PIX_FMT_MJPEG:
                        buf->vb.size = jpgsize;
                        memcpy(vbuf, tmpbuf, buf->vb.size);
                        break;
@@ -856,7 +870,9 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
 
        if (index >= ARRAY_SIZE(formats))
                return -EINVAL;
-
+    if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) ||
+                        (formats[index].fourcc == V4L2_PIX_FMT_MJPEG)))
+       return -EINVAL;
        dprintk(4, "name %s\n", formats[index].name);
        strlcpy(f->description, formats[index].name, sizeof(f->description));
        f->pixelformat = formats[index].fourcc;
@@ -1037,6 +1053,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                mode.color |= COLOR_Y8;
                break;
        case V4L2_PIX_FMT_JPEG:
+       case V4L2_PIX_FMT_MJPEG:
                mode.color &= ~MASK_COLOR;
                mode.color |= COLOR_JPG;
                mode.color |= (channel->jc.quality << 8);
@@ -2382,7 +2399,7 @@ static void read_pipe_completion(struct urb *purb)
                          read_pipe_completion, pipe_info);
 
        if (pipe_info->state != 0) {
-               if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL)) {
+               if (usb_submit_urb(pipe_info->stream_urb, GFP_ATOMIC)) {
                        dev_err(&dev->udev->dev, "error submitting urb\n");
                }
        } else {
index 7ea1b14..df6954a 100644 (file)
@@ -1,3 +1,5 @@
+s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-capture.o
+s5p-csis-objs := mipi-csis.o
 
-obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) := s5p-fimc.o
-s5p-fimc-y := fimc-core.o fimc-reg.o fimc-capture.o
+obj-$(CONFIG_VIDEO_S5P_MIPI_CSIS)      += s5p-csis.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC)   += s5p-fimc.o
diff --git a/drivers/media/video/s5p-fimc/mipi-csis.c b/drivers/media/video/s5p-fimc/mipi-csis.c
new file mode 100644 (file)
index 0000000..ef056d6
--- /dev/null
@@ -0,0 +1,724 @@
+/*
+ * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.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.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/memory.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-subdev.h>
+#include <plat/mipi_csis.h>
+#include "mipi-csis.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+/* Register map definition */
+
+/* CSIS global control */
+#define S5PCSIS_CTRL                   0x00
+#define S5PCSIS_CTRL_DPDN_DEFAULT      (0 << 31)
+#define S5PCSIS_CTRL_DPDN_SWAP         (1 << 31)
+#define S5PCSIS_CTRL_ALIGN_32BIT       (1 << 20)
+#define S5PCSIS_CTRL_UPDATE_SHADOW     (1 << 16)
+#define S5PCSIS_CTRL_WCLK_EXTCLK       (1 << 8)
+#define S5PCSIS_CTRL_RESET             (1 << 4)
+#define S5PCSIS_CTRL_ENABLE            (1 << 0)
+
+/* D-PHY control */
+#define S5PCSIS_DPHYCTRL               0x04
+#define S5PCSIS_DPHYCTRL_HSS_MASK      (0x1f << 27)
+#define S5PCSIS_DPHYCTRL_ENABLE                (0x1f << 0)
+
+#define S5PCSIS_CONFIG                 0x08
+#define S5PCSIS_CFG_FMT_YCBCR422_8BIT  (0x1e << 2)
+#define S5PCSIS_CFG_FMT_RAW8           (0x2a << 2)
+#define S5PCSIS_CFG_FMT_RAW10          (0x2b << 2)
+#define S5PCSIS_CFG_FMT_RAW12          (0x2c << 2)
+/* User defined formats, x = 1...4 */
+#define S5PCSIS_CFG_FMT_USER(x)                ((0x30 + x - 1) << 2)
+#define S5PCSIS_CFG_FMT_MASK           (0x3f << 2)
+#define S5PCSIS_CFG_NR_LANE_MASK       3
+
+/* Interrupt mask. */
+#define S5PCSIS_INTMSK                 0x10
+#define S5PCSIS_INTMSK_EN_ALL          0xf000003f
+#define S5PCSIS_INTSRC                 0x14
+
+/* Pixel resolution */
+#define S5PCSIS_RESOL                  0x2c
+#define CSIS_MAX_PIX_WIDTH             0xffff
+#define CSIS_MAX_PIX_HEIGHT            0xffff
+
+enum {
+       CSIS_CLK_MUX,
+       CSIS_CLK_GATE,
+};
+
+static char *csi_clock_name[] = {
+       [CSIS_CLK_MUX]  = "sclk_csis",
+       [CSIS_CLK_GATE] = "csis",
+};
+#define NUM_CSIS_CLOCKS        ARRAY_SIZE(csi_clock_name)
+
+enum {
+       ST_POWERED      = 1,
+       ST_STREAMING    = 2,
+       ST_SUSPENDED    = 4,
+};
+
+/**
+ * struct csis_state - the driver's internal state data structure
+ * @lock: mutex serializing the subdev and power management operations,
+ *        protecting @format and @flags members
+ * @pads: CSIS pads array
+ * @sd: v4l2_subdev associated with CSIS device instance
+ * @pdev: CSIS platform device
+ * @regs_res: requested I/O register memory resource
+ * @regs: mmaped I/O registers memory
+ * @clock: CSIS clocks
+ * @irq: requested s5p-mipi-csis irq number
+ * @flags: the state variable for power and streaming control
+ * @csis_fmt: current CSIS pixel format
+ * @format: common media bus format for the source and sink pad
+ */
+struct csis_state {
+       struct mutex lock;
+       struct media_pad pads[CSIS_PADS_NUM];
+       struct v4l2_subdev sd;
+       struct platform_device *pdev;
+       struct resource *regs_res;
+       void __iomem *regs;
+       struct clk *clock[NUM_CSIS_CLOCKS];
+       int irq;
+       struct regulator *supply;
+       u32 flags;
+       const struct csis_pix_format *csis_fmt;
+       struct v4l2_mbus_framefmt format;
+};
+
+/**
+ * struct csis_pix_format - CSIS pixel format description
+ * @pix_width_alignment: horizontal pixel alignment, width will be
+ *                       multiple of 2^pix_width_alignment
+ * @code: corresponding media bus code
+ * @fmt_reg: S5PCSIS_CONFIG register value
+ */
+struct csis_pix_format {
+       unsigned int pix_width_alignment;
+       enum v4l2_mbus_pixelcode code;
+       u32 fmt_reg;
+};
+
+static const struct csis_pix_format s5pcsis_formats[] = {
+       {
+               .code = V4L2_MBUS_FMT_VYUY8_2X8,
+               .fmt_reg = S5PCSIS_CFG_FMT_YCBCR422_8BIT,
+       }, {
+               .code = V4L2_MBUS_FMT_JPEG_1X8,
+               .fmt_reg = S5PCSIS_CFG_FMT_USER(1),
+       },
+};
+
+#define s5pcsis_write(__csis, __r, __v) writel(__v, __csis->regs + __r)
+#define s5pcsis_read(__csis, __r) readl(__csis->regs + __r)
+
+static struct csis_state *sd_to_csis_state(struct v4l2_subdev *sdev)
+{
+       return container_of(sdev, struct csis_state, sd);
+}
+
+static const struct csis_pix_format *find_csis_format(
+       struct v4l2_mbus_framefmt *mf)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(s5pcsis_formats); i++)
+               if (mf->code == s5pcsis_formats[i].code)
+                       return &s5pcsis_formats[i];
+       return NULL;
+}
+
+static void s5pcsis_enable_interrupts(struct csis_state *state, bool on)
+{
+       u32 val = s5pcsis_read(state, S5PCSIS_INTMSK);
+
+       val = on ? val | S5PCSIS_INTMSK_EN_ALL :
+                  val & ~S5PCSIS_INTMSK_EN_ALL;
+       s5pcsis_write(state, S5PCSIS_INTMSK, val);
+}
+
+static void s5pcsis_reset(struct csis_state *state)
+{
+       u32 val = s5pcsis_read(state, S5PCSIS_CTRL);
+
+       s5pcsis_write(state, S5PCSIS_CTRL, val | S5PCSIS_CTRL_RESET);
+       udelay(10);
+}
+
+static void s5pcsis_system_enable(struct csis_state *state, int on)
+{
+       u32 val;
+
+       val = s5pcsis_read(state, S5PCSIS_CTRL);
+       if (on)
+               val |= S5PCSIS_CTRL_ENABLE;
+       else
+               val &= ~S5PCSIS_CTRL_ENABLE;
+       s5pcsis_write(state, S5PCSIS_CTRL, val);
+
+       val = s5pcsis_read(state, S5PCSIS_DPHYCTRL);
+       if (on)
+               val |= S5PCSIS_DPHYCTRL_ENABLE;
+       else
+               val &= ~S5PCSIS_DPHYCTRL_ENABLE;
+       s5pcsis_write(state, S5PCSIS_DPHYCTRL, val);
+}
+
+/* Called with the state.lock mutex held */
+static void __s5pcsis_set_format(struct csis_state *state)
+{
+       struct v4l2_mbus_framefmt *mf = &state->format;
+       u32 val;
+
+       v4l2_dbg(1, debug, &state->sd, "fmt: %d, %d x %d\n",
+                mf->code, mf->width, mf->height);
+
+       /* Color format */
+       val = s5pcsis_read(state, S5PCSIS_CONFIG);
+       val = (val & ~S5PCSIS_CFG_FMT_MASK) | state->csis_fmt->fmt_reg;
+       s5pcsis_write(state, S5PCSIS_CONFIG, val);
+
+       /* Pixel resolution */
+       val = (mf->width << 16) | mf->height;
+       s5pcsis_write(state, S5PCSIS_RESOL, val);
+}
+
+static void s5pcsis_set_hsync_settle(struct csis_state *state, int settle)
+{
+       u32 val = s5pcsis_read(state, S5PCSIS_DPHYCTRL);
+
+       val = (val & ~S5PCSIS_DPHYCTRL_HSS_MASK) | (settle << 27);
+       s5pcsis_write(state, S5PCSIS_DPHYCTRL, val);
+}
+
+static void s5pcsis_set_params(struct csis_state *state)
+{
+       struct s5p_platform_mipi_csis *pdata = state->pdev->dev.platform_data;
+       u32 val;
+
+       val = s5pcsis_read(state, S5PCSIS_CONFIG);
+       val = (val & ~S5PCSIS_CFG_NR_LANE_MASK) | (pdata->lanes - 1);
+       s5pcsis_write(state, S5PCSIS_CONFIG, val);
+
+       __s5pcsis_set_format(state);
+       s5pcsis_set_hsync_settle(state, pdata->hs_settle);
+
+       val = s5pcsis_read(state, S5PCSIS_CTRL);
+       if (pdata->alignment == 32)
+               val |= S5PCSIS_CTRL_ALIGN_32BIT;
+       else /* 24-bits */
+               val &= ~S5PCSIS_CTRL_ALIGN_32BIT;
+       /* Not using external clock. */
+       val &= ~S5PCSIS_CTRL_WCLK_EXTCLK;
+       s5pcsis_write(state, S5PCSIS_CTRL, val);
+
+       /* Update the shadow register. */
+       val = s5pcsis_read(state, S5PCSIS_CTRL);
+       s5pcsis_write(state, S5PCSIS_CTRL, val | S5PCSIS_CTRL_UPDATE_SHADOW);
+}
+
+static void s5pcsis_clk_put(struct csis_state *state)
+{
+       int i;
+
+       for (i = 0; i < NUM_CSIS_CLOCKS; i++)
+               if (!IS_ERR_OR_NULL(state->clock[i]))
+                       clk_put(state->clock[i]);
+}
+
+static int s5pcsis_clk_get(struct csis_state *state)
+{
+       struct device *dev = &state->pdev->dev;
+       int i;
+
+       for (i = 0; i < NUM_CSIS_CLOCKS; i++) {
+               state->clock[i] = clk_get(dev, csi_clock_name[i]);
+               if (IS_ERR(state->clock[i])) {
+                       s5pcsis_clk_put(state);
+                       dev_err(dev, "failed to get clock: %s\n",
+                               csi_clock_name[i]);
+                       return -ENXIO;
+               }
+       }
+       return 0;
+}
+
+static int s5pcsis_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct csis_state *state = sd_to_csis_state(sd);
+       struct device *dev = &state->pdev->dev;
+
+       if (on)
+               return pm_runtime_get_sync(dev);
+
+       return pm_runtime_put_sync(dev);
+}
+
+static void s5pcsis_start_stream(struct csis_state *state)
+{
+       s5pcsis_reset(state);
+       s5pcsis_set_params(state);
+       s5pcsis_system_enable(state, true);
+       s5pcsis_enable_interrupts(state, true);
+}
+
+static void s5pcsis_stop_stream(struct csis_state *state)
+{
+       s5pcsis_enable_interrupts(state, false);
+       s5pcsis_system_enable(state, false);
+}
+
+/* v4l2_subdev operations */
+static int s5pcsis_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct csis_state *state = sd_to_csis_state(sd);
+       int ret = 0;
+
+       v4l2_dbg(1, debug, sd, "%s: %d, state: 0x%x\n",
+                __func__, enable, state->flags);
+
+       if (enable) {
+               ret = pm_runtime_get_sync(&state->pdev->dev);
+               if (ret && ret != 1)
+                       return ret;
+       }
+       mutex_lock(&state->lock);
+       if (enable) {
+               if (state->flags & ST_SUSPENDED) {
+                       ret = -EBUSY;
+                       goto unlock;
+               }
+               s5pcsis_start_stream(state);
+               state->flags |= ST_STREAMING;
+       } else {
+               s5pcsis_stop_stream(state);
+               state->flags &= ~ST_STREAMING;
+       }
+unlock:
+       mutex_unlock(&state->lock);
+       if (!enable)
+               pm_runtime_put(&state->pdev->dev);
+
+       return ret == 1 ? 0 : ret;
+}
+
+static int s5pcsis_enum_mbus_code(struct v4l2_subdev *sd,
+                                 struct v4l2_subdev_fh *fh,
+                                 struct v4l2_subdev_mbus_code_enum *code)
+{
+       if (code->index >= ARRAY_SIZE(s5pcsis_formats))
+               return -EINVAL;
+
+       code->code = s5pcsis_formats[code->index].code;
+       return 0;
+}
+
+static struct csis_pix_format const *s5pcsis_try_format(
+       struct v4l2_mbus_framefmt *mf)
+{
+       struct csis_pix_format const *csis_fmt;
+
+       csis_fmt = find_csis_format(mf);
+       if (csis_fmt == NULL)
+               csis_fmt = &s5pcsis_formats[0];
+
+       mf->code = csis_fmt->code;
+       v4l_bound_align_image(&mf->width, 1, CSIS_MAX_PIX_WIDTH,
+                             csis_fmt->pix_width_alignment,
+                             &mf->height, 1, CSIS_MAX_PIX_HEIGHT, 1,
+                             0);
+       return csis_fmt;
+}
+
+static struct v4l2_mbus_framefmt *__s5pcsis_get_format(
+               struct csis_state *state, struct v4l2_subdev_fh *fh,
+               u32 pad, enum v4l2_subdev_format_whence which)
+{
+       if (which == V4L2_SUBDEV_FORMAT_TRY)
+               return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL;
+
+       return &state->format;
+}
+
+static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                          struct v4l2_subdev_format *fmt)
+{
+       struct csis_state *state = sd_to_csis_state(sd);
+       struct csis_pix_format const *csis_fmt;
+       struct v4l2_mbus_framefmt *mf;
+
+       if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK)
+               return -EINVAL;
+
+       mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which);
+
+       if (fmt->pad == CSIS_PAD_SOURCE) {
+               if (mf) {
+                       mutex_lock(&state->lock);
+                       fmt->format = *mf;
+                       mutex_unlock(&state->lock);
+               }
+               return 0;
+       }
+       csis_fmt = s5pcsis_try_format(&fmt->format);
+       if (mf) {
+               mutex_lock(&state->lock);
+               *mf = fmt->format;
+               if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+                       state->csis_fmt = csis_fmt;
+               mutex_unlock(&state->lock);
+       }
+       return 0;
+}
+
+static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                          struct v4l2_subdev_format *fmt)
+{
+       struct csis_state *state = sd_to_csis_state(sd);
+       struct v4l2_mbus_framefmt *mf;
+
+       if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK)
+               return -EINVAL;
+
+       mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which);
+       if (!mf)
+               return -EINVAL;
+
+       mutex_lock(&state->lock);
+       fmt->format = *mf;
+       mutex_unlock(&state->lock);
+       return 0;
+}
+
+static struct v4l2_subdev_core_ops s5pcsis_core_ops = {
+       .s_power = s5pcsis_s_power,
+};
+
+static struct v4l2_subdev_pad_ops s5pcsis_pad_ops = {
+       .enum_mbus_code = s5pcsis_enum_mbus_code,
+       .get_fmt = s5pcsis_get_fmt,
+       .set_fmt = s5pcsis_set_fmt,
+};
+
+static struct v4l2_subdev_video_ops s5pcsis_video_ops = {
+       .s_stream = s5pcsis_s_stream,
+};
+
+static struct v4l2_subdev_ops s5pcsis_subdev_ops = {
+       .core = &s5pcsis_core_ops,
+       .pad = &s5pcsis_pad_ops,
+       .video = &s5pcsis_video_ops,
+};
+
+static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id)
+{
+       struct csis_state *state = dev_id;
+       u32 val;
+
+       /* Just clear the interrupt pending bits. */
+       val = s5pcsis_read(state, S5PCSIS_INTSRC);
+       s5pcsis_write(state, S5PCSIS_INTSRC, val);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit s5pcsis_probe(struct platform_device *pdev)
+{
+       struct s5p_platform_mipi_csis *pdata;
+       struct resource *mem_res;
+       struct resource *regs_res;
+       struct csis_state *state;
+       int ret = -ENOMEM;
+
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return -ENOMEM;
+
+       mutex_init(&state->lock);
+       state->pdev = pdev;
+
+       pdata = pdev->dev.platform_data;
+       if (pdata == NULL || pdata->phy_enable == NULL) {
+               dev_err(&pdev->dev, "Platform data not fully specified\n");
+               goto e_free;
+       }
+
+       if ((pdev->id == 1 && pdata->lanes > CSIS1_MAX_LANES) ||
+           pdata->lanes > CSIS0_MAX_LANES) {
+               ret = -EINVAL;
+               dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n",
+                       pdata->lanes);
+               goto e_free;
+       }
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem_res) {
+               dev_err(&pdev->dev, "Failed to get IO memory region\n");
+               goto e_free;
+       }
+
+       regs_res = request_mem_region(mem_res->start, resource_size(mem_res),
+                                     pdev->name);
+       if (!regs_res) {
+               dev_err(&pdev->dev, "Failed to request IO memory region\n");
+               goto e_free;
+       }
+       state->regs_res = regs_res;
+
+       state->regs = ioremap(mem_res->start, resource_size(mem_res));
+       if (!state->regs) {
+               dev_err(&pdev->dev, "Failed to remap IO region\n");
+               goto e_reqmem;
+       }
+
+       ret = s5pcsis_clk_get(state);
+       if (ret)
+               goto e_unmap;
+
+       clk_enable(state->clock[CSIS_CLK_MUX]);
+       if (pdata->clk_rate)
+               clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate);
+       else
+               dev_WARN(&pdev->dev, "No clock frequency specified!\n");
+
+       state->irq = platform_get_irq(pdev, 0);
+       if (state->irq < 0) {
+               ret = state->irq;
+               dev_err(&pdev->dev, "Failed to get irq\n");
+               goto e_clkput;
+       }
+
+       if (!pdata->fixed_phy_vdd) {
+               state->supply = regulator_get(&pdev->dev, "vdd");
+               if (IS_ERR(state->supply)) {
+                       ret = PTR_ERR(state->supply);
+                       state->supply = NULL;
+                       goto e_clkput;
+               }
+       }
+
+       ret = request_irq(state->irq, s5pcsis_irq_handler, 0,
+                         dev_name(&pdev->dev), state);
+       if (ret) {
+               dev_err(&pdev->dev, "request_irq failed\n");
+               goto e_regput;
+       }
+
+       v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops);
+       state->sd.owner = THIS_MODULE;
+       strlcpy(state->sd.name, dev_name(&pdev->dev), sizeof(state->sd.name));
+       state->csis_fmt = &s5pcsis_formats[0];
+
+       state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+       state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+       ret = media_entity_init(&state->sd.entity,
+                               CSIS_PADS_NUM, state->pads, 0);
+       if (ret < 0)
+               goto e_irqfree;
+
+       /* This allows to retrieve the platform device id by the host driver */
+       v4l2_set_subdevdata(&state->sd, pdev);
+
+       /* .. and a pointer to the subdev. */
+       platform_set_drvdata(pdev, &state->sd);
+
+       state->flags = ST_SUSPENDED;
+       pm_runtime_enable(&pdev->dev);
+
+       return 0;
+
+e_irqfree:
+       free_irq(state->irq, state);
+e_regput:
+       if (state->supply)
+               regulator_put(state->supply);
+e_clkput:
+       clk_disable(state->clock[CSIS_CLK_MUX]);
+       s5pcsis_clk_put(state);
+e_unmap:
+       iounmap(state->regs);
+e_reqmem:
+       release_mem_region(regs_res->start, resource_size(regs_res));
+e_free:
+       kfree(state);
+       return ret;
+}
+
+static int s5pcsis_suspend(struct device *dev)
+{
+       struct s5p_platform_mipi_csis *pdata = dev->platform_data;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+       struct csis_state *state = sd_to_csis_state(sd);
+       int ret = 0;
+
+       v4l2_dbg(1, debug, sd, "%s: flags: 0x%x\n",
+                __func__, state->flags);
+
+       mutex_lock(&state->lock);
+       if (state->flags & ST_POWERED) {
+               s5pcsis_stop_stream(state);
+               ret = pdata->phy_enable(state->pdev, false);
+               if (ret)
+                       goto unlock;
+               if (state->supply) {
+                       ret = regulator_disable(state->supply);
+                       if (ret)
+                               goto unlock;
+               }
+               clk_disable(state->clock[CSIS_CLK_GATE]);
+               state->flags &= ~ST_POWERED;
+       }
+       state->flags |= ST_SUSPENDED;
+ unlock:
+       mutex_unlock(&state->lock);
+       return ret ? -EAGAIN : 0;
+}
+
+static int s5pcsis_resume(struct device *dev)
+{
+       struct s5p_platform_mipi_csis *pdata = dev->platform_data;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+       struct csis_state *state = sd_to_csis_state(sd);
+       int ret = 0;
+
+       v4l2_dbg(1, debug, sd, "%s: flags: 0x%x\n",
+                __func__, state->flags);
+
+       mutex_lock(&state->lock);
+       if (!(state->flags & ST_SUSPENDED))
+               goto unlock;
+
+       if (!(state->flags & ST_POWERED)) {
+               if (state->supply)
+                       ret = regulator_enable(state->supply);
+               if (ret)
+                       goto unlock;
+
+               ret = pdata->phy_enable(state->pdev, true);
+               if (!ret) {
+                       state->flags |= ST_POWERED;
+               } else if (state->supply) {
+                       regulator_disable(state->supply);
+                       goto unlock;
+               }
+               clk_enable(state->clock[CSIS_CLK_GATE]);
+       }
+       if (state->flags & ST_STREAMING)
+               s5pcsis_start_stream(state);
+
+       state->flags &= ~ST_SUSPENDED;
+ unlock:
+       mutex_unlock(&state->lock);
+       return ret ? -EAGAIN : 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int s5pcsis_pm_suspend(struct device *dev)
+{
+       return s5pcsis_suspend(dev);
+}
+
+static int s5pcsis_pm_resume(struct device *dev)
+{
+       int ret;
+
+       ret = s5pcsis_resume(dev);
+
+       if (!ret) {
+               pm_runtime_disable(dev);
+               ret = pm_runtime_set_active(dev);
+               pm_runtime_enable(dev);
+       }
+
+       return ret;
+}
+#endif
+
+static int __devexit s5pcsis_remove(struct platform_device *pdev)
+{
+       struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+       struct csis_state *state = sd_to_csis_state(sd);
+       struct resource *res = state->regs_res;
+
+       pm_runtime_disable(&pdev->dev);
+       s5pcsis_suspend(&pdev->dev);
+       clk_disable(state->clock[CSIS_CLK_MUX]);
+       pm_runtime_set_suspended(&pdev->dev);
+
+       s5pcsis_clk_put(state);
+       if (state->supply)
+               regulator_put(state->supply);
+
+       media_entity_cleanup(&state->sd.entity);
+       free_irq(state->irq, state);
+       iounmap(state->regs);
+       release_mem_region(res->start, resource_size(res));
+       kfree(state);
+
+       return 0;
+}
+
+static const struct dev_pm_ops s5pcsis_pm_ops = {
+       SET_RUNTIME_PM_OPS(s5pcsis_suspend, s5pcsis_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_pm_suspend, s5pcsis_pm_resume)
+};
+
+static struct platform_driver s5pcsis_driver = {
+       .probe          = s5pcsis_probe,
+       .remove         = __devexit_p(s5pcsis_remove),
+       .driver         = {
+               .name   = CSIS_DRIVER_NAME,
+               .owner  = THIS_MODULE,
+               .pm     = &s5pcsis_pm_ops,
+       },
+};
+
+static int __init s5pcsis_init(void)
+{
+       return platform_driver_probe(&s5pcsis_driver, s5pcsis_probe);
+}
+
+static void __exit s5pcsis_exit(void)
+{
+       platform_driver_unregister(&s5pcsis_driver);
+}
+
+module_init(s5pcsis_init);
+module_exit(s5pcsis_exit);
+
+MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
+MODULE_DESCRIPTION("S5P/EXYNOS4 MIPI CSI receiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/s5p-fimc/mipi-csis.h b/drivers/media/video/s5p-fimc/mipi-csis.h
new file mode 100644 (file)
index 0000000..f569133
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *
+ * 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 S5P_MIPI_CSIS_H_
+#define S5P_MIPI_CSIS_H_
+
+#define CSIS_DRIVER_NAME       "s5p-mipi-csis"
+#define CSIS_MAX_ENTITIES      2
+#define CSIS0_MAX_LANES                4
+#define CSIS1_MAX_LANES                2
+
+#define CSIS_PAD_SINK          0
+#define CSIS_PAD_SOURCE                1
+#define CSIS_PADS_NUM          2
+
+#endif
index 50f1be0..e2062b2 100644 (file)
@@ -5591,6 +5591,105 @@ struct saa7134_board saa7134_boards[] = {
                        .amux = TV,
                },
        },
+       [SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2] = {
+               /* Timothy Lee <timothy.lee@siriushk.com> */
+               .name           = "MagicPro ProHDTV Pro2 DMB-TH/Hybrid",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_config   = 3,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .gpiomask       = 0x02050000,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .ts_type        = SAA7134_MPEG_TS_PARALLEL,
+               .inputs         = { {
+                       .name   = name_tv,
+                       .vmux   = 1,
+                       .amux   = TV,
+                       .tv     = 1,
+                       .gpio   = 0x00050000,
+               }, {
+                       .name   = name_comp1,
+                       .vmux   = 3,
+                       .amux   = LINE1,
+                       .gpio   = 0x00050000,
+               }, {
+                       .name   = name_svideo,
+                       .vmux   = 8,
+                       .amux   = LINE1,
+                       .gpio   = 0x00050000,
+               } },
+               .radio = {
+                       .name   = name_radio,
+                       .amux   = TV,
+                       .gpio   = 0x00050000,
+               },
+               .mute = {
+                       .name   = name_mute,
+                       .vmux   = 0,
+                       .amux   = TV,
+                       .gpio   = 0x00050000,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_501] = {
+               /*       Beholder Intl. Ltd. 2010       */
+               /* Dmitry Belimov <d.belimov@gmail.com> */
+               .name           = "Beholder BeholdTV 501",
+               .audio_clock    = 0x00200000,
+               .tuner_type     = TUNER_ABSENT,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .gpiomask       = 0x00008000,
+               .inputs         = { {
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = LINE2,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+               .mute = {
+                       .name = name_mute,
+                       .amux = LINE1,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_503FM] = {
+               /*       Beholder Intl. Ltd. 2010       */
+               /* Dmitry Belimov <d.belimov@gmail.com> */
+               .name           = "Beholder BeholdTV 503 FM",
+               .audio_clock    = 0x00200000,
+               .tuner_type     = TUNER_ABSENT,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .gpiomask       = 0x00008000,
+               .inputs         = { {
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = LINE2,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+               .mute = {
+                       .name = name_mute,
+                       .amux = LINE1,
+               },
+       },
 
 };
 
@@ -6795,6 +6894,24 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x185b,
                .subdevice    = 0xc900,
                .driver_data  = SAA7134_BOARD_VIDEOMATE_M1F,
+       }, {
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x5ace,
+               .subdevice    = 0x5030,
+               .driver_data  = SAA7134_BOARD_BEHOLD_503FM,
+       }, {
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+               .subvendor    = 0x5ace,
+               .subdevice    = 0x5010,
+               .driver_data  = SAA7134_BOARD_BEHOLD_501,
+       }, {
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x17de,
+               .subdevice    = 0xd136,
+               .driver_data  = SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2,
        }, {
                /* --- boards without eeprom + subsystem ID --- */
                .vendor       = PCI_VENDOR_ID_PHILIPS,
@@ -6988,6 +7105,7 @@ static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev,
                switch (dev->board) {
                case SAA7134_BOARD_HAUPPAUGE_HVR1150:
                case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+               case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
                        ret = saa7134_tda18271_hvr11x0_toggle_agc(dev, arg);
                        break;
                case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
@@ -7014,6 +7132,7 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev,
        case SAA7134_BOARD_HAUPPAUGE_HVR1120:
        case SAA7134_BOARD_AVERMEDIA_M733A:
        case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
+       case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
                /* tda8290 + tda18271 */
                ret = saa7134_tda8290_18271_callback(dev, command, arg);
                break;
@@ -7264,6 +7383,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
                break;
        case SAA7134_BOARD_HAUPPAUGE_HVR1150:
        case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+               dev->has_remote = SAA7134_REMOTE_GPIO;
                /* GPIO 26 high for digital, low for analog */
                saa7134_set_gpio(dev, 26, 0);
                msleep(1);
@@ -7326,6 +7446,11 @@ int saa7134_board_init1(struct saa7134_dev *dev)
                saa7134_set_gpio(dev, 1, 1);
                dev->has_remote = SAA7134_REMOTE_GPIO;
                break;
+       case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
+               /* enable LGS-8G75 */
+               saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x0e050000, 0x0c050000);
+               saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0e050000, 0x0c050000);
+               break;
        }
        return 0;
 }
index 41f836f..f9be737 100644 (file)
@@ -927,7 +927,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
        }
 
        /* print pci info */
-       pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+       dev->pci_rev = pci_dev->revision;
        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
        printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, "
               "latency: %d, mmio: 0x%llx\n", dev->name,
index f65cad2..996a206 100644 (file)
@@ -53,6 +53,7 @@
 #include "lgdt3305.h"
 #include "tda8290.h"
 #include "mb86a20s.h"
+#include "lgs8gxx.h"
 
 #include "zl10353.h"
 
@@ -1123,6 +1124,26 @@ static struct tda18271_config dtv1000s_tda18271_config = {
        .gate    = TDA18271_GATE_ANALOG,
 };
 
+static struct lgs8gxx_config prohdtv_pro2_lgs8g75_config = {
+       .prod = LGS8GXX_PROD_LGS8G75,
+       .demod_address = 0x1d,
+       .serial_ts = 0,
+       .ts_clk_pol = 1,
+       .ts_clk_gated = 0,
+       .if_clk_freq = 30400, /* 30.4 MHz */
+       .if_freq = 4000, /* 4.00 MHz */
+       .if_neg_center = 0,
+       .ext_adc = 0,
+       .adc_signed = 1,
+       .adc_vpp = 3, /* 2.0 Vpp */
+       .if_neg_edge = 1,
+};
+
+static struct tda18271_config prohdtv_pro2_tda18271_config = {
+       .gate = TDA18271_GATE_ANALOG,
+       .output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
 /* ==================================================================
  * Core code
  */
@@ -1674,6 +1695,19 @@ static int dvb_init(struct saa7134_dev *dev)
 
                /* mb86a20s need to use the I2C gateway */
                break;
+       case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
+               fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
+                                              &prohdtv_pro2_lgs8g75_config,
+                                              &dev->i2c_adap);
+               if (fe0->dvb.frontend != NULL) {
+                       dvb_attach(tda829x_attach, fe0->dvb.frontend,
+                                  &dev->i2c_adap, 0x4b,
+                                  &tda829x_no_probe);
+                       dvb_attach(tda18271_attach, fe0->dvb.frontend,
+                                  0x60, &dev->i2c_adap,
+                                  &prohdtv_pro2_tda18271_config);
+               }
+               break;
        default:
                wprintk("Huh? unknown DVB card?\n");
                break;
index be1c2a2..ff6c0e9 100644 (file)
@@ -756,6 +756,14 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                mask_keycode = 0x0ff00;
                mask_keyup   = 0x040000;
                break;
+       case SAA7134_BOARD_HAUPPAUGE_HVR1150:
+       case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+               ir_codes     = RC_MAP_HAUPPAUGE;
+               mask_keydown = 0x0040000;       /* Enable GPIO18 line on both edges */
+               mask_keyup   = 0x0040000;
+               mask_keycode = 0xffff;
+               raw_decode   = true;
+               break;
        }
        if (NULL == ir_codes) {
                printk("%s: Oops: IR config error [card=%d]\n",
index f96cd5d..28eb103 100644 (file)
@@ -328,6 +328,9 @@ struct saa7134_card_ir {
 #define SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG 182
 #define SAA7134_BOARD_VIDEOMATE_M1F         183
 #define SAA7134_BOARD_ENCORE_ENLTV_FM3      184
+#define SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2 185
+#define SAA7134_BOARD_BEHOLD_501            186
+#define SAA7134_BOARD_BEHOLD_503FM          187
 
 #define SAA7134_MAXBOARDS 32
 #define SAA7134_INPUT_MAX 8
index b813aec..3b7d7b4 100644 (file)
@@ -1247,7 +1247,7 @@ static int __devinit saa7164_initdev(struct pci_dev *pci_dev,
        }
 
        /* print pci info */
-       pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+       dev->pci_rev = pci_dev->revision;
        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
        printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
               "latency: %d, mmio: 0x%llx\n", dev->name,
index 134e86b..3ae5c9c 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/io.h>
+#include <linux/completion.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/errno.h>
@@ -106,6 +107,7 @@ struct sh_mobile_ceu_dev {
        struct vb2_alloc_ctx *alloc_ctx;
 
        struct sh_mobile_ceu_info *pdata;
+       struct completion complete;
 
        u32 cflcr;
 
@@ -114,6 +116,7 @@ struct sh_mobile_ceu_dev {
 
        unsigned int image_mode:1;
        unsigned int is_16bit:1;
+       unsigned int frozen:1;
 };
 
 struct sh_mobile_ceu_cam {
@@ -273,7 +276,8 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
        ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) & ~CEU_CEIER_MASK);
        status = ceu_read(pcdev, CETCR);
        ceu_write(pcdev, CETCR, ~status & CEU_CETCR_MAGIC);
-       ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | CEU_CEIER_MASK);
+       if (!pcdev->frozen)
+               ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | CEU_CEIER_MASK);
        ceu_write(pcdev, CAPCR, ceu_read(pcdev, CAPCR) & ~CEU_CAPCR_CTNCP);
        ceu_write(pcdev, CETCR, CEU_CETCR_MAGIC ^ CEU_CETCR_IGRW);
 
@@ -287,6 +291,11 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
                ret = -EIO;
        }
 
+       if (pcdev->frozen) {
+               complete(&pcdev->complete);
+               return ret;
+       }
+
        if (!pcdev->active)
                return ret;
 
@@ -378,12 +387,11 @@ static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb)
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);
-       unsigned long flags;
 
        dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
                vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
 
-       spin_lock_irqsave(&pcdev->lock, flags);
+       spin_lock_irq(&pcdev->lock);
        list_add_tail(&buf->queue, &pcdev->capture);
 
        if (!pcdev->active) {
@@ -395,7 +403,7 @@ static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb)
                pcdev->active = vb;
                sh_mobile_ceu_capture(pcdev);
        }
-       spin_unlock_irqrestore(&pcdev->lock, flags);
+       spin_unlock_irq(&pcdev->lock);
 }
 
 static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
@@ -404,9 +412,8 @@ static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
-       unsigned long flags;
 
-       spin_lock_irqsave(&pcdev->lock, flags);
+       spin_lock_irq(&pcdev->lock);
 
        if (pcdev->active == vb) {
                /* disable capture (release DMA buffer), reset */
@@ -417,7 +424,7 @@ static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
        /* Doesn't hurt also if the list is empty */
        list_del_init(&buf->queue);
 
-       spin_unlock_irqrestore(&pcdev->lock, flags);
+       spin_unlock_irq(&pcdev->lock);
 }
 
 static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb)
@@ -427,6 +434,25 @@ static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb)
        return 0;
 }
 
+static int sh_mobile_ceu_stop_streaming(struct vb2_queue *q)
+{
+       struct soc_camera_device *icd = container_of(q, struct soc_camera_device, vb2_vidq);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct sh_mobile_ceu_dev *pcdev = ici->priv;
+       struct list_head *buf_head, *tmp;
+
+       spin_lock_irq(&pcdev->lock);
+
+       pcdev->active = NULL;
+
+       list_for_each_safe(buf_head, tmp, &pcdev->capture)
+               list_del_init(buf_head);
+
+       spin_unlock_irq(&pcdev->lock);
+
+       return sh_mobile_ceu_soft_reset(pcdev);
+}
+
 static struct vb2_ops sh_mobile_ceu_videobuf_ops = {
        .queue_setup    = sh_mobile_ceu_videobuf_setup,
        .buf_prepare    = sh_mobile_ceu_videobuf_prepare,
@@ -435,6 +461,7 @@ static struct vb2_ops sh_mobile_ceu_videobuf_ops = {
        .buf_init       = sh_mobile_ceu_videobuf_init,
        .wait_prepare   = soc_camera_unlock,
        .wait_finish    = soc_camera_lock,
+       .stop_streaming = sh_mobile_ceu_stop_streaming,
 };
 
 static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
@@ -500,7 +527,6 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
-       unsigned long flags;
 
        BUG_ON(icd != pcdev->icd);
 
@@ -509,13 +535,13 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
        sh_mobile_ceu_soft_reset(pcdev);
 
        /* make sure active buffer is canceled */
-       spin_lock_irqsave(&pcdev->lock, flags);
+       spin_lock_irq(&pcdev->lock);
        if (pcdev->active) {
                list_del_init(&to_ceu_vb(pcdev->active)->queue);
                vb2_buffer_done(pcdev->active, VB2_BUF_STATE_ERROR);
                pcdev->active = NULL;
        }
-       spin_unlock_irqrestore(&pcdev->lock, flags);
+       spin_unlock_irq(&pcdev->lock);
 
        pm_runtime_put_sync(ici->v4l2_dev.dev);
 
@@ -891,8 +917,8 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
 
        fmt = soc_mbus_get_fmtdesc(code);
        if (!fmt) {
-               dev_err(dev, "Invalid format code #%u: %d\n", idx, code);
-               return -EINVAL;
+               dev_warn(dev, "unsupported format code #%u: %d\n", idx, code);
+               return 0;
        }
 
        if (!pcdev->pdata->csi2_dev) {
@@ -1330,7 +1356,7 @@ static int client_scale(struct soc_camera_device *icd,
 /*
  * CEU can scale and crop, but we don't want to waste bandwidth and kill the
  * framerate by always requesting the maximum image from the client. See
- * Documentation/video4linux/sh_mobile_camera_ceu.txt for a description of
+ * Documentation/video4linux/sh_mobile_ceu_camera.txt for a description of
  * scaling and cropping algorithms and for the meaning of referenced here steps.
  */
 static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
@@ -1377,10 +1403,6 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
        if (mf.width > 2560 || mf.height > 1920)
                return -EINVAL;
 
-       /* Cache camera output window */
-       cam->width      = mf.width;
-       cam->height     = mf.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);
@@ -1389,6 +1411,39 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
        interm_width    = scale_down(rect->width, scale_cam_h);
        interm_height   = scale_down(rect->height, scale_cam_v);
 
+       if (interm_width < icd->user_width) {
+               u32 new_scale_h;
+
+               new_scale_h = calc_generic_scale(rect->width, icd->user_width);
+
+               mf.width = scale_down(cam_rect->width, new_scale_h);
+       }
+
+       if (interm_height < icd->user_height) {
+               u32 new_scale_v;
+
+               new_scale_v = calc_generic_scale(rect->height, icd->user_height);
+
+               mf.height = scale_down(cam_rect->height, new_scale_v);
+       }
+
+       if (interm_width < icd->user_width || interm_height < icd->user_height) {
+               ret = v4l2_device_call_until_err(sd->v4l2_dev, (int)icd, video,
+                                                s_mbus_fmt, &mf);
+               if (ret < 0)
+                       return ret;
+
+               dev_geo(dev, "New camera output %ux%u\n", mf.width, mf.height);
+               scale_cam_h     = calc_generic_scale(cam_rect->width, mf.width);
+               scale_cam_v     = calc_generic_scale(cam_rect->height, mf.height);
+               interm_width    = scale_down(rect->width, scale_cam_h);
+               interm_height   = scale_down(rect->height, scale_cam_v);
+       }
+
+       /* Cache camera output window */
+       cam->width      = mf.width;
+       cam->height     = mf.height;
+
        if (pcdev->image_mode) {
                out_width       = min(interm_width, icd->user_width);
                out_height      = min(interm_height, icd->user_height);
@@ -1704,6 +1759,63 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
        return ret;
 }
 
+static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd,
+                                     struct v4l2_crop *a)
+{
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct sh_mobile_ceu_dev *pcdev = ici->priv;
+       u32 out_width = icd->user_width, out_height = icd->user_height;
+       int ret;
+
+       /* Freeze queue */
+       pcdev->frozen = 1;
+       /* Wait for frame */
+       ret = wait_for_completion_interruptible(&pcdev->complete);
+       /* Stop the client */
+       ret = v4l2_subdev_call(sd, video, s_stream, 0);
+       if (ret < 0)
+               dev_warn(icd->dev.parent,
+                        "Client failed to stop the stream: %d\n", ret);
+       else
+               /* Do the crop, if it fails, there's nothing more we can do */
+               sh_mobile_ceu_set_crop(icd, a);
+
+       dev_geo(icd->dev.parent, "Output after crop: %ux%u\n", icd->user_width, icd->user_height);
+
+       if (icd->user_width != out_width || icd->user_height != out_height) {
+               struct v4l2_format f = {
+                       .type   = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                       .fmt.pix        = {
+                               .width          = out_width,
+                               .height         = out_height,
+                               .pixelformat    = icd->current_fmt->host_fmt->fourcc,
+                               .field          = pcdev->field,
+                               .colorspace     = icd->colorspace,
+                       },
+               };
+               ret = sh_mobile_ceu_set_fmt(icd, &f);
+               if (!ret && (out_width != f.fmt.pix.width ||
+                            out_height != f.fmt.pix.height))
+                       ret = -EINVAL;
+               if (!ret) {
+                       icd->user_width         = out_width;
+                       icd->user_height        = out_height;
+                       ret = sh_mobile_ceu_set_bus_param(icd,
+                                       icd->current_fmt->host_fmt->fourcc);
+               }
+       }
+
+       /* Thaw the queue */
+       pcdev->frozen = 0;
+       spin_lock_irq(&pcdev->lock);
+       sh_mobile_ceu_capture(pcdev);
+       spin_unlock_irq(&pcdev->lock);
+       /* Start the client */
+       ret = v4l2_subdev_call(sd, video, s_stream, 1);
+       return ret;
+}
+
 static unsigned int sh_mobile_ceu_poll(struct file *file, poll_table *pt)
 {
        struct soc_camera_device *icd = file->private_data;
@@ -1790,6 +1902,7 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
        .put_formats    = sh_mobile_ceu_put_formats,
        .get_crop       = sh_mobile_ceu_get_crop,
        .set_crop       = sh_mobile_ceu_set_crop,
+       .set_livecrop   = sh_mobile_ceu_set_livecrop,
        .set_fmt        = sh_mobile_ceu_set_fmt,
        .try_fmt        = sh_mobile_ceu_try_fmt,
        .set_ctrl       = sh_mobile_ceu_set_ctrl,
@@ -1856,6 +1969,7 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
 
        INIT_LIST_HEAD(&pcdev->capture);
        spin_lock_init(&pcdev->lock);
+       init_completion(&pcdev->complete);
 
        pcdev->pdata = pdev->dev.platform_data;
        if (!pcdev->pdata) {
index ddb4c09..3988643 100644 (file)
 #define DEFAULT_WIDTH  640
 #define DEFAULT_HEIGHT 480
 
+#define is_streaming(ici, icd)                         \
+       (((ici)->ops->init_videobuf) ?                  \
+        (icd)->vb_vidq.streaming :                     \
+        vb2_is_streaming(&(icd)->vb2_vidq))
+
 static LIST_HEAD(hosts);
 static LIST_HEAD(devices);
 static DEFINE_MUTEX(list_lock);                /* Protects the list of hosts */
@@ -358,8 +363,6 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd)
        if (!icd->user_formats)
                return -ENOMEM;
 
-       icd->num_user_formats = fmts;
-
        dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts);
 
        /* Second pass - actually fill data formats */
@@ -367,9 +370,10 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd)
        for (i = 0; i < raw_fmts; i++)
                if (!ici->ops->get_formats) {
                        v4l2_subdev_call(sd, video, enum_mbus_fmt, i, &code);
-                       icd->user_formats[i].host_fmt =
+                       icd->user_formats[fmts].host_fmt =
                                soc_mbus_get_fmtdesc(code);
-                       icd->user_formats[i].code = code;
+                       if (icd->user_formats[fmts].host_fmt)
+                               icd->user_formats[fmts++].code = code;
                } else {
                        ret = ici->ops->get_formats(icd, i,
                                                    &icd->user_formats[fmts]);
@@ -378,12 +382,12 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd)
                        fmts += ret;
                }
 
+       icd->num_user_formats = fmts;
        icd->current_fmt = &icd->user_formats[0];
 
        return 0;
 
 egfmt:
-       icd->num_user_formats = 0;
        vfree(icd->user_formats);
        return ret;
 }
@@ -662,7 +666,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
        if (icd->streamer && icd->streamer != file)
                return -EBUSY;
 
-       if (icd->vb_vidq.bufs[0]) {
+       if (is_streaming(to_soc_camera_host(icd->dev.parent), icd)) {
                dev_err(&icd->dev, "S_FMT denied: queue initialised\n");
                return -EBUSY;
        }
@@ -903,14 +907,17 @@ static int soc_camera_s_crop(struct file *file, void *fh,
        if (ret < 0) {
                dev_err(&icd->dev,
                        "S_CROP denied: getting current crop failed\n");
-       } else if (icd->vb_vidq.bufs[0] &&
-                  (a->c.width != current_crop.c.width ||
-                   a->c.height != current_crop.c.height)) {
+       } else if ((a->c.width == current_crop.c.width &&
+                   a->c.height == current_crop.c.height) ||
+                  !is_streaming(ici, icd)) {
+               /* same size or not streaming - use .set_crop() */
+               ret = ici->ops->set_crop(icd, a);
+       } else if (ici->ops->set_livecrop) {
+               ret = ici->ops->set_livecrop(icd, a);
+       } else {
                dev_err(&icd->dev,
                        "S_CROP denied: queue initialised and sizes differ\n");
                ret = -EBUSY;
-       } else {
-               ret = ici->ops->set_crop(icd, a);
        }
 
        return ret;
index ed77aa0..bea7c9c 100644 (file)
 #include <media/v4l2-mediabus.h>
 #include <media/soc_mediabus.h>
 
-#define MBUS_IDX(f) (V4L2_MBUS_FMT_ ## f - V4L2_MBUS_FMT_FIXED - 1)
-
-static const struct soc_mbus_pixelfmt mbus_fmt[] = {
-       [MBUS_IDX(YUYV8_2X8)] = {
+static const struct soc_mbus_lookup mbus_fmt[] = {
+{
+       .code = V4L2_MBUS_FMT_YUYV8_2X8,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_YUYV,
                .name                   = "YUYV",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_LE,
        },
-       [MBUS_IDX(YVYU8_2X8)] = {
+}, {
+       .code = V4L2_MBUS_FMT_YVYU8_2X8,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_YVYU,
                .name                   = "YVYU",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_LE,
        },
-       [MBUS_IDX(UYVY8_2X8)] = {
+}, {
+       .code = V4L2_MBUS_FMT_UYVY8_2X8,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_UYVY,
                .name                   = "UYVY",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_LE,
        },
-       [MBUS_IDX(VYUY8_2X8)] = {
+}, {
+       .code = V4L2_MBUS_FMT_VYUY8_2X8,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_VYUY,
                .name                   = "VYUY",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_LE,
        },
-       [MBUS_IDX(RGB555_2X8_PADHI_LE)] = {
+}, {
+       .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_RGB555,
                .name                   = "RGB555",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_LE,
        },
-       [MBUS_IDX(RGB555_2X8_PADHI_BE)] = {
+}, {
+       .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_RGB555X,
                .name                   = "RGB555X",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_LE,
        },
-       [MBUS_IDX(RGB565_2X8_LE)] = {
+}, {
+       .code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_RGB565,
                .name                   = "RGB565",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_LE,
        },
-       [MBUS_IDX(RGB565_2X8_BE)] = {
+}, {
+       .code = V4L2_MBUS_FMT_RGB565_2X8_BE,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_RGB565X,
                .name                   = "RGB565X",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_LE,
        },
-       [MBUS_IDX(SBGGR8_1X8)] = {
+}, {
+       .code = V4L2_MBUS_FMT_SBGGR8_1X8,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_SBGGR8,
                .name                   = "Bayer 8 BGGR",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_NONE,
                .order                  = SOC_MBUS_ORDER_LE,
        },
-       [MBUS_IDX(SBGGR10_1X10)] = {
+}, {
+       .code = V4L2_MBUS_FMT_SBGGR10_1X10,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_SBGGR10,
                .name                   = "Bayer 10 BGGR",
                .bits_per_sample        = 10,
                .packing                = SOC_MBUS_PACKING_EXTEND16,
                .order                  = SOC_MBUS_ORDER_LE,
        },
-       [MBUS_IDX(Y8_1X8)] = {
+}, {
+       .code = V4L2_MBUS_FMT_Y8_1X8,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_GREY,
                .name                   = "Grey",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_NONE,
                .order                  = SOC_MBUS_ORDER_LE,
        },
-       [MBUS_IDX(Y10_1X10)] = {
+}, {
+       .code = V4L2_MBUS_FMT_Y10_1X10,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_Y10,
                .name                   = "Grey 10bit",
                .bits_per_sample        = 10,
                .packing                = SOC_MBUS_PACKING_EXTEND16,
                .order                  = SOC_MBUS_ORDER_LE,
        },
-       [MBUS_IDX(SBGGR10_2X8_PADHI_LE)] = {
+}, {
+       .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_SBGGR10,
                .name                   = "Bayer 10 BGGR",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_LE,
        },
-       [MBUS_IDX(SBGGR10_2X8_PADLO_LE)] = {
+}, {
+       .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_SBGGR10,
                .name                   = "Bayer 10 BGGR",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADLO,
                .order                  = SOC_MBUS_ORDER_LE,
        },
-       [MBUS_IDX(SBGGR10_2X8_PADHI_BE)] = {
+}, {
+       .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_SBGGR10,
                .name                   = "Bayer 10 BGGR",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_BE,
        },
-       [MBUS_IDX(SBGGR10_2X8_PADLO_BE)] = {
+}, {
+       .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
+       .fmt = {
                .fourcc                 = V4L2_PIX_FMT_SBGGR10,
                .name                   = "Bayer 10 BGGR",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADLO,
                .order                  = SOC_MBUS_ORDER_BE,
        },
+}, {
+       .code = V4L2_MBUS_FMT_JPEG_1X8,
+       .fmt = {
+               .fourcc                 = V4L2_PIX_FMT_JPEG,
+               .name                   = "JPEG",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_VARIABLE,
+               .order                  = SOC_MBUS_ORDER_LE,
+       },
+}, {
+       .code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE,
+       .fmt = {
+               .fourcc                 = V4L2_PIX_FMT_RGB444,
+               .name                   = "RGB444",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_2X8_PADHI,
+               .order                  = SOC_MBUS_ORDER_BE,
+       },
+}, {
+       .code = V4L2_MBUS_FMT_YUYV8_1_5X8,
+       .fmt = {
+               .fourcc                 = V4L2_PIX_FMT_YUV420,
+               .name                   = "YUYV 4:2:0",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_1_5X8,
+               .order                  = SOC_MBUS_ORDER_LE,
+       },
+}, {
+       .code = V4L2_MBUS_FMT_YVYU8_1_5X8,
+       .fmt = {
+               .fourcc                 = V4L2_PIX_FMT_YVU420,
+               .name                   = "YVYU 4:2:0",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_1_5X8,
+               .order                  = SOC_MBUS_ORDER_LE,
+       },
+}, {
+       .code = V4L2_MBUS_FMT_UYVY8_1X16,
+       .fmt = {
+               .fourcc                 = V4L2_PIX_FMT_UYVY,
+               .name                   = "UYVY 16bit",
+               .bits_per_sample        = 16,
+               .packing                = SOC_MBUS_PACKING_EXTEND16,
+               .order                  = SOC_MBUS_ORDER_LE,
+       },
+}, {
+       .code = V4L2_MBUS_FMT_VYUY8_1X16,
+       .fmt = {
+               .fourcc                 = V4L2_PIX_FMT_VYUY,
+               .name                   = "VYUY 16bit",
+               .bits_per_sample        = 16,
+               .packing                = SOC_MBUS_PACKING_EXTEND16,
+               .order                  = SOC_MBUS_ORDER_LE,
+       },
+}, {
+       .code = V4L2_MBUS_FMT_YUYV8_1X16,
+       .fmt = {
+               .fourcc                 = V4L2_PIX_FMT_YUYV,
+               .name                   = "YUYV 16bit",
+               .bits_per_sample        = 16,
+               .packing                = SOC_MBUS_PACKING_EXTEND16,
+               .order                  = SOC_MBUS_ORDER_LE,
+       },
+}, {
+       .code = V4L2_MBUS_FMT_YVYU8_1X16,
+       .fmt = {
+               .fourcc                 = V4L2_PIX_FMT_YVYU,
+               .name                   = "YVYU 16bit",
+               .bits_per_sample        = 16,
+               .packing                = SOC_MBUS_PACKING_EXTEND16,
+               .order                  = SOC_MBUS_ORDER_LE,
+       },
+}, {
+       .code = V4L2_MBUS_FMT_SGRBG8_1X8,
+       .fmt = {
+               .fourcc                 = V4L2_PIX_FMT_SGRBG8,
+               .name                   = "Bayer 8 GRBG",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_NONE,
+               .order                  = SOC_MBUS_ORDER_LE,
+       },
+}, {
+       .code = V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
+       .fmt = {
+               .fourcc                 = V4L2_PIX_FMT_SGRBG10DPCM8,
+               .name                   = "Bayer 10 BGGR DPCM 8",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_NONE,
+               .order                  = SOC_MBUS_ORDER_LE,
+       },
+}, {
+       .code = V4L2_MBUS_FMT_SGBRG10_1X10,
+       .fmt = {
+               .fourcc                 = V4L2_PIX_FMT_SGBRG10,
+               .name                   = "Bayer 10 GBRG",
+               .bits_per_sample        = 10,
+               .packing                = SOC_MBUS_PACKING_EXTEND16,
+               .order                  = SOC_MBUS_ORDER_LE,
+       },
+}, {
+       .code = V4L2_MBUS_FMT_SGRBG10_1X10,
+       .fmt = {
+               .fourcc                 = V4L2_PIX_FMT_SGRBG10,
+               .name                   = "Bayer 10 GRBG",
+               .bits_per_sample        = 10,
+               .packing                = SOC_MBUS_PACKING_EXTEND16,
+               .order                  = SOC_MBUS_ORDER_LE,
+       },
+}, {
+       .code = V4L2_MBUS_FMT_SRGGB10_1X10,
+       .fmt = {
+               .fourcc                 = V4L2_PIX_FMT_SRGGB10,
+               .name                   = "Bayer 10 RGGB",
+               .bits_per_sample        = 10,
+               .packing                = SOC_MBUS_PACKING_EXTEND16,
+               .order                  = SOC_MBUS_ORDER_LE,
+       },
+}, {
+       .code = V4L2_MBUS_FMT_SBGGR12_1X12,
+       .fmt = {
+               .fourcc                 = V4L2_PIX_FMT_SBGGR12,
+               .name                   = "Bayer 12 BGGR",
+               .bits_per_sample        = 12,
+               .packing                = SOC_MBUS_PACKING_EXTEND16,
+               .order                  = SOC_MBUS_ORDER_LE,
+       },
+}, {
+       .code = V4L2_MBUS_FMT_SGBRG12_1X12,
+       .fmt = {
+               .fourcc                 = V4L2_PIX_FMT_SGBRG12,
+               .name                   = "Bayer 12 GBRG",
+               .bits_per_sample        = 12,
+               .packing                = SOC_MBUS_PACKING_EXTEND16,
+               .order                  = SOC_MBUS_ORDER_LE,
+       },
+}, {
+       .code = V4L2_MBUS_FMT_SGRBG12_1X12,
+       .fmt = {
+               .fourcc                 = V4L2_PIX_FMT_SGRBG12,
+               .name                   = "Bayer 12 GRBG",
+               .bits_per_sample        = 12,
+               .packing                = SOC_MBUS_PACKING_EXTEND16,
+               .order                  = SOC_MBUS_ORDER_LE,
+       },
+}, {
+       .code = V4L2_MBUS_FMT_SRGGB12_1X12,
+       .fmt = {
+               .fourcc                 = V4L2_PIX_FMT_SRGGB12,
+               .name                   = "Bayer 12 RGGB",
+               .bits_per_sample        = 12,
+               .packing                = SOC_MBUS_PACKING_EXTEND16,
+               .order                  = SOC_MBUS_ORDER_LE,
+       },
+},
 };
 
-int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf)
+int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf,
+                       unsigned int *numerator, unsigned int *denominator)
 {
        switch (mf->packing) {
        case SOC_MBUS_PACKING_NONE:
        case SOC_MBUS_PACKING_EXTEND16:
-               return 1;
+               *numerator = 1;
+               *denominator = 1;
+               return 0;
        case SOC_MBUS_PACKING_2X8_PADHI:
        case SOC_MBUS_PACKING_2X8_PADLO:
-               return 2;
+               *numerator = 2;
+               *denominator = 1;
+               return 0;
+       case SOC_MBUS_PACKING_1_5X8:
+               *numerator = 3;
+               *denominator = 2;
+               return 0;
+       case SOC_MBUS_PACKING_VARIABLE:
+               *numerator = 0;
+               *denominator = 1;
+               return 0;
        }
        return -EINVAL;
 }
@@ -155,18 +352,34 @@ s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
        case SOC_MBUS_PACKING_2X8_PADLO:
        case SOC_MBUS_PACKING_EXTEND16:
                return width * 2;
+       case SOC_MBUS_PACKING_1_5X8:
+               return width * 3 / 2;
+       case SOC_MBUS_PACKING_VARIABLE:
+               return 0;
        }
        return -EINVAL;
 }
 EXPORT_SYMBOL(soc_mbus_bytes_per_line);
 
+const struct soc_mbus_pixelfmt *soc_mbus_find_fmtdesc(
+       enum v4l2_mbus_pixelcode code,
+       const struct soc_mbus_lookup *lookup,
+       int n)
+{
+       int i;
+
+       for (i = 0; i < n; i++)
+               if (lookup[i].code == code)
+                       return &lookup[i].fmt;
+
+       return NULL;
+}
+EXPORT_SYMBOL(soc_mbus_find_fmtdesc);
+
 const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc(
        enum v4l2_mbus_pixelcode code)
 {
-       if (code - V4L2_MBUS_FMT_FIXED > ARRAY_SIZE(mbus_fmt) ||
-           code <= V4L2_MBUS_FMT_FIXED)
-               return NULL;
-       return mbus_fmt + code - V4L2_MBUS_FMT_FIXED - 1;
+       return soc_mbus_find_fmtdesc(code, mbus_fmt, ARRAY_SIZE(mbus_fmt));
 }
 EXPORT_SYMBOL(soc_mbus_get_fmtdesc);
 
index 07fabdd..6103d1b 100644 (file)
@@ -267,21 +267,27 @@ hauppauge_tuner[] =
        { TUNER_ABSENT,                 "Xceive XC4000"},
        { TUNER_ABSENT,                 "Dibcom 7070"},
        { TUNER_PHILIPS_TDA8290,        "NXP 18271C2"},
-       { TUNER_ABSENT,                 "unknown"},
-       { TUNER_ABSENT,                 "unknown"},
-       { TUNER_ABSENT,                 "unknown"},
-       { TUNER_ABSENT,                 "unknown"},
+       { TUNER_ABSENT,                 "Siano SMS1010"},
+       { TUNER_ABSENT,                 "Siano SMS1150"},
+       { TUNER_ABSENT,                 "MaxLinear 5007"},
+       { TUNER_ABSENT,                 "TCL M09WPP_2P_E"},
        /* 160-169 */
-       { TUNER_ABSENT,                 "unknown"},
-       { TUNER_ABSENT,                 "unknown"},
-       { TUNER_ABSENT,                 "unknown"},
-       { TUNER_ABSENT,                 "unknown"},
-       { TUNER_ABSENT,                 "unknown"},
-       { TUNER_ABSENT,                 "unknown"},
-       { TUNER_ABSENT,                 "unknown"},
-       { TUNER_ABSENT,                 "unknown"},
+       { TUNER_ABSENT,                 "Siano SMS1180"},
+       { TUNER_ABSENT,                 "Maxim_MAX2165"},
+       { TUNER_ABSENT,                 "Siano SMS1140"},
+       { TUNER_ABSENT,                 "Siano SMS1150 B1"},
+       { TUNER_ABSENT,                 "MaxLinear 111"},
+       { TUNER_ABSENT,                 "Dibcom 7770"},
+       { TUNER_ABSENT,                 "Siano SMS1180VNS"},
+       { TUNER_ABSENT,                 "Siano SMS1184"},
        { TUNER_PHILIPS_FQ1236_MK5,     "TCL M30WTP-4N-E"},
-       { TUNER_ABSENT,                 "unknown"},
+       { TUNER_ABSENT,                 "TCL_M11WPP_2PN_E"},
+       /* 170-179 */
+       { TUNER_ABSENT,                 "MaxLinear 301"},
+       { TUNER_ABSENT,                 "Mirics MSi001"},
+       { TUNER_ABSENT,                 "MaxLinear MxL241SF"},
+       { TUNER_ABSENT,                 "Xceive XC5000C"},
+       { TUNER_ABSENT,                 "Montage M68TS2020"},
 };
 
 /* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are
index 68b998b..8f52661 100644 (file)
@@ -1025,6 +1025,34 @@ struct usbvision_device_data_st  usbvision_device_data[] = {
                .y_offset       = -1,
                .model_string   = "Hauppauge WinTv-USB",
        },
+       [MICROCAM_NTSC] = {
+               .interface      = -1,
+               .codec          = CODEC_WEBCAM,
+               .video_channels = 1,
+               .video_norm     = V4L2_STD_NTSC,
+               .audio_channels = 0,
+               .radio          = 0,
+               .vbi            = 0,
+               .tuner          = 0,
+               .tuner_type     = 0,
+               .x_offset       = 71,
+               .y_offset       = 15,
+               .model_string   = "Nogatech USB MicroCam NTSC (NV3000N)",
+       },
+       [MICROCAM_PAL] = {
+               .interface      = -1,
+               .codec          = CODEC_WEBCAM,
+               .video_channels = 1,
+               .video_norm     = V4L2_STD_PAL,
+               .audio_channels = 0,
+               .radio          = 0,
+               .vbi            = 0,
+               .tuner          = 0,
+               .tuner_type     = 0,
+               .x_offset       = 71,
+               .y_offset       = 18,
+               .model_string   = "Nogatech USB MicroCam PAL (NV3001P)",
+       },
 };
 const int usbvision_device_data_size = ARRAY_SIZE(usbvision_device_data);
 
@@ -1042,6 +1070,8 @@ struct usb_device_id usbvision_table[] = {
        { USB_DEVICE(0x0573, 0x2d00), .driver_info = HPG_WINTV_LIVE_PAL_BG },
        { USB_DEVICE(0x0573, 0x2d01), .driver_info = HPG_WINTV_LIVE_PRO_NTSC_MN },
        { USB_DEVICE(0x0573, 0x2101), .driver_info = ZORAN_PMD_NOGATECH },
+       { USB_DEVICE(0x0573, 0x3000), .driver_info = MICROCAM_NTSC },
+       { USB_DEVICE(0x0573, 0x3001), .driver_info = MICROCAM_PAL },
        { USB_DEVICE(0x0573, 0x4100), .driver_info = NOGATECH_USB_TV_NTSC_FM },
        { USB_DEVICE(0x0573, 0x4110), .driver_info = PNY_USB_TV_NTSC_FM },
        { USB_DEVICE(0x0573, 0x4450), .driver_info = PV_PLAYTV_USB_PRO_PAL_FM },
@@ -1088,8 +1118,7 @@ struct usb_device_id usbvision_table[] = {
        { USB_DEVICE(0x2304, 0x0110), .driver_info = PINNA_PCTV_USB_PAL_FM },
        { USB_DEVICE(0x2304, 0x0111), .driver_info = MIRO_PCTV_USB },
        { USB_DEVICE(0x2304, 0x0112), .driver_info = PINNA_PCTV_USB_NTSC_FM },
-       { USB_DEVICE(0x2304, 0x0113),
-         .driver_info = PINNA_PCTV_USB_NTSC_FM_V3 },
+       { USB_DEVICE(0x2304, 0x0113), .driver_info = PINNA_PCTV_USB_NTSC_FM_V3 },
        { USB_DEVICE(0x2304, 0x0210), .driver_info = PINNA_PCTV_USB_PAL_FM_V2 },
        { USB_DEVICE(0x2304, 0x0212), .driver_info = PINNA_PCTV_USB_NTSC_FM_V2 },
        { USB_DEVICE(0x2304, 0x0214), .driver_info = PINNA_PCTV_USB_PAL_FM_V3 },
index 9c6ad22..a51cc11 100644 (file)
@@ -63,5 +63,7 @@
 #define PINNA_PCTV_BUNGEE_PAL_FM                 62
 #define HPG_WINTV                                63
 #define PINNA_PCTV_USB_NTSC_FM_V3                64
+#define MICROCAM_NTSC                            65
+#define MICROCAM_PAL                             66
 
 extern const int usbvision_device_data_size;
index c8feb0d..f344411 100644 (file)
@@ -49,10 +49,6 @@ static unsigned int core_debug;
 module_param(core_debug, int, 0644);
 MODULE_PARM_DESC(core_debug, "enable debug messages [core]");
 
-static unsigned int force_testpattern;
-module_param(force_testpattern, int, 0644);
-MODULE_PARM_DESC(force_testpattern, "enable test pattern display [core]");
-
 static int adjust_compression = 1;     /* Set the compression to be adaptive */
 module_param(adjust_compression, int, 0444);
 MODULE_PARM_DESC(adjust_compression, " Set the ADPCM compression for the device.  Default: 1 (On)");
@@ -387,90 +383,6 @@ void usbvision_scratch_free(struct usb_usbvision *usbvision)
        usbvision->scratch = NULL;
 }
 
-/*
- * usbvision_testpattern()
- *
- * Procedure forms a test pattern (yellow grid on blue background).
- *
- * Parameters:
- * fullframe:   if TRUE then entire frame is filled, otherwise the procedure
- *             continues from the current scanline.
- * pmode       0: fill the frame with solid blue color (like on VCR or TV)
- *             1: Draw a colored grid
- *
- */
-static void usbvision_testpattern(struct usb_usbvision *usbvision,
-                                 int fullframe, int pmode)
-{
-       static const char proc[] = "usbvision_testpattern";
-       struct usbvision_frame *frame;
-       unsigned char *f;
-       int num_cell = 0;
-       int scan_length = 0;
-       static int num_pass;
-
-       if (usbvision == NULL) {
-               printk(KERN_ERR "%s: usbvision == NULL\n", proc);
-               return;
-       }
-       if (usbvision->cur_frame == NULL) {
-               printk(KERN_ERR "%s: usbvision->cur_frame is NULL.\n", proc);
-               return;
-       }
-
-       /* Grab the current frame */
-       frame = usbvision->cur_frame;
-
-       /* Optionally start at the beginning */
-       if (fullframe) {
-               frame->curline = 0;
-               frame->scanlength = 0;
-       }
-
-       /* Form every scan line */
-       for (; frame->curline < frame->frmheight; frame->curline++) {
-               int i;
-
-               f = frame->data + (usbvision->curwidth * 3 * frame->curline);
-               for (i = 0; i < usbvision->curwidth; i++) {
-                       unsigned char cb = 0x80;
-                       unsigned char cg = 0;
-                       unsigned char cr = 0;
-
-                       if (pmode == 1) {
-                               if (frame->curline % 32 == 0)
-                                       cb = 0, cg = cr = 0xFF;
-                               else if (i % 32 == 0) {
-                                       if (frame->curline % 32 == 1)
-                                               num_cell++;
-                                       cb = 0, cg = cr = 0xFF;
-                               } else {
-                                       cb =
-                                           ((num_cell * 7) +
-                                            num_pass) & 0xFF;
-                                       cg =
-                                           ((num_cell * 5) +
-                                            num_pass * 2) & 0xFF;
-                                       cr =
-                                           ((num_cell * 3) +
-                                            num_pass * 3) & 0xFF;
-                               }
-                       } else {
-                               /* Just the blue screen */
-                       }
-
-                       *f++ = cb;
-                       *f++ = cg;
-                       *f++ = cr;
-                       scan_length += 3;
-               }
-       }
-
-       frame->grabstate = frame_state_done;
-       frame->scanlength += scan_length;
-       ++num_pass;
-}
-
 /*
  * usbvision_decompress_alloc()
  *
@@ -571,10 +483,6 @@ static enum parse_state usbvision_find_header(struct usb_usbvision *usbvision)
        frame->scanstate = scan_state_lines;
        frame->curline = 0;
 
-       if (force_testpattern) {
-               usbvision_testpattern(usbvision, 1, 1);
-               return parse_state_next_frame;
-       }
        return parse_state_continue;
 }
 
@@ -1679,6 +1587,55 @@ int usbvision_power_off(struct usb_usbvision *usbvision)
        return err_code;
 }
 
+/* configure webcam image sensor using the serial port */
+static int usbvision_init_webcam(struct usb_usbvision *usbvision)
+{
+       int rc;
+       int i;
+       static char init_values[38][3] = {
+               { 0x04, 0x12, 0x08 }, { 0x05, 0xff, 0xc8 }, { 0x06, 0x18, 0x07 }, { 0x07, 0x90, 0x00 },
+               { 0x09, 0x00, 0x00 }, { 0x0a, 0x00, 0x00 }, { 0x0b, 0x08, 0x00 }, { 0x0d, 0xcc, 0xcc },
+               { 0x0e, 0x13, 0x14 }, { 0x10, 0x9b, 0x83 }, { 0x11, 0x5a, 0x3f }, { 0x12, 0xe4, 0x73 },
+               { 0x13, 0x88, 0x84 }, { 0x14, 0x89, 0x80 }, { 0x15, 0x00, 0x20 }, { 0x16, 0x00, 0x00 },
+               { 0x17, 0xff, 0xa0 }, { 0x18, 0x6b, 0x20 }, { 0x19, 0x22, 0x40 }, { 0x1a, 0x10, 0x07 },
+               { 0x1b, 0x00, 0x47 }, { 0x1c, 0x03, 0xe0 }, { 0x1d, 0x00, 0x00 }, { 0x1e, 0x00, 0x00 },
+               { 0x1f, 0x00, 0x00 }, { 0x20, 0x00, 0x00 }, { 0x21, 0x00, 0x00 }, { 0x22, 0x00, 0x00 },
+               { 0x23, 0x00, 0x00 }, { 0x24, 0x00, 0x00 }, { 0x25, 0x00, 0x00 }, { 0x26, 0x00, 0x00 },
+               { 0x27, 0x00, 0x00 }, { 0x28, 0x00, 0x00 }, { 0x29, 0x00, 0x00 }, { 0x08, 0x80, 0x60 },
+               { 0x0f, 0x2d, 0x24 }, { 0x0c, 0x80, 0x80 }
+       };
+       char value[3];
+
+       /* the only difference between PAL and NTSC init_values */
+       if (usbvision_device_data[usbvision->dev_model].video_norm == V4L2_STD_NTSC)
+               init_values[4][1] = 0x34;
+
+       for (i = 0; i < sizeof(init_values) / 3; i++) {
+               usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT);
+               memcpy(value, init_values[i], 3);
+               rc = usb_control_msg(usbvision->dev,
+                                    usb_sndctrlpipe(usbvision->dev, 1),
+                                    USBVISION_OP_CODE,
+                                    USB_DIR_OUT | USB_TYPE_VENDOR |
+                                    USB_RECIP_ENDPOINT, 0,
+                                    (__u16) USBVISION_SER_DAT1, value,
+                                    3, HZ);
+               if (rc < 0)
+                       return rc;
+               usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SIO);
+               /* write 3 bytes to the serial port using SIO mode */
+               usbvision_write_reg(usbvision, USBVISION_SER_CONT, 3 | 0x10);
+               usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, 0);
+               usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT);
+               usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, USBVISION_IO_2);
+               usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT | USBVISION_CLK_OUT);
+               usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT | USBVISION_DAT_IO);
+               usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT | USBVISION_CLK_OUT | USBVISION_DAT_IO);
+       }
+
+       return 0;
+}
+
 /*
  * usbvision_set_video_format()
  *
@@ -1797,6 +1754,13 @@ int usbvision_set_output(struct usb_usbvision *usbvision, int width,
 
        frame_drop = FRAMERATE_MAX;     /* We can allow the maximum here, because dropping is controlled */
 
+       if (usbvision_device_data[usbvision->dev_model].codec == CODEC_WEBCAM) {
+               if (usbvision_device_data[usbvision->dev_model].video_norm == V4L2_STD_PAL)
+                       frame_drop = 25;
+               else
+                       frame_drop = 30;
+       }
+
        /* frame_drop = 7; => frame_phase = 1, 5, 9, 13, 17, 21, 25, 0, 4, 8, ...
                => frame_skip = 4;
                => frame_rate = (7 + 1) * 25 / 32 = 200 / 32 = 6.25;
@@ -2046,6 +2010,12 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
                value[7] = 0x00;        /* 0x0010 -> 16 Input video v offset */
        }
 
+       /* webcam is only 480 pixels wide, both PAL and NTSC version */
+       if (usbvision_device_data[usbvision->dev_model].codec == CODEC_WEBCAM) {
+               value[0] = 0xe0;
+               value[1] = 0x01;        /* 0x01E0 -> 480 Input video line length */
+       }
+
        if (usbvision_device_data[usbvision->dev_model].x_offset >= 0) {
                value[4] = usbvision_device_data[usbvision->dev_model].x_offset & 0xff;
                value[5] = (usbvision_device_data[usbvision->dev_model].x_offset & 0x0300) >> 8;
@@ -2148,7 +2118,7 @@ static int usbvision_set_dram_settings(struct usb_usbvision *usbvision)
                             (__u16) USBVISION_DRM_PRM1, value, 8, HZ);
 
        if (rc < 0) {
-               dev_err(&usbvision->dev->dev, "%sERROR=%d\n", __func__, rc);
+               dev_err(&usbvision->dev->dev, "%sERROR=%d\n", __func__, rc);
                return rc;
        }
 
@@ -2180,8 +2150,15 @@ int usbvision_power_on(struct usb_usbvision *usbvision)
        usbvision_write_reg(usbvision, USBVISION_PWR_REG,
                        USBVISION_SSPND_EN | USBVISION_RES2);
 
+       if (usbvision_device_data[usbvision->dev_model].codec == CODEC_WEBCAM) {
+               usbvision_write_reg(usbvision, USBVISION_VIN_REG1,
+                               USBVISION_16_422_SYNC | USBVISION_HVALID_PO);
+               usbvision_write_reg(usbvision, USBVISION_VIN_REG2,
+                               USBVISION_NOHVALID | USBVISION_KEEP_BLANK);
+       }
        usbvision_write_reg(usbvision, USBVISION_PWR_REG,
                        USBVISION_SSPND_EN | USBVISION_PWR_VID);
+       mdelay(10);
        err_code = usbvision_write_reg(usbvision, USBVISION_PWR_REG,
                        USBVISION_SSPND_EN | USBVISION_PWR_VID | USBVISION_RES2);
        if (err_code == 1)
@@ -2310,6 +2287,8 @@ int usbvision_set_audio(struct usb_usbvision *usbvision, int audio_channel)
 
 int usbvision_setup(struct usb_usbvision *usbvision, int format)
 {
+       if (usbvision_device_data[usbvision->dev_model].codec == CODEC_WEBCAM)
+               usbvision_init_webcam(usbvision);
        usbvision_set_video_format(usbvision, format);
        usbvision_set_dram_settings(usbvision);
        usbvision_set_compress_params(usbvision);
index 05b1344..d7f9751 100644 (file)
@@ -222,7 +222,7 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision)
        i2c_set_adapdata(&usbvision->i2c_adap, &usbvision->v4l2_dev);
 
        if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) {
-               printk(KERN_ERR "usbvision_register: can't write reg\n");
+               printk(KERN_ERR "usbvision_i2c_register: can't write reg\n");
                return -EBUSY;
        }
 
index 9855fbe..ea8ea8a 100644 (file)
@@ -1471,7 +1471,8 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision)
 
        /* This should be here to make i2c clients to be able to register */
        /* first switch off audio */
-       usbvision_audio_off(usbvision);
+       if (usbvision_device_data[model].audio_channels > 0)
+               usbvision_audio_off(usbvision);
        if (!power_on_at_open) {
                /* and then power up the noisy tuner */
                usbvision_power_on(usbvision);
index 8074787..43cf61f 100644 (file)
        #define USBVISION_AUDIO_RADIO           2
        #define USBVISION_AUDIO_MUTE            3
 #define USBVISION_SER_MODE             0x07
+       #define USBVISION_CLK_OUT               (1 << 0)
+       #define USBVISION_DAT_IO                (1 << 1)
+       #define USBVISION_SENS_OUT              (1 << 2)
+       #define USBVISION_SER_MODE_SOFT         (0 << 4)
+       #define USBVISION_SER_MODE_SIO          (1 << 4)
 #define USBVISION_SER_ADRS             0x08
 #define USBVISION_SER_CONT             0x09
 #define USBVISION_SER_DAT1             0x0A
@@ -328,6 +333,7 @@ struct usbvision_frame {
 
 #define CODEC_SAA7113  7113
 #define CODEC_SAA7111  7111
+#define CODEC_WEBCAM   3000
 #define BRIDGE_NT1003  1003
 #define BRIDGE_NT1004  1004
 #define BRIDGE_NT1005   1005
index 59f8a9a..a4db26f 100644 (file)
@@ -42,281 +42,313 @@ static struct uvc_control_info uvc_ctrls[] = {
                .selector       = UVC_PU_BRIGHTNESS_CONTROL,
                .index          = 0,
                .size           = 2,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-                               | UVC_CONTROL_RESTORE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR
+                               | UVC_CTRL_FLAG_GET_RANGE
+                               | UVC_CTRL_FLAG_RESTORE,
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
                .selector       = UVC_PU_CONTRAST_CONTROL,
                .index          = 1,
                .size           = 2,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-                               | UVC_CONTROL_RESTORE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR
+                               | UVC_CTRL_FLAG_GET_RANGE
+                               | UVC_CTRL_FLAG_RESTORE,
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
                .selector       = UVC_PU_HUE_CONTROL,
                .index          = 2,
                .size           = 2,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-                               | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR
+                               | UVC_CTRL_FLAG_GET_RANGE
+                               | UVC_CTRL_FLAG_RESTORE
+                               | UVC_CTRL_FLAG_AUTO_UPDATE,
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
                .selector       = UVC_PU_SATURATION_CONTROL,
                .index          = 3,
                .size           = 2,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-                               | UVC_CONTROL_RESTORE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR
+                               | UVC_CTRL_FLAG_GET_RANGE
+                               | UVC_CTRL_FLAG_RESTORE,
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
                .selector       = UVC_PU_SHARPNESS_CONTROL,
                .index          = 4,
                .size           = 2,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-                               | UVC_CONTROL_RESTORE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR
+                               | UVC_CTRL_FLAG_GET_RANGE
+                               | UVC_CTRL_FLAG_RESTORE,
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
                .selector       = UVC_PU_GAMMA_CONTROL,
                .index          = 5,
                .size           = 2,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-                               | UVC_CONTROL_RESTORE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR
+                               | UVC_CTRL_FLAG_GET_RANGE
+                               | UVC_CTRL_FLAG_RESTORE,
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
                .selector       = UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
                .index          = 6,
                .size           = 2,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-                               | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR
+                               | UVC_CTRL_FLAG_GET_RANGE
+                               | UVC_CTRL_FLAG_RESTORE
+                               | UVC_CTRL_FLAG_AUTO_UPDATE,
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
                .selector       = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL,
                .index          = 7,
                .size           = 4,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-                               | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR
+                               | UVC_CTRL_FLAG_GET_RANGE
+                               | UVC_CTRL_FLAG_RESTORE
+                               | UVC_CTRL_FLAG_AUTO_UPDATE,
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
                .selector       = UVC_PU_BACKLIGHT_COMPENSATION_CONTROL,
                .index          = 8,
                .size           = 2,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-                               | UVC_CONTROL_RESTORE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR
+                               | UVC_CTRL_FLAG_GET_RANGE
+                               | UVC_CTRL_FLAG_RESTORE,
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
                .selector       = UVC_PU_GAIN_CONTROL,
                .index          = 9,
                .size           = 2,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-                               | UVC_CONTROL_RESTORE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR
+                               | UVC_CTRL_FLAG_GET_RANGE
+                               | UVC_CTRL_FLAG_RESTORE,
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
                .selector       = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
                .index          = 10,
                .size           = 1,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
-                               | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+                               | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE,
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
                .selector       = UVC_PU_HUE_AUTO_CONTROL,
                .index          = 11,
                .size           = 1,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
-                               | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+                               | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE,
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
                .selector       = UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
                .index          = 12,
                .size           = 1,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
-                               | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+                               | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE,
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
                .selector       = UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
                .index          = 13,
                .size           = 1,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
-                               | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+                               | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE,
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
                .selector       = UVC_PU_DIGITAL_MULTIPLIER_CONTROL,
                .index          = 14,
                .size           = 2,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-                               | UVC_CONTROL_RESTORE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR
+                               | UVC_CTRL_FLAG_GET_RANGE
+                               | UVC_CTRL_FLAG_RESTORE,
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
                .selector       = UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL,
                .index          = 15,
                .size           = 2,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-                               | UVC_CONTROL_RESTORE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR
+                               | UVC_CTRL_FLAG_GET_RANGE
+                               | UVC_CTRL_FLAG_RESTORE,
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
                .selector       = UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL,
                .index          = 16,
                .size           = 1,
-               .flags          = UVC_CONTROL_GET_CUR,
+               .flags          = UVC_CTRL_FLAG_GET_CUR,
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
                .selector       = UVC_PU_ANALOG_LOCK_STATUS_CONTROL,
                .index          = 17,
                .size           = 1,
-               .flags          = UVC_CONTROL_GET_CUR,
+               .flags          = UVC_CTRL_FLAG_GET_CUR,
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
                .selector       = UVC_CT_SCANNING_MODE_CONTROL,
                .index          = 0,
                .size           = 1,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
-                               | UVC_CONTROL_RESTORE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+                               | UVC_CTRL_FLAG_RESTORE,
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
                .selector       = UVC_CT_AE_MODE_CONTROL,
                .index          = 1,
                .size           = 1,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
-                               | UVC_CONTROL_GET_DEF | UVC_CONTROL_GET_RES
-                               | UVC_CONTROL_RESTORE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+                               | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_GET_RES
+                               | UVC_CTRL_FLAG_RESTORE,
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
                .selector       = UVC_CT_AE_PRIORITY_CONTROL,
                .index          = 2,
                .size           = 1,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
-                               | UVC_CONTROL_RESTORE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+                               | UVC_CTRL_FLAG_RESTORE,
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
                .selector       = UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
                .index          = 3,
                .size           = 4,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-                               | UVC_CONTROL_RESTORE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR
+                               | UVC_CTRL_FLAG_GET_RANGE
+                               | UVC_CTRL_FLAG_RESTORE,
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
                .selector       = UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL,
                .index          = 4,
                .size           = 1,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_RESTORE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_RESTORE,
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
                .selector       = UVC_CT_FOCUS_ABSOLUTE_CONTROL,
                .index          = 5,
                .size           = 2,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-                               | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR
+                               | UVC_CTRL_FLAG_GET_RANGE
+                               | UVC_CTRL_FLAG_RESTORE
+                               | UVC_CTRL_FLAG_AUTO_UPDATE,
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
                .selector       = UVC_CT_FOCUS_RELATIVE_CONTROL,
                .index          = 6,
                .size           = 2,
-               .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,
+               .flags          = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN
+                               | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES
+                               | UVC_CTRL_FLAG_GET_DEF
+                               | UVC_CTRL_FLAG_AUTO_UPDATE,
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
                .selector       = UVC_CT_IRIS_ABSOLUTE_CONTROL,
                .index          = 7,
                .size           = 2,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-                               | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR
+                               | UVC_CTRL_FLAG_GET_RANGE
+                               | UVC_CTRL_FLAG_RESTORE
+                               | UVC_CTRL_FLAG_AUTO_UPDATE,
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
                .selector       = UVC_CT_IRIS_RELATIVE_CONTROL,
                .index          = 8,
                .size           = 1,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_AUTO_UPDATE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR
+                               | UVC_CTRL_FLAG_AUTO_UPDATE,
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
                .selector       = UVC_CT_ZOOM_ABSOLUTE_CONTROL,
                .index          = 9,
                .size           = 2,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-                               | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR
+                               | UVC_CTRL_FLAG_GET_RANGE
+                               | UVC_CTRL_FLAG_RESTORE
+                               | UVC_CTRL_FLAG_AUTO_UPDATE,
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
                .selector       = UVC_CT_ZOOM_RELATIVE_CONTROL,
                .index          = 10,
                .size           = 3,
-               .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,
+               .flags          = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN
+                               | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES
+                               | UVC_CTRL_FLAG_GET_DEF
+                               | UVC_CTRL_FLAG_AUTO_UPDATE,
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
                .selector       = UVC_CT_PANTILT_ABSOLUTE_CONTROL,
                .index          = 11,
                .size           = 8,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-                               | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR
+                               | UVC_CTRL_FLAG_GET_RANGE
+                               | UVC_CTRL_FLAG_RESTORE
+                               | UVC_CTRL_FLAG_AUTO_UPDATE,
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
                .selector       = UVC_CT_PANTILT_RELATIVE_CONTROL,
                .index          = 12,
                .size           = 4,
-               .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,
+               .flags          = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN
+                               | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES
+                               | UVC_CTRL_FLAG_GET_DEF
+                               | UVC_CTRL_FLAG_AUTO_UPDATE,
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
                .selector       = UVC_CT_ROLL_ABSOLUTE_CONTROL,
                .index          = 13,
                .size           = 2,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-                               | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR
+                               | UVC_CTRL_FLAG_GET_RANGE
+                               | UVC_CTRL_FLAG_RESTORE
+                               | UVC_CTRL_FLAG_AUTO_UPDATE,
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
                .selector       = UVC_CT_ROLL_RELATIVE_CONTROL,
                .index          = 14,
                .size           = 2,
-               .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,
+               .flags          = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN
+                               | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES
+                               | UVC_CTRL_FLAG_GET_DEF
+                               | UVC_CTRL_FLAG_AUTO_UPDATE,
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
                .selector       = UVC_CT_FOCUS_AUTO_CONTROL,
                .index          = 17,
                .size           = 1,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
-                               | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+                               | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE,
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
                .selector       = UVC_CT_PRIVACY_CONTROL,
                .index          = 18,
                .size           = 1,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
-                               | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+               .flags          = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+                               | UVC_CTRL_FLAG_RESTORE
+                               | UVC_CTRL_FLAG_AUTO_UPDATE,
        },
 };
 
@@ -816,7 +848,7 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
 {
        int ret;
 
-       if (ctrl->info.flags & UVC_CONTROL_GET_DEF) {
+       if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {
                ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
                                     chain->dev->intfnum, ctrl->info.selector,
                                     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF),
@@ -825,7 +857,7 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
                        return ret;
        }
 
-       if (ctrl->info.flags & UVC_CONTROL_GET_MIN) {
+       if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN) {
                ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
                                     chain->dev->intfnum, ctrl->info.selector,
                                     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN),
@@ -833,7 +865,7 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
                if (ret < 0)
                        return ret;
        }
-       if (ctrl->info.flags & UVC_CONTROL_GET_MAX) {
+       if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) {
                ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
                                     chain->dev->intfnum, ctrl->info.selector,
                                     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX),
@@ -841,7 +873,7 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
                if (ret < 0)
                        return ret;
        }
-       if (ctrl->info.flags & UVC_CONTROL_GET_RES) {
+       if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) {
                ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
                                     chain->dev->intfnum, ctrl->info.selector,
                                     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
@@ -879,9 +911,9 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
        strlcpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name);
        v4l2_ctrl->flags = 0;
 
-       if (!(ctrl->info.flags & UVC_CONTROL_GET_CUR))
+       if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
                v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
-       if (!(ctrl->info.flags & UVC_CONTROL_SET_CUR))
+       if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
                v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 
        if (!ctrl->cached) {
@@ -890,7 +922,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
                        goto done;
        }
 
-       if (ctrl->info.flags & UVC_CONTROL_GET_DEF) {
+       if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {
                v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF,
                                uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
        }
@@ -927,15 +959,15 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
                break;
        }
 
-       if (ctrl->info.flags & UVC_CONTROL_GET_MIN)
+       if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN)
                v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN,
                                     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
 
-       if (ctrl->info.flags & UVC_CONTROL_GET_MAX)
+       if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX)
                v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX,
                                     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
 
-       if (ctrl->info.flags & UVC_CONTROL_GET_RES)
+       if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)
                v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES,
                                  uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
 
@@ -983,6 +1015,24 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
        }
 
        menu_info = &mapping->menu_info[query_menu->index];
+
+       if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) {
+               s32 bitmap;
+
+               if (!ctrl->cached) {
+                       ret = uvc_ctrl_populate_cache(chain, ctrl);
+                       if (ret < 0)
+                               goto done;
+               }
+
+               bitmap = mapping->get(mapping, UVC_GET_RES,
+                                     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+               if (!(bitmap & menu_info->value)) {
+                       ret = -EINVAL;
+                       goto done;
+               }
+       }
+
        strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name);
 
 done:
@@ -1039,7 +1089,7 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
                 * marked as loaded in uvc_ctrl_get/uvc_ctrl_set to prevent
                 * uvc_ctrl_get from using the cached value.
                 */
-               if (ctrl->info.flags & UVC_CONTROL_AUTO_UPDATE)
+               if (ctrl->info.flags & UVC_CTRL_FLAG_AUTO_UPDATE)
                        ctrl->loaded = 0;
 
                if (!ctrl->dirty)
@@ -1094,7 +1144,7 @@ int uvc_ctrl_get(struct uvc_video_chain *chain,
        int ret;
 
        ctrl = uvc_find_control(chain, xctrl->id, &mapping);
-       if (ctrl == NULL || (ctrl->info.flags & UVC_CONTROL_GET_CUR) == 0)
+       if (ctrl == NULL || (ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0)
                return -EINVAL;
 
        if (!ctrl->loaded) {
@@ -1136,7 +1186,7 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
        int ret;
 
        ctrl = uvc_find_control(chain, xctrl->id, &mapping);
-       if (ctrl == NULL || (ctrl->info.flags & UVC_CONTROL_SET_CUR) == 0)
+       if (ctrl == NULL || (ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR) == 0)
                return -EINVAL;
 
        /* Clamp out of range values. */
@@ -1171,6 +1221,23 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
                if (xctrl->value < 0 || xctrl->value >= mapping->menu_count)
                        return -ERANGE;
                value = mapping->menu_info[xctrl->value].value;
+
+               /* Valid menu indices are reported by the GET_RES request for
+                * UVC controls that support it.
+                */
+               if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) {
+                       if (!ctrl->cached) {
+                               ret = uvc_ctrl_populate_cache(chain, ctrl);
+                               if (ret < 0)
+                                       return ret;
+                       }
+
+                       step = mapping->get(mapping, UVC_GET_RES,
+                                       uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+                       if (!(step & value))
+                               return -ERANGE;
+               }
+
                break;
 
        default:
@@ -1183,7 +1250,7 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
         * operation.
         */
        if (!ctrl->loaded && (ctrl->info.size * 8) != mapping->size) {
-               if ((ctrl->info.flags & UVC_CONTROL_GET_CUR) == 0) {
+               if ((ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0) {
                        memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
                                0, ctrl->info.size);
                } else {
@@ -1230,17 +1297,17 @@ static void uvc_ctrl_fixup_xu_info(struct uvc_device *dev,
 
        static const struct uvc_ctrl_fixup fixups[] = {
                { { USB_DEVICE(0x046d, 0x08c2) }, 9, 1,
-                       UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
-                       UVC_CONTROL_GET_DEF | UVC_CONTROL_SET_CUR |
-                       UVC_CONTROL_AUTO_UPDATE },
+                       UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX |
+                       UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR |
+                       UVC_CTRL_FLAG_AUTO_UPDATE },
                { { USB_DEVICE(0x046d, 0x08cc) }, 9, 1,
-                       UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
-                       UVC_CONTROL_GET_DEF | UVC_CONTROL_SET_CUR |
-                       UVC_CONTROL_AUTO_UPDATE },
+                       UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX |
+                       UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR |
+                       UVC_CTRL_FLAG_AUTO_UPDATE },
                { { USB_DEVICE(0x046d, 0x0994) }, 9, 1,
-                       UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
-                       UVC_CONTROL_GET_DEF | UVC_CONTROL_SET_CUR |
-                       UVC_CONTROL_AUTO_UPDATE },
+                       UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX |
+                       UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR |
+                       UVC_CTRL_FLAG_AUTO_UPDATE },
        };
 
        unsigned int i;
@@ -1297,21 +1364,23 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
                goto done;
        }
 
-       info->flags = UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX
-                   | UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF
-                   | (data[0] & UVC_CONTROL_CAP_GET ? UVC_CONTROL_GET_CUR : 0)
-                   | (data[0] & UVC_CONTROL_CAP_SET ? UVC_CONTROL_SET_CUR : 0)
+       info->flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
+                   | UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF
+                   | (data[0] & UVC_CONTROL_CAP_GET ?
+                      UVC_CTRL_FLAG_GET_CUR : 0)
+                   | (data[0] & UVC_CONTROL_CAP_SET ?
+                      UVC_CTRL_FLAG_SET_CUR : 0)
                    | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
-                      UVC_CONTROL_AUTO_UPDATE : 0);
+                      UVC_CTRL_FLAG_AUTO_UPDATE : 0);
 
        uvc_ctrl_fixup_xu_info(dev, ctrl, info);
 
        uvc_trace(UVC_TRACE_CONTROL, "XU control %pUl/%u queried: len %u, "
                  "flags { get %u set %u auto %u }.\n",
                  info->entity, info->selector, info->size,
-                 (info->flags & UVC_CONTROL_GET_CUR) ? 1 : 0,
-                 (info->flags & UVC_CONTROL_SET_CUR) ? 1 : 0,
-                 (info->flags & UVC_CONTROL_AUTO_UPDATE) ? 1 : 0);
+                 (info->flags & UVC_CTRL_FLAG_GET_CUR) ? 1 : 0,
+                 (info->flags & UVC_CTRL_FLAG_SET_CUR) ? 1 : 0,
+                 (info->flags & UVC_CTRL_FLAG_AUTO_UPDATE) ? 1 : 0);
 
 done:
        kfree(data);
@@ -1344,32 +1413,33 @@ static int uvc_ctrl_init_xu_ctrl(struct uvc_device *dev,
 }
 
 int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
-       struct uvc_xu_control *xctrl, int set)
+       struct uvc_xu_control_query *xqry)
 {
        struct uvc_entity *entity;
-       struct uvc_control *ctrl = NULL;
+       struct uvc_control *ctrl;
        unsigned int i, found = 0;
-       int restore = 0;
-       __u8 *data;
+       __u32 reqflags;
+       __u16 size;
+       __u8 *data = NULL;
        int ret;
 
        /* Find the extension unit. */
        list_for_each_entry(entity, &chain->entities, chain) {
                if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT &&
-                   entity->id == xctrl->unit)
+                   entity->id == xqry->unit)
                        break;
        }
 
-       if (entity->id != xctrl->unit) {
+       if (entity->id != xqry->unit) {
                uvc_trace(UVC_TRACE_CONTROL, "Extension unit %u not found.\n",
-                       xctrl->unit);
-               return -EINVAL;
+                       xqry->unit);
+               return -ENOENT;
        }
 
        /* Find the control and perform delayed initialization if needed. */
        for (i = 0; i < entity->ncontrols; ++i) {
                ctrl = &entity->controls[i];
-               if (ctrl->index == xctrl->selector - 1) {
+               if (ctrl->index == xqry->selector - 1) {
                        found = 1;
                        break;
                }
@@ -1377,8 +1447,8 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
 
        if (!found) {
                uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u not found.\n",
-                       entity->extension.guidExtensionCode, xctrl->selector);
-               return -EINVAL;
+                       entity->extension.guidExtensionCode, xqry->selector);
+               return -ENOENT;
        }
 
        if (mutex_lock_interruptible(&chain->ctrl_mutex))
@@ -1390,43 +1460,72 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
                goto done;
        }
 
-       /* Validate control data size. */
-       if (ctrl->info.size != xctrl->size) {
+       /* Validate the required buffer size and flags for the request */
+       reqflags = 0;
+       size = ctrl->info.size;
+
+       switch (xqry->query) {
+       case UVC_GET_CUR:
+               reqflags = UVC_CTRL_FLAG_GET_CUR;
+               break;
+       case UVC_GET_MIN:
+               reqflags = UVC_CTRL_FLAG_GET_MIN;
+               break;
+       case UVC_GET_MAX:
+               reqflags = UVC_CTRL_FLAG_GET_MAX;
+               break;
+       case UVC_GET_DEF:
+               reqflags = UVC_CTRL_FLAG_GET_DEF;
+               break;
+       case UVC_GET_RES:
+               reqflags = UVC_CTRL_FLAG_GET_RES;
+               break;
+       case UVC_SET_CUR:
+               reqflags = UVC_CTRL_FLAG_SET_CUR;
+               break;
+       case UVC_GET_LEN:
+               size = 2;
+               break;
+       case UVC_GET_INFO:
+               size = 1;
+               break;
+       default:
                ret = -EINVAL;
                goto done;
        }
 
-       if ((set && !(ctrl->info.flags & UVC_CONTROL_SET_CUR)) ||
-           (!set && !(ctrl->info.flags & UVC_CONTROL_GET_CUR))) {
-               ret = -EINVAL;
+       if (size != xqry->size) {
+               ret = -ENOBUFS;
                goto done;
        }
 
-       memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
-              uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
-              ctrl->info.size);
-       data = uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT);
-       restore = set;
+       if (reqflags && !(ctrl->info.flags & reqflags)) {
+               ret = -EBADRQC;
+               goto done;
+       }
 
-       if (set && copy_from_user(data, xctrl->data, xctrl->size)) {
+       data = kmalloc(size, GFP_KERNEL);
+       if (data == NULL) {
+               ret = -ENOMEM;
+               goto done;
+       }
+
+       if (xqry->query == UVC_SET_CUR &&
+           copy_from_user(data, xqry->data, size)) {
                ret = -EFAULT;
                goto done;
        }
 
-       ret = uvc_query_ctrl(chain->dev, set ? UVC_SET_CUR : UVC_GET_CUR,
-                            xctrl->unit, chain->dev->intfnum, xctrl->selector,
-                            data, xctrl->size);
+       ret = uvc_query_ctrl(chain->dev, xqry->query, xqry->unit,
+                            chain->dev->intfnum, xqry->selector, data, size);
        if (ret < 0)
                goto done;
 
-       if (!set && copy_to_user(xctrl->data, data, xctrl->size))
+       if (xqry->query != UVC_SET_CUR &&
+           copy_to_user(xqry->data, data, size))
                ret = -EFAULT;
 done:
-       if (ret && restore)
-               memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
-                      uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
-                      xctrl->size);
-
+       kfree(data);
        mutex_unlock(&chain->ctrl_mutex);
        return ret;
 }
@@ -1458,7 +1557,7 @@ int uvc_ctrl_resume_device(struct uvc_device *dev)
                        ctrl = &entity->controls[i];
 
                        if (!ctrl->initialized || !ctrl->modified ||
-                           (ctrl->info.flags & UVC_CONTROL_RESTORE) == 0)
+                           (ctrl->info.flags & UVC_CTRL_FLAG_RESTORE) == 0)
                                continue;
 
                        printk(KERN_INFO "restoring control %pUl/%u/%u\n",
index 6459b8c..823f4b3 100644 (file)
@@ -83,6 +83,11 @@ static struct uvc_format_desc uvc_fmts[] = {
                .guid           = UVC_GUID_FORMAT_I420,
                .fcc            = V4L2_PIX_FMT_YUV420,
        },
+       {
+               .name           = "YUV 4:2:0 (M420)",
+               .guid           = UVC_GUID_FORMAT_M420,
+               .fcc            = V4L2_PIX_FMT_M420,
+       },
        {
                .name           = "YUV 4:2:2 (UYVY)",
                .guid           = UVC_GUID_FORMAT_UYVY,
@@ -103,6 +108,11 @@ static struct uvc_format_desc uvc_fmts[] = {
                .guid           = UVC_GUID_FORMAT_BY8,
                .fcc            = V4L2_PIX_FMT_SBGGR8,
        },
+       {
+               .name           = "RGB565",
+               .guid           = UVC_GUID_FORMAT_RGBP,
+               .fcc            = V4L2_PIX_FMT_RGB565,
+       },
 };
 
 /* ------------------------------------------------------------------------
@@ -2077,6 +2087,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_STREAM_NO_FID },
+       /* Hercules Classic Silver */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x06f8,
+         .idProduct            = 0x300c,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_FIX_BANDWIDTH },
        /* ViMicro Vega */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2123,6 +2142,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_STREAM_NO_FID },
+       /* JMicron USB2.0 XGA WebCam */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x152d,
+         .idProduct            = 0x0310,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
        /* Syntek (HP Spartan) */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
index f14581b..109a063 100644 (file)
@@ -424,7 +424,7 @@ int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
                        break;
        }
 
-       if (i == queue->count || size != queue->buf_size) {
+       if (i == queue->count || PAGE_ALIGN(size) != queue->buf_size) {
                ret = -EINVAL;
                goto done;
        }
@@ -436,6 +436,7 @@ int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
        vma->vm_flags |= VM_IO;
 
        addr = (unsigned long)queue->mem + buffer->buf.m.offset;
+#ifdef CONFIG_MMU
        while (size > 0) {
                page = vmalloc_to_page((void *)addr);
                if ((ret = vm_insert_page(vma, start, page)) < 0)
@@ -445,6 +446,7 @@ int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
                addr += PAGE_SIZE;
                size -= PAGE_SIZE;
        }
+#endif
 
        vma->vm_ops = &uvc_vm_ops;
        vma->vm_private_data = buffer;
@@ -488,6 +490,36 @@ done:
        return mask;
 }
 
+#ifndef CONFIG_MMU
+/*
+ * Get unmapped area.
+ *
+ * NO-MMU arch need this function to make mmap() work correctly.
+ */
+unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
+               unsigned long pgoff)
+{
+       struct uvc_buffer *buffer;
+       unsigned int i;
+       unsigned long ret;
+
+       mutex_lock(&queue->mutex);
+       for (i = 0; i < queue->count; ++i) {
+               buffer = &queue->buffer[i];
+               if ((buffer->buf.m.offset >> PAGE_SHIFT) == pgoff)
+                       break;
+       }
+       if (i == queue->count) {
+               ret = -EINVAL;
+               goto done;
+       }
+       ret = (unsigned long)queue->mem + buffer->buf.m.offset;
+done:
+       mutex_unlock(&queue->mutex);
+       return ret;
+}
+#endif
+
 /*
  * Enable or disable the video buffers queue.
  *
index 9005a8d..543a803 100644 (file)
@@ -538,6 +538,20 @@ static int uvc_v4l2_release(struct file *file)
        return 0;
 }
 
+static void uvc_v4l2_ioctl_warn(void)
+{
+       static int warned;
+
+       if (warned)
+               return;
+
+       uvc_printk(KERN_INFO, "Deprecated UVCIOC_CTRL_{ADD,MAP_OLD,GET,SET} "
+                  "ioctls will be removed in 2.6.42.\n");
+       uvc_printk(KERN_INFO, "See http://www.ideasonboard.org/uvc/upgrade/ "
+                  "for upgrade instructions.\n");
+       warned = 1;
+}
+
 static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct video_device *vdev = video_devdata(file);
@@ -1018,21 +1032,40 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                uvc_trace(UVC_TRACE_IOCTL, "Unsupported ioctl 0x%08x\n", cmd);
                return -EINVAL;
 
-       /* Dynamic controls. */
-       case UVCIOC_CTRL_ADD:
-               /* Legacy ioctl, kept for API compatibility reasons */
+       /* Dynamic controls. UVCIOC_CTRL_ADD, UVCIOC_CTRL_MAP_OLD,
+        * UVCIOC_CTRL_GET and UVCIOC_CTRL_SET are deprecated and scheduled for
+        * removal in 2.6.42.
+        */
+       case __UVCIOC_CTRL_ADD:
+               uvc_v4l2_ioctl_warn();
                return -EEXIST;
 
-       case UVCIOC_CTRL_MAP_OLD:
+       case __UVCIOC_CTRL_MAP_OLD:
+               uvc_v4l2_ioctl_warn();
+       case __UVCIOC_CTRL_MAP:
        case UVCIOC_CTRL_MAP:
                return uvc_ioctl_ctrl_map(chain, arg,
-                                         cmd == UVCIOC_CTRL_MAP_OLD);
+                                         cmd == __UVCIOC_CTRL_MAP_OLD);
 
-       case UVCIOC_CTRL_GET:
-               return uvc_xu_ctrl_query(chain, arg, 0);
+       case __UVCIOC_CTRL_GET:
+       case __UVCIOC_CTRL_SET:
+       {
+               struct uvc_xu_control *xctrl = arg;
+               struct uvc_xu_control_query xqry = {
+                       .unit           = xctrl->unit,
+                       .selector       = xctrl->selector,
+                       .query          = cmd == __UVCIOC_CTRL_GET
+                                       ? UVC_GET_CUR : UVC_SET_CUR,
+                       .size           = xctrl->size,
+                       .data           = xctrl->data,
+               };
+
+               uvc_v4l2_ioctl_warn();
+               return uvc_xu_ctrl_query(chain, &xqry);
+       }
 
-       case UVCIOC_CTRL_SET:
-               return uvc_xu_ctrl_query(chain, arg, 1);
+       case UVCIOC_CTRL_QUERY:
+               return uvc_xu_ctrl_query(chain, arg);
 
        default:
                uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n", cmd);
@@ -1081,6 +1114,20 @@ static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
        return uvc_queue_poll(&stream->queue, file, wait);
 }
 
+#ifndef CONFIG_MMU
+static unsigned long uvc_v4l2_get_unmapped_area(struct file *file,
+               unsigned long addr, unsigned long len, unsigned long pgoff,
+               unsigned long flags)
+{
+       struct uvc_fh *handle = file->private_data;
+       struct uvc_streaming *stream = handle->stream;
+
+       uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_get_unmapped_area\n");
+
+       return uvc_queue_get_unmapped_area(&stream->queue, pgoff);
+}
+#endif
+
 const struct v4l2_file_operations uvc_fops = {
        .owner          = THIS_MODULE,
        .open           = uvc_v4l2_open,
@@ -1089,5 +1136,8 @@ const struct v4l2_file_operations uvc_fops = {
        .read           = uvc_v4l2_read,
        .mmap           = uvc_v4l2_mmap,
        .poll           = uvc_v4l2_poll,
+#ifndef CONFIG_MMU
+       .get_unmapped_area = uvc_v4l2_get_unmapped_area,
+#endif
 };
 
index 45f01e7..7cf224b 100644 (file)
@@ -4,6 +4,14 @@
 #include <linux/kernel.h>
 #include <linux/videodev2.h>
 
+#ifndef __KERNEL__
+/*
+ * This header provides binary compatibility with applications using the private
+ * uvcvideo API. This API is deprecated and will be removed in 2.6.42.
+ * Applications should be recompiled against the public linux/uvcvideo.h header.
+ */
+#warn "The uvcvideo.h header is deprecated, use linux/uvcvideo.h instead."
+
 /*
  * Dynamic controls
  */
 #define UVC_CONTROL_GET_MAX    (1 << 3)
 #define UVC_CONTROL_GET_RES    (1 << 4)
 #define UVC_CONTROL_GET_DEF    (1 << 5)
-/* Control should be saved at suspend and restored at resume. */
 #define UVC_CONTROL_RESTORE    (1 << 6)
-/* Control can be updated by the camera. */
 #define UVC_CONTROL_AUTO_UPDATE        (1 << 7)
 
 #define UVC_CONTROL_GET_RANGE  (UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \
                                 UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \
                                 UVC_CONTROL_GET_DEF)
 
-struct uvc_xu_control_info {
-       __u8 entity[16];
-       __u8 index;
-       __u8 selector;
-       __u16 size;
-       __u32 flags;
-};
-
 struct uvc_menu_info {
        __u32 value;
        __u8 name[32];
 };
 
-struct uvc_xu_control_mapping_old {
-       __u8 reserved[64];
-};
-
 struct uvc_xu_control_mapping {
        __u32 id;
        __u8 name[32];
@@ -57,7 +51,7 @@ struct uvc_xu_control_mapping {
 
        __u8 size;
        __u8 offset;
-       enum v4l2_ctrl_type v4l2_type;
+       __u32 v4l2_type;
        __u32 data_type;
 
        struct uvc_menu_info __user *menu_info;
@@ -66,6 +60,20 @@ struct uvc_xu_control_mapping {
        __u32 reserved[4];
 };
 
+#endif
+
+struct uvc_xu_control_info {
+       __u8 entity[16];
+       __u8 index;
+       __u8 selector;
+       __u16 size;
+       __u32 flags;
+};
+
+struct uvc_xu_control_mapping_old {
+       __u8 reserved[64];
+};
+
 struct uvc_xu_control {
        __u8 unit;
        __u8 selector;
@@ -73,16 +81,25 @@ struct uvc_xu_control {
        __u8 __user *data;
 };
 
+#ifndef __KERNEL__
 #define UVCIOC_CTRL_ADD                _IOW('U', 1, struct uvc_xu_control_info)
 #define UVCIOC_CTRL_MAP_OLD    _IOWR('U', 2, struct uvc_xu_control_mapping_old)
 #define UVCIOC_CTRL_MAP                _IOWR('U', 2, struct uvc_xu_control_mapping)
 #define UVCIOC_CTRL_GET                _IOWR('U', 3, struct uvc_xu_control)
 #define UVCIOC_CTRL_SET                _IOW('U', 4, struct uvc_xu_control)
+#else
+#define __UVCIOC_CTRL_ADD      _IOW('U', 1, struct uvc_xu_control_info)
+#define __UVCIOC_CTRL_MAP_OLD  _IOWR('U', 2, struct uvc_xu_control_mapping_old)
+#define __UVCIOC_CTRL_MAP      _IOWR('U', 2, struct uvc_xu_control_mapping)
+#define __UVCIOC_CTRL_GET      _IOWR('U', 3, struct uvc_xu_control)
+#define __UVCIOC_CTRL_SET      _IOW('U', 4, struct uvc_xu_control)
+#endif
 
 #ifdef __KERNEL__
 
 #include <linux/poll.h>
 #include <linux/usb/video.h>
+#include <linux/uvcvideo.h>
 
 /* --------------------------------------------------------------------------
  * UVC constants
@@ -152,13 +169,19 @@ struct uvc_xu_control {
 #define UVC_GUID_FORMAT_BY8 \
        { 'B',  'Y',  '8',  ' ', 0x00, 0x00, 0x10, 0x00, \
         0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_RGBP \
+       { 'R',  'G',  'B',  'P', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_M420 \
+       { 'M',  '4',  '2',  '0', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
 
 /* ------------------------------------------------------------------------
  * Driver specific constants.
  */
 
-#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(1, 0, 0)
-#define DRIVER_VERSION         "v1.0.0"
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(1, 1, 0)
+#define DRIVER_VERSION         "v1.1.0"
 
 /* Number of isochronous URBs. */
 #define UVC_URBS               5
@@ -580,6 +603,10 @@ extern int uvc_queue_mmap(struct uvc_video_queue *queue,
                struct vm_area_struct *vma);
 extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
                struct file *file, poll_table *wait);
+#ifndef CONFIG_MMU
+extern unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
+               unsigned long pgoff);
+#endif
 extern int uvc_queue_allocated(struct uvc_video_queue *queue);
 static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
 {
@@ -638,7 +665,7 @@ extern int uvc_ctrl_set(struct uvc_video_chain *chain,
                struct v4l2_ext_control *xctrl);
 
 extern int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
-               struct uvc_xu_control *ctrl, int set);
+               struct uvc_xu_control_query *xqry);
 
 /* Utility functions */
 extern void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator,
@@ -655,4 +682,3 @@ void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream,
 #endif /* __KERNEL__ */
 
 #endif
-
index 6dc7196..19d5ae2 100644 (file)
@@ -352,6 +352,23 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        return ret;
 }
 
+#ifdef CONFIG_MMU
+#define v4l2_get_unmapped_area NULL
+#else
+static unsigned long v4l2_get_unmapped_area(struct file *filp,
+               unsigned long addr, unsigned long len, unsigned long pgoff,
+               unsigned long flags)
+{
+       struct video_device *vdev = video_devdata(filp);
+
+       if (!vdev->fops->get_unmapped_area)
+               return -ENOSYS;
+       if (!video_is_registered(vdev))
+               return -ENODEV;
+       return vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags);
+}
+#endif
+
 static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
 {
        struct video_device *vdev = video_devdata(filp);
@@ -454,6 +471,7 @@ static const struct file_operations v4l2_fops = {
        .read = v4l2_read,
        .write = v4l2_write,
        .open = v4l2_open,
+       .get_unmapped_area = v4l2_get_unmapped_area,
        .mmap = v4l2_mmap,
        .unlocked_ioctl = v4l2_ioctl,
 #ifdef CONFIG_COMPAT
index 8c780c2..85d3048 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "via-camera.h"
 
+MODULE_ALIAS("platform:viafb-camera");
 MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
 MODULE_DESCRIPTION("VIA framebuffer-based camera controller driver");
 MODULE_LICENSE("GPL");
index 9f2bac5..79b04ac 100644 (file)
@@ -64,14 +64,6 @@ static int card[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 };
 module_param_array(card, int, NULL, 0444);
 MODULE_PARM_DESC(card, "Card type");
 
-static int encoder[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 };
-module_param_array(encoder, int, NULL, 0444);
-MODULE_PARM_DESC(encoder, "Video encoder chip");
-
-static int decoder[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 };
-module_param_array(decoder, int, NULL, 0444);
-MODULE_PARM_DESC(decoder, "Video decoder chip");
-
 /*
    The video mem address of the video card.
    The driver has a little database for some videocards
@@ -1230,7 +1222,7 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
        mutex_init(&zr->other_lock);
        if (pci_enable_device(pdev))
                goto zr_unreg;
-       pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision);
+       zr->revision = zr->pci_dev->revision;
 
        dprintk(1,
                KERN_INFO
index 63a438d..7080cde 100644 (file)
@@ -570,6 +570,7 @@ static void incoming_packet(struct sasem_context *context,
        unsigned char *buf = urb->transfer_buffer;
        long ms;
        struct timeval tv;
+       int i;
 
        if (len != 8) {
                printk(KERN_WARNING "%s: invalid incoming packet size (%d)\n",
@@ -577,12 +578,12 @@ static void incoming_packet(struct sasem_context *context,
                return;
        }
 
-#ifdef DEBUG
-       int i;
-       for (i = 0; i < 8; ++i)
-               printk(KERN_INFO "%02x ", buf[i]);
-       printk(KERN_INFO "\n");
-#endif
+       if (debug) {
+               printk(KERN_INFO "Incoming data: ");
+               for (i = 0; i < 8; ++i)
+                       printk(KERN_CONT "%02x ", buf[i]);
+               printk(KERN_CONT "\n");
+       }
 
        /*
         * Lirc could deal with the repeat code, but we really need to block it
diff --git a/drivers/staging/tm6000/CARDLIST b/drivers/staging/tm6000/CARDLIST
new file mode 100644 (file)
index 0000000..b5edce4
--- /dev/null
@@ -0,0 +1,16 @@
+  1 -> Generic tm5600 board                   (tm5600)          [6000:0001]
+  2 -> Generic tm6000 board                   (tm6000)          [6000:0001]
+  3 -> Generic tm6010 board                   (tm6010)          [6000:0002]
+  4 -> 10Moons UT821                          (tm5600)          [6000:0001]
+  5 -> 10Moons UT330                          (tm5600)
+  6 -> ADSTech Dual TV                        (tm6000)          [06e1:f332]
+  7 -> FreeCom and similar                    (tm6000)          [14aa:0620]
+  8 -> ADSTech Mini Dual TV                   (tm6000)          [06e1:b339]
+  9 -> Hauppauge WinTV HVR-900H/USB2 Stick    (tm6010)          [2040:6600,2040:6601,2040:6610,2040:6611]
+ 10 -> Beholder Wander                        (tm6010)          [6000:dec0]
+ 11 -> Beholder Voyager                       (tm6010)          [6000:dec1]
+ 12 -> TerraTec Cinergy Hybrid XE/Cinergy Hybrid Stick (tm6010) [0ccd:0086,0ccd:00a5]
+ 13 -> TwinHan TU501                          (tm6010)          [13d3:3240,13d3:3241,13d3:3243,13d3:3264]
+ 14 -> Beholder Wander Lite                   (tm6010)          [6000:dec2]
+ 15 -> Beholder Voyager Lite                  (tm6010)          [6000:dec3]
+
index acb0317..2b96047 100644 (file)
@@ -84,7 +84,6 @@ static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip)
 
        tm6000_set_audio_bitrate(core, 48000);
 
-       tm6000_set_reg(core, TM6010_REQ08_R01_A_INIT, 0x80);
 
        return 0;
 }
@@ -101,8 +100,6 @@ static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip)
        /* Disables audio */
        tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x00, 0x40);
 
-       tm6000_set_reg(core, TM6010_REQ08_R01_A_INIT, 0);
-
        return 0;
 }
 
index 146c7e8..a69c82e 100644 (file)
 #define TM6010_BOARD_BEHOLD_VOYAGER_LITE       15
 #define TM5600_BOARD_TERRATEC_GRABSTER         16
 
+#define is_generic(model) ((model == TM6000_BOARD_UNKNOWN) || \
+                          (model == TM5600_BOARD_GENERIC) || \
+                          (model == TM6000_BOARD_GENERIC) || \
+                          (model == TM6010_BOARD_GENERIC))
+
 #define TM6000_MAXBOARDS        16
 static unsigned int card[]     = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET };
 
@@ -64,10 +69,11 @@ static unsigned long tm6000_devused;
 
 struct tm6000_board {
        char            *name;
+       char            eename[16];             /* EEPROM name */
+       unsigned        eename_size;            /* size of EEPROM name */
+       unsigned        eename_pos;             /* Position where it appears at ROM */
 
        struct tm6000_capabilities caps;
-       enum            tm6000_inaudio aradio;
-       enum            tm6000_inaudio avideo;
 
        enum            tm6000_devtype type;    /* variant of the chipset */
        int             tuner_type;     /* type of the tuner */
@@ -76,6 +82,9 @@ struct tm6000_board {
 
        struct tm6000_gpio gpio;
 
+       struct tm6000_input     vinput[3];
+       struct tm6000_input     rinput;
+
        char            *ir_codes;
 };
 
@@ -83,11 +92,26 @@ struct tm6000_board tm6000_boards[] = {
        [TM6000_BOARD_UNKNOWN] = {
                .name         = "Unknown tm6000 video grabber",
                .caps = {
-                       .has_tuner    = 1,
+                       .has_tuner      = 1,
+                       .has_eeprom     = 1,
                },
                .gpio = {
                        .tuner_reset    = TM6000_GPIO_1,
                },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_ADC1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
        },
        [TM5600_BOARD_GENERIC] = {
                .name         = "Generic tm5600 board",
@@ -96,10 +120,25 @@ struct tm6000_board tm6000_boards[] = {
                .tuner_addr   = 0xc2 >> 1,
                .caps = {
                        .has_tuner      = 1,
+                       .has_eeprom     = 1,
                },
                .gpio = {
                        .tuner_reset    = TM6000_GPIO_1,
                },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_ADC1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
        },
        [TM6000_BOARD_GENERIC] = {
                .name         = "Generic tm6000 board",
@@ -107,11 +146,25 @@ struct tm6000_board tm6000_boards[] = {
                .tuner_addr   = 0xc2 >> 1,
                .caps = {
                        .has_tuner      = 1,
-                       .has_dvb        = 1,
+                       .has_eeprom     = 1,
                },
                .gpio = {
                        .tuner_reset    = TM6000_GPIO_1,
                },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_ADC1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
        },
        [TM6010_BOARD_GENERIC] = {
                .name         = "Generic tm6010 board",
@@ -135,10 +188,27 @@ struct tm6000_board tm6000_boards[] = {
                        .dvb_led        = TM6010_GPIO_5,
                        .ir             = TM6010_GPIO_0,
                },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_SIF1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
        },
        [TM5600_BOARD_10MOONS_UT821] = {
                .name         = "10Moons UT 821",
                .tuner_type   = TUNER_XC2028,
+               .eename       = { '1', '0', 'M', 'O', 'O', 'N', 'S', '5', '6', '0', '0', 0xff, 0x45, 0x5b},
+               .eename_size  = 14,
+               .eename_pos   = 0x14,
                .type         = TM5600,
                .tuner_addr   = 0xc2 >> 1,
                .caps = {
@@ -148,6 +218,20 @@ struct tm6000_board tm6000_boards[] = {
                .gpio = {
                        .tuner_reset    = TM6000_GPIO_1,
                },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_ADC1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
        },
        [TM5600_BOARD_10MOONS_UT330] = {
                .name         = "10Moons UT 330",
@@ -159,6 +243,20 @@ struct tm6000_board tm6000_boards[] = {
                        .has_zl10353  = 0,
                        .has_eeprom   = 1,
                },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_ADC1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
        },
        [TM6000_BOARD_ADSTECH_DUAL_TV] = {
                .name         = "ADSTECH Dual TV USB",
@@ -171,6 +269,20 @@ struct tm6000_board tm6000_boards[] = {
                        .has_zl10353  = 1,
                        .has_eeprom   = 1,
                },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_ADC1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
        },
        [TM6000_BOARD_FREECOM_AND_SIMILAR] = {
                .name         = "Freecom Hybrid Stick / Moka DVB-T Receiver Dual",
@@ -187,6 +299,20 @@ struct tm6000_board tm6000_boards[] = {
                .gpio = {
                        .tuner_reset    = TM6000_GPIO_4,
                },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_ADC1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
        },
        [TM6000_BOARD_ADSTECH_MINI_DUAL_TV] = {
                .name         = "ADSTECH Mini Dual TV USB",
@@ -202,9 +328,26 @@ struct tm6000_board tm6000_boards[] = {
                .gpio = {
                        .tuner_reset    = TM6000_GPIO_4,
                },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_ADC1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
        },
        [TM6010_BOARD_HAUPPAUGE_900H] = {
                .name         = "Hauppauge WinTV HVR-900H / WinTV USB2-Stick",
+               .eename       = { 'H', 0, 'V', 0, 'R', 0, '9', 0, '0', 0, '0', 0, 'H', 0 },
+               .eename_size  = 14,
+               .eename_pos   = 0x42,
                .tuner_type   = TUNER_XC2028, /* has a XC3028 */
                .tuner_addr   = 0xc2 >> 1,
                .demod_addr   = 0x1e >> 1,
@@ -225,6 +368,20 @@ struct tm6000_board tm6000_boards[] = {
                        .dvb_led        = TM6010_GPIO_5,
                        .ir             = TM6010_GPIO_0,
                },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_SIF1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
        },
        [TM6010_BOARD_BEHOLD_WANDER] = {
                .name         = "Beholder Wander DVB-T/TV/FM USB2.0",
@@ -232,43 +389,73 @@ struct tm6000_board tm6000_boards[] = {
                .tuner_addr   = 0xc2 >> 1,
                .demod_addr   = 0x1e >> 1,
                .type         = TM6010,
-               .avideo       = TM6000_AIP_SIF1,
-               .aradio       = TM6000_AIP_LINE1,
                .caps = {
                        .has_tuner      = 1,
                        .has_dvb        = 1,
                        .has_zl10353    = 1,
                        .has_eeprom     = 1,
                        .has_remote     = 1,
-                       .has_input_comp = 1,
-                       .has_input_svid = 1,
+                       .has_radio      = 1.
                },
                .gpio = {
                        .tuner_reset    = TM6010_GPIO_0,
                        .demod_reset    = TM6010_GPIO_1,
                        .power_led      = TM6010_GPIO_6,
                },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_SIF1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
+               .rinput = {
+                       .type   = TM6000_INPUT_RADIO,
+                       .amux   = TM6000_AMUX_ADC1,
+               },
        },
        [TM6010_BOARD_BEHOLD_VOYAGER] = {
                .name         = "Beholder Voyager TV/FM USB2.0",
                .tuner_type   = TUNER_XC5000,
                .tuner_addr   = 0xc2 >> 1,
                .type         = TM6010,
-               .avideo       = TM6000_AIP_SIF1,
-               .aradio       = TM6000_AIP_LINE1,
                .caps = {
                        .has_tuner      = 1,
                        .has_dvb        = 0,
                        .has_zl10353    = 0,
                        .has_eeprom     = 1,
                        .has_remote     = 1,
-                       .has_input_comp = 1,
-                       .has_input_svid = 1,
+                       .has_radio      = 1,
                },
                .gpio = {
                        .tuner_reset    = TM6010_GPIO_0,
                        .power_led      = TM6010_GPIO_6,
                },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_SIF1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
+               .rinput = {
+                       .type   = TM6000_INPUT_RADIO,
+                       .amux   = TM6000_AMUX_ADC1,
+               },
        },
        [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = {
                .name         = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick",
@@ -293,11 +480,39 @@ struct tm6000_board tm6000_boards[] = {
                        .ir             = TM6010_GPIO_0,
                },
                .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_SIF1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
        },
        [TM5600_BOARD_TERRATEC_GRABSTER] = {
                .name         = "Terratec Grabster AV 150/250 MX",
                .type         = TM5600,
                .tuner_type   = TUNER_ABSENT,
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_ADC1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
        },
        [TM6010_BOARD_TWINHAN_TU501] = {
                .name         = "Twinhan TU501(704D1)",
@@ -321,6 +536,20 @@ struct tm6000_board tm6000_boards[] = {
                        .dvb_led        = TM6010_GPIO_5,
                        .ir             = TM6010_GPIO_0,
                },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_SIF1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
        },
        [TM6010_BOARD_BEHOLD_WANDER_LITE] = {
                .name         = "Beholder Wander Lite DVB-T/TV/FM USB2.0",
@@ -328,49 +557,63 @@ struct tm6000_board tm6000_boards[] = {
                .tuner_addr   = 0xc2 >> 1,
                .demod_addr   = 0x1e >> 1,
                .type         = TM6010,
-               .avideo       = TM6000_AIP_SIF1,
-               .aradio       = TM6000_AIP_LINE1,
                .caps = {
                        .has_tuner      = 1,
                        .has_dvb        = 1,
                        .has_zl10353    = 1,
                        .has_eeprom     = 1,
                        .has_remote     = 0,
-                       .has_input_comp = 0,
-                       .has_input_svid = 0,
+                       .has_radio      = 1,
                },
                .gpio = {
                        .tuner_reset    = TM6010_GPIO_0,
                        .demod_reset    = TM6010_GPIO_1,
                        .power_led      = TM6010_GPIO_6,
                },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_SIF1,
+                       },
+               },
+               .rinput = {
+                       .type   = TM6000_INPUT_RADIO,
+                       .amux   = TM6000_AMUX_ADC1,
+               },
        },
        [TM6010_BOARD_BEHOLD_VOYAGER_LITE] = {
                .name         = "Beholder Voyager Lite TV/FM USB2.0",
                .tuner_type   = TUNER_XC5000,
                .tuner_addr   = 0xc2 >> 1,
                .type         = TM6010,
-               .avideo       = TM6000_AIP_SIF1,
-               .aradio       = TM6000_AIP_LINE1,
                .caps = {
                        .has_tuner      = 1,
                        .has_dvb        = 0,
                        .has_zl10353    = 0,
                        .has_eeprom     = 1,
                        .has_remote     = 0,
-                       .has_input_comp = 0,
-                       .has_input_svid = 0,
+                       .has_radio      = 1,
                },
                .gpio = {
                        .tuner_reset    = TM6010_GPIO_0,
                        .power_led      = TM6010_GPIO_6,
                },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_SIF1,
+                       },
+               },
+               .rinput = {
+                       .type   = TM6000_INPUT_RADIO,
+                       .amux   = TM6000_AMUX_ADC1,
+               },
        },
 };
 
 /* 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, 0x0001), .driver_info = TM5600_BOARD_GENERIC },
        { 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 },
@@ -679,12 +922,8 @@ static void tm6000_config_tuner(struct tm6000_core *dev)
                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;
 
@@ -729,16 +968,10 @@ static void tm6000_config_tuner(struct tm6000_core *dev)
        }
 }
 
-static int tm6000_init_dev(struct tm6000_core *dev)
+static int fill_board_specific_data(struct tm6000_core *dev)
 {
-       struct v4l2_frequency f;
-       int rc = 0;
-
-       mutex_init(&dev->lock);
-
-       mutex_lock(&dev->lock);
+       int rc;
 
-       /* 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;
@@ -751,21 +984,85 @@ static int tm6000_init_dev(struct tm6000_core *dev)
 
        dev->caps = tm6000_boards[dev->model].caps;
 
-       dev->avideo = tm6000_boards[dev->model].avideo;
-       dev->aradio = tm6000_boards[dev->model].aradio;
+       dev->vinput[0] = tm6000_boards[dev->model].vinput[0];
+       dev->vinput[1] = tm6000_boards[dev->model].vinput[1];
+       dev->vinput[2] = tm6000_boards[dev->model].vinput[2];
+       dev->rinput = tm6000_boards[dev->model].rinput;
+
        /* initialize hardware */
        rc = tm6000_init(dev);
        if (rc < 0)
-               goto err;
+               return rc;
 
        rc = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
        if (rc < 0)
-               goto err;
+               return rc;
 
-       /* register i2c bus */
-       rc = tm6000_i2c_register(dev);
-       if (rc < 0)
-               goto err;
+       return rc;
+}
+
+
+static void use_alternative_detection_method(struct tm6000_core *dev)
+{
+       int i, model = -1;
+
+       if (!dev->eedata_size)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(tm6000_boards); i++) {
+               if (!tm6000_boards[i].eename_size)
+                       continue;
+               if (dev->eedata_size < tm6000_boards[i].eename_pos +
+                                      tm6000_boards[i].eename_size)
+                       continue;
+
+               if (!memcmp(&dev->eedata[tm6000_boards[i].eename_pos],
+                           tm6000_boards[i].eename,
+                           tm6000_boards[i].eename_size)) {
+                       model = i;
+                       break;
+               }
+       }
+       if (model < 0) {
+               printk(KERN_INFO "Device has eeprom but is currently unknown\n");
+               return;
+       }
+
+       dev->model = model;
+
+       printk(KERN_INFO "Device identified via eeprom as %s (type = %d)\n",
+              tm6000_boards[model].name, model);
+}
+
+static int tm6000_init_dev(struct tm6000_core *dev)
+{
+       struct v4l2_frequency f;
+       int rc = 0;
+
+       mutex_init(&dev->lock);
+       mutex_lock(&dev->lock);
+
+       if (!is_generic(dev->model)) {
+               rc = fill_board_specific_data(dev);
+               if (rc < 0)
+                       goto err;
+
+               /* register i2c bus */
+               rc = tm6000_i2c_register(dev);
+               if (rc < 0)
+                       goto err;
+       } else {
+               /* register i2c bus */
+               rc = tm6000_i2c_register(dev);
+               if (rc < 0)
+                       goto err;
+
+               use_alternative_detection_method(dev);
+
+               rc = fill_board_specific_data(dev);
+               if (rc < 0)
+                       goto err;
+       }
 
        /* Default values for STD and resolutions */
        dev->width = 720;
index 778e534..d7eb2e2 100644 (file)
@@ -268,19 +268,18 @@ int tm6000_init_analog_mode(struct tm6000_core *dev)
        struct v4l2_frequency f;
 
        if (dev->dev_type == TM6010) {
-               /* Enable video */
-
+               /* Enable video and audio */
                tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF,
                                                        0x60, 0x60);
+               /* Disable TS input */
                tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE,
                                                        0x00, 0x40);
-               tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc);
-
        } else {
                /* Enables soft reset */
                tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
 
                if (dev->scaler)
+                       /* Disable Hfilter and Enable TS Drop err */
                        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);
@@ -300,14 +299,6 @@ int tm6000_init_analog_mode(struct tm6000_core *dev)
 
                /* Disables soft reset */
                tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00);
-
-               /* E3: Select input 0 - TV tuner */
-               tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x00);
-               tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 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);
 
@@ -327,7 +318,7 @@ int tm6000_init_analog_mode(struct tm6000_core *dev)
        v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
 
        msleep(100);
-       tm6000_set_standard(dev, &dev->norm);
+       tm6000_set_standard(dev);
        tm6000_set_vbi(dev);
        tm6000_set_audio_bitrate(dev, 48000);
 
@@ -343,21 +334,16 @@ int tm6000_init_analog_mode(struct tm6000_core *dev)
 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);
+               /* Disable video and audio */
+               tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF,
+                               0x00, 0x60);
+               /* Enable TS input */
+               tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE,
+                               0x40, 0x40);
+               /* all power down, but not the digital data port */
                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_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);
@@ -489,14 +475,6 @@ struct reg_init tm6010_init_tab[] = {
        { TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0 },
        { TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2 },
        { TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60 },
-       { TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00},
-       { TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0x80},
-       { TM6010_REQ08_R0C_A_ASD_THRES2, 0x0a},
-       { TM6010_REQ08_R0D_A_AMD_THRES, 0x40},
-       { TM6010_REQ08_R1A_A_NICAM_SER_MAX, 0x64},
-       { TM6010_REQ08_R1B_A_NICAM_SER_MIN, 0x20},
-       { TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe},
-       { TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01},
        { TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc },
 
        { TM6010_REQ07_R3F_RESET, 0x01 },
@@ -657,24 +635,29 @@ int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate)
 }
 EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate);
 
-int tm6000_set_audio_input(struct tm6000_core *dev, enum tm6000_inaudio ainp)
+int tm6000_set_audio_rinput(struct tm6000_core *dev)
 {
        if (dev->dev_type == TM6010) {
                /* Audio crossbar setting, default SIF1 */
-               u8 areg_f0 = 0x03;
+               u8 areg_f0;
 
-               switch (ainp) {
-               case TM6000_AIP_SIF1:
-               case TM6000_AIP_SIF2:
+               switch (dev->rinput.amux) {
+               case TM6000_AMUX_SIF1:
+               case TM6000_AMUX_SIF2:
                        areg_f0 = 0x03;
                        break;
-               case TM6000_AIP_LINE1:
+               case TM6000_AMUX_ADC1:
                        areg_f0 = 0x00;
                        break;
-               case TM6000_AIP_LINE2:
+               case TM6000_AMUX_ADC2:
                        areg_f0 = 0x08;
                        break;
+               case TM6000_AMUX_I2S:
+                       areg_f0 = 0x04;
+                       break;
                default:
+                       printk(KERN_INFO "%s: audio input dosn't support\n",
+                               dev->name);
                        return 0;
                        break;
                }
@@ -682,17 +665,18 @@ int tm6000_set_audio_input(struct tm6000_core *dev, enum tm6000_inaudio ainp)
                tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
                                                        areg_f0, 0x0f);
        } else {
+               u8 areg_eb;
                /* Audio setting, default LINE1 */
-               u8 areg_eb = 0x00;
-
-               switch (ainp) {
-               case TM6000_AIP_LINE1:
+               switch (dev->rinput.amux) {
+               case TM6000_AMUX_ADC1:
                        areg_eb = 0x00;
                        break;
-               case TM6000_AIP_LINE2:
+               case TM6000_AMUX_ADC2:
                        areg_eb = 0x04;
                        break;
                default:
+                       printk(KERN_INFO "%s: audio input dosn't support\n",
+                               dev->name);
                        return 0;
                        break;
                }
@@ -702,7 +686,6 @@ int tm6000_set_audio_input(struct tm6000_core *dev, enum tm6000_inaudio ainp)
        }
        return 0;
 }
-EXPORT_SYMBOL_GPL(tm6000_set_audio_input);
 
 void tm6010_set_mute_sif(struct tm6000_core *dev, u8 mute)
 {
@@ -736,16 +719,16 @@ void tm6010_set_mute_adc(struct tm6000_core *dev, u8 mute)
 
 int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute)
 {
-       enum tm6000_inaudio ainp;
+       enum tm6000_mux mux;
 
        if (dev->radio)
-               ainp = dev->aradio;
+               mux = dev->rinput.amux;
        else
-               ainp = dev->avideo;
+               mux = dev->vinput[dev->input].amux;
 
-       switch (ainp) {
-       case TM6000_AIP_SIF1:
-       case TM6000_AIP_SIF2:
+       switch (mux) {
+       case TM6000_AMUX_SIF1:
+       case TM6000_AMUX_SIF2:
                if (dev->dev_type == TM6010)
                        tm6010_set_mute_sif(dev, mute);
                else {
@@ -755,8 +738,8 @@ int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute)
                        return -EINVAL;
                }
                break;
-       case TM6000_AIP_LINE1:
-       case TM6000_AIP_LINE2:
+       case TM6000_AMUX_ADC1:
+       case TM6000_AMUX_ADC2:
                tm6010_set_mute_adc(dev, mute);
                break;
        default:
@@ -765,7 +748,6 @@ int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute)
        }
        return 0;
 }
-EXPORT_SYMBOL_GPL(tm6000_tvaudio_set_mute);
 
 void tm6010_set_volume_sif(struct tm6000_core *dev, int vol)
 {
@@ -797,17 +779,17 @@ void tm6010_set_volume_adc(struct tm6000_core *dev, int vol)
 
 void tm6000_set_volume(struct tm6000_core *dev, int vol)
 {
-       enum tm6000_inaudio ainp;
+       enum tm6000_mux mux;
 
        if (dev->radio) {
-               ainp = dev->aradio;
+               mux = dev->rinput.amux;
                vol += 8; /* Offset to 0 dB */
        } else
-               ainp = dev->avideo;
+               mux = dev->vinput[dev->input].amux;
 
-       switch (ainp) {
-       case TM6000_AIP_SIF1:
-       case TM6000_AIP_SIF2:
+       switch (mux) {
+       case TM6000_AMUX_SIF1:
+       case TM6000_AMUX_SIF2:
                if (dev->dev_type == TM6010)
                        tm6010_set_volume_sif(dev, vol);
                else
@@ -815,15 +797,14 @@ void tm6000_set_volume(struct tm6000_core *dev, int vol)
                                        " SIF audio inputs. Please check the %s"
                                        " configuration.\n", dev->name);
                break;
-       case TM6000_AIP_LINE1:
-       case TM6000_AIP_LINE2:
+       case TM6000_AMUX_ADC1:
+       case TM6000_AMUX_ADC2:
                tm6010_set_volume_adc(dev, vol);
                break;
        default:
                break;
        }
 }
-EXPORT_SYMBOL_GPL(tm6000_set_volume);
 
 static LIST_HEAD(tm6000_devlist);
 static DEFINE_MUTEX(tm6000_devlist_mutex);
index 18de474..8828c12 100644 (file)
@@ -237,35 +237,36 @@ err:
        return rc;
 }
 
-static int tm6000_i2c_eeprom(struct tm6000_core *dev,
-                            unsigned char *eedata, int len)
+static int tm6000_i2c_eeprom(struct tm6000_core *dev)
 {
        int i, rc;
-       unsigned char *p = eedata;
+       unsigned char *p = dev->eedata;
        unsigned char bytes[17];
 
        dev->i2c_client.addr = 0xa0 >> 1;
+       dev->eedata_size = 0;
 
        bytes[16] = '\0';
-       for (i = 0; i < len; ) {
-       *p = i;
-       rc = tm6000_i2c_recv_regs(dev, 0xa0, i, p, 1);
+       for (i = 0; i < sizeof(dev->eedata); ) {
+               *p = i;
+               rc = tm6000_i2c_recv_regs(dev, 0xa0, i, p, 1);
                if (rc < 1) {
-                       if (p == eedata)
+                       if (p == dev->eedata)
                                goto noeeprom;
                        else {
                                printk(KERN_WARNING
                                "%s: i2c eeprom read error (err=%d)\n",
                                dev->name, rc);
                        }
-                       return -1;
+                       return -EINVAL;
                }
+               dev->eedata_size++;
                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];
+               printk(" %02x", dev->eedata[i]);
+               if ((dev->eedata[i] >= ' ') && (dev->eedata[i] <= 'z'))
+                       bytes[i%16] = dev->eedata[i];
                else
                        bytes[i%16] = '.';
 
@@ -280,15 +281,15 @@ static int tm6000_i2c_eeprom(struct tm6000_core *dev,
                bytes[i%16] = '\0';
                for (i %= 16; i < 16; i++)
                        printk("   ");
+               printk("  %s\n", bytes);
        }
-       printk("  %s\n", bytes);
 
        return 0;
 
 noeeprom:
        printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
-                      dev->name, rc);
-       return rc;
+              dev->name, rc);
+       return -EINVAL;
 }
 
 /* ----------------------------------------------------------- */
@@ -314,7 +315,6 @@ static const struct i2c_algorithm tm6000_algo = {
  */
 int tm6000_i2c_register(struct tm6000_core *dev)
 {
-       unsigned char eedata[256];
        int rc;
 
        dev->i2c_adap.owner = THIS_MODULE;
@@ -329,8 +329,7 @@ int tm6000_i2c_register(struct tm6000_core *dev)
 
        dev->i2c_client.adapter = &dev->i2c_adap;
        strlcpy(dev->i2c_client.name, "tm6000 internal", I2C_NAME_SIZE);
-
-       tm6000_i2c_eeprom(dev, eedata, sizeof(eedata));
+       tm6000_i2c_eeprom(dev);
 
        return 0;
 }
index da3e51b..8b29d73 100644 (file)
 #include "tm6000.h"
 #include "tm6000-regs.h"
 
+static unsigned int tm6010_a_mode = 0;
+module_param(tm6010_a_mode, int, 0644);
+MODULE_PARM_DESC(tm6010_a_mode, "set tm6010 sif audio mode");
+
 struct tm6000_reg_settings {
        unsigned char req;
        unsigned char reg;
        unsigned char value;
 };
 
-enum tm6000_audio_std {
-       BG_NICAM,
-       BTSC,
-       BG_A2,
-       DK_NICAM,
-       EIAJ,
-       FM_RADIO,
-       I_NICAM,
-       KOREA_A2,
-       L_NICAM,
-};
-
-struct tm6000_std_tv_settings {
-       v4l2_std_id id;
-       enum tm6000_audio_std audio_default_std;
-
-       struct tm6000_reg_settings sif[12];
-       struct tm6000_reg_settings nosif[12];
-       struct tm6000_reg_settings common[26];
-};
 
 struct tm6000_std_settings {
        v4l2_std_id id;
-       enum tm6000_audio_std audio_default_std;
-       struct tm6000_reg_settings common[37];
-};
-
-static struct tm6000_std_tv_settings tv_stds[] = {
-       {
-               .id = V4L2_STD_PAL_M,
-               .audio_default_std = BTSC,
-               .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, 0x31},
-                       {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,
-               .audio_default_std = BTSC,
-               .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, 0x31},
-                       {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,
-               .audio_default_std = BG_A2,
-               .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, 0x31},
-                       {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_B | V4L2_STD_SECAM_G,
-               .audio_default_std = BG_NICAM,
-               .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, 0x31},
-                       {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_SECAM_DK,
-               .audio_default_std = DK_NICAM,
-               .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, 0x31},
-                       {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,
-               .audio_default_std = BTSC,
-               .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, 0x31},
-                       {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},
-               },
-       },
+       struct tm6000_reg_settings common[27];
 };
 
 static struct tm6000_std_settings composite_stds[] = {
        {
                .id = V4L2_STD_PAL_M,
-               .audio_default_std = BTSC,
                .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},
@@ -467,20 +71,7 @@ static struct tm6000_std_settings composite_stds[] = {
                },
         }, {
                .id = V4L2_STD_PAL_Nc,
-               .audio_default_std = BTSC,
                .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},
@@ -510,20 +101,7 @@ static struct tm6000_std_settings composite_stds[] = {
                },
        }, {
                .id = V4L2_STD_PAL,
-               .audio_default_std = BG_A2,
                .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},
@@ -553,62 +131,7 @@ static struct tm6000_std_settings composite_stds[] = {
                },
         }, {
                .id = V4L2_STD_SECAM,
-               .audio_default_std = BG_NICAM,
-               .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, 0x31},
-                       {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_SECAM_DK,
-               .audio_default_std = DK_NICAM,
                .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},
@@ -637,20 +160,7 @@ static struct tm6000_std_settings composite_stds[] = {
                },
        }, {
                .id = V4L2_STD_NTSC,
-               .audio_default_std = BTSC,
                .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},
@@ -684,20 +194,7 @@ static struct tm6000_std_settings composite_stds[] = {
 static struct tm6000_std_settings svideo_stds[] = {
        {
                .id = V4L2_STD_PAL_M,
-               .audio_default_std = BTSC,
                .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},
@@ -727,20 +224,7 @@ static struct tm6000_std_settings svideo_stds[] = {
                },
        }, {
                .id = V4L2_STD_PAL_Nc,
-               .audio_default_std = BTSC,
                .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},
@@ -770,20 +254,7 @@ static struct tm6000_std_settings svideo_stds[] = {
                },
        }, {
                .id = V4L2_STD_PAL,
-               .audio_default_std = BG_A2,
                .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},
@@ -813,62 +284,7 @@ static struct tm6000_std_settings svideo_stds[] = {
                },
         }, {
                .id = V4L2_STD_SECAM,
-               .audio_default_std = BG_NICAM,
-               .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, 0x31},
-                       {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_SECAM_DK,
-               .audio_default_std = DK_NICAM,
                .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},
@@ -897,20 +313,7 @@ static struct tm6000_std_settings svideo_stds[] = {
                },
        }, {
                .id = V4L2_STD_NTSC,
-               .audio_default_std = BTSC,
                .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},
@@ -943,13 +346,11 @@ static struct tm6000_std_settings svideo_stds[] = {
 };
 
 
-static int tm6000_set_audio_std(struct tm6000_core *dev,
-                               enum tm6000_audio_std std)
+static int tm6000_set_audio_std(struct tm6000_core *dev)
 {
        uint8_t areg_02 = 0x04; /* GC1 Fixed gain 0dB */
-       uint8_t areg_05 = 0x09; /* Auto 4.5 = M Japan, Auto 6.5 = DK */
+       uint8_t areg_05 = 0x01; /* Auto 4.5 = M Japan, Auto 6.5 = DK */
        uint8_t areg_06 = 0x02; /* Auto de-emphasis, mannual channel mode */
-       uint8_t mono_flag = 0;  /* No mono */
        uint8_t nicam_flag = 0; /* No NICAM */
 
        if (dev->radio) {
@@ -958,81 +359,99 @@ static int tm6000_set_audio_std(struct tm6000_core *dev,
                tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00);
                tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0x80);
                tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, 0x0c);
-               tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00);
+               /* set mono or stereo */
+               if (dev->amode == V4L2_TUNER_MODE_MONO)
+                       tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00);
+               else if (dev->amode == V4L2_TUNER_MODE_STEREO)
+                       tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x02);
                tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x18);
                tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x0a);
                tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x40);
-               tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc);
+               tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe);
                tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13);
                tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80);
                return 0;
        }
 
-       switch (std) {
-#if 0
-       case DK_MONO:
-               mono_flag = 1;
-               break;
-       case DK_A2_1:
-               break;
-       case DK_A2_3:
-               areg_05 = 0x0b;
-               break;
-       case BG_MONO:
-               mono_flag = 1;
-               areg_05 = 0x05;
-               break;
-#endif
-       case BG_NICAM:
-               areg_05 = 0x07;
-               nicam_flag = 1;
-               break;
-       case BTSC:
-               areg_05 = 0x02;
-               break;
-       case BG_A2:
-               areg_05 = 0x05;
-               break;
-       case DK_NICAM:
-               areg_05 = 0x06;
-               nicam_flag = 1;
-               break;
-       case EIAJ:
-               areg_05 = 0x02;
-               break;
-       case I_NICAM:
-               areg_05 = 0x08;
-               nicam_flag = 1;
+       switch (tm6010_a_mode) {
+       /* auto */
+       case 0:
+               switch (dev->norm) {
+               case V4L2_STD_NTSC_M_KR:
+                       areg_05 |= 0x00;
+                       break;
+               case V4L2_STD_NTSC_M_JP:
+                       areg_05 |= 0x40;
+                       break;
+               case V4L2_STD_NTSC_M:
+               case V4L2_STD_PAL_M:
+               case V4L2_STD_PAL_N:
+                       areg_05 |= 0x20;
+                       break;
+               case V4L2_STD_PAL_Nc:
+                       areg_05 |= 0x60;
+                       break;
+               case V4L2_STD_SECAM_L:
+                       areg_05 |= 0x00;
+                       break;
+               case V4L2_STD_DK:
+                       areg_05 |= 0x10;
+                       break;
+               }
                break;
-       case KOREA_A2:
-               areg_05 = 0x04;
+       /* A2 */
+       case 1:
+               switch (dev->norm) {
+               case V4L2_STD_B:
+               case V4L2_STD_GH:
+                       areg_05 = 0x05;
+                       break;
+               case V4L2_STD_DK:
+                       areg_05 = 0x09;
+                       break;
+               }
                break;
-       case L_NICAM:
-               areg_02 = 0x02; /* GC1 Fixed gain +12dB */
-               areg_05 = 0x0a;
+       /* NICAM */
+       case 2:
+               switch (dev->norm) {
+               case V4L2_STD_B:
+               case V4L2_STD_GH:
+                       areg_05 = 0x07;
+                       break;
+               case V4L2_STD_DK:
+                       areg_05 = 0x06;
+                       break;
+               case V4L2_STD_PAL_I:
+                       areg_05 = 0x08;
+                       break;
+               case V4L2_STD_SECAM_L:
+                       areg_05 = 0x0a;
+                       areg_02 = 0x02;
+                       break;
+               }
                nicam_flag = 1;
                break;
-       default:
-               /* do nothink */
-               break;
-       }
-
-#if 0
-       switch (tv_audio_mode) {
-       case TV_MONO:
-               areg_06 = (nicam_flag) ? 0x03 : 0x00;
-               break;
-       case TV_LANG_A:
-               areg_06 = 0x00;
-               break;
-       case TV_LANG_B:
-               areg_06 = 0x01;
+       /* other */
+       case 3:
+               switch (dev->norm) {
+               /* DK3_A2 */
+               case V4L2_STD_DK:
+                       areg_05 = 0x0b;
+                       break;
+               /* Korea */
+               case V4L2_STD_NTSC_M_KR:
+                       areg_05 = 0x04;
+                       break;
+               /* EIAJ */
+               case V4L2_STD_NTSC_M_JP:
+                       areg_05 = 0x03;
+                       break;
+               default:
+                       areg_05 = 0x02;
+                       break;
+               }
                break;
        }
-#endif
-
-       if (mono_flag)
-               areg_06 = 0x00;
 
        tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
        tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, areg_02);
@@ -1066,9 +485,6 @@ static int tm6000_set_audio_std(struct tm6000_core *dev,
        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_RF1_AADC_POWER_DOWN, 0xfc);
        tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80);
 
        return 0;
@@ -1095,10 +511,6 @@ static int tm6000_load_std(struct tm6000_core *dev,
                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 "
@@ -1111,53 +523,126 @@ static int tm6000_load_std(struct tm6000_core *dev,
        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));
-
-       tm6000_set_audio_std(dev, tv_stds[pos].audio_default_std);
-
-       return rc;
-}
-
-int tm6000_set_standard(struct tm6000_core *dev, v4l2_std_id * norm)
+int tm6000_set_standard(struct tm6000_core *dev)
 {
        int i, rc = 0;
+       u8 reg_07_fe = 0x8a;
+       u8 reg_08_f1 = 0xfc;
+       u8 reg_08_e2 = 0xf0;
+       u8 reg_08_e6 = 0x0f;
 
-       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;
-                       }
+       if (dev->radio) {
+               /* todo */
+       }
+
+       if (dev->dev_type == TM6010) {
+               switch (dev->vinput[dev->input].vmux) {
+               case TM6000_VMUX_VIDEO_A:
+                       tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4);
+                       tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1);
+                       tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0);
+                       tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2);
+                       tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe8);
+                       reg_07_fe |= 0x01;
+                       break;
+               case TM6000_VMUX_VIDEO_B:
+                       tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8);
+                       tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1);
+                       tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0);
+                       tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2);
+                       tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe8);
+                       reg_07_fe |= 0x01;
+                       break;
+               case TM6000_VMUX_VIDEO_AB:
+                       tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc);
+                       tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8);
+                       reg_08_e6 = 0x00;
+                       tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2);
+                       tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0);
+                       tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2);
+                       tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe0);
+                       break;
+               default:
+                       break;
                }
-               return -EINVAL;
-       case TM6000_INPUT_SVIDEO:
+               switch (dev->vinput[dev->input].amux) {
+               case TM6000_AMUX_ADC1:
+                       tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
+                               0x00, 0x0f);
+                       break;
+               case TM6000_AMUX_ADC2:
+                       tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
+                               0x08, 0x0f);
+                       break;
+               case TM6000_AMUX_SIF1:
+                       reg_08_e2 |= 0x02;
+                       reg_08_e6 = 0x08;
+                       reg_07_fe |= 0x40;
+                       reg_08_f1 |= 0x02;
+                       tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3);
+                       tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
+                               0x02, 0x0f);
+                       break;
+               case TM6000_AMUX_SIF2:
+                       reg_08_e2 |= 0x02;
+                       reg_08_e6 = 0x08;
+                       reg_07_fe |= 0x40;
+                       reg_08_f1 |= 0x02;
+                       tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf7);
+                       tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
+                               0x02, 0x0f);
+                       break;
+               default:
+                       break;
+               }
+               tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, reg_08_e2);
+               tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, reg_08_e6);
+               tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, reg_08_f1);
+               tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, reg_07_fe);
+       } else {
+               switch (dev->vinput[dev->input].vmux) {
+               case TM6000_VMUX_VIDEO_A:
+                       tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10);
+                       tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00);
+                       tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x0f);
+                       tm6000_set_reg(dev,
+                           REQ_03_SET_GET_MCU_PIN, dev->vinput[dev->input].v_gpio, 0);
+                       break;
+               case TM6000_VMUX_VIDEO_B:
+                       tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x00);
+                       tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00);
+                       tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x0f);
+                       tm6000_set_reg(dev,
+                           REQ_03_SET_GET_MCU_PIN, dev->vinput[dev->input].v_gpio, 0);
+                       break;
+               case TM6000_VMUX_VIDEO_AB:
+                       tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10);
+                       tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x10);
+                       tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x00);
+                       tm6000_set_reg(dev,
+                           REQ_03_SET_GET_MCU_PIN, dev->vinput[dev->input].v_gpio, 1);
+                       break;
+               default:
+                       break;
+               }
+               switch (dev->vinput[dev->input].amux) {
+               case TM6000_AMUX_ADC1:
+                       tm6000_set_reg_mask(dev,
+                               TM6000_REQ07_REB_VADC_AADC_MODE, 0x00, 0x0f);
+                       break;
+               case TM6000_AMUX_ADC2:
+                       tm6000_set_reg_mask(dev,
+                               TM6000_REQ07_REB_VADC_AADC_MODE, 0x04, 0x0f);
+                       break;
+               default:
+                       break;
+               }
+       }
+       if (dev->vinput[dev->input].type == TM6000_INPUT_SVIDEO) {
                for (i = 0; i < ARRAY_SIZE(svideo_stds); i++) {
-                       if (*norm & svideo_stds[i].id) {
+                       if (dev->norm & svideo_stds[i].id) {
                                rc = tm6000_load_std(dev, svideo_stds[i].common,
                                                     sizeof(svideo_stds[i].
                                                            common));
@@ -1165,14 +650,13 @@ int tm6000_set_standard(struct tm6000_core *dev, v4l2_std_id * norm)
                        }
                }
                return -EINVAL;
-       case TM6000_INPUT_COMPOSITE:
+       } else {
                for (i = 0; i < ARRAY_SIZE(composite_stds); i++) {
-                       if (*norm & composite_stds[i].id) {
+                       if (dev->norm & composite_stds[i].id) {
                                rc = tm6000_load_std(dev,
                                                     composite_stds[i].common,
                                                     sizeof(composite_stds[i].
                                                            common));
-                               tm6000_set_audio_std(dev, composite_stds[i].audio_default_std);
                                goto ret;
                        }
                }
@@ -1183,6 +667,11 @@ ret:
        if (rc < 0)
                return rc;
 
+       if ((dev->dev_type == TM6010) &&
+           ((dev->vinput[dev->input].amux == TM6000_AMUX_SIF1) ||
+           (dev->vinput[dev->input].amux == TM6000_AMUX_SIF2)))
+               tm6000_set_audio_std(dev);
+
        msleep(40);
 
 
index a9e61d9..084c2a8 100644 (file)
@@ -39,7 +39,7 @@ struct usb_isoc_ctl {
        int                             pos, size, pktsize;
 
                /* Last field: ODD or EVEN? */
-       int                             vfield;
+       int                             vfield, field;
 
                /* Stores incomplete commands */
        u32                             tmp_buf;
index 17db668..4264064 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/usb.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-ioctl.h>
+#include <media/tuner.h>
 #include <linux/interrupt.h>
 #include <linux/kthread.h>
 #include <linux/highmem.h>
@@ -228,7 +229,7 @@ static int copy_streams(u8 *data, unsigned long len,
        unsigned long header = 0;
        int rc = 0;
        unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0;
-       struct tm6000_buffer *vbuf;
+       struct tm6000_buffer *vbuf = NULL;
        char *voutp = NULL;
        unsigned int linewidth;
 
@@ -318,7 +319,7 @@ static int copy_streams(u8 *data, unsigned long len,
                                        if (pos + size > vbuf->vb.size)
                                                cmd = TM6000_URB_MSG_ERR;
                                        dev->isoc_ctl.vfield = field;
-                       }
+                               }
                                break;
                        case TM6000_URB_MSG_VBI:
                                break;
@@ -333,6 +334,7 @@ static int copy_streams(u8 *data, unsigned long len,
                        size = dev->isoc_ctl.size;
                        pos = dev->isoc_ctl.pos;
                        pktsize = dev->isoc_ctl.pktsize;
+                       field = dev->isoc_ctl.field;
                }
                cpysize = (endp - ptr > size) ? size : endp - ptr;
                if (cpysize) {
@@ -343,24 +345,26 @@ static int copy_streams(u8 *data, unsigned long len,
                                if (vbuf)
                                        memcpy(&voutp[pos], ptr, cpysize);
                                break;
-                       case TM6000_URB_MSG_AUDIO:
-                               /* Need some code to copy audio buffer */
-                               if (dev->fourcc == V4L2_PIX_FMT_YUYV) {
-                                       /* Swap word bytes */
-                                       int i;
+                       case TM6000_URB_MSG_AUDIO: {
+                               int i;
+                               for (i = 0; i < cpysize; i += 2)
+                                       swab16s((u16 *)(ptr + i));
 
-                                       for (i = 0; i < cpysize; i += 2)
-                                               swab16s((u16 *)(ptr + i));
-                               }
                                tm6000_call_fillbuf(dev, TM6000_AUDIO, ptr, cpysize);
                                break;
+                       }
                        case TM6000_URB_MSG_VBI:
                                /* Need some code to copy vbi buffer */
                                break;
-                       case TM6000_URB_MSG_PTS:
+                       case TM6000_URB_MSG_PTS: {
                                /* Need some code to copy pts */
+                               u32 pts;
+                               pts = *(u32 *)ptr;
+                               dprintk(dev, V4L2_DEBUG_ISOC, "field %d, PTS %x",
+                                       field, pts);
                                break;
                        }
+                       }
                }
                if (ptr + pktsize > endp) {
                        /* End of URB packet, but cmd processing is not
@@ -369,6 +373,7 @@ static int copy_streams(u8 *data, unsigned long len,
                        dev->isoc_ctl.pos = pos + cpysize;
                        dev->isoc_ctl.size = size - cpysize;
                        dev->isoc_ctl.cmd = cmd;
+                       dev->isoc_ctl.field = field;
                        dev->isoc_ctl.pktsize = pktsize - (endp - ptr);
                        ptr += endp - ptr;
                } else {
@@ -883,14 +888,19 @@ static void res_free(struct tm6000_core *dev, struct tm6000_fh *fh)
 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));
        cap->version = TM6000_VERSION;
        cap->capabilities =     V4L2_CAP_VIDEO_CAPTURE |
                                V4L2_CAP_STREAMING     |
-                               V4L2_CAP_TUNER         |
+                               V4L2_CAP_AUDIO         |
                                V4L2_CAP_READWRITE;
+
+       if (dev->tuner_type != TUNER_ABSENT)
+               cap->capabilities |= V4L2_CAP_TUNER;
+
        return 0;
 }
 
@@ -1077,35 +1087,37 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *norm)
        return 0;
 }
 
+static const char *iname [] = {
+       [TM6000_INPUT_TV] = "Television",
+       [TM6000_INPUT_COMPOSITE1] = "Composite 1",
+       [TM6000_INPUT_COMPOSITE2] = "Composite 2",
+       [TM6000_INPUT_SVIDEO] = "S-Video",
+};
+
 static int vidioc_enum_input(struct file *file, void *priv,
-                               struct v4l2_input *inp)
+                               struct v4l2_input *i)
 {
        struct tm6000_fh   *fh = priv;
        struct tm6000_core *dev = fh->dev;
+       unsigned int n;
 
-       switch (inp->index) {
-       case TM6000_INPUT_TV:
-               inp->type = V4L2_INPUT_TYPE_TUNER;
-               strcpy(inp->name, "Television");
-               break;
-       case TM6000_INPUT_COMPOSITE:
-               if (dev->caps.has_input_comp) {
-                       inp->type = V4L2_INPUT_TYPE_CAMERA;
-                       strcpy(inp->name, "Composite");
-               } else
-                       return -EINVAL;
-               break;
-       case TM6000_INPUT_SVIDEO:
-               if (dev->caps.has_input_svid) {
-                       inp->type = V4L2_INPUT_TYPE_CAMERA;
-                       strcpy(inp->name, "S-Video");
-               } else
-                       return -EINVAL;
-               break;
-       default:
+       n = i->index;
+       if (n >= 3)
                return -EINVAL;
-       }
-       inp->std = TM6000_STD;
+
+       if (!dev->vinput[n].type)
+               return -EINVAL;
+
+       i->index = n;
+
+       if (dev->vinput[n].type == TM6000_INPUT_TV)
+               i->type = V4L2_INPUT_TYPE_TUNER;
+       else
+               i->type = V4L2_INPUT_TYPE_CAMERA;
+
+       strcpy(i->name, iname[dev->vinput[n].type]);
+
+       i->std = TM6000_STD;
 
        return 0;
 }
@@ -1119,38 +1131,26 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
 
        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:
+       if (i >= 3)
+               return -EINVAL;
+       if (!dev->vinput[i].type)
                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);
-       }
+       dev->input = i;
+
+       rc = vidioc_s_std(file, priv, &dev->vfd->current_norm);
 
        return rc;
 }
 
-       /* --- controls ---------------------------------------------- */
+/* --- controls ---------------------------------------------- */
 static int vidioc_queryctrl(struct file *file, void *priv,
                                struct v4l2_queryctrl *qc)
 {
@@ -1251,7 +1251,11 @@ static int vidioc_g_tuner(struct file *file, void *priv,
        t->type       = V4L2_TUNER_ANALOG_TV;
        t->capability = V4L2_TUNER_CAP_NORM;
        t->rangehigh  = 0xffffffffUL;
-       t->rxsubchans = V4L2_TUNER_SUB_MONO;
+       t->rxsubchans = V4L2_TUNER_SUB_STEREO;
+
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
+
+       t->audmode = dev->amode;
 
        return 0;
 }
@@ -1267,6 +1271,11 @@ static int vidioc_s_tuner(struct file *file, void *priv,
        if (0 != t->index)
                return -EINVAL;
 
+       dev->amode = t->audmode;
+       dprintk(dev, 3, "audio mode: %x\n", t->audmode);
+
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
+
        return 0;
 }
 
@@ -1320,7 +1329,11 @@ static int radio_querycap(struct file *file, void *priv,
                le16_to_cpu(dev->udev->descriptor.idVendor),
                le16_to_cpu(dev->udev->descriptor.idProduct));
        cap->version = dev->dev_type;
-       cap->capabilities = V4L2_CAP_TUNER;
+       cap->capabilities = V4L2_CAP_TUNER |
+                       V4L2_CAP_AUDIO     |
+                       V4L2_CAP_RADIO     |
+                       V4L2_CAP_READWRITE |
+                       V4L2_CAP_STREAMING;
 
        return 0;
 }
@@ -1337,17 +1350,10 @@ static int radio_g_tuner(struct file *file, void *priv,
        memset(t, 0, sizeof(*t));
        strcpy(t->name, "Radio");
        t->type = V4L2_TUNER_RADIO;
+       t->rxsubchans = V4L2_TUNER_SUB_STEREO;
 
        v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
 
-       if ((dev->aradio == TM6000_AIP_LINE1) ||
-                               (dev->aradio == TM6000_AIP_LINE2)) {
-               t->rxsubchans = V4L2_TUNER_SUB_MONO;
-       }
-       else {
-               t->rxsubchans = V4L2_TUNER_SUB_STEREO;
-       }
-
        return 0;
 }
 
@@ -1368,9 +1374,15 @@ static int radio_s_tuner(struct file *file, void *priv,
 static int radio_enum_input(struct file *file, void *priv,
                                        struct v4l2_input *i)
 {
+       struct tm6000_fh *fh = priv;
+       struct tm6000_core *dev = fh->dev;
+
        if (i->index != 0)
                return -EINVAL;
 
+       if (!dev->rinput.type)
+               return -EINVAL;
+
        strcpy(i->name, "Radio");
        i->type = V4L2_INPUT_TYPE_TUNER;
 
@@ -1379,7 +1391,14 @@ static int radio_enum_input(struct file *file, void *priv,
 
 static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
 {
-       *i = 0;
+       struct tm6000_fh *fh = priv;
+       struct tm6000_core *dev = fh->dev;
+
+       if (dev->input !=5)
+               return -EINVAL;
+
+       *i = dev->input -5;
+
        return 0;
 }
 
@@ -1399,6 +1418,17 @@ static int radio_s_audio(struct file *file, void *priv,
 
 static int radio_s_input(struct file *filp, void *priv, unsigned int i)
 {
+       struct tm6000_fh *fh = priv;
+       struct tm6000_core *dev = fh->dev;
+
+       if (i)
+               return -EINVAL;
+
+       if (!dev->rinput.type)
+               return -EINVAL;
+
+       dev->input = i + 5;
+
        return 0;
 }
 
@@ -1512,16 +1542,12 @@ static int tm6000_open(struct file *file)
 
        if (fh->radio) {
                dprintk(dev, V4L2_DEBUG_OPEN, "video_open: setting radio device\n");
-               tm6000_set_audio_input(dev, dev->aradio);
-               tm6000_set_volume(dev, dev->ctl_volume);
+               dev->input = 5;
+               tm6000_set_audio_rinput(dev);
                v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
                tm6000_prepare_isoc(dev);
                tm6000_start_thread(dev);
        }
-       else {
-               tm6000_set_audio_input(dev, dev->avideo);
-               tm6000_set_volume(dev, dev->ctl_volume);
-       }
 
        return 0;
 }
@@ -1647,10 +1673,10 @@ static struct video_device tm6000_template = {
 };
 
 static const struct v4l2_file_operations radio_fops = {
-       .owner    = THIS_MODULE,
-       .open     = tm6000_open,
-       .release  = tm6000_release,
-       .ioctl    = video_ioctl2,
+       .owner          = THIS_MODULE,
+       .open           = tm6000_open,
+       .release        = tm6000_release,
+       .unlocked_ioctl = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops radio_ioctl_ops = {
@@ -1730,24 +1756,26 @@ int tm6000_v4l2_register(struct tm6000_core *dev)
        printk(KERN_INFO "%s: registered device %s\n",
               dev->name, video_device_node_name(dev->vfd));
 
-       dev->radio_dev = vdev_init(dev, &tm6000_radio_template,
-                                                  "radio");
-       if (!dev->radio_dev) {
-               printk(KERN_INFO "%s: can't register radio device\n",
-                      dev->name);
-               return ret; /* FIXME release resource */
-       }
+       if (dev->caps.has_radio) {
+               dev->radio_dev = vdev_init(dev, &tm6000_radio_template,
+                                                          "radio");
+               if (!dev->radio_dev) {
+                       printk(KERN_INFO "%s: can't register radio device\n",
+                              dev->name);
+                       return ret; /* FIXME release resource */
+               }
 
-       ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
-                                   radio_nr);
-       if (ret < 0) {
-               printk(KERN_INFO "%s: can't register radio device\n",
-                      dev->name);
-               return ret; /* FIXME release resource */
-       }
+               ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
+                                           radio_nr);
+               if (ret < 0) {
+                       printk(KERN_INFO "%s: can't register radio device\n",
+                              dev->name);
+                       return ret; /* FIXME release resource */
+               }
 
-       printk(KERN_INFO "%s: registered device %s\n",
-              dev->name, video_device_node_name(dev->radio_dev));
+               printk(KERN_INFO "%s: registered device %s\n",
+                      dev->name, video_device_node_name(dev->radio_dev));
+       }
 
        printk(KERN_INFO "Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d)\n", ret);
        return ret;
index 99ae50e..ae6369b 100644 (file)
 #define TM6000_VERSION KERNEL_VERSION(0, 0, 2)
 
 /* Inputs */
-
 enum tm6000_itype {
-       TM6000_INPUT_TV = 0,
-       TM6000_INPUT_COMPOSITE,
+       TM6000_INPUT_TV = 1,
+       TM6000_INPUT_COMPOSITE1,
+       TM6000_INPUT_COMPOSITE2,
        TM6000_INPUT_SVIDEO,
+       TM6000_INPUT_DVB,
+       TM6000_INPUT_RADIO,
+};
+
+enum tm6000_mux {
+       TM6000_VMUX_VIDEO_A = 1,
+       TM6000_VMUX_VIDEO_B,
+       TM6000_VMUX_VIDEO_AB,
+       TM6000_AMUX_ADC1,
+       TM6000_AMUX_ADC2,
+       TM6000_AMUX_SIF1,
+       TM6000_AMUX_SIF2,
+       TM6000_AMUX_I2S,
 };
 
 enum tm6000_devtype {
@@ -53,12 +66,12 @@ enum tm6000_devtype {
        TM6010,
 };
 
-enum tm6000_inaudio {
-       TM6000_AIP_UNK = 0,
-       TM6000_AIP_SIF1,
-       TM6000_AIP_SIF2,
-       TM6000_AIP_LINE1,
-       TM6000_AIP_LINE2,
+struct tm6000_input {
+       enum tm6000_itype       type;
+       enum tm6000_mux         vmux;
+       enum tm6000_mux         amux;
+       unsigned int            v_gpio;
+       unsigned int            a_gpio;
 };
 
 /* ------------------------------------------------------------------
@@ -129,8 +142,7 @@ struct tm6000_capabilities {
        unsigned int    has_zl10353:1;
        unsigned int    has_eeprom:1;
        unsigned int    has_remote:1;
-       unsigned int    has_input_comp:1;
-       unsigned int    has_input_svid:1;
+       unsigned int    has_radio:1;
 };
 
 struct tm6000_dvb {
@@ -167,6 +179,8 @@ struct tm6000_core {
        int                             model;          /* index in the device_data struct */
        int                             devno;          /* marks the number of this device */
        enum tm6000_devtype             dev_type;       /* type of device */
+       unsigned char                   eedata[256];    /* Eeprom data */
+       unsigned                        eedata_size;    /* Size of the eeprom info */
 
        v4l2_std_id                     norm;           /* Current norm */
        int                             width, height;  /* Selected resolution */
@@ -211,6 +225,9 @@ struct tm6000_core {
        struct v4l2_device              v4l2_dev;
 
        int                             input;
+       struct tm6000_input             vinput[3];      /* video input */
+       struct tm6000_input             rinput;         /* radio input */
+
        int                             freq;
        unsigned int                    fourcc;
 
@@ -218,6 +235,7 @@ struct tm6000_core {
 
        int                             ctl_mute;             /* audio */
        int                             ctl_volume;
+       int                             amode;
 
        /* DVB-T support */
        struct tm6000_dvb               *dvb;
@@ -226,8 +244,6 @@ struct tm6000_core {
        struct snd_tm6000_card          *adev;
        struct work_struct              wq_trigger;   /* Trigger to start/stop audio for alsa module */
        atomic_t                        stream_started;  /* stream should be running if true */
-       enum tm6000_inaudio             avideo;
-       enum tm6000_inaudio             aradio;
 
        struct tm6000_IR                *ir;
 
@@ -302,7 +318,7 @@ 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_set_audio_input(struct tm6000_core *dev, enum tm6000_inaudio ainp);
+int tm6000_set_audio_rinput(struct tm6000_core *dev);
 int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute);
 void tm6000_set_volume(struct tm6000_core *dev, int vol);
 
@@ -323,7 +339,7 @@ int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type,
 
 /* 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);
+int tm6000_set_standard(struct tm6000_core *dev);
 
 /* In tm6000-i2c.c */
 int tm6000_i2c_register(struct tm6000_core *dev);
index 75cf611..cb1ded2 100644 (file)
@@ -372,6 +372,7 @@ header-y += unistd.h
 header-y += usbdevice_fs.h
 header-y += utime.h
 header-y += utsname.h
+header-y += uvcvideo.h
 header-y += v4l2-mediabus.h
 header-y += v4l2-subdev.h
 header-y += veth.h
index 493a2bf..36a3ed6 100644 (file)
@@ -175,14 +175,20 @@ typedef enum fe_transmit_mode {
        TRANSMISSION_MODE_2K,
        TRANSMISSION_MODE_8K,
        TRANSMISSION_MODE_AUTO,
-       TRANSMISSION_MODE_4K
+       TRANSMISSION_MODE_4K,
+       TRANSMISSION_MODE_1K,
+       TRANSMISSION_MODE_16K,
+       TRANSMISSION_MODE_32K,
 } fe_transmit_mode_t;
 
 typedef enum fe_bandwidth {
        BANDWIDTH_8_MHZ,
        BANDWIDTH_7_MHZ,
        BANDWIDTH_6_MHZ,
-       BANDWIDTH_AUTO
+       BANDWIDTH_AUTO,
+       BANDWIDTH_5_MHZ,
+       BANDWIDTH_10_MHZ,
+       BANDWIDTH_1_712_MHZ,
 } fe_bandwidth_t;
 
 
@@ -191,7 +197,10 @@ typedef enum fe_guard_interval {
        GUARD_INTERVAL_1_16,
        GUARD_INTERVAL_1_8,
        GUARD_INTERVAL_1_4,
-       GUARD_INTERVAL_AUTO
+       GUARD_INTERVAL_AUTO,
+       GUARD_INTERVAL_1_128,
+       GUARD_INTERVAL_19_128,
+       GUARD_INTERVAL_19_256,
 } fe_guard_interval_t;
 
 
@@ -305,7 +314,9 @@ struct dvb_frontend_event {
 
 #define DTV_ISDBS_TS_ID                42
 
-#define DTV_MAX_COMMAND                                DTV_ISDBS_TS_ID
+#define DTV_DVBT2_PLP_ID       43
+
+#define DTV_MAX_COMMAND                                DTV_DVBT2_PLP_ID
 
 typedef enum fe_pilot {
        PILOT_ON,
@@ -337,6 +348,7 @@ typedef enum fe_delivery_system {
        SYS_DMBTH,
        SYS_CMMB,
        SYS_DAB,
+       SYS_DVBT2,
 } fe_delivery_system_t;
 
 struct dtv_cmds_h {
index 5a7546c..1421cc8 100644 (file)
@@ -24,6 +24,6 @@
 #define _DVBVERSION_H_
 
 #define DVB_API_VERSION 5
-#define DVB_API_VERSION_MINOR 2
+#define DVB_API_VERSION_MINOR 3
 
 #endif /*_DVBVERSION_H_*/
diff --git a/include/linux/uvcvideo.h b/include/linux/uvcvideo.h
new file mode 100644 (file)
index 0000000..f46a53f
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef __LINUX_UVCVIDEO_H_
+#define __LINUX_UVCVIDEO_H_
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/*
+ * Dynamic controls
+ */
+
+/* Data types for UVC control data */
+#define UVC_CTRL_DATA_TYPE_RAW         0
+#define UVC_CTRL_DATA_TYPE_SIGNED      1
+#define UVC_CTRL_DATA_TYPE_UNSIGNED    2
+#define UVC_CTRL_DATA_TYPE_BOOLEAN     3
+#define UVC_CTRL_DATA_TYPE_ENUM                4
+#define UVC_CTRL_DATA_TYPE_BITMASK     5
+
+/* Control flags */
+#define UVC_CTRL_FLAG_SET_CUR          (1 << 0)
+#define UVC_CTRL_FLAG_GET_CUR          (1 << 1)
+#define UVC_CTRL_FLAG_GET_MIN          (1 << 2)
+#define UVC_CTRL_FLAG_GET_MAX          (1 << 3)
+#define UVC_CTRL_FLAG_GET_RES          (1 << 4)
+#define UVC_CTRL_FLAG_GET_DEF          (1 << 5)
+/* Control should be saved at suspend and restored at resume. */
+#define UVC_CTRL_FLAG_RESTORE          (1 << 6)
+/* Control can be updated by the camera. */
+#define UVC_CTRL_FLAG_AUTO_UPDATE      (1 << 7)
+
+#define UVC_CTRL_FLAG_GET_RANGE \
+       (UVC_CTRL_FLAG_GET_CUR | UVC_CTRL_FLAG_GET_MIN | \
+        UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES | \
+        UVC_CTRL_FLAG_GET_DEF)
+
+struct uvc_menu_info {
+       __u32 value;
+       __u8 name[32];
+};
+
+struct uvc_xu_control_mapping {
+       __u32 id;
+       __u8 name[32];
+       __u8 entity[16];
+       __u8 selector;
+
+       __u8 size;
+       __u8 offset;
+       __u32 v4l2_type;
+       __u32 data_type;
+
+       struct uvc_menu_info __user *menu_info;
+       __u32 menu_count;
+
+       __u32 reserved[4];
+};
+
+struct uvc_xu_control_query {
+       __u8 unit;
+       __u8 selector;
+       __u8 query;
+       __u16 size;
+       __u8 __user *data;
+};
+
+#define UVCIOC_CTRL_MAP                _IOWR('u', 0x20, struct uvc_xu_control_mapping)
+#define UVCIOC_CTRL_QUERY      _IOWR('u', 0x21, struct uvc_xu_control_query)
+
+#endif
index de5c159..5ea7f75 100644 (file)
@@ -89,6 +89,9 @@ enum v4l2_mbus_pixelcode {
        V4L2_MBUS_FMT_SGBRG12_1X12 = 0x3010,
        V4L2_MBUS_FMT_SGRBG12_1X12 = 0x3011,
        V4L2_MBUS_FMT_SRGGB12_1X12 = 0x3012,
+
+       /* JPEG compressed formats - next is 0x4002 */
+       V4L2_MBUS_FMT_JPEG_1X8 = 0x4001,
 };
 
 /**
index be82c8e..8a4c309 100644 (file)
@@ -311,6 +311,9 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_Y12     v4l2_fourcc('Y', '1', '2', ' ') /* 12  Greyscale     */
 #define V4L2_PIX_FMT_Y16     v4l2_fourcc('Y', '1', '6', ' ') /* 16  Greyscale     */
 
+/* Grey bit-packed formats */
+#define V4L2_PIX_FMT_Y10BPACK    v4l2_fourcc('Y', '1', '0', 'B') /* 10  Greyscale bit-packed */
+
 /* Palette formats */
 #define V4L2_PIX_FMT_PAL8    v4l2_fourcc('P', 'A', 'L', '8') /*  8  8-bit palette */
 
@@ -333,6 +336,7 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_YUV420  v4l2_fourcc('Y', 'U', '1', '2') /* 12  YUV 4:2:0     */
 #define V4L2_PIX_FMT_HI240   v4l2_fourcc('H', 'I', '2', '4') /*  8  8-bit color   */
 #define V4L2_PIX_FMT_HM12    v4l2_fourcc('H', 'M', '1', '2') /*  8  YUV 4:2:0 16x16 macroblocks */
+#define V4L2_PIX_FMT_M420    v4l2_fourcc('M', '4', '2', '0') /* 12  YUV 4:2:0 2 lines y, 1 line uv interleaved */
 
 /* two planes -- one Y, one Cr + Cb interleaved  */
 #define V4L2_PIX_FMT_NV12    v4l2_fourcc('N', 'V', '1', '2') /* 12  Y/CbCr 4:2:0  */
diff --git a/include/media/mt9v032.h b/include/media/mt9v032.h
new file mode 100644 (file)
index 0000000..5e27f9b
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _MEDIA_MT9V032_H
+#define _MEDIA_MT9V032_H
+
+struct v4l2_subdev;
+
+struct mt9v032_platform_data {
+       unsigned int clk_pol:1;
+
+       void (*set_clock)(struct v4l2_subdev *subdev, unsigned int rate);
+};
+
+#endif
index 2963263..60536c7 100644 (file)
@@ -40,10 +40,12 @@ enum rc_driver_type {
  * @driver_name: name of the hardware driver which registered this device
  * @map_name: name of the default keymap
  * @rc_map: current scan/key table
+ * @lock: used to ensure we've filled in all protocol details before
+ *     anyone can call show_protocols or store_protocols
  * @devno: unique remote control device number
  * @raw: additional data for raw pulse/space devices
  * @input_dev: the input child device used to communicate events to userspace
- * @driver_type: specifies if protocol decoding is done in hardware or software 
+ * @driver_type: specifies if protocol decoding is done in hardware or software
  * @idle: used to keep track of RX state
  * @allowed_protos: bitmask with the supported RC_TYPE_* protocols
  * @scanmask: some hardware decoders are not capable of providing the full
@@ -86,7 +88,8 @@ struct rc_dev {
        struct input_id                 input_id;
        char                            *driver_name;
        const char                      *map_name;
-       struct rc_map   rc_map;
+       struct rc_map                   rc_map;
+       struct mutex                    lock;
        unsigned long                   devno;
        struct ir_raw_event_ctrl        *raw;
        struct input_dev                *input_dev;
index 9184751..4e1409e 100644 (file)
@@ -136,6 +136,7 @@ void rc_map_init(void);
 #define RC_MAP_TERRATEC_SLIM             "rc-terratec-slim"
 #define RC_MAP_TERRATEC_SLIM_2           "rc-terratec-slim-2"
 #define RC_MAP_TEVII_NEC                 "rc-tevii-nec"
+#define RC_MAP_TIVO                      "rc-tivo"
 #define RC_MAP_TOTAL_MEDIA_IN_HAND       "rc-total-media-in-hand"
 #define RC_MAP_TREKSTOR                  "rc-trekstor"
 #define RC_MAP_TT_1500                   "rc-tt-1500"
index f80b537..238bd33 100644 (file)
@@ -80,6 +80,11 @@ struct soc_camera_host_ops {
        int (*cropcap)(struct soc_camera_device *, struct v4l2_cropcap *);
        int (*get_crop)(struct soc_camera_device *, struct v4l2_crop *);
        int (*set_crop)(struct soc_camera_device *, struct v4l2_crop *);
+       /*
+        * The difference to .set_crop() is, that .set_livecrop is not allowed
+        * to change the output sizes
+        */
+       int (*set_livecrop)(struct soc_camera_device *, struct v4l2_crop *);
        int (*set_fmt)(struct soc_camera_device *, struct v4l2_format *);
        int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *);
        void (*init_videobuf)(struct videobuf_queue *,
@@ -104,6 +109,12 @@ struct soc_camera_host_ops {
 #define SOCAM_SENSOR_INVERT_HSYNC      (1 << 2)
 #define SOCAM_SENSOR_INVERT_VSYNC      (1 << 3)
 #define SOCAM_SENSOR_INVERT_DATA       (1 << 4)
+#define SOCAM_MIPI_1LANE               (1 << 5)
+#define SOCAM_MIPI_2LANE               (1 << 6)
+#define SOCAM_MIPI_3LANE               (1 << 7)
+#define SOCAM_MIPI_4LANE               (1 << 8)
+#define SOCAM_MIPI     (SOCAM_MIPI_1LANE | SOCAM_MIPI_2LANE | \
+                       SOCAM_MIPI_3LANE | SOCAM_MIPI_4LANE)
 
 struct i2c_board_info;
 struct regulator_bulk_data;
@@ -268,6 +279,7 @@ static inline unsigned long soc_camera_bus_param_compatible(
                        unsigned long camera_flags, unsigned long bus_flags)
 {
        unsigned long common_flags, hsync, vsync, pclk, data, buswidth, mode;
+       unsigned long mipi;
 
        common_flags = camera_flags & bus_flags;
 
@@ -277,8 +289,9 @@ static inline unsigned long soc_camera_bus_param_compatible(
        data = common_flags & (SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_LOW);
        mode = common_flags & (SOCAM_MASTER | SOCAM_SLAVE);
        buswidth = common_flags & SOCAM_DATAWIDTH_MASK;
+       mipi = common_flags & SOCAM_MIPI;
 
-       return (!hsync || !vsync || !pclk || !data || !mode || !buswidth) ? 0 :
+       return ((!hsync || !vsync || !pclk || !data || !mode || !buswidth) && !mipi) ? 0 :
                common_flags;
 }
 
index 0ecefe2..6d7a4fd 100644 (file)
@@ -25,4 +25,54 @@ struct soc_camera_platform_info {
        int (*set_capture)(struct soc_camera_platform_info *info, int enable);
 };
 
+static inline void soc_camera_platform_release(struct platform_device **pdev)
+{
+       *pdev = NULL;
+}
+
+static inline int soc_camera_platform_add(const struct soc_camera_link *icl,
+                                         struct device *dev,
+                                         struct platform_device **pdev,
+                                         struct soc_camera_link *plink,
+                                         void (*release)(struct device *dev),
+                                         int id)
+{
+       struct soc_camera_platform_info *info = plink->priv;
+       int ret;
+
+       if (icl != plink)
+               return -ENODEV;
+
+       if (*pdev)
+               return -EBUSY;
+
+       *pdev = platform_device_alloc("soc_camera_platform", id);
+       if (!*pdev)
+               return -ENOMEM;
+
+       info->dev = dev;
+
+       (*pdev)->dev.platform_data = info;
+       (*pdev)->dev.release = release;
+
+       ret = platform_device_add(*pdev);
+       if (ret < 0) {
+               platform_device_put(*pdev);
+               *pdev = NULL;
+               info->dev = NULL;
+       }
+
+       return ret;
+}
+
+static inline void soc_camera_platform_del(const struct soc_camera_link *icl,
+                                          struct platform_device *pdev,
+                                          const struct soc_camera_link *plink)
+{
+       if (icl != plink || !pdev)
+               return;
+
+       platform_device_unregister(pdev);
+}
+
 #endif /* __SOC_CAMERA_H__ */
index b338108..fae4325 100644 (file)
 
 /**
  * enum soc_mbus_packing - data packing types on the media-bus
- * @SOC_MBUS_PACKING_NONE:     no packing, bit-for-bit transfer to RAM
+ * @SOC_MBUS_PACKING_NONE:     no packing, bit-for-bit transfer to RAM, one
+ *                             sample represents one pixel
  * @SOC_MBUS_PACKING_2X8_PADHI:        16 bits transferred in 2 8-bit samples, in the
  *                             possibly incomplete byte high bits are padding
  * @SOC_MBUS_PACKING_2X8_PADLO:        as above, but low bits are padding
  * @SOC_MBUS_PACKING_EXTEND16: sample width (e.g., 10 bits) has to be extended
  *                             to 16 bits
+ * @SOC_MBUS_PACKING_VARIABLE: compressed formats with variable packing
+ * @SOC_MBUS_PACKING_1_5X8:    used for packed YUV 4:2:0 formats, where 4
+ *                             pixels occupy 6 bytes in RAM
  */
 enum soc_mbus_packing {
        SOC_MBUS_PACKING_NONE,
        SOC_MBUS_PACKING_2X8_PADHI,
        SOC_MBUS_PACKING_2X8_PADLO,
        SOC_MBUS_PACKING_EXTEND16,
+       SOC_MBUS_PACKING_VARIABLE,
+       SOC_MBUS_PACKING_1_5X8,
 };
 
 /**
@@ -57,9 +63,24 @@ struct soc_mbus_pixelfmt {
        u8                      bits_per_sample;
 };
 
+/**
+ * struct soc_mbus_lookup - Lookup FOURCC IDs by mediabus codes for pass-through
+ * @code:      mediabus pixel-code
+ * @fmt:       pixel format description
+ */
+struct soc_mbus_lookup {
+       enum v4l2_mbus_pixelcode        code;
+       struct soc_mbus_pixelfmt        fmt;
+};
+
+const struct soc_mbus_pixelfmt *soc_mbus_find_fmtdesc(
+       enum v4l2_mbus_pixelcode code,
+       const struct soc_mbus_lookup *lookup,
+       int n);
 const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc(
        enum v4l2_mbus_pixelcode code);
 s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf);
-int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf);
+int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf,
+                       unsigned int *numerator, unsigned int *denominator);
 
 #endif
index 8266d5a..93e96fb 100644 (file)
@@ -62,6 +62,8 @@ struct v4l2_file_operations {
        unsigned int (*poll) (struct file *, struct poll_table_struct *);
        long (*ioctl) (struct file *, unsigned int, unsigned long);
        long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
+       unsigned long (*get_unmapped_area) (struct file *, unsigned long,
+                               unsigned long, unsigned long, unsigned long);
        int (*mmap) (struct file *, struct vm_area_struct *);
        int (*open) (struct file *);
        int (*release) (struct file *);